From 768a33bb64a5fef23201c5224bd53336eb80e133 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Fri, 6 Jan 2023 23:31:19 +0300 Subject: [PATCH 01/31] Add request class --- .../Online/API/Requests/CommentPostRequest.cs | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 osu.Game/Online/API/Requests/CommentPostRequest.cs diff --git a/osu.Game/Online/API/Requests/CommentPostRequest.cs b/osu.Game/Online/API/Requests/CommentPostRequest.cs new file mode 100644 index 0000000000..bd69c04bed --- /dev/null +++ b/osu.Game/Online/API/Requests/CommentPostRequest.cs @@ -0,0 +1,41 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Net.Http; +using osu.Framework.IO.Network; +using osu.Game.Online.API.Requests.Responses; + +namespace osu.Game.Online.API.Requests +{ + public class CommentPostRequest : APIRequest + { + public readonly CommentableType Commentable; + public readonly long CommentableId; + public readonly string Message; + public readonly long? ReplyTo; + + public CommentPostRequest(CommentableType commentable, long commentableId, string message, long? replyTo = null) + { + Commentable = commentable; + CommentableId = commentableId; + Message = message; + ReplyTo = replyTo; + } + + protected override WebRequest CreateWebRequest() + { + var req = base.CreateWebRequest(); + req.Method = HttpMethod.Post; + + req.AddParameter(@"comment[commentable_type]", Commentable.ToString()); + req.AddParameter(@"comment[commentable_id]", $"{CommentableId}"); + req.AddParameter(@"comment[message]", Message); + if (ReplyTo.HasValue) + req.AddParameter(@"comment[parent_id]", $"{ReplyTo}"); + + return req; + } + + protected override string Target => "comments"; + } +} From 32e90829e3d0b2df4241ecf9f419446a4d42d587 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 7 Jan 2023 02:59:24 +0300 Subject: [PATCH 02/31] Integrate comment editor into container --- .../Overlays/Comments/CommentsContainer.cs | 68 ++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index 7bd2d6a5e6..c8a2ab39ae 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -17,15 +17,23 @@ using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Threading; using System.Collections.Generic; using JetBrains.Annotations; +using osu.Framework.Localisation; using osu.Game.Graphics.Sprites; using osu.Game.Resources.Localisation.Web; -using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; +using osu.Game.Users.Drawables; +using osuTK; namespace osu.Game.Overlays.Comments { + [Cached] public partial class CommentsContainer : CompositeDrawable { + private const string cid = "commentableId"; + + [Cached] private readonly Bindable type = new Bindable(); + + [Cached(name: cid)] private readonly BindableLong id = new BindableLong(); public readonly Bindable Sort = new Bindable(); @@ -46,12 +54,14 @@ namespace osu.Game.Overlays.Comments private DeletedCommentsCounter deletedCommentsCounter; private CommentsShowMoreButton moreButton; private TotalCommentsCounter commentCounter; + private UpdateableAvatar avatar; [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider) { RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; + AddRangeInternal(new Drawable[] { new Box @@ -86,6 +96,29 @@ namespace osu.Game.Overlays.Comments }, }, }, + new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Padding = new MarginPadding { Horizontal = 50, Vertical = 20 }, + Children = new Drawable[] + { + avatar = new UpdateableAvatar(api.LocalUser.Value) + { + Size = new Vector2(50), + CornerExponent = 2, + CornerRadius = 25, + Masking = true, + }, + new Container + { + Padding = new MarginPadding { Left = 60 }, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Child = new NewCommentEditor() + } + } + }, new CommentsHeader { Sort = { BindTarget = Sort }, @@ -146,6 +179,7 @@ namespace osu.Game.Overlays.Comments }); User.BindTo(api.LocalUser); + User.BindValueChanged(e => avatar.User = e.NewValue); } protected override void LoadComplete() @@ -336,5 +370,37 @@ namespace osu.Game.Overlays.Comments }); } } + + private partial class NewCommentEditor : CommentEditor + { + [Resolved] + public Bindable CommentableType { get; set; } + + [Resolved(name: cid)] + public BindableLong CommentableId { get; set; } + + protected override LocalisableString FooterText => default; + protected override LocalisableString CommitButtonText => CommonStrings.ButtonsPost; + protected override LocalisableString TextBoxPlaceholder => CommentsStrings.PlaceholderNew; + + [Resolved] + private IAPIProvider api { get; set; } + + protected override void OnCommit(string text) + { + CommitButton.IsLoadingSpinnerShown = true; + CommentPostRequest req = new CommentPostRequest(CommentableType.Value, CommentableId.Value, text); + req.Failure += _ => Schedule(() => + { + CommitButton.IsLoadingSpinnerShown = false; + }); + req.Success += cb => Schedule(() => + { + CommitButton.IsLoadingSpinnerShown = false; + Current.Value = string.Empty; + }); + api.Queue(req); + } + } } } From 58bf7349eea9cd4a3600f7c71ca6968feb85e776 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 7 Jan 2023 02:59:32 +0300 Subject: [PATCH 03/31] Fix request --- osu.Game/Online/API/Requests/CommentPostRequest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/API/Requests/CommentPostRequest.cs b/osu.Game/Online/API/Requests/CommentPostRequest.cs index bd69c04bed..7012d479bd 100644 --- a/osu.Game/Online/API/Requests/CommentPostRequest.cs +++ b/osu.Game/Online/API/Requests/CommentPostRequest.cs @@ -27,7 +27,7 @@ namespace osu.Game.Online.API.Requests var req = base.CreateWebRequest(); req.Method = HttpMethod.Post; - req.AddParameter(@"comment[commentable_type]", Commentable.ToString()); + req.AddParameter(@"comment[commentable_type]", Commentable.ToString().ToLowerInvariant()); req.AddParameter(@"comment[commentable_id]", $"{CommentableId}"); req.AddParameter(@"comment[message]", Message); if (ReplyTo.HasValue) From 927773d56584c1b288642a3b143ef118d6ce4d65 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 7 Jan 2023 04:15:43 +0300 Subject: [PATCH 04/31] Display submitted comments locally --- .../Overlays/Comments/CommentsContainer.cs | 46 ++++++++++++++++++- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index c8a2ab39ae..98c186b273 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -3,6 +3,7 @@ #nullable disable +using System; using osu.Framework.Allocation; using osu.Framework.Graphics.Containers; using osu.Game.Online.API; @@ -115,7 +116,10 @@ namespace osu.Game.Overlays.Comments Padding = new MarginPadding { Left = 60 }, RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Child = new NewCommentEditor() + Child = new NewCommentEditor + { + OnPost = prependPostedComments + } } } }, @@ -279,7 +283,6 @@ namespace osu.Game.Overlays.Comments { pinnedContent.AddRange(loaded.Where(d => d.Comment.Pinned)); content.AddRange(loaded.Where(d => !d.Comment.Pinned)); - deletedCommentsCounter.Count.Value += topLevelComments.Select(d => d.Comment).Count(c => c.IsDeleted && c.IsTopLevel); if (bundle.HasMore) @@ -322,6 +325,42 @@ namespace osu.Game.Overlays.Comments } } + private void prependPostedComments(CommentBundle bundle) + { + var topLevelComments = new List(); + + foreach (var comment in bundle.Comments) + { + // Exclude possible duplicated comments. + if (CommentDictionary.ContainsKey(comment.Id)) + continue; + + topLevelComments.Add(getDrawableComment(comment)); + } + + if (topLevelComments.Any()) + { + LoadComponentsAsync(topLevelComments, loaded => + { + if (content[0] is NoCommentsPlaceholder placeholder) + content.Remove(placeholder, true); + + foreach (var comment in loaded) + { + int pos = -1; + + if (content.Count > 0) + { + var first = content.FlowingChildren.First(); + pos = (int)(content.GetLayoutPosition(first) - 1); + } + + content.Insert(pos, comment); + } + }, (loadCancellation = new CancellationTokenSource()).Token); + } + } + private DrawableComment getDrawableComment(Comment comment) { if (CommentDictionary.TryGetValue(comment.Id, out var existing)) @@ -386,6 +425,8 @@ namespace osu.Game.Overlays.Comments [Resolved] private IAPIProvider api { get; set; } + public Action OnPost; + protected override void OnCommit(string text) { CommitButton.IsLoadingSpinnerShown = true; @@ -398,6 +439,7 @@ namespace osu.Game.Overlays.Comments { CommitButton.IsLoadingSpinnerShown = false; Current.Value = string.Empty; + OnPost?.Invoke(cb); }); api.Queue(req); } From 49ce50878d2c761fcc0a43132cf1669f9966d687 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 7 Jan 2023 04:15:53 +0300 Subject: [PATCH 05/31] Add simple test --- .../Online/TestSceneCommentsContainer.cs | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs index 291ccd634d..86a574cf77 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs @@ -11,7 +11,11 @@ using osu.Game.Overlays; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.UserInterface; using osu.Framework.Testing; +using osu.Framework.Utils; +using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; @@ -126,6 +130,24 @@ namespace osu.Game.Tests.Visual.Online commentsContainer.ChildrenOfType().Count(d => d.Comment.Pinned == withPinned) == 1); } + [TestCase] + public void TestPost() + { + setUpCommentsResponse(getExampleComments()); + AddStep("show comments", () => commentsContainer.ShowComments(CommentableType.Beatmapset, 123)); + setUpPostResponse(); + AddStep("Enter text", () => this.ChildrenOfType().Single().ChildrenOfType().Single().Current.Value = "comm"); + AddStep("Submit", () => this.ChildrenOfType().Single().ChildrenOfType().First().TriggerClick()); + AddUntilStep("Comment sent", () => + { + var text = this.ChildrenOfType().Single().ChildrenOfType().Single().Current.Value; + return this.ChildrenOfType().Any(x => + { + return x.ChildrenOfType().Any(y => y.Text == text); + }); + }); + } + private void setUpCommentsResponse(CommentBundle commentBundle) => AddStep("set up response", () => { @@ -139,6 +161,32 @@ namespace osu.Game.Tests.Visual.Online }; }); + private void setUpPostResponse() + => AddStep("set up response", () => + { + dummyAPI.HandleRequest = request => + { + if (!(request is CommentPostRequest req)) + return false; + + req.TriggerSuccess(new CommentBundle + { + Comments = new List + { + new Comment + { + Id = 98, + Message = req.Message, + LegacyName = "FirstUser", + CreatedAt = DateTimeOffset.Now, + VotesCount = 98, + } + } + }); + return true; + }; + }); + private CommentBundle getExampleComments(bool withPinned = false) { var bundle = new CommentBundle From 4baa2670953b4c201f5d70b64149fd6cb064d86d Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 7 Jan 2023 04:26:52 +0300 Subject: [PATCH 06/31] warnings --- osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs index 86a574cf77..e58423241b 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs @@ -14,7 +14,6 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.UserInterface; using osu.Framework.Testing; -using osu.Framework.Utils; using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Online.API; using osu.Game.Online.API.Requests; @@ -140,7 +139,7 @@ namespace osu.Game.Tests.Visual.Online AddStep("Submit", () => this.ChildrenOfType().Single().ChildrenOfType().First().TriggerClick()); AddUntilStep("Comment sent", () => { - var text = this.ChildrenOfType().Single().ChildrenOfType().Single().Current.Value; + string text = this.ChildrenOfType().Single().ChildrenOfType().Single().Current.Value; return this.ChildrenOfType().Any(x => { return x.ChildrenOfType().Any(y => y.Text == text); @@ -187,7 +186,7 @@ namespace osu.Game.Tests.Visual.Online }; }); - private CommentBundle getExampleComments(bool withPinned = false) + private static CommentBundle getExampleComments(bool withPinned = false) { var bundle = new CommentBundle { From 9e7ecbf4a14ebf97459677b128ef70528d0115e2 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 14 Jan 2023 02:41:11 +0300 Subject: [PATCH 07/31] Adapt to changes in base class --- osu.Game/Overlays/Comments/CommentsContainer.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index 98c186b273..08542bbcea 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -429,15 +429,15 @@ namespace osu.Game.Overlays.Comments protected override void OnCommit(string text) { - CommitButton.IsLoadingSpinnerShown = true; + ShowLoadingSpinner = true; CommentPostRequest req = new CommentPostRequest(CommentableType.Value, CommentableId.Value, text); req.Failure += _ => Schedule(() => { - CommitButton.IsLoadingSpinnerShown = false; + ShowLoadingSpinner = false; }); req.Success += cb => Schedule(() => { - CommitButton.IsLoadingSpinnerShown = false; + ShowLoadingSpinner = false; Current.Value = string.Empty; OnPost?.Invoke(cb); }); From bb8bcd7248153a5bf1ae2c96dcaf0e93bda0502e Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 14 Jan 2023 02:50:30 +0300 Subject: [PATCH 08/31] Move avatar update bind to LoadComplete --- osu.Game/Overlays/Comments/CommentsContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index 08542bbcea..9446857f5e 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -183,12 +183,12 @@ namespace osu.Game.Overlays.Comments }); User.BindTo(api.LocalUser); - User.BindValueChanged(e => avatar.User = e.NewValue); } protected override void LoadComplete() { User.BindValueChanged(_ => refetchComments()); + User.BindValueChanged(e => avatar.User = e.NewValue); Sort.BindValueChanged(_ => refetchComments(), true); base.LoadComplete(); } From fbb674d8e9d809b9a5154525d96e36685e928fac Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 14 Jan 2023 20:15:19 +0300 Subject: [PATCH 09/31] Rename parent comment id field --- osu.Game/Online/API/Requests/CommentPostRequest.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game/Online/API/Requests/CommentPostRequest.cs b/osu.Game/Online/API/Requests/CommentPostRequest.cs index 7012d479bd..45e5eb1a94 100644 --- a/osu.Game/Online/API/Requests/CommentPostRequest.cs +++ b/osu.Game/Online/API/Requests/CommentPostRequest.cs @@ -12,14 +12,14 @@ namespace osu.Game.Online.API.Requests public readonly CommentableType Commentable; public readonly long CommentableId; public readonly string Message; - public readonly long? ReplyTo; + public readonly long? ParentCommentId; - public CommentPostRequest(CommentableType commentable, long commentableId, string message, long? replyTo = null) + public CommentPostRequest(CommentableType commentable, long commentableId, string message, long? parentCommentId = null) { Commentable = commentable; CommentableId = commentableId; Message = message; - ReplyTo = replyTo; + ParentCommentId = parentCommentId; } protected override WebRequest CreateWebRequest() @@ -30,8 +30,8 @@ namespace osu.Game.Online.API.Requests req.AddParameter(@"comment[commentable_type]", Commentable.ToString().ToLowerInvariant()); req.AddParameter(@"comment[commentable_id]", $"{CommentableId}"); req.AddParameter(@"comment[message]", Message); - if (ReplyTo.HasValue) - req.AddParameter(@"comment[parent_id]", $"{ReplyTo}"); + if (ParentCommentId.HasValue) + req.AddParameter(@"comment[parent_id]", $"{ParentCommentId}"); return req; } From 88c3eef8e1b48e01827c50d10cacfca55bebad53 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 14 Jan 2023 20:59:13 +0300 Subject: [PATCH 10/31] Add test case with no existing comments --- .../Online/TestSceneCommentsContainer.cs | 45 ++++++++++++++----- .../Overlays/Comments/CommentsContainer.cs | 2 +- 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs index e58423241b..4a41eca898 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs @@ -32,13 +32,18 @@ namespace osu.Game.Tests.Visual.Online private CommentsContainer commentsContainer; + private TextBox editorTextBox; + [SetUp] public void SetUp() => Schedule(() => + { Child = new BasicScrollContainer { RelativeSizeAxes = Axes.Both, Child = commentsContainer = new CommentsContainer() - }); + }; + editorTextBox = commentsContainer.ChildrenOfType().First(); + }); [Test] public void TestIdleState() @@ -129,21 +134,41 @@ namespace osu.Game.Tests.Visual.Online commentsContainer.ChildrenOfType().Count(d => d.Comment.Pinned == withPinned) == 1); } - [TestCase] + [Test] public void TestPost() + { + setUpCommentsResponse(new CommentBundle { Comments = new List() }); + AddStep("show comments", () => commentsContainer.ShowComments(CommentableType.Beatmapset, 123)); + AddAssert("no comments placeholder shown", () => commentsContainer.ChildrenOfType().Any()); + + setUpPostResponse(); + AddStep("enter text", () => editorTextBox.Current.Value = "comm"); + AddStep("submit", () => commentsContainer.ChildrenOfType().First().TriggerClick()); + + AddUntilStep("comment sent", () => + { + string writtenText = editorTextBox.Current.Value; + var comment = commentsContainer.ChildrenOfType().Last(); + return comment.ChildrenOfType().Any(y => y.Text == writtenText); + }); + AddAssert("no comments placeholder removed", () => !commentsContainer.ChildrenOfType().Any()); + } + + [Test] + public void TestPostWithExistingComments() { setUpCommentsResponse(getExampleComments()); AddStep("show comments", () => commentsContainer.ShowComments(CommentableType.Beatmapset, 123)); + setUpPostResponse(); - AddStep("Enter text", () => this.ChildrenOfType().Single().ChildrenOfType().Single().Current.Value = "comm"); - AddStep("Submit", () => this.ChildrenOfType().Single().ChildrenOfType().First().TriggerClick()); - AddUntilStep("Comment sent", () => + AddStep("enter text", () => editorTextBox.Current.Value = "comm"); + AddStep("submit", () => commentsContainer.ChildrenOfType().Single().ChildrenOfType().First().TriggerClick()); + + AddUntilStep("comment sent", () => { - string text = this.ChildrenOfType().Single().ChildrenOfType().Single().Current.Value; - return this.ChildrenOfType().Any(x => - { - return x.ChildrenOfType().Any(y => y.Text == text); - }); + string writtenText = editorTextBox.Current.Value; + var comment = commentsContainer.ChildrenOfType().Last(); + return comment.ChildrenOfType().Any(y => y.Text == writtenText); }); } diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index 9446857f5e..a8939ffdc6 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -390,7 +390,7 @@ namespace osu.Game.Overlays.Comments base.Dispose(isDisposing); } - private partial class NoCommentsPlaceholder : CompositeDrawable + internal partial class NoCommentsPlaceholder : CompositeDrawable { [BackgroundDependencyLoader] private void load() From cdf3aafdddd4c987c2ad8b5aa4ece2a03703f174 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 14 Jan 2023 22:37:05 +0300 Subject: [PATCH 11/31] Add check for any drawables in content before looking for placeholder --- osu.Game/Overlays/Comments/CommentsContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index a8939ffdc6..58f7a72ee5 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -342,7 +342,7 @@ namespace osu.Game.Overlays.Comments { LoadComponentsAsync(topLevelComments, loaded => { - if (content[0] is NoCommentsPlaceholder placeholder) + if (content.Count > 0 && content[0] is NoCommentsPlaceholder placeholder) content.Remove(placeholder, true); foreach (var comment in loaded) From c2bb0949f52404739cea5dd5d544b3068615efb8 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 14 Jan 2023 22:57:23 +0300 Subject: [PATCH 12/31] Take type and id from container directly on submit --- .../Overlays/Comments/CommentsContainer.cs | 24 ++++++++----------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index 58f7a72ee5..67db0714dc 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -29,13 +29,10 @@ namespace osu.Game.Overlays.Comments [Cached] public partial class CommentsContainer : CompositeDrawable { - private const string cid = "commentableId"; - - [Cached] private readonly Bindable type = new Bindable(); - - [Cached(name: cid)] private readonly BindableLong id = new BindableLong(); + public IBindable Type => type; + public IBindable Id => id; public readonly Bindable Sort = new Bindable(); public readonly BindableBool ShowDeleted = new BindableBool(); @@ -413,24 +410,23 @@ namespace osu.Game.Overlays.Comments private partial class NewCommentEditor : CommentEditor { [Resolved] - public Bindable CommentableType { get; set; } - - [Resolved(name: cid)] - public BindableLong CommentableId { get; set; } - - protected override LocalisableString FooterText => default; - protected override LocalisableString CommitButtonText => CommonStrings.ButtonsPost; - protected override LocalisableString TextBoxPlaceholder => CommentsStrings.PlaceholderNew; + private CommentsContainer commentsContainer { get; set; } [Resolved] private IAPIProvider api { get; set; } public Action OnPost; + protected override LocalisableString FooterText => default; + + protected override LocalisableString CommitButtonText => CommonStrings.ButtonsPost; + + protected override LocalisableString TextBoxPlaceholder => CommentsStrings.PlaceholderNew; + protected override void OnCommit(string text) { ShowLoadingSpinner = true; - CommentPostRequest req = new CommentPostRequest(CommentableType.Value, CommentableId.Value, text); + CommentPostRequest req = new CommentPostRequest(commentsContainer.Type.Value, commentsContainer.Id.Value, text); req.Failure += _ => Schedule(() => { ShowLoadingSpinner = false; From c36922dd2c630dfb621633e359de61b0636941e7 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 14 Jan 2023 22:57:51 +0300 Subject: [PATCH 13/31] Use clock to obtain a position for comment insertion --- osu.Game/Overlays/Comments/CommentsContainer.cs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index 67db0714dc..c626d1f26c 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -344,15 +344,7 @@ namespace osu.Game.Overlays.Comments foreach (var comment in loaded) { - int pos = -1; - - if (content.Count > 0) - { - var first = content.FlowingChildren.First(); - pos = (int)(content.GetLayoutPosition(first) - 1); - } - - content.Insert(pos, comment); + content.Insert((int)-Clock.CurrentTime, comment); } }, (loadCancellation = new CancellationTokenSource()).Token); } From 58406cae19851cf6910ffb5fbc04aea54af78e42 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 14 Jan 2023 23:42:10 +0300 Subject: [PATCH 14/31] Make test wait for comment loading --- .../Visual/Online/TestSceneCommentsContainer.cs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs index 4a41eca898..3d8781d902 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs @@ -1,8 +1,6 @@ // 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 System.Collections.Generic; using System.Linq; @@ -30,9 +28,9 @@ namespace osu.Game.Tests.Visual.Online private DummyAPIAccess dummyAPI => (DummyAPIAccess)API; - private CommentsContainer commentsContainer; + private CommentsContainer commentsContainer = null!; - private TextBox editorTextBox; + private TextBox editorTextBox = null!; [SetUp] public void SetUp() => Schedule(() => @@ -148,8 +146,8 @@ namespace osu.Game.Tests.Visual.Online AddUntilStep("comment sent", () => { string writtenText = editorTextBox.Current.Value; - var comment = commentsContainer.ChildrenOfType().Last(); - return comment.ChildrenOfType().Any(y => y.Text == writtenText); + var comment = commentsContainer.ChildrenOfType().LastOrDefault(); + return comment != null && comment.ChildrenOfType().Any(y => y.Text == writtenText); }); AddAssert("no comments placeholder removed", () => !commentsContainer.ChildrenOfType().Any()); } @@ -167,8 +165,8 @@ namespace osu.Game.Tests.Visual.Online AddUntilStep("comment sent", () => { string writtenText = editorTextBox.Current.Value; - var comment = commentsContainer.ChildrenOfType().Last(); - return comment.ChildrenOfType().Any(y => y.Text == writtenText); + var comment = commentsContainer.ChildrenOfType().LastOrDefault(); + return comment != null && comment.ChildrenOfType().Any(y => y.Text == writtenText); }); } From 1480c691ae8bbf2ca0fbe4b88acc5eb426f7ffc5 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 14 Jan 2023 23:42:56 +0300 Subject: [PATCH 15/31] Explain empty string in editor's footer --- osu.Game/Overlays/Comments/CommentsContainer.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index c626d1f26c..3639fe1835 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -409,6 +409,7 @@ namespace osu.Game.Overlays.Comments public Action OnPost; + //TODO should match web, left empty due to no multiline support protected override LocalisableString FooterText => default; protected override LocalisableString CommitButtonText => CommonStrings.ButtonsPost; From 26cd70f2bfde476c3fe08df4ef363b6bfc10512b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Jan 2023 18:44:42 +0900 Subject: [PATCH 16/31] Always use production (non-experimental) endpoints for tournament client --- osu.Game.Tournament/TournamentGameBase.cs | 9 +++++++++ .../ExperimentalEndpointConfiguration.cs | 19 +++++++++++++++++++ .../Online/ProductionEndpointConfiguration.cs | 5 +---- osu.Game/OsuGameBase.cs | 4 ++-- 4 files changed, 31 insertions(+), 6 deletions(-) create mode 100644 osu.Game/Online/ExperimentalEndpointConfiguration.cs diff --git a/osu.Game.Tournament/TournamentGameBase.cs b/osu.Game.Tournament/TournamentGameBase.cs index 08f21cb556..c61ee0d3e8 100644 --- a/osu.Game.Tournament/TournamentGameBase.cs +++ b/osu.Game.Tournament/TournamentGameBase.cs @@ -16,6 +16,7 @@ using osu.Framework.IO.Stores; using osu.Framework.Logging; using osu.Framework.Platform; using osu.Game.Graphics; +using osu.Game.Online; using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; using osu.Game.Tournament.IO; @@ -44,6 +45,14 @@ namespace osu.Game.Tournament return dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); } + public override EndpointConfiguration CreateEndpoints() + { + if (UseDevelopmentServer) + return base.CreateEndpoints(); + + return new ProductionEndpointConfiguration(); + } + private TournamentSpriteText initialisationText; [BackgroundDependencyLoader] diff --git a/osu.Game/Online/ExperimentalEndpointConfiguration.cs b/osu.Game/Online/ExperimentalEndpointConfiguration.cs new file mode 100644 index 0000000000..c3d0014c8b --- /dev/null +++ b/osu.Game/Online/ExperimentalEndpointConfiguration.cs @@ -0,0 +1,19 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +namespace osu.Game.Online +{ + public class ExperimentalEndpointConfiguration : EndpointConfiguration + { + public ExperimentalEndpointConfiguration() + { + WebsiteRootUrl = @"https://osu.ppy.sh"; + APIEndpointUrl = @"https://lazer.ppy.sh"; + APIClientSecret = @"FGc9GAtyHzeQDshWP5Ah7dega8hJACAJpQtw6OXk"; + APIClientID = "5"; + SpectatorEndpointUrl = "https://spectator.ppy.sh/spectator"; + MultiplayerEndpointUrl = "https://spectator.ppy.sh/multiplayer"; + MetadataEndpointUrl = "https://spectator.ppy.sh/metadata"; + } + } +} diff --git a/osu.Game/Online/ProductionEndpointConfiguration.cs b/osu.Game/Online/ProductionEndpointConfiguration.cs index 003ec50afd..0244761b65 100644 --- a/osu.Game/Online/ProductionEndpointConfiguration.cs +++ b/osu.Game/Online/ProductionEndpointConfiguration.cs @@ -1,16 +1,13 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - namespace osu.Game.Online { public class ProductionEndpointConfiguration : EndpointConfiguration { public ProductionEndpointConfiguration() { - WebsiteRootUrl = @"https://osu.ppy.sh"; - APIEndpointUrl = @"https://lazer.ppy.sh"; + WebsiteRootUrl = APIEndpointUrl = @"https://osu.ppy.sh"; APIClientSecret = @"FGc9GAtyHzeQDshWP5Ah7dega8hJACAJpQtw6OXk"; APIClientID = "5"; SpectatorEndpointUrl = "https://spectator.ppy.sh/spectator"; diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index b27be37591..1c50349941 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -98,8 +98,8 @@ namespace osu.Game public virtual bool UseDevelopmentServer => DebugUtils.IsDebugBuild; - internal EndpointConfiguration CreateEndpoints() => - UseDevelopmentServer ? new DevelopmentEndpointConfiguration() : new ProductionEndpointConfiguration(); + public virtual EndpointConfiguration CreateEndpoints() => + UseDevelopmentServer ? new DevelopmentEndpointConfiguration() : new ExperimentalEndpointConfiguration(); public virtual Version AssemblyVersion => Assembly.GetEntryAssembly()?.GetName().Version ?? new Version(); From 68636aeaaa339d9a2dc82402d46d68bbb6004b90 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Jan 2023 18:56:15 +0900 Subject: [PATCH 17/31] Fix tournament client not saving changes after populating new data --- osu.Game.Tournament/TournamentGameBase.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tournament/TournamentGameBase.cs b/osu.Game.Tournament/TournamentGameBase.cs index 08f21cb556..e4fe922a51 100644 --- a/osu.Game.Tournament/TournamentGameBase.cs +++ b/osu.Game.Tournament/TournamentGameBase.cs @@ -156,7 +156,7 @@ namespace osu.Game.Tournament addedInfo |= addSeedingBeatmaps(); if (addedInfo) - SaveChanges(); + saveChanges(); ladder.CurrentMatch.Value = ladder.Matches.FirstOrDefault(p => p.Current.Value); } @@ -306,6 +306,11 @@ namespace osu.Game.Tournament return; } + saveChanges(); + } + + private void saveChanges() + { foreach (var r in ladder.Rounds) r.Matches = ladder.Matches.Where(p => p.Round.Value == r).Select(p => p.ID).ToList(); From 74bb44e05d668b70a53d08d1d1289e9ae9084cdd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Jan 2023 18:59:43 +0900 Subject: [PATCH 18/31] Fix player rank data not being re-fetched after a tournament's ruleset is changed --- osu.Game.Tournament/Screens/Setup/SetupScreen.cs | 2 +- osu.Game.Tournament/TournamentGameBase.cs | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tournament/Screens/Setup/SetupScreen.cs b/osu.Game.Tournament/Screens/Setup/SetupScreen.cs index b86513eb49..ceddd4d1a1 100644 --- a/osu.Game.Tournament/Screens/Setup/SetupScreen.cs +++ b/osu.Game.Tournament/Screens/Setup/SetupScreen.cs @@ -113,7 +113,7 @@ namespace osu.Game.Tournament.Screens.Setup new LabelledDropdown { Label = "Ruleset", - Description = "Decides what stats are displayed and which ranks are retrieved for players.", + Description = "Decides what stats are displayed and which ranks are retrieved for players. This requires a restart to reload data for an existing bracket.", Items = rulesets.AvailableRulesets, Current = LadderInfo.Ruleset, }, diff --git a/osu.Game.Tournament/TournamentGameBase.cs b/osu.Game.Tournament/TournamentGameBase.cs index 08f21cb556..ed766c69df 100644 --- a/osu.Game.Tournament/TournamentGameBase.cs +++ b/osu.Game.Tournament/TournamentGameBase.cs @@ -159,6 +159,18 @@ namespace osu.Game.Tournament SaveChanges(); ladder.CurrentMatch.Value = ladder.Matches.FirstOrDefault(p => p.Current.Value); + + ladder.Ruleset.BindValueChanged(r => + { + // Refetch player rank data on next startup as the ruleset has changed. + foreach (var team in ladder.Teams) + { + foreach (var player in team.Players) + player.Rank = null; + } + + SaveChanges(); + }); } catch (Exception e) { From e65108533ab3f42a0d6a6fdfc0926d2cf02f96a0 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Tue, 17 Jan 2023 22:12:06 +0900 Subject: [PATCH 19/31] Reduce number of tested value combination 121 combinations took 2min+ --- .../TestSceneSliderFollowCircleInput.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderFollowCircleInput.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderFollowCircleInput.cs index 0af0ff5604..369c3d6168 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderFollowCircleInput.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderFollowCircleInput.cs @@ -31,9 +31,9 @@ namespace osu.Game.Rulesets.Osu.Tests [Test] public void TestMaximumDistanceTrackingWithoutMovement( - [Values(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)] + [Values(0, 5, 10)] float circleSize, - [Values(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)] + [Values(0, 5, 10)] double velocity) { const double time_slider_start = 1000; From 8e1002b7448e1045f12cea690ed50c2e3361c6ed Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Jan 2023 01:56:12 +0900 Subject: [PATCH 20/31] Fix song select potentially operating on `Carousel` before it is fully loaded Should fix test failures like https://github.com/ppy/osu/actions/runs/3939620830/jobs/6739690253. --- osu.Game/Screens/Select/SongSelect.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 64deb59026..db4d326991 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -860,9 +860,13 @@ namespace osu.Game.Screens.Select Logger.Log($"decoupled ruleset transferred (\"{decoupledRuleset.Value}\" -> \"{Ruleset.Value}\")"); rulesetNoDebounce = decoupledRuleset.Value = Ruleset.Value; - // if we have a pending filter operation, we want to run it now. - // it could change selection (ie. if the ruleset has been changed). - Carousel.FlushPendingFilterOperations(); + if (Carousel.IsLoaded) + { + // if we have a pending filter operation, we want to run it now. + // it could change selection (ie. if the ruleset has been changed). + Carousel.FlushPendingFilterOperations(); + } + return true; } From 452bf9255023fe6a7ac9c62e6856af7d721b4b3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 17 Jan 2023 18:02:06 +0100 Subject: [PATCH 21/31] Fix code quality inspection --- .../TestSceneSliderFollowCircleInput.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderFollowCircleInput.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderFollowCircleInput.cs index 369c3d6168..a32f0a13b8 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderFollowCircleInput.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderFollowCircleInput.cs @@ -31,10 +31,8 @@ namespace osu.Game.Rulesets.Osu.Tests [Test] public void TestMaximumDistanceTrackingWithoutMovement( - [Values(0, 5, 10)] - float circleSize, - [Values(0, 5, 10)] - double velocity) + [Values(0, 5, 10)] float circleSize, + [Values(0, 5, 10)] double velocity) { const double time_slider_start = 1000; From 97bd76efc6638c4994c06442c3bcd28057bd9672 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Tue, 17 Jan 2023 09:47:42 -0800 Subject: [PATCH 22/31] Add ability to easily mention users in chat by right clicking username --- osu.Game/Localisation/ChatStrings.cs | 5 +++++ osu.Game/Online/Chat/StandAloneChatDisplay.cs | 1 + osu.Game/Overlays/Chat/DrawableUsername.cs | 13 +++++++++++++ 3 files changed, 19 insertions(+) diff --git a/osu.Game/Localisation/ChatStrings.cs b/osu.Game/Localisation/ChatStrings.cs index 7bd284a94e..6b0a6bd8e1 100644 --- a/osu.Game/Localisation/ChatStrings.cs +++ b/osu.Game/Localisation/ChatStrings.cs @@ -19,6 +19,11 @@ namespace osu.Game.Localisation /// public static LocalisableString HeaderDescription => new TranslatableString(getKey(@"header_description"), @"join the real-time discussion"); + /// + /// "Mention" + /// + public static LocalisableString MentionUser => new TranslatableString(getKey(@"mention_user"), @"Mention"); + private static string getKey(string key) => $"{prefix}:{key}"; } } diff --git a/osu.Game/Online/Chat/StandAloneChatDisplay.cs b/osu.Game/Online/Chat/StandAloneChatDisplay.cs index 0a5434822b..e3b5037367 100644 --- a/osu.Game/Online/Chat/StandAloneChatDisplay.cs +++ b/osu.Game/Online/Chat/StandAloneChatDisplay.cs @@ -25,6 +25,7 @@ namespace osu.Game.Online.Chat /// public partial class StandAloneChatDisplay : CompositeDrawable { + [Cached] public readonly Bindable Channel = new Bindable(); protected readonly ChatTextBox TextBox; diff --git a/osu.Game/Overlays/Chat/DrawableUsername.cs b/osu.Game/Overlays/Chat/DrawableUsername.cs index 8cd16047f3..73eb335e99 100644 --- a/osu.Game/Overlays/Chat/DrawableUsername.cs +++ b/osu.Game/Overlays/Chat/DrawableUsername.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -24,6 +25,7 @@ using osu.Game.Online.Chat; using osu.Game.Resources.Localisation.Web; using osuTK; using osuTK.Graphics; +using ChatStrings = osu.Game.Localisation.ChatStrings; namespace osu.Game.Overlays.Chat { @@ -65,6 +67,9 @@ namespace osu.Game.Overlays.Chat [Resolved(canBeNull: true)] private UserProfileOverlay? profileOverlay { get; set; } + [Resolved] + private Bindable? currentChannel { get; set; } + private readonly APIUser user; private readonly OsuSpriteText drawableText; @@ -156,6 +161,14 @@ namespace osu.Game.Overlays.Chat if (!user.Equals(api.LocalUser.Value)) items.Add(new OsuMenuItem(UsersStrings.CardSendMessage, MenuItemType.Standard, openUserChannel)); + if (currentChannel != null) + { + items.Add(new OsuMenuItem(ChatStrings.MentionUser, MenuItemType.Standard, () => + { + currentChannel.Value.TextBoxMessage.Value += $"@{user.Username}"; + })); + } + return items.ToArray(); } } From 364034280563cfd683136e9c005e91801fc3a678 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 17 Jan 2023 21:30:46 +0100 Subject: [PATCH 23/31] Add logging on comment post failure --- osu.Game/Overlays/Comments/CommentsContainer.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index 3639fe1835..a334fac215 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -19,6 +19,7 @@ using osu.Framework.Threading; using System.Collections.Generic; using JetBrains.Annotations; using osu.Framework.Localisation; +using osu.Framework.Logging; using osu.Game.Graphics.Sprites; using osu.Game.Resources.Localisation.Web; using osu.Game.Users.Drawables; @@ -420,9 +421,10 @@ namespace osu.Game.Overlays.Comments { ShowLoadingSpinner = true; CommentPostRequest req = new CommentPostRequest(commentsContainer.Type.Value, commentsContainer.Id.Value, text); - req.Failure += _ => Schedule(() => + req.Failure += e => Schedule(() => { ShowLoadingSpinner = false; + Logger.Error(e, "Posting comment failed."); }); req.Success += cb => Schedule(() => { From 350cce1315d050b8d466edd3549ad309517fe8d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 31 Dec 2022 18:39:36 +0100 Subject: [PATCH 24/31] Move contents of detail header to separate component --- .../Profile/Header/Components/MainDetails.cs | 187 ++++++++++++++++++ .../Profile/Header/DetailHeaderContainer.cs | 161 +-------------- 2 files changed, 190 insertions(+), 158 deletions(-) create mode 100644 osu.Game/Overlays/Profile/Header/Components/MainDetails.cs diff --git a/osu.Game/Overlays/Profile/Header/Components/MainDetails.cs b/osu.Game/Overlays/Profile/Header/Components/MainDetails.cs new file mode 100644 index 0000000000..930ba29c7f --- /dev/null +++ b/osu.Game/Overlays/Profile/Header/Components/MainDetails.cs @@ -0,0 +1,187 @@ +// 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.LocalisationExtensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Localisation; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Online.Leaderboards; +using osu.Game.Resources.Localisation.Web; +using osu.Game.Scoring; +using osuTK; + +namespace osu.Game.Overlays.Profile.Header.Components +{ + public partial class MainDetails : CompositeDrawable + { + private readonly Dictionary scoreRankInfos = new Dictionary(); + private ProfileValueDisplay medalInfo = null!; + private ProfileValueDisplay ppInfo = null!; + private ProfileValueDisplay detailGlobalRank = null!; + private ProfileValueDisplay detailCountryRank = null!; + private RankGraph rankGraph = null!; + + public readonly Bindable User = new Bindable(); + + [BackgroundDependencyLoader] + private void load() + { + AutoSizeAxes = Axes.Y; + + InternalChild = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + AutoSizeDuration = 200, + AutoSizeEasing = Easing.OutQuint, + Masking = true, + Padding = new MarginPadding { Horizontal = UserProfileOverlay.CONTENT_X_MARGIN, Vertical = 10 }, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 15), + Children = new Drawable[] + { + new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(20), + Children = new Drawable[] + { + detailGlobalRank = new ProfileValueDisplay(true) + { + Title = UsersStrings.ShowRankGlobalSimple, + }, + detailCountryRank = new ProfileValueDisplay(true) + { + Title = UsersStrings.ShowRankCountrySimple, + }, + } + }, + new Container + { + RelativeSizeAxes = Axes.X, + Height = 60, + Children = new Drawable[] + { + rankGraph = new RankGraph + { + RelativeSizeAxes = Axes.Both, + }, + } + }, + new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Children = new Drawable[] + { + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(10, 0), + Children = new Drawable[] + { + medalInfo = new ProfileValueDisplay + { + Title = UsersStrings.ShowStatsMedals, + }, + ppInfo = new ProfileValueDisplay + { + Title = "pp", + }, + new TotalPlayTime + { + User = { BindTarget = User } + }, + } + }, + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(5), + Children = new[] + { + scoreRankInfos[ScoreRank.XH] = new ScoreRankInfo(ScoreRank.XH), + scoreRankInfos[ScoreRank.X] = new ScoreRankInfo(ScoreRank.X), + scoreRankInfos[ScoreRank.SH] = new ScoreRankInfo(ScoreRank.SH), + scoreRankInfos[ScoreRank.S] = new ScoreRankInfo(ScoreRank.S), + scoreRankInfos[ScoreRank.A] = new ScoreRankInfo(ScoreRank.A), + } + } + } + }, + } + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + User.BindValueChanged(e => updateDisplay(e.NewValue), true); + } + + private void updateDisplay(UserProfileData? data) + { + var user = data?.User; + + medalInfo.Content = user?.Achievements?.Length.ToString() ?? "0"; + ppInfo.Content = user?.Statistics?.PP?.ToLocalisableString("#,##0") ?? (LocalisableString)"0"; + + foreach (var scoreRankInfo in scoreRankInfos) + scoreRankInfo.Value.RankCount = user?.Statistics?.GradesCount[scoreRankInfo.Key] ?? 0; + + detailGlobalRank.Content = user?.Statistics?.GlobalRank?.ToLocalisableString("\\##,##0") ?? (LocalisableString)"-"; + detailCountryRank.Content = user?.Statistics?.CountryRank?.ToLocalisableString("\\##,##0") ?? (LocalisableString)"-"; + + rankGraph.Statistics.Value = user?.Statistics; + } + + private partial class ScoreRankInfo : CompositeDrawable + { + private readonly OsuSpriteText rankCount; + + public int RankCount + { + set => rankCount.Text = value.ToLocalisableString("#,##0"); + } + + public ScoreRankInfo(ScoreRank rank) + { + AutoSizeAxes = Axes.Both; + InternalChild = new FillFlowContainer + { + AutoSizeAxes = Axes.Y, + Width = 44, + Direction = FillDirection.Vertical, + Children = new Drawable[] + { + new DrawableRank(rank) + { + RelativeSizeAxes = Axes.X, + Height = 22, + }, + rankCount = new OsuSpriteText + { + Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold), + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre + } + } + }; + } + } + } +} diff --git a/osu.Game/Overlays/Profile/Header/DetailHeaderContainer.cs b/osu.Game/Overlays/Profile/Header/DetailHeaderContainer.cs index 890e6c4e04..17de8b8ba0 100644 --- a/osu.Game/Overlays/Profile/Header/DetailHeaderContainer.cs +++ b/osu.Game/Overlays/Profile/Header/DetailHeaderContainer.cs @@ -1,33 +1,17 @@ // 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.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; -using osu.Framework.Localisation; -using osu.Game.Graphics; -using osu.Game.Graphics.Sprites; -using osu.Game.Online.Leaderboards; using osu.Game.Overlays.Profile.Header.Components; -using osu.Game.Resources.Localisation.Web; -using osu.Game.Scoring; -using osuTK; namespace osu.Game.Overlays.Profile.Header { public partial class DetailHeaderContainer : CompositeDrawable { - private readonly Dictionary scoreRankInfos = new Dictionary(); - private ProfileValueDisplay medalInfo = null!; - private ProfileValueDisplay ppInfo = null!; - private ProfileValueDisplay detailGlobalRank = null!; - private ProfileValueDisplay detailCountryRank = null!; - private RankGraph rankGraph = null!; - public readonly Bindable User = new Bindable(); [BackgroundDependencyLoader] @@ -35,8 +19,6 @@ namespace osu.Game.Overlays.Profile.Header { AutoSizeAxes = Axes.Y; - User.ValueChanged += e => updateDisplay(e.NewValue); - InternalChildren = new Drawable[] { new Box @@ -44,149 +26,12 @@ namespace osu.Game.Overlays.Profile.Header RelativeSizeAxes = Axes.Both, Colour = colourProvider.Background5, }, - new FillFlowContainer + new MainDetails { RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - AutoSizeDuration = 200, - AutoSizeEasing = Easing.OutQuint, - Masking = true, - Padding = new MarginPadding { Horizontal = UserProfileOverlay.CONTENT_X_MARGIN, Vertical = 10 }, - Direction = FillDirection.Vertical, - Spacing = new Vector2(0, 15), - Children = new Drawable[] - { - new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(20), - Children = new Drawable[] - { - detailGlobalRank = new ProfileValueDisplay(true) - { - Title = UsersStrings.ShowRankGlobalSimple, - }, - detailCountryRank = new ProfileValueDisplay(true) - { - Title = UsersStrings.ShowRankCountrySimple, - }, - } - }, - new Container - { - RelativeSizeAxes = Axes.X, - Height = 60, - Children = new Drawable[] - { - rankGraph = new RankGraph - { - RelativeSizeAxes = Axes.Both, - }, - } - }, - new Container - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Children = new Drawable[] - { - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(10, 0), - Children = new Drawable[] - { - medalInfo = new ProfileValueDisplay - { - Title = UsersStrings.ShowStatsMedals, - }, - ppInfo = new ProfileValueDisplay - { - Title = "pp", - }, - new TotalPlayTime - { - User = { BindTarget = User } - }, - } - }, - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(5), - Children = new[] - { - scoreRankInfos[ScoreRank.XH] = new ScoreRankInfo(ScoreRank.XH), - scoreRankInfos[ScoreRank.X] = new ScoreRankInfo(ScoreRank.X), - scoreRankInfos[ScoreRank.SH] = new ScoreRankInfo(ScoreRank.SH), - scoreRankInfos[ScoreRank.S] = new ScoreRankInfo(ScoreRank.S), - scoreRankInfos[ScoreRank.A] = new ScoreRankInfo(ScoreRank.A), - } - } - } - }, - } - }, + User = { BindTarget = User } + } }; } - - private void updateDisplay(UserProfileData? data) - { - var user = data?.User; - - medalInfo.Content = user?.Achievements?.Length.ToString() ?? "0"; - ppInfo.Content = user?.Statistics?.PP?.ToLocalisableString("#,##0") ?? (LocalisableString)"0"; - - foreach (var scoreRankInfo in scoreRankInfos) - scoreRankInfo.Value.RankCount = user?.Statistics?.GradesCount[scoreRankInfo.Key] ?? 0; - - detailGlobalRank.Content = user?.Statistics?.GlobalRank?.ToLocalisableString("\\##,##0") ?? (LocalisableString)"-"; - detailCountryRank.Content = user?.Statistics?.CountryRank?.ToLocalisableString("\\##,##0") ?? (LocalisableString)"-"; - - rankGraph.Statistics.Value = user?.Statistics; - } - - private partial class ScoreRankInfo : CompositeDrawable - { - private readonly OsuSpriteText rankCount; - - public int RankCount - { - set => rankCount.Text = value.ToLocalisableString("#,##0"); - } - - public ScoreRankInfo(ScoreRank rank) - { - AutoSizeAxes = Axes.Both; - InternalChild = new FillFlowContainer - { - AutoSizeAxes = Axes.Y, - Width = 44, - Direction = FillDirection.Vertical, - Children = new Drawable[] - { - new DrawableRank(rank) - { - RelativeSizeAxes = Axes.X, - Height = 22, - }, - rankCount = new OsuSpriteText - { - Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold), - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre - } - } - }; - } - } } } From 7a475d9cf8b160ad9ce77ba283c8b4696298c2aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 31 Dec 2022 18:55:27 +0100 Subject: [PATCH 25/31] Move out stats from top header container --- .../Header/Components/ExtendedDetails.cs | 108 ++++++++++++++++++ .../Profile/Header/TopHeaderContainer.cs | 51 --------- 2 files changed, 108 insertions(+), 51 deletions(-) create mode 100644 osu.Game/Overlays/Profile/Header/Components/ExtendedDetails.cs diff --git a/osu.Game/Overlays/Profile/Header/Components/ExtendedDetails.cs b/osu.Game/Overlays/Profile/Header/Components/ExtendedDetails.cs new file mode 100644 index 0000000000..b50b0041d0 --- /dev/null +++ b/osu.Game/Overlays/Profile/Header/Components/ExtendedDetails.cs @@ -0,0 +1,108 @@ +// 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.Extensions.LocalisationExtensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Resources.Localisation.Web; +using osu.Game.Users; +using osuTK; + +namespace osu.Game.Overlays.Profile.Header.Components +{ + public partial class ExtendedDetails : CompositeDrawable + { + public Bindable UserProfile { get; } = new Bindable(); + + private SpriteText rankedScore = null!; + private SpriteText hitAccuracy = null!; + private SpriteText playCount = null!; + private SpriteText totalScore = null!; + private SpriteText totalHits = null!; + private SpriteText maximumCombo = null!; + private SpriteText replaysWatched = null!; + + [BackgroundDependencyLoader] + private void load() + { + var font = OsuFont.Default.With(size: 12); + const float vertical_spacing = 4; + + AutoSizeAxes = Axes.Both; + + // this should really be a grid, but trying to avoid one to avoid the performance hit. + InternalChild = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(20, 0), + Children = new[] + { + new FillFlowContainer + { + Name = @"Labels", + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, vertical_spacing), + Children = new Drawable[] + { + new OsuSpriteText { Font = font, Text = UsersStrings.ShowStatsRankedScore }, + new OsuSpriteText { Font = font, Text = UsersStrings.ShowStatsHitAccuracy }, + new OsuSpriteText { Font = font, Text = UsersStrings.ShowStatsPlayCount }, + new OsuSpriteText { Font = font, Text = UsersStrings.ShowStatsTotalScore }, + new OsuSpriteText { Font = font, Text = UsersStrings.ShowStatsTotalHits }, + new OsuSpriteText { Font = font, Text = UsersStrings.ShowStatsMaximumCombo }, + new OsuSpriteText { Font = font, Text = UsersStrings.ShowStatsReplaysWatchedByOthers }, + } + }, + new FillFlowContainer + { + Name = @"Values", + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, vertical_spacing), + Children = new Drawable[] + { + rankedScore = new OsuSpriteText { Font = font }, + hitAccuracy = new OsuSpriteText { Font = font }, + playCount = new OsuSpriteText { Font = font }, + totalScore = new OsuSpriteText { Font = font }, + totalHits = new OsuSpriteText { Font = font }, + maximumCombo = new OsuSpriteText { Font = font }, + replaysWatched = new OsuSpriteText { Font = font }, + } + }, + } + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + UserProfile.BindValueChanged(userProfile => updateStatistics(userProfile.NewValue?.User.Statistics), true); + } + + private void updateStatistics(UserStatistics? statistics) + { + if (statistics == null) + { + Alpha = 0; + return; + } + + Alpha = 1; + + rankedScore.Text = statistics.RankedScore.ToLocalisableString(@"N0"); + hitAccuracy.Text = statistics.DisplayAccuracy; + playCount.Text = statistics.PlayCount.ToLocalisableString(@"N0"); + totalScore.Text = statistics.TotalScore.ToLocalisableString(@"N0"); + totalHits.Text = statistics.TotalHits.ToLocalisableString(@"N0"); + maximumCombo.Text = statistics.MaxCombo.ToLocalisableString(@"N0"); + replaysWatched.Text = statistics.ReplaysWatched.ToLocalisableString(@"N0"); + } + } +} diff --git a/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs b/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs index e04a8ad9ad..1fe39cb570 100644 --- a/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs +++ b/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs @@ -5,18 +5,15 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions; using osu.Framework.Extensions.Color4Extensions; -using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; -using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Cursor; using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; using osu.Game.Overlays.Profile.Header.Components; -using osu.Game.Resources.Localisation.Web; using osu.Game.Users.Drawables; using osuTK; @@ -38,7 +35,6 @@ namespace osu.Game.Overlays.Profile.Header private OsuSpriteText titleText = null!; private UpdateableFlag userFlag = null!; private OsuSpriteText userCountryText = null!; - private FillFlowContainer userStats = null!; private GroupBadgeFlow groupBadgeFlow = null!; [BackgroundDependencyLoader] @@ -164,16 +160,6 @@ namespace osu.Game.Overlays.Profile.Header } } }, - userStats = new FillFlowContainer - { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - AutoSizeAxes = Axes.Y, - Width = 300, - Margin = new MarginPadding { Right = UserProfileOverlay.CONTENT_X_MARGIN }, - Padding = new MarginPadding { Vertical = 15 }, - Spacing = new Vector2(0, 2) - } }; User.BindValueChanged(user => updateUser(user.NewValue)); @@ -192,43 +178,6 @@ namespace osu.Game.Overlays.Profile.Header titleText.Text = user?.Title ?? string.Empty; titleText.Colour = Color4Extensions.FromHex(user?.Colour ?? "fff"); groupBadgeFlow.User.Value = user; - - userStats.Clear(); - - if (user?.Statistics != null) - { - userStats.Add(new UserStatsLine(UsersStrings.ShowStatsRankedScore, user.Statistics.RankedScore.ToLocalisableString("#,##0"))); - userStats.Add(new UserStatsLine(UsersStrings.ShowStatsHitAccuracy, user.Statistics.DisplayAccuracy)); - userStats.Add(new UserStatsLine(UsersStrings.ShowStatsPlayCount, user.Statistics.PlayCount.ToLocalisableString("#,##0"))); - userStats.Add(new UserStatsLine(UsersStrings.ShowStatsTotalScore, user.Statistics.TotalScore.ToLocalisableString("#,##0"))); - userStats.Add(new UserStatsLine(UsersStrings.ShowStatsTotalHits, user.Statistics.TotalHits.ToLocalisableString("#,##0"))); - userStats.Add(new UserStatsLine(UsersStrings.ShowStatsMaximumCombo, user.Statistics.MaxCombo.ToLocalisableString("#,##0"))); - userStats.Add(new UserStatsLine(UsersStrings.ShowStatsReplaysWatchedByOthers, user.Statistics.ReplaysWatched.ToLocalisableString("#,##0"))); - } - } - - private partial class UserStatsLine : Container - { - public UserStatsLine(LocalisableString left, LocalisableString right) - { - RelativeSizeAxes = Axes.X; - AutoSizeAxes = Axes.Y; - Children = new Drawable[] - { - new OsuSpriteText - { - Font = OsuFont.GetFont(size: 15), - Text = left, - }, - new OsuSpriteText - { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - Font = OsuFont.GetFont(size: 15, weight: FontWeight.Bold), - Text = right, - }, - }; - } } } } From f7c942ac10b22d365f9f9b98228959d8c5d8350e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 31 Dec 2022 19:00:40 +0100 Subject: [PATCH 26/31] Move user stats into detail header container --- .../Header/Components/ExtendedDetails.cs | 6 ++- .../Profile/Header/Components/MainDetails.cs | 1 - .../Profile/Header/DetailHeaderContainer.cs | 44 ++++++++++++++++++- 3 files changed, 46 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/Profile/Header/Components/ExtendedDetails.cs b/osu.Game/Overlays/Profile/Header/Components/ExtendedDetails.cs index b50b0041d0..50fc52600c 100644 --- a/osu.Game/Overlays/Profile/Header/Components/ExtendedDetails.cs +++ b/osu.Game/Overlays/Profile/Header/Components/ExtendedDetails.cs @@ -17,7 +17,7 @@ namespace osu.Game.Overlays.Profile.Header.Components { public partial class ExtendedDetails : CompositeDrawable { - public Bindable UserProfile { get; } = new Bindable(); + public Bindable User { get; } = new Bindable(); private SpriteText rankedScore = null!; private SpriteText hitAccuracy = null!; @@ -46,6 +46,7 @@ namespace osu.Game.Overlays.Profile.Header.Components new FillFlowContainer { Name = @"Labels", + AutoSizeAxes = Axes.Both, Direction = FillDirection.Vertical, Spacing = new Vector2(0, vertical_spacing), Children = new Drawable[] @@ -62,6 +63,7 @@ namespace osu.Game.Overlays.Profile.Header.Components new FillFlowContainer { Name = @"Values", + AutoSizeAxes = Axes.Both, Direction = FillDirection.Vertical, Spacing = new Vector2(0, vertical_spacing), Children = new Drawable[] @@ -83,7 +85,7 @@ namespace osu.Game.Overlays.Profile.Header.Components { base.LoadComplete(); - UserProfile.BindValueChanged(userProfile => updateStatistics(userProfile.NewValue?.User.Statistics), true); + User.BindValueChanged(user => updateStatistics(user.NewValue?.User.Statistics), true); } private void updateStatistics(UserStatistics? statistics) diff --git a/osu.Game/Overlays/Profile/Header/Components/MainDetails.cs b/osu.Game/Overlays/Profile/Header/Components/MainDetails.cs index 930ba29c7f..b89973c5e5 100644 --- a/osu.Game/Overlays/Profile/Header/Components/MainDetails.cs +++ b/osu.Game/Overlays/Profile/Header/Components/MainDetails.cs @@ -40,7 +40,6 @@ namespace osu.Game.Overlays.Profile.Header.Components AutoSizeDuration = 200, AutoSizeEasing = Easing.OutQuint, Masking = true, - Padding = new MarginPadding { Horizontal = UserProfileOverlay.CONTENT_X_MARGIN, Vertical = 10 }, Direction = FillDirection.Vertical, Spacing = new Vector2(0, 15), Children = new Drawable[] diff --git a/osu.Game/Overlays/Profile/Header/DetailHeaderContainer.cs b/osu.Game/Overlays/Profile/Header/DetailHeaderContainer.cs index 17de8b8ba0..1cc3aae735 100644 --- a/osu.Game/Overlays/Profile/Header/DetailHeaderContainer.cs +++ b/osu.Game/Overlays/Profile/Header/DetailHeaderContainer.cs @@ -26,10 +26,50 @@ namespace osu.Game.Overlays.Profile.Header RelativeSizeAxes = Axes.Both, Colour = colourProvider.Background5, }, - new MainDetails + new Container { RelativeSizeAxes = Axes.X, - User = { BindTarget = User } + AutoSizeAxes = Axes.Y, + Padding = new MarginPadding { Horizontal = UserProfileOverlay.CONTENT_X_MARGIN, Vertical = 10 }, + Child = new GridContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + RowDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize), + }, + ColumnDimensions = new[] + { + new Dimension(), + new Dimension(GridSizeMode.AutoSize), + new Dimension(GridSizeMode.AutoSize), + }, + Content = new[] + { + new Drawable[] + { + new MainDetails + { + RelativeSizeAxes = Axes.X, + User = { BindTarget = User } + }, + new Box + { + RelativeSizeAxes = Axes.Y, + Width = 2, + Colour = colourProvider.Background6, + Margin = new MarginPadding { Horizontal = 15 } + }, + new ExtendedDetails + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + User = { BindTarget = User } + } + } + } + } } }; } From 254c881ded6bc1c7b7875d3fe07ab88a02a39409 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Tue, 17 Jan 2023 14:12:48 -0800 Subject: [PATCH 27/31] Also check null for bindable channel value --- osu.Game/Overlays/Chat/DrawableUsername.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Chat/DrawableUsername.cs b/osu.Game/Overlays/Chat/DrawableUsername.cs index 73eb335e99..771ccdcbef 100644 --- a/osu.Game/Overlays/Chat/DrawableUsername.cs +++ b/osu.Game/Overlays/Chat/DrawableUsername.cs @@ -68,7 +68,7 @@ namespace osu.Game.Overlays.Chat private UserProfileOverlay? profileOverlay { get; set; } [Resolved] - private Bindable? currentChannel { get; set; } + private Bindable? currentChannel { get; set; } private readonly APIUser user; private readonly OsuSpriteText drawableText; @@ -161,7 +161,7 @@ namespace osu.Game.Overlays.Chat if (!user.Equals(api.LocalUser.Value)) items.Add(new OsuMenuItem(UsersStrings.CardSendMessage, MenuItemType.Standard, openUserChannel)); - if (currentChannel != null) + if (currentChannel?.Value != null) { items.Add(new OsuMenuItem(ChatStrings.MentionUser, MenuItemType.Standard, () => { From dfea42fd163f0ec8c558ba2b954a054a2af2d10c Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Tue, 17 Jan 2023 14:13:50 -0800 Subject: [PATCH 28/31] Add space after username mention --- osu.Game/Overlays/Chat/DrawableUsername.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Chat/DrawableUsername.cs b/osu.Game/Overlays/Chat/DrawableUsername.cs index 771ccdcbef..031a0b6ae2 100644 --- a/osu.Game/Overlays/Chat/DrawableUsername.cs +++ b/osu.Game/Overlays/Chat/DrawableUsername.cs @@ -165,7 +165,7 @@ namespace osu.Game.Overlays.Chat { items.Add(new OsuMenuItem(ChatStrings.MentionUser, MenuItemType.Standard, () => { - currentChannel.Value.TextBoxMessage.Value += $"@{user.Username}"; + currentChannel.Value.TextBoxMessage.Value += $"@{user.Username} "; })); } From 12544c16eab2510ce4c8d90ba415103ba632b364 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Wed, 18 Jan 2023 02:10:02 +0300 Subject: [PATCH 29/31] Remove canBeNull --- osu.Game/Overlays/Comments/DrawableComment.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 834abd5e9f..70ffbd8baf 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -70,7 +70,7 @@ namespace osu.Game.Overlays.Comments private GridContainer content = null!; private VotePill votePill = null!; - [Resolved(canBeNull: true)] + [Resolved] private IDialogOverlay? dialogOverlay { get; set; } [Resolved] @@ -79,7 +79,7 @@ namespace osu.Game.Overlays.Comments [Resolved] private GameHost host { get; set; } = null!; - [Resolved(canBeNull: true)] + [Resolved] private OnScreenDisplay? onScreenDisplay { get; set; } public DrawableComment(Comment comment) From ca3be7138149e9ed8f6af73986cef0b559fa60f6 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Wed, 18 Jan 2023 02:11:07 +0300 Subject: [PATCH 30/31] Track comment's nesting and reduce padding for too nested --- osu.Game/Overlays/Comments/DrawableComment.cs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 70ffbd8baf..1df65ab4b1 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -57,6 +57,11 @@ namespace osu.Game.Overlays.Comments /// public bool WasDeleted { get; protected set; } + /// + /// Tracks this comment's level of nesting. 0 means that this comment has no parents. + /// + public int Level { get; private set; } + private FillFlowContainer childCommentsVisibilityContainer = null!; private FillFlowContainer childCommentsContainer = null!; private LoadRepliesButton loadRepliesButton = null!; @@ -88,12 +93,16 @@ namespace osu.Game.Overlays.Comments } [BackgroundDependencyLoader] - private void load(OverlayColourProvider colourProvider) + private void load(OverlayColourProvider colourProvider, DrawableComment? parentComment) { LinkFlowContainer username; FillFlowContainer info; CommentMarkdownContainer message; + Level = parentComment?.Level + 1 ?? 0; + + float childrenPadding = Level < 6 ? 20 : 5; + RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; InternalChildren = new Drawable[] @@ -248,7 +257,7 @@ namespace osu.Game.Overlays.Comments RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Direction = FillDirection.Vertical, - Padding = new MarginPadding { Left = 20 }, + Padding = new MarginPadding { Left = childrenPadding }, Children = new Drawable[] { childCommentsContainer = new FillFlowContainer From 4ad79a8a0ac721be0e409a9fd729a45d5c6c1bd0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Jan 2023 12:00:47 +0900 Subject: [PATCH 31/31] Move `IsLoaded` check inside `BeatmapCarousel` --- osu.Game/Screens/Select/BeatmapCarousel.cs | 3 +++ osu.Game/Screens/Select/SongSelect.cs | 9 +++------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index 19eced08d9..774ecc2c9c 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -596,6 +596,9 @@ namespace osu.Game.Screens.Select public void FlushPendingFilterOperations() { + if (!IsLoaded) + return; + if (PendingFilter?.Completed == false) { applyActiveCriteria(false); diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index db4d326991..4b3222c14a 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -860,12 +860,9 @@ namespace osu.Game.Screens.Select Logger.Log($"decoupled ruleset transferred (\"{decoupledRuleset.Value}\" -> \"{Ruleset.Value}\")"); rulesetNoDebounce = decoupledRuleset.Value = Ruleset.Value; - if (Carousel.IsLoaded) - { - // if we have a pending filter operation, we want to run it now. - // it could change selection (ie. if the ruleset has been changed). - Carousel.FlushPendingFilterOperations(); - } + // if we have a pending filter operation, we want to run it now. + // it could change selection (ie. if the ruleset has been changed). + Carousel.FlushPendingFilterOperations(); return true; }