Properly disable comment box on beatmaps that cannot be commented on

Closes https://github.com/ppy/osu/issues/30052.

Compare:

- 83816dbe24/resources/js/components/comment-editor.tsx (L54-L60)
- 83816dbe24/resources/js/components/comment-editor.tsx (L47-L52)
This commit is contained in:
Bartłomiej Dach 2024-09-30 11:02:00 +02:00
parent a258059d43
commit e91c8fb4bd
No known key found for this signature in database
6 changed files with 89 additions and 18 deletions

View File

@ -12,6 +12,7 @@
using osu.Framework.Testing; using osu.Framework.Testing;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API; using osu.Game.Online.API;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays; using osu.Game.Overlays;
using osu.Game.Overlays.Comments; using osu.Game.Overlays.Comments;
using osuTK; using osuTK;
@ -133,6 +134,34 @@ void assertLoggedOutState()
assertLoggedInState(); assertLoggedInState();
} }
[Test]
public void TestCommentsDisabled()
{
AddStep("no reason for disable", () => commentEditor.CommentableMeta.Value = new CommentableMeta
{
CurrentUserAttributes = new CommentableMeta.CommentableCurrentUserAttributes(),
});
AddAssert("textbox enabled", () => commentEditor.ChildrenOfType<TextBox>().Single().ReadOnly, () => Is.False);
AddStep("specific reason for disable", () => commentEditor.CommentableMeta.Value = new CommentableMeta
{
CurrentUserAttributes = new CommentableMeta.CommentableCurrentUserAttributes
{
CanNewCommentReason = "This comment section is disabled. For reasons.",
}
});
AddAssert("textbox disabled", () => commentEditor.ChildrenOfType<TextBox>().Single().ReadOnly, () => Is.True);
AddStep("entire commentable meta missing", () => commentEditor.CommentableMeta.Value = null);
AddAssert("textbox enabled", () => commentEditor.ChildrenOfType<TextBox>().Single().ReadOnly, () => Is.False);
AddStep("current user attributes missing", () => commentEditor.CommentableMeta.Value = new CommentableMeta
{
CurrentUserAttributes = null,
});
AddAssert("textbox enabled", () => commentEditor.ChildrenOfType<TextBox>().Single().ReadOnly, () => Is.True);
}
[Test] [Test]
public void TestCancelAction() public void TestCancelAction()
{ {
@ -167,8 +196,7 @@ protected override void OnCommit(string value)
protected override LocalisableString GetButtonText(bool isLoggedIn) => protected override LocalisableString GetButtonText(bool isLoggedIn) =>
isLoggedIn ? @"Commit" : "You're logged out!"; isLoggedIn ? @"Commit" : "You're logged out!";
protected override LocalisableString GetPlaceholderText(bool isLoggedIn) => protected override LocalisableString GetPlaceholderText() => @"This text box is empty";
isLoggedIn ? @"This text box is empty" : "Still empty, but now you can't type in it.";
} }
private partial class TestCancellableCommentEditor : CancellableCommentEditor private partial class TestCancellableCommentEditor : CancellableCommentEditor
@ -189,7 +217,7 @@ protected override void OnCommit(string text)
} }
protected override LocalisableString GetButtonText(bool isLoggedIn) => @"Save"; protected override LocalisableString GetButtonText(bool isLoggedIn) => @"Save";
protected override LocalisableString GetPlaceholderText(bool isLoggedIn) => @"Multiline textboxes soon"; protected override LocalisableString GetPlaceholderText() => @"Multiline textboxes soon";
} }
} }
} }

View File

@ -24,5 +24,14 @@ public class CommentableMeta
[JsonProperty("url")] [JsonProperty("url")]
public string Url { get; set; } = string.Empty; public string Url { get; set; } = string.Empty;
[JsonProperty("current_user_attributes")]
public CommentableCurrentUserAttributes? CurrentUserAttributes { get; set; }
public struct CommentableCurrentUserAttributes
{
[JsonProperty("can_new_comment_reason")]
public string? CanNewCommentReason { get; set; }
}
} }
} }

View File

@ -14,6 +14,8 @@
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Graphics.UserInterfaceV2;
using osu.Game.Online.API; using osu.Game.Online.API;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Resources.Localisation.Web;
using osuTK; using osuTK;
using osuTK.Graphics; using osuTK.Graphics;
@ -21,6 +23,8 @@ namespace osu.Game.Overlays.Comments
{ {
public abstract partial class CommentEditor : CompositeDrawable public abstract partial class CommentEditor : CompositeDrawable
{ {
public Bindable<CommentableMeta?> CommentableMeta { get; set; } = new Bindable<CommentableMeta?>();
private const int side_padding = 8; private const int side_padding = 8;
protected abstract LocalisableString FooterText { get; } protected abstract LocalisableString FooterText { get; }
@ -53,8 +57,7 @@ public abstract partial class CommentEditor : CompositeDrawable
/// <summary> /// <summary>
/// Returns the placeholder text for the comment box. /// Returns the placeholder text for the comment box.
/// </summary> /// </summary>
/// <param name="isLoggedIn">Whether the current user is logged in.</param> protected abstract LocalisableString GetPlaceholderText();
protected abstract LocalisableString GetPlaceholderText(bool isLoggedIn);
protected bool ShowLoadingSpinner protected bool ShowLoadingSpinner
{ {
@ -168,7 +171,8 @@ protected override void LoadComplete()
{ {
base.LoadComplete(); base.LoadComplete();
Current.BindValueChanged(_ => updateCommitButtonState(), true); Current.BindValueChanged(_ => updateCommitButtonState(), true);
apiState.BindValueChanged(updateStateForLoggedIn, true); apiState.BindValueChanged(_ => updateEnabledState());
CommentableMeta.BindValueChanged(_ => updateEnabledState(), true);
} }
protected abstract void OnCommit(string text); protected abstract void OnCommit(string text);
@ -176,16 +180,25 @@ protected override void LoadComplete()
private void updateCommitButtonState() => private void updateCommitButtonState() =>
commitButton.Enabled.Value = loadingSpinner.State.Value == Visibility.Hidden && !string.IsNullOrEmpty(Current.Value); commitButton.Enabled.Value = loadingSpinner.State.Value == Visibility.Hidden && !string.IsNullOrEmpty(Current.Value);
private void updateStateForLoggedIn(ValueChangedEvent<APIState> state) => Schedule(() => private void updateEnabledState() => Schedule(() =>
{ {
bool isAvailable = state.NewValue > APIState.Offline; bool isOnline = apiState.Value > APIState.Offline;
var canNewCommentReason = CommentEditor.canNewCommentReason(CommentableMeta.Value);
bool commentsDisabled = canNewCommentReason != null;
bool canComment = isOnline && !commentsDisabled;
TextBox.PlaceholderText = GetPlaceholderText(isAvailable); if (!isOnline)
TextBox.ReadOnly = !isAvailable; TextBox.PlaceholderText = AuthorizationStrings.RequireLogin;
else if (canNewCommentReason != null)
TextBox.PlaceholderText = canNewCommentReason.Value;
else
TextBox.PlaceholderText = GetPlaceholderText();
TextBox.ReadOnly = !canComment;
if (isAvailable) if (isOnline)
{ {
commitButton.Show(); commitButton.Show();
commitButton.Enabled.Value = !commentsDisabled;
logInButton.Hide(); logInButton.Hide();
} }
else else
@ -195,6 +208,24 @@ private void updateStateForLoggedIn(ValueChangedEvent<APIState> state) => Schedu
} }
}); });
// https://github.com/ppy/osu-web/blob/83816dbe24ad2927273cba968f2fcd2694a121a9/resources/js/components/comment-editor.tsx#L54-L60
// careful here, logic is VERY finicky.
private static LocalisableString? canNewCommentReason(CommentableMeta? meta)
{
if (meta == null)
return null;
if (meta.CurrentUserAttributes != null)
{
if (meta.CurrentUserAttributes.Value.CanNewCommentReason is string reason)
return reason;
return null;
}
return AuthorizationStrings.CommentStoreDisabled;
}
private partial class EditorTextBox : OsuTextBox private partial class EditorTextBox : OsuTextBox
{ {
protected override float LeftRightPadding => side_padding; protected override float LeftRightPadding => side_padding;

View File

@ -20,6 +20,7 @@
using JetBrains.Annotations; using JetBrains.Annotations;
using osu.Framework.Localisation; using osu.Framework.Localisation;
using osu.Framework.Logging; using osu.Framework.Logging;
using osu.Game.Extensions;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osu.Game.Resources.Localisation.Web; using osu.Game.Resources.Localisation.Web;
using osu.Game.Users.Drawables; using osu.Game.Users.Drawables;
@ -49,6 +50,7 @@ public partial class CommentsContainer : CompositeDrawable
private int currentPage; private int currentPage;
private FillFlowContainer pinnedContent; private FillFlowContainer pinnedContent;
private NewCommentEditor newCommentEditor;
private FillFlowContainer content; private FillFlowContainer content;
private DeletedCommentsCounter deletedCommentsCounter; private DeletedCommentsCounter deletedCommentsCounter;
private CommentsShowMoreButton moreButton; private CommentsShowMoreButton moreButton;
@ -114,7 +116,7 @@ private void load(OverlayColourProvider colourProvider)
Padding = new MarginPadding { Left = 60 }, Padding = new MarginPadding { Left = 60 },
RelativeSizeAxes = Axes.X, RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y, AutoSizeAxes = Axes.Y,
Child = new NewCommentEditor Child = newCommentEditor = new NewCommentEditor
{ {
OnPost = prependPostedComments OnPost = prependPostedComments
} }
@ -242,6 +244,7 @@ protected void ClearComments()
protected void OnSuccess(CommentBundle response) protected void OnSuccess(CommentBundle response)
{ {
commentCounter.Current.Value = response.Total; commentCounter.Current.Value = response.Total;
newCommentEditor.CommentableMeta.Value = response.CommentableMeta.SingleOrDefault(m => m.Id == id.Value && m.Type == type.Value.ToString().ToSnakeCase().ToLowerInvariant());
if (!response.Comments.Any()) if (!response.Comments.Any())
{ {
@ -413,8 +416,7 @@ private partial class NewCommentEditor : CommentEditor
protected override LocalisableString GetButtonText(bool isLoggedIn) => protected override LocalisableString GetButtonText(bool isLoggedIn) =>
isLoggedIn ? CommonStrings.ButtonsPost : CommentsStrings.GuestButtonNew; isLoggedIn ? CommonStrings.ButtonsPost : CommentsStrings.GuestButtonNew;
protected override LocalisableString GetPlaceholderText(bool isLoggedIn) => protected override LocalisableString GetPlaceholderText() => CommentsStrings.PlaceholderNew;
isLoggedIn ? CommentsStrings.PlaceholderNew : AuthorizationStrings.RequireLogin;
protected override void OnCommit(string text) protected override void OnCommit(string text)
{ {

View File

@ -428,7 +428,7 @@ private void toggleReply()
if (replyEditorContainer.Count == 0) if (replyEditorContainer.Count == 0)
{ {
replyEditorContainer.Show(); replyEditorContainer.Show();
replyEditorContainer.Add(new ReplyCommentEditor(Comment) replyEditorContainer.Add(new ReplyCommentEditor(Comment, Meta)
{ {
OnPost = comments => OnPost = comments =>
{ {

View File

@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Localisation; using osu.Framework.Localisation;
@ -26,12 +27,12 @@ public partial class ReplyCommentEditor : CancellableCommentEditor
protected override LocalisableString GetButtonText(bool isLoggedIn) => protected override LocalisableString GetButtonText(bool isLoggedIn) =>
isLoggedIn ? CommonStrings.ButtonsReply : CommentsStrings.GuestButtonReply; isLoggedIn ? CommonStrings.ButtonsReply : CommentsStrings.GuestButtonReply;
protected override LocalisableString GetPlaceholderText(bool isLoggedIn) => protected override LocalisableString GetPlaceholderText() => CommentsStrings.PlaceholderReply;
isLoggedIn ? CommentsStrings.PlaceholderReply : AuthorizationStrings.RequireLogin;
public ReplyCommentEditor(Comment parent) public ReplyCommentEditor(Comment parent, IEnumerable<CommentableMeta> meta)
{ {
parentComment = parent; parentComment = parent;
CommentableMeta.Value = meta.SingleOrDefault(m => m.Id == parent.CommentableId && m.Type == parent.CommentableType);
} }
protected override void LoadComplete() protected override void LoadComplete()