diff --git a/osu.Game/Misskey/Users/Drawables/ClickableAvatar.cs b/osu.Game/Misskey/Users/Drawables/ClickableAvatar.cs
index c123b6d986..db0fccd88e 100644
--- a/osu.Game/Misskey/Users/Drawables/ClickableAvatar.cs
+++ b/osu.Game/Misskey/Users/Drawables/ClickableAvatar.cs
@@ -11,6 +11,7 @@ using osu.Framework.Localisation;
using osu.Game.Graphics.Containers;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.MisskeyAPI.Requests.Responses;
+using osu.Game.Online.MisskeyAPI.Responses.Types;
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;
}
- private readonly I user;
+ private readonly User user;
[Resolved(CanBeNull = true)]
private OsuGame game { get; set; }
@@ -47,7 +48,7 @@ namespace osu.Game.Misskey.Users.Drawables
/// If is true, clicking will open the user's profile.
///
/// The user. A null value will get a placeholder avatar.
- public ClickableAvatar(I user = null)
+ public ClickableAvatar(User user = null)
{
this.user = user;
@@ -66,6 +67,11 @@ namespace osu.Game.Misskey.Users.Drawables
LoadComponentAsync(new DrawableAvatar(user), clickableArea.Add);
}
+ protected override void LoadComplete()
+ {
+ CornerRadius = DrawHeight / 2;
+ }
+
private void openProfile()
{
// if (!string.IsNullOrEmpty(user?.Username))
diff --git a/osu.Game/Misskey/Users/Drawables/DrawableAvatar.cs b/osu.Game/Misskey/Users/Drawables/DrawableAvatar.cs
index f58cd927ec..598c9e5dea 100644
--- a/osu.Game/Misskey/Users/Drawables/DrawableAvatar.cs
+++ b/osu.Game/Misskey/Users/Drawables/DrawableAvatar.cs
@@ -9,19 +9,20 @@ using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.MisskeyAPI.Requests.Responses;
+using osu.Game.Online.MisskeyAPI.Responses.Types;
namespace osu.Game.Misskey.Users.Drawables
{
[LongRunningLoad]
public partial class DrawableAvatar : Sprite
{
- private readonly I user;
+ private readonly User user;
///
/// A simple, non-interactable avatar sprite for the specified user.
///
/// The user. A null value will get a placeholder avatar.
- public DrawableAvatar(I user = null)
+ public DrawableAvatar(User user = null)
{
this.user = user;
diff --git a/osu.Game/Misskey/Users/Drawables/UpdateableAvatar.cs b/osu.Game/Misskey/Users/Drawables/UpdateableAvatar.cs
index 849f894a9b..1af7b99957 100644
--- a/osu.Game/Misskey/Users/Drawables/UpdateableAvatar.cs
+++ b/osu.Game/Misskey/Users/Drawables/UpdateableAvatar.cs
@@ -8,15 +8,16 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.MisskeyAPI.Requests.Responses;
+using osu.Game.Online.MisskeyAPI.Responses.Types;
namespace osu.Game.Misskey.Users.Drawables
{
///
/// An avatar which can update to a new user when needed.
///
- public partial class UpdateableAvatar : ModelBackedDrawable
+ public partial class UpdateableAvatar : ModelBackedDrawable
{
- public I User
+ public User User
{
get => Model;
set => Model = value;
@@ -59,7 +60,7 @@ namespace osu.Game.Misskey.Users.Drawables
/// If set to true, hover/click sounds will play and clicking the avatar will open the user's profile.
/// Whether to show the username rather than "view profile" on the tooltip. (note: this only applies if is also true)
/// Whether to show a default guest representation on null user (as opposed to nothing).
- 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.showUsernameTooltip = showUsernameTooltip;
@@ -68,7 +69,7 @@ namespace osu.Game.Misskey.Users.Drawables
User = user;
}
- protected override Drawable CreateDrawable(I user)
+ protected override Drawable CreateDrawable(User user)
{
if (user == null && !showGuestOnNull)
return null;
diff --git a/osu.Game/Misskey/Users/ExtendedUserPanel.cs b/osu.Game/Misskey/Users/ExtendedUserPanel.cs
index 36dec24412..0fd61411be 100644
--- a/osu.Game/Misskey/Users/ExtendedUserPanel.cs
+++ b/osu.Game/Misskey/Users/ExtendedUserPanel.cs
@@ -15,6 +15,7 @@ using osu.Game.Misskey.Users.Drawables;
using osu.Framework.Input.Events;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.MisskeyAPI.Requests.Responses;
+using osu.Game.Online.MisskeyAPI.Responses.Types;
namespace osu.Game.Misskey.Users
{
@@ -29,7 +30,7 @@ namespace osu.Game.Misskey.Users
private SpriteIcon statusIcon;
private OsuSpriteText statusMessage;
- protected ExtendedUserPanel(I user)
+ protected ExtendedUserPanel(User user)
: base(user)
{
}
diff --git a/osu.Game/Misskey/Users/UserCoverBackground.cs b/osu.Game/Misskey/Users/UserCoverBackground.cs
index 62dabb1d2f..827eef252d 100644
--- a/osu.Game/Misskey/Users/UserCoverBackground.cs
+++ b/osu.Game/Misskey/Users/UserCoverBackground.cs
@@ -14,19 +14,20 @@ using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.MisskeyAPI.Requests.Responses;
+using osu.Game.Online.MisskeyAPI.Responses.Types;
using osuTK.Graphics;
namespace osu.Game.Misskey.Users
{
- public partial class UserCoverBackground : ModelBackedDrawable
+ public partial class UserCoverBackground : ModelBackedDrawable
{
- public I User
+ public User User
{
get => Model;
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;
@@ -41,9 +42,9 @@ namespace osu.Game.Misskey.Users
[LongRunningLoad]
private partial class Cover : CompositeDrawable
{
- private readonly I user;
+ private readonly User user;
- public Cover(I user)
+ public Cover(User user)
{
this.user = user;
diff --git a/osu.Game/Misskey/Users/UserGridPanel.cs b/osu.Game/Misskey/Users/UserGridPanel.cs
index 742212532f..2b38d2ceb3 100644
--- a/osu.Game/Misskey/Users/UserGridPanel.cs
+++ b/osu.Game/Misskey/Users/UserGridPanel.cs
@@ -8,6 +8,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.MisskeyAPI.Requests.Responses;
+using osu.Game.Online.MisskeyAPI.Responses.Types;
using osu.Game.Overlays.Profile.Header.Components;
using osuTK;
@@ -17,7 +18,7 @@ namespace osu.Game.Misskey.Users
{
private const int margin = 10;
- public UserGridPanel(I user)
+ public UserGridPanel(User user)
: base(user)
{
Height = 120;
diff --git a/osu.Game/Misskey/Users/UserListPanel.cs b/osu.Game/Misskey/Users/UserListPanel.cs
index 57b751a5b5..55da87f9c2 100644
--- a/osu.Game/Misskey/Users/UserListPanel.cs
+++ b/osu.Game/Misskey/Users/UserListPanel.cs
@@ -11,6 +11,7 @@ using osuTK.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.MisskeyAPI.Requests.Responses;
+using osu.Game.Online.MisskeyAPI.Responses.Types;
using osuTK;
using osu.Game.Overlays.Profile.Header.Components;
@@ -18,7 +19,7 @@ namespace osu.Game.Misskey.Users
{
public partial class UserListPanel : ExtendedUserPanel
{
- public UserListPanel(I user)
+ public UserListPanel(User user)
: base(user)
{
RelativeSizeAxes = Axes.X;
diff --git a/osu.Game/Misskey/Users/UserPanel.cs b/osu.Game/Misskey/Users/UserPanel.cs
index 0d073471a9..594d06f8d7 100644
--- a/osu.Game/Misskey/Users/UserPanel.cs
+++ b/osu.Game/Misskey/Users/UserPanel.cs
@@ -17,12 +17,13 @@ using osu.Game.Graphics.Containers;
using JetBrains.Annotations;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.MisskeyAPI.Requests.Responses;
+using osu.Game.Online.MisskeyAPI.Responses.Types;
namespace osu.Game.Misskey.Users
{
public abstract partial class UserPanel : OsuClickableContainer, IHasContextMenu
{
- public readonly I User;
+ public readonly User User;
///
/// 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 UserPanel(I user)
+ protected UserPanel(User user)
: base(HoverSampleSet.Button)
{
if (user == null)
diff --git a/osu.Game/Online/MisskeyAPI/APIAccess.cs b/osu.Game/Online/MisskeyAPI/APIAccess.cs
index d2cd2e7d93..070e83f321 100644
--- a/osu.Game/Online/MisskeyAPI/APIAccess.cs
+++ b/osu.Game/Online/MisskeyAPI/APIAccess.cs
@@ -18,9 +18,12 @@ using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Graphics;
using osu.Framework.Logging;
using osu.Game.Configuration;
+using osu.Game.Misskey.Users;
using osu.Game.Online.MisskeyAPI.Requests;
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
{
@@ -44,10 +47,10 @@ namespace osu.Game.Online.MisskeyAPI
private string password;
- public IBindable LocalUser => localUser;
+ public IBindable LocalUser => localUser;
public IBindable Activity => activity;
- private Bindable localUser { get; } = new Bindable(createGuestUser());
+ private Bindable localUser { get; } = new Bindable(createGuestUser());
private Bindable activity { get; } = new Bindable();
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)
{
log.Add(@"Queueing a ping request");
- Queue(new Requests.I(AccessToken));
+ Queue(new Requests.User(AccessToken));
}
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 =>
{
@@ -428,7 +431,7 @@ namespace osu.Game.Online.MisskeyAPI
flushQueue();
}
- private static Requests.Responses.I createGuestUser() => new GuestUser();
+ private static User createGuestUser() => new GuestUser();
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()
{
diff --git a/osu.Game/Online/MisskeyAPI/APIRequest.cs b/osu.Game/Online/MisskeyAPI/APIRequest.cs
index 1b0704f384..a963ebf9ef 100644
--- a/osu.Game/Online/MisskeyAPI/APIRequest.cs
+++ b/osu.Game/Online/MisskeyAPI/APIRequest.cs
@@ -12,6 +12,7 @@ using Newtonsoft.Json;
using osu.Framework.IO.Network;
using osu.Framework.Logging;
using osu.Game.Online.MisskeyAPI.Requests.Responses;
+using osu.Game.Online.MisskeyAPI.Responses.Types;
namespace osu.Game.Online.MisskeyAPI
{
@@ -85,7 +86,7 @@ namespace osu.Game.Online.MisskeyAPI
////
//// The currently logged in user. Note that this will only be populated during .
////
- protected I User { get; private set; }
+ protected User User { get; private set; }
///
/// Invoked on successful completion of an API request.
diff --git a/osu.Game/Online/MisskeyAPI/IAPIProvider.cs b/osu.Game/Online/MisskeyAPI/IAPIProvider.cs
index 3d1e8cbedb..862f6f6760 100644
--- a/osu.Game/Online/MisskeyAPI/IAPIProvider.cs
+++ b/osu.Game/Online/MisskeyAPI/IAPIProvider.cs
@@ -7,6 +7,7 @@ using System;
using System.Threading.Tasks;
using osu.Framework.Bindables;
using osu.Game.Online.MisskeyAPI.Requests.Responses;
+using osu.Game.Online.MisskeyAPI.Responses.Types;
using osu.Game.Users;
namespace osu.Game.Online.MisskeyAPI
@@ -17,7 +18,7 @@ namespace osu.Game.Online.MisskeyAPI
/// The local user.
/// This is not thread-safe and should be scheduled locally if consumed from a drawable component.
///
- IBindable LocalUser { get; }
+ IBindable LocalUser { get; }
///
/// The current user's activity.
diff --git a/osu.Game/Online/MisskeyAPI/Requests/I/I.cs b/osu.Game/Online/MisskeyAPI/Requests/I/I.cs
index 18b830c9c3..e1389f5f69 100644
--- a/osu.Game/Online/MisskeyAPI/Requests/I/I.cs
+++ b/osu.Game/Online/MisskeyAPI/Requests/I/I.cs
@@ -8,12 +8,12 @@ using osu.Framework.IO.Network;
namespace osu.Game.Online.MisskeyAPI.Requests
{
- public class I : APIRequest
+ public class User : APIRequest
{
private string i;
- public I(string i)
+ public User(string i)
{
this.i = i;
}
diff --git a/osu.Game/Online/MisskeyAPI/Requests/Notes/Create.cs b/osu.Game/Online/MisskeyAPI/Requests/Notes/Create.cs
index 45b83423d4..a053415a06 100644
--- a/osu.Game/Online/MisskeyAPI/Requests/Notes/Create.cs
+++ b/osu.Game/Online/MisskeyAPI/Requests/Notes/Create.cs
@@ -13,17 +13,25 @@ namespace osu.Game.Online.MisskeyAPI.Requests.Notes
{
private string text;
private string i;
+ private string? cw;
public Create(string i, string Text)
{
- this.text = Text;
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
{
public string? text;
public string? i;
+ public string? cw;
};
protected override WebRequest CreateWebRequest()
{
@@ -34,6 +42,10 @@ namespace osu.Game.Online.MisskeyAPI.Requests.Notes
text = text,
i = i
};
+ if (cw != null)
+ {
+ body.cw = cw;
+ }
var json = JsonConvert.SerializeObject(body);
Logger.Log(json, LoggingTarget.Network, LogLevel.Debug);
req.AddRaw(json);
diff --git a/osu.Game/Online/MisskeyAPI/Requests/Notes/HybridTimeline.cs b/osu.Game/Online/MisskeyAPI/Requests/Notes/HybridTimeline.cs
index 13e5a4d48e..054b80b41a 100644
--- a/osu.Game/Online/MisskeyAPI/Requests/Notes/HybridTimeline.cs
+++ b/osu.Game/Online/MisskeyAPI/Requests/Notes/HybridTimeline.cs
@@ -6,41 +6,46 @@ using System.Net.Http;
using JetBrains.Annotations;
using Newtonsoft.Json;
using osu.Framework.IO.Network;
+using osu.Game.Online.MisskeyAPI.Responses.Types;
using Realms;
namespace osu.Game.Online.MisskeyAPI.Requests.Notes
{
- public class HybridTimeline : APIRequest
+ public class HybridTimeline : APIRequest
{
private readonly string i;
- private readonly string sinceId;
- private readonly string untilId;
+ // private readonly string? sinceId;
+ private readonly string? untilId;
public HybridTimeline(
string i,
- string sinceId = "",
string untilId = ""
)
{
this.i = i;
- this.sinceId = sinceId;
this.untilId = untilId;
}
+ public HybridTimeline(string i)
+ {
+ this.i = i;
+ }
+
protected override WebRequest CreateWebRequest()
{
var req = base.CreateWebRequest();
req.Method = HttpMethod.Post;
- var body = new Dictionary
+ var body = new Dictionary
{
{ "i", i },
+ { "limit", 30 },
};
- if (sinceId != "")
- body.Add("sinceId", sinceId);
- if (untilId != "")
+ // if (sinceId != null)
+ // body.Add("sinceId", sinceId);
+ if (untilId != null)
body.Add("untilId", untilId);
req.AddRaw(JsonConvert.SerializeObject(body));
diff --git a/osu.Game/Online/MisskeyAPI/Responses/Notes/HybridTimeline.cs b/osu.Game/Online/MisskeyAPI/Responses/Notes/HybridTimeline.cs
deleted file mode 100644
index cf165811fe..0000000000
--- a/osu.Game/Online/MisskeyAPI/Responses/Notes/HybridTimeline.cs
+++ /dev/null
@@ -1,267 +0,0 @@
-// Copyright (c) sim1222 . 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 Mentions { get; set; }
-
- [JsonProperty("visibleUserIds")]
- public List VisibleUserIds { get; set; }
-
- [JsonProperty("fileIds")]
- public List FileIds { get; set; }
-
- [JsonProperty("files")]
- public List Files { get; set; }
-
- [JsonProperty("tags")]
- public List 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 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 Emojis { get; set; }
-
- [JsonProperty("onlineStatus")]
- public string OnlineStatus { get; set; }
- }
-}
diff --git a/osu.Game/Online/MisskeyAPI/Types.cs b/osu.Game/Online/MisskeyAPI/Types.cs
index 2f4bca603f..16570b5dd9 100644
--- a/osu.Game/Online/MisskeyAPI/Types.cs
+++ b/osu.Game/Online/MisskeyAPI/Types.cs
@@ -6,6 +6,9 @@
using System.Collections.Generic;
using JetBrains.Annotations;
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
{
@@ -79,7 +82,7 @@ namespace osu.Game.Online.MisskeyAPI.Responses.Types
public class Choice
{
[JsonProperty("isVoted")]
- public bool Id { get; set; }
+ public bool IsVoted { get; set; }
[JsonProperty("text")]
public string Text { get; set; }
@@ -96,7 +99,7 @@ namespace osu.Game.Online.MisskeyAPI.Responses.Types
public bool Multiple { get; set; }
[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
@@ -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
{
+ ///
+ /// A user ID which can be used to represent any system user which is not attached to a user profile.
+ ///
+ public const string SYSTEM_USER_ID = "system";
+
+ public readonly Bindable Status = new Bindable();
+
[JsonProperty("id")]
public string Id { get; set; }
@@ -725,6 +735,9 @@ namespace osu.Game.Online.MisskeyAPI.Responses.Types
[CanBeNull]
public string Host { get; set; }
+ [JsonProperty("name")]
+ public string Name { get; set; }
+
[JsonProperty("onlineStatus")] // 'online' | 'active' | 'offline' | 'unknown'
public string OnlineStatus { get; set; }
diff --git a/osu.Game/Overlays/BeatmapListingOverlay.cs b/osu.Game/Overlays/BeatmapListingOverlay.cs
index d6d4f1a67b..8b3f259d53 100644
--- a/osu.Game/Overlays/BeatmapListingOverlay.cs
+++ b/osu.Game/Overlays/BeatmapListingOverlay.cs
@@ -28,6 +28,7 @@ using osu.Game.Overlays.BeatmapListing;
using osu.Game.Resources.Localisation.Web;
using osuTK;
using osuTK.Graphics;
+using ExpandedContentScrollContainer = osu.Game.Screens.Misskey.Components.Note.Cards.ExpandedContentScrollContainer;
namespace osu.Game.Overlays
{
diff --git a/osu.Game/Overlays/Rankings/SpotlightsLayout.cs b/osu.Game/Overlays/Rankings/SpotlightsLayout.cs
index 8a1b929753..d87ef4099d 100644
--- a/osu.Game/Overlays/Rankings/SpotlightsLayout.cs
+++ b/osu.Game/Overlays/Rankings/SpotlightsLayout.cs
@@ -18,6 +18,7 @@ using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays.Rankings.Tables;
using osu.Game.Rulesets;
using osuTK;
+using ExpandedContentScrollContainer = osu.Game.Screens.Misskey.Components.Note.Cards.ExpandedContentScrollContainer;
namespace osu.Game.Overlays.Rankings
{
diff --git a/osu.Game/Screens/Misskey/Components/Avatar.cs b/osu.Game/Screens/Misskey/Components/Avatar.cs
index bad4d8cc3c..7c1cdfee78 100644
--- a/osu.Game/Screens/Misskey/Components/Avatar.cs
+++ b/osu.Game/Screens/Misskey/Components/Avatar.cs
@@ -13,26 +13,30 @@ using osu.Game.Graphics.Containers;
using osu.Game.Online.API.Requests.Responses;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
+using osuTK;
namespace osu.Game.Screens.Misskey.Components
{
+
[LongRunningLoad]
public partial class Avatar : Sprite
{
// private readonly APIUser user;
+ private Online.MisskeyAPI.Responses.Types.Note note;
///
/// A simple, non-interactable avatar sprite for the specified user.
///
///// The user. A null value will get a placeholder avatar.
- public Avatar()
+ public Avatar(Online.MisskeyAPI.Responses.Types.Note note)
{
// this.user = user;
-
- RelativeSizeAxes = Axes.Both;
+ // RelativeSizeAxes = Axes.Both;
+ Size = new Vector2(10f);
FillMode = FillMode.Fit;
Anchor = Anchor.Centre;
Origin = Anchor.Centre;
+ this.note = note;
}
[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.
// 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()
diff --git a/osu.Game/Screens/Misskey/Components/Note/Cards/BeatmapCardDownloadProgressBar.cs b/osu.Game/Screens/Misskey/Components/Note/Cards/BeatmapCardDownloadProgressBar.cs
new file mode 100644
index 0000000000..386ea1ca57
--- /dev/null
+++ b/osu.Game/Screens/Misskey/Components/Note/Cards/BeatmapCardDownloadProgressBar.cs
@@ -0,0 +1,98 @@
+// Copyright (c) ppy Pty Ltd . 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 State => state;
+ private readonly Bindable state = new Bindable();
+
+ public IBindable 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);
+ }
+ }
+}
diff --git a/osu.Game/Screens/Misskey/Components/Note/Cards/BeatmapSetFavouriteState.cs b/osu.Game/Screens/Misskey/Components/Note/Cards/BeatmapSetFavouriteState.cs
new file mode 100644
index 0000000000..0c0d1bac06
--- /dev/null
+++ b/osu.Game/Screens/Misskey/Components/Note/Cards/BeatmapSetFavouriteState.cs
@@ -0,0 +1,33 @@
+// Copyright (c) ppy Pty Ltd . 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
+{
+ ///
+ /// Stores the current favourite state of a beatmap set.
+ /// Used to coordinate between and .
+ ///
+ public readonly struct BeatmapSetFavouriteState
+ {
+ ///
+ /// Whether the currently logged-in user has favourited this beatmap.
+ ///
+ public bool Favourited { get; }
+
+ ///
+ /// The number of favourites that the beatmap set has received, including the currently logged-in user.
+ ///
+ public int FavouriteCount { get; }
+
+ public BeatmapSetFavouriteState(bool favourited, int favouriteCount)
+ {
+ Favourited = favourited;
+ FavouriteCount = favouriteCount;
+ }
+ }
+}
diff --git a/osu.Game/Screens/Misskey/Components/Note/Cards/Buttons/BeatmapCardIconButton.cs b/osu.Game/Screens/Misskey/Components/Note/Cards/Buttons/BeatmapCardIconButton.cs
new file mode 100644
index 0000000000..5eda213ee7
--- /dev/null
+++ b/osu.Game/Screens/Misskey/Components/Note/Cards/Buttons/BeatmapCardIconButton.cs
@@ -0,0 +1,137 @@
+// Copyright (c) ppy Pty Ltd . 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 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);
+ }
+ }
+}
diff --git a/osu.Game/Screens/Misskey/Components/Note/Cards/Buttons/DownloadButton.cs b/osu.Game/Screens/Misskey/Components/Note/Cards/Buttons/DownloadButton.cs
new file mode 100644
index 0000000000..3243523685
--- /dev/null
+++ b/osu.Game/Screens/Misskey/Components/Note/Cards/Buttons/DownloadButton.cs
@@ -0,0 +1,103 @@
+// Copyright (c) ppy Pty Ltd . 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 State { get; } = new Bindable();
+
+ private readonly APIBeatmapSet beatmapSet;
+
+ private Bindable 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(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.");
+ }
+ }
+ }
+}
diff --git a/osu.Game/Screens/Misskey/Components/Note/Cards/Buttons/FavouriteButton.cs b/osu.Game/Screens/Misskey/Components/Note/Cards/Buttons/FavouriteButton.cs
new file mode 100644
index 0000000000..5470f47015
--- /dev/null
+++ b/osu.Game/Screens/Misskey/Components/Note/Cards/Buttons/FavouriteButton.cs
@@ -0,0 +1,88 @@
+// Copyright (c) ppy Pty Ltd . 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
+ {
+ private readonly BindableWithCurrent current;
+
+ public Bindable 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(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;
+ }
+ }
+ }
+}
diff --git a/osu.Game/Screens/Misskey/Components/Note/Cards/Buttons/GoToBeatmapButton.cs b/osu.Game/Screens/Misskey/Components/Note/Cards/Buttons/GoToBeatmapButton.cs
new file mode 100644
index 0000000000..6914cc56b8
--- /dev/null
+++ b/osu.Game/Screens/Misskey/Components/Note/Cards/Buttons/GoToBeatmapButton.cs
@@ -0,0 +1,48 @@
+// Copyright (c) ppy Pty Ltd . 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 State => state;
+ private readonly Bindable state = new Bindable();
+
+ 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);
+ }
+ }
+}
diff --git a/osu.Game/Screens/Misskey/Components/Note/Cards/Buttons/PlayButton.cs b/osu.Game/Screens/Misskey/Components/Note/Cards/Buttons/PlayButton.cs
new file mode 100644
index 0000000000..6c1037f388
--- /dev/null
+++ b/osu.Game/Screens/Misskey/Components/Note/Cards/Buttons/PlayButton.cs
@@ -0,0 +1,154 @@
+// Copyright (c) ppy Pty Ltd . 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 Progress => progress;
+ private readonly BindableDouble progress = new BindableDouble();
+
+ public BindableBool Playing { get; } = new BindableBool();
+
+ private readonly IBeatmapSetInfo beatmapSetInfo;
+
+ protected override IEnumerable 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 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;
+ }
+ }
+}
diff --git a/osu.Game/Screens/Misskey/Components/DrawableNoteCard.cs b/osu.Game/Screens/Misskey/Components/Note/Cards/DrawableNoteCard.cs
similarity index 54%
rename from osu.Game/Screens/Misskey/Components/DrawableNoteCard.cs
rename to osu.Game/Screens/Misskey/Components/Note/Cards/DrawableNoteCard.cs
index 7a35d206e5..4170bd3350 100644
--- a/osu.Game/Screens/Misskey/Components/DrawableNoteCard.cs
+++ b/osu.Game/Screens/Misskey/Components/Note/Cards/DrawableNoteCard.cs
@@ -10,10 +10,9 @@ using osu.Game.Beatmaps.Drawables.Cards;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online;
-using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays;
-namespace osu.Game.Screens.Misskey.Components
+namespace osu.Game.Screens.Misskey.Components.Note.Cards
{
public abstract partial class DrawableNoteCard : OsuClickableContainer
{
@@ -24,38 +23,38 @@ namespace osu.Game.Screens.Misskey.Components
public IBindable Expanded { get; }
- public readonly APIBeatmapSet BeatmapSet;
+ public readonly Online.MisskeyAPI.Responses.Types.Note Note;
- protected readonly Bindable FavouriteState;
+ // protected readonly Bindable FavouriteState;
- protected abstract Drawable IdleContent { get; }
- protected abstract Drawable DownloadInProgressContent { get; }
+ // protected abstract Drawable IdleContent { 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)
{
Expanded = new BindableBool { Disabled = !allowExpansion };
- BeatmapSet = beatmapSet;
- FavouriteState = new Bindable(new BeatmapSetFavouriteState(beatmapSet.HasFavourited, beatmapSet.FavouriteCount));
- DownloadTracker = new BeatmapDownloadTracker(beatmapSet);
+ Note = note;
+ // FavouriteState = new Bindable(new BeatmapSetFavouriteState(note.HasFavourited, note.FavouriteCount));
+ // DownloadTracker = new BeatmapDownloadTracker(note);
}
[BackgroundDependencyLoader(true)]
private void load(BeatmapSetOverlay? beatmapSetOverlay)
{
- Action = () => beatmapSetOverlay?.FetchAndShowBeatmapSet(BeatmapSet.OnlineID);
+ // Action = () => beatmapSetOverlay?.FetchAndShowBeatmapSet(Note.OnlineID);
- AddInternal(DownloadTracker);
+ // AddInternal(DownloadTracker);
}
protected override void LoadComplete()
{
base.LoadComplete();
- DownloadTracker.State.BindValueChanged(_ => UpdateState());
+ // DownloadTracker.State.BindValueChanged(_ => UpdateState());
Expanded.BindValueChanged(_ => UpdateState(), true);
FinishTransforms(true);
}
@@ -74,24 +73,24 @@ namespace osu.Game.Screens.Misskey.Components
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);
- DownloadInProgressContent.FadeTo(showProgress ? 1 : 0, TRANSITION_DURATION, Easing.OutQuint);
+ // IdleContent.FadeTo(showProgress ? 0 : 1, TRANSITION_DURATION, Easing.OutQuint);
+ // DownloadInProgressContent.FadeTo(showProgress ? 1 : 0, TRANSITION_DURATION, Easing.OutQuint);
}
///
- /// Creates a beatmap card of the given for the supplied .
+ /// Creates a beatmap card of the given for the supplied .
///
- 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)
{
case BeatmapCardSize.Normal:
- return new BeatmapCardNormal(beatmapSet, allowExpansion);
+ return new NoteCardNormal(note, allowExpansion);
case BeatmapCardSize.Extra:
- return new BeatmapCardExtra(beatmapSet, allowExpansion);
+ return new NoteCardNormal(note, allowExpansion); //todo: extra
default:
throw new ArgumentOutOfRangeException(nameof(size), size, @"Unsupported card size");
diff --git a/osu.Game/Screens/Misskey/Components/Note/Cards/ExpandedContentScrollContainer.cs b/osu.Game/Screens/Misskey/Components/Note/Cards/ExpandedContentScrollContainer.cs
new file mode 100644
index 0000000000..1ce3a6b5ee
--- /dev/null
+++ b/osu.Game/Screens/Misskey/Components/Note/Cards/ExpandedContentScrollContainer.cs
@@ -0,0 +1,81 @@
+// Copyright (c) ppy Pty Ltd . 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;
+ }
+ }
+ }
+}
diff --git a/osu.Game/Screens/Misskey/Components/Note/Cards/HoverHandlingContainer.cs b/osu.Game/Screens/Misskey/Components/Note/Cards/HoverHandlingContainer.cs
new file mode 100644
index 0000000000..f15034c353
--- /dev/null
+++ b/osu.Game/Screens/Misskey/Components/Note/Cards/HoverHandlingContainer.cs
@@ -0,0 +1,27 @@
+// Copyright (c) ppy Pty Ltd . 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? Hovered { get; set; }
+ public Action? 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);
+ }
+ }
+}
diff --git a/osu.Game/Screens/Misskey/Components/Note/Cards/IconPill.cs b/osu.Game/Screens/Misskey/Components/Note/Cards/IconPill.cs
new file mode 100644
index 0000000000..5bb3478bf8
--- /dev/null
+++ b/osu.Game/Screens/Misskey/Components/Note/Cards/IconPill.cs
@@ -0,0 +1,57 @@
+// Copyright (c) ppy Pty Ltd . 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; }
+ }
+}
diff --git a/osu.Game/Screens/Misskey/Components/NoteCard.cs b/osu.Game/Screens/Misskey/Components/Note/Cards/NoteCard.cs
similarity index 57%
rename from osu.Game/Screens/Misskey/Components/NoteCard.cs
rename to osu.Game/Screens/Misskey/Components/Note/Cards/NoteCard.cs
index cd947be57f..8805be2939 100644
--- a/osu.Game/Screens/Misskey/Components/NoteCard.cs
+++ b/osu.Game/Screens/Misskey/Components/Note/Cards/NoteCard.cs
@@ -13,7 +13,7 @@ using osu.Game.Online;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays;
-namespace osu.Game.Screens.Misskey.Components
+namespace osu.Game.Screens.Misskey.Components.Note.Cards
{
public abstract partial class NoteCard : OsuClickableContainer
{
@@ -24,38 +24,38 @@ namespace osu.Game.Screens.Misskey.Components
public IBindable Expanded { get; }
- public readonly APIBeatmapSet BeatmapSet;
+ public readonly Online.MisskeyAPI.Responses.Types.Note Note;
- protected readonly Bindable FavouriteState;
+ // protected readonly Bindable FavouriteState;
protected abstract Drawable IdleContent { 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)
{
Expanded = new BindableBool { Disabled = !allowExpansion };
- BeatmapSet = beatmapSet;
- FavouriteState = new Bindable(new BeatmapSetFavouriteState(beatmapSet.HasFavourited, beatmapSet.FavouriteCount));
- DownloadTracker = new BeatmapDownloadTracker(beatmapSet);
+ Note = note;
+ // FavouriteState = new Bindable(new BeatmapSetFavouriteState(note.HasFavourited, note.FavouriteCount));
+ // DownloadTracker = new BeatmapDownloadTracker(note);
}
[BackgroundDependencyLoader(true)]
private void load(BeatmapSetOverlay? beatmapSetOverlay)
{
- Action = () => beatmapSetOverlay?.FetchAndShowBeatmapSet(BeatmapSet.OnlineID);
+ // Action = () => beatmapSetOverlay?.FetchAndShowBeatmapSet(Note.OnlineID);
- AddInternal(DownloadTracker);
+ // AddInternal(DownloadTracker);
}
protected override void LoadComplete()
{
base.LoadComplete();
- DownloadTracker.State.BindValueChanged(_ => UpdateState());
+ // DownloadTracker.State.BindValueChanged(_ => UpdateState());
Expanded.BindValueChanged(_ => UpdateState(), true);
FinishTransforms(true);
}
@@ -74,24 +74,24 @@ namespace osu.Game.Screens.Misskey.Components
protected virtual void UpdateState()
{
- bool showProgress = DownloadTracker.State.Value == DownloadState.Downloading || DownloadTracker.State.Value == DownloadState.Importing;
-
- IdleContent.FadeTo(showProgress ? 0 : 1, TRANSITION_DURATION, Easing.OutQuint);
- DownloadInProgressContent.FadeTo(showProgress ? 1 : 0, TRANSITION_DURATION, Easing.OutQuint);
+ // bool showProgress = DownloadTracker.State.Value == DownloadState.Downloading || DownloadTracker.State.Value == DownloadState.Importing;
+ //
+ // IdleContent.FadeTo(showProgress ? 0 : 1, TRANSITION_DURATION, Easing.OutQuint);
+ // DownloadInProgressContent.FadeTo(showProgress ? 1 : 0, TRANSITION_DURATION, Easing.OutQuint);
}
///
- /// Creates a beatmap card of the given for the supplied .
+ /// Creates a beatmap card of the given for the supplied .
///
- 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)
{
case BeatmapCardSize.Normal:
- return new BeatmapCardNormal(beatmapSet, allowExpansion);
+ return new NoteCardNormal(note, allowExpansion);
- case BeatmapCardSize.Extra:
- return new BeatmapCardExtra(beatmapSet, allowExpansion);
+ // case BeatmapCardSize.Extra:
+ // return new BeatmapCardExtra(note, allowExpansion);
default:
throw new ArgumentOutOfRangeException(nameof(size), size, @"Unsupported card size");
diff --git a/osu.Game/Screens/Misskey/Components/Note/Cards/NoteCardAvatar.cs b/osu.Game/Screens/Misskey/Components/Note/Cards/NoteCardAvatar.cs
new file mode 100644
index 0000000000..c3062c3b45
--- /dev/null
+++ b/osu.Game/Screens/Misskey/Components/Note/Cards/NoteCardAvatar.cs
@@ -0,0 +1,75 @@
+// Copyright (c) ppy Pty Ltd . 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()
+ {
+ }
+ }
+}
diff --git a/osu.Game/Screens/Misskey/Components/Note/Cards/NoteCardContent.cs b/osu.Game/Screens/Misskey/Components/Note/Cards/NoteCardContent.cs
new file mode 100644
index 0000000000..fc6db22592
--- /dev/null
+++ b/osu.Game/Screens/Misskey/Components/Note/Cards/NoteCardContent.cs
@@ -0,0 +1,156 @@
+// Copyright (c) ppy Pty Ltd . 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 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);
+ }
+ }
+}
diff --git a/osu.Game/Screens/Misskey/Components/NoteCardNormal.cs b/osu.Game/Screens/Misskey/Components/Note/Cards/NoteCardNormal.cs
similarity index 52%
rename from osu.Game/Screens/Misskey/Components/NoteCardNormal.cs
rename to osu.Game/Screens/Misskey/Components/Note/Cards/NoteCardNormal.cs
index fe252cc4d0..76b6ab8ac6 100644
--- a/osu.Game/Screens/Misskey/Components/NoteCardNormal.cs
+++ b/osu.Game/Screens/Misskey/Components/Note/Cards/NoteCardNormal.cs
@@ -7,19 +7,20 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Localisation;
using osu.Game.Beatmaps.Drawables.Cards;
-using osu.Game.Beatmaps.Drawables.Cards.Statistics;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
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.BeatmapSet;
-using osuTK;
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 DownloadInProgressContent => downloadProgressBar;
@@ -27,23 +28,27 @@ namespace osu.Game.Screens.Misskey.Components
private const float height = 100;
[Cached]
- private readonly BeatmapCardContent content;
+ private readonly NoteCardContent content;
- private BeatmapCardThumbnail thumbnail = null!;
- private CollapsibleButtonContainer buttonContainer = null!;
+ private NoteCardAvatar thumbnail = null!;
+ // private CollapsibleButtonContainer buttonContainer = null!;
- private FillFlowContainer statisticsContainer = null!;
+ // private FillFlowContainer statisticsContainer = null!;
+ private TextFlowContainer noteText = null!;
private FillFlowContainer idleBottomContent = null!;
private BeatmapCardDownloadProgressBar downloadProgressBar = null!;
[Resolved]
- private OverlayColourProvider colourProvider { get; set; } = null!;
+ private IAPIProvider api { get; set; } = null!;
- public NoteCardNormal(APIBeatmapSet beatmapSet, bool allowExpansion = true)
- : base(beatmapSet, allowExpansion)
+ // [Resolved]
+ // 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]
@@ -56,6 +61,9 @@ namespace osu.Game.Screens.Misskey.Components
FillFlowContainer titleBadgeArea = null!;
GridContainer artistContainer = null!;
+ // LinkFlowContainer titleText = null!;
+ LinkFlowContainer artistText = null!;
+
Child = content.With(c =>
{
c.MainContent = new Container
@@ -63,11 +71,11 @@ namespace osu.Game.Screens.Misskey.Components
RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
{
- thumbnail = new BeatmapCardThumbnail(BeatmapSet)
+ thumbnail = new NoteCardAvatar(Note)
{
Name = @"Left (icon) area",
- Size = new Vector2(height),
- Padding = new MarginPadding { Right = CORNER_RADIUS },
+ Size = new Vector2(height - 10),
+ // Padding = new MarginPadding { Right = CORNER_RADIUS },
Child = leftIconArea = new FillFlowContainer
{
Margin = new MarginPadding(5),
@@ -76,17 +84,19 @@ namespace osu.Game.Screens.Misskey.Components
Spacing = new Vector2(1)
}
},
- buttonContainer = new CollapsibleButtonContainer(BeatmapSet)
- {
- X = height - CORNER_RADIUS,
- Width = WIDTH - height + CORNER_RADIUS,
- FavouriteState = { BindTarget = FavouriteState },
- ButtonsCollapsedWidth = CORNER_RADIUS,
- ButtonsExpandedWidth = 30,
- Children = new Drawable[]
- {
+ // buttonContainer = new CollapsibleButtonContainer(Note)
+ // {
+ // X = height - CORNER_RADIUS,
+ // Width = WIDTH - height + CORNER_RADIUS,
+ // // FavouriteState = { BindTarget = FavouriteState },
+ // ButtonsCollapsedWidth = CORNER_RADIUS,
+ // ButtonsExpandedWidth = 30,
+ // Children = new Drawable[]
+ // {
new FillFlowContainer
{
+ // X = height - CORNER_RADIUS,
+ X = height,
RelativeSizeAxes = Axes.Both,
Direction = FillDirection.Vertical,
Children = new Drawable[]
@@ -108,12 +118,14 @@ namespace osu.Game.Screens.Misskey.Components
{
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),
RelativeSizeAxes = Axes.X,
Truncate = true
+ // Padding = new MarginPadding { Left = SettingsPanel.CONTENT_MARGINS },
+ // AutoSizeAxes = Axes.Y,
},
titleBadgeArea = new FillFlowContainer
{
@@ -142,28 +154,28 @@ namespace osu.Game.Screens.Misskey.Components
{
new[]
{
- new OsuSpriteText
+ artistText = new LinkFlowContainer()
{
- Text = createArtistText(),
- Font = OsuFont.Default.With(size: 17.5f, weight: FontWeight.SemiBold),
+ // Text = createArtistText(),
+ // Font = OsuFont.Default.With(size: 17.5f, weight: FontWeight.SemiBold),
RelativeSizeAxes = Axes.X,
- Truncate = true
+ // Truncate = true
+ AutoSizeAxes = Axes.Y,
},
Empty()
},
}
},
- new LinkFlowContainer(s =>
+ noteText = new TextFlowContainer
{
- s.Shadow = false;
- s.Font = OsuFont.GetFont(size: 14, weight: FontWeight.SemiBold);
- }).With(d =>
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Alpha = 1,
+ AlwaysPresent = true,
+ }.With(flow =>
{
- d.AutoSizeAxes = Axes.Both;
- d.Margin = new MarginPadding { Top = 2 };
- d.AddText("mapped by ", t => t.Colour = colourProvider.Content2);
- d.AddUserLink(BeatmapSet.Author);
- }),
+ flow.AddText(Note.Text, t => t.Font = OsuFont.Default.With(size: 15));
+ })
}
},
new Container
@@ -184,104 +196,97 @@ namespace osu.Game.Screens.Misskey.Components
AlwaysPresent = true,
Children = new Drawable[]
{
- statisticsContainer = new FillFlowContainer
- {
- RelativeSizeAxes = Axes.X,
- AutoSizeAxes = Axes.Y,
- Direction = FillDirection.Horizontal,
- Spacing = new Vector2(10, 0),
- Alpha = 0,
- AlwaysPresent = true,
- ChildrenEnumerable = createStatistics()
- },
- new BeatmapCardExtraInfoRow(BeatmapSet)
+ // statisticsContainer = new FillFlowContainer
+ // {
+ // RelativeSizeAxes = Axes.X,
+ // AutoSizeAxes = Axes.Y,
+ // Direction = FillDirection.Horizontal,
+ // Spacing = new Vector2(10, 0),
+ // Alpha = 0,
+ // AlwaysPresent = true,
+ // ChildrenEnumerable = createStatistics()
+ // },
+
}
- },
- 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
- {
- RelativeSizeAxes = Axes.X,
- AutoSizeAxes = Axes.Y,
- Padding = new MarginPadding { Horizontal = 10, Vertical = 13 },
- Child = new BeatmapCardDifficultyList(BeatmapSet)
- };
+ // c.ExpandedContent = new Container
+ // {
+ // RelativeSizeAxes = Axes.X,
+ // AutoSizeAxes = Axes.Y,
+ // Padding = new MarginPadding { Horizontal = 10, Vertical = 13 },
+ // Child = new BeatmapCardDifficultyList(BeatmapSet)
+ // };
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)
- leftIconArea.Add(new VideoIconPill { IconSize = new Vector2(20) });
+ // if (BeatmapSet.HasVideo)
+ // 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)
- leftIconArea.Add(new StoryboardIconPill { IconSize = new Vector2(20) });
+ // if (BeatmapSet.HasExplicitContent)
+ // {
+ // titleBadgeArea.Add(new ExplicitContentBeatmapBadge
+ // {
+ // Anchor = Anchor.BottomRight,
+ // Origin = Anchor.BottomRight,
+ // Margin = new MarginPadding { Left = 5 }
+ // });
+ // }
- if (BeatmapSet.FeaturedInSpotlight)
- {
- titleBadgeArea.Add(new SpotlightBeatmapBadge
- {
- Anchor = Anchor.BottomRight,
- Origin = Anchor.BottomRight,
- 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 }
- };
- }
+ // if (BeatmapSet.TrackId != null)
+ // {
+ // artistContainer.Content[0][1] = new FeaturedArtistBeatmapBadge
+ // {
+ // Anchor = Anchor.BottomRight,
+ // Origin = Anchor.BottomRight,
+ // Margin = new MarginPadding { Left = 5 }
+ // };
+ // }
}
private LocalisableString createArtistText()
{
- var romanisableArtist = new RomanisableString(BeatmapSet.ArtistUnicode, BeatmapSet.Artist);
- return BeatmapsetsStrings.ShowDetailsByArtist(romanisableArtist);
+ var romanisableArtist = new RomanisableString(Note.User.Username + "@" + Note.User.Host, Note.User.Username + "@" + Note.User.Host);
+ return romanisableArtist;
}
- private IEnumerable createStatistics()
- {
- var hypesStatistic = HypesStatistic.CreateFor(BeatmapSet);
- if (hypesStatistic != null)
- yield return hypesStatistic;
-
- var nominationsStatistic = NominationsStatistic.CreateFor(BeatmapSet);
- if (nominationsStatistic != null)
- yield return nominationsStatistic;
-
- yield return new FavouritesStatistic(BeatmapSet) { Current = FavouriteState };
- yield return new PlayCountStatistic(BeatmapSet);
-
- var dateStatistic = BeatmapCardDateStatistic.CreateFor(BeatmapSet);
- if (dateStatistic != null)
- yield return dateStatistic;
- }
+ // private IEnumerable createStatistics()
+ // {
+ // var hypesStatistic = HypesStatistic.CreateFor(BeatmapSet);
+ // if (hypesStatistic != null)
+ // yield return hypesStatistic;
+ //
+ // var nominationsStatistic = NominationsStatistic.CreateFor(BeatmapSet);
+ // if (nominationsStatistic != null)
+ // yield return nominationsStatistic;
+ //
+ // yield return new FavouritesStatistic(BeatmapSet) { Current = FavouriteState };
+ // yield return new PlayCountStatistic(BeatmapSet);
+ //
+ // var dateStatistic = BeatmapCardDateStatistic.CreateFor(BeatmapSet);
+ // if (dateStatistic != null)
+ // yield return dateStatistic;
+ // }
protected override void UpdateState()
{
@@ -289,10 +294,10 @@ namespace osu.Game.Screens.Misskey.Components
bool showDetails = IsHovered || Expanded.Value;
- buttonContainer.ShowDetails.Value = showDetails;
+ // buttonContainer.ShowDetails.Value = showDetails;
thumbnail.Dimmed.Value = showDetails;
- statisticsContainer.FadeTo(showDetails ? 1 : 0, TRANSITION_DURATION, Easing.OutQuint);
+ // statisticsContainer.FadeTo(showDetails ? 1 : 0, TRANSITION_DURATION, Easing.OutQuint);
}
}
}
diff --git a/osu.Game/Screens/Misskey/Components/Note/Cards/Statistics/BeatmapCardDateStatistic.cs b/osu.Game/Screens/Misskey/Components/Note/Cards/Statistics/BeatmapCardDateStatistic.cs
new file mode 100644
index 0000000000..d706c3b6f1
--- /dev/null
+++ b/osu.Game/Screens/Misskey/Components/Note/Cards/Statistics/BeatmapCardDateStatistic.cs
@@ -0,0 +1,54 @@
+// Copyright (c) ppy Pty Ltd . 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;
+ }
+ }
+ }
+}
diff --git a/osu.Game/Screens/Misskey/Components/Note/Cards/Statistics/BeatmapCardStatistic.cs b/osu.Game/Screens/Misskey/Components/Note/Cards/Statistics/BeatmapCardStatistic.cs
new file mode 100644
index 0000000000..6b968c8435
--- /dev/null
+++ b/osu.Game/Screens/Misskey/Components/Note/Cards/Statistics/BeatmapCardStatistic.cs
@@ -0,0 +1,82 @@
+// Copyright (c) ppy Pty Ltd . 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
+{
+ ///
+ /// A single statistic shown on a beatmap card.
+ ///
+ 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
+ }
+}
diff --git a/osu.Game/Screens/Misskey/Components/Note/Cards/Statistics/FavouritesStatistic.cs b/osu.Game/Screens/Misskey/Components/Note/Cards/Statistics/FavouritesStatistic.cs
new file mode 100644
index 0000000000..a9826d63ce
--- /dev/null
+++ b/osu.Game/Screens/Misskey/Components/Note/Cards/Statistics/FavouritesStatistic.cs
@@ -0,0 +1,47 @@
+// Copyright (c) ppy Pty Ltd . 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
+{
+ ///
+ /// Shows the number of favourites that a beatmap set has received.
+ ///
+ public partial class FavouritesStatistic : BeatmapCardStatistic, IHasCurrentValue
+ {
+ private readonly BindableWithCurrent current;
+
+ public Bindable Current
+ {
+ get => current.Current;
+ set => current.Current = value;
+ }
+
+ public FavouritesStatistic(IBeatmapSetOnlineInfo onlineInfo)
+ {
+ current = new BindableWithCurrent(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"));
+ }
+ }
+}
diff --git a/osu.Game/Screens/Misskey/Components/Note/Cards/Statistics/HypesStatistic.cs b/osu.Game/Screens/Misskey/Components/Note/Cards/Statistics/HypesStatistic.cs
new file mode 100644
index 0000000000..a9a0f53ef2
--- /dev/null
+++ b/osu.Game/Screens/Misskey/Components/Note/Cards/Statistics/HypesStatistic.cs
@@ -0,0 +1,26 @@
+// Copyright (c) ppy Pty Ltd . 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
+{
+ ///
+ /// Shows the number of current hypes that a map has received, as well as the number of hypes required for nomination.
+ ///
+ 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);
+ }
+}
diff --git a/osu.Game/Screens/Misskey/Components/Note/Cards/Statistics/NominationsStatistic.cs b/osu.Game/Screens/Misskey/Components/Note/Cards/Statistics/NominationsStatistic.cs
new file mode 100644
index 0000000000..2255a5ab24
--- /dev/null
+++ b/osu.Game/Screens/Misskey/Components/Note/Cards/Statistics/NominationsStatistic.cs
@@ -0,0 +1,28 @@
+// Copyright (c) ppy Pty Ltd . 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
+{
+ ///
+ /// Shows the number of current nominations that a map has received, as well as the number of nominations required for qualification.
+ ///
+ 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);
+ }
+}
diff --git a/osu.Game/Screens/Misskey/Components/Note/Cards/Statistics/PlayCountStatistic.cs b/osu.Game/Screens/Misskey/Components/Note/Cards/Statistics/PlayCountStatistic.cs
new file mode 100644
index 0000000000..78addb53bc
--- /dev/null
+++ b/osu.Game/Screens/Misskey/Components/Note/Cards/Statistics/PlayCountStatistic.cs
@@ -0,0 +1,26 @@
+// Copyright (c) ppy Pty Ltd . 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
+{
+ ///
+ /// Shows the number of times the given beatmap set has been played.
+ ///
+ 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"));
+ }
+ }
+}
diff --git a/osu.Game/Screens/Misskey/Components/Note/Cards/StoryboardIconPill.cs b/osu.Game/Screens/Misskey/Components/Note/Cards/StoryboardIconPill.cs
new file mode 100644
index 0000000000..97c94c1a45
--- /dev/null
+++ b/osu.Game/Screens/Misskey/Components/Note/Cards/StoryboardIconPill.cs
@@ -0,0 +1,21 @@
+// Copyright (c) ppy Pty Ltd . 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;
+ }
+}
diff --git a/osu.Game/Screens/Misskey/Components/Note/Cards/VideoIconPill.cs b/osu.Game/Screens/Misskey/Components/Note/Cards/VideoIconPill.cs
new file mode 100644
index 0000000000..2fb964c24c
--- /dev/null
+++ b/osu.Game/Screens/Misskey/Components/Note/Cards/VideoIconPill.cs
@@ -0,0 +1,21 @@
+// Copyright (c) ppy Pty Ltd . 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;
+ }
+}
diff --git a/osu.Game/Screens/Misskey/Components/PostForm.cs b/osu.Game/Screens/Misskey/Components/PostForm.cs
index 1996f1b0bb..8bdb64aa0b 100644
--- a/osu.Game/Screens/Misskey/Components/PostForm.cs
+++ b/osu.Game/Screens/Misskey/Components/PostForm.cs
@@ -6,6 +6,7 @@ using osu.Framework.Allocation;
using osu.Framework.Extensions.LocalisationExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input.Events;
using osu.Game.Configuration;
@@ -16,6 +17,7 @@ using osu.Game.Online.MisskeyAPI;
using osu.Game.Misskey.Overlays.Settings;
using osu.Game.Online.MisskeyAPI.Requests.Notes;
using osu.Game.Overlays;
+using osu.Game.Overlays.Notifications;
using osu.Game.Overlays.OSD;
using osu.Game.Resources.Localisation.Web;
using osu.Game.Screens.Misskey;
@@ -26,6 +28,8 @@ namespace osu.Game.Screens.Misskey.Components
public partial class PostForm : FillFlowContainer
{
private OnScreenDisplay? onScreenDisplay { get; set; }
+ [Resolved(CanBeNull = true)]
+ private INotificationOverlay? notifications { get; set; }
private partial class ResToast : Toast
{
public ResToast(string value, string desc)
@@ -57,11 +61,20 @@ namespace osu.Game.Screens.Misskey.Components
{
textBox.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);
- onScreenDisplay?.Display(new ResToast("送信しています", ""));
+ notifications?.Post(new SimpleNotification
+ {
+ Text = "送信しています",
+ Icon = FontAwesome.Solid.PaperPlane,
+ });
+
}
[BackgroundDependencyLoader(permitNulls: true)]
@@ -128,15 +141,14 @@ namespace osu.Game.Screens.Misskey.Components
}
}
},
- // new SettingsButton
- // {
- // Text = "Register",
- // Action = () =>
- // {
- // RequestHide?.Invoke();
- // accountCreation.Show();
- // }
- // }
+ new SettingsButton
+ {
+ Text = "test",
+ Action = () =>
+ {
+ onScreenDisplay?.Display(new ResToast("送信しています", ""));
+ }
+ }
};
// forgottenPaswordLink.AddLink(LayoutStrings.PopupLoginLoginForgot, $"https://simkey.net/about");
diff --git a/osu.Game/Screens/Misskey/MisskeyComponents.cs b/osu.Game/Screens/Misskey/MisskeyComponents.cs
index 929609b436..bd5fa0c1da 100644
--- a/osu.Game/Screens/Misskey/MisskeyComponents.cs
+++ b/osu.Game/Screens/Misskey/MisskeyComponents.cs
@@ -20,7 +20,7 @@ namespace osu.Game.Screens.Misskey
public partial class MisskeyComponents : OsuScreen
{
private Container contentContainer;
- private Drawable avatar;
+ // private Drawable avatar;
[Resolved]
private OsuColour colours { get; set; }
@@ -44,23 +44,23 @@ namespace osu.Game.Screens.Misskey
Colour = Color4.Black,
Alpha = 0.6f,
},
- new Container
- {
- // RelativeSizeAxes = Axes.Both,
- // AutoSizeAxes = Axes.Y,
- Size = new Vector2(200),
- Masking = true,
- CornerRadius = 100,
- AutoSizeEasing = Easing.OutQuint,
- Children = new Drawable[]
- {
- avatar = new DelayedLoadWrapper(
- new Avatar()
- {
- RelativeSizeAxes = Axes.Both,
- })
- },
- }
+ // new Container
+ // {
+ // // RelativeSizeAxes = Axes.Both,
+ // // AutoSizeAxes = Axes.Y,
+ // Size = new Vector2(200),
+ // Masking = true,
+ // CornerRadius = 100,
+ // AutoSizeEasing = Easing.OutQuint,
+ // Children = new Drawable[]
+ // {
+ // avatar = new DelayedLoadWrapper(
+ // new Avatar()
+ // {
+ // RelativeSizeAxes = Axes.Both,
+ // })
+ // },
+ // }
}
};
}
diff --git a/osu.Game/Screens/Misskey/MisskeyScreenSelector.cs b/osu.Game/Screens/Misskey/MisskeyScreenSelector.cs
index 1bedb3509e..c1a9d5763c 100644
--- a/osu.Game/Screens/Misskey/MisskeyScreenSelector.cs
+++ b/osu.Game/Screens/Misskey/MisskeyScreenSelector.cs
@@ -98,14 +98,14 @@ namespace osu.Game.Screens.Misskey
Text = "MisskeyLogin",
Action = () => this.Push(new MisskeyLogin())
},
- // new OsuButton()
- // {
- // Anchor = Anchor.Centre,
- // Origin = Anchor.Centre,
- // Size = new Vector2(500f, 50f),
- // Text = "Timeline",
- // Action = () => this.Push(new Timeline())
- // },
+ new OsuButton()
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Size = new Vector2(500f, 50f),
+ Text = "Timeline",
+ Action = () => this.Push(new Timeline())
+ },
new OsuButton()
{
Anchor = Anchor.Centre,
diff --git a/osu.Game/Screens/Misskey/Timeline.cs b/osu.Game/Screens/Misskey/Timeline.cs
new file mode 100644
index 0000000000..a9310b7bc4
--- /dev/null
+++ b/osu.Game/Screens/Misskey/Timeline.cs
@@ -0,0 +1,303 @@
+// Copyright (c) ppy Pty Ltd . 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 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 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 createCardContainerFor(IEnumerable 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
+ {
+ 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
+ {
+ 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();
+ }
+ }
+}
diff --git a/osu.Game/Screens/Misskey/Welcome.cs b/osu.Game/Screens/Misskey/Welcome.cs
index 235bf48033..1ef9426717 100644
--- a/osu.Game/Screens/Misskey/Welcome.cs
+++ b/osu.Game/Screens/Misskey/Welcome.cs
@@ -147,7 +147,7 @@ namespace osu.Game.Screens.Misskey
Origin = Anchor.TopCentre,
Margin = new MarginPadding(100),
Width = 400f,
- Text = "Misskey.io は、地球で生まれた分散マイクロブログSNSです。Fediverse(様々なSNSで構成される宇宙)の中に存在するため、他のSNSと相互に繋がっています。\n暫し都会の喧騒から離れて、新しいインターネットにダイブしてみませんか。",
+ Text = "Misskey.。Fediverse(様々なSNSで構成される宇宙)の中に存在するため、他のSNSと相互に繋がっています。\n暫し都会の喧騒から離れて、新しいインターネットにダイブしてみませんか。",
Font = new FontUsage(size: 20),
Colour = Colour4.White,
},
diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj
index b1c85f1e0b..536f206fc1 100644
--- a/osu.Game/osu.Game.csproj
+++ b/osu.Game/osu.Game.csproj
@@ -45,4 +45,7 @@
+
+
+