mirror of
https://github.com/osukey/osukey.git
synced 2025-05-30 09:57:21 +09:00
timeline works💪
This commit is contained in:
parent
387f434257
commit
dd81505982
@ -11,6 +11,7 @@ using osu.Framework.Localisation;
|
|||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Online.API.Requests.Responses;
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
using osu.Game.Online.MisskeyAPI.Requests.Responses;
|
using osu.Game.Online.MisskeyAPI.Requests.Responses;
|
||||||
|
using osu.Game.Online.MisskeyAPI.Responses.Types;
|
||||||
|
|
||||||
namespace osu.Game.Misskey.Users.Drawables
|
namespace osu.Game.Misskey.Users.Drawables
|
||||||
{
|
{
|
||||||
@ -35,7 +36,7 @@ namespace osu.Game.Misskey.Users.Drawables
|
|||||||
set => clickableArea.TooltipText = value ? (user?.Username ?? string.Empty) : default_tooltip_text;
|
set => clickableArea.TooltipText = value ? (user?.Username ?? string.Empty) : default_tooltip_text;
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly I user;
|
private readonly User user;
|
||||||
|
|
||||||
[Resolved(CanBeNull = true)]
|
[Resolved(CanBeNull = true)]
|
||||||
private OsuGame game { get; set; }
|
private OsuGame game { get; set; }
|
||||||
@ -47,7 +48,7 @@ namespace osu.Game.Misskey.Users.Drawables
|
|||||||
/// If <see cref="OpenOnClick"/> is <c>true</c>, clicking will open the user's profile.
|
/// If <see cref="OpenOnClick"/> is <c>true</c>, clicking will open the user's profile.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="user">The user. A null value will get a placeholder avatar.</param>
|
/// <param name="user">The user. A null value will get a placeholder avatar.</param>
|
||||||
public ClickableAvatar(I user = null)
|
public ClickableAvatar(User user = null)
|
||||||
{
|
{
|
||||||
this.user = user;
|
this.user = user;
|
||||||
|
|
||||||
@ -66,6 +67,11 @@ namespace osu.Game.Misskey.Users.Drawables
|
|||||||
LoadComponentAsync(new DrawableAvatar(user), clickableArea.Add);
|
LoadComponentAsync(new DrawableAvatar(user), clickableArea.Add);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
CornerRadius = DrawHeight / 2;
|
||||||
|
}
|
||||||
|
|
||||||
private void openProfile()
|
private void openProfile()
|
||||||
{
|
{
|
||||||
// if (!string.IsNullOrEmpty(user?.Username))
|
// if (!string.IsNullOrEmpty(user?.Username))
|
||||||
|
@ -9,19 +9,20 @@ using osu.Framework.Graphics.Sprites;
|
|||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Game.Online.API.Requests.Responses;
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
using osu.Game.Online.MisskeyAPI.Requests.Responses;
|
using osu.Game.Online.MisskeyAPI.Requests.Responses;
|
||||||
|
using osu.Game.Online.MisskeyAPI.Responses.Types;
|
||||||
|
|
||||||
namespace osu.Game.Misskey.Users.Drawables
|
namespace osu.Game.Misskey.Users.Drawables
|
||||||
{
|
{
|
||||||
[LongRunningLoad]
|
[LongRunningLoad]
|
||||||
public partial class DrawableAvatar : Sprite
|
public partial class DrawableAvatar : Sprite
|
||||||
{
|
{
|
||||||
private readonly I user;
|
private readonly User user;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A simple, non-interactable avatar sprite for the specified user.
|
/// A simple, non-interactable avatar sprite for the specified user.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="user">The user. A null value will get a placeholder avatar.</param>
|
/// <param name="user">The user. A null value will get a placeholder avatar.</param>
|
||||||
public DrawableAvatar(I user = null)
|
public DrawableAvatar(User user = null)
|
||||||
{
|
{
|
||||||
this.user = user;
|
this.user = user;
|
||||||
|
|
||||||
|
@ -8,15 +8,16 @@ using osu.Framework.Graphics.Containers;
|
|||||||
using osu.Framework.Graphics.Effects;
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Game.Online.API.Requests.Responses;
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
using osu.Game.Online.MisskeyAPI.Requests.Responses;
|
using osu.Game.Online.MisskeyAPI.Requests.Responses;
|
||||||
|
using osu.Game.Online.MisskeyAPI.Responses.Types;
|
||||||
|
|
||||||
namespace osu.Game.Misskey.Users.Drawables
|
namespace osu.Game.Misskey.Users.Drawables
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// An avatar which can update to a new user when needed.
|
/// An avatar which can update to a new user when needed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class UpdateableAvatar : ModelBackedDrawable<I>
|
public partial class UpdateableAvatar : ModelBackedDrawable<User>
|
||||||
{
|
{
|
||||||
public I User
|
public User User
|
||||||
{
|
{
|
||||||
get => Model;
|
get => Model;
|
||||||
set => Model = value;
|
set => Model = value;
|
||||||
@ -59,7 +60,7 @@ namespace osu.Game.Misskey.Users.Drawables
|
|||||||
/// <param name="isInteractive">If set to true, hover/click sounds will play and clicking the avatar will open the user's profile.</param>
|
/// <param name="isInteractive">If set to true, hover/click sounds will play and clicking the avatar will open the user's profile.</param>
|
||||||
/// <param name="showUsernameTooltip">Whether to show the username rather than "view profile" on the tooltip. (note: this only applies if <paramref name="isInteractive"/> is also true)</param>
|
/// <param name="showUsernameTooltip">Whether to show the username rather than "view profile" on the tooltip. (note: this only applies if <paramref name="isInteractive"/> is also true)</param>
|
||||||
/// <param name="showGuestOnNull">Whether to show a default guest representation on null user (as opposed to nothing).</param>
|
/// <param name="showGuestOnNull">Whether to show a default guest representation on null user (as opposed to nothing).</param>
|
||||||
public UpdateableAvatar(I user = null, bool isInteractive = true, bool showUsernameTooltip = false, bool showGuestOnNull = true)
|
public UpdateableAvatar(User user = null, bool isInteractive = true, bool showUsernameTooltip = false, bool showGuestOnNull = true)
|
||||||
{
|
{
|
||||||
this.isInteractive = isInteractive;
|
this.isInteractive = isInteractive;
|
||||||
this.showUsernameTooltip = showUsernameTooltip;
|
this.showUsernameTooltip = showUsernameTooltip;
|
||||||
@ -68,7 +69,7 @@ namespace osu.Game.Misskey.Users.Drawables
|
|||||||
User = user;
|
User = user;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Drawable CreateDrawable(I user)
|
protected override Drawable CreateDrawable(User user)
|
||||||
{
|
{
|
||||||
if (user == null && !showGuestOnNull)
|
if (user == null && !showGuestOnNull)
|
||||||
return null;
|
return null;
|
||||||
|
@ -15,6 +15,7 @@ using osu.Game.Misskey.Users.Drawables;
|
|||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Online.API.Requests.Responses;
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
using osu.Game.Online.MisskeyAPI.Requests.Responses;
|
using osu.Game.Online.MisskeyAPI.Requests.Responses;
|
||||||
|
using osu.Game.Online.MisskeyAPI.Responses.Types;
|
||||||
|
|
||||||
namespace osu.Game.Misskey.Users
|
namespace osu.Game.Misskey.Users
|
||||||
{
|
{
|
||||||
@ -29,7 +30,7 @@ namespace osu.Game.Misskey.Users
|
|||||||
private SpriteIcon statusIcon;
|
private SpriteIcon statusIcon;
|
||||||
private OsuSpriteText statusMessage;
|
private OsuSpriteText statusMessage;
|
||||||
|
|
||||||
protected ExtendedUserPanel(I user)
|
protected ExtendedUserPanel(User user)
|
||||||
: base(user)
|
: base(user)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -14,19 +14,20 @@ using osu.Framework.Graphics.Sprites;
|
|||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Game.Online.API.Requests.Responses;
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
using osu.Game.Online.MisskeyAPI.Requests.Responses;
|
using osu.Game.Online.MisskeyAPI.Requests.Responses;
|
||||||
|
using osu.Game.Online.MisskeyAPI.Responses.Types;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
|
|
||||||
namespace osu.Game.Misskey.Users
|
namespace osu.Game.Misskey.Users
|
||||||
{
|
{
|
||||||
public partial class UserCoverBackground : ModelBackedDrawable<I>
|
public partial class UserCoverBackground : ModelBackedDrawable<User>
|
||||||
{
|
{
|
||||||
public I User
|
public User User
|
||||||
{
|
{
|
||||||
get => Model;
|
get => Model;
|
||||||
set => Model = value;
|
set => Model = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Drawable CreateDrawable(I user) => new Cover(user);
|
protected override Drawable CreateDrawable(User user) => new Cover(user);
|
||||||
|
|
||||||
protected override double LoadDelay => 300;
|
protected override double LoadDelay => 300;
|
||||||
|
|
||||||
@ -41,9 +42,9 @@ namespace osu.Game.Misskey.Users
|
|||||||
[LongRunningLoad]
|
[LongRunningLoad]
|
||||||
private partial class Cover : CompositeDrawable
|
private partial class Cover : CompositeDrawable
|
||||||
{
|
{
|
||||||
private readonly I user;
|
private readonly User user;
|
||||||
|
|
||||||
public Cover(I user)
|
public Cover(User user)
|
||||||
{
|
{
|
||||||
this.user = user;
|
this.user = user;
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Game.Online.API.Requests.Responses;
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
using osu.Game.Online.MisskeyAPI.Requests.Responses;
|
using osu.Game.Online.MisskeyAPI.Requests.Responses;
|
||||||
|
using osu.Game.Online.MisskeyAPI.Responses.Types;
|
||||||
using osu.Game.Overlays.Profile.Header.Components;
|
using osu.Game.Overlays.Profile.Header.Components;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
@ -17,7 +18,7 @@ namespace osu.Game.Misskey.Users
|
|||||||
{
|
{
|
||||||
private const int margin = 10;
|
private const int margin = 10;
|
||||||
|
|
||||||
public UserGridPanel(I user)
|
public UserGridPanel(User user)
|
||||||
: base(user)
|
: base(user)
|
||||||
{
|
{
|
||||||
Height = 120;
|
Height = 120;
|
||||||
|
@ -11,6 +11,7 @@ using osuTK.Graphics;
|
|||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Game.Online.API.Requests.Responses;
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
using osu.Game.Online.MisskeyAPI.Requests.Responses;
|
using osu.Game.Online.MisskeyAPI.Requests.Responses;
|
||||||
|
using osu.Game.Online.MisskeyAPI.Responses.Types;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osu.Game.Overlays.Profile.Header.Components;
|
using osu.Game.Overlays.Profile.Header.Components;
|
||||||
|
|
||||||
@ -18,7 +19,7 @@ namespace osu.Game.Misskey.Users
|
|||||||
{
|
{
|
||||||
public partial class UserListPanel : ExtendedUserPanel
|
public partial class UserListPanel : ExtendedUserPanel
|
||||||
{
|
{
|
||||||
public UserListPanel(I user)
|
public UserListPanel(User user)
|
||||||
: base(user)
|
: base(user)
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X;
|
RelativeSizeAxes = Axes.X;
|
||||||
|
@ -17,12 +17,13 @@ using osu.Game.Graphics.Containers;
|
|||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using osu.Game.Online.API.Requests.Responses;
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
using osu.Game.Online.MisskeyAPI.Requests.Responses;
|
using osu.Game.Online.MisskeyAPI.Requests.Responses;
|
||||||
|
using osu.Game.Online.MisskeyAPI.Responses.Types;
|
||||||
|
|
||||||
namespace osu.Game.Misskey.Users
|
namespace osu.Game.Misskey.Users
|
||||||
{
|
{
|
||||||
public abstract partial class UserPanel : OsuClickableContainer, IHasContextMenu
|
public abstract partial class UserPanel : OsuClickableContainer, IHasContextMenu
|
||||||
{
|
{
|
||||||
public readonly I User;
|
public readonly User User;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Perform an action in addition to showing the user's profile.
|
/// Perform an action in addition to showing the user's profile.
|
||||||
@ -34,7 +35,7 @@ namespace osu.Game.Misskey.Users
|
|||||||
|
|
||||||
protected Drawable Background { get; private set; }
|
protected Drawable Background { get; private set; }
|
||||||
|
|
||||||
protected UserPanel(I user)
|
protected UserPanel(User user)
|
||||||
: base(HoverSampleSet.Button)
|
: base(HoverSampleSet.Button)
|
||||||
{
|
{
|
||||||
if (user == null)
|
if (user == null)
|
||||||
|
@ -18,9 +18,12 @@ using osu.Framework.Extensions.ObjectExtensions;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Logging;
|
using osu.Framework.Logging;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
|
using osu.Game.Misskey.Users;
|
||||||
using osu.Game.Online.MisskeyAPI.Requests;
|
using osu.Game.Online.MisskeyAPI.Requests;
|
||||||
using osu.Game.Online.MisskeyAPI.Requests.Responses;
|
using osu.Game.Online.MisskeyAPI.Requests.Responses;
|
||||||
using osu.Game.Users;
|
using osu.Game.Online.MisskeyAPI.Responses.Types;
|
||||||
|
using User = osu.Game.Online.MisskeyAPI.Responses.Types.User;
|
||||||
|
using UserActivity = osu.Game.Users.UserActivity;
|
||||||
|
|
||||||
namespace osu.Game.Online.MisskeyAPI
|
namespace osu.Game.Online.MisskeyAPI
|
||||||
{
|
{
|
||||||
@ -44,10 +47,10 @@ namespace osu.Game.Online.MisskeyAPI
|
|||||||
|
|
||||||
private string password;
|
private string password;
|
||||||
|
|
||||||
public IBindable<Requests.Responses.I> LocalUser => localUser;
|
public IBindable<User> LocalUser => localUser;
|
||||||
public IBindable<UserActivity> Activity => activity;
|
public IBindable<UserActivity> Activity => activity;
|
||||||
|
|
||||||
private Bindable<Requests.Responses.I> localUser { get; } = new Bindable<Requests.Responses.I>(createGuestUser());
|
private Bindable<User> localUser { get; } = new Bindable<User>(createGuestUser());
|
||||||
private Bindable<UserActivity> activity { get; } = new Bindable<UserActivity>();
|
private Bindable<UserActivity> activity { get; } = new Bindable<UserActivity>();
|
||||||
|
|
||||||
protected bool HasLogin => authentication.Token.Value != null || (!string.IsNullOrEmpty(ProvidedUsername) && !string.IsNullOrEmpty(password));
|
protected bool HasLogin => authentication.Token.Value != null || (!string.IsNullOrEmpty(ProvidedUsername) && !string.IsNullOrEmpty(password));
|
||||||
@ -108,7 +111,7 @@ namespace osu.Game.Online.MisskeyAPI
|
|||||||
if (queue.Count == 0)
|
if (queue.Count == 0)
|
||||||
{
|
{
|
||||||
log.Add(@"Queueing a ping request");
|
log.Add(@"Queueing a ping request");
|
||||||
Queue(new Requests.I(AccessToken));
|
Queue(new Requests.User(AccessToken));
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -149,7 +152,7 @@ namespace osu.Game.Online.MisskeyAPI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var userReq = new Requests.I(AccessToken);
|
var userReq = new Requests.User(AccessToken);
|
||||||
|
|
||||||
userReq.Failure += ex =>
|
userReq.Failure += ex =>
|
||||||
{
|
{
|
||||||
@ -428,7 +431,7 @@ namespace osu.Game.Online.MisskeyAPI
|
|||||||
flushQueue();
|
flushQueue();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Requests.Responses.I createGuestUser() => new GuestUser();
|
private static User createGuestUser() => new GuestUser();
|
||||||
|
|
||||||
protected override void Dispose(bool isDisposing)
|
protected override void Dispose(bool isDisposing)
|
||||||
{
|
{
|
||||||
@ -439,7 +442,7 @@ namespace osu.Game.Online.MisskeyAPI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class GuestUser : Requests.Responses.I
|
internal class GuestUser : User
|
||||||
{
|
{
|
||||||
public GuestUser()
|
public GuestUser()
|
||||||
{
|
{
|
||||||
|
@ -12,6 +12,7 @@ using Newtonsoft.Json;
|
|||||||
using osu.Framework.IO.Network;
|
using osu.Framework.IO.Network;
|
||||||
using osu.Framework.Logging;
|
using osu.Framework.Logging;
|
||||||
using osu.Game.Online.MisskeyAPI.Requests.Responses;
|
using osu.Game.Online.MisskeyAPI.Requests.Responses;
|
||||||
|
using osu.Game.Online.MisskeyAPI.Responses.Types;
|
||||||
|
|
||||||
namespace osu.Game.Online.MisskeyAPI
|
namespace osu.Game.Online.MisskeyAPI
|
||||||
{
|
{
|
||||||
@ -85,7 +86,7 @@ namespace osu.Game.Online.MisskeyAPI
|
|||||||
//// <summary>
|
//// <summary>
|
||||||
//// The currently logged in user. Note that this will only be populated during <see cref="Perform"/>.
|
//// The currently logged in user. Note that this will only be populated during <see cref="Perform"/>.
|
||||||
//// </summary>
|
//// </summary>
|
||||||
protected I User { get; private set; }
|
protected User User { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Invoked on successful completion of an API request.
|
/// Invoked on successful completion of an API request.
|
||||||
|
@ -7,6 +7,7 @@ using System;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Game.Online.MisskeyAPI.Requests.Responses;
|
using osu.Game.Online.MisskeyAPI.Requests.Responses;
|
||||||
|
using osu.Game.Online.MisskeyAPI.Responses.Types;
|
||||||
using osu.Game.Users;
|
using osu.Game.Users;
|
||||||
|
|
||||||
namespace osu.Game.Online.MisskeyAPI
|
namespace osu.Game.Online.MisskeyAPI
|
||||||
@ -17,7 +18,7 @@ namespace osu.Game.Online.MisskeyAPI
|
|||||||
/// The local user.
|
/// The local user.
|
||||||
/// This is not thread-safe and should be scheduled locally if consumed from a drawable component.
|
/// This is not thread-safe and should be scheduled locally if consumed from a drawable component.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
IBindable<Requests.Responses.I> LocalUser { get; }
|
IBindable<User> LocalUser { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The current user's activity.
|
/// The current user's activity.
|
||||||
|
@ -8,12 +8,12 @@ using osu.Framework.IO.Network;
|
|||||||
namespace osu.Game.Online.MisskeyAPI.Requests
|
namespace osu.Game.Online.MisskeyAPI.Requests
|
||||||
{
|
{
|
||||||
|
|
||||||
public class I : APIRequest<MisskeyAPI.Requests.Responses.I>
|
public class User : APIRequest<MisskeyAPI.Responses.Types.User>
|
||||||
{
|
{
|
||||||
|
|
||||||
private string i;
|
private string i;
|
||||||
|
|
||||||
public I(string i)
|
public User(string i)
|
||||||
{
|
{
|
||||||
this.i = i;
|
this.i = i;
|
||||||
}
|
}
|
||||||
|
@ -13,17 +13,25 @@ namespace osu.Game.Online.MisskeyAPI.Requests.Notes
|
|||||||
{
|
{
|
||||||
private string text;
|
private string text;
|
||||||
private string i;
|
private string i;
|
||||||
|
private string? cw;
|
||||||
|
|
||||||
public Create(string i, string Text)
|
public Create(string i, string Text)
|
||||||
{
|
{
|
||||||
this.text = Text;
|
|
||||||
this.i = i;
|
this.i = i;
|
||||||
|
this.text = Text;
|
||||||
|
}
|
||||||
|
public Create(string i, string Text, string cw)
|
||||||
|
{
|
||||||
|
this.i = i;
|
||||||
|
this.text = Text;
|
||||||
|
this.cw = cw;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ReqBody
|
private class ReqBody
|
||||||
{
|
{
|
||||||
public string? text;
|
public string? text;
|
||||||
public string? i;
|
public string? i;
|
||||||
|
public string? cw;
|
||||||
};
|
};
|
||||||
protected override WebRequest CreateWebRequest()
|
protected override WebRequest CreateWebRequest()
|
||||||
{
|
{
|
||||||
@ -34,6 +42,10 @@ namespace osu.Game.Online.MisskeyAPI.Requests.Notes
|
|||||||
text = text,
|
text = text,
|
||||||
i = i
|
i = i
|
||||||
};
|
};
|
||||||
|
if (cw != null)
|
||||||
|
{
|
||||||
|
body.cw = cw;
|
||||||
|
}
|
||||||
var json = JsonConvert.SerializeObject(body);
|
var json = JsonConvert.SerializeObject(body);
|
||||||
Logger.Log(json, LoggingTarget.Network, LogLevel.Debug);
|
Logger.Log(json, LoggingTarget.Network, LogLevel.Debug);
|
||||||
req.AddRaw(json);
|
req.AddRaw(json);
|
||||||
|
@ -6,41 +6,46 @@ using System.Net.Http;
|
|||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using osu.Framework.IO.Network;
|
using osu.Framework.IO.Network;
|
||||||
|
using osu.Game.Online.MisskeyAPI.Responses.Types;
|
||||||
using Realms;
|
using Realms;
|
||||||
|
|
||||||
namespace osu.Game.Online.MisskeyAPI.Requests.Notes
|
namespace osu.Game.Online.MisskeyAPI.Requests.Notes
|
||||||
{
|
{
|
||||||
public class HybridTimeline : APIRequest<MisskeyAPI.Requests.Responses.Notes.HybridTimeline>
|
public class HybridTimeline : APIRequest<Note[]>
|
||||||
{
|
{
|
||||||
private readonly string i;
|
private readonly string i;
|
||||||
|
|
||||||
private readonly string sinceId;
|
// private readonly string? sinceId;
|
||||||
private readonly string untilId;
|
private readonly string? untilId;
|
||||||
|
|
||||||
public HybridTimeline(
|
public HybridTimeline(
|
||||||
string i,
|
string i,
|
||||||
string sinceId = "",
|
|
||||||
string untilId = ""
|
string untilId = ""
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
this.i = i;
|
this.i = i;
|
||||||
this.sinceId = sinceId;
|
|
||||||
this.untilId = untilId;
|
this.untilId = untilId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public HybridTimeline(string i)
|
||||||
|
{
|
||||||
|
this.i = i;
|
||||||
|
}
|
||||||
|
|
||||||
protected override WebRequest CreateWebRequest()
|
protected override WebRequest CreateWebRequest()
|
||||||
{
|
{
|
||||||
var req = base.CreateWebRequest();
|
var req = base.CreateWebRequest();
|
||||||
req.Method = HttpMethod.Post;
|
req.Method = HttpMethod.Post;
|
||||||
|
|
||||||
var body = new Dictionary<string, string>
|
var body = new Dictionary<string, object>
|
||||||
{
|
{
|
||||||
{ "i", i },
|
{ "i", i },
|
||||||
|
{ "limit", 30 },
|
||||||
};
|
};
|
||||||
|
|
||||||
if (sinceId != "")
|
// if (sinceId != null)
|
||||||
body.Add("sinceId", sinceId);
|
// body.Add("sinceId", sinceId);
|
||||||
if (untilId != "")
|
if (untilId != null)
|
||||||
body.Add("untilId", untilId);
|
body.Add("untilId", untilId);
|
||||||
|
|
||||||
req.AddRaw(JsonConvert.SerializeObject(body));
|
req.AddRaw(JsonConvert.SerializeObject(body));
|
||||||
|
@ -1,267 +0,0 @@
|
|||||||
// Copyright (c) sim1222 <kokt@sim1222.com>. Licensed under the MIT Licence.
|
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
|
|
||||||
namespace osu.Game.Online.MisskeyAPI.Requests.Responses.Notes
|
|
||||||
{
|
|
||||||
public class Channel
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Emoji
|
|
||||||
{
|
|
||||||
[JsonProperty("name")]
|
|
||||||
public string Name { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("url")]
|
|
||||||
public string Url { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class File
|
|
||||||
{
|
|
||||||
[JsonProperty("id")]
|
|
||||||
public string Id { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("createdAt")]
|
|
||||||
public DateTime? CreatedAt { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("name")]
|
|
||||||
public string Name { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("type")]
|
|
||||||
public string Type { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("md5")]
|
|
||||||
public string Md5 { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("size")]
|
|
||||||
public int? Size { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("isSensitive")]
|
|
||||||
public bool? IsSensitive { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("blurhash")]
|
|
||||||
public string Blurhash { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("properties")]
|
|
||||||
public Properties Properties { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("url")]
|
|
||||||
public string Url { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("thumbnailUrl")]
|
|
||||||
public string ThumbnailUrl { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("comment")]
|
|
||||||
public string Comment { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("folderId")]
|
|
||||||
public string FolderId { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("folder")]
|
|
||||||
public Folder Folder { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("userId")]
|
|
||||||
public string UserId { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("user")]
|
|
||||||
public User User { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Folder
|
|
||||||
{
|
|
||||||
[JsonProperty("id")]
|
|
||||||
public string Id { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("createdAt")]
|
|
||||||
public DateTime? CreatedAt { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("name")]
|
|
||||||
public string Name { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("foldersCount")]
|
|
||||||
public int? FoldersCount { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("filesCount")]
|
|
||||||
public int? FilesCount { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("parentId")]
|
|
||||||
public string ParentId { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("parent")]
|
|
||||||
public Parent Parent { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class MyReaction
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Parent
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Poll
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Properties
|
|
||||||
{
|
|
||||||
[JsonProperty("width")]
|
|
||||||
public int? Width { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("height")]
|
|
||||||
public int? Height { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("orientation")]
|
|
||||||
public int? Orientation { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("avgColor")]
|
|
||||||
public string AvgColor { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Reactions
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Renote
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Reply
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public class HybridTimeline
|
|
||||||
{
|
|
||||||
[JsonProperty("id")]
|
|
||||||
public string Id { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("createdAt")]
|
|
||||||
public DateTime? CreatedAt { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("text")]
|
|
||||||
public string Text { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("cw")]
|
|
||||||
public string Cw { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("userId")]
|
|
||||||
public string UserId { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("user")]
|
|
||||||
public User User { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("replyId")]
|
|
||||||
public string ReplyId { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("renoteId")]
|
|
||||||
public string RenoteId { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("reply")]
|
|
||||||
public Reply Reply { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("renote")]
|
|
||||||
public Renote Renote { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("isHidden")]
|
|
||||||
public bool? IsHidden { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("visibility")]
|
|
||||||
public string Visibility { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("mentions")]
|
|
||||||
public List<string> Mentions { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("visibleUserIds")]
|
|
||||||
public List<string> VisibleUserIds { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("fileIds")]
|
|
||||||
public List<string> FileIds { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("files")]
|
|
||||||
public List<File> Files { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("tags")]
|
|
||||||
public List<string> Tags { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("poll")]
|
|
||||||
public Poll Poll { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("channelId")]
|
|
||||||
public string ChannelId { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("channel")]
|
|
||||||
public Channel Channel { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("localOnly")]
|
|
||||||
public bool? LocalOnly { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("emojis")]
|
|
||||||
public List<Emoji> Emojis { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("reactions")]
|
|
||||||
public Reactions Reactions { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("renoteCount")]
|
|
||||||
public int? RenoteCount { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("repliesCount")]
|
|
||||||
public int? RepliesCount { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("uri")]
|
|
||||||
public string Uri { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("url")]
|
|
||||||
public string Url { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("myReaction")]
|
|
||||||
public MyReaction MyReaction { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class User
|
|
||||||
{
|
|
||||||
[JsonProperty("id")]
|
|
||||||
public string Id { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("name")]
|
|
||||||
public string Name { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("username")]
|
|
||||||
public string Username { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("host")]
|
|
||||||
public string Host { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("avatarUrl")]
|
|
||||||
public string AvatarUrl { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("avatarBlurhash")]
|
|
||||||
public object AvatarBlurhash { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("avatarColor")]
|
|
||||||
public object AvatarColor { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("isAdmin")]
|
|
||||||
public bool? IsAdmin { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("isModerator")]
|
|
||||||
public bool? IsModerator { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("isBot")]
|
|
||||||
public bool? IsBot { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("isCat")]
|
|
||||||
public bool? IsCat { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("emojis")]
|
|
||||||
public List<Emoji> Emojis { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("onlineStatus")]
|
|
||||||
public string OnlineStatus { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -6,6 +6,9 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Game.Misskey.Users;
|
||||||
|
using UserStatusOnline = osu.Game.Users.UserStatusOnline;
|
||||||
|
|
||||||
namespace osu.Game.Online.MisskeyAPI.Responses.Types
|
namespace osu.Game.Online.MisskeyAPI.Responses.Types
|
||||||
{
|
{
|
||||||
@ -79,7 +82,7 @@ namespace osu.Game.Online.MisskeyAPI.Responses.Types
|
|||||||
public class Choice
|
public class Choice
|
||||||
{
|
{
|
||||||
[JsonProperty("isVoted")]
|
[JsonProperty("isVoted")]
|
||||||
public bool Id { get; set; }
|
public bool IsVoted { get; set; }
|
||||||
|
|
||||||
[JsonProperty("text")]
|
[JsonProperty("text")]
|
||||||
public string Text { get; set; }
|
public string Text { get; set; }
|
||||||
@ -96,7 +99,7 @@ namespace osu.Game.Online.MisskeyAPI.Responses.Types
|
|||||||
public bool Multiple { get; set; }
|
public bool Multiple { get; set; }
|
||||||
|
|
||||||
[JsonProperty("choices")]
|
[JsonProperty("choices")]
|
||||||
public Choice Choices { get; set; }
|
public Choice[] Choices { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Note // https://github.com/misskey-dev/misskey.js/blob/c89374c321aeb1cca2582922d4a9a9be059c691e/src/entities.ts#L128
|
public class Note // https://github.com/misskey-dev/misskey.js/blob/c89374c321aeb1cca2582922d4a9a9be059c691e/src/entities.ts#L128
|
||||||
@ -715,6 +718,13 @@ namespace osu.Game.Online.MisskeyAPI.Responses.Types
|
|||||||
|
|
||||||
public class UserLite // https://github.com/misskey-dev/misskey.js/blob/c89374c321aeb1cca2582922d4a9a9be059c691e/src/entities.ts#L9
|
public class UserLite // https://github.com/misskey-dev/misskey.js/blob/c89374c321aeb1cca2582922d4a9a9be059c691e/src/entities.ts#L9
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A user ID which can be used to represent any system user which is not attached to a user profile.
|
||||||
|
/// </summary>
|
||||||
|
public const string SYSTEM_USER_ID = "system";
|
||||||
|
|
||||||
|
public readonly Bindable<UserStatus> Status = new Bindable<UserStatus>();
|
||||||
|
|
||||||
[JsonProperty("id")]
|
[JsonProperty("id")]
|
||||||
public string Id { get; set; }
|
public string Id { get; set; }
|
||||||
|
|
||||||
@ -725,6 +735,9 @@ namespace osu.Game.Online.MisskeyAPI.Responses.Types
|
|||||||
[CanBeNull]
|
[CanBeNull]
|
||||||
public string Host { get; set; }
|
public string Host { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("name")]
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
[JsonProperty("onlineStatus")] // 'online' | 'active' | 'offline' | 'unknown'
|
[JsonProperty("onlineStatus")] // 'online' | 'active' | 'offline' | 'unknown'
|
||||||
public string OnlineStatus { get; set; }
|
public string OnlineStatus { get; set; }
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@ using osu.Game.Overlays.BeatmapListing;
|
|||||||
using osu.Game.Resources.Localisation.Web;
|
using osu.Game.Resources.Localisation.Web;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
|
using ExpandedContentScrollContainer = osu.Game.Screens.Misskey.Components.Note.Cards.ExpandedContentScrollContainer;
|
||||||
|
|
||||||
namespace osu.Game.Overlays
|
namespace osu.Game.Overlays
|
||||||
{
|
{
|
||||||
|
@ -18,6 +18,7 @@ using osu.Game.Online.API.Requests.Responses;
|
|||||||
using osu.Game.Overlays.Rankings.Tables;
|
using osu.Game.Overlays.Rankings.Tables;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
using ExpandedContentScrollContainer = osu.Game.Screens.Misskey.Components.Note.Cards.ExpandedContentScrollContainer;
|
||||||
|
|
||||||
namespace osu.Game.Overlays.Rankings
|
namespace osu.Game.Overlays.Rankings
|
||||||
{
|
{
|
||||||
|
@ -13,26 +13,30 @@ using osu.Game.Graphics.Containers;
|
|||||||
using osu.Game.Online.API.Requests.Responses;
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Screens.Misskey.Components
|
namespace osu.Game.Screens.Misskey.Components
|
||||||
{
|
{
|
||||||
|
|
||||||
[LongRunningLoad]
|
[LongRunningLoad]
|
||||||
public partial class Avatar : Sprite
|
public partial class Avatar : Sprite
|
||||||
{
|
{
|
||||||
// private readonly APIUser user;
|
// private readonly APIUser user;
|
||||||
|
private Online.MisskeyAPI.Responses.Types.Note note;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A simple, non-interactable avatar sprite for the specified user.
|
/// A simple, non-interactable avatar sprite for the specified user.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
///// <param name="user">The user. A null value will get a placeholder avatar.</param>
|
///// <param name="user">The user. A null value will get a placeholder avatar.</param>
|
||||||
public Avatar()
|
public Avatar(Online.MisskeyAPI.Responses.Types.Note note)
|
||||||
{
|
{
|
||||||
// this.user = user;
|
// this.user = user;
|
||||||
|
// RelativeSizeAxes = Axes.Both;
|
||||||
RelativeSizeAxes = Axes.Both;
|
Size = new Vector2(10f);
|
||||||
FillMode = FillMode.Fit;
|
FillMode = FillMode.Fit;
|
||||||
Anchor = Anchor.Centre;
|
Anchor = Anchor.Centre;
|
||||||
Origin = Anchor.Centre;
|
Origin = Anchor.Centre;
|
||||||
|
this.note = note;
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
@ -43,7 +47,7 @@ namespace osu.Game.Screens.Misskey.Components
|
|||||||
// // in remaining cases where this is required (chat tabs, local leaderboard), at which point this should be removed.
|
// // in remaining cases where this is required (chat tabs, local leaderboard), at which point this should be removed.
|
||||||
// Texture = textures.Get(user.AvatarUrl ?? $@"https://a.ppy.sh/{user.Id}");
|
// Texture = textures.Get(user.AvatarUrl ?? $@"https://a.ppy.sh/{user.Id}");
|
||||||
|
|
||||||
Texture ??= textures.Get(@"https://simkey.net/files/thumbnail-328eb27f-f06f-4454-ad52-a79d5f780a6b");
|
Texture ??= textures.Get(note.User.AvatarUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
|
@ -0,0 +1,98 @@
|
|||||||
|
// 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;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Game.Beatmaps.Drawables.Cards;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Online;
|
||||||
|
using osu.Game.Overlays;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Misskey.Components.Note.Cards
|
||||||
|
{
|
||||||
|
public partial class BeatmapCardDownloadProgressBar : CompositeDrawable
|
||||||
|
{
|
||||||
|
public IBindable<DownloadState> State => state;
|
||||||
|
private readonly Bindable<DownloadState> state = new Bindable<DownloadState>();
|
||||||
|
|
||||||
|
public IBindable<double> Progress => progress;
|
||||||
|
private readonly BindableDouble progress = new BindableDouble();
|
||||||
|
|
||||||
|
public override bool IsPresent => true;
|
||||||
|
|
||||||
|
private readonly CircularContainer foreground;
|
||||||
|
|
||||||
|
private readonly Box backgroundFill;
|
||||||
|
private readonly Box foregroundFill;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private OsuColour colours { get; set; }
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private OverlayColourProvider colourProvider { get; set; }
|
||||||
|
|
||||||
|
public BeatmapCardDownloadProgressBar()
|
||||||
|
{
|
||||||
|
InternalChildren = new Drawable[]
|
||||||
|
{
|
||||||
|
new CircularContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Masking = true,
|
||||||
|
Child = backgroundFill = new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
foreground = new CircularContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Masking = true,
|
||||||
|
Child = foregroundFill = new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
backgroundFill.Colour = colourProvider.Background6;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
state.BindValueChanged(_ => stateChanged(), true);
|
||||||
|
progress.BindValueChanged(_ => progressChanged(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void stateChanged()
|
||||||
|
{
|
||||||
|
switch (state.Value)
|
||||||
|
{
|
||||||
|
case DownloadState.Downloading:
|
||||||
|
FinishTransforms(true);
|
||||||
|
foregroundFill.Colour = colourProvider.Highlight1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DownloadState.Importing:
|
||||||
|
foregroundFill.FadeColour(colours.Yellow, BeatmapCard.TRANSITION_DURATION, Easing.OutQuint);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void progressChanged()
|
||||||
|
{
|
||||||
|
foreground.ResizeWidthTo((float)progress.Value, progress.Value > 0 ? BeatmapCard.TRANSITION_DURATION : 0, Easing.OutQuint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
// 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.Game.Screens.Misskey.Components.Note.Cards.Buttons;
|
||||||
|
using osu.Game.Screens.Misskey.Components.Note.Cards.Statistics;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Misskey.Components.Note.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,137 @@
|
|||||||
|
// 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.Extensions.Color4Extensions;
|
||||||
|
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.Game.Beatmaps.Drawables.Cards;
|
||||||
|
using osu.Game.Graphics.Containers;
|
||||||
|
using osu.Game.Overlays;
|
||||||
|
using osuTK;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Misskey.Components.Note.Cards.Buttons
|
||||||
|
{
|
||||||
|
public abstract partial class BeatmapCardIconButton : OsuClickableContainer
|
||||||
|
{
|
||||||
|
private Colour4 idleColour;
|
||||||
|
|
||||||
|
public Colour4 IdleColour
|
||||||
|
{
|
||||||
|
get => idleColour;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
idleColour = value;
|
||||||
|
if (IsLoaded)
|
||||||
|
updateState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Colour4 hoverColour;
|
||||||
|
|
||||||
|
public Colour4 HoverColour
|
||||||
|
{
|
||||||
|
get => hoverColour;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
hoverColour = value;
|
||||||
|
if (IsLoaded)
|
||||||
|
updateState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private float iconSize;
|
||||||
|
|
||||||
|
public float IconSize
|
||||||
|
{
|
||||||
|
get => iconSize;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
iconSize = value;
|
||||||
|
Icon.Size = new Vector2(iconSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected readonly SpriteIcon Icon;
|
||||||
|
|
||||||
|
protected override Container<Drawable> Content => content;
|
||||||
|
|
||||||
|
private readonly Container content;
|
||||||
|
private readonly Box hover;
|
||||||
|
|
||||||
|
protected BeatmapCardIconButton()
|
||||||
|
{
|
||||||
|
Origin = Anchor.Centre;
|
||||||
|
Anchor = Anchor.Centre;
|
||||||
|
|
||||||
|
base.Content.Add(content = new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Masking = true,
|
||||||
|
CornerRadius = BeatmapCard.CORNER_RADIUS,
|
||||||
|
Scale = new Vector2(0.8f),
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
hover = new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = Color4.White.Opacity(0.1f),
|
||||||
|
Blending = BlendingParameters.Additive,
|
||||||
|
},
|
||||||
|
Icon = new SpriteIcon
|
||||||
|
{
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Scale = new Vector2(1.2f),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
IconSize = 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OverlayColourProvider colourProvider)
|
||||||
|
{
|
||||||
|
IdleColour = colourProvider.Light1;
|
||||||
|
HoverColour = colourProvider.Content1;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
Enabled.BindValueChanged(_ => updateState(), true);
|
||||||
|
FinishTransforms(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool OnHover(HoverEvent e)
|
||||||
|
{
|
||||||
|
updateState();
|
||||||
|
return base.OnHover(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnHoverLost(HoverLostEvent e)
|
||||||
|
{
|
||||||
|
base.OnHoverLost(e);
|
||||||
|
updateState();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateState()
|
||||||
|
{
|
||||||
|
bool isHovered = IsHovered && Enabled.Value;
|
||||||
|
|
||||||
|
hover.FadeTo(isHovered ? 1f : 0f, 500, Easing.OutQuint);
|
||||||
|
content.ScaleTo(isHovered ? 1 : 0.8f, 500, Easing.OutQuint);
|
||||||
|
Icon.FadeColour(isHovered ? HoverColour : IdleColour, BeatmapCard.TRANSITION_DURATION, Easing.OutQuint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,103 @@
|
|||||||
|
// 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;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Beatmaps.Drawables.Cards;
|
||||||
|
using osu.Game.Configuration;
|
||||||
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
using osu.Game.Online;
|
||||||
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
|
using osu.Game.Resources.Localisation.Web;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Misskey.Components.Note.Cards.Buttons
|
||||||
|
{
|
||||||
|
public partial class DownloadButton : BeatmapCardIconButton
|
||||||
|
{
|
||||||
|
public Bindable<DownloadState> State { get; } = new Bindable<DownloadState>();
|
||||||
|
|
||||||
|
private readonly APIBeatmapSet beatmapSet;
|
||||||
|
|
||||||
|
private Bindable<bool> preferNoVideo = null!;
|
||||||
|
|
||||||
|
private readonly LoadingSpinner spinner;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private BeatmapModelDownloader beatmaps { get; set; } = null!;
|
||||||
|
|
||||||
|
public DownloadButton(APIBeatmapSet beatmapSet)
|
||||||
|
{
|
||||||
|
Icon.Icon = FontAwesome.Solid.Download;
|
||||||
|
|
||||||
|
Content.Add(spinner = new LoadingSpinner { Size = new Vector2(IconSize) });
|
||||||
|
|
||||||
|
this.beatmapSet = beatmapSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuConfigManager config)
|
||||||
|
{
|
||||||
|
preferNoVideo = config.GetBindable<bool>(OsuSetting.PreferNoVideo);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
preferNoVideo.BindValueChanged(_ => updateState());
|
||||||
|
State.BindValueChanged(_ => updateState(), true);
|
||||||
|
FinishTransforms(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateState()
|
||||||
|
{
|
||||||
|
switch (State.Value)
|
||||||
|
{
|
||||||
|
case DownloadState.Unknown:
|
||||||
|
Action = null;
|
||||||
|
TooltipText = string.Empty;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DownloadState.Downloading:
|
||||||
|
case DownloadState.Importing:
|
||||||
|
Action = null;
|
||||||
|
TooltipText = string.Empty;
|
||||||
|
spinner.Show();
|
||||||
|
Icon.Hide();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DownloadState.LocallyAvailable:
|
||||||
|
Action = null;
|
||||||
|
TooltipText = string.Empty;
|
||||||
|
this.FadeOut(BeatmapCard.TRANSITION_DURATION, Easing.OutQuint);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DownloadState.NotDownloaded:
|
||||||
|
if (beatmapSet.Availability.DownloadDisabled)
|
||||||
|
{
|
||||||
|
Enabled.Value = false;
|
||||||
|
TooltipText = BeatmapsetsStrings.AvailabilityDisabled;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Action = () => beatmaps.Download(beatmapSet, preferNoVideo.Value);
|
||||||
|
this.FadeIn(BeatmapCard.TRANSITION_DURATION, Easing.OutQuint);
|
||||||
|
spinner.Hide();
|
||||||
|
Icon.Show();
|
||||||
|
|
||||||
|
if (!beatmapSet.HasVideo)
|
||||||
|
TooltipText = BeatmapsetsStrings.PanelDownloadAll;
|
||||||
|
else
|
||||||
|
TooltipText = preferNoVideo.Value ? BeatmapsetsStrings.PanelDownloadNoVideo : BeatmapsetsStrings.PanelDownloadVideo;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new InvalidOperationException($"Unknown {nameof(DownloadState)} specified.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,88 @@
|
|||||||
|
// 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.Framework.Logging;
|
||||||
|
using osu.Game.Online.API;
|
||||||
|
using osu.Game.Online.API.Requests;
|
||||||
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
|
using osu.Game.Resources.Localisation.Web;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Misskey.Components.Note.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);
|
||||||
|
|
||||||
|
Enabled.Value = false;
|
||||||
|
favouriteRequest.Success += () =>
|
||||||
|
{
|
||||||
|
bool favourited = actionType == BeatmapFavouriteAction.Favourite;
|
||||||
|
|
||||||
|
current.Value = new BeatmapSetFavouriteState(favourited, current.Value.FavouriteCount + (favourited ? 1 : -1));
|
||||||
|
|
||||||
|
Enabled.Value = true;
|
||||||
|
};
|
||||||
|
favouriteRequest.Failure += e =>
|
||||||
|
{
|
||||||
|
Logger.Error(e, $"Failed to {actionType.ToString().ToLowerInvariant()} beatmap: {e.Message}");
|
||||||
|
Enabled.Value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
// 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.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Game.Beatmaps.Drawables.Cards;
|
||||||
|
using osu.Game.Online;
|
||||||
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Misskey.Components.Note.Cards.Buttons
|
||||||
|
{
|
||||||
|
public partial class GoToBeatmapButton : BeatmapCardIconButton
|
||||||
|
{
|
||||||
|
public IBindable<DownloadState> State => state;
|
||||||
|
private readonly Bindable<DownloadState> state = new Bindable<DownloadState>();
|
||||||
|
|
||||||
|
private readonly APIBeatmapSet beatmapSet;
|
||||||
|
|
||||||
|
public GoToBeatmapButton(APIBeatmapSet beatmapSet)
|
||||||
|
{
|
||||||
|
this.beatmapSet = beatmapSet;
|
||||||
|
|
||||||
|
Icon.Icon = FontAwesome.Solid.AngleDoubleRight;
|
||||||
|
TooltipText = "Go to beatmap";
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader(true)]
|
||||||
|
private void load(OsuGame? game)
|
||||||
|
{
|
||||||
|
Action = () => game?.PresentBeatmap(beatmapSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
state.BindValueChanged(_ => updateState(), true);
|
||||||
|
FinishTransforms(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateState()
|
||||||
|
{
|
||||||
|
this.FadeTo(state.Value == DownloadState.LocallyAvailable ? 1 : 0, BeatmapCard.TRANSITION_DURATION, Easing.OutQuint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,154 @@
|
|||||||
|
// 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.Collections.Generic;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Game.Audio;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Beatmaps.Drawables.Cards;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Graphics.Containers;
|
||||||
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Misskey.Components.Note.Cards.Buttons
|
||||||
|
{
|
||||||
|
public partial class PlayButton : OsuHoverContainer
|
||||||
|
{
|
||||||
|
public IBindable<double> Progress => progress;
|
||||||
|
private readonly BindableDouble progress = new BindableDouble();
|
||||||
|
|
||||||
|
public BindableBool Playing { get; } = new BindableBool();
|
||||||
|
|
||||||
|
private readonly IBeatmapSetInfo beatmapSetInfo;
|
||||||
|
|
||||||
|
protected override IEnumerable<Drawable> EffectTargets => icon.Yield();
|
||||||
|
|
||||||
|
private readonly SpriteIcon icon;
|
||||||
|
private readonly LoadingSpinner loadingSpinner;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private PreviewTrackManager previewTrackManager { get; set; } = null!;
|
||||||
|
|
||||||
|
private PreviewTrack? previewTrack;
|
||||||
|
|
||||||
|
public PlayButton(IBeatmapSetInfo beatmapSetInfo)
|
||||||
|
{
|
||||||
|
this.beatmapSetInfo = beatmapSetInfo;
|
||||||
|
|
||||||
|
Anchor = Origin = Anchor.Centre;
|
||||||
|
|
||||||
|
// needed for touch input to work when card is not hovered/expanded
|
||||||
|
AlwaysPresent = true;
|
||||||
|
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
icon = new SpriteIcon
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Icon = FontAwesome.Solid.Play,
|
||||||
|
Size = new Vector2(14)
|
||||||
|
},
|
||||||
|
loadingSpinner = new LoadingSpinner
|
||||||
|
{
|
||||||
|
Size = new Vector2(14)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Action = () => Playing.Toggle();
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colours)
|
||||||
|
{
|
||||||
|
HoverColour = colours.Yellow;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
Playing.BindValueChanged(updateState, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Update()
|
||||||
|
{
|
||||||
|
base.Update();
|
||||||
|
|
||||||
|
if (Playing.Value && previewTrack != null && previewTrack.TrackLoaded)
|
||||||
|
progress.Value = previewTrack.CurrentTime / previewTrack.Length;
|
||||||
|
else
|
||||||
|
progress.Value = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateState(ValueChangedEvent<bool> playing)
|
||||||
|
{
|
||||||
|
icon.Icon = playing.NewValue ? FontAwesome.Solid.Stop : FontAwesome.Solid.Play;
|
||||||
|
|
||||||
|
if (!playing.NewValue)
|
||||||
|
{
|
||||||
|
stopPreview();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (previewTrack == null)
|
||||||
|
{
|
||||||
|
toggleLoading(true);
|
||||||
|
|
||||||
|
LoadComponentAsync(previewTrack = previewTrackManager.Get(beatmapSetInfo), onPreviewLoaded);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
tryStartPreview();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void stopPreview()
|
||||||
|
{
|
||||||
|
toggleLoading(false);
|
||||||
|
Playing.Value = false;
|
||||||
|
previewTrack?.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onPreviewLoaded(PreviewTrack loadedPreview)
|
||||||
|
{
|
||||||
|
// Make sure that we schedule to after the next audio frame to fix crashes in single-threaded execution.
|
||||||
|
// See: https://github.com/ppy/osu-framework/issues/4692
|
||||||
|
Schedule(() =>
|
||||||
|
{
|
||||||
|
// another async load might have completed before this one.
|
||||||
|
// if so, do not make any changes.
|
||||||
|
if (loadedPreview != previewTrack)
|
||||||
|
{
|
||||||
|
loadedPreview.Dispose();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AddInternal(loadedPreview);
|
||||||
|
toggleLoading(false);
|
||||||
|
|
||||||
|
loadedPreview.Stopped += () => Schedule(() => Playing.Value = false);
|
||||||
|
|
||||||
|
if (Playing.Value)
|
||||||
|
tryStartPreview();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void tryStartPreview()
|
||||||
|
{
|
||||||
|
if (previewTrack?.Start() == false)
|
||||||
|
Playing.Value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void toggleLoading(bool loading)
|
||||||
|
{
|
||||||
|
Enabled.Value = !loading;
|
||||||
|
icon.FadeTo(loading ? 0 : 1, BeatmapCard.TRANSITION_DURATION, Easing.OutQuint);
|
||||||
|
loadingSpinner.State.Value = loading ? Visibility.Visible : Visibility.Hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -10,10 +10,9 @@ using osu.Game.Beatmaps.Drawables.Cards;
|
|||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Online;
|
using osu.Game.Online;
|
||||||
using osu.Game.Online.API.Requests.Responses;
|
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
|
|
||||||
namespace osu.Game.Screens.Misskey.Components
|
namespace osu.Game.Screens.Misskey.Components.Note.Cards
|
||||||
{
|
{
|
||||||
public abstract partial class DrawableNoteCard : OsuClickableContainer
|
public abstract partial class DrawableNoteCard : OsuClickableContainer
|
||||||
{
|
{
|
||||||
@ -24,38 +23,38 @@ namespace osu.Game.Screens.Misskey.Components
|
|||||||
|
|
||||||
public IBindable<bool> Expanded { get; }
|
public IBindable<bool> Expanded { get; }
|
||||||
|
|
||||||
public readonly APIBeatmapSet BeatmapSet;
|
public readonly Online.MisskeyAPI.Responses.Types.Note Note;
|
||||||
|
|
||||||
protected readonly Bindable<BeatmapSetFavouriteState> FavouriteState;
|
// protected readonly Bindable<BeatmapSetFavouriteState> FavouriteState;
|
||||||
|
|
||||||
protected abstract Drawable IdleContent { get; }
|
// protected abstract Drawable IdleContent { get; }
|
||||||
protected abstract Drawable DownloadInProgressContent { get; }
|
// protected abstract Drawable DownloadInProgressContent { get; }
|
||||||
|
|
||||||
protected readonly BeatmapDownloadTracker DownloadTracker;
|
// protected readonly BeatmapDownloadTracker DownloadTracker;
|
||||||
|
|
||||||
protected DrawableNoteCard(APIBeatmapSet beatmapSet, bool allowExpansion = true)
|
protected DrawableNoteCard(Online.MisskeyAPI.Responses.Types.Note note, bool allowExpansion = true)
|
||||||
: base(HoverSampleSet.Button)
|
: base(HoverSampleSet.Button)
|
||||||
{
|
{
|
||||||
Expanded = new BindableBool { Disabled = !allowExpansion };
|
Expanded = new BindableBool { Disabled = !allowExpansion };
|
||||||
|
|
||||||
BeatmapSet = beatmapSet;
|
Note = note;
|
||||||
FavouriteState = new Bindable<BeatmapSetFavouriteState>(new BeatmapSetFavouriteState(beatmapSet.HasFavourited, beatmapSet.FavouriteCount));
|
// FavouriteState = new Bindable<BeatmapSetFavouriteState>(new BeatmapSetFavouriteState(note.HasFavourited, note.FavouriteCount));
|
||||||
DownloadTracker = new BeatmapDownloadTracker(beatmapSet);
|
// DownloadTracker = new BeatmapDownloadTracker(note);
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader(true)]
|
[BackgroundDependencyLoader(true)]
|
||||||
private void load(BeatmapSetOverlay? beatmapSetOverlay)
|
private void load(BeatmapSetOverlay? beatmapSetOverlay)
|
||||||
{
|
{
|
||||||
Action = () => beatmapSetOverlay?.FetchAndShowBeatmapSet(BeatmapSet.OnlineID);
|
// Action = () => beatmapSetOverlay?.FetchAndShowBeatmapSet(Note.OnlineID);
|
||||||
|
|
||||||
AddInternal(DownloadTracker);
|
// AddInternal(DownloadTracker);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
|
||||||
DownloadTracker.State.BindValueChanged(_ => UpdateState());
|
// DownloadTracker.State.BindValueChanged(_ => UpdateState());
|
||||||
Expanded.BindValueChanged(_ => UpdateState(), true);
|
Expanded.BindValueChanged(_ => UpdateState(), true);
|
||||||
FinishTransforms(true);
|
FinishTransforms(true);
|
||||||
}
|
}
|
||||||
@ -74,24 +73,24 @@ namespace osu.Game.Screens.Misskey.Components
|
|||||||
|
|
||||||
protected virtual void UpdateState()
|
protected virtual void UpdateState()
|
||||||
{
|
{
|
||||||
bool showProgress = DownloadTracker.State.Value == DownloadState.Downloading || DownloadTracker.State.Value == DownloadState.Importing;
|
// bool showProgress = DownloadTracker.State.Value == DownloadState.Downloading || DownloadTracker.State.Value == DownloadState.Importing;
|
||||||
|
|
||||||
IdleContent.FadeTo(showProgress ? 0 : 1, TRANSITION_DURATION, Easing.OutQuint);
|
// IdleContent.FadeTo(showProgress ? 0 : 1, TRANSITION_DURATION, Easing.OutQuint);
|
||||||
DownloadInProgressContent.FadeTo(showProgress ? 1 : 0, TRANSITION_DURATION, Easing.OutQuint);
|
// DownloadInProgressContent.FadeTo(showProgress ? 1 : 0, TRANSITION_DURATION, Easing.OutQuint);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a beatmap card of the given <paramref name="size"/> for the supplied <paramref name="beatmapSet"/>.
|
/// Creates a beatmap card of the given <paramref name="size"/> for the supplied <paramref name="note"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static BeatmapCard Create(APIBeatmapSet beatmapSet, BeatmapCardSize size, bool allowExpansion = true)
|
public static NoteCard Create(Online.MisskeyAPI.Responses.Types.Note note, BeatmapCardSize size, bool allowExpansion = true)
|
||||||
{
|
{
|
||||||
switch (size)
|
switch (size)
|
||||||
{
|
{
|
||||||
case BeatmapCardSize.Normal:
|
case BeatmapCardSize.Normal:
|
||||||
return new BeatmapCardNormal(beatmapSet, allowExpansion);
|
return new NoteCardNormal(note, allowExpansion);
|
||||||
|
|
||||||
case BeatmapCardSize.Extra:
|
case BeatmapCardSize.Extra:
|
||||||
return new BeatmapCardExtra(beatmapSet, allowExpansion);
|
return new NoteCardNormal(note, allowExpansion); //todo: extra
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new ArgumentOutOfRangeException(nameof(size), size, @"Unsupported card size");
|
throw new ArgumentOutOfRangeException(nameof(size), size, @"Unsupported card size");
|
@ -0,0 +1,81 @@
|
|||||||
|
// 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 System;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Input.Events;
|
||||||
|
using osu.Framework.Utils;
|
||||||
|
using osu.Game.Graphics.Containers;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Misskey.Components.Note.Cards
|
||||||
|
{
|
||||||
|
public partial class ExpandedContentScrollContainer : OsuScrollContainer
|
||||||
|
{
|
||||||
|
public const float HEIGHT = 200;
|
||||||
|
|
||||||
|
protected override ScrollbarContainer CreateScrollbar(Direction direction) => new ExpandedContentScrollbar(direction);
|
||||||
|
|
||||||
|
protected override void Update()
|
||||||
|
{
|
||||||
|
base.Update();
|
||||||
|
|
||||||
|
Height = Math.Min(Content.DrawHeight, HEIGHT);
|
||||||
|
ScrollbarVisible = allowScroll;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool allowScroll => !Precision.AlmostEquals(DrawSize, Content.DrawSize);
|
||||||
|
|
||||||
|
protected override bool OnDragStart(DragStartEvent e)
|
||||||
|
{
|
||||||
|
if (!allowScroll)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return base.OnDragStart(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnDrag(DragEvent e)
|
||||||
|
{
|
||||||
|
if (!allowScroll)
|
||||||
|
return;
|
||||||
|
|
||||||
|
base.OnDrag(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnDragEnd(DragEndEvent e)
|
||||||
|
{
|
||||||
|
if (!allowScroll)
|
||||||
|
return;
|
||||||
|
|
||||||
|
base.OnDragEnd(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool OnScroll(ScrollEvent e)
|
||||||
|
{
|
||||||
|
if (!allowScroll)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return base.OnScroll(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool OnClick(ClickEvent e) => true;
|
||||||
|
|
||||||
|
private partial class ExpandedContentScrollbar : OsuScrollbar
|
||||||
|
{
|
||||||
|
public ExpandedContentScrollbar(Direction scrollDir)
|
||||||
|
: base(scrollDir)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool OnHover(HoverEvent e)
|
||||||
|
{
|
||||||
|
base.OnHover(e);
|
||||||
|
// do not handle hover, as handling hover would make the beatmap card's expanded content not-hovered
|
||||||
|
// and therefore cause it to hide when trying to drag the scroll bar.
|
||||||
|
// see: `BeatmapCardContent.dropdownContent` and its `Unhovered` handler.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
// 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;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Input.Events;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Misskey.Components.Note.Cards
|
||||||
|
{
|
||||||
|
public partial class HoverHandlingContainer : Container
|
||||||
|
{
|
||||||
|
public Func<HoverEvent, bool>? Hovered { get; set; }
|
||||||
|
public Action<HoverLostEvent>? Unhovered { get; set; }
|
||||||
|
|
||||||
|
protected override bool OnHover(HoverEvent e)
|
||||||
|
{
|
||||||
|
bool handledByBase = base.OnHover(e);
|
||||||
|
return Hovered?.Invoke(e) ?? handledByBase;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnHoverLost(HoverLostEvent e)
|
||||||
|
{
|
||||||
|
base.OnHoverLost(e);
|
||||||
|
Unhovered?.Invoke(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
57
osu.Game/Screens/Misskey/Components/Note/Cards/IconPill.cs
Normal file
57
osu.Game/Screens/Misskey/Components/Note/Cards/IconPill.cs
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
// 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.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Cursor;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Framework.Localisation;
|
||||||
|
using osuTK;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Misskey.Components.Note.Cards
|
||||||
|
{
|
||||||
|
public abstract partial class IconPill : CircularContainer, IHasTooltip
|
||||||
|
{
|
||||||
|
public Vector2 IconSize
|
||||||
|
{
|
||||||
|
get => iconContainer.Size;
|
||||||
|
set => iconContainer.Size = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly Container iconContainer;
|
||||||
|
|
||||||
|
protected IconPill(IconUsage icon)
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both;
|
||||||
|
Masking = true;
|
||||||
|
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = Color4.Black,
|
||||||
|
Alpha = 0.5f,
|
||||||
|
},
|
||||||
|
iconContainer = new Container
|
||||||
|
{
|
||||||
|
Size = new Vector2(22),
|
||||||
|
Padding = new MarginPadding(5),
|
||||||
|
Child = new SpriteIcon
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Icon = icon,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract LocalisableString TooltipText { get; }
|
||||||
|
}
|
||||||
|
}
|
@ -13,7 +13,7 @@ using osu.Game.Online;
|
|||||||
using osu.Game.Online.API.Requests.Responses;
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
|
|
||||||
namespace osu.Game.Screens.Misskey.Components
|
namespace osu.Game.Screens.Misskey.Components.Note.Cards
|
||||||
{
|
{
|
||||||
public abstract partial class NoteCard : OsuClickableContainer
|
public abstract partial class NoteCard : OsuClickableContainer
|
||||||
{
|
{
|
||||||
@ -24,38 +24,38 @@ namespace osu.Game.Screens.Misskey.Components
|
|||||||
|
|
||||||
public IBindable<bool> Expanded { get; }
|
public IBindable<bool> Expanded { get; }
|
||||||
|
|
||||||
public readonly APIBeatmapSet BeatmapSet;
|
public readonly Online.MisskeyAPI.Responses.Types.Note Note;
|
||||||
|
|
||||||
protected readonly Bindable<BeatmapSetFavouriteState> FavouriteState;
|
// protected readonly Bindable<BeatmapSetFavouriteState> FavouriteState;
|
||||||
|
|
||||||
protected abstract Drawable IdleContent { get; }
|
protected abstract Drawable IdleContent { get; }
|
||||||
protected abstract Drawable DownloadInProgressContent { get; }
|
protected abstract Drawable DownloadInProgressContent { get; }
|
||||||
|
|
||||||
protected readonly BeatmapDownloadTracker DownloadTracker;
|
// protected readonly BeatmapDownloadTracker DownloadTracker;
|
||||||
|
|
||||||
protected NoteCard(APIBeatmapSet beatmapSet, bool allowExpansion = true)
|
protected NoteCard(Online.MisskeyAPI.Responses.Types.Note note, bool allowExpansion = true)
|
||||||
: base(HoverSampleSet.Button)
|
: base(HoverSampleSet.Button)
|
||||||
{
|
{
|
||||||
Expanded = new BindableBool { Disabled = !allowExpansion };
|
Expanded = new BindableBool { Disabled = !allowExpansion };
|
||||||
|
|
||||||
BeatmapSet = beatmapSet;
|
Note = note;
|
||||||
FavouriteState = new Bindable<BeatmapSetFavouriteState>(new BeatmapSetFavouriteState(beatmapSet.HasFavourited, beatmapSet.FavouriteCount));
|
// FavouriteState = new Bindable<BeatmapSetFavouriteState>(new BeatmapSetFavouriteState(note.HasFavourited, note.FavouriteCount));
|
||||||
DownloadTracker = new BeatmapDownloadTracker(beatmapSet);
|
// DownloadTracker = new BeatmapDownloadTracker(note);
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader(true)]
|
[BackgroundDependencyLoader(true)]
|
||||||
private void load(BeatmapSetOverlay? beatmapSetOverlay)
|
private void load(BeatmapSetOverlay? beatmapSetOverlay)
|
||||||
{
|
{
|
||||||
Action = () => beatmapSetOverlay?.FetchAndShowBeatmapSet(BeatmapSet.OnlineID);
|
// Action = () => beatmapSetOverlay?.FetchAndShowBeatmapSet(Note.OnlineID);
|
||||||
|
|
||||||
AddInternal(DownloadTracker);
|
// AddInternal(DownloadTracker);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
|
||||||
DownloadTracker.State.BindValueChanged(_ => UpdateState());
|
// DownloadTracker.State.BindValueChanged(_ => UpdateState());
|
||||||
Expanded.BindValueChanged(_ => UpdateState(), true);
|
Expanded.BindValueChanged(_ => UpdateState(), true);
|
||||||
FinishTransforms(true);
|
FinishTransforms(true);
|
||||||
}
|
}
|
||||||
@ -74,24 +74,24 @@ namespace osu.Game.Screens.Misskey.Components
|
|||||||
|
|
||||||
protected virtual void UpdateState()
|
protected virtual void UpdateState()
|
||||||
{
|
{
|
||||||
bool showProgress = DownloadTracker.State.Value == DownloadState.Downloading || DownloadTracker.State.Value == DownloadState.Importing;
|
// bool showProgress = DownloadTracker.State.Value == DownloadState.Downloading || DownloadTracker.State.Value == DownloadState.Importing;
|
||||||
|
//
|
||||||
IdleContent.FadeTo(showProgress ? 0 : 1, TRANSITION_DURATION, Easing.OutQuint);
|
// IdleContent.FadeTo(showProgress ? 0 : 1, TRANSITION_DURATION, Easing.OutQuint);
|
||||||
DownloadInProgressContent.FadeTo(showProgress ? 1 : 0, TRANSITION_DURATION, Easing.OutQuint);
|
// DownloadInProgressContent.FadeTo(showProgress ? 1 : 0, TRANSITION_DURATION, Easing.OutQuint);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a beatmap card of the given <paramref name="size"/> for the supplied <paramref name="beatmapSet"/>.
|
/// Creates a beatmap card of the given <paramref name="size"/> for the supplied <paramref name="note"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static BeatmapCard Create(APIBeatmapSet beatmapSet, BeatmapCardSize size, bool allowExpansion = true)
|
public static NoteCard Create(Online.MisskeyAPI.Responses.Types.Note note, BeatmapCardSize size, bool allowExpansion = true)
|
||||||
{
|
{
|
||||||
switch (size)
|
switch (size)
|
||||||
{
|
{
|
||||||
case BeatmapCardSize.Normal:
|
case BeatmapCardSize.Normal:
|
||||||
return new BeatmapCardNormal(beatmapSet, allowExpansion);
|
return new NoteCardNormal(note, allowExpansion);
|
||||||
|
|
||||||
case BeatmapCardSize.Extra:
|
// case BeatmapCardSize.Extra:
|
||||||
return new BeatmapCardExtra(beatmapSet, allowExpansion);
|
// return new BeatmapCardExtra(note, allowExpansion);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new ArgumentOutOfRangeException(nameof(size), size, @"Unsupported card size");
|
throw new ArgumentOutOfRangeException(nameof(size), size, @"Unsupported card size");
|
@ -0,0 +1,75 @@
|
|||||||
|
// 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;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.UserInterface;
|
||||||
|
using osu.Game.Beatmaps.Drawables;
|
||||||
|
using osu.Game.Beatmaps.Drawables.Cards;
|
||||||
|
using osu.Game.Beatmaps.Drawables.Cards.Buttons;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Misskey.Users.Drawables;
|
||||||
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
|
using osu.Game.Online.MisskeyAPI.Responses.Types;
|
||||||
|
using osu.Game.Overlays;
|
||||||
|
using osuTK;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Misskey.Components.Note.Cards
|
||||||
|
{
|
||||||
|
public partial class NoteCardAvatar : Container
|
||||||
|
{
|
||||||
|
public BindableBool Dimmed { get; } = new BindableBool();
|
||||||
|
|
||||||
|
private Drawable avatar;
|
||||||
|
|
||||||
|
private readonly User user;
|
||||||
|
|
||||||
|
|
||||||
|
public NoteCardAvatar(Online.MisskeyAPI.Responses.Types.Note note)
|
||||||
|
{
|
||||||
|
this.user = note.User;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
ClickableAvatar internalAvatar;
|
||||||
|
|
||||||
|
Children = new[]
|
||||||
|
{
|
||||||
|
avatar = new DelayedLoadWrapper(
|
||||||
|
internalAvatar = new ClickableAvatar(user)
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Masking = true,
|
||||||
|
CornerRadius = 50,
|
||||||
|
// EdgeEffect = new EdgeEffectParameters
|
||||||
|
// {
|
||||||
|
// Type = EdgeEffectType.Shadow,
|
||||||
|
// Radius = 1,
|
||||||
|
// Colour = Color4.Black.Opacity(0.2f),
|
||||||
|
// },
|
||||||
|
})
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
// Size = new Vector2(HEIGHT - edge_margin * 2, HEIGHT - edge_margin * 2),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// internalAvatar.OnLoadComplete += d => d.FadeInFromZero(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateState()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,156 @@
|
|||||||
|
// 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.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Framework.Threading;
|
||||||
|
using osu.Game.Beatmaps.Drawables.Cards;
|
||||||
|
using osu.Game.Graphics.Containers;
|
||||||
|
using osu.Game.Overlays;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Misskey.Components.Note.Cards
|
||||||
|
{
|
||||||
|
public partial class NoteCardContent : CompositeDrawable
|
||||||
|
{
|
||||||
|
public Drawable MainContent
|
||||||
|
{
|
||||||
|
set => bodyContent.Child = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Drawable ExpandedContent
|
||||||
|
{
|
||||||
|
set => dropdownScroll.Child = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IBindable<bool> Expanded => expanded;
|
||||||
|
|
||||||
|
private readonly BindableBool expanded = new BindableBool();
|
||||||
|
|
||||||
|
private readonly Box background;
|
||||||
|
private readonly Container content;
|
||||||
|
private readonly Container bodyContent;
|
||||||
|
private readonly Container dropdownContent;
|
||||||
|
private readonly OsuScrollContainer dropdownScroll;
|
||||||
|
private readonly Container borderContainer;
|
||||||
|
|
||||||
|
public NoteCardContent(float height)
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X;
|
||||||
|
Height = height;
|
||||||
|
|
||||||
|
Anchor = Anchor.Centre;
|
||||||
|
Origin = Anchor.Centre;
|
||||||
|
|
||||||
|
InternalChild = content = new HoverHandlingContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
CornerRadius = NoteCard.CORNER_RADIUS,
|
||||||
|
Masking = true,
|
||||||
|
Unhovered = _ => updateFromHoverChange(),
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
background = new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both
|
||||||
|
},
|
||||||
|
bodyContent = new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Height = height,
|
||||||
|
CornerRadius = NoteCard.CORNER_RADIUS,
|
||||||
|
Masking = true,
|
||||||
|
},
|
||||||
|
dropdownContent = new HoverHandlingContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Margin = new MarginPadding { Top = height },
|
||||||
|
Alpha = 0,
|
||||||
|
Hovered = _ =>
|
||||||
|
{
|
||||||
|
updateFromHoverChange();
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
Unhovered = _ => updateFromHoverChange(),
|
||||||
|
Child = dropdownScroll = new ExpandedContentScrollContainer
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
ScrollbarVisible = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
borderContainer = new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
CornerRadius = NoteCard.CORNER_RADIUS,
|
||||||
|
Masking = true,
|
||||||
|
BorderThickness = 3,
|
||||||
|
Child = new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Alpha = 0,
|
||||||
|
AlwaysPresent = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
background.Colour = Colour4.Gray;
|
||||||
|
borderContainer.BorderColour = Colour4.White;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
Expanded.BindValueChanged(_ => updateState(), true);
|
||||||
|
FinishTransforms(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ScheduledDelegate? scheduledExpandedChange;
|
||||||
|
|
||||||
|
public void ExpandAfterDelay() => queueExpandedStateChange(true, 100);
|
||||||
|
|
||||||
|
public void CancelExpand() => scheduledExpandedChange?.Cancel();
|
||||||
|
|
||||||
|
private void updateFromHoverChange() =>
|
||||||
|
queueExpandedStateChange(content.IsHovered || dropdownContent.IsHovered, 100);
|
||||||
|
|
||||||
|
private void queueExpandedStateChange(bool newState, int delay = 0)
|
||||||
|
{
|
||||||
|
if (Expanded.Disabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
scheduledExpandedChange?.Cancel();
|
||||||
|
scheduledExpandedChange = Scheduler.AddDelayed(() => expanded.Value = newState, delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateState()
|
||||||
|
{
|
||||||
|
// Scale value is intentionally chosen to fit in the spacing of listing displays, as to not overlap horizontally with adjacent cards.
|
||||||
|
// This avoids depth issues where a hovered (scaled) card to the right of another card would be beneath the card to the left.
|
||||||
|
this.ScaleTo(Expanded.Value ? 1.03f : 1, 500, Easing.OutQuint);
|
||||||
|
|
||||||
|
background.FadeTo(Expanded.Value ? 1 : 0, NoteCard.TRANSITION_DURATION, Easing.OutQuint);
|
||||||
|
dropdownContent.FadeTo(Expanded.Value ? 1 : 0, NoteCard.TRANSITION_DURATION, Easing.OutQuint);
|
||||||
|
borderContainer.FadeTo(Expanded.Value ? 1 : 0, NoteCard.TRANSITION_DURATION, Easing.OutQuint);
|
||||||
|
|
||||||
|
content.TweenEdgeEffectTo(new EdgeEffectParameters
|
||||||
|
{
|
||||||
|
Type = EdgeEffectType.Shadow,
|
||||||
|
Offset = new Vector2(0, 2),
|
||||||
|
Radius = 10,
|
||||||
|
Colour = Colour4.Black.Opacity(Expanded.Value ? 0.3f : 0f),
|
||||||
|
Hollow = true,
|
||||||
|
}, NoteCard.TRANSITION_DURATION, Easing.OutQuint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -7,19 +7,20 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Localisation;
|
using osu.Framework.Localisation;
|
||||||
using osu.Game.Beatmaps.Drawables.Cards;
|
using osu.Game.Beatmaps.Drawables.Cards;
|
||||||
using osu.Game.Beatmaps.Drawables.Cards.Statistics;
|
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
using osu.Game.Online.API.Requests.Responses;
|
using osu.Game.Online.MisskeyAPI;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Overlays.BeatmapSet;
|
using osu.Game.Overlays.BeatmapSet;
|
||||||
using osuTK;
|
|
||||||
using osu.Game.Resources.Localisation.Web;
|
using osu.Game.Resources.Localisation.Web;
|
||||||
|
using osu.Game.Screens.Misskey.Components.Note.Cards.Statistics;
|
||||||
|
using osu.Game.Skinning.Components;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Screens.Misskey.Components
|
namespace osu.Game.Screens.Misskey.Components.Note.Cards
|
||||||
{
|
{
|
||||||
public partial class NoteCardNormal : DrawableNoteCard
|
public partial class NoteCardNormal : NoteCard
|
||||||
{
|
{
|
||||||
protected override Drawable IdleContent => idleBottomContent;
|
protected override Drawable IdleContent => idleBottomContent;
|
||||||
protected override Drawable DownloadInProgressContent => downloadProgressBar;
|
protected override Drawable DownloadInProgressContent => downloadProgressBar;
|
||||||
@ -27,23 +28,27 @@ namespace osu.Game.Screens.Misskey.Components
|
|||||||
private const float height = 100;
|
private const float height = 100;
|
||||||
|
|
||||||
[Cached]
|
[Cached]
|
||||||
private readonly BeatmapCardContent content;
|
private readonly NoteCardContent content;
|
||||||
|
|
||||||
private BeatmapCardThumbnail thumbnail = null!;
|
private NoteCardAvatar thumbnail = null!;
|
||||||
private CollapsibleButtonContainer buttonContainer = null!;
|
// private CollapsibleButtonContainer buttonContainer = null!;
|
||||||
|
|
||||||
private FillFlowContainer<BeatmapCardStatistic> statisticsContainer = null!;
|
// private FillFlowContainer<BeatmapCardStatistic> statisticsContainer = null!;
|
||||||
|
private TextFlowContainer noteText = null!;
|
||||||
|
|
||||||
private FillFlowContainer idleBottomContent = null!;
|
private FillFlowContainer idleBottomContent = null!;
|
||||||
private BeatmapCardDownloadProgressBar downloadProgressBar = null!;
|
private BeatmapCardDownloadProgressBar downloadProgressBar = null!;
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private OverlayColourProvider colourProvider { get; set; } = null!;
|
private IAPIProvider api { get; set; } = null!;
|
||||||
|
|
||||||
public NoteCardNormal(APIBeatmapSet beatmapSet, bool allowExpansion = true)
|
// [Resolved]
|
||||||
: base(beatmapSet, allowExpansion)
|
// private OverlayColourProvider colourProvider { get; set; } = null!;
|
||||||
|
|
||||||
|
public NoteCardNormal(Online.MisskeyAPI.Responses.Types.Note note, bool allowExpansion = true)
|
||||||
|
: base(note, allowExpansion)
|
||||||
{
|
{
|
||||||
content = new BeatmapCardContent(height);
|
content = new NoteCardContent(height);
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
@ -56,6 +61,9 @@ namespace osu.Game.Screens.Misskey.Components
|
|||||||
FillFlowContainer titleBadgeArea = null!;
|
FillFlowContainer titleBadgeArea = null!;
|
||||||
GridContainer artistContainer = null!;
|
GridContainer artistContainer = null!;
|
||||||
|
|
||||||
|
// LinkFlowContainer titleText = null!;
|
||||||
|
LinkFlowContainer artistText = null!;
|
||||||
|
|
||||||
Child = content.With(c =>
|
Child = content.With(c =>
|
||||||
{
|
{
|
||||||
c.MainContent = new Container
|
c.MainContent = new Container
|
||||||
@ -63,11 +71,11 @@ namespace osu.Game.Screens.Misskey.Components
|
|||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
thumbnail = new BeatmapCardThumbnail(BeatmapSet)
|
thumbnail = new NoteCardAvatar(Note)
|
||||||
{
|
{
|
||||||
Name = @"Left (icon) area",
|
Name = @"Left (icon) area",
|
||||||
Size = new Vector2(height),
|
Size = new Vector2(height - 10),
|
||||||
Padding = new MarginPadding { Right = CORNER_RADIUS },
|
// Padding = new MarginPadding { Right = CORNER_RADIUS },
|
||||||
Child = leftIconArea = new FillFlowContainer
|
Child = leftIconArea = new FillFlowContainer
|
||||||
{
|
{
|
||||||
Margin = new MarginPadding(5),
|
Margin = new MarginPadding(5),
|
||||||
@ -76,17 +84,19 @@ namespace osu.Game.Screens.Misskey.Components
|
|||||||
Spacing = new Vector2(1)
|
Spacing = new Vector2(1)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
buttonContainer = new CollapsibleButtonContainer(BeatmapSet)
|
// buttonContainer = new CollapsibleButtonContainer(Note)
|
||||||
{
|
// {
|
||||||
X = height - CORNER_RADIUS,
|
// X = height - CORNER_RADIUS,
|
||||||
Width = WIDTH - height + CORNER_RADIUS,
|
// Width = WIDTH - height + CORNER_RADIUS,
|
||||||
FavouriteState = { BindTarget = FavouriteState },
|
// // FavouriteState = { BindTarget = FavouriteState },
|
||||||
ButtonsCollapsedWidth = CORNER_RADIUS,
|
// ButtonsCollapsedWidth = CORNER_RADIUS,
|
||||||
ButtonsExpandedWidth = 30,
|
// ButtonsExpandedWidth = 30,
|
||||||
Children = new Drawable[]
|
// Children = new Drawable[]
|
||||||
{
|
// {
|
||||||
new FillFlowContainer
|
new FillFlowContainer
|
||||||
{
|
{
|
||||||
|
// X = height - CORNER_RADIUS,
|
||||||
|
X = height,
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Direction = FillDirection.Vertical,
|
Direction = FillDirection.Vertical,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
@ -108,12 +118,14 @@ namespace osu.Game.Screens.Misskey.Components
|
|||||||
{
|
{
|
||||||
new Drawable[]
|
new Drawable[]
|
||||||
{
|
{
|
||||||
new OsuSpriteText
|
new OsuSpriteText()
|
||||||
{
|
{
|
||||||
Text = new RomanisableString(BeatmapSet.TitleUnicode, BeatmapSet.Title),
|
Text = new RomanisableString(Note.User.Name, Note.User.Username),
|
||||||
Font = OsuFont.Default.With(size: 22.5f, weight: FontWeight.SemiBold),
|
Font = OsuFont.Default.With(size: 22.5f, weight: FontWeight.SemiBold),
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
Truncate = true
|
Truncate = true
|
||||||
|
// Padding = new MarginPadding { Left = SettingsPanel.CONTENT_MARGINS },
|
||||||
|
// AutoSizeAxes = Axes.Y,
|
||||||
},
|
},
|
||||||
titleBadgeArea = new FillFlowContainer
|
titleBadgeArea = new FillFlowContainer
|
||||||
{
|
{
|
||||||
@ -142,28 +154,28 @@ namespace osu.Game.Screens.Misskey.Components
|
|||||||
{
|
{
|
||||||
new[]
|
new[]
|
||||||
{
|
{
|
||||||
new OsuSpriteText
|
artistText = new LinkFlowContainer()
|
||||||
{
|
{
|
||||||
Text = createArtistText(),
|
// Text = createArtistText(),
|
||||||
Font = OsuFont.Default.With(size: 17.5f, weight: FontWeight.SemiBold),
|
// Font = OsuFont.Default.With(size: 17.5f, weight: FontWeight.SemiBold),
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
Truncate = true
|
// Truncate = true
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
},
|
},
|
||||||
Empty()
|
Empty()
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
new LinkFlowContainer(s =>
|
noteText = new TextFlowContainer
|
||||||
{
|
{
|
||||||
s.Shadow = false;
|
RelativeSizeAxes = Axes.X,
|
||||||
s.Font = OsuFont.GetFont(size: 14, weight: FontWeight.SemiBold);
|
AutoSizeAxes = Axes.Y,
|
||||||
}).With(d =>
|
Alpha = 1,
|
||||||
|
AlwaysPresent = true,
|
||||||
|
}.With(flow =>
|
||||||
{
|
{
|
||||||
d.AutoSizeAxes = Axes.Both;
|
flow.AddText(Note.Text, t => t.Font = OsuFont.Default.With(size: 15));
|
||||||
d.Margin = new MarginPadding { Top = 2 };
|
})
|
||||||
d.AddText("mapped by ", t => t.Colour = colourProvider.Content2);
|
|
||||||
d.AddUserLink(BeatmapSet.Author);
|
|
||||||
}),
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
new Container
|
new Container
|
||||||
@ -184,104 +196,97 @@ namespace osu.Game.Screens.Misskey.Components
|
|||||||
AlwaysPresent = true,
|
AlwaysPresent = true,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
statisticsContainer = new FillFlowContainer<BeatmapCardStatistic>
|
// statisticsContainer = new FillFlowContainer<BeatmapCardStatistic>
|
||||||
{
|
// {
|
||||||
RelativeSizeAxes = Axes.X,
|
// RelativeSizeAxes = Axes.X,
|
||||||
AutoSizeAxes = Axes.Y,
|
// AutoSizeAxes = Axes.Y,
|
||||||
Direction = FillDirection.Horizontal,
|
// Direction = FillDirection.Horizontal,
|
||||||
Spacing = new Vector2(10, 0),
|
// Spacing = new Vector2(10, 0),
|
||||||
Alpha = 0,
|
// Alpha = 0,
|
||||||
AlwaysPresent = true,
|
// AlwaysPresent = true,
|
||||||
ChildrenEnumerable = createStatistics()
|
// ChildrenEnumerable = createStatistics()
|
||||||
},
|
// },
|
||||||
new BeatmapCardExtraInfoRow(BeatmapSet)
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
downloadProgressBar = new BeatmapCardDownloadProgressBar
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.X,
|
|
||||||
Height = 6,
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
State = { BindTarget = DownloadTracker.State },
|
|
||||||
Progress = { BindTarget = DownloadTracker.Progress }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
c.ExpandedContent = new Container
|
// c.ExpandedContent = new Container
|
||||||
{
|
// {
|
||||||
RelativeSizeAxes = Axes.X,
|
// RelativeSizeAxes = Axes.X,
|
||||||
AutoSizeAxes = Axes.Y,
|
// AutoSizeAxes = Axes.Y,
|
||||||
Padding = new MarginPadding { Horizontal = 10, Vertical = 13 },
|
// Padding = new MarginPadding { Horizontal = 10, Vertical = 13 },
|
||||||
Child = new BeatmapCardDifficultyList(BeatmapSet)
|
// Child = new BeatmapCardDifficultyList(BeatmapSet)
|
||||||
};
|
// };
|
||||||
c.Expanded.BindTarget = Expanded;
|
c.Expanded.BindTarget = Expanded;
|
||||||
|
// titleText.AddLink(Note.User.Name, $"{api.APIEndpointUrl}@{Note.User.Username}@{Note.User.Host}");
|
||||||
|
artistText.AddLink($"@{Note.User.Username}@{Note.User.Host}", $"{api.APIEndpointUrl}/@{Note.User.Username}@{Note.User.Host}");
|
||||||
});
|
});
|
||||||
|
|
||||||
if (BeatmapSet.HasVideo)
|
// if (BeatmapSet.HasVideo)
|
||||||
leftIconArea.Add(new VideoIconPill { IconSize = new Vector2(20) });
|
// leftIconArea.Add(new VideoIconPill { IconSize = new Vector2(20) });
|
||||||
|
//
|
||||||
|
// if (BeatmapSet.HasStoryboard)
|
||||||
|
// leftIconArea.Add(new StoryboardIconPill { IconSize = new Vector2(20) });
|
||||||
|
//
|
||||||
|
// if (BeatmapSet.FeaturedInSpotlight)
|
||||||
|
// {
|
||||||
|
// titleBadgeArea.Add(new SpotlightBeatmapBadge
|
||||||
|
// {
|
||||||
|
// Anchor = Anchor.BottomRight,
|
||||||
|
// Origin = Anchor.BottomRight,
|
||||||
|
// Margin = new MarginPadding { Left = 5 }
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
if (BeatmapSet.HasStoryboard)
|
// if (BeatmapSet.HasExplicitContent)
|
||||||
leftIconArea.Add(new StoryboardIconPill { IconSize = new Vector2(20) });
|
// {
|
||||||
|
// titleBadgeArea.Add(new ExplicitContentBeatmapBadge
|
||||||
|
// {
|
||||||
|
// Anchor = Anchor.BottomRight,
|
||||||
|
// Origin = Anchor.BottomRight,
|
||||||
|
// Margin = new MarginPadding { Left = 5 }
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
if (BeatmapSet.FeaturedInSpotlight)
|
// if (BeatmapSet.TrackId != null)
|
||||||
{
|
// {
|
||||||
titleBadgeArea.Add(new SpotlightBeatmapBadge
|
// artistContainer.Content[0][1] = new FeaturedArtistBeatmapBadge
|
||||||
{
|
// {
|
||||||
Anchor = Anchor.BottomRight,
|
// Anchor = Anchor.BottomRight,
|
||||||
Origin = Anchor.BottomRight,
|
// Origin = Anchor.BottomRight,
|
||||||
Margin = new MarginPadding { Left = 5 }
|
// Margin = new MarginPadding { Left = 5 }
|
||||||
});
|
// };
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (BeatmapSet.HasExplicitContent)
|
|
||||||
{
|
|
||||||
titleBadgeArea.Add(new ExplicitContentBeatmapBadge
|
|
||||||
{
|
|
||||||
Anchor = Anchor.BottomRight,
|
|
||||||
Origin = Anchor.BottomRight,
|
|
||||||
Margin = new MarginPadding { Left = 5 }
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (BeatmapSet.TrackId != null)
|
|
||||||
{
|
|
||||||
artistContainer.Content[0][1] = new FeaturedArtistBeatmapBadge
|
|
||||||
{
|
|
||||||
Anchor = Anchor.BottomRight,
|
|
||||||
Origin = Anchor.BottomRight,
|
|
||||||
Margin = new MarginPadding { Left = 5 }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private LocalisableString createArtistText()
|
private LocalisableString createArtistText()
|
||||||
{
|
{
|
||||||
var romanisableArtist = new RomanisableString(BeatmapSet.ArtistUnicode, BeatmapSet.Artist);
|
var romanisableArtist = new RomanisableString(Note.User.Username + "@" + Note.User.Host, Note.User.Username + "@" + Note.User.Host);
|
||||||
return BeatmapsetsStrings.ShowDetailsByArtist(romanisableArtist);
|
return romanisableArtist;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<BeatmapCardStatistic> createStatistics()
|
// private IEnumerable<BeatmapCardStatistic> createStatistics()
|
||||||
{
|
// {
|
||||||
var hypesStatistic = HypesStatistic.CreateFor(BeatmapSet);
|
// var hypesStatistic = HypesStatistic.CreateFor(BeatmapSet);
|
||||||
if (hypesStatistic != null)
|
// if (hypesStatistic != null)
|
||||||
yield return hypesStatistic;
|
// yield return hypesStatistic;
|
||||||
|
//
|
||||||
var nominationsStatistic = NominationsStatistic.CreateFor(BeatmapSet);
|
// var nominationsStatistic = NominationsStatistic.CreateFor(BeatmapSet);
|
||||||
if (nominationsStatistic != null)
|
// if (nominationsStatistic != null)
|
||||||
yield return nominationsStatistic;
|
// yield return nominationsStatistic;
|
||||||
|
//
|
||||||
yield return new FavouritesStatistic(BeatmapSet) { Current = FavouriteState };
|
// 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);
|
||||||
if (dateStatistic != null)
|
// if (dateStatistic != null)
|
||||||
yield return dateStatistic;
|
// yield return dateStatistic;
|
||||||
}
|
// }
|
||||||
|
|
||||||
protected override void UpdateState()
|
protected override void UpdateState()
|
||||||
{
|
{
|
||||||
@ -289,10 +294,10 @@ namespace osu.Game.Screens.Misskey.Components
|
|||||||
|
|
||||||
bool showDetails = IsHovered || Expanded.Value;
|
bool showDetails = IsHovered || Expanded.Value;
|
||||||
|
|
||||||
buttonContainer.ShowDetails.Value = showDetails;
|
// buttonContainer.ShowDetails.Value = showDetails;
|
||||||
thumbnail.Dimmed.Value = showDetails;
|
thumbnail.Dimmed.Value = showDetails;
|
||||||
|
|
||||||
statisticsContainer.FadeTo(showDetails ? 1 : 0, TRANSITION_DURATION, Easing.OutQuint);
|
// statisticsContainer.FadeTo(showDetails ? 1 : 0, TRANSITION_DURATION, Easing.OutQuint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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 System;
|
||||||
|
using osu.Framework.Extensions.LocalisationExtensions;
|
||||||
|
using osu.Framework.Graphics.Cursor;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Misskey.Components.Note.Cards.Statistics
|
||||||
|
{
|
||||||
|
public partial 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 BeatmapOnlineStatus.Ranked:
|
||||||
|
case BeatmapOnlineStatus.Approved:
|
||||||
|
case BeatmapOnlineStatus.Loved:
|
||||||
|
case BeatmapOnlineStatus.Qualified:
|
||||||
|
return beatmapSetInfo.Ranked;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return beatmapSetInfo.LastUpdated;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,82 @@
|
|||||||
|
// 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.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.Screens.Misskey.Components.Note.Cards.Statistics
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A single statistic shown on a beatmap card.
|
||||||
|
/// </summary>
|
||||||
|
public abstract partial 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalisableString TooltipText { get; protected 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
|
||||||
|
|
||||||
|
public virtual ITooltip GetCustomTooltip() => null;
|
||||||
|
public virtual object TooltipContent => null;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
// 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 Humanizer;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Extensions.LocalisationExtensions;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Framework.Graphics.UserInterface;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Resources.Localisation.Web;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Misskey.Components.Note.Cards.Statistics
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Shows the number of favourites that a beatmap set has received.
|
||||||
|
/// </summary>
|
||||||
|
public partial 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)
|
||||||
|
{
|
||||||
|
current = new BindableWithCurrent<BeatmapSetFavouriteState>(new BeatmapSetFavouriteState(onlineInfo.HasFavourited, onlineInfo.FavouriteCount));
|
||||||
|
}
|
||||||
|
|
||||||
|
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"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
// 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.Extensions.LocalisationExtensions;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Resources.Localisation.Web;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Misskey.Components.Note.Cards.Statistics
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Shows the number of current hypes that a map has received, as well as the number of hypes required for nomination.
|
||||||
|
/// </summary>
|
||||||
|
public partial class HypesStatistic : BeatmapCardStatistic
|
||||||
|
{
|
||||||
|
private HypesStatistic(BeatmapSetHypeStatus hypeStatus)
|
||||||
|
{
|
||||||
|
Icon = FontAwesome.Solid.Bullhorn;
|
||||||
|
Text = hypeStatus.Current.ToLocalisableString();
|
||||||
|
TooltipText = BeatmapsStrings.HypeRequiredText(hypeStatus.Current.ToLocalisableString(), hypeStatus.Required.ToLocalisableString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HypesStatistic? CreateFor(IBeatmapSetOnlineInfo beatmapSetOnlineInfo)
|
||||||
|
=> beatmapSetOnlineInfo.HypeStatus == null ? null : new HypesStatistic(beatmapSetOnlineInfo.HypeStatus);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
// 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.Extensions.LocalisationExtensions;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Resources.Localisation.Web;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Misskey.Components.Note.Cards.Statistics
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Shows the number of current nominations that a map has received, as well as the number of nominations required for qualification.
|
||||||
|
/// </summary>
|
||||||
|
public partial class NominationsStatistic : BeatmapCardStatistic
|
||||||
|
{
|
||||||
|
private NominationsStatistic(BeatmapSetNominationStatus nominationStatus)
|
||||||
|
{
|
||||||
|
Icon = FontAwesome.Solid.ThumbsUp;
|
||||||
|
Text = nominationStatus.Current.ToLocalisableString();
|
||||||
|
TooltipText = BeatmapsStrings.NominationsRequiredText(nominationStatus.Current.ToLocalisableString(), nominationStatus.Required.ToLocalisableString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static NominationsStatistic? CreateFor(IBeatmapSetOnlineInfo beatmapSetOnlineInfo)
|
||||||
|
// web does not show nominations unless hypes are also present.
|
||||||
|
// see: https://github.com/ppy/osu-web/blob/8ed7d071fd1d3eaa7e43cf0e4ff55ca2fef9c07c/resources/assets/lib/beatmapset-panel.tsx#L443
|
||||||
|
=> beatmapSetOnlineInfo.HypeStatus == null || beatmapSetOnlineInfo.NominationStatus == null ? null : new NominationsStatistic(beatmapSetOnlineInfo.NominationStatus);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
// 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 Humanizer;
|
||||||
|
using osu.Framework.Extensions.LocalisationExtensions;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Resources.Localisation.Web;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Misskey.Components.Note.Cards.Statistics
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Shows the number of times the given beatmap set has been played.
|
||||||
|
/// </summary>
|
||||||
|
public partial class PlayCountStatistic : BeatmapCardStatistic
|
||||||
|
{
|
||||||
|
public PlayCountStatistic(IBeatmapSetOnlineInfo onlineInfo)
|
||||||
|
{
|
||||||
|
Icon = FontAwesome.Regular.PlayCircle;
|
||||||
|
Text = onlineInfo.PlayCount.ToMetric(decimals: 1);
|
||||||
|
TooltipText = BeatmapsStrings.PanelPlaycount(onlineInfo.PlayCount.ToLocalisableString(@"N0"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
// 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.Graphics.Sprites;
|
||||||
|
using osu.Framework.Localisation;
|
||||||
|
using osu.Game.Resources.Localisation.Web;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Misskey.Components.Note.Cards
|
||||||
|
{
|
||||||
|
public partial class StoryboardIconPill : IconPill
|
||||||
|
{
|
||||||
|
public StoryboardIconPill()
|
||||||
|
: base(FontAwesome.Solid.Image)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override LocalisableString TooltipText => BeatmapsetsStrings.ShowInfoStoryboard;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
// 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.Graphics.Sprites;
|
||||||
|
using osu.Framework.Localisation;
|
||||||
|
using osu.Game.Resources.Localisation.Web;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Misskey.Components.Note.Cards
|
||||||
|
{
|
||||||
|
public partial class VideoIconPill : IconPill
|
||||||
|
{
|
||||||
|
public VideoIconPill()
|
||||||
|
: base(FontAwesome.Solid.Film)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override LocalisableString TooltipText => BeatmapsetsStrings.ShowInfoVideo;
|
||||||
|
}
|
||||||
|
}
|
@ -6,6 +6,7 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Extensions.LocalisationExtensions;
|
using osu.Framework.Extensions.LocalisationExtensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Graphics.UserInterface;
|
using osu.Framework.Graphics.UserInterface;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
@ -16,6 +17,7 @@ using osu.Game.Online.MisskeyAPI;
|
|||||||
using osu.Game.Misskey.Overlays.Settings;
|
using osu.Game.Misskey.Overlays.Settings;
|
||||||
using osu.Game.Online.MisskeyAPI.Requests.Notes;
|
using osu.Game.Online.MisskeyAPI.Requests.Notes;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
|
using osu.Game.Overlays.Notifications;
|
||||||
using osu.Game.Overlays.OSD;
|
using osu.Game.Overlays.OSD;
|
||||||
using osu.Game.Resources.Localisation.Web;
|
using osu.Game.Resources.Localisation.Web;
|
||||||
using osu.Game.Screens.Misskey;
|
using osu.Game.Screens.Misskey;
|
||||||
@ -26,6 +28,8 @@ namespace osu.Game.Screens.Misskey.Components
|
|||||||
public partial class PostForm : FillFlowContainer
|
public partial class PostForm : FillFlowContainer
|
||||||
{
|
{
|
||||||
private OnScreenDisplay? onScreenDisplay { get; set; }
|
private OnScreenDisplay? onScreenDisplay { get; set; }
|
||||||
|
[Resolved(CanBeNull = true)]
|
||||||
|
private INotificationOverlay? notifications { get; set; }
|
||||||
private partial class ResToast : Toast
|
private partial class ResToast : Toast
|
||||||
{
|
{
|
||||||
public ResToast(string value, string desc)
|
public ResToast(string value, string desc)
|
||||||
@ -57,11 +61,20 @@ namespace osu.Game.Screens.Misskey.Components
|
|||||||
{
|
{
|
||||||
textBox.Text = string.Empty;
|
textBox.Text = string.Empty;
|
||||||
cwBox.Text = string.Empty;
|
cwBox.Text = string.Empty;
|
||||||
onScreenDisplay?.Display(new ResToast("投稿しました", createReq.CompletionState.ToString()));
|
notifications?.Post(new SimpleNotification
|
||||||
|
{
|
||||||
|
Text = "投稿しました",
|
||||||
|
Icon = FontAwesome.Solid.Check,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
api.Queue(createReq);
|
api.Queue(createReq);
|
||||||
onScreenDisplay?.Display(new ResToast("送信しています", ""));
|
notifications?.Post(new SimpleNotification
|
||||||
|
{
|
||||||
|
Text = "送信しています",
|
||||||
|
Icon = FontAwesome.Solid.PaperPlane,
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader(permitNulls: true)]
|
[BackgroundDependencyLoader(permitNulls: true)]
|
||||||
@ -128,15 +141,14 @@ namespace osu.Game.Screens.Misskey.Components
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// new SettingsButton
|
new SettingsButton
|
||||||
// {
|
{
|
||||||
// Text = "Register",
|
Text = "test",
|
||||||
// Action = () =>
|
Action = () =>
|
||||||
// {
|
{
|
||||||
// RequestHide?.Invoke();
|
onScreenDisplay?.Display(new ResToast("送信しています", ""));
|
||||||
// accountCreation.Show();
|
}
|
||||||
// }
|
}
|
||||||
// }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// forgottenPaswordLink.AddLink(LayoutStrings.PopupLoginLoginForgot, $"https://simkey.net/about");
|
// forgottenPaswordLink.AddLink(LayoutStrings.PopupLoginLoginForgot, $"https://simkey.net/about");
|
||||||
|
@ -20,7 +20,7 @@ namespace osu.Game.Screens.Misskey
|
|||||||
public partial class MisskeyComponents : OsuScreen
|
public partial class MisskeyComponents : OsuScreen
|
||||||
{
|
{
|
||||||
private Container contentContainer;
|
private Container contentContainer;
|
||||||
private Drawable avatar;
|
// private Drawable avatar;
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private OsuColour colours { get; set; }
|
private OsuColour colours { get; set; }
|
||||||
@ -44,23 +44,23 @@ namespace osu.Game.Screens.Misskey
|
|||||||
Colour = Color4.Black,
|
Colour = Color4.Black,
|
||||||
Alpha = 0.6f,
|
Alpha = 0.6f,
|
||||||
},
|
},
|
||||||
new Container
|
// new Container
|
||||||
{
|
// {
|
||||||
// RelativeSizeAxes = Axes.Both,
|
// // RelativeSizeAxes = Axes.Both,
|
||||||
// AutoSizeAxes = Axes.Y,
|
// // AutoSizeAxes = Axes.Y,
|
||||||
Size = new Vector2(200),
|
// Size = new Vector2(200),
|
||||||
Masking = true,
|
// Masking = true,
|
||||||
CornerRadius = 100,
|
// CornerRadius = 100,
|
||||||
AutoSizeEasing = Easing.OutQuint,
|
// AutoSizeEasing = Easing.OutQuint,
|
||||||
Children = new Drawable[]
|
// Children = new Drawable[]
|
||||||
{
|
// {
|
||||||
avatar = new DelayedLoadWrapper(
|
// avatar = new DelayedLoadWrapper(
|
||||||
new Avatar()
|
// new Avatar()
|
||||||
{
|
// {
|
||||||
RelativeSizeAxes = Axes.Both,
|
// RelativeSizeAxes = Axes.Both,
|
||||||
})
|
// })
|
||||||
},
|
// },
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -98,14 +98,14 @@ namespace osu.Game.Screens.Misskey
|
|||||||
Text = "MisskeyLogin",
|
Text = "MisskeyLogin",
|
||||||
Action = () => this.Push(new MisskeyLogin())
|
Action = () => this.Push(new MisskeyLogin())
|
||||||
},
|
},
|
||||||
// new OsuButton()
|
new OsuButton()
|
||||||
// {
|
{
|
||||||
// Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
// Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
// Size = new Vector2(500f, 50f),
|
Size = new Vector2(500f, 50f),
|
||||||
// Text = "Timeline",
|
Text = "Timeline",
|
||||||
// Action = () => this.Push(new Timeline())
|
Action = () => this.Push(new Timeline())
|
||||||
// },
|
},
|
||||||
new OsuButton()
|
new OsuButton()
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
|
303
osu.Game/Screens/Misskey/Timeline.cs
Normal file
303
osu.Game/Screens/Misskey/Timeline.cs
Normal file
@ -0,0 +1,303 @@
|
|||||||
|
// 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 System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Framework.Graphics.Textures;
|
||||||
|
using osu.Framework.Input.Events;
|
||||||
|
using osu.Framework.Localisation;
|
||||||
|
using osu.Game.Audio;
|
||||||
|
using osu.Game.Beatmaps.Drawables.Cards;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Graphics.Containers;
|
||||||
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
using osu.Game.Online.API;
|
||||||
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
|
using osu.Game.Online.MisskeyAPI.Requests.Notes;
|
||||||
|
using osu.Game.Online.MisskeyAPI.Responses.Types;
|
||||||
|
using osu.Game.Overlays;
|
||||||
|
using osu.Game.Overlays.BeatmapListing;
|
||||||
|
using osu.Game.Resources.Localisation.Web;
|
||||||
|
using osu.Game.Screens.Misskey.Components;
|
||||||
|
using osuTK;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
using ExpandedContentScrollContainer = osu.Game.Screens.Misskey.Components.Note.Cards.ExpandedContentScrollContainer;
|
||||||
|
using IAPIProvider = osu.Game.Online.MisskeyAPI.IAPIProvider;
|
||||||
|
using NoteCard = osu.Game.Screens.Misskey.Components.Note.Cards.NoteCard;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Misskey
|
||||||
|
{
|
||||||
|
public partial class Timeline : OsuScreen
|
||||||
|
{
|
||||||
|
// [Cached]
|
||||||
|
// protected readonly OsuScrollContainer ScrollFlow;
|
||||||
|
|
||||||
|
protected readonly LoadingLayer Loading;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private PreviewTrackManager previewTrackManager { get; set; }
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private IAPIProvider api { get; set; }
|
||||||
|
|
||||||
|
private OsuScrollContainer panelTarget;
|
||||||
|
private FillFlowContainer<NoteCard> foundContent;
|
||||||
|
|
||||||
|
private int page = 0;
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
InternalChild = new FillFlowContainer
|
||||||
|
{
|
||||||
|
Margin = new MarginPadding(10f),
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Direction = FillDirection.Vertical,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = OsuColour.Gray(0.1f)
|
||||||
|
},
|
||||||
|
panelTarget = new OsuScrollContainer()
|
||||||
|
{
|
||||||
|
Height = 750f,
|
||||||
|
Width = 600f,
|
||||||
|
Anchor = Anchor.TopCentre,
|
||||||
|
Origin = Anchor.TopCentre,
|
||||||
|
// RelativeSizeAxes = Axes.X,
|
||||||
|
Masking = true,
|
||||||
|
Padding = new MarginPadding { Horizontal = 20 },
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private string lastNoteID;
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
var req = new HybridTimeline(api.AccessToken);
|
||||||
|
req.Success += res =>
|
||||||
|
{
|
||||||
|
onSearchFinished(res);
|
||||||
|
lastNoteID = res.Last().Id;
|
||||||
|
};
|
||||||
|
onSearchStarted();
|
||||||
|
api.Queue(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
private CancellationTokenSource cancellationToken;
|
||||||
|
|
||||||
|
private Task panelLoadTask;
|
||||||
|
|
||||||
|
private void onSearchStarted()
|
||||||
|
{
|
||||||
|
cancellationToken?.Cancel();
|
||||||
|
|
||||||
|
// if (panelTarget.Any())
|
||||||
|
// Loading.Show();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onSearchFinished(Note[] searchResult)
|
||||||
|
{
|
||||||
|
cancellationToken?.Cancel();
|
||||||
|
|
||||||
|
var newCards = createCardsFor(searchResult);
|
||||||
|
|
||||||
|
if (page == 0)
|
||||||
|
{
|
||||||
|
//No matches case
|
||||||
|
if (!newCards.Any())
|
||||||
|
{
|
||||||
|
replaceResultsAreaContent(new NotFoundDrawable());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var content = createCardContainerFor(newCards);
|
||||||
|
|
||||||
|
panelLoadTask = LoadComponentAsync(foundContent = content, replaceResultsAreaContent, (cancellationToken = new CancellationTokenSource()).Token);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// new results may contain beatmaps from a previous page,
|
||||||
|
// this is dodgy but matches web behaviour for now.
|
||||||
|
// see: https://github.com/ppy/osu-web/issues/9270
|
||||||
|
// todo: replace custom equality compraer with ExceptBy in net6.0
|
||||||
|
// newCards = newCards.ExceptBy(foundContent.Select(c => c.BeatmapSet.OnlineID), c => c.BeatmapSet.OnlineID);
|
||||||
|
// newCards = newCards.Except(foundContent, BeatmapCardEqualityComparer.Default);
|
||||||
|
|
||||||
|
panelLoadTask = LoadComponentsAsync(newCards, loaded =>
|
||||||
|
{
|
||||||
|
lastFetchDisplayedTime = Time.Current;
|
||||||
|
foundContent.AddRange(loaded);
|
||||||
|
loaded.ForEach(p => p.FadeIn(200, Easing.OutQuint));
|
||||||
|
}, (cancellationToken = new CancellationTokenSource()).Token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<NoteCard> createCardsFor(Note[] notes) =>
|
||||||
|
notes.Select(set =>
|
||||||
|
NoteCard.Create(set, BeatmapCardSize.Normal).With(c =>
|
||||||
|
{
|
||||||
|
c.Anchor = Anchor.TopCentre;
|
||||||
|
c.Origin = Anchor.TopCentre;
|
||||||
|
})).ToArray();
|
||||||
|
|
||||||
|
private static ReverseChildIDFillFlowContainer<NoteCard> createCardContainerFor(IEnumerable<NoteCard> newCards)
|
||||||
|
{
|
||||||
|
// spawn new children with the contained so we only clear old content at the last moment.
|
||||||
|
// reverse ID flow is required for correct Z-ordering of the cards' expandable content (last card should be front-most).
|
||||||
|
var content = new ReverseChildIDFillFlowContainer<NoteCard>
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Spacing = new Vector2(10),
|
||||||
|
Alpha = 0,
|
||||||
|
Margin = new MarginPadding
|
||||||
|
{
|
||||||
|
Top = 15,
|
||||||
|
// the + 20 adjustment is roughly eyeballed in order to fit all of the expanded content height after it's scaled
|
||||||
|
// as well as provide visual balance to the top margin.
|
||||||
|
Bottom = ExpandedContentScrollContainer.HEIGHT + 20
|
||||||
|
},
|
||||||
|
ChildrenEnumerable = newCards
|
||||||
|
};
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void replaceResultsAreaContent(Drawable content)
|
||||||
|
{
|
||||||
|
// Loading.Hide();
|
||||||
|
lastFetchDisplayedTime = Time.Current;
|
||||||
|
|
||||||
|
panelTarget.Child = content;
|
||||||
|
|
||||||
|
content.FadeInFromZero();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool isDisposing)
|
||||||
|
{
|
||||||
|
cancellationToken?.Cancel();
|
||||||
|
base.Dispose(isDisposing);
|
||||||
|
}
|
||||||
|
|
||||||
|
public partial class NotFoundDrawable : CompositeDrawable
|
||||||
|
{
|
||||||
|
public NotFoundDrawable()
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X;
|
||||||
|
Height = 250;
|
||||||
|
Alpha = 0;
|
||||||
|
Margin = new MarginPadding { Top = 15 };
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(LargeTextureStore textures)
|
||||||
|
{
|
||||||
|
AddInternal(new FillFlowContainer
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
AutoSizeAxes = Axes.X,
|
||||||
|
Direction = FillDirection.Horizontal,
|
||||||
|
Spacing = new Vector2(10, 0),
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new Sprite
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
FillMode = FillMode.Fit,
|
||||||
|
Texture = textures.Get(@"Online/not-found")
|
||||||
|
},
|
||||||
|
new OsuSpriteText
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Text = BeatmapsStrings.ListingSearchNotFoundQuote,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: localisation requires Text/LinkFlowContainer support for localising strings with links inside
|
||||||
|
// (https://github.com/ppy/osu-framework/issues/4530)
|
||||||
|
|
||||||
|
private const double time_between_fetches = 500;
|
||||||
|
|
||||||
|
private double lastFetchDisplayedTime;
|
||||||
|
|
||||||
|
protected override void Update()
|
||||||
|
{
|
||||||
|
base.Update();
|
||||||
|
|
||||||
|
const int pagination_scroll_distance = 200;
|
||||||
|
|
||||||
|
bool shouldShowMore = panelLoadTask?.IsCompleted != false
|
||||||
|
&& Time.Current - lastFetchDisplayedTime > time_between_fetches
|
||||||
|
&& (panelTarget.ScrollableExtent > 0 && panelTarget.IsScrolledToEnd(pagination_scroll_distance));
|
||||||
|
|
||||||
|
if (shouldShowMore)
|
||||||
|
FetchNextPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool locked;
|
||||||
|
private void FetchNextPage()
|
||||||
|
{
|
||||||
|
if (locked)
|
||||||
|
return;
|
||||||
|
var req = new HybridTimeline(api.AccessToken, lastNoteID);
|
||||||
|
req.Success += res =>
|
||||||
|
{
|
||||||
|
lastNoteID = res.Last().Id;
|
||||||
|
page++;
|
||||||
|
onSearchFinished(res);
|
||||||
|
locked = false;
|
||||||
|
};
|
||||||
|
api.Queue(req);
|
||||||
|
locked = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class BeatmapCardEqualityComparer : IEqualityComparer<BeatmapCard>
|
||||||
|
{
|
||||||
|
public static BeatmapCardEqualityComparer Default { get; } = new BeatmapCardEqualityComparer();
|
||||||
|
|
||||||
|
public bool Equals(BeatmapCard x, BeatmapCard y)
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(x, y)) return true;
|
||||||
|
if (ReferenceEquals(x, null)) return false;
|
||||||
|
if (ReferenceEquals(y, null)) return false;
|
||||||
|
|
||||||
|
return x.BeatmapSet.Equals(y.BeatmapSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GetHashCode(BeatmapCard obj) => obj.BeatmapSet.GetHashCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -147,7 +147,7 @@ namespace osu.Game.Screens.Misskey
|
|||||||
Origin = Anchor.TopCentre,
|
Origin = Anchor.TopCentre,
|
||||||
Margin = new MarginPadding(100),
|
Margin = new MarginPadding(100),
|
||||||
Width = 400f,
|
Width = 400f,
|
||||||
Text = "Misskey.io は、地球で生まれた分散マイクロブログSNSです。Fediverse(様々なSNSで構成される宇宙)の中に存在するため、他のSNSと相互に繋がっています。\n暫し都会の喧騒から離れて、新しいインターネットにダイブしてみませんか。",
|
Text = "Misskey.。Fediverse(様々なSNSで構成される宇宙)の中に存在するため、他のSNSと相互に繋がっています。\n暫し都会の喧騒から離れて、新しいインターネットにダイブしてみませんか。",
|
||||||
Font = new FontUsage(size: 20),
|
Font = new FontUsage(size: 20),
|
||||||
Colour = Colour4.White,
|
Colour = Colour4.White,
|
||||||
},
|
},
|
||||||
|
@ -45,4 +45,7 @@
|
|||||||
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
|
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
|
||||||
<PackageReference Include="TagLibSharp" Version="2.3.0" />
|
<PackageReference Include="TagLibSharp" Version="2.3.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Folder Include="Online\MisskeyAPI\Responses\Notes" />
|
||||||
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user