From 76db200bd3efd8f3f1a93820e852cbdb9e54fdc8 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 7 Oct 2019 16:48:05 +0300 Subject: [PATCH 01/80] Implement GetCommentsRequest --- .../Online/API/Requests/GetCommentsRequest.cs | 53 ++++++++++++++++++ .../API/Requests/Responses/APIComments.cs | 36 ++++++++++++ .../Online/API/Requests/Responses/Comment.cs | 56 +++++++++++++++++++ 3 files changed, 145 insertions(+) create mode 100644 osu.Game/Online/API/Requests/GetCommentsRequest.cs create mode 100644 osu.Game/Online/API/Requests/Responses/APIComments.cs create mode 100644 osu.Game/Online/API/Requests/Responses/Comment.cs diff --git a/osu.Game/Online/API/Requests/GetCommentsRequest.cs b/osu.Game/Online/API/Requests/GetCommentsRequest.cs new file mode 100644 index 0000000000..279a1905da --- /dev/null +++ b/osu.Game/Online/API/Requests/GetCommentsRequest.cs @@ -0,0 +1,53 @@ +// 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.IO.Network; +using Humanizer; +using osu.Game.Online.API.Requests.Responses; + +namespace osu.Game.Online.API.Requests +{ + public class GetCommentsRequest : APIRequest + { + private readonly long id; + private readonly int page; + private readonly CommentableType type; + private readonly SortCommentsBy sort; + + public GetCommentsRequest(CommentableType type, long id, SortCommentsBy sort = SortCommentsBy.New, int page = 1) + { + this.type = type; + this.sort = sort; + this.id = id; + this.page = page; + } + + protected override WebRequest CreateWebRequest() + { + var req = base.CreateWebRequest(); + + req.AddParameter("commentable_type", type.ToString().Underscore().ToLowerInvariant()); + req.AddParameter("commentable_id", id.ToString()); + req.AddParameter("sort", sort.ToString()); + req.AddParameter("page", page.ToString()); + + return req; + } + + protected override string Target => "comments"; + } + + public enum CommentableType + { + Build, + Beatmapset, + NewsPost + } + + public enum SortCommentsBy + { + New, + Old, + Top + } +} diff --git a/osu.Game/Online/API/Requests/Responses/APIComments.cs b/osu.Game/Online/API/Requests/Responses/APIComments.cs new file mode 100644 index 0000000000..158430a5b6 --- /dev/null +++ b/osu.Game/Online/API/Requests/Responses/APIComments.cs @@ -0,0 +1,36 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using Newtonsoft.Json; +using osu.Game.Users; +using System.Collections.Generic; + +namespace osu.Game.Online.API.Requests.Responses +{ + public class APIComments + { + [JsonProperty(@"comments")] + public List Comments { get; set; } + + [JsonProperty(@"has_more")] + public bool HasMore { get; set; } + + [JsonProperty(@"has_more_id")] + public long HasMoreId { get; set; } + + [JsonProperty(@"user_follow")] + public bool UserFollow { get; set; } + + [JsonProperty(@"included_comments")] + public List IncludedComments { get; set; } + + [JsonProperty(@"users")] + public List Users { get; set; } + + [JsonProperty(@"total")] + public int Total { get; set; } + + [JsonProperty(@"top_level_count")] + public int TopLevelCount { get; set; } + } +} diff --git a/osu.Game/Online/API/Requests/Responses/Comment.cs b/osu.Game/Online/API/Requests/Responses/Comment.cs new file mode 100644 index 0000000000..e157a10f8a --- /dev/null +++ b/osu.Game/Online/API/Requests/Responses/Comment.cs @@ -0,0 +1,56 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using Newtonsoft.Json; +using System; + +namespace osu.Game.Online.API.Requests.Responses +{ + public class Comment + { + [JsonProperty(@"id")] + public long Id { get; set; } + + [JsonProperty(@"parent_id")] + public long ParentId { get; set; } + + [JsonProperty(@"user_id")] + public long UserId { get; set; } + + [JsonProperty(@"message")] + public string Message { get; set; } + + [JsonProperty(@"message_html")] + public string MessageHTML { get; set; } + + [JsonProperty(@"replies_count")] + public int RepliesCount { get; set; } + + [JsonProperty(@"votes_count")] + public int VotesCount { get; set; } + + [JsonProperty(@"commenatble_type")] + public string CommentableType { get; set; } + + [JsonProperty(@"commentable_id")] + public int CommentableId { get; set; } + + [JsonProperty(@"legacy_name")] + public string LegacyName { get; set; } + + [JsonProperty(@"created_at")] + public DateTimeOffset CreatedAt { get; set; } + + [JsonProperty(@"updated_at")] + public DateTimeOffset UpdatedAt { get; set; } + + [JsonProperty(@"deleted_at")] + public DateTimeOffset DeletedAt { get; set; } + + [JsonProperty(@"edited_at")] + public DateTimeOffset EditedAt { get; set; } + + [JsonProperty(@"edited_by_id")] + public long EditedById { get; set; } + } +} From 738580ec617a23789236575f2525606a6a4d227e Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 7 Oct 2019 16:58:24 +0300 Subject: [PATCH 02/80] Add IsTopLevel property --- osu.Game/Online/API/Requests/Responses/Comment.cs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/osu.Game/Online/API/Requests/Responses/Comment.cs b/osu.Game/Online/API/Requests/Responses/Comment.cs index e157a10f8a..6edf13d2da 100644 --- a/osu.Game/Online/API/Requests/Responses/Comment.cs +++ b/osu.Game/Online/API/Requests/Responses/Comment.cs @@ -11,8 +11,18 @@ namespace osu.Game.Online.API.Requests.Responses [JsonProperty(@"id")] public long Id { get; set; } + private long? parentId; + [JsonProperty(@"parent_id")] - public long ParentId { get; set; } + public long? ParentId + { + get => parentId; + set + { + parentId = value; + IsTopLevel = value != null; + } + } [JsonProperty(@"user_id")] public long UserId { get; set; } @@ -52,5 +62,7 @@ namespace osu.Game.Online.API.Requests.Responses [JsonProperty(@"edited_by_id")] public long EditedById { get; set; } + + public bool IsTopLevel { get; set; } } } From e772822bd5ee46afddc5bc14398e73f84ff84564 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 7 Oct 2019 17:49:20 +0300 Subject: [PATCH 03/80] Basic implementation --- .../Online/TestSceneCommentsContainer.cs | 29 +++++ osu.Game/Overlays/CommentsContainer.cs | 110 ++++++++++++++++++ 2 files changed, 139 insertions(+) create mode 100644 osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs create mode 100644 osu.Game/Overlays/CommentsContainer.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs new file mode 100644 index 0000000000..c99062d59b --- /dev/null +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs @@ -0,0 +1,29 @@ +// 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 System.Collections.Generic; +using NUnit.Framework; +using osu.Game.Overlays; +using osu.Game.Online.API.Requests; + +namespace osu.Game.Tests.Visual.Online +{ + [TestFixture] + public class TestSceneCommentsContainer : OsuTestScene + { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(CommentsContainer), + }; + + public TestSceneCommentsContainer() + { + AddStep("Big Black comments", () => + { + Clear(); + Add(new CommentsContainer(CommentableType.Beatmapset, 41823)); + }); + } + } +} diff --git a/osu.Game/Overlays/CommentsContainer.cs b/osu.Game/Overlays/CommentsContainer.cs new file mode 100644 index 0000000000..8ed6fd0878 --- /dev/null +++ b/osu.Game/Overlays/CommentsContainer.cs @@ -0,0 +1,110 @@ +// 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.Graphics.Containers; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests; +using osu.Framework.Graphics; +using osu.Framework.Bindables; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics; +using osu.Framework.Graphics.Sprites; +using osuTK; + +namespace osu.Game.Overlays +{ + public class CommentsContainer : CompositeDrawable + { + private readonly CommentableType type; + private readonly long id; + + public readonly Bindable Sort = new Bindable(); + + [Resolved] + private IAPIProvider api { get; set; } + + private readonly CommentsHeader header; + private readonly Box background; + + public CommentsContainer(CommentableType type, long id) + { + this.type = type; + this.id = id; + + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + AddRangeInternal(new Drawable[] + { + background = new Box + { + RelativeSizeAxes = Axes.Both, + }, + header = new CommentsHeader + { + Sort = { BindTarget = Sort } + } + }); + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + background.Colour = colours.Gray3; + } + + private class CommentsHeader : CompositeDrawable + { + private const int height = 40; + private const int spacing = 10; + private const int padding = 50; + + public readonly Bindable Sort = new Bindable(); + + private readonly Box background; + + public CommentsHeader() + { + RelativeSizeAxes = Axes.X; + Height = height; + AddRangeInternal(new Drawable[] + { + background = new Box + { + RelativeSizeAxes = Axes.Both, + }, + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Horizontal = padding }, + Children = new Drawable[] + { + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(spacing, 0), + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Children = new Drawable[] + { + new SpriteText + { + Font = OsuFont.GetFont(size: 14), + Text = @"Sort by" + } + } + } + } + } + }); + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + background.Colour = colours.Gray4; + } + } + } +} From aa8df0fa20426b0beec6997a2f2a07895cdddbaf Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 7 Oct 2019 18:26:07 +0300 Subject: [PATCH 04/80] Hook up api and implement some visual comments representation --- .../Online/TestSceneCommentsContainer.cs | 15 +++- .../API/Requests/Responses/APIComments.cs | 2 +- .../Online/API/Requests/Responses/Comment.cs | 8 +- osu.Game/Overlays/CommentsContainer.cs | 84 ++++++++++++++++++- 4 files changed, 99 insertions(+), 10 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs index c99062d59b..bf4117189a 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs @@ -6,6 +6,8 @@ using System.Collections.Generic; using NUnit.Framework; using osu.Game.Overlays; using osu.Game.Online.API.Requests; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics; namespace osu.Game.Tests.Visual.Online { @@ -17,12 +19,21 @@ namespace osu.Game.Tests.Visual.Online typeof(CommentsContainer), }; + protected override bool UseOnlineAPI => true; + public TestSceneCommentsContainer() { + BasicScrollContainer scrollFlow; + + Add(scrollFlow = new BasicScrollContainer + { + RelativeSizeAxes = Axes.Both, + }); + AddStep("Big Black comments", () => { - Clear(); - Add(new CommentsContainer(CommentableType.Beatmapset, 41823)); + scrollFlow.Clear(); + scrollFlow.Add(new CommentsContainer(CommentableType.Beatmapset, 41823)); }); } } diff --git a/osu.Game/Online/API/Requests/Responses/APIComments.cs b/osu.Game/Online/API/Requests/Responses/APIComments.cs index 158430a5b6..af7650e512 100644 --- a/osu.Game/Online/API/Requests/Responses/APIComments.cs +++ b/osu.Game/Online/API/Requests/Responses/APIComments.cs @@ -16,7 +16,7 @@ namespace osu.Game.Online.API.Requests.Responses public bool HasMore { get; set; } [JsonProperty(@"has_more_id")] - public long HasMoreId { get; set; } + public long? HasMoreId { get; set; } [JsonProperty(@"user_follow")] public bool UserFollow { get; set; } diff --git a/osu.Game/Online/API/Requests/Responses/Comment.cs b/osu.Game/Online/API/Requests/Responses/Comment.cs index 6edf13d2da..df5c812fa0 100644 --- a/osu.Game/Online/API/Requests/Responses/Comment.cs +++ b/osu.Game/Online/API/Requests/Responses/Comment.cs @@ -52,16 +52,16 @@ namespace osu.Game.Online.API.Requests.Responses public DateTimeOffset CreatedAt { get; set; } [JsonProperty(@"updated_at")] - public DateTimeOffset UpdatedAt { get; set; } + public DateTimeOffset? UpdatedAt { get; set; } [JsonProperty(@"deleted_at")] - public DateTimeOffset DeletedAt { get; set; } + public DateTimeOffset? DeletedAt { get; set; } [JsonProperty(@"edited_at")] - public DateTimeOffset EditedAt { get; set; } + public DateTimeOffset? EditedAt { get; set; } [JsonProperty(@"edited_by_id")] - public long EditedById { get; set; } + public long? EditedById { get; set; } public bool IsTopLevel { get; set; } } diff --git a/osu.Game/Overlays/CommentsContainer.cs b/osu.Game/Overlays/CommentsContainer.cs index 8ed6fd0878..fce9b3f03b 100644 --- a/osu.Game/Overlays/CommentsContainer.cs +++ b/osu.Game/Overlays/CommentsContainer.cs @@ -11,6 +11,7 @@ using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Framework.Graphics.Sprites; using osuTK; +using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Overlays { @@ -24,8 +25,14 @@ namespace osu.Game.Overlays [Resolved] private IAPIProvider api { get; set; } + [Resolved] + private OsuColour colours { get; set; } + + private GetCommentsRequest request; + private readonly CommentsHeader header; private readonly Box background; + private readonly FillFlowContainer content; public CommentsContainer(CommentableType type, long id) { @@ -40,15 +47,86 @@ namespace osu.Game.Overlays { RelativeSizeAxes = Axes.Both, }, - header = new CommentsHeader + new FillFlowContainer { - Sort = { BindTarget = Sort } + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Children = new Drawable[] + { + header = new CommentsHeader + { + Sort = { BindTarget = Sort } + }, + content = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + } + } + } + }); + } + + protected override void LoadComplete() + { + Sort.BindValueChanged(onSortChanged, true); + base.LoadComplete(); + } + + private void onSortChanged(ValueChangedEvent sort) => getComments(); + + private void getComments() + { + request?.Cancel(); + request = new GetCommentsRequest(type, id, Sort.Value); + request.Success += onSuccess; + api.Queue(request); + } + + private void onSuccess(APIComments response) + { + content.Clear(); + + foreach (var c in response.Comments) + { + createDrawableComment(c); + } + } + + private void createDrawableComment(Comment comment) + { + content.Add(new Container + { + RelativeSizeAxes = Axes.X, + Height = 70, + Children = new Drawable[] + { + new SpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Text = comment.MessageHTML, + }, + new Container + { + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + RelativeSizeAxes = Axes.X, + Height = 1, + Child = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colours.Gray1, + } + } } }); } [BackgroundDependencyLoader] - private void load(OsuColour colours) + private void load() { background.Colour = colours.Gray3; } From cc6bf2f173b4d53c9fb568963c4685e133417254 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 7 Oct 2019 18:45:22 +0300 Subject: [PATCH 05/80] Add IsDeleted property --- .../Online/API/Requests/Responses/Comment.cs | 16 ++++++++++++++-- osu.Game/Overlays/CommentsContainer.cs | 6 +++--- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/osu.Game/Online/API/Requests/Responses/Comment.cs b/osu.Game/Online/API/Requests/Responses/Comment.cs index df5c812fa0..e4b66ddeee 100644 --- a/osu.Game/Online/API/Requests/Responses/Comment.cs +++ b/osu.Game/Online/API/Requests/Responses/Comment.cs @@ -20,7 +20,7 @@ namespace osu.Game.Online.API.Requests.Responses set { parentId = value; - IsTopLevel = value != null; + IsTopLevel = value == null; } } @@ -54,8 +54,18 @@ namespace osu.Game.Online.API.Requests.Responses [JsonProperty(@"updated_at")] public DateTimeOffset? UpdatedAt { get; set; } + private DateTimeOffset? deletedAt; + [JsonProperty(@"deleted_at")] - public DateTimeOffset? DeletedAt { get; set; } + public DateTimeOffset? DeletedAt + { + get => deletedAt; + set + { + deletedAt = value; + IsDeleted = value != null; + } + } [JsonProperty(@"edited_at")] public DateTimeOffset? EditedAt { get; set; } @@ -64,5 +74,7 @@ namespace osu.Game.Online.API.Requests.Responses public long? EditedById { get; set; } public bool IsTopLevel { get; set; } + + public bool IsDeleted { get; set; } } } diff --git a/osu.Game/Overlays/CommentsContainer.cs b/osu.Game/Overlays/CommentsContainer.cs index fce9b3f03b..b22fefb3de 100644 --- a/osu.Game/Overlays/CommentsContainer.cs +++ b/osu.Game/Overlays/CommentsContainer.cs @@ -30,7 +30,6 @@ namespace osu.Game.Overlays private GetCommentsRequest request; - private readonly CommentsHeader header; private readonly Box background; private readonly FillFlowContainer content; @@ -54,7 +53,7 @@ namespace osu.Game.Overlays Direction = FillDirection.Vertical, Children = new Drawable[] { - header = new CommentsHeader + new CommentsHeader { Sort = { BindTarget = Sort } }, @@ -91,7 +90,8 @@ namespace osu.Game.Overlays foreach (var c in response.Comments) { - createDrawableComment(c); + if (!c.IsDeleted) + createDrawableComment(c); } } From 4b1a40dabaebadb49d07cbc077d71709714fe6d8 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 8 Oct 2019 13:31:49 +0300 Subject: [PATCH 06/80] Implement temp fix to get the actual message --- osu.Game/Online/API/Requests/Responses/Comment.cs | 6 ++++++ osu.Game/Overlays/CommentsContainer.cs | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/osu.Game/Online/API/Requests/Responses/Comment.cs b/osu.Game/Online/API/Requests/Responses/Comment.cs index e4b66ddeee..ba71faa843 100644 --- a/osu.Game/Online/API/Requests/Responses/Comment.cs +++ b/osu.Game/Online/API/Requests/Responses/Comment.cs @@ -76,5 +76,11 @@ namespace osu.Game.Online.API.Requests.Responses public bool IsTopLevel { get; set; } public bool IsDeleted { get; set; } + + public string GetMessage() + { + //temporary fix until HTML parsing will be implemented + return MessageHTML.Remove(MessageHTML.LastIndexOf("

")).Substring(65); + } } } diff --git a/osu.Game/Overlays/CommentsContainer.cs b/osu.Game/Overlays/CommentsContainer.cs index b22fefb3de..1b4bbee6a1 100644 --- a/osu.Game/Overlays/CommentsContainer.cs +++ b/osu.Game/Overlays/CommentsContainer.cs @@ -107,7 +107,7 @@ namespace osu.Game.Overlays { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, - Text = comment.MessageHTML, + Text = comment.GetMessage(), }, new Container { From 801b5b474e300343bafc0defc0a8818e3516919d Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 8 Oct 2019 13:45:13 +0300 Subject: [PATCH 07/80] Add a User property to the comment for easy access --- .../API/Requests/Responses/APIComments.cs | 20 ++++++++++++++++- .../Online/API/Requests/Responses/Comment.cs | 3 +++ osu.Game/Overlays/CommentsContainer.cs | 22 +++++++++++++++++-- 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/osu.Game/Online/API/Requests/Responses/APIComments.cs b/osu.Game/Online/API/Requests/Responses/APIComments.cs index af7650e512..86bbf0358a 100644 --- a/osu.Game/Online/API/Requests/Responses/APIComments.cs +++ b/osu.Game/Online/API/Requests/Responses/APIComments.cs @@ -24,8 +24,26 @@ namespace osu.Game.Online.API.Requests.Responses [JsonProperty(@"included_comments")] public List IncludedComments { get; set; } + private List users; + [JsonProperty(@"users")] - public List Users { get; set; } + public List Users + { + get => users; + set + { + users = value; + + value.ForEach(u => + { + Comments.ForEach(c => + { + if (c.UserId == u.Id) + c.User = u; + }); + }); + } + } [JsonProperty(@"total")] public int Total { get; set; } diff --git a/osu.Game/Online/API/Requests/Responses/Comment.cs b/osu.Game/Online/API/Requests/Responses/Comment.cs index ba71faa843..46212dd50f 100644 --- a/osu.Game/Online/API/Requests/Responses/Comment.cs +++ b/osu.Game/Online/API/Requests/Responses/Comment.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using Newtonsoft.Json; +using osu.Game.Users; using System; namespace osu.Game.Online.API.Requests.Responses @@ -27,6 +28,8 @@ namespace osu.Game.Online.API.Requests.Responses [JsonProperty(@"user_id")] public long UserId { get; set; } + public User User { get; set; } + [JsonProperty(@"message")] public string Message { get; set; } diff --git a/osu.Game/Overlays/CommentsContainer.cs b/osu.Game/Overlays/CommentsContainer.cs index 1b4bbee6a1..c871810d8a 100644 --- a/osu.Game/Overlays/CommentsContainer.cs +++ b/osu.Game/Overlays/CommentsContainer.cs @@ -103,11 +103,29 @@ namespace osu.Game.Overlays Height = 70, Children = new Drawable[] { - new SpriteText + new FillFlowContainer { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, - Text = comment.GetMessage(), + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 3), + Children = new[] + { + new SpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Text = $"user: {comment.User.Username}", + }, + new SpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Text = $"message: {comment.GetMessage()}", + }, + } }, new Container { From 1c89841949e025fe693aab73a97dd9a93c78b85b Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 8 Oct 2019 14:51:12 +0300 Subject: [PATCH 08/80] Move all the logic to it's own namespace --- .../Online/TestSceneCommentsContainer.cs | 2 +- .../{ => Comments}/CommentsContainer.cs | 67 +++---------- osu.Game/Overlays/Comments/DrawableComment.cs | 99 +++++++++++++++++++ 3 files changed, 116 insertions(+), 52 deletions(-) rename osu.Game/Overlays/{ => Comments}/CommentsContainer.cs (73%) create mode 100644 osu.Game/Overlays/Comments/DrawableComment.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs index bf4117189a..e6f9582910 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs @@ -4,10 +4,10 @@ using System; using System.Collections.Generic; using NUnit.Framework; -using osu.Game.Overlays; using osu.Game.Online.API.Requests; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics; +using osu.Game.Overlays.Comments; namespace osu.Game.Tests.Visual.Online { diff --git a/osu.Game/Overlays/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs similarity index 73% rename from osu.Game/Overlays/CommentsContainer.cs rename to osu.Game/Overlays/Comments/CommentsContainer.cs index c871810d8a..60b22428f0 100644 --- a/osu.Game/Overlays/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -13,7 +13,7 @@ using osu.Framework.Graphics.Sprites; using osuTK; using osu.Game.Online.API.Requests.Responses; -namespace osu.Game.Overlays +namespace osu.Game.Overlays.Comments { public class CommentsContainer : CompositeDrawable { @@ -90,59 +90,24 @@ namespace osu.Game.Overlays foreach (var c in response.Comments) { - if (!c.IsDeleted) - createDrawableComment(c); + if (!c.IsDeleted && c.IsTopLevel) + content.AddRange(new Drawable[] + { + new DrawableComment(c), + new Container + { + RelativeSizeAxes = Axes.X, + Height = 1, + Child = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colours.Gray1, + } + } + }); } } - private void createDrawableComment(Comment comment) - { - content.Add(new Container - { - RelativeSizeAxes = Axes.X, - Height = 70, - Children = new Drawable[] - { - new FillFlowContainer - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical, - Spacing = new Vector2(0, 3), - Children = new[] - { - new SpriteText - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Text = $"user: {comment.User.Username}", - }, - new SpriteText - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Text = $"message: {comment.GetMessage()}", - }, - } - }, - new Container - { - Anchor = Anchor.BottomCentre, - Origin = Anchor.BottomCentre, - RelativeSizeAxes = Axes.X, - Height = 1, - Child = new Box - { - RelativeSizeAxes = Axes.Both, - Colour = colours.Gray1, - } - } - } - }); - } - [BackgroundDependencyLoader] private void load() { diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs new file mode 100644 index 0000000000..bbb804dc5b --- /dev/null +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -0,0 +1,99 @@ +// 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.Graphics.Containers; +using osu.Framework.Graphics; +using osu.Game.Graphics; +using osu.Framework.Graphics.Sprites; +using osuTK; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Users.Drawables; +using osu.Game.Graphics.Containers; +using osu.Game.Utils; + +namespace osu.Game.Overlays.Comments +{ + public class DrawableComment : CompositeDrawable + { + private const int avatar_size = 40; + private const int margin = 10; + + public DrawableComment(Comment comment) + { + LinkFlowContainer username; + + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + InternalChild = new GridContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Margin = new MarginPadding(margin), + ColumnDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize), + new Dimension(), + }, + RowDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize), + new Dimension(GridSizeMode.AutoSize) + }, + Content = new[] + { + new Drawable[] + { + new UpdateableAvatar(comment.User) + { + Size = new Vector2(avatar_size), + Margin = new MarginPadding { Horizontal = margin }, + Masking = true, + CornerRadius = avatar_size / 2, + }, + new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Spacing = new Vector2(0, 2), + Children = new Drawable[] + { + username = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true)) + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + AutoSizeAxes = Axes.Both, + }, + new TextFlowContainer(s => s.Font = OsuFont.GetFont(size: 18)) + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Text = comment.GetMessage() + } + } + } + }, + new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Both, + }, + new SpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Font = OsuFont.GetFont(size: 12), + Text = HumanizerUtils.Humanize(comment.CreatedAt) + } + } + } + }; + + username.AddUserLink(comment.User); + } + } +} From 2564214a72b70007368fa3c5763c407fab2192ac Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 8 Oct 2019 15:01:18 +0300 Subject: [PATCH 09/80] Fix some padding issues with the big comments --- osu.Game/Overlays/Comments/DrawableComment.cs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index bbb804dc5b..6f3d92c7fd 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -54,21 +54,16 @@ namespace osu.Game.Overlays.Comments { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, + Margin = new MarginPadding { Top = margin / 2 }, Spacing = new Vector2(0, 2), Children = new Drawable[] { username = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true)) { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, AutoSizeAxes = Axes.Both, }, - new TextFlowContainer(s => s.Font = OsuFont.GetFont(size: 18)) + new TextFlowContainer(s => s.Font = OsuFont.GetFont(size: 14)) { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Text = comment.GetMessage() From 451a7342ce7459ae42562521e549af8e7e8a1d5b Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 8 Oct 2019 15:39:03 +0300 Subject: [PATCH 10/80] Parse child comments --- .../API/Requests/Responses/APIComments.cs | 22 +++- .../Online/API/Requests/Responses/Comment.cs | 3 + .../Overlays/Comments/CommentsContainer.cs | 4 +- osu.Game/Overlays/Comments/DrawableComment.cs | 106 +++++++++++------- 4 files changed, 92 insertions(+), 43 deletions(-) diff --git a/osu.Game/Online/API/Requests/Responses/APIComments.cs b/osu.Game/Online/API/Requests/Responses/APIComments.cs index 86bbf0358a..9a12fb613e 100644 --- a/osu.Game/Online/API/Requests/Responses/APIComments.cs +++ b/osu.Game/Online/API/Requests/Responses/APIComments.cs @@ -9,8 +9,28 @@ namespace osu.Game.Online.API.Requests.Responses { public class APIComments { + private List comments; + [JsonProperty(@"comments")] - public List Comments { get; set; } + public List Comments + { + get => comments; + set + { + comments = value; + comments.ForEach(child => + { + if (child.ParentId != null) + { + comments.ForEach(parent => + { + if (parent.Id == child.ParentId) + parent.ChildComments.Add(child); + }); + } + }); + } + } [JsonProperty(@"has_more")] public bool HasMore { get; set; } diff --git a/osu.Game/Online/API/Requests/Responses/Comment.cs b/osu.Game/Online/API/Requests/Responses/Comment.cs index 46212dd50f..cdc3c3204b 100644 --- a/osu.Game/Online/API/Requests/Responses/Comment.cs +++ b/osu.Game/Online/API/Requests/Responses/Comment.cs @@ -4,6 +4,7 @@ using Newtonsoft.Json; using osu.Game.Users; using System; +using System.Collections.Generic; namespace osu.Game.Online.API.Requests.Responses { @@ -25,6 +26,8 @@ namespace osu.Game.Online.API.Requests.Responses } } + public List ChildComments = new List(); + [JsonProperty(@"user_id")] public long UserId { get; set; } diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index 60b22428f0..d02e74a5a4 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -17,6 +17,8 @@ namespace osu.Game.Overlays.Comments { public class CommentsContainer : CompositeDrawable { + private const float separator_height = 1.5f; + private readonly CommentableType type; private readonly long id; @@ -97,7 +99,7 @@ namespace osu.Game.Overlays.Comments new Container { RelativeSizeAxes = Axes.X, - Height = 1, + Height = separator_height, Child = new Box { RelativeSizeAxes = Axes.Both, diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 6f3d92c7fd..53366be878 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -17,78 +17,102 @@ namespace osu.Game.Overlays.Comments { private const int avatar_size = 40; private const int margin = 10; + private const int child_margin = 20; public DrawableComment(Comment comment) { LinkFlowContainer username; + FillFlowContainer childCommentsContainer; RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; - InternalChild = new GridContainer + InternalChild = new FillFlowContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Margin = new MarginPadding(margin), - ColumnDimensions = new[] + Direction = FillDirection.Vertical, + Children = new Drawable[] { - new Dimension(GridSizeMode.AutoSize), - new Dimension(), - }, - RowDimensions = new[] - { - new Dimension(GridSizeMode.AutoSize), - new Dimension(GridSizeMode.AutoSize) - }, - Content = new[] - { - new Drawable[] + new GridContainer { - new UpdateableAvatar(comment.User) + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Margin = new MarginPadding(margin), + ColumnDimensions = new[] { - Size = new Vector2(avatar_size), - Margin = new MarginPadding { Horizontal = margin }, - Masking = true, - CornerRadius = avatar_size / 2, + new Dimension(GridSizeMode.AutoSize), + new Dimension(), }, - new FillFlowContainer + RowDimensions = new[] { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Margin = new MarginPadding { Top = margin / 2 }, - Spacing = new Vector2(0, 2), - Children = new Drawable[] + new Dimension(GridSizeMode.AutoSize), + new Dimension(GridSizeMode.AutoSize) + }, + Content = new[] + { + new Drawable[] { - username = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true)) + new UpdateableAvatar(comment.User) { - AutoSizeAxes = Axes.Both, + Size = new Vector2(avatar_size), + Margin = new MarginPadding { Horizontal = margin }, + Masking = true, + CornerRadius = avatar_size / 2, }, - new TextFlowContainer(s => s.Font = OsuFont.GetFont(size: 14)) + new FillFlowContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Text = comment.GetMessage() + Margin = new MarginPadding { Top = margin / 2 }, + Spacing = new Vector2(0, 2), + Children = new Drawable[] + { + username = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true)) + { + AutoSizeAxes = Axes.Both, + }, + new TextFlowContainer(s => s.Font = OsuFont.GetFont(size: 14)) + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Text = comment.GetMessage() + } + } + } + }, + new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Both, + }, + new SpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Font = OsuFont.GetFont(size: 12), + Text = HumanizerUtils.Humanize(comment.CreatedAt) } } } }, - new Drawable[] + childCommentsContainer = new FillFlowContainer { - new Container - { - RelativeSizeAxes = Axes.Both, - }, - new SpriteText - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Font = OsuFont.GetFont(size: 12), - Text = HumanizerUtils.Humanize(comment.CreatedAt) - } + Margin = new MarginPadding { Left = child_margin }, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical } } }; username.AddUserLink(comment.User); + + comment.ChildComments.ForEach(c => + { + if (!c.IsDeleted) + childCommentsContainer.Add(new DrawableComment(c)); + }); } } } From 9c7e403cf8ca62b83ded5505c030b77f8ee0a81b Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 8 Oct 2019 16:00:34 +0300 Subject: [PATCH 11/80] Implement replies button --- osu.Game/Overlays/Comments/DrawableComment.cs | 98 +++++++++++++++++-- 1 file changed, 90 insertions(+), 8 deletions(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 53366be878..9879995b00 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -10,6 +10,8 @@ using osu.Game.Online.API.Requests.Responses; using osu.Game.Users.Drawables; using osu.Game.Graphics.Containers; using osu.Game.Utils; +using osu.Framework.Input.Events; +using System; namespace osu.Game.Overlays.Comments { @@ -18,11 +20,39 @@ namespace osu.Game.Overlays.Comments private const int avatar_size = 40; private const int margin = 10; private const int child_margin = 20; + private const int duration = 200; + + private bool childExpanded = true; + + public bool ChildExpanded + { + get => childExpanded; + set + { + if (childExpanded == value) + return; + + childExpanded = value; + + childCommentsVisibilityContainer.ClearTransforms(); + + if (childExpanded) + childCommentsVisibilityContainer.AutoSizeAxes = Axes.Y; + else + { + childCommentsVisibilityContainer.AutoSizeAxes = Axes.None; + childCommentsVisibilityContainer.ResizeHeightTo(0, duration, Easing.OutQuint); + } + } + } + + private readonly Container childCommentsVisibilityContainer; public DrawableComment(Comment comment) { LinkFlowContainer username; FillFlowContainer childCommentsContainer; + RepliesButton replies; RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; @@ -86,22 +116,40 @@ namespace osu.Game.Overlays.Comments { RelativeSizeAxes = Axes.Both, }, - new SpriteText + new FillFlowContainer { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Font = OsuFont.GetFont(size: 12), - Text = HumanizerUtils.Humanize(comment.CreatedAt) + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(5, 0), + Children = new Drawable[] + { + new SpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Font = OsuFont.GetFont(size: 12), + Text = HumanizerUtils.Humanize(comment.CreatedAt) + }, + replies = new RepliesButton(comment.RepliesCount), + } } } } }, - childCommentsContainer = new FillFlowContainer + childCommentsVisibilityContainer = new Container { - Margin = new MarginPadding { Left = child_margin }, RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical + AutoSizeDuration = duration, + AutoSizeEasing = Easing.OutQuint, + Masking = true, + Child = childCommentsContainer = new FillFlowContainer + { + Margin = new MarginPadding { Left = child_margin }, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical + } } } }; @@ -113,6 +161,40 @@ namespace osu.Game.Overlays.Comments if (!c.IsDeleted) childCommentsContainer.Add(new DrawableComment(c)); }); + + replies.Action += expanded => ChildExpanded = expanded; + } + + private class RepliesButton : Container + { + private readonly SpriteText text; + private bool expanded; + private readonly int count; + + public Action Action; + + public RepliesButton(int count) + { + this.count = count; + + AutoSizeAxes = Axes.Both; + Alpha = count == 0 ? 0 : 1; + Child = text = new SpriteText + { + Font = OsuFont.GetFont(size: 12), + Text = $@"[-] replies ({count})" + }; + + expanded = true; + } + + protected override bool OnClick(ClickEvent e) + { + text.Text = $@"{(expanded ? "[+]" : "[-]")} replies ({count})"; + expanded = !expanded; + Action?.Invoke(expanded); + return base.OnClick(e); + } } } } From 3f8fecbc5034d2b601ea6e6bc3643e25b8e13fc6 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 8 Oct 2019 16:04:52 +0300 Subject: [PATCH 12/80] Adjust spacing --- osu.Game/Overlays/Comments/DrawableComment.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 9879995b00..f3d8d2f577 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -120,7 +120,7 @@ namespace osu.Game.Overlays.Comments { AutoSizeAxes = Axes.Both, Direction = FillDirection.Horizontal, - Spacing = new Vector2(5, 0), + Spacing = new Vector2(10, 0), Children = new Drawable[] { new SpriteText From 000e4a563cf4389d9fc86683838ece2e8251230b Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 8 Oct 2019 19:09:02 +0300 Subject: [PATCH 13/80] Parse parent comments --- .../API/Requests/Responses/APIComments.cs | 3 ++ .../Online/API/Requests/Responses/Comment.cs | 2 + osu.Game/Overlays/Comments/DrawableComment.cs | 45 ++++++++++++++++++- 3 files changed, 49 insertions(+), 1 deletion(-) diff --git a/osu.Game/Online/API/Requests/Responses/APIComments.cs b/osu.Game/Online/API/Requests/Responses/APIComments.cs index 9a12fb613e..f454d4052f 100644 --- a/osu.Game/Online/API/Requests/Responses/APIComments.cs +++ b/osu.Game/Online/API/Requests/Responses/APIComments.cs @@ -25,7 +25,10 @@ namespace osu.Game.Online.API.Requests.Responses comments.ForEach(parent => { if (parent.Id == child.ParentId) + { parent.ChildComments.Add(child); + child.ParentComment = parent; + } }); } }); diff --git a/osu.Game/Online/API/Requests/Responses/Comment.cs b/osu.Game/Online/API/Requests/Responses/Comment.cs index cdc3c3204b..e5d3f14d27 100644 --- a/osu.Game/Online/API/Requests/Responses/Comment.cs +++ b/osu.Game/Online/API/Requests/Responses/Comment.cs @@ -28,6 +28,8 @@ namespace osu.Game.Online.API.Requests.Responses public List ChildComments = new List(); + public Comment ParentComment { get; set; } + [JsonProperty(@"user_id")] public long UserId { get; set; } diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index f3d8d2f577..dea14f22c8 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -12,6 +12,7 @@ using osu.Game.Graphics.Containers; using osu.Game.Utils; using osu.Framework.Input.Events; using System; +using osu.Framework.Graphics.Cursor; namespace osu.Game.Overlays.Comments { @@ -97,9 +98,19 @@ namespace osu.Game.Overlays.Comments Spacing = new Vector2(0, 2), Children = new Drawable[] { - username = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true)) + new FillFlowContainer { AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(7, 0), + Children = new Drawable[] + { + username = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true)) + { + AutoSizeAxes = Axes.Both, + }, + new ParentUsername(comment) + } }, new TextFlowContainer(s => s.Font = OsuFont.GetFont(size: 14)) { @@ -196,5 +207,37 @@ namespace osu.Game.Overlays.Comments return base.OnClick(e); } } + + private class ParentUsername : FillFlowContainer, IHasTooltip + { + private const int spacing = 3; + + public string TooltipText => comment.ParentComment?.GetMessage() ?? ""; + + private readonly Comment comment; + + public ParentUsername(Comment comment) + { + this.comment = comment; + + AutoSizeAxes = Axes.Both; + Direction = FillDirection.Horizontal; + Spacing = new Vector2(spacing, 0); + Alpha = comment.ParentId == null ? 0 : 1; + Children = new Drawable[] + { + new SpriteIcon + { + Icon = FontAwesome.Solid.Reply, + Size = new Vector2(14), + }, + new SpriteText + { + Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true), + Text = comment.ParentComment?.User?.Username + } + }; + } + } } } From 341702b91d084207316711e6f43e33afa3fadcc6 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 8 Oct 2019 19:18:46 +0300 Subject: [PATCH 14/80] Use Bindable for expansion logic --- osu.Game/Overlays/Comments/DrawableComment.cs | 68 +++++++++---------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index dea14f22c8..bf24cbb70d 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -11,8 +11,8 @@ using osu.Game.Users.Drawables; using osu.Game.Graphics.Containers; using osu.Game.Utils; using osu.Framework.Input.Events; -using System; using osu.Framework.Graphics.Cursor; +using osu.Framework.Bindables; namespace osu.Game.Overlays.Comments { @@ -23,29 +23,7 @@ namespace osu.Game.Overlays.Comments private const int child_margin = 20; private const int duration = 200; - private bool childExpanded = true; - - public bool ChildExpanded - { - get => childExpanded; - set - { - if (childExpanded == value) - return; - - childExpanded = value; - - childCommentsVisibilityContainer.ClearTransforms(); - - if (childExpanded) - childCommentsVisibilityContainer.AutoSizeAxes = Axes.Y; - else - { - childCommentsVisibilityContainer.AutoSizeAxes = Axes.None; - childCommentsVisibilityContainer.ResizeHeightTo(0, duration, Easing.OutQuint); - } - } - } + private readonly BindableBool childExpanded = new BindableBool(true); private readonly Container childCommentsVisibilityContainer; @@ -53,7 +31,6 @@ namespace osu.Game.Overlays.Comments { LinkFlowContainer username; FillFlowContainer childCommentsContainer; - RepliesButton replies; RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; @@ -141,7 +118,8 @@ namespace osu.Game.Overlays.Comments Font = OsuFont.GetFont(size: 12), Text = HumanizerUtils.Humanize(comment.CreatedAt) }, - replies = new RepliesButton(comment.RepliesCount), + new RepliesButton(comment.RepliesCount) + { Expanded = { BindTarget = childExpanded } }, } } } @@ -172,17 +150,33 @@ namespace osu.Game.Overlays.Comments if (!c.IsDeleted) childCommentsContainer.Add(new DrawableComment(c)); }); + } - replies.Action += expanded => ChildExpanded = expanded; + protected override void LoadComplete() + { + childExpanded.BindValueChanged(onChildExpandedChanged, true); + base.LoadComplete(); + } + + private void onChildExpandedChanged(ValueChangedEvent expanded) + { + childCommentsVisibilityContainer.ClearTransforms(); + + if (expanded.NewValue) + childCommentsVisibilityContainer.AutoSizeAxes = Axes.Y; + else + { + childCommentsVisibilityContainer.AutoSizeAxes = Axes.None; + childCommentsVisibilityContainer.ResizeHeightTo(0, duration, Easing.OutQuint); + } } private class RepliesButton : Container { private readonly SpriteText text; - private bool expanded; private readonly int count; - public Action Action; + public readonly BindableBool Expanded = new BindableBool(true); public RepliesButton(int count) { @@ -193,17 +187,23 @@ namespace osu.Game.Overlays.Comments Child = text = new SpriteText { Font = OsuFont.GetFont(size: 12), - Text = $@"[-] replies ({count})" }; + } - expanded = true; + protected override void LoadComplete() + { + Expanded.BindValueChanged(onExpandedChanged, true); + base.LoadComplete(); + } + + private void onExpandedChanged(ValueChangedEvent expanded) + { + text.Text = $@"{(expanded.NewValue ? "[+]" : "[-]")} replies ({count})"; } protected override bool OnClick(ClickEvent e) { - text.Text = $@"{(expanded ? "[+]" : "[-]")} replies ({count})"; - expanded = !expanded; - Action?.Invoke(expanded); + Expanded.Value = !Expanded.Value; return base.OnClick(e); } } From 4230b00110768023bd1cf9d0e1fc098d5b273224 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 8 Oct 2019 19:22:23 +0300 Subject: [PATCH 15/80] Rename APIComments to APICommentsController --- osu.Game/Online/API/Requests/GetCommentsRequest.cs | 2 +- .../Responses/{APIComments.cs => APICommentsController.cs} | 2 +- osu.Game/Overlays/Comments/CommentsContainer.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename osu.Game/Online/API/Requests/Responses/{APIComments.cs => APICommentsController.cs} (98%) diff --git a/osu.Game/Online/API/Requests/GetCommentsRequest.cs b/osu.Game/Online/API/Requests/GetCommentsRequest.cs index 279a1905da..5a2b61b4d0 100644 --- a/osu.Game/Online/API/Requests/GetCommentsRequest.cs +++ b/osu.Game/Online/API/Requests/GetCommentsRequest.cs @@ -7,7 +7,7 @@ using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Online.API.Requests { - public class GetCommentsRequest : APIRequest + public class GetCommentsRequest : APIRequest { private readonly long id; private readonly int page; diff --git a/osu.Game/Online/API/Requests/Responses/APIComments.cs b/osu.Game/Online/API/Requests/Responses/APICommentsController.cs similarity index 98% rename from osu.Game/Online/API/Requests/Responses/APIComments.cs rename to osu.Game/Online/API/Requests/Responses/APICommentsController.cs index f454d4052f..cf2e5e8a35 100644 --- a/osu.Game/Online/API/Requests/Responses/APIComments.cs +++ b/osu.Game/Online/API/Requests/Responses/APICommentsController.cs @@ -7,7 +7,7 @@ using System.Collections.Generic; namespace osu.Game.Online.API.Requests.Responses { - public class APIComments + public class APICommentsController { private List comments; diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index d02e74a5a4..abbd2cdbde 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -86,7 +86,7 @@ namespace osu.Game.Overlays.Comments api.Queue(request); } - private void onSuccess(APIComments response) + private void onSuccess(APICommentsController response) { content.Clear(); From 35cfb16c8d21594237251fbf63d4fd69491efc3f Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 8 Oct 2019 19:56:43 +0300 Subject: [PATCH 16/80] Implement VotePill component --- osu.Game/Overlays/Comments/DrawableComment.cs | 55 +++++++++++++++++-- 1 file changed, 51 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index bf24cbb70d..ce60d905ad 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -13,6 +13,8 @@ using osu.Game.Utils; using osu.Framework.Input.Events; using osu.Framework.Graphics.Cursor; using osu.Framework.Bindables; +using osu.Framework.Graphics.Shapes; +using osuTK.Graphics; namespace osu.Game.Overlays.Comments { @@ -60,12 +62,28 @@ namespace osu.Game.Overlays.Comments { new Drawable[] { - new UpdateableAvatar(comment.User) + new FillFlowContainer { - Size = new Vector2(avatar_size), + AutoSizeAxes = Axes.Both, Margin = new MarginPadding { Horizontal = margin }, - Masking = true, - CornerRadius = avatar_size / 2, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(5, 0), + Children = new Drawable[] + { + new VotePill(comment.VotesCount) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, + new UpdateableAvatar(comment.User) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(avatar_size), + Masking = true, + CornerRadius = avatar_size / 2, + }, + } }, new FillFlowContainer { @@ -239,5 +257,34 @@ namespace osu.Game.Overlays.Comments }; } } + + private class VotePill : CircularContainer + { + private const int height = 20; + private const int margin = 10; + + public VotePill(int count) + { + AutoSizeAxes = Axes.X; + Height = height; + Masking = true; + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black + }, + new SpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Margin = new MarginPadding { Horizontal = margin }, + Font = OsuFont.GetFont(size: 14), + Text = $"+{count}" + } + }; + } + } } } From 9ab309fc0ef387e2226991c7f010e75f52fe1a19 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 8 Oct 2019 20:44:01 +0300 Subject: [PATCH 17/80] Use bold font for replies button --- osu.Game/Overlays/Comments/DrawableComment.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index ce60d905ad..ce78dfec9f 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -204,7 +204,7 @@ namespace osu.Game.Overlays.Comments Alpha = count == 0 ? 0 : 1; Child = text = new SpriteText { - Font = OsuFont.GetFont(size: 12), + Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold), }; } From b9ad079bf8b077ae7a9aa53bdb2da1e6dcc0993e Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 8 Oct 2019 20:57:55 +0300 Subject: [PATCH 18/80] Move CommentsHeader to it's own file --- .../Online/TestSceneCommentsContainer.cs | 2 + .../Overlays/Comments/CommentsContainer.cs | 56 --------------- osu.Game/Overlays/Comments/CommentsHeader.cs | 69 +++++++++++++++++++ 3 files changed, 71 insertions(+), 56 deletions(-) create mode 100644 osu.Game/Overlays/Comments/CommentsHeader.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs index e6f9582910..c8d16bdf21 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs @@ -17,6 +17,8 @@ namespace osu.Game.Tests.Visual.Online public override IReadOnlyList RequiredTypes => new[] { typeof(CommentsContainer), + typeof(CommentsHeader), + typeof(DrawableComment), }; protected override bool UseOnlineAPI => true; diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index abbd2cdbde..f8783952d1 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -9,8 +9,6 @@ using osu.Framework.Graphics; using osu.Framework.Bindables; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; -using osu.Framework.Graphics.Sprites; -using osuTK; using osu.Game.Online.API.Requests.Responses; namespace osu.Game.Overlays.Comments @@ -115,59 +113,5 @@ namespace osu.Game.Overlays.Comments { background.Colour = colours.Gray3; } - - private class CommentsHeader : CompositeDrawable - { - private const int height = 40; - private const int spacing = 10; - private const int padding = 50; - - public readonly Bindable Sort = new Bindable(); - - private readonly Box background; - - public CommentsHeader() - { - RelativeSizeAxes = Axes.X; - Height = height; - AddRangeInternal(new Drawable[] - { - background = new Box - { - RelativeSizeAxes = Axes.Both, - }, - new Container - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Horizontal = padding }, - Children = new Drawable[] - { - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(spacing, 0), - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Children = new Drawable[] - { - new SpriteText - { - Font = OsuFont.GetFont(size: 14), - Text = @"Sort by" - } - } - } - } - } - }); - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - background.Colour = colours.Gray4; - } - } } } diff --git a/osu.Game/Overlays/Comments/CommentsHeader.cs b/osu.Game/Overlays/Comments/CommentsHeader.cs new file mode 100644 index 0000000000..9ebd257a5d --- /dev/null +++ b/osu.Game/Overlays/Comments/CommentsHeader.cs @@ -0,0 +1,69 @@ +// 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.Graphics.Containers; +using osu.Game.Online.API.Requests; +using osu.Framework.Graphics; +using osu.Framework.Bindables; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics; +using osu.Framework.Graphics.Sprites; +using osuTK; + +namespace osu.Game.Overlays.Comments +{ + public class CommentsHeader : CompositeDrawable + { + private const int height = 40; + private const int spacing = 10; + private const int padding = 50; + + public readonly Bindable Sort = new Bindable(); + + private readonly Box background; + + public CommentsHeader() + { + RelativeSizeAxes = Axes.X; + Height = height; + AddRangeInternal(new Drawable[] + { + background = new Box + { + RelativeSizeAxes = Axes.Both, + }, + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Horizontal = padding }, + Children = new Drawable[] + { + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(spacing, 0), + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Children = new Drawable[] + { + new SpriteText + { + Font = OsuFont.GetFont(size: 14), + Text = @"Sort by" + } + } + } + } + } + }); + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + background.Colour = colours.Gray4; + } + } +} From 574170124cff05070833415e324f77a2e5fe88ef Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 8 Oct 2019 21:38:19 +0300 Subject: [PATCH 19/80] Implement HeaderButton component --- .../Online/TestSceneCommentsContainer.cs | 1 + osu.Game/Overlays/Comments/CommentsHeader.cs | 63 ++++++++++++++++- osu.Game/Overlays/Comments/HeaderButton.cs | 68 +++++++++++++++++++ 3 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 osu.Game/Overlays/Comments/HeaderButton.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs index c8d16bdf21..f5205552e0 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs @@ -19,6 +19,7 @@ namespace osu.Game.Tests.Visual.Online typeof(CommentsContainer), typeof(CommentsHeader), typeof(DrawableComment), + typeof(HeaderButton), }; protected override bool UseOnlineAPI => true; diff --git a/osu.Game/Overlays/Comments/CommentsHeader.cs b/osu.Game/Overlays/Comments/CommentsHeader.cs index 9ebd257a5d..b9dee7935e 100644 --- a/osu.Game/Overlays/Comments/CommentsHeader.cs +++ b/osu.Game/Overlays/Comments/CommentsHeader.cs @@ -10,6 +10,7 @@ using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Framework.Graphics.Sprites; using osuTK; +using osu.Framework.Input.Events; namespace osu.Game.Overlays.Comments { @@ -18,8 +19,10 @@ namespace osu.Game.Overlays.Comments private const int height = 40; private const int spacing = 10; private const int padding = 50; + private const int text_size = 14; public readonly Bindable Sort = new Bindable(); + public readonly BindableBool ShowDeleted = new BindableBool(); private readonly Box background; @@ -50,10 +53,16 @@ namespace osu.Game.Overlays.Comments { new SpriteText { - Font = OsuFont.GetFont(size: 14), + Font = OsuFont.GetFont(size: text_size), Text = @"Sort by" } } + }, + new ShowDeletedButton + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + Checked = { BindTarget = ShowDeleted } } } } @@ -65,5 +74,57 @@ namespace osu.Game.Overlays.Comments { background.Colour = colours.Gray4; } + + private class ShowDeletedButton : HeaderButton + { + private const int spacing = 5; + + public readonly BindableBool Checked = new BindableBool(); + + private readonly SpriteIcon checkboxIcon; + + public ShowDeletedButton() + { + Add(new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(spacing, 0), + Children = new Drawable[] + { + checkboxIcon = new SpriteIcon + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Size = new Vector2(10), + }, + new SpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Font = OsuFont.GetFont(size: text_size), + Text = @"Show deleted" + } + }, + }); + } + + protected override void LoadComplete() + { + Checked.BindValueChanged(onCheckedChanged, true); + base.LoadComplete(); + } + + private void onCheckedChanged(ValueChangedEvent isChecked) + { + checkboxIcon.Icon = isChecked.NewValue ? FontAwesome.Solid.CheckSquare : FontAwesome.Regular.Square; + } + + protected override bool OnClick(ClickEvent e) + { + Checked.Value = !Checked.Value; + return base.OnClick(e); + } + } } } diff --git a/osu.Game/Overlays/Comments/HeaderButton.cs b/osu.Game/Overlays/Comments/HeaderButton.cs new file mode 100644 index 0000000000..db8ea92a1a --- /dev/null +++ b/osu.Game/Overlays/Comments/HeaderButton.cs @@ -0,0 +1,68 @@ +// 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.Graphics.Containers; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics; +using osu.Framework.Input.Events; +using osu.Game.Graphics.UserInterface; + +namespace osu.Game.Overlays.Comments +{ + public class HeaderButton : Container + { + private const int height = 20; + private const int corner_radius = 3; + private const int margin = 10; + private const int duration = 200; + + protected override Container Content => content; + + private readonly Box background; + private readonly Container content; + + public HeaderButton() + { + AutoSizeAxes = Axes.X; + Height = height; + Masking = true; + CornerRadius = corner_radius; + AddRangeInternal(new Drawable[] + { + background = new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0, + }, + content = new Container + { + AutoSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Margin = new MarginPadding { Horizontal = margin } + }, + new HoverClickSounds(), + }); + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + background.Colour = colours.Gray6; + } + + protected override bool OnHover(HoverEvent e) + { + background.FadeIn(duration, Easing.OutQuint); + return base.OnHover(e); + } + + protected override void OnHoverLost(HoverLostEvent e) + { + base.OnHoverLost(e); + background.FadeOut(duration, Easing.OutQuint); + } + } +} From 29b0eacc821b5091c0251d6066e2e52296d8c279 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 8 Oct 2019 22:46:42 +0300 Subject: [PATCH 20/80] Implement SortSelector component --- .../Online/TestSceneCommentsContainer.cs | 1 + .../Online/API/Requests/GetCommentsRequest.cs | 2 +- .../Online/API/Requests/Responses/Comment.cs | 2 +- .../Overlays/Comments/CommentsContainer.cs | 3 +- osu.Game/Overlays/Comments/CommentsHeader.cs | 8 ++ osu.Game/Overlays/Comments/DrawableComment.cs | 9 ++- osu.Game/Overlays/Comments/HeaderButton.cs | 8 +- osu.Game/Overlays/Comments/SortSelector.cs | 75 +++++++++++++++++++ 8 files changed, 101 insertions(+), 7 deletions(-) create mode 100644 osu.Game/Overlays/Comments/SortSelector.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs index f5205552e0..7fbe9d7e8b 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs @@ -20,6 +20,7 @@ namespace osu.Game.Tests.Visual.Online typeof(CommentsHeader), typeof(DrawableComment), typeof(HeaderButton), + typeof(SortSelector) }; protected override bool UseOnlineAPI => true; diff --git a/osu.Game/Online/API/Requests/GetCommentsRequest.cs b/osu.Game/Online/API/Requests/GetCommentsRequest.cs index 5a2b61b4d0..02a36f7aa2 100644 --- a/osu.Game/Online/API/Requests/GetCommentsRequest.cs +++ b/osu.Game/Online/API/Requests/GetCommentsRequest.cs @@ -28,7 +28,7 @@ namespace osu.Game.Online.API.Requests req.AddParameter("commentable_type", type.ToString().Underscore().ToLowerInvariant()); req.AddParameter("commentable_id", id.ToString()); - req.AddParameter("sort", sort.ToString()); + req.AddParameter("sort", sort.ToString().ToLowerInvariant()); req.AddParameter("page", page.ToString()); return req; diff --git a/osu.Game/Online/API/Requests/Responses/Comment.cs b/osu.Game/Online/API/Requests/Responses/Comment.cs index e5d3f14d27..30aca3c2ea 100644 --- a/osu.Game/Online/API/Requests/Responses/Comment.cs +++ b/osu.Game/Online/API/Requests/Responses/Comment.cs @@ -31,7 +31,7 @@ namespace osu.Game.Online.API.Requests.Responses public Comment ParentComment { get; set; } [JsonProperty(@"user_id")] - public long UserId { get; set; } + public long? UserId { get; set; } public User User { get; set; } diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index f8783952d1..5be1b6c1c4 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -79,6 +79,7 @@ namespace osu.Game.Overlays.Comments private void getComments() { request?.Cancel(); + content.Clear(); request = new GetCommentsRequest(type, id, Sort.Value); request.Success += onSuccess; api.Queue(request); @@ -86,8 +87,6 @@ namespace osu.Game.Overlays.Comments private void onSuccess(APICommentsController response) { - content.Clear(); - foreach (var c in response.Comments) { if (!c.IsDeleted && c.IsTopLevel) diff --git a/osu.Game/Overlays/Comments/CommentsHeader.cs b/osu.Game/Overlays/Comments/CommentsHeader.cs index b9dee7935e..90a6f44d6b 100644 --- a/osu.Game/Overlays/Comments/CommentsHeader.cs +++ b/osu.Game/Overlays/Comments/CommentsHeader.cs @@ -53,8 +53,16 @@ namespace osu.Game.Overlays.Comments { new SpriteText { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, Font = OsuFont.GetFont(size: text_size), Text = @"Sort by" + }, + new SortSelector + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Current = { BindTarget = Sort } } } }, diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index ce78dfec9f..41b30513a1 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -161,7 +161,14 @@ namespace osu.Game.Overlays.Comments } }; - username.AddUserLink(comment.User); + if (comment.UserId == null) + { + username.AddText(comment.LegacyName); + } + else + { + username.AddUserLink(comment.User); + } comment.ChildComments.ForEach(c => { diff --git a/osu.Game/Overlays/Comments/HeaderButton.cs b/osu.Game/Overlays/Comments/HeaderButton.cs index db8ea92a1a..e3729b3b05 100644 --- a/osu.Game/Overlays/Comments/HeaderButton.cs +++ b/osu.Game/Overlays/Comments/HeaderButton.cs @@ -55,14 +55,18 @@ namespace osu.Game.Overlays.Comments protected override bool OnHover(HoverEvent e) { - background.FadeIn(duration, Easing.OutQuint); + FadeInBackground(); return base.OnHover(e); } protected override void OnHoverLost(HoverLostEvent e) { base.OnHoverLost(e); - background.FadeOut(duration, Easing.OutQuint); + FadeOutBackground(); } + + public void FadeInBackground() => background.FadeIn(duration, Easing.OutQuint); + + public void FadeOutBackground() => background.FadeOut(duration, Easing.OutQuint); } } diff --git a/osu.Game/Overlays/Comments/SortSelector.cs b/osu.Game/Overlays/Comments/SortSelector.cs new file mode 100644 index 0000000000..4425145c3e --- /dev/null +++ b/osu.Game/Overlays/Comments/SortSelector.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. + +using osu.Game.Online.API.Requests; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics; +using osu.Framework.Graphics.UserInterface; +using osu.Framework.Graphics.Sprites; +using osu.Game.Graphics; +using osuTK; +using osu.Game.Graphics.UserInterface; +using osu.Framework.Input.Events; +using osu.Framework.Bindables; + +namespace osu.Game.Overlays.Comments +{ + public class SortSelector : OsuTabControl + { + private const int spacing = 5; + + protected override Dropdown CreateDropdown() => null; + + protected override TabItem CreateTabItem(SortCommentsBy value) => new SortTabItem(value); + + protected override TabFillFlowContainer CreateTabFlow() => new TabFillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(spacing, 0), + }; + + public SortSelector() + { + AutoSizeAxes = Axes.Both; + } + + private class SortTabItem : TabItem + { + private readonly TabContent content; + + public SortTabItem(SortCommentsBy value) + : base(value) + { + AutoSizeAxes = Axes.Both; + Child = content = new TabContent(value) + { Active = { BindTarget = Active } }; + } + + protected override void OnActivated() => content.FadeInBackground(); + + protected override void OnDeactivated() => content.FadeOutBackground(); + + private class TabContent : HeaderButton + { + private const int text_size = 14; + + public readonly BindableBool Active = new BindableBool(); + + public TabContent(SortCommentsBy value) + { + Add(new SpriteText + { + Font = OsuFont.GetFont(size: text_size), + Text = value.ToString() + }); + } + + protected override void OnHoverLost(HoverLostEvent e) + { + if (!Active.Value) base.OnHoverLost(e); + } + } + } + } +} From faef4d932d08cc7ef5fde89d88953b3c21cd7ac6 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 9 Oct 2019 10:17:14 +0300 Subject: [PATCH 21/80] Improve message parsing --- osu.Game/Online/API/Requests/Responses/Comment.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Online/API/Requests/Responses/Comment.cs b/osu.Game/Online/API/Requests/Responses/Comment.cs index 30aca3c2ea..fb0aad0e0b 100644 --- a/osu.Game/Online/API/Requests/Responses/Comment.cs +++ b/osu.Game/Online/API/Requests/Responses/Comment.cs @@ -87,8 +87,7 @@ namespace osu.Game.Online.API.Requests.Responses public string GetMessage() { - //temporary fix until HTML parsing will be implemented - return MessageHTML.Remove(MessageHTML.LastIndexOf("

")).Substring(65); + return MessageHTML.Replace("
", "").Replace("

", "").Replace("
", "").Replace("

", "").Replace("
", ""); } } } From 4462d454e87fba91a25b92b3bc4fef0a9ba6007c Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 9 Oct 2019 10:34:17 +0300 Subject: [PATCH 22/80] Message padding improvements --- osu.Game/Overlays/Comments/CommentsContainer.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index 5be1b6c1c4..b9effb39e8 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -16,6 +16,7 @@ namespace osu.Game.Overlays.Comments public class CommentsContainer : CompositeDrawable { private const float separator_height = 1.5f; + private const int padding = 40; private readonly CommentableType type; private readonly long id; @@ -92,7 +93,13 @@ namespace osu.Game.Overlays.Comments if (!c.IsDeleted && c.IsTopLevel) content.AddRange(new Drawable[] { - new DrawableComment(c), + new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Padding = new MarginPadding { Right = padding }, + Child = new DrawableComment(c) + }, new Container { RelativeSizeAxes = Axes.X, From 0a56b041fdf7116ceb72d8a7251383f912961f5f Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 9 Oct 2019 11:07:56 +0300 Subject: [PATCH 23/80] Implement ShowChildsButton --- .../Online/TestSceneCommentsContainer.cs | 3 +- .../Online/API/Requests/Responses/Comment.cs | 2 +- .../Overlays/Comments/CommentsContainer.cs | 9 +-- osu.Game/Overlays/Comments/DrawableComment.cs | 72 ++++++++++++------- .../Overlays/Comments/ShowChildsButton.cs | 34 +++++++++ 5 files changed, 85 insertions(+), 35 deletions(-) create mode 100644 osu.Game/Overlays/Comments/ShowChildsButton.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs index 7fbe9d7e8b..4187771963 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs @@ -20,7 +20,8 @@ namespace osu.Game.Tests.Visual.Online typeof(CommentsHeader), typeof(DrawableComment), typeof(HeaderButton), - typeof(SortSelector) + typeof(SortSelector), + typeof(ShowChildsButton) }; protected override bool UseOnlineAPI => true; diff --git a/osu.Game/Online/API/Requests/Responses/Comment.cs b/osu.Game/Online/API/Requests/Responses/Comment.cs index fb0aad0e0b..9a3dee30b4 100644 --- a/osu.Game/Online/API/Requests/Responses/Comment.cs +++ b/osu.Game/Online/API/Requests/Responses/Comment.cs @@ -87,7 +87,7 @@ namespace osu.Game.Online.API.Requests.Responses public string GetMessage() { - return MessageHTML.Replace("
", "").Replace("

", "").Replace("
", "").Replace("

", "").Replace("
", ""); + return MessageHTML.Replace("
", "").Replace("

", "").Replace("
", "").Replace("

", "").Replace("
", "").Replace(""", "\""); } } } diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index b9effb39e8..5be1b6c1c4 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -16,7 +16,6 @@ namespace osu.Game.Overlays.Comments public class CommentsContainer : CompositeDrawable { private const float separator_height = 1.5f; - private const int padding = 40; private readonly CommentableType type; private readonly long id; @@ -93,13 +92,7 @@ namespace osu.Game.Overlays.Comments if (!c.IsDeleted && c.IsTopLevel) content.AddRange(new Drawable[] { - new Container - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Padding = new MarginPadding { Right = padding }, - Child = new DrawableComment(c) - }, + new DrawableComment(c), new Container { RelativeSizeAxes = Axes.X, diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 41b30513a1..a66b8fcd44 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -10,11 +10,11 @@ using osu.Game.Online.API.Requests.Responses; using osu.Game.Users.Drawables; using osu.Game.Graphics.Containers; using osu.Game.Utils; -using osu.Framework.Input.Events; using osu.Framework.Graphics.Cursor; using osu.Framework.Bindables; using osu.Framework.Graphics.Shapes; using osuTK.Graphics; +using System.Linq; namespace osu.Game.Overlays.Comments { @@ -23,6 +23,8 @@ namespace osu.Game.Overlays.Comments private const int avatar_size = 40; private const int margin = 10; private const int child_margin = 20; + private const int chevron_margin = 30; + private const int message_padding = 40; private const int duration = 200; private readonly BindableBool childExpanded = new BindableBool(true); @@ -93,25 +95,41 @@ namespace osu.Game.Overlays.Comments Spacing = new Vector2(0, 2), Children = new Drawable[] { - new FillFlowContainer + new Container { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(7, 0), + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, Children = new Drawable[] { - username = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true)) + new FillFlowContainer { AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(7, 0), + Children = new Drawable[] + { + username = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true)) + { + AutoSizeAxes = Axes.Both, + }, + new ParentUsername(comment) + } }, - new ParentUsername(comment) + new ChevronButton(comment) + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + Margin = new MarginPadding { Right = chevron_margin }, + Expanded = { BindTarget = childExpanded } + } } }, new TextFlowContainer(s => s.Font = OsuFont.GetFont(size: 14)) { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Text = comment.GetMessage() + Text = comment.GetMessage(), + Padding = new MarginPadding { Right = message_padding } } } } @@ -196,18 +214,34 @@ namespace osu.Game.Overlays.Comments } } - private class RepliesButton : Container + private class ChevronButton : ShowChildsButton + { + private readonly SpriteIcon icon; + + public ChevronButton(Comment comment) + { + Alpha = comment.IsTopLevel && comment.ChildComments.Any() ? 1 : 0; + Child = icon = new SpriteIcon + { + Size = new Vector2(12), + }; + } + + protected override void OnExpandedChanged(ValueChangedEvent expanded) + { + icon.Icon = expanded.NewValue ? FontAwesome.Solid.ChevronUp : FontAwesome.Solid.ChevronDown; + } + } + + private class RepliesButton : ShowChildsButton { private readonly SpriteText text; private readonly int count; - public readonly BindableBool Expanded = new BindableBool(true); - public RepliesButton(int count) { this.count = count; - AutoSizeAxes = Axes.Both; Alpha = count == 0 ? 0 : 1; Child = text = new SpriteText { @@ -215,22 +249,10 @@ namespace osu.Game.Overlays.Comments }; } - protected override void LoadComplete() - { - Expanded.BindValueChanged(onExpandedChanged, true); - base.LoadComplete(); - } - - private void onExpandedChanged(ValueChangedEvent expanded) + protected override void OnExpandedChanged(ValueChangedEvent expanded) { text.Text = $@"{(expanded.NewValue ? "[+]" : "[-]")} replies ({count})"; } - - protected override bool OnClick(ClickEvent e) - { - Expanded.Value = !Expanded.Value; - return base.OnClick(e); - } } private class ParentUsername : FillFlowContainer, IHasTooltip diff --git a/osu.Game/Overlays/Comments/ShowChildsButton.cs b/osu.Game/Overlays/Comments/ShowChildsButton.cs new file mode 100644 index 0000000000..81280a71b5 --- /dev/null +++ b/osu.Game/Overlays/Comments/ShowChildsButton.cs @@ -0,0 +1,34 @@ +// 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.Graphics; +using osu.Game.Graphics.Containers; +using osu.Framework.Input.Events; +using osu.Framework.Bindables; + +namespace osu.Game.Overlays.Comments +{ + public abstract class ShowChildsButton : OsuHoverContainer + { + public readonly BindableBool Expanded = new BindableBool(true); + + public ShowChildsButton() + { + AutoSizeAxes = Axes.Both; + } + + protected override void LoadComplete() + { + Expanded.BindValueChanged(OnExpandedChanged, true); + base.LoadComplete(); + } + + protected abstract void OnExpandedChanged(ValueChangedEvent expanded); + + protected override bool OnClick(ClickEvent e) + { + Expanded.Value = !Expanded.Value; + return base.OnClick(e); + } + } +} From a0dfbfe1488e9cbb66ad068828fdbf88069b24ec Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 9 Oct 2019 11:18:26 +0300 Subject: [PATCH 24/80] Handle parent usernames for legacy comments --- osu.Game/Overlays/Comments/DrawableComment.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index a66b8fcd44..6215f5e108 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -281,7 +281,7 @@ namespace osu.Game.Overlays.Comments new SpriteText { Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true), - Text = comment.ParentComment?.User?.Username + Text = comment.ParentComment?.User?.Username ?? comment.ParentComment?.LegacyName } }; } From ad99a3236f052d2f2130a8c3559093f5c3c3699d Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 9 Oct 2019 11:32:17 +0300 Subject: [PATCH 25/80] Handle edited comments --- .../Requests/Responses/APICommentsController.cs | 3 +++ osu.Game/Online/API/Requests/Responses/Comment.cs | 2 ++ osu.Game/Overlays/Comments/DrawableComment.cs | 14 +++++++++++++- 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/osu.Game/Online/API/Requests/Responses/APICommentsController.cs b/osu.Game/Online/API/Requests/Responses/APICommentsController.cs index cf2e5e8a35..ca6062e371 100644 --- a/osu.Game/Online/API/Requests/Responses/APICommentsController.cs +++ b/osu.Game/Online/API/Requests/Responses/APICommentsController.cs @@ -63,6 +63,9 @@ namespace osu.Game.Online.API.Requests.Responses { if (c.UserId == u.Id) c.User = u; + + if (c.EditedById == u.Id) + c.EditedUser = u; }); }); } diff --git a/osu.Game/Online/API/Requests/Responses/Comment.cs b/osu.Game/Online/API/Requests/Responses/Comment.cs index 9a3dee30b4..e420a585fe 100644 --- a/osu.Game/Online/API/Requests/Responses/Comment.cs +++ b/osu.Game/Online/API/Requests/Responses/Comment.cs @@ -81,6 +81,8 @@ namespace osu.Game.Online.API.Requests.Responses [JsonProperty(@"edited_by_id")] public long? EditedById { get; set; } + public User EditedUser { get; set; } + public bool IsTopLevel { get; set; } public bool IsDeleted { get; set; } diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 6215f5e108..92b59a985b 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -35,6 +35,7 @@ namespace osu.Game.Overlays.Comments { LinkFlowContainer username; FillFlowContainer childCommentsContainer; + FillFlowContainer info; RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; @@ -140,7 +141,7 @@ namespace osu.Game.Overlays.Comments { RelativeSizeAxes = Axes.Both, }, - new FillFlowContainer + info = new FillFlowContainer { AutoSizeAxes = Axes.Both, Direction = FillDirection.Horizontal, @@ -188,6 +189,17 @@ namespace osu.Game.Overlays.Comments username.AddUserLink(comment.User); } + if (comment.EditedAt.HasValue) + { + info.Add(new SpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Font = OsuFont.GetFont(size: 12), + Text = $@"edited {HumanizerUtils.Humanize(comment.EditedAt.Value)} by {comment.EditedUser.Username}" + }); + } + comment.ChildComments.ForEach(c => { if (!c.IsDeleted) From b2bd78308dc4473d89d89244b873e5bd97b9f54f Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 9 Oct 2019 12:18:49 +0300 Subject: [PATCH 26/80] Handle deleted comments --- .../Online/API/Requests/Responses/Comment.cs | 2 +- .../Overlays/Comments/CommentsContainer.cs | 24 +-- osu.Game/Overlays/Comments/DrawableComment.cs | 150 +++++++++++------- 3 files changed, 98 insertions(+), 78 deletions(-) diff --git a/osu.Game/Online/API/Requests/Responses/Comment.cs b/osu.Game/Online/API/Requests/Responses/Comment.cs index e420a585fe..76a322e5c9 100644 --- a/osu.Game/Online/API/Requests/Responses/Comment.cs +++ b/osu.Game/Online/API/Requests/Responses/Comment.cs @@ -89,7 +89,7 @@ namespace osu.Game.Online.API.Requests.Responses public string GetMessage() { - return MessageHTML.Replace("
", "").Replace("

", "").Replace("
", "").Replace("

", "").Replace("
", "").Replace(""", "\""); + return IsDeleted ? @"deleted" : MessageHTML.Replace("
", "").Replace("

", "").Replace("
", "").Replace("

", "").Replace("
", "").Replace(""", "\""); } } } diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index 5be1b6c1c4..fb97f08a6e 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -15,12 +15,11 @@ namespace osu.Game.Overlays.Comments { public class CommentsContainer : CompositeDrawable { - private const float separator_height = 1.5f; - private readonly CommentableType type; private readonly long id; public readonly Bindable Sort = new Bindable(); + public readonly BindableBool ShowDeleted = new BindableBool(); [Resolved] private IAPIProvider api { get; set; } @@ -55,7 +54,8 @@ namespace osu.Game.Overlays.Comments { new CommentsHeader { - Sort = { BindTarget = Sort } + Sort = { BindTarget = Sort }, + ShowDeleted = { BindTarget = ShowDeleted } }, content = new FillFlowContainer { @@ -89,21 +89,9 @@ namespace osu.Game.Overlays.Comments { foreach (var c in response.Comments) { - if (!c.IsDeleted && c.IsTopLevel) - content.AddRange(new Drawable[] - { - new DrawableComment(c), - new Container - { - RelativeSizeAxes = Axes.X, - Height = separator_height, - Child = new Box - { - RelativeSizeAxes = Axes.Both, - Colour = colours.Gray1, - } - } - }); + if (c.IsTopLevel) + content.Add(new DrawableComment(c) + { ShowDeleted = { BindTarget = ShowDeleted } }); } } diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 92b59a985b..4092cbb177 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -26,19 +26,29 @@ namespace osu.Game.Overlays.Comments private const int chevron_margin = 30; private const int message_padding = 40; private const int duration = 200; + private const float separator_height = 1.5f; + + public readonly BindableBool ShowDeleted = new BindableBool(); private readonly BindableBool childExpanded = new BindableBool(true); private readonly Container childCommentsVisibilityContainer; + private readonly Comment comment; public DrawableComment(Comment comment) { LinkFlowContainer username; FillFlowContainer childCommentsContainer; FillFlowContainer info; + TextFlowContainer message; + GridContainer content; + VotePill votePill; + + this.comment = comment; RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; + Masking = true; InternalChild = new FillFlowContainer { RelativeSizeAxes = Axes.X, @@ -46,7 +56,7 @@ namespace osu.Game.Overlays.Comments Direction = FillDirection.Vertical, Children = new Drawable[] { - new GridContainer + content = new GridContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, @@ -58,7 +68,6 @@ namespace osu.Game.Overlays.Comments }, RowDimensions = new[] { - new Dimension(GridSizeMode.AutoSize), new Dimension(GridSizeMode.AutoSize) }, Content = new[] @@ -73,10 +82,11 @@ namespace osu.Game.Overlays.Comments Spacing = new Vector2(5, 0), Children = new Drawable[] { - new VotePill(comment.VotesCount) + votePill = new VotePill(comment.VotesCount) { Anchor = Anchor.Centre, Origin = Anchor.Centre, + AlwaysPresent = true, }, new UpdateableAvatar(comment.User) { @@ -92,71 +102,53 @@ namespace osu.Game.Overlays.Comments { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Margin = new MarginPadding { Top = margin / 2 }, - Spacing = new Vector2(0, 2), + Spacing = new Vector2(0, 3), Children = new Drawable[] { - new Container + new FillFlowContainer { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(7, 0), Children = new Drawable[] { - new FillFlowContainer + username = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true)) { AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(7, 0), - Children = new Drawable[] - { - username = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true)) - { - AutoSizeAxes = Axes.Both, - }, - new ParentUsername(comment) - } }, - new ChevronButton(comment) + new ParentUsername(comment), + new SpriteText { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - Margin = new MarginPadding { Right = chevron_margin }, - Expanded = { BindTarget = childExpanded } + Alpha = comment.IsDeleted? 1 : 0, + Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true), + Text = @"deleted", } } }, - new TextFlowContainer(s => s.Font = OsuFont.GetFont(size: 14)) + message = new TextFlowContainer(s => s.Font = OsuFont.GetFont(size: 14)) { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Text = comment.GetMessage(), Padding = new MarginPadding { Right = message_padding } - } - } - } - }, - new Drawable[] - { - new Container - { - RelativeSizeAxes = Axes.Both, - }, - info = new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(10, 0), - Children = new Drawable[] - { - new SpriteText - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Font = OsuFont.GetFont(size: 12), - Text = HumanizerUtils.Humanize(comment.CreatedAt) }, - new RepliesButton(comment.RepliesCount) - { Expanded = { BindTarget = childExpanded } }, + info = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(10, 0), + Children = new Drawable[] + { + new SpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Font = OsuFont.GetFont(size: 12), + Text = HumanizerUtils.Humanize(comment.CreatedAt) + }, + new RepliesButton(comment.RepliesCount) + { Expanded = { BindTarget = childExpanded } }, + } + } } } } @@ -181,13 +173,9 @@ namespace osu.Game.Overlays.Comments }; if (comment.UserId == null) - { username.AddText(comment.LegacyName); - } else - { username.AddUserLink(comment.User); - } if (comment.EditedAt.HasValue) { @@ -200,15 +188,45 @@ namespace osu.Game.Overlays.Comments }); } - comment.ChildComments.ForEach(c => + if (!comment.IsDeleted) + message.Text = comment.GetMessage(); + else { - if (!c.IsDeleted) - childCommentsContainer.Add(new DrawableComment(c)); - }); + content.FadeColour(OsuColour.Gray(0.5f)); + votePill.Hide(); + } + + if (comment.IsTopLevel) + { + AddInternal(new Container + { + RelativeSizeAxes = Axes.X, + Height = separator_height, + Child = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = OsuColour.Gray(0.1f) + } + }); + + if (comment.ChildComments.Any()) + { + AddInternal(new ChevronButton(comment) + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + Margin = new MarginPadding { Right = chevron_margin, Top = margin }, + Expanded = { BindTarget = childExpanded } + }); + } + } + + comment.ChildComments.ForEach(c => childCommentsContainer.Add(new DrawableComment(c))); } protected override void LoadComplete() { + ShowDeleted.BindValueChanged(onShowDeletedChanged, true); childExpanded.BindValueChanged(onChildExpandedChanged, true); base.LoadComplete(); } @@ -226,6 +244,20 @@ namespace osu.Game.Overlays.Comments } } + private void onShowDeletedChanged(ValueChangedEvent show) + { + if (comment.IsDeleted) + { + if (show.NewValue) + AutoSizeAxes = Axes.Y; + else + { + AutoSizeAxes = Axes.None; + this.ResizeHeightTo(0); + } + } + } + private class ChevronButton : ShowChildsButton { private readonly SpriteIcon icon; From 7e3c97f4962e0503b16527d13cc2fb545a3dc659 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 9 Oct 2019 13:37:07 +0300 Subject: [PATCH 27/80] Implement DeletedChildsPlaceholder component --- .../Online/TestSceneCommentsContainer.cs | 6 ++ .../Online/API/Requests/Responses/Comment.cs | 18 +++++ osu.Game/Overlays/Comments/DrawableComment.cs | 66 +++++++++++++++++-- 3 files changed, 86 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs index 4187771963..8a6ec81d8e 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs @@ -40,6 +40,12 @@ namespace osu.Game.Tests.Visual.Online scrollFlow.Clear(); scrollFlow.Add(new CommentsContainer(CommentableType.Beatmapset, 41823)); }); + + AddStep("Airman comments", () => + { + scrollFlow.Clear(); + scrollFlow.Add(new CommentsContainer(CommentableType.Beatmapset, 24313)); + }); } } } diff --git a/osu.Game/Online/API/Requests/Responses/Comment.cs b/osu.Game/Online/API/Requests/Responses/Comment.cs index 76a322e5c9..6fea994cb9 100644 --- a/osu.Game/Online/API/Requests/Responses/Comment.cs +++ b/osu.Game/Online/API/Requests/Responses/Comment.cs @@ -5,6 +5,7 @@ using Newtonsoft.Json; using osu.Game.Users; using System; using System.Collections.Generic; +using System.Linq; namespace osu.Game.Online.API.Requests.Responses { @@ -91,5 +92,22 @@ namespace osu.Game.Online.API.Requests.Responses { return IsDeleted ? @"deleted" : MessageHTML.Replace("
", "").Replace("

", "").Replace("
", "").Replace("

", "").Replace("
", "").Replace(""", "\""); } + + public int GetDeletedChildsCount() + { + int count = 0; + + if (ChildComments.Any()) + ChildComments.ForEach(child => + { + if (child.IsDeleted) + count++; + }); + + if (IsDeleted) + count++; + + return count; + } } } diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 4092cbb177..60cae8c62a 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -27,6 +27,7 @@ namespace osu.Game.Overlays.Comments private const int message_padding = 40; private const int duration = 200; private const float separator_height = 1.5f; + private const int deleted_placeholder_margin = 80; public readonly BindableBool ShowDeleted = new BindableBool(); @@ -161,12 +162,26 @@ namespace osu.Game.Overlays.Comments AutoSizeDuration = duration, AutoSizeEasing = Easing.OutQuint, Masking = true, - Child = childCommentsContainer = new FillFlowContainer + Child = new FillFlowContainer { - Margin = new MarginPadding { Left = child_margin }, RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical + Direction = FillDirection.Vertical, + Children = new Drawable[] + { + childCommentsContainer = new FillFlowContainer + { + Margin = new MarginPadding { Left = child_margin }, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical + }, + new DeletedChildsPlaceholder(comment.GetDeletedChildsCount()) + { + Margin = new MarginPadding { Bottom = margin, Left = deleted_placeholder_margin }, + ShowDeleted = { BindTarget = ShowDeleted } + } + } } } } @@ -221,7 +236,8 @@ namespace osu.Game.Overlays.Comments } } - comment.ChildComments.ForEach(c => childCommentsContainer.Add(new DrawableComment(c))); + comment.ChildComments.ForEach(c => childCommentsContainer.Add(new DrawableComment(c) + { ShowDeleted = { BindTarget = ShowDeleted } })); } protected override void LoadComplete() @@ -258,6 +274,48 @@ namespace osu.Game.Overlays.Comments } } + private class DeletedChildsPlaceholder : FillFlowContainer + { + public readonly BindableBool ShowDeleted = new BindableBool(); + + private readonly bool canBeVisible; + + public DeletedChildsPlaceholder(int count) + { + canBeVisible = count != 0; + + AutoSizeAxes = Axes.Both; + Direction = FillDirection.Horizontal; + Spacing = new Vector2(3, 0); + Alpha = 0; + Children = new Drawable[] + { + new SpriteIcon + { + Icon = FontAwesome.Solid.Trash, + Size = new Vector2(14), + }, + new SpriteText + { + Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true), + Text = $@"{count} deleted comments" + } + }; + } + + protected override void LoadComplete() + { + ShowDeleted.BindValueChanged(onShowDeletedChanged, true); + base.LoadComplete(); + } + + private void onShowDeletedChanged(ValueChangedEvent showDeleted) + { + if (canBeVisible) + this.FadeTo(showDeleted.NewValue ? 0 : 1); + } + } + private class ChevronButton : ShowChildsButton { private readonly SpriteIcon icon; From c9d5bea0f1bd1a8a01c4fe2f08242e8292dffe22 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 9 Oct 2019 13:45:14 +0300 Subject: [PATCH 28/80] Remove animations --- osu.Game/Overlays/Comments/DrawableComment.cs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 60cae8c62a..94ec7a861a 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -25,7 +25,6 @@ namespace osu.Game.Overlays.Comments private const int child_margin = 20; private const int chevron_margin = 30; private const int message_padding = 40; - private const int duration = 200; private const float separator_height = 1.5f; private const int deleted_placeholder_margin = 80; @@ -159,8 +158,6 @@ namespace osu.Game.Overlays.Comments { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - AutoSizeDuration = duration, - AutoSizeEasing = Easing.OutQuint, Masking = true, Child = new FillFlowContainer { @@ -249,14 +246,12 @@ namespace osu.Game.Overlays.Comments private void onChildExpandedChanged(ValueChangedEvent expanded) { - childCommentsVisibilityContainer.ClearTransforms(); - if (expanded.NewValue) childCommentsVisibilityContainer.AutoSizeAxes = Axes.Y; else { childCommentsVisibilityContainer.AutoSizeAxes = Axes.None; - childCommentsVisibilityContainer.ResizeHeightTo(0, duration, Easing.OutQuint); + childCommentsVisibilityContainer.ResizeHeightTo(0); } } From 107d39c3e97edb17e56bc9377d7e6cf76574ed43 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 9 Oct 2019 14:10:05 +0300 Subject: [PATCH 29/80] Add DeletedChildsPlaceholder to the bottom of the comments container --- .../Online/TestSceneCommentsContainer.cs | 3 +- .../Online/API/Requests/Responses/Comment.cs | 3 - .../Overlays/Comments/CommentsContainer.cs | 13 +++++ .../Comments/DeletedChildsPlaceholder.cs | 58 +++++++++++++++++++ osu.Game/Overlays/Comments/DrawableComment.cs | 46 +-------------- 5 files changed, 75 insertions(+), 48 deletions(-) create mode 100644 osu.Game/Overlays/Comments/DeletedChildsPlaceholder.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs index 8a6ec81d8e..342ba487f0 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs @@ -21,7 +21,8 @@ namespace osu.Game.Tests.Visual.Online typeof(DrawableComment), typeof(HeaderButton), typeof(SortSelector), - typeof(ShowChildsButton) + typeof(ShowChildsButton), + typeof(DeletedChildsPlaceholder) }; protected override bool UseOnlineAPI => true; diff --git a/osu.Game/Online/API/Requests/Responses/Comment.cs b/osu.Game/Online/API/Requests/Responses/Comment.cs index 6fea994cb9..2334c86519 100644 --- a/osu.Game/Online/API/Requests/Responses/Comment.cs +++ b/osu.Game/Online/API/Requests/Responses/Comment.cs @@ -104,9 +104,6 @@ namespace osu.Game.Online.API.Requests.Responses count++; }); - if (IsDeleted) - count++; - return count; } } diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index fb97f08a6e..bf68457988 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -93,6 +93,19 @@ namespace osu.Game.Overlays.Comments content.Add(new DrawableComment(c) { ShowDeleted = { BindTarget = ShowDeleted } }); } + + int deletedComments = 0; + + response.Comments.ForEach(comment => + { + if (comment.IsDeleted && comment.IsTopLevel) + deletedComments++; + }); + + content.Add(new DeletedChildsPlaceholder(deletedComments) + { + ShowDeleted = { BindTarget = ShowDeleted } + }); } [BackgroundDependencyLoader] diff --git a/osu.Game/Overlays/Comments/DeletedChildsPlaceholder.cs b/osu.Game/Overlays/Comments/DeletedChildsPlaceholder.cs new file mode 100644 index 0000000000..d0e6c17ccb --- /dev/null +++ b/osu.Game/Overlays/Comments/DeletedChildsPlaceholder.cs @@ -0,0 +1,58 @@ +// 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.Graphics.Containers; +using osu.Framework.Graphics; +using osu.Game.Graphics; +using osu.Framework.Graphics.Sprites; +using osuTK; +using osu.Framework.Bindables; + +namespace osu.Game.Overlays.Comments +{ + public class DeletedChildsPlaceholder : FillFlowContainer + { + private const int deleted_placeholder_margin = 80; + private const int margin = 10; + + public readonly BindableBool ShowDeleted = new BindableBool(); + + private readonly bool canBeVisible; + + public DeletedChildsPlaceholder(int count) + { + canBeVisible = count != 0; + + AutoSizeAxes = Axes.Both; + Direction = FillDirection.Horizontal; + Spacing = new Vector2(3, 0); + Margin = new MarginPadding { Vertical = margin, Left = deleted_placeholder_margin }; + Alpha = 0; + Children = new Drawable[] + { + new SpriteIcon + { + Icon = FontAwesome.Solid.Trash, + Size = new Vector2(14), + }, + new SpriteText + { + Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true), + Text = $@"{count} deleted comments" + } + }; + } + + protected override void LoadComplete() + { + ShowDeleted.BindValueChanged(onShowDeletedChanged, true); + base.LoadComplete(); + } + + private void onShowDeletedChanged(ValueChangedEvent showDeleted) + { + if (canBeVisible) + this.FadeTo(showDeleted.NewValue ? 0 : 1); + } + } +} diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 94ec7a861a..4af2e07227 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -26,7 +26,6 @@ namespace osu.Game.Overlays.Comments private const int chevron_margin = 30; private const int message_padding = 40; private const float separator_height = 1.5f; - private const int deleted_placeholder_margin = 80; public readonly BindableBool ShowDeleted = new BindableBool(); @@ -175,7 +174,6 @@ namespace osu.Game.Overlays.Comments }, new DeletedChildsPlaceholder(comment.GetDeletedChildsCount()) { - Margin = new MarginPadding { Bottom = margin, Left = deleted_placeholder_margin }, ShowDeleted = { BindTarget = ShowDeleted } } } @@ -214,6 +212,8 @@ namespace osu.Game.Overlays.Comments { RelativeSizeAxes = Axes.X, Height = separator_height, + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, Child = new Box { RelativeSizeAxes = Axes.Both, @@ -269,48 +269,6 @@ namespace osu.Game.Overlays.Comments } } - private class DeletedChildsPlaceholder : FillFlowContainer - { - public readonly BindableBool ShowDeleted = new BindableBool(); - - private readonly bool canBeVisible; - - public DeletedChildsPlaceholder(int count) - { - canBeVisible = count != 0; - - AutoSizeAxes = Axes.Both; - Direction = FillDirection.Horizontal; - Spacing = new Vector2(3, 0); - Alpha = 0; - Children = new Drawable[] - { - new SpriteIcon - { - Icon = FontAwesome.Solid.Trash, - Size = new Vector2(14), - }, - new SpriteText - { - Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true), - Text = $@"{count} deleted comments" - } - }; - } - - protected override void LoadComplete() - { - ShowDeleted.BindValueChanged(onShowDeletedChanged, true); - base.LoadComplete(); - } - - private void onShowDeletedChanged(ValueChangedEvent showDeleted) - { - if (canBeVisible) - this.FadeTo(showDeleted.NewValue ? 0 : 1); - } - } - private class ChevronButton : ShowChildsButton { private readonly SpriteIcon icon; From f6b78ad6617508f49654c86696585b934c83a8d2 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Thu, 10 Oct 2019 11:43:45 +0300 Subject: [PATCH 30/80] Overall cleanups --- .../Online/API/Requests/GetCommentsRequest.cs | 8 +-- .../Overlays/Comments/CommentsContainer.cs | 4 +- osu.Game/Overlays/Comments/CommentsHeader.cs | 3 +- .../Comments/DeletedChildsPlaceholder.cs | 3 +- osu.Game/Overlays/Comments/DrawableComment.cs | 59 +++++++------------ osu.Game/Overlays/Comments/SortSelector.cs | 8 ++- 6 files changed, 35 insertions(+), 50 deletions(-) diff --git a/osu.Game/Online/API/Requests/GetCommentsRequest.cs b/osu.Game/Online/API/Requests/GetCommentsRequest.cs index 02a36f7aa2..fb30130ee9 100644 --- a/osu.Game/Online/API/Requests/GetCommentsRequest.cs +++ b/osu.Game/Online/API/Requests/GetCommentsRequest.cs @@ -4,6 +4,7 @@ using osu.Framework.IO.Network; using Humanizer; using osu.Game.Online.API.Requests.Responses; +using osu.Game.Overlays.Comments; namespace osu.Game.Online.API.Requests { @@ -43,11 +44,4 @@ namespace osu.Game.Online.API.Requests Beatmapset, NewsPost } - - public enum SortCommentsBy - { - New, - Old, - Top - } } diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index bf68457988..314376f5ff 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -91,7 +91,9 @@ namespace osu.Game.Overlays.Comments { if (c.IsTopLevel) content.Add(new DrawableComment(c) - { ShowDeleted = { BindTarget = ShowDeleted } }); + { + ShowDeleted = { BindTarget = ShowDeleted } + }); } int deletedComments = 0; diff --git a/osu.Game/Overlays/Comments/CommentsHeader.cs b/osu.Game/Overlays/Comments/CommentsHeader.cs index 90a6f44d6b..6e9864f153 100644 --- a/osu.Game/Overlays/Comments/CommentsHeader.cs +++ b/osu.Game/Overlays/Comments/CommentsHeader.cs @@ -3,7 +3,6 @@ using osu.Framework.Allocation; using osu.Framework.Graphics.Containers; -using osu.Game.Online.API.Requests; using osu.Framework.Graphics; using osu.Framework.Bindables; using osu.Framework.Graphics.Shapes; @@ -62,7 +61,7 @@ namespace osu.Game.Overlays.Comments { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, - Current = { BindTarget = Sort } + Current = Sort } } }, diff --git a/osu.Game/Overlays/Comments/DeletedChildsPlaceholder.cs b/osu.Game/Overlays/Comments/DeletedChildsPlaceholder.cs index d0e6c17ccb..7aae42908e 100644 --- a/osu.Game/Overlays/Comments/DeletedChildsPlaceholder.cs +++ b/osu.Game/Overlays/Comments/DeletedChildsPlaceholder.cs @@ -7,6 +7,7 @@ using osu.Game.Graphics; using osu.Framework.Graphics.Sprites; using osuTK; using osu.Framework.Bindables; +using System.Linq; namespace osu.Game.Overlays.Comments { @@ -38,7 +39,7 @@ namespace osu.Game.Overlays.Comments new SpriteText { Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true), - Text = $@"{count} deleted comments" + Text = $@"{count} deleted comment{(count.ToString().ToCharArray().Last() == '1' ? "" : "s")}" } }; } diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 4af2e07227..fd7f874304 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -31,7 +31,7 @@ namespace osu.Game.Overlays.Comments private readonly BindableBool childExpanded = new BindableBool(true); - private readonly Container childCommentsVisibilityContainer; + private readonly FillFlowContainer childCommentsVisibilityContainer; private readonly Comment comment; public DrawableComment(Comment comment) @@ -47,7 +47,6 @@ namespace osu.Game.Overlays.Comments RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; - Masking = true; InternalChild = new FillFlowContainer { RelativeSizeAxes = Axes.X, @@ -145,7 +144,9 @@ namespace osu.Game.Overlays.Comments Text = HumanizerUtils.Humanize(comment.CreatedAt) }, new RepliesButton(comment.RepliesCount) - { Expanded = { BindTarget = childExpanded } }, + { + Expanded = { BindTarget = childExpanded } + }, } } } @@ -153,29 +154,23 @@ namespace osu.Game.Overlays.Comments } } }, - childCommentsVisibilityContainer = new Container + childCommentsVisibilityContainer = new FillFlowContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Masking = true, - Child = new FillFlowContainer + Direction = FillDirection.Vertical, + Children = new Drawable[] { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical, - Children = new Drawable[] + childCommentsContainer = new FillFlowContainer { - childCommentsContainer = new FillFlowContainer - { - Margin = new MarginPadding { Left = child_margin }, - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical - }, - new DeletedChildsPlaceholder(comment.GetDeletedChildsCount()) - { - ShowDeleted = { BindTarget = ShowDeleted } - } + Margin = new MarginPadding { Left = child_margin }, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical + }, + new DeletedChildsPlaceholder(comment.GetDeletedChildsCount()) + { + ShowDeleted = { BindTarget = ShowDeleted } } } } @@ -234,7 +229,9 @@ namespace osu.Game.Overlays.Comments } comment.ChildComments.ForEach(c => childCommentsContainer.Add(new DrawableComment(c) - { ShowDeleted = { BindTarget = ShowDeleted } })); + { + ShowDeleted = { BindTarget = ShowDeleted } + })); } protected override void LoadComplete() @@ -246,27 +243,13 @@ namespace osu.Game.Overlays.Comments private void onChildExpandedChanged(ValueChangedEvent expanded) { - if (expanded.NewValue) - childCommentsVisibilityContainer.AutoSizeAxes = Axes.Y; - else - { - childCommentsVisibilityContainer.AutoSizeAxes = Axes.None; - childCommentsVisibilityContainer.ResizeHeightTo(0); - } + childCommentsVisibilityContainer.FadeTo(expanded.NewValue ? 1 : 0); } private void onShowDeletedChanged(ValueChangedEvent show) { if (comment.IsDeleted) - { - if (show.NewValue) - AutoSizeAxes = Axes.Y; - else - { - AutoSizeAxes = Axes.None; - this.ResizeHeightTo(0); - } - } + this.FadeTo(show.NewValue ? 1 : 0); } private class ChevronButton : ShowChildsButton diff --git a/osu.Game/Overlays/Comments/SortSelector.cs b/osu.Game/Overlays/Comments/SortSelector.cs index 4425145c3e..cb95a758ff 100644 --- a/osu.Game/Overlays/Comments/SortSelector.cs +++ b/osu.Game/Overlays/Comments/SortSelector.cs @@ -1,7 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osu.Game.Online.API.Requests; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics; using osu.Framework.Graphics.UserInterface; @@ -72,4 +71,11 @@ namespace osu.Game.Overlays.Comments } } } + + public enum SortCommentsBy + { + New, + Old, + Top + } } From 6301f837e0b17a8216f2af8a3ee55e064249b16d Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 11 Oct 2019 15:27:23 +0900 Subject: [PATCH 31/80] Initial implementation of osu! beat snapping grid --- .../TestSceneOsuBeatSnapGrid.cs | 170 ++++++++++++++++++ 1 file changed, 170 insertions(+) create mode 100644 osu.Game.Rulesets.Osu.Tests/TestSceneOsuBeatSnapGrid.cs diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuBeatSnapGrid.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuBeatSnapGrid.cs new file mode 100644 index 0000000000..9f0d59afab --- /dev/null +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuBeatSnapGrid.cs @@ -0,0 +1,170 @@ +// 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 NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.UserInterface; +using osu.Framework.Input.Events; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Osu.Beatmaps; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Screens.Edit; +using osu.Game.Screens.Edit.Compose.Components; +using osu.Game.Tests.Visual; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Rulesets.Osu.Tests +{ + public class TestSceneOsuBeatSnapGrid : ManualInputManagerTestScene + { + private const double beat_length = 100; + private static readonly Vector2 grid_position = new Vector2(512, 384); + + [Cached(typeof(IEditorBeatmap))] + private readonly EditorBeatmap editorBeatmap; + + [Cached] + private readonly BindableBeatDivisor beatDivisor = new BindableBeatDivisor(); + + private OsuBeatSnapGrid grid; + private Drawable cursor; + + public TestSceneOsuBeatSnapGrid() + { + editorBeatmap = new EditorBeatmap(new OsuBeatmap()); + } + + [SetUp] + public void Setup() => Schedule(() => + { + Clear(); + + editorBeatmap.ControlPointInfo.TimingPoints.Clear(); + editorBeatmap.ControlPointInfo.TimingPoints.Add(new TimingControlPoint { BeatLength = beat_length }); + + beatDivisor.Value = 1; + }); + + protected override bool OnMouseMove(MouseMoveEvent e) + { + base.OnMouseMove(e); + + if (cursor != null) + cursor.Position = grid?.GetSnapPosition(grid.ToLocalSpace(e.ScreenSpaceMousePosition)) ?? e.ScreenSpaceMousePosition; + + return true; + } + + [TestCase(1)] + [TestCase(2)] + [TestCase(3)] + [TestCase(4)] + [TestCase(6)] + [TestCase(8)] + [TestCase(12)] + [TestCase(16)] + public void TestBeatDivisor(int divisor) + { + AddStep($"set beat divisor = {divisor}", () => beatDivisor.Value = divisor); + createGrid(); + } + + private void createGrid() + { + AddStep("create grid", () => + { + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.SlateGray + }, + grid = new OsuBeatSnapGrid(new HitCircle { Position = grid_position }), + cursor = new Circle + { + Origin = Anchor.Centre, + Size = new Vector2(50), + Colour = Color4.Red + } + }; + }); + } + + private abstract class CircularBeatSnapGrid : BeatSnapGrid + { + protected override void CreateGrid(Vector2 startPosition) + { + float maxDistance = Math.Max( + Vector2.Distance(startPosition, Vector2.Zero), + Math.Max( + Vector2.Distance(startPosition, new Vector2(DrawWidth, 0)), + Math.Max( + Vector2.Distance(startPosition, new Vector2(0, DrawHeight)), + Vector2.Distance(startPosition, DrawSize)))); + + int requiredCircles = (int)(maxDistance / DistanceSpacing); + + for (int i = 0; i < requiredCircles; i++) + { + float radius = (i + 1) * DistanceSpacing * 2; + + AddInternal(new CircularProgress + { + Origin = Anchor.Centre, + Position = startPosition, + Current = { Value = 1 }, + Size = new Vector2(radius), + InnerRadius = 4 * 1f / radius, + Colour = GetColourForBeatIndex(i) + }); + } + } + + public override Vector2 GetSnapPosition(Vector2 position) + { + Vector2 direction = position - StartPosition; + float distance = direction.Length; + + float radius = DistanceSpacing; + int radialCount = Math.Max(1, (int)Math.Round(distance / radius)); + + if (radialCount <= 0) + return position; + + Vector2 normalisedDirection = direction * new Vector2(1f / distance); + + return StartPosition + normalisedDirection * radialCount * radius; + } + } + + private class OsuBeatSnapGrid : CircularBeatSnapGrid + { + /// + /// Scoring distance with a speed-adjusted beat length of 1 second. + /// + private const float base_scoring_distance = 100; + + public OsuBeatSnapGrid(OsuHitObject hitObject) + : base(hitObject, hitObject.StackedEndPosition) + { + } + + protected override float GetVelocity(double time, ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) + { + TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(time); + DifficultyControlPoint difficultyPoint = controlPointInfo.DifficultyPointAt(time); + + double scoringDistance = base_scoring_distance * difficulty.SliderMultiplier * difficultyPoint.SpeedMultiplier; + + return (float)(scoringDistance / timingPoint.BeatLength); + } + } + } +} From 4d32a8aa6b5cca76f5b993791ce4e536a4709836 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 11 Oct 2019 17:11:37 +0900 Subject: [PATCH 32/80] More tests --- .../TestSceneOsuBeatSnapGrid.cs | 172 +++++++++++++++--- 1 file changed, 145 insertions(+), 27 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuBeatSnapGrid.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuBeatSnapGrid.cs index 9f0d59afab..7baa2f0d72 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuBeatSnapGrid.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuBeatSnapGrid.cs @@ -5,9 +5,11 @@ using System; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; +using osu.Framework.MathUtils; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Objects; @@ -32,12 +34,13 @@ namespace osu.Game.Rulesets.Osu.Tests [Cached] private readonly BindableBeatDivisor beatDivisor = new BindableBeatDivisor(); - private OsuBeatSnapGrid grid; - private Drawable cursor; + private TestOsuBeatSnapGrid grid; public TestSceneOsuBeatSnapGrid() { editorBeatmap = new EditorBeatmap(new OsuBeatmap()); + + createGrid(); } [SetUp] @@ -45,22 +48,14 @@ namespace osu.Game.Rulesets.Osu.Tests { Clear(); + editorBeatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier = 1; + editorBeatmap.ControlPointInfo.DifficultyPoints.Clear(); editorBeatmap.ControlPointInfo.TimingPoints.Clear(); editorBeatmap.ControlPointInfo.TimingPoints.Add(new TimingControlPoint { BeatLength = beat_length }); beatDivisor.Value = 1; }); - protected override bool OnMouseMove(MouseMoveEvent e) - { - base.OnMouseMove(e); - - if (cursor != null) - cursor.Position = grid?.GetSnapPosition(grid.ToLocalSpace(e.ScreenSpaceMousePosition)) ?? e.ScreenSpaceMousePosition; - - return true; - } - [TestCase(1)] [TestCase(2)] [TestCase(3)] @@ -75,6 +70,80 @@ namespace osu.Game.Rulesets.Osu.Tests createGrid(); } + [TestCase(100, 100)] + [TestCase(200, 100)] + public void TestBeatLength(float beatLength, float expectedSpacing) + { + AddStep($"set beat length = {beatLength}", () => + { + editorBeatmap.ControlPointInfo.TimingPoints.Clear(); + editorBeatmap.ControlPointInfo.TimingPoints.Add(new TimingControlPoint { BeatLength = beatLength }); + }); + + createGrid(); + AddAssert($"spacing = {expectedSpacing}", () => Precision.AlmostEquals(expectedSpacing, grid.DistanceSpacing)); + } + + [TestCase(0.5f, 50)] + [TestCase(1, 100)] + [TestCase(1.5f, 150)] + public void TestSpeedMultiplier(float multiplier, float expectedSpacing) + { + AddStep($"set speed multiplier = {multiplier}", () => + { + editorBeatmap.ControlPointInfo.DifficultyPoints.Clear(); + editorBeatmap.ControlPointInfo.DifficultyPoints.Add(new DifficultyControlPoint { SpeedMultiplier = multiplier }); + }); + + createGrid(); + AddAssert($"spacing = {expectedSpacing}", () => Precision.AlmostEquals(expectedSpacing, grid.DistanceSpacing)); + } + + [TestCase(0.5f, 50)] + [TestCase(1, 100)] + [TestCase(1.5f, 150)] + public void TestSliderMultiplier(float multiplier, float expectedSpacing) + { + AddStep($"set speed multiplier = {multiplier}", () => editorBeatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier = multiplier); + createGrid(); + AddAssert($"spacing = {expectedSpacing}", () => Precision.AlmostEquals(expectedSpacing, grid.DistanceSpacing)); + } + + [Test] + public void TestCursorInCentre() + { + createGrid(); + + AddStep("move mouse to centre", () => InputManager.MoveMouseTo(grid.ToScreenSpace(grid_position))); + assertSnappedDistance((float)beat_length); + } + + [Test] + public void TestCursorBeforeMovementPoint() + { + createGrid(); + + AddStep("move mouse to just before movement point", () => InputManager.MoveMouseTo(grid.ToScreenSpace(grid_position + new Vector2((float)beat_length, 0) * 1.49f))); + assertSnappedDistance((float)beat_length); + } + + [Test] + public void TestCursorAfterMovementPoint() + { + createGrid(); + + AddStep("move mouse to just after movement point", () => InputManager.MoveMouseTo(grid.ToScreenSpace(grid_position + new Vector2((float)beat_length, 0) * 1.51f))); + assertSnappedDistance((float)beat_length * 2); + } + + private void assertSnappedDistance(float expectedDistance) => AddAssert($"snap distance = {expectedDistance}", () => + { + Vector2 snappedPosition = grid.GetSnapPosition(grid.ToLocalSpace(InputManager.CurrentState.Mouse.Position)); + float distance = Vector2.Distance(snappedPosition, grid_position); + + return Precision.AlmostEquals(expectedDistance, distance); + }); + private void createGrid() { AddStep("create grid", () => @@ -86,28 +155,77 @@ namespace osu.Game.Rulesets.Osu.Tests RelativeSizeAxes = Axes.Both, Colour = Color4.SlateGray }, - grid = new OsuBeatSnapGrid(new HitCircle { Position = grid_position }), - cursor = new Circle - { - Origin = Anchor.Centre, - Size = new Vector2(50), - Colour = Color4.Red - } + grid = new TestOsuBeatSnapGrid(new HitCircle { Position = grid_position }), + new SnappingCursorContainer { GetSnapPosition = v => grid.GetSnapPosition(grid.ToLocalSpace(v)) } }; }); } + private class SnappingCursorContainer : CompositeDrawable + { + public Func GetSnapPosition; + + private readonly Drawable cursor; + + public SnappingCursorContainer() + { + RelativeSizeAxes = Axes.Both; + + InternalChild = cursor = new Circle + { + Origin = Anchor.Centre, + Size = new Vector2(50), + Colour = Color4.Red + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + updatePosition(GetContainingInputManager().CurrentState.Mouse.Position); + } + + protected override bool OnMouseMove(MouseMoveEvent e) + { + base.OnMouseMove(e); + + updatePosition(e.ScreenSpaceMousePosition); + return true; + } + + private void updatePosition(Vector2 screenSpacePosition) + { + cursor.Position = GetSnapPosition.Invoke(screenSpacePosition); + } + } + + private class TestOsuBeatSnapGrid : OsuBeatSnapGrid + { + public new float DistanceSpacing => base.DistanceSpacing; + + public TestOsuBeatSnapGrid(OsuHitObject hitObject) + : base(hitObject) + { + } + } + private abstract class CircularBeatSnapGrid : BeatSnapGrid { - protected override void CreateGrid(Vector2 startPosition) + protected CircularBeatSnapGrid(HitObject hitObject, Vector2 centrePosition) + : base(hitObject, centrePosition) + { + } + + protected override void CreateContent(Vector2 centrePosition) { float maxDistance = Math.Max( - Vector2.Distance(startPosition, Vector2.Zero), + Vector2.Distance(centrePosition, Vector2.Zero), Math.Max( - Vector2.Distance(startPosition, new Vector2(DrawWidth, 0)), + Vector2.Distance(centrePosition, new Vector2(DrawWidth, 0)), Math.Max( - Vector2.Distance(startPosition, new Vector2(0, DrawHeight)), - Vector2.Distance(startPosition, DrawSize)))); + Vector2.Distance(centrePosition, new Vector2(0, DrawHeight)), + Vector2.Distance(centrePosition, DrawSize)))); int requiredCircles = (int)(maxDistance / DistanceSpacing); @@ -118,7 +236,7 @@ namespace osu.Game.Rulesets.Osu.Tests AddInternal(new CircularProgress { Origin = Anchor.Centre, - Position = startPosition, + Position = centrePosition, Current = { Value = 1 }, Size = new Vector2(radius), InnerRadius = 4 * 1f / radius, @@ -129,7 +247,7 @@ namespace osu.Game.Rulesets.Osu.Tests public override Vector2 GetSnapPosition(Vector2 position) { - Vector2 direction = position - StartPosition; + Vector2 direction = position - CentrePosition; float distance = direction.Length; float radius = DistanceSpacing; @@ -140,7 +258,7 @@ namespace osu.Game.Rulesets.Osu.Tests Vector2 normalisedDirection = direction * new Vector2(1f / distance); - return StartPosition + normalisedDirection * radialCount * radius; + return CentrePosition + normalisedDirection * radialCount * radius; } } From 45835f97a177597fb236793116382f5b8c7918ea Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 11 Oct 2019 17:13:28 +0900 Subject: [PATCH 33/80] Split out grids into separate files --- .../TestSceneOsuBeatSnapGrid.cs | 80 +------------------ osu.Game.Rulesets.Osu/Edit/OsuBeatSnapGrid.cs | 33 ++++++++ .../Components/CircularBeatSnapGrid.cs | 63 +++++++++++++++ 3 files changed, 97 insertions(+), 79 deletions(-) create mode 100644 osu.Game.Rulesets.Osu/Edit/OsuBeatSnapGrid.cs create mode 100644 osu.Game/Screens/Edit/Compose/Components/CircularBeatSnapGrid.cs diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuBeatSnapGrid.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuBeatSnapGrid.cs index 7baa2f0d72..7399f12372 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuBeatSnapGrid.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuBeatSnapGrid.cs @@ -7,16 +7,13 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; using osu.Framework.MathUtils; -using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; -using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Osu.Beatmaps; +using osu.Game.Rulesets.Osu.Edit; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Screens.Edit; -using osu.Game.Screens.Edit.Compose.Components; using osu.Game.Tests.Visual; using osuTK; using osuTK.Graphics; @@ -209,80 +206,5 @@ namespace osu.Game.Rulesets.Osu.Tests { } } - - private abstract class CircularBeatSnapGrid : BeatSnapGrid - { - protected CircularBeatSnapGrid(HitObject hitObject, Vector2 centrePosition) - : base(hitObject, centrePosition) - { - } - - protected override void CreateContent(Vector2 centrePosition) - { - float maxDistance = Math.Max( - Vector2.Distance(centrePosition, Vector2.Zero), - Math.Max( - Vector2.Distance(centrePosition, new Vector2(DrawWidth, 0)), - Math.Max( - Vector2.Distance(centrePosition, new Vector2(0, DrawHeight)), - Vector2.Distance(centrePosition, DrawSize)))); - - int requiredCircles = (int)(maxDistance / DistanceSpacing); - - for (int i = 0; i < requiredCircles; i++) - { - float radius = (i + 1) * DistanceSpacing * 2; - - AddInternal(new CircularProgress - { - Origin = Anchor.Centre, - Position = centrePosition, - Current = { Value = 1 }, - Size = new Vector2(radius), - InnerRadius = 4 * 1f / radius, - Colour = GetColourForBeatIndex(i) - }); - } - } - - public override Vector2 GetSnapPosition(Vector2 position) - { - Vector2 direction = position - CentrePosition; - float distance = direction.Length; - - float radius = DistanceSpacing; - int radialCount = Math.Max(1, (int)Math.Round(distance / radius)); - - if (radialCount <= 0) - return position; - - Vector2 normalisedDirection = direction * new Vector2(1f / distance); - - return CentrePosition + normalisedDirection * radialCount * radius; - } - } - - private class OsuBeatSnapGrid : CircularBeatSnapGrid - { - /// - /// Scoring distance with a speed-adjusted beat length of 1 second. - /// - private const float base_scoring_distance = 100; - - public OsuBeatSnapGrid(OsuHitObject hitObject) - : base(hitObject, hitObject.StackedEndPosition) - { - } - - protected override float GetVelocity(double time, ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) - { - TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(time); - DifficultyControlPoint difficultyPoint = controlPointInfo.DifficultyPointAt(time); - - double scoringDistance = base_scoring_distance * difficulty.SliderMultiplier * difficultyPoint.SpeedMultiplier; - - return (float)(scoringDistance / timingPoint.BeatLength); - } - } } } diff --git a/osu.Game.Rulesets.Osu/Edit/OsuBeatSnapGrid.cs b/osu.Game.Rulesets.Osu/Edit/OsuBeatSnapGrid.cs new file mode 100644 index 0000000000..d453e3d062 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Edit/OsuBeatSnapGrid.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. + +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Screens.Edit.Compose.Components; + +namespace osu.Game.Rulesets.Osu.Edit +{ + public class OsuBeatSnapGrid : CircularBeatSnapGrid + { + /// + /// Scoring distance with a speed-adjusted beat length of 1 second. + /// + private const float base_scoring_distance = 100; + + public OsuBeatSnapGrid(OsuHitObject hitObject) + : base(hitObject, hitObject.StackedEndPosition) + { + } + + protected override float GetVelocity(double time, ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) + { + TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(time); + DifficultyControlPoint difficultyPoint = controlPointInfo.DifficultyPointAt(time); + + double scoringDistance = base_scoring_distance * difficulty.SliderMultiplier * difficultyPoint.SpeedMultiplier; + + return (float)(scoringDistance / timingPoint.BeatLength); + } + } +} diff --git a/osu.Game/Screens/Edit/Compose/Components/CircularBeatSnapGrid.cs b/osu.Game/Screens/Edit/Compose/Components/CircularBeatSnapGrid.cs new file mode 100644 index 0000000000..8492771808 --- /dev/null +++ b/osu.Game/Screens/Edit/Compose/Components/CircularBeatSnapGrid.cs @@ -0,0 +1,63 @@ +// 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; +using osu.Framework.Graphics.UserInterface; +using osu.Game.Rulesets.Objects; +using osuTK; + +namespace osu.Game.Screens.Edit.Compose.Components +{ + public abstract class CircularBeatSnapGrid : BeatSnapGrid + { + protected CircularBeatSnapGrid(HitObject hitObject, Vector2 centrePosition) + : base(hitObject, centrePosition) + { + } + + protected override void CreateContent(Vector2 centrePosition) + { + float maxDistance = Math.Max( + Vector2.Distance(centrePosition, Vector2.Zero), + Math.Max( + Vector2.Distance(centrePosition, new Vector2(DrawWidth, 0)), + Math.Max( + Vector2.Distance(centrePosition, new Vector2(0, DrawHeight)), + Vector2.Distance(centrePosition, DrawSize)))); + + int requiredCircles = (int)(maxDistance / DistanceSpacing); + + for (int i = 0; i < requiredCircles; i++) + { + float radius = (i + 1) * DistanceSpacing * 2; + + AddInternal(new CircularProgress + { + Origin = Anchor.Centre, + Position = centrePosition, + Current = { Value = 1 }, + Size = new Vector2(radius), + InnerRadius = 4 * 1f / radius, + Colour = GetColourForBeatIndex(i) + }); + } + } + + public override Vector2 GetSnapPosition(Vector2 position) + { + Vector2 direction = position - CentrePosition; + float distance = direction.Length; + + float radius = DistanceSpacing; + int radialCount = Math.Max(1, (int)Math.Round(distance / radius)); + + if (radialCount <= 0) + return position; + + Vector2 normalisedDirection = direction * new Vector2(1f / distance); + + return CentrePosition + normalisedDirection * radialCount * radius; + } + } +} From 4d971e49ff050685a4498cc31b941fd426f41ef1 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 13 Oct 2019 11:50:27 +0300 Subject: [PATCH 34/80] Colours update --- osu.Game/Overlays/Comments/CommentsContainer.cs | 2 +- osu.Game/Overlays/Comments/DrawableComment.cs | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index 265793226e..b66374cb69 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -113,7 +113,7 @@ namespace osu.Game.Overlays.Comments [BackgroundDependencyLoader] private void load() { - background.Colour = colours.Gray3; + background.Colour = colours.Gray2; } } } diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index fd7f874304..4617f6f86e 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -13,7 +13,6 @@ using osu.Game.Utils; using osu.Framework.Graphics.Cursor; using osu.Framework.Bindables; using osu.Framework.Graphics.Shapes; -using osuTK.Graphics; using System.Linq; namespace osu.Game.Overlays.Comments @@ -134,6 +133,7 @@ namespace osu.Game.Overlays.Comments AutoSizeAxes = Axes.Both, Direction = FillDirection.Horizontal, Spacing = new Vector2(10, 0), + Colour = OsuColour.Gray(0.7f), Children = new Drawable[] { new SpriteText @@ -262,6 +262,7 @@ namespace osu.Game.Overlays.Comments Child = icon = new SpriteIcon { Size = new Vector2(12), + Colour = OsuColour.Gray(0.7f) }; } @@ -340,7 +341,7 @@ namespace osu.Game.Overlays.Comments new Box { RelativeSizeAxes = Axes.Both, - Colour = Color4.Black + Colour = OsuColour.Gray(0.05f) }, new SpriteText { From 795ce8146895f435744a41e929a4621d0a212f16 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 13 Oct 2019 12:10:01 +0300 Subject: [PATCH 35/80] Use async loading for comment pages --- .../Overlays/Comments/CommentsContainer.cs | 42 +++++++++++++------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index b66374cb69..3b997540c4 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -10,6 +10,7 @@ using osu.Framework.Bindables; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Game.Online.API.Requests.Responses; +using System.Threading; namespace osu.Game.Overlays.Comments { @@ -28,6 +29,7 @@ namespace osu.Game.Overlays.Comments private OsuColour colours { get; set; } private GetCommentsRequest request; + private CancellationTokenSource loadCancellation; private readonly Box background; private readonly FillFlowContainer content; @@ -79,7 +81,7 @@ namespace osu.Game.Overlays.Comments private void getComments() { request?.Cancel(); - content.Clear(); + loadCancellation?.Cancel(); request = new GetCommentsRequest(type, id, Sort.Value); request.Success += onSuccess; api.Queue(request); @@ -87,27 +89,43 @@ namespace osu.Game.Overlays.Comments private void onSuccess(APICommentsController response) { + loadCancellation = new CancellationTokenSource(); + + FillFlowContainer page = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + }; + foreach (var c in response.Comments) { if (c.IsTopLevel) - content.Add(new DrawableComment(c) + page.Add(new DrawableComment(c) { ShowDeleted = { BindTarget = ShowDeleted } }); } - int deletedComments = 0; - - response.Comments.ForEach(comment => + LoadComponentAsync(page, loaded => { - if (comment.IsDeleted && comment.IsTopLevel) - deletedComments++; - }); + content.Clear(); - content.Add(new DeletedChildsPlaceholder(deletedComments) - { - ShowDeleted = { BindTarget = ShowDeleted } - }); + content.Add(loaded); + + int deletedComments = 0; + + response.Comments.ForEach(comment => + { + if (comment.IsDeleted && comment.IsTopLevel) + deletedComments++; + }); + + content.Add(new DeletedChildsPlaceholder(deletedComments) + { + ShowDeleted = { BindTarget = ShowDeleted } + }); + }, loadCancellation.Token); } [BackgroundDependencyLoader] From 60954f969d77f6350b0f63903cf2f5696046c248 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 13 Oct 2019 12:38:50 +0300 Subject: [PATCH 36/80] DeletedChildsPlaceholder refactor --- .../Overlays/Comments/CommentsContainer.cs | 33 ++++++++++++++++--- .../Comments/DeletedChildsPlaceholder.cs | 30 ++++++++++++----- osu.Game/Overlays/Comments/DrawableComment.cs | 5 ++- 3 files changed, 55 insertions(+), 13 deletions(-) diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index 3b997540c4..1fca9ca5e5 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -33,6 +33,8 @@ namespace osu.Game.Overlays.Comments private readonly Box background; private readonly FillFlowContainer content; + private readonly FillFlowContainer footer; + private readonly DeletedChildsPlaceholder deletedChildsPlaceholder; public CommentsContainer(CommentableType type, long id) { @@ -64,6 +66,32 @@ namespace osu.Game.Overlays.Comments RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Direction = FillDirection.Vertical, + }, + new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = OsuColour.Gray(0.2f) + }, + footer = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Children = new Drawable[] + { + deletedChildsPlaceholder = new DeletedChildsPlaceholder + { + ShowDeleted = { BindTarget = ShowDeleted } + } + } + } + } } } } @@ -121,10 +149,7 @@ namespace osu.Game.Overlays.Comments deletedComments++; }); - content.Add(new DeletedChildsPlaceholder(deletedComments) - { - ShowDeleted = { BindTarget = ShowDeleted } - }); + deletedChildsPlaceholder.DeletedCount.Value = deletedComments; }, loadCancellation.Token); } diff --git a/osu.Game/Overlays/Comments/DeletedChildsPlaceholder.cs b/osu.Game/Overlays/Comments/DeletedChildsPlaceholder.cs index 7aae42908e..b5dcf433f1 100644 --- a/osu.Game/Overlays/Comments/DeletedChildsPlaceholder.cs +++ b/osu.Game/Overlays/Comments/DeletedChildsPlaceholder.cs @@ -17,18 +17,18 @@ namespace osu.Game.Overlays.Comments private const int margin = 10; public readonly BindableBool ShowDeleted = new BindableBool(); + public readonly BindableInt DeletedCount = new BindableInt(); - private readonly bool canBeVisible; + private bool canBeShown; - public DeletedChildsPlaceholder(int count) + private readonly SpriteText countText; + + public DeletedChildsPlaceholder() { - canBeVisible = count != 0; - AutoSizeAxes = Axes.Both; Direction = FillDirection.Horizontal; Spacing = new Vector2(3, 0); Margin = new MarginPadding { Vertical = margin, Left = deleted_placeholder_margin }; - Alpha = 0; Children = new Drawable[] { new SpriteIcon @@ -36,24 +36,38 @@ namespace osu.Game.Overlays.Comments Icon = FontAwesome.Solid.Trash, Size = new Vector2(14), }, - new SpriteText + countText = new SpriteText { Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true), - Text = $@"{count} deleted comment{(count.ToString().ToCharArray().Last() == '1' ? "" : "s")}" } }; } protected override void LoadComplete() { + DeletedCount.BindValueChanged(onCountChanged, true); ShowDeleted.BindValueChanged(onShowDeletedChanged, true); base.LoadComplete(); } private void onShowDeletedChanged(ValueChangedEvent showDeleted) { - if (canBeVisible) + if (canBeShown) this.FadeTo(showDeleted.NewValue ? 0 : 1); } + + private void onCountChanged(ValueChangedEvent count) + { + canBeShown = count.NewValue != 0; + + if (!canBeShown) + { + Hide(); + return; + } + + countText.Text = $@"{count.NewValue} deleted comment{(count.NewValue.ToString().ToCharArray().Last() == '1' ? "" : "s")}"; + Show(); + } } } diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 4617f6f86e..8c356a6156 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -32,6 +32,7 @@ namespace osu.Game.Overlays.Comments private readonly FillFlowContainer childCommentsVisibilityContainer; private readonly Comment comment; + private readonly DeletedChildsPlaceholder deletedChildsPlaceholder; public DrawableComment(Comment comment) { @@ -168,7 +169,7 @@ namespace osu.Game.Overlays.Comments AutoSizeAxes = Axes.Y, Direction = FillDirection.Vertical }, - new DeletedChildsPlaceholder(comment.GetDeletedChildsCount()) + deletedChildsPlaceholder = new DeletedChildsPlaceholder { ShowDeleted = { BindTarget = ShowDeleted } } @@ -177,6 +178,8 @@ namespace osu.Game.Overlays.Comments } }; + deletedChildsPlaceholder.DeletedCount.Value = comment.GetDeletedChildsCount(); + if (comment.UserId == null) username.AddText(comment.LegacyName); else From a44cc2e70baf13f3f90c6635d23bb2645b06841f Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 13 Oct 2019 14:43:30 +0300 Subject: [PATCH 37/80] Implement CommentsShowMoreButton --- .../Online/TestSceneCommentsContainer.cs | 6 ++ .../Visual/Online/TestSceneShowMoreButton.cs | 5 +- .../UserInterface}/ShowMoreButton.cs | 67 ++++++++++--------- .../Overlays/Comments/CommentsContainer.cs | 54 ++++++++++++--- .../Comments/CommentsShowMoreButton.cs | 32 +++++++++ .../Comments/DeletedChildsPlaceholder.cs | 8 ++- .../Profile/Sections/PaginatedContainer.cs | 4 +- .../Profile/Sections/ProfileShowMoreButton.cs | 20 ++++++ 8 files changed, 151 insertions(+), 45 deletions(-) rename osu.Game/{Overlays/Profile/Sections => Graphics/UserInterface}/ShowMoreButton.cs (77%) create mode 100644 osu.Game/Overlays/Comments/CommentsShowMoreButton.cs create mode 100644 osu.Game/Overlays/Profile/Sections/ProfileShowMoreButton.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs index 342ba487f0..a283663a4a 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs @@ -47,6 +47,12 @@ namespace osu.Game.Tests.Visual.Online scrollFlow.Clear(); scrollFlow.Add(new CommentsContainer(CommentableType.Beatmapset, 24313)); }); + + AddStep("lazer build comments", () => + { + scrollFlow.Clear(); + scrollFlow.Add(new CommentsContainer(CommentableType.Build, 4772)); + }); } } } diff --git a/osu.Game.Tests/Visual/Online/TestSceneShowMoreButton.cs b/osu.Game.Tests/Visual/Online/TestSceneShowMoreButton.cs index bccb263600..8d4955abf0 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneShowMoreButton.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneShowMoreButton.cs @@ -5,6 +5,7 @@ using osu.Game.Overlays.Profile.Sections; using System; using System.Collections.Generic; using osu.Framework.Graphics; +using osu.Game.Graphics.UserInterface; namespace osu.Game.Tests.Visual.Online { @@ -17,11 +18,11 @@ namespace osu.Game.Tests.Visual.Online public TestSceneShowMoreButton() { - ShowMoreButton button = null; + ProfileShowMoreButton button = null; int fireCount = 0; - Add(button = new ShowMoreButton + Add(button = new ProfileShowMoreButton { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game/Overlays/Profile/Sections/ShowMoreButton.cs b/osu.Game/Graphics/UserInterface/ShowMoreButton.cs similarity index 77% rename from osu.Game/Overlays/Profile/Sections/ShowMoreButton.cs rename to osu.Game/Graphics/UserInterface/ShowMoreButton.cs index cf4e1c0dde..627ad995e8 100644 --- a/osu.Game/Overlays/Profile/Sections/ShowMoreButton.cs +++ b/osu.Game/Graphics/UserInterface/ShowMoreButton.cs @@ -1,30 +1,36 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// 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.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Events; -using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; -using osu.Game.Graphics.UserInterface; using osuTK; +using osuTK.Graphics; using System.Collections.Generic; -namespace osu.Game.Overlays.Profile.Sections +namespace osu.Game.Graphics.UserInterface { public class ShowMoreButton : OsuHoverContainer { private const float fade_duration = 200; - private readonly Box background; - private readonly LoadingAnimation loading; - private readonly FillFlowContainer content; + private Color4 chevronIconColour; - protected override IEnumerable EffectTargets => new[] { background }; + public Color4 ChevronIconColour + { + get => chevronIconColour; + set { chevronIconColour = leftChevron.AccentColour = rightChevron.AccentColour = value; } + } + + public string Text + { + get => text.Text; + set { text.Text = value; } + } private bool isLoading; @@ -33,26 +39,32 @@ namespace osu.Game.Overlays.Profile.Sections get => isLoading; set { - if (isLoading == value) - return; - isLoading = value; Enabled.Value = !isLoading; if (value) { - loading.FadeIn(fade_duration, Easing.OutQuint); + loading.Show(); content.FadeOut(fade_duration, Easing.OutQuint); } else { - loading.FadeOut(fade_duration, Easing.OutQuint); + loading.Hide(); content.FadeIn(fade_duration, Easing.OutQuint); } } } + private readonly Box background; + private readonly LoadingAnimation loading; + private readonly FillFlowContainer content; + private readonly ChevronIcon leftChevron; + private readonly ChevronIcon rightChevron; + private readonly SpriteText text; + + protected override IEnumerable EffectTargets => new[] { background }; + public ShowMoreButton() { AutoSizeAxes = Axes.Both; @@ -77,15 +89,15 @@ namespace osu.Game.Overlays.Profile.Sections Spacing = new Vector2(7), Children = new Drawable[] { - new ChevronIcon(), - new OsuSpriteText + leftChevron = new ChevronIcon(), + text = new OsuSpriteText { Anchor = Anchor.Centre, Origin = Anchor.Centre, Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold), Text = "show more".ToUpper(), }, - new ChevronIcon(), + rightChevron = new ChevronIcon(), } }, loading = new LoadingAnimation @@ -99,13 +111,6 @@ namespace osu.Game.Overlays.Profile.Sections }; } - [BackgroundDependencyLoader] - private void load(OsuColour colors) - { - IdleColour = colors.GreySeafoamDark; - HoverColour = colors.GreySeafoam; - } - protected override bool OnClick(ClickEvent e) { if (!Enabled.Value) @@ -126,6 +131,14 @@ namespace osu.Game.Overlays.Profile.Sections { private const int icon_size = 8; + private Color4 accentColour; + + public Color4 AccentColour + { + get => accentColour; + set { accentColour = Colour = value; } + } + public ChevronIcon() { Anchor = Anchor.Centre; @@ -133,12 +146,6 @@ namespace osu.Game.Overlays.Profile.Sections Size = new Vector2(icon_size); Icon = FontAwesome.Solid.ChevronDown; } - - [BackgroundDependencyLoader] - private void load(OsuColour colors) - { - Colour = colors.Yellow; - } } } } diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index 1fca9ca5e5..1111313d7f 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -16,6 +16,8 @@ namespace osu.Game.Overlays.Comments { public class CommentsContainer : CompositeDrawable { + private const int more_button_margin = 5; + private readonly CommentableType type; private readonly long id; @@ -30,11 +32,13 @@ namespace osu.Game.Overlays.Comments private GetCommentsRequest request; private CancellationTokenSource loadCancellation; + private int currentPage; + private int loadedTopLevelComments; private readonly Box background; private readonly FillFlowContainer content; - private readonly FillFlowContainer footer; private readonly DeletedChildsPlaceholder deletedChildsPlaceholder; + private readonly CommentsShowMoreButton moreButton; public CommentsContainer(CommentableType type, long id) { @@ -78,7 +82,7 @@ namespace osu.Game.Overlays.Comments RelativeSizeAxes = Axes.Both, Colour = OsuColour.Gray(0.2f) }, - footer = new FillFlowContainer + new FillFlowContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, @@ -88,6 +92,18 @@ namespace osu.Game.Overlays.Comments deletedChildsPlaceholder = new DeletedChildsPlaceholder { ShowDeleted = { BindTarget = ShowDeleted } + }, + new Container + { + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, + Child = moreButton = new CommentsShowMoreButton + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Margin = new MarginPadding(more_button_margin), + Action = () => getComments(false), + } } } } @@ -106,16 +122,25 @@ namespace osu.Game.Overlays.Comments private void onSortChanged(ValueChangedEvent sort) => getComments(); - private void getComments() + private void getComments(bool initial = true) { + if (initial) + { + currentPage = 1; + loadedTopLevelComments = 0; + deletedChildsPlaceholder.DeletedCount.Value = 0; + moreButton.IsLoading = true; + content.Clear(); + } + request?.Cancel(); loadCancellation?.Cancel(); - request = new GetCommentsRequest(type, id, Sort.Value); - request.Success += onSuccess; + request = new GetCommentsRequest(type, id, Sort.Value, currentPage++); + request.Success += response => onSuccess(response, initial); api.Queue(request); } - private void onSuccess(APICommentsController response) + private void onSuccess(APICommentsController response, bool initial) { loadCancellation = new CancellationTokenSource(); @@ -137,8 +162,6 @@ namespace osu.Game.Overlays.Comments LoadComponentAsync(page, loaded => { - content.Clear(); - content.Add(loaded); int deletedComments = 0; @@ -149,7 +172,20 @@ namespace osu.Game.Overlays.Comments deletedComments++; }); - deletedChildsPlaceholder.DeletedCount.Value = deletedComments; + deletedChildsPlaceholder.DeletedCount.Value = initial ? deletedComments : deletedChildsPlaceholder.DeletedCount.Value + deletedComments; + + if (response.HasMore) + { + response.Comments.ForEach(comment => + { + if (comment.IsTopLevel) + loadedTopLevelComments++; + }); + moreButton.Current.Value = response.TopLevelCount - loadedTopLevelComments; + moreButton.IsLoading = false; + } + moreButton.FadeTo(response.HasMore ? 1 : 0); + }, loadCancellation.Token); } diff --git a/osu.Game/Overlays/Comments/CommentsShowMoreButton.cs b/osu.Game/Overlays/Comments/CommentsShowMoreButton.cs new file mode 100644 index 0000000000..b0174e7b1a --- /dev/null +++ b/osu.Game/Overlays/Comments/CommentsShowMoreButton.cs @@ -0,0 +1,32 @@ +// 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.Bindables; +using osu.Game.Graphics; +using osu.Game.Graphics.UserInterface; + +namespace osu.Game.Overlays.Comments +{ + public class CommentsShowMoreButton : ShowMoreButton + { + public readonly BindableInt Current = new BindableInt(); + + public CommentsShowMoreButton() + { + IdleColour = OsuColour.Gray(0.3f); + HoverColour = OsuColour.Gray(0.4f); + ChevronIconColour = OsuColour.Gray(0.5f); + } + + protected override void LoadComplete() + { + Current.BindValueChanged(onCurrentChanged, true); + base.LoadComplete(); + } + + private void onCurrentChanged(ValueChangedEvent count) + { + Text = $@"Show More ({count.NewValue})".ToUpper(); + } + } +} diff --git a/osu.Game/Overlays/Comments/DeletedChildsPlaceholder.cs b/osu.Game/Overlays/Comments/DeletedChildsPlaceholder.cs index b5dcf433f1..d626c13afd 100644 --- a/osu.Game/Overlays/Comments/DeletedChildsPlaceholder.cs +++ b/osu.Game/Overlays/Comments/DeletedChildsPlaceholder.cs @@ -7,7 +7,6 @@ using osu.Game.Graphics; using osu.Framework.Graphics.Sprites; using osuTK; using osu.Framework.Bindables; -using System.Linq; namespace osu.Game.Overlays.Comments { @@ -66,7 +65,12 @@ namespace osu.Game.Overlays.Comments return; } - countText.Text = $@"{count.NewValue} deleted comment{(count.NewValue.ToString().ToCharArray().Last() == '1' ? "" : "s")}"; + string str = $@"{count.NewValue} deleted comment"; + + if (!(count.NewValue.ToString().EndsWith("1") && !count.NewValue.ToString().EndsWith("11"))) + str += "s"; + + countText.Text = str; Show(); } } diff --git a/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs b/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs index bb221bd43a..dc1a847b14 100644 --- a/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs +++ b/osu.Game/Overlays/Profile/Sections/PaginatedContainer.cs @@ -19,7 +19,7 @@ namespace osu.Game.Overlays.Profile.Sections { public abstract class PaginatedContainer : FillFlowContainer { - private readonly ShowMoreButton moreButton; + private readonly ProfileShowMoreButton moreButton; private readonly OsuSpriteText missingText; private APIRequest> retrievalRequest; private CancellationTokenSource loadCancellation; @@ -56,7 +56,7 @@ namespace osu.Game.Overlays.Profile.Sections RelativeSizeAxes = Axes.X, Spacing = new Vector2(0, 2), }, - moreButton = new ShowMoreButton + moreButton = new ProfileShowMoreButton { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, diff --git a/osu.Game/Overlays/Profile/Sections/ProfileShowMoreButton.cs b/osu.Game/Overlays/Profile/Sections/ProfileShowMoreButton.cs new file mode 100644 index 0000000000..28486cc743 --- /dev/null +++ b/osu.Game/Overlays/Profile/Sections/ProfileShowMoreButton.cs @@ -0,0 +1,20 @@ +// 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.Game.Graphics; +using osu.Game.Graphics.UserInterface; + +namespace osu.Game.Overlays.Profile.Sections +{ + public class ProfileShowMoreButton : ShowMoreButton + { + [BackgroundDependencyLoader] + private void load(OsuColour colors) + { + IdleColour = colors.GreySeafoamDark; + HoverColour = colors.GreySeafoam; + ChevronIconColour = colors.Yellow; + } + } +} From 328b4d6863a3002b396b65bbcdde32d0a95568ff Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 13 Oct 2019 16:22:10 +0300 Subject: [PATCH 38/80] Cancel request on dispose --- osu.Game/Overlays/Comments/CommentsContainer.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index 1111313d7f..4c27c498c3 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -194,5 +194,12 @@ namespace osu.Game.Overlays.Comments { background.Colour = colours.Gray2; } + + protected override void Dispose(bool isDisposing) + { + request?.Cancel(); + loadCancellation?.Cancel(); + base.Dispose(isDisposing); + } } } From 9372526d3af9f42da19442ed21baca4c692a358d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 14 Oct 2019 20:08:05 +0900 Subject: [PATCH 39/80] Don't automatically return to gameplay from map pool if no picks are made Closes #6491. --- osu.Game.Tournament/Screens/MapPool/MapPoolScreen.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tournament/Screens/MapPool/MapPoolScreen.cs b/osu.Game.Tournament/Screens/MapPool/MapPoolScreen.cs index d32c0d6156..ec55bb5b54 100644 --- a/osu.Game.Tournament/Screens/MapPool/MapPoolScreen.cs +++ b/osu.Game.Tournament/Screens/MapPool/MapPoolScreen.cs @@ -196,7 +196,7 @@ namespace osu.Game.Tournament.Screens.MapPool setNextMode(); - if (pickType == ChoiceType.Pick) + if (pickType == ChoiceType.Pick && currentMatch.Value.PicksBans.Any(i => i.Type == ChoiceType.Pick)) { scheduledChange?.Cancel(); scheduledChange = Scheduler.AddDelayed(() => { sceneManager?.SetScreen(typeof(GameplayScreen)); }, 10000); From 7cd3f5656d4c7b482fb995ce9ce4489db0a20d3d Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 14 Oct 2019 16:43:43 +0300 Subject: [PATCH 40/80] Cleanups --- .../Online/TestSceneCommentsContainer.cs | 2 +- .../Online/API/Requests/Responses/Comment.cs | 6 ++++- .../Overlays/Comments/CommentsContainer.cs | 4 +-- .../Comments/DeletedChildsPlaceholder.cs | 5 +--- osu.Game/Overlays/Comments/DrawableComment.cs | 27 +++++++------------ .../Overlays/Comments/ShowChildsButton.cs | 2 +- 6 files changed, 18 insertions(+), 28 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs index a283663a4a..5e4aa27fae 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs @@ -20,7 +20,7 @@ namespace osu.Game.Tests.Visual.Online typeof(CommentsHeader), typeof(DrawableComment), typeof(HeaderButton), - typeof(SortSelector), + typeof(SortTabControl), typeof(ShowChildsButton), typeof(DeletedChildsPlaceholder) }; diff --git a/osu.Game/Online/API/Requests/Responses/Comment.cs b/osu.Game/Online/API/Requests/Responses/Comment.cs index 2334c86519..d0f7e4fac5 100644 --- a/osu.Game/Online/API/Requests/Responses/Comment.cs +++ b/osu.Game/Online/API/Requests/Responses/Comment.cs @@ -6,6 +6,7 @@ using osu.Game.Users; using System; using System.Collections.Generic; using System.Linq; +using System.Text.RegularExpressions; namespace osu.Game.Online.API.Requests.Responses { @@ -90,7 +91,10 @@ namespace osu.Game.Online.API.Requests.Responses public string GetMessage() { - return IsDeleted ? @"deleted" : MessageHTML.Replace("
", "").Replace("

", "").Replace("
", "").Replace("

", "").Replace("
", "").Replace(""", "\""); + if (IsDeleted) + return @"deleted"; + + return Regex.Replace(MessageHTML, @"\<.*?\>", ""); } public int GetDeletedChildsCount() diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index 4c27c498c3..8680234d4b 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -16,8 +16,6 @@ namespace osu.Game.Overlays.Comments { public class CommentsContainer : CompositeDrawable { - private const int more_button_margin = 5; - private readonly CommentableType type; private readonly long id; @@ -101,7 +99,7 @@ namespace osu.Game.Overlays.Comments { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Margin = new MarginPadding(more_button_margin), + Margin = new MarginPadding(5), Action = () => getComments(false), } } diff --git a/osu.Game/Overlays/Comments/DeletedChildsPlaceholder.cs b/osu.Game/Overlays/Comments/DeletedChildsPlaceholder.cs index d626c13afd..058f8cc750 100644 --- a/osu.Game/Overlays/Comments/DeletedChildsPlaceholder.cs +++ b/osu.Game/Overlays/Comments/DeletedChildsPlaceholder.cs @@ -12,9 +12,6 @@ namespace osu.Game.Overlays.Comments { public class DeletedChildsPlaceholder : FillFlowContainer { - private const int deleted_placeholder_margin = 80; - private const int margin = 10; - public readonly BindableBool ShowDeleted = new BindableBool(); public readonly BindableInt DeletedCount = new BindableInt(); @@ -27,7 +24,7 @@ namespace osu.Game.Overlays.Comments AutoSizeAxes = Axes.Both; Direction = FillDirection.Horizontal; Spacing = new Vector2(3, 0); - Margin = new MarginPadding { Vertical = margin, Left = deleted_placeholder_margin }; + Margin = new MarginPadding { Vertical = 10, Left = 80 }; Children = new Drawable[] { new SpriteIcon diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 8c356a6156..756eb8caf9 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -21,18 +21,14 @@ namespace osu.Game.Overlays.Comments { private const int avatar_size = 40; private const int margin = 10; - private const int child_margin = 20; - private const int chevron_margin = 30; - private const int message_padding = 40; - private const float separator_height = 1.5f; public readonly BindableBool ShowDeleted = new BindableBool(); private readonly BindableBool childExpanded = new BindableBool(true); private readonly FillFlowContainer childCommentsVisibilityContainer; - private readonly Comment comment; private readonly DeletedChildsPlaceholder deletedChildsPlaceholder; + private readonly Comment comment; public DrawableComment(Comment comment) { @@ -127,7 +123,7 @@ namespace osu.Game.Overlays.Comments { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Padding = new MarginPadding { Right = message_padding } + Padding = new MarginPadding { Right = 40 } }, info = new FillFlowContainer { @@ -164,7 +160,7 @@ namespace osu.Game.Overlays.Comments { childCommentsContainer = new FillFlowContainer { - Margin = new MarginPadding { Left = child_margin }, + Margin = new MarginPadding { Left = 20 }, RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Direction = FillDirection.Vertical @@ -180,10 +176,10 @@ namespace osu.Game.Overlays.Comments deletedChildsPlaceholder.DeletedCount.Value = comment.GetDeletedChildsCount(); - if (comment.UserId == null) - username.AddText(comment.LegacyName); - else + if (comment.UserId.HasValue) username.AddUserLink(comment.User); + else + username.AddText(comment.LegacyName); if (comment.EditedAt.HasValue) { @@ -209,7 +205,7 @@ namespace osu.Game.Overlays.Comments AddInternal(new Container { RelativeSizeAxes = Axes.X, - Height = separator_height, + Height = 1.5f, Anchor = Anchor.BottomCentre, Origin = Anchor.BottomCentre, Child = new Box @@ -225,7 +221,7 @@ namespace osu.Game.Overlays.Comments { Anchor = Anchor.TopRight, Origin = Anchor.TopRight, - Margin = new MarginPadding { Right = chevron_margin, Top = margin }, + Margin = new MarginPadding { Right = 30, Top = margin }, Expanded = { BindTarget = childExpanded } }); } @@ -240,15 +236,10 @@ namespace osu.Game.Overlays.Comments protected override void LoadComplete() { ShowDeleted.BindValueChanged(onShowDeletedChanged, true); - childExpanded.BindValueChanged(onChildExpandedChanged, true); + childExpanded.BindValueChanged(expanded => childCommentsVisibilityContainer.FadeTo(expanded.NewValue ? 1 : 0), true); base.LoadComplete(); } - private void onChildExpandedChanged(ValueChangedEvent expanded) - { - childCommentsVisibilityContainer.FadeTo(expanded.NewValue ? 1 : 0); - } - private void onShowDeletedChanged(ValueChangedEvent show) { if (comment.IsDeleted) diff --git a/osu.Game/Overlays/Comments/ShowChildsButton.cs b/osu.Game/Overlays/Comments/ShowChildsButton.cs index 81280a71b5..b29e316e80 100644 --- a/osu.Game/Overlays/Comments/ShowChildsButton.cs +++ b/osu.Game/Overlays/Comments/ShowChildsButton.cs @@ -28,7 +28,7 @@ namespace osu.Game.Overlays.Comments protected override bool OnClick(ClickEvent e) { Expanded.Value = !Expanded.Value; - return base.OnClick(e); + return true; } } } From a81d5cd81968fc113f924552c87f728da17d0ef6 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 14 Oct 2019 16:56:07 +0300 Subject: [PATCH 41/80] Handle links in message --- osu.Game/Overlays/Comments/DrawableComment.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 756eb8caf9..c492e48acf 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -14,6 +14,7 @@ using osu.Framework.Graphics.Cursor; using osu.Framework.Bindables; using osu.Framework.Graphics.Shapes; using System.Linq; +using osu.Game.Online.Chat; namespace osu.Game.Overlays.Comments { @@ -35,7 +36,7 @@ namespace osu.Game.Overlays.Comments LinkFlowContainer username; FillFlowContainer childCommentsContainer; FillFlowContainer info; - TextFlowContainer message; + LinkFlowContainer message; GridContainer content; VotePill votePill; @@ -119,7 +120,7 @@ namespace osu.Game.Overlays.Comments } } }, - message = new TextFlowContainer(s => s.Font = OsuFont.GetFont(size: 14)) + message = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 14)) { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, @@ -193,7 +194,10 @@ namespace osu.Game.Overlays.Comments } if (!comment.IsDeleted) - message.Text = comment.GetMessage(); + { + var formattedSource = MessageFormatter.FormatText(comment.GetMessage()); + message.AddLinks(formattedSource.Text, formattedSource.Links); + } else { content.FadeColour(OsuColour.Gray(0.5f)); From a4ffd4798dfc76b516f4da2cb8b2f8f58a5f858f Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 14 Oct 2019 17:02:48 +0300 Subject: [PATCH 42/80] Fix escaped html strings not being unescaped --- osu.Game/Online/API/Requests/Responses/Comment.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Online/API/Requests/Responses/Comment.cs b/osu.Game/Online/API/Requests/Responses/Comment.cs index d0f7e4fac5..5e67bff859 100644 --- a/osu.Game/Online/API/Requests/Responses/Comment.cs +++ b/osu.Game/Online/API/Requests/Responses/Comment.cs @@ -6,6 +6,7 @@ using osu.Game.Users; using System; using System.Collections.Generic; using System.Linq; +using System.Net; using System.Text.RegularExpressions; namespace osu.Game.Online.API.Requests.Responses @@ -94,7 +95,7 @@ namespace osu.Game.Online.API.Requests.Responses if (IsDeleted) return @"deleted"; - return Regex.Replace(MessageHTML, @"\<.*?\>", ""); + return WebUtility.HtmlDecode(Regex.Replace(MessageHTML, @"<(.|\n)*?>", string.Empty)); } public int GetDeletedChildsCount() From b53fb0d228ba112044285ca31272432a53938a43 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 14 Oct 2019 17:07:50 +0300 Subject: [PATCH 43/80] Remove empty line --- osu.Game/Overlays/Comments/CommentsContainer.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index 8680234d4b..a5e921e2c0 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -183,7 +183,6 @@ namespace osu.Game.Overlays.Comments moreButton.IsLoading = false; } moreButton.FadeTo(response.HasMore ? 1 : 0); - }, loadCancellation.Token); } From 139170cdc859f2689e99b0a940f8334b2b46fa19 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 14 Oct 2019 17:26:12 +0300 Subject: [PATCH 44/80] Fix incorrect padding for nested comments --- osu.Game/Overlays/Comments/DrawableComment.cs | 169 +++++++++--------- 1 file changed, 87 insertions(+), 82 deletions(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index c492e48acf..e5258ef3cc 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -51,100 +51,105 @@ namespace osu.Game.Overlays.Comments Direction = FillDirection.Vertical, Children = new Drawable[] { - content = new GridContainer + new Container { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Margin = new MarginPadding(margin), - ColumnDimensions = new[] + Padding = new MarginPadding(margin), + Child = content = new GridContainer { - new Dimension(GridSizeMode.AutoSize), - new Dimension(), - }, - RowDimensions = new[] - { - new Dimension(GridSizeMode.AutoSize) - }, - Content = new[] - { - new Drawable[] + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + ColumnDimensions = new[] { - new FillFlowContainer + new Dimension(GridSizeMode.AutoSize), + new Dimension(), + }, + RowDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize) + }, + Content = new[] + { + new Drawable[] { - AutoSizeAxes = Axes.Both, - Margin = new MarginPadding { Horizontal = margin }, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(5, 0), - Children = new Drawable[] + new FillFlowContainer { - votePill = new VotePill(comment.VotesCount) + AutoSizeAxes = Axes.Both, + Margin = new MarginPadding { Horizontal = margin }, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(5, 0), + Children = new Drawable[] { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - AlwaysPresent = true, - }, - new UpdateableAvatar(comment.User) - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Size = new Vector2(avatar_size), - Masking = true, - CornerRadius = avatar_size / 2, - }, - } - }, - new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Spacing = new Vector2(0, 3), - Children = new Drawable[] - { - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(7, 0), - Children = new Drawable[] + votePill = new VotePill(comment.VotesCount) { - username = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true)) + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + AlwaysPresent = true, + }, + new UpdateableAvatar(comment.User) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(avatar_size), + Masking = true, + CornerRadius = avatar_size / 2, + }, + } + }, + new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Spacing = new Vector2(0, 3), + Children = new Drawable[] + { + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(7, 0), + Children = new Drawable[] { - AutoSizeAxes = Axes.Both, - }, - new ParentUsername(comment), - new SpriteText - { - Alpha = comment.IsDeleted? 1 : 0, - Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true), - Text = @"deleted", + username = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true)) + { + AutoSizeAxes = Axes.Both, + }, + new ParentUsername(comment), + new SpriteText + { + Alpha = comment.IsDeleted? 1 : 0, + Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true), + Text = @"deleted", + } } - } - }, - message = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 14)) - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Padding = new MarginPadding { Right = 40 } - }, - info = new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(10, 0), - Colour = OsuColour.Gray(0.7f), - Children = new Drawable[] + }, + message = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 14)) { - new SpriteText + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Padding = new MarginPadding { Right = 40 } + }, + info = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(10, 0), + Colour = OsuColour.Gray(0.7f), + Children = new Drawable[] { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Font = OsuFont.GetFont(size: 12), - Text = HumanizerUtils.Humanize(comment.CreatedAt) - }, - new RepliesButton(comment.RepliesCount) - { - Expanded = { BindTarget = childExpanded } - }, + new SpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Font = OsuFont.GetFont(size: 12), + Text = HumanizerUtils.Humanize(comment.CreatedAt) + }, + new RepliesButton(comment.RepliesCount) + { + Expanded = { BindTarget = childExpanded } + }, + } } } } @@ -161,7 +166,7 @@ namespace osu.Game.Overlays.Comments { childCommentsContainer = new FillFlowContainer { - Margin = new MarginPadding { Left = 20 }, + Padding = new MarginPadding { Left = 20 }, RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Direction = FillDirection.Vertical From d4843285dbf091b6756b71e86599a94ffb8bbde0 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Mon, 14 Oct 2019 17:33:14 +0300 Subject: [PATCH 45/80] CI fixes --- osu.Game/Graphics/UserInterface/ShowMoreButton.cs | 6 +++--- osu.Game/Online/API/Requests/Responses/Comment.cs | 4 ++-- osu.Game/Overlays/Comments/CommentsContainer.cs | 1 + osu.Game/Overlays/Comments/DrawableComment.cs | 15 +++++---------- osu.Game/Overlays/Comments/ShowChildsButton.cs | 2 +- 5 files changed, 12 insertions(+), 16 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/ShowMoreButton.cs b/osu.Game/Graphics/UserInterface/ShowMoreButton.cs index 627ad995e8..8b2eb31d96 100644 --- a/osu.Game/Graphics/UserInterface/ShowMoreButton.cs +++ b/osu.Game/Graphics/UserInterface/ShowMoreButton.cs @@ -23,13 +23,13 @@ namespace osu.Game.Graphics.UserInterface public Color4 ChevronIconColour { get => chevronIconColour; - set { chevronIconColour = leftChevron.AccentColour = rightChevron.AccentColour = value; } + set => chevronIconColour = leftChevron.AccentColour = rightChevron.AccentColour = value; } public string Text { get => text.Text; - set { text.Text = value; } + set => text.Text = value; } private bool isLoading; @@ -136,7 +136,7 @@ namespace osu.Game.Graphics.UserInterface public Color4 AccentColour { get => accentColour; - set { accentColour = Colour = value; } + set => accentColour = Colour = value; } public ChevronIcon() diff --git a/osu.Game/Online/API/Requests/Responses/Comment.cs b/osu.Game/Online/API/Requests/Responses/Comment.cs index 5e67bff859..6243ea4fb6 100644 --- a/osu.Game/Online/API/Requests/Responses/Comment.cs +++ b/osu.Game/Online/API/Requests/Responses/Comment.cs @@ -42,7 +42,7 @@ namespace osu.Game.Online.API.Requests.Responses public string Message { get; set; } [JsonProperty(@"message_html")] - public string MessageHTML { get; set; } + public string MessageHtml { get; set; } [JsonProperty(@"replies_count")] public int RepliesCount { get; set; } @@ -95,7 +95,7 @@ namespace osu.Game.Online.API.Requests.Responses if (IsDeleted) return @"deleted"; - return WebUtility.HtmlDecode(Regex.Replace(MessageHTML, @"<(.|\n)*?>", string.Empty)); + return WebUtility.HtmlDecode(Regex.Replace(MessageHtml, @"<(.|\n)*?>", string.Empty)); } public int GetDeletedChildsCount() diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index a5e921e2c0..6c674678df 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -182,6 +182,7 @@ namespace osu.Game.Overlays.Comments moreButton.Current.Value = response.TopLevelCount - loadedTopLevelComments; moreButton.IsLoading = false; } + moreButton.FadeTo(response.HasMore ? 1 : 0); }, loadCancellation.Token); } diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index e5258ef3cc..38e45949e1 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -28,13 +28,13 @@ namespace osu.Game.Overlays.Comments private readonly BindableBool childExpanded = new BindableBool(true); private readonly FillFlowContainer childCommentsVisibilityContainer; - private readonly DeletedChildsPlaceholder deletedChildsPlaceholder; private readonly Comment comment; public DrawableComment(Comment comment) { LinkFlowContainer username; FillFlowContainer childCommentsContainer; + DeletedChildsPlaceholder deletedChildsPlaceholder; FillFlowContainer info; LinkFlowContainer message; GridContainer content; @@ -93,7 +93,7 @@ namespace osu.Game.Overlays.Comments Origin = Anchor.Centre, Size = new Vector2(avatar_size), Masking = true, - CornerRadius = avatar_size / 2, + CornerRadius = avatar_size / 2f, }, } }, @@ -118,7 +118,7 @@ namespace osu.Game.Overlays.Comments new ParentUsername(comment), new SpriteText { - Alpha = comment.IsDeleted? 1 : 0, + Alpha = comment.IsDeleted ? 1 : 0, Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true), Text = @"deleted", } @@ -299,8 +299,6 @@ namespace osu.Game.Overlays.Comments private class ParentUsername : FillFlowContainer, IHasTooltip { - private const int spacing = 3; - public string TooltipText => comment.ParentComment?.GetMessage() ?? ""; private readonly Comment comment; @@ -311,7 +309,7 @@ namespace osu.Game.Overlays.Comments AutoSizeAxes = Axes.Both; Direction = FillDirection.Horizontal; - Spacing = new Vector2(spacing, 0); + Spacing = new Vector2(3, 0); Alpha = comment.ParentId == null ? 0 : 1; Children = new Drawable[] { @@ -331,13 +329,10 @@ namespace osu.Game.Overlays.Comments private class VotePill : CircularContainer { - private const int height = 20; - private const int margin = 10; - public VotePill(int count) { AutoSizeAxes = Axes.X; - Height = height; + Height = 20; Masking = true; Children = new Drawable[] { diff --git a/osu.Game/Overlays/Comments/ShowChildsButton.cs b/osu.Game/Overlays/Comments/ShowChildsButton.cs index b29e316e80..464c0a1503 100644 --- a/osu.Game/Overlays/Comments/ShowChildsButton.cs +++ b/osu.Game/Overlays/Comments/ShowChildsButton.cs @@ -12,7 +12,7 @@ namespace osu.Game.Overlays.Comments { public readonly BindableBool Expanded = new BindableBool(true); - public ShowChildsButton() + protected ShowChildsButton() { AutoSizeAxes = Axes.Both; } From b1f7a673e719ede09fd76bd4e2da36658aaa53bc Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 15 Oct 2019 00:10:02 +0300 Subject: [PATCH 46/80] Simplify chevron icon coloring --- osu.Game/Graphics/UserInterface/ShowMoreButton.cs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/ShowMoreButton.cs b/osu.Game/Graphics/UserInterface/ShowMoreButton.cs index 8b2eb31d96..854b7abce1 100644 --- a/osu.Game/Graphics/UserInterface/ShowMoreButton.cs +++ b/osu.Game/Graphics/UserInterface/ShowMoreButton.cs @@ -23,7 +23,7 @@ namespace osu.Game.Graphics.UserInterface public Color4 ChevronIconColour { get => chevronIconColour; - set => chevronIconColour = leftChevron.AccentColour = rightChevron.AccentColour = value; + set => chevronIconColour = leftChevron.Colour = rightChevron.Colour = value; } public string Text @@ -131,14 +131,6 @@ namespace osu.Game.Graphics.UserInterface { private const int icon_size = 8; - private Color4 accentColour; - - public Color4 AccentColour - { - get => accentColour; - set => accentColour = Colour = value; - } - public ChevronIcon() { Anchor = Anchor.Centre; From 0676c880b53a612093ef2f0fb8f46c03246f355d Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 15 Oct 2019 00:26:31 +0300 Subject: [PATCH 47/80] Simplify IsTopLevel and IsDeleted properties --- .../Online/API/Requests/Responses/Comment.cs | 30 ++++--------------- 1 file changed, 5 insertions(+), 25 deletions(-) diff --git a/osu.Game/Online/API/Requests/Responses/Comment.cs b/osu.Game/Online/API/Requests/Responses/Comment.cs index 6243ea4fb6..5accd7fd5b 100644 --- a/osu.Game/Online/API/Requests/Responses/Comment.cs +++ b/osu.Game/Online/API/Requests/Responses/Comment.cs @@ -16,20 +16,10 @@ namespace osu.Game.Online.API.Requests.Responses [JsonProperty(@"id")] public long Id { get; set; } - private long? parentId; - [JsonProperty(@"parent_id")] - public long? ParentId - { - get => parentId; - set - { - parentId = value; - IsTopLevel = value == null; - } - } + public long? ParentId { get; set; } - public List ChildComments = new List(); + public readonly List ChildComments = new List(); public Comment ParentComment { get; set; } @@ -65,18 +55,8 @@ namespace osu.Game.Online.API.Requests.Responses [JsonProperty(@"updated_at")] public DateTimeOffset? UpdatedAt { get; set; } - private DateTimeOffset? deletedAt; - [JsonProperty(@"deleted_at")] - public DateTimeOffset? DeletedAt - { - get => deletedAt; - set - { - deletedAt = value; - IsDeleted = value != null; - } - } + public DateTimeOffset? DeletedAt { get; set; } [JsonProperty(@"edited_at")] public DateTimeOffset? EditedAt { get; set; } @@ -86,9 +66,9 @@ namespace osu.Game.Online.API.Requests.Responses public User EditedUser { get; set; } - public bool IsTopLevel { get; set; } + public bool IsTopLevel => !ParentId.HasValue; - public bool IsDeleted { get; set; } + public bool IsDeleted => DeletedAt.HasValue; public string GetMessage() { From 09621f066e8fc1ac9b93e755c1fc94b416b8148e Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 15 Oct 2019 00:32:21 +0300 Subject: [PATCH 48/80] Childs -> Children --- .../Online/TestSceneCommentsContainer.cs | 4 ++-- .../Online/API/Requests/Responses/Comment.cs | 2 +- .../Overlays/Comments/CommentsContainer.cs | 8 ++++---- ...holder.cs => DeletedChildrenPlaceholder.cs} | 4 ++-- osu.Game/Overlays/Comments/DrawableComment.cs | 18 +++++++++--------- ...owChildsButton.cs => ShowChildrenButton.cs} | 4 ++-- 6 files changed, 20 insertions(+), 20 deletions(-) rename osu.Game/Overlays/Comments/{DeletedChildsPlaceholder.cs => DeletedChildrenPlaceholder.cs} (95%) rename osu.Game/Overlays/Comments/{ShowChildsButton.cs => ShowChildrenButton.cs} (89%) diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs index 5e4aa27fae..436e80d6f5 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs @@ -21,8 +21,8 @@ namespace osu.Game.Tests.Visual.Online typeof(DrawableComment), typeof(HeaderButton), typeof(SortTabControl), - typeof(ShowChildsButton), - typeof(DeletedChildsPlaceholder) + typeof(ShowChildrenButton), + typeof(DeletedChildrenPlaceholder) }; protected override bool UseOnlineAPI => true; diff --git a/osu.Game/Online/API/Requests/Responses/Comment.cs b/osu.Game/Online/API/Requests/Responses/Comment.cs index 5accd7fd5b..9e8f0cada2 100644 --- a/osu.Game/Online/API/Requests/Responses/Comment.cs +++ b/osu.Game/Online/API/Requests/Responses/Comment.cs @@ -78,7 +78,7 @@ namespace osu.Game.Online.API.Requests.Responses return WebUtility.HtmlDecode(Regex.Replace(MessageHtml, @"<(.|\n)*?>", string.Empty)); } - public int GetDeletedChildsCount() + public int GetDeletedChildrenCount() { int count = 0; diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index 6c674678df..48b3952093 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -35,7 +35,7 @@ namespace osu.Game.Overlays.Comments private readonly Box background; private readonly FillFlowContainer content; - private readonly DeletedChildsPlaceholder deletedChildsPlaceholder; + private readonly DeletedChildrenPlaceholder deletedChildrenPlaceholder; private readonly CommentsShowMoreButton moreButton; public CommentsContainer(CommentableType type, long id) @@ -87,7 +87,7 @@ namespace osu.Game.Overlays.Comments Direction = FillDirection.Vertical, Children = new Drawable[] { - deletedChildsPlaceholder = new DeletedChildsPlaceholder + deletedChildrenPlaceholder = new DeletedChildrenPlaceholder { ShowDeleted = { BindTarget = ShowDeleted } }, @@ -126,7 +126,7 @@ namespace osu.Game.Overlays.Comments { currentPage = 1; loadedTopLevelComments = 0; - deletedChildsPlaceholder.DeletedCount.Value = 0; + deletedChildrenPlaceholder.DeletedCount.Value = 0; moreButton.IsLoading = true; content.Clear(); } @@ -170,7 +170,7 @@ namespace osu.Game.Overlays.Comments deletedComments++; }); - deletedChildsPlaceholder.DeletedCount.Value = initial ? deletedComments : deletedChildsPlaceholder.DeletedCount.Value + deletedComments; + deletedChildrenPlaceholder.DeletedCount.Value = initial ? deletedComments : deletedChildrenPlaceholder.DeletedCount.Value + deletedComments; if (response.HasMore) { diff --git a/osu.Game/Overlays/Comments/DeletedChildsPlaceholder.cs b/osu.Game/Overlays/Comments/DeletedChildrenPlaceholder.cs similarity index 95% rename from osu.Game/Overlays/Comments/DeletedChildsPlaceholder.cs rename to osu.Game/Overlays/Comments/DeletedChildrenPlaceholder.cs index 058f8cc750..f537141d7f 100644 --- a/osu.Game/Overlays/Comments/DeletedChildsPlaceholder.cs +++ b/osu.Game/Overlays/Comments/DeletedChildrenPlaceholder.cs @@ -10,7 +10,7 @@ using osu.Framework.Bindables; namespace osu.Game.Overlays.Comments { - public class DeletedChildsPlaceholder : FillFlowContainer + public class DeletedChildrenPlaceholder : FillFlowContainer { public readonly BindableBool ShowDeleted = new BindableBool(); public readonly BindableInt DeletedCount = new BindableInt(); @@ -19,7 +19,7 @@ namespace osu.Game.Overlays.Comments private readonly SpriteText countText; - public DeletedChildsPlaceholder() + public DeletedChildrenPlaceholder() { AutoSizeAxes = Axes.Both; Direction = FillDirection.Horizontal; diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 38e45949e1..81a6c6a743 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -25,7 +25,7 @@ namespace osu.Game.Overlays.Comments public readonly BindableBool ShowDeleted = new BindableBool(); - private readonly BindableBool childExpanded = new BindableBool(true); + private readonly BindableBool childrenExpanded = new BindableBool(true); private readonly FillFlowContainer childCommentsVisibilityContainer; private readonly Comment comment; @@ -34,7 +34,7 @@ namespace osu.Game.Overlays.Comments { LinkFlowContainer username; FillFlowContainer childCommentsContainer; - DeletedChildsPlaceholder deletedChildsPlaceholder; + DeletedChildrenPlaceholder deletedChildrenPlaceholder; FillFlowContainer info; LinkFlowContainer message; GridContainer content; @@ -147,7 +147,7 @@ namespace osu.Game.Overlays.Comments }, new RepliesButton(comment.RepliesCount) { - Expanded = { BindTarget = childExpanded } + Expanded = { BindTarget = childrenExpanded } }, } } @@ -171,7 +171,7 @@ namespace osu.Game.Overlays.Comments AutoSizeAxes = Axes.Y, Direction = FillDirection.Vertical }, - deletedChildsPlaceholder = new DeletedChildsPlaceholder + deletedChildrenPlaceholder = new DeletedChildrenPlaceholder { ShowDeleted = { BindTarget = ShowDeleted } } @@ -180,7 +180,7 @@ namespace osu.Game.Overlays.Comments } }; - deletedChildsPlaceholder.DeletedCount.Value = comment.GetDeletedChildsCount(); + deletedChildrenPlaceholder.DeletedCount.Value = comment.GetDeletedChildrenCount(); if (comment.UserId.HasValue) username.AddUserLink(comment.User); @@ -231,7 +231,7 @@ namespace osu.Game.Overlays.Comments Anchor = Anchor.TopRight, Origin = Anchor.TopRight, Margin = new MarginPadding { Right = 30, Top = margin }, - Expanded = { BindTarget = childExpanded } + Expanded = { BindTarget = childrenExpanded } }); } } @@ -245,7 +245,7 @@ namespace osu.Game.Overlays.Comments protected override void LoadComplete() { ShowDeleted.BindValueChanged(onShowDeletedChanged, true); - childExpanded.BindValueChanged(expanded => childCommentsVisibilityContainer.FadeTo(expanded.NewValue ? 1 : 0), true); + childrenExpanded.BindValueChanged(expanded => childCommentsVisibilityContainer.FadeTo(expanded.NewValue ? 1 : 0), true); base.LoadComplete(); } @@ -255,7 +255,7 @@ namespace osu.Game.Overlays.Comments this.FadeTo(show.NewValue ? 1 : 0); } - private class ChevronButton : ShowChildsButton + private class ChevronButton : ShowChildrenButton { private readonly SpriteIcon icon; @@ -275,7 +275,7 @@ namespace osu.Game.Overlays.Comments } } - private class RepliesButton : ShowChildsButton + private class RepliesButton : ShowChildrenButton { private readonly SpriteText text; private readonly int count; diff --git a/osu.Game/Overlays/Comments/ShowChildsButton.cs b/osu.Game/Overlays/Comments/ShowChildrenButton.cs similarity index 89% rename from osu.Game/Overlays/Comments/ShowChildsButton.cs rename to osu.Game/Overlays/Comments/ShowChildrenButton.cs index 464c0a1503..be04b6e5de 100644 --- a/osu.Game/Overlays/Comments/ShowChildsButton.cs +++ b/osu.Game/Overlays/Comments/ShowChildrenButton.cs @@ -8,11 +8,11 @@ using osu.Framework.Bindables; namespace osu.Game.Overlays.Comments { - public abstract class ShowChildsButton : OsuHoverContainer + public abstract class ShowChildrenButton : OsuHoverContainer { public readonly BindableBool Expanded = new BindableBool(true); - protected ShowChildsButton() + protected ShowChildrenButton() { AutoSizeAxes = Axes.Both; } From b84c9dfd84f206d3766b950803116fd687c61c7d Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 15 Oct 2019 00:35:44 +0300 Subject: [PATCH 49/80] Use Humanizer.ToQuantity instead of manual parsing --- osu.Game/Overlays/Comments/DeletedChildrenPlaceholder.cs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/osu.Game/Overlays/Comments/DeletedChildrenPlaceholder.cs b/osu.Game/Overlays/Comments/DeletedChildrenPlaceholder.cs index f537141d7f..21cf01f993 100644 --- a/osu.Game/Overlays/Comments/DeletedChildrenPlaceholder.cs +++ b/osu.Game/Overlays/Comments/DeletedChildrenPlaceholder.cs @@ -7,6 +7,7 @@ using osu.Game.Graphics; using osu.Framework.Graphics.Sprites; using osuTK; using osu.Framework.Bindables; +using Humanizer; namespace osu.Game.Overlays.Comments { @@ -62,12 +63,7 @@ namespace osu.Game.Overlays.Comments return; } - string str = $@"{count.NewValue} deleted comment"; - - if (!(count.NewValue.ToString().EndsWith("1") && !count.NewValue.ToString().EndsWith("11"))) - str += "s"; - - countText.Text = str; + countText.Text = @"deleted comment".ToQuantity(count.NewValue); Show(); } } From 0fd6b0c8524912ec9cc4b98cae03434a9db1154c Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 15 Oct 2019 00:55:33 +0300 Subject: [PATCH 50/80] Use linq expression to count deleted comments --- osu.Game/Online/API/Requests/Responses/Comment.cs | 14 +------------- osu.Game/Overlays/Comments/CommentsContainer.cs | 9 ++------- osu.Game/Overlays/Comments/DrawableComment.cs | 2 +- 3 files changed, 4 insertions(+), 21 deletions(-) diff --git a/osu.Game/Online/API/Requests/Responses/Comment.cs b/osu.Game/Online/API/Requests/Responses/Comment.cs index 9e8f0cada2..046de194db 100644 --- a/osu.Game/Online/API/Requests/Responses/Comment.cs +++ b/osu.Game/Online/API/Requests/Responses/Comment.cs @@ -78,18 +78,6 @@ namespace osu.Game.Online.API.Requests.Responses return WebUtility.HtmlDecode(Regex.Replace(MessageHtml, @"<(.|\n)*?>", string.Empty)); } - public int GetDeletedChildrenCount() - { - int count = 0; - - if (ChildComments.Any()) - ChildComments.ForEach(child => - { - if (child.IsDeleted) - count++; - }); - - return count; - } + public int GetDeletedChildrenCount => ChildComments.Select(c => c.IsDeleted).Where(c => c).Count(); } } diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index 48b3952093..318422bedb 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -11,6 +11,7 @@ using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Game.Online.API.Requests.Responses; using System.Threading; +using System.Linq; namespace osu.Game.Overlays.Comments { @@ -162,13 +163,7 @@ namespace osu.Game.Overlays.Comments { content.Add(loaded); - int deletedComments = 0; - - response.Comments.ForEach(comment => - { - if (comment.IsDeleted && comment.IsTopLevel) - deletedComments++; - }); + int deletedComments = response.Comments.Select(c => c.IsDeleted && c.IsTopLevel).Where(c => c).Count(); deletedChildrenPlaceholder.DeletedCount.Value = initial ? deletedComments : deletedChildrenPlaceholder.DeletedCount.Value + deletedComments; diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 81a6c6a743..13c67b9f5b 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -180,7 +180,7 @@ namespace osu.Game.Overlays.Comments } }; - deletedChildrenPlaceholder.DeletedCount.Value = comment.GetDeletedChildrenCount(); + deletedChildrenPlaceholder.DeletedCount.Value = comment.GetDeletedChildrenCount; if (comment.UserId.HasValue) username.AddUserLink(comment.User); From 42a06a54ffb3779c7079e0b8cbd934e7d204fe77 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 15 Oct 2019 01:08:23 +0300 Subject: [PATCH 51/80] Don't use ProfileShowMoreButton in the test scene to avoid confusion --- .../Visual/Online/TestSceneShowMoreButton.cs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneShowMoreButton.cs b/osu.Game.Tests/Visual/Online/TestSceneShowMoreButton.cs index 8d4955abf0..b9fbbfef6b 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneShowMoreButton.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneShowMoreButton.cs @@ -1,11 +1,12 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osu.Game.Overlays.Profile.Sections; using System; using System.Collections.Generic; using osu.Framework.Graphics; using osu.Game.Graphics.UserInterface; +using osu.Framework.Allocation; +using osu.Game.Graphics; namespace osu.Game.Tests.Visual.Online { @@ -18,11 +19,11 @@ namespace osu.Game.Tests.Visual.Online public TestSceneShowMoreButton() { - ProfileShowMoreButton button = null; + TestButton button = null; int fireCount = 0; - Add(button = new ProfileShowMoreButton + Add(button = new TestButton { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -52,5 +53,16 @@ namespace osu.Game.Tests.Visual.Online AddAssert("action fired twice", () => fireCount == 2); AddAssert("is in loading state", () => button.IsLoading); } + + private class TestButton : ShowMoreButton + { + [BackgroundDependencyLoader] + private void load(OsuColour colors) + { + IdleColour = colors.YellowDark; + HoverColour = colors.Yellow; + ChevronIconColour = colors.Red; + } + } } } From ad32d663652c2432a4f31bb73dc3b555a1e743c4 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 15 Oct 2019 01:10:23 +0300 Subject: [PATCH 52/80] CI fix --- osu.Game/Online/API/Requests/Responses/Comment.cs | 2 +- osu.Game/Overlays/Comments/CommentsContainer.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Online/API/Requests/Responses/Comment.cs b/osu.Game/Online/API/Requests/Responses/Comment.cs index 046de194db..9d011c49c1 100644 --- a/osu.Game/Online/API/Requests/Responses/Comment.cs +++ b/osu.Game/Online/API/Requests/Responses/Comment.cs @@ -78,6 +78,6 @@ namespace osu.Game.Online.API.Requests.Responses return WebUtility.HtmlDecode(Regex.Replace(MessageHtml, @"<(.|\n)*?>", string.Empty)); } - public int GetDeletedChildrenCount => ChildComments.Select(c => c.IsDeleted).Where(c => c).Count(); + public int GetDeletedChildrenCount => ChildComments.Select(c => c.IsDeleted).Count(c => c); } } diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index 318422bedb..49c479f6e5 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -163,7 +163,7 @@ namespace osu.Game.Overlays.Comments { content.Add(loaded); - int deletedComments = response.Comments.Select(c => c.IsDeleted && c.IsTopLevel).Where(c => c).Count(); + int deletedComments = response.Comments.Select(c => c.IsDeleted && c.IsTopLevel).Count(c => c); deletedChildrenPlaceholder.DeletedCount.Value = initial ? deletedComments : deletedChildrenPlaceholder.DeletedCount.Value + deletedComments; From ccc753a3151b1f8066e5015527d0bba6f448687a Mon Sep 17 00:00:00 2001 From: Joehu Date: Mon, 14 Oct 2019 16:27:59 -0700 Subject: [PATCH 53/80] Make OverlayContainers with no blocking input VisibilityContainers --- osu.Game/OsuGame.cs | 2 +- osu.Game/Overlays/Toolbar/Toolbar.cs | 4 +--- osu.Game/Overlays/VolumeOverlay.cs | 4 +--- osu.Game/Screens/Play/ResumeOverlay.cs | 4 +--- osu.Game/Screens/Play/SkipOverlay.cs | 3 +-- osu.Game/Screens/Select/BeatmapInfoWedge.cs | 4 +--- 6 files changed, 6 insertions(+), 15 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 5742d423bb..4dcc181bea 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -102,7 +102,7 @@ namespace osu.Game private readonly List overlays = new List(); - private readonly List toolbarElements = new List(); + private readonly List toolbarElements = new List(); private readonly List visibleBlockingOverlays = new List(); diff --git a/osu.Game/Overlays/Toolbar/Toolbar.cs b/osu.Game/Overlays/Toolbar/Toolbar.cs index 19038c3981..b044bc4de0 100644 --- a/osu.Game/Overlays/Toolbar/Toolbar.cs +++ b/osu.Game/Overlays/Toolbar/Toolbar.cs @@ -16,7 +16,7 @@ using osu.Game.Rulesets; namespace osu.Game.Overlays.Toolbar { - public class Toolbar : OverlayContainer + public class Toolbar : VisibilityContainer { public const float HEIGHT = 40; public const float TOOLTIP_HEIGHT = 30; @@ -26,8 +26,6 @@ namespace osu.Game.Overlays.Toolbar private ToolbarUserButton userButton; private ToolbarRulesetSelector rulesetSelector; - protected override bool BlockPositionalInput => false; - private const double transition_time = 500; private const float alpha_hovering = 0.8f; diff --git a/osu.Game/Overlays/VolumeOverlay.cs b/osu.Game/Overlays/VolumeOverlay.cs index 27e2eef200..ca7665eba5 100644 --- a/osu.Game/Overlays/VolumeOverlay.cs +++ b/osu.Game/Overlays/VolumeOverlay.cs @@ -19,7 +19,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays { - public class VolumeOverlay : OverlayContainer + public class VolumeOverlay : VisibilityContainer { private const float offset = 10; @@ -28,8 +28,6 @@ namespace osu.Game.Overlays private VolumeMeter volumeMeterMusic; private MuteButton muteButton; - protected override bool BlockPositionalInput => false; - private readonly BindableDouble muteAdjustment = new BindableDouble(); private readonly Bindable isMuted = new Bindable(); diff --git a/osu.Game/Screens/Play/ResumeOverlay.cs b/osu.Game/Screens/Play/ResumeOverlay.cs index 2ef76069c2..641d5358ba 100644 --- a/osu.Game/Screens/Play/ResumeOverlay.cs +++ b/osu.Game/Screens/Play/ResumeOverlay.cs @@ -16,7 +16,7 @@ namespace osu.Game.Screens.Play /// /// An overlay which can be used to require further user actions before gameplay is resumed. /// - public abstract class ResumeOverlay : OverlayContainer + public abstract class ResumeOverlay : VisibilityContainer { public CursorContainer GameplayCursor { get; set; } @@ -29,8 +29,6 @@ namespace osu.Game.Screens.Play protected const float TRANSITION_TIME = 500; - protected override bool BlockPositionalInput => false; - protected abstract string Message { get; } public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true; diff --git a/osu.Game/Screens/Play/SkipOverlay.cs b/osu.Game/Screens/Play/SkipOverlay.cs index d6c2b59d98..31cdff5fb9 100644 --- a/osu.Game/Screens/Play/SkipOverlay.cs +++ b/osu.Game/Screens/Play/SkipOverlay.cs @@ -23,7 +23,7 @@ using osu.Game.Input.Bindings; namespace osu.Game.Screens.Play { - public class SkipOverlay : OverlayContainer, IKeyBindingHandler + public class SkipOverlay : VisibilityContainer, IKeyBindingHandler { private readonly double startTime; @@ -36,7 +36,6 @@ namespace osu.Game.Screens.Play private double displayTime; public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true; - protected override bool BlockPositionalInput => false; /// /// Displays a skip overlay, giving the user the ability to skip forward. diff --git a/osu.Game/Screens/Select/BeatmapInfoWedge.cs b/osu.Game/Screens/Select/BeatmapInfoWedge.cs index 8b360d4a86..d54c13c7db 100644 --- a/osu.Game/Screens/Select/BeatmapInfoWedge.cs +++ b/osu.Game/Screens/Select/BeatmapInfoWedge.cs @@ -29,7 +29,7 @@ using osu.Game.Rulesets.UI; namespace osu.Game.Screens.Select { - public class BeatmapInfoWedge : OverlayContainer + public class BeatmapInfoWedge : VisibilityContainer { private const float shear_width = 36.75f; @@ -62,8 +62,6 @@ namespace osu.Game.Screens.Select ruleset.ValueChanged += _ => updateDisplay(); } - protected override bool BlockPositionalInput => false; - protected override void PopIn() { this.MoveToX(0, 800, Easing.OutQuint); From f4924dc3cf876999b027c0bc0e9a89e203999e1b Mon Sep 17 00:00:00 2001 From: Joehu Date: Mon, 14 Oct 2019 16:37:54 -0700 Subject: [PATCH 54/80] Fix volume scrolling when hovering VersionManager --- osu.Desktop/Overlays/VersionManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Desktop/Overlays/VersionManager.cs b/osu.Desktop/Overlays/VersionManager.cs index 6eed46867a..8c759f8487 100644 --- a/osu.Desktop/Overlays/VersionManager.cs +++ b/osu.Desktop/Overlays/VersionManager.cs @@ -15,7 +15,7 @@ using osuTK.Graphics; namespace osu.Desktop.Overlays { - public class VersionManager : OverlayContainer + public class VersionManager : VisibilityContainer { [BackgroundDependencyLoader] private void load(OsuColour colours, TextureStore textures, OsuGameBase game) From efc201ec852561e3ab31491c4e171d9767a93665 Mon Sep 17 00:00:00 2001 From: Joehu Date: Mon, 14 Oct 2019 16:40:53 -0700 Subject: [PATCH 55/80] Make PlaylistOverlay a VisibilityContainer --- osu.Game/Overlays/Music/PlaylistOverlay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Music/PlaylistOverlay.cs b/osu.Game/Overlays/Music/PlaylistOverlay.cs index bb88960280..b89a577282 100644 --- a/osu.Game/Overlays/Music/PlaylistOverlay.cs +++ b/osu.Game/Overlays/Music/PlaylistOverlay.cs @@ -16,7 +16,7 @@ using osuTK.Graphics; namespace osu.Game.Overlays.Music { - public class PlaylistOverlay : OverlayContainer + public class PlaylistOverlay : VisibilityContainer { private const float transition_duration = 600; private const float playlist_height = 510; From 12cd57744b87d559679e179f5f366ab1e64f6238 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 15 Oct 2019 16:14:06 +0900 Subject: [PATCH 56/80] Make RulestStore initialise at construction time --- .../Background/TestSceneUserDimContainer.cs | 6 ++ .../SongSelect/TestScenePlaySongSelect.cs | 6 ++ osu.Game/OsuGameBase.cs | 6 ++ osu.Game/Rulesets/RulesetStore.cs | 57 +++++++++++-------- 4 files changed, 52 insertions(+), 23 deletions(-) diff --git a/osu.Game.Tests/Visual/Background/TestSceneUserDimContainer.cs b/osu.Game.Tests/Visual/Background/TestSceneUserDimContainer.cs index 3061a3a542..f858174ff2 100644 --- a/osu.Game.Tests/Visual/Background/TestSceneUserDimContainer.cs +++ b/osu.Game.Tests/Visual/Background/TestSceneUserDimContainer.cs @@ -285,6 +285,12 @@ namespace osu.Game.Tests.Visual.Background }); } + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + rulesets?.Dispose(); + } + private class DummySongSelect : PlaySongSelect { protected override BackgroundScreen CreateBackground() diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs index a7020b6534..efe7fee5e4 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs @@ -349,5 +349,11 @@ namespace osu.Game.Tests.Visual.SongSelect DateAdded = DateTimeOffset.UtcNow, }; } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + rulesets?.Dispose(); + } } } diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 8578517a17..194a439b06 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -298,6 +298,12 @@ namespace osu.Game public string[] HandledExtensions => fileImporters.SelectMany(i => i.HandledExtensions).ToArray(); + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + RulesetStore?.Dispose(); + } + private class OsuUserInputManager : UserInputManager { protected override MouseButtonEventManager CreateButtonManagerFor(MouseButton button) diff --git a/osu.Game/Rulesets/RulesetStore.cs b/osu.Game/Rulesets/RulesetStore.cs index 47aad43966..1df8568ee1 100644 --- a/osu.Game/Rulesets/RulesetStore.cs +++ b/osu.Game/Rulesets/RulesetStore.cs @@ -14,25 +14,22 @@ namespace osu.Game.Rulesets /// /// Todo: All of this needs to be moved to a RulesetStore. /// - public class RulesetStore : DatabaseBackedStore + public class RulesetStore : DatabaseBackedStore, IDisposable { - private static readonly Dictionary loaded_assemblies = new Dictionary(); + private const string ruleset_library_prefix = "osu.Game.Rulesets"; - static RulesetStore() - { - AppDomain.CurrentDomain.AssemblyResolve += currentDomain_AssemblyResolve; - - // On android in release configuration assemblies are loaded from the apk directly into memory. - // We cannot read assemblies from cwd, so should check loaded assemblies instead. - loadFromAppDomain(); - - loadFromDisk(); - } + private readonly Dictionary loadedAssemblies = new Dictionary(); public RulesetStore(IDatabaseContextFactory factory) : base(factory) { + // On android in release configuration assemblies are loaded from the apk directly into memory. + // We cannot read assemblies from cwd, so should check loaded assemblies instead. + loadFromAppDomain(); + loadFromDisk(); addMissingRulesets(); + + AppDomain.CurrentDomain.AssemblyResolve += resolveRulesetAssembly; } /// @@ -54,9 +51,7 @@ namespace osu.Game.Rulesets /// public IEnumerable AvailableRulesets { get; private set; } - private static Assembly currentDomain_AssemblyResolve(object sender, ResolveEventArgs args) => loaded_assemblies.Keys.FirstOrDefault(a => a.FullName == args.Name); - - private const string ruleset_library_prefix = "osu.Game.Rulesets"; + private Assembly resolveRulesetAssembly(object sender, ResolveEventArgs args) => loadedAssemblies.Keys.FirstOrDefault(a => a.FullName == args.Name); private void addMissingRulesets() { @@ -64,7 +59,7 @@ namespace osu.Game.Rulesets { var context = usage.Context; - var instances = loaded_assemblies.Values.Select(r => (Ruleset)Activator.CreateInstance(r, (RulesetInfo)null)).ToList(); + var instances = loadedAssemblies.Values.Select(r => (Ruleset)Activator.CreateInstance(r, (RulesetInfo)null)).ToList(); //add all legacy modes in correct order foreach (var r in instances.Where(r => r.LegacyID != null).OrderBy(r => r.LegacyID)) @@ -113,7 +108,7 @@ namespace osu.Game.Rulesets } } - private static void loadFromAppDomain() + private void loadFromAppDomain() { foreach (var ruleset in AppDomain.CurrentDomain.GetAssemblies()) { @@ -126,7 +121,7 @@ namespace osu.Game.Rulesets } } - private static void loadFromDisk() + private void loadFromDisk() { try { @@ -141,11 +136,11 @@ namespace osu.Game.Rulesets } } - private static void loadRulesetFromFile(string file) + private void loadRulesetFromFile(string file) { var filename = Path.GetFileNameWithoutExtension(file); - if (loaded_assemblies.Values.Any(t => t.Namespace == filename)) + if (loadedAssemblies.Values.Any(t => t.Namespace == filename)) return; try @@ -158,19 +153,35 @@ namespace osu.Game.Rulesets } } - private static void addRuleset(Assembly assembly) + private void addRuleset(Assembly assembly) { - if (loaded_assemblies.ContainsKey(assembly)) + if (loadedAssemblies.ContainsKey(assembly)) return; try { - loaded_assemblies[assembly] = assembly.GetTypes().First(t => t.IsPublic && t.IsSubclassOf(typeof(Ruleset))); + loadedAssemblies[assembly] = assembly.GetTypes().First(t => t.IsPublic && t.IsSubclassOf(typeof(Ruleset))); } catch (Exception e) { Logger.Error(e, $"Failed to add ruleset {assembly}"); } } + + ~RulesetStore() + { + Dispose(false); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + AppDomain.CurrentDomain.AssemblyResolve -= resolveRulesetAssembly; + } } } From 96c6aeefe92a864ecd783f253506b899a6a18741 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 15 Oct 2019 16:16:33 +0900 Subject: [PATCH 57/80] Remove out-of-date todo --- osu.Game/Rulesets/RulesetStore.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game/Rulesets/RulesetStore.cs b/osu.Game/Rulesets/RulesetStore.cs index 1df8568ee1..0e6e0b8676 100644 --- a/osu.Game/Rulesets/RulesetStore.cs +++ b/osu.Game/Rulesets/RulesetStore.cs @@ -11,9 +11,6 @@ using osu.Game.Database; namespace osu.Game.Rulesets { - /// - /// Todo: All of this needs to be moved to a RulesetStore. - /// public class RulesetStore : DatabaseBackedStore, IDisposable { private const string ruleset_library_prefix = "osu.Game.Rulesets"; From 3c714dc01307216b23250329c5bc3bf0560138fe Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 15 Oct 2019 11:20:06 +0300 Subject: [PATCH 58/80] APICommentsController -> CommentBundle --- osu.Game/Online/API/Requests/GetCommentsRequest.cs | 2 +- .../Responses/{APICommentsController.cs => CommentBundle.cs} | 2 +- osu.Game/Overlays/Comments/CommentsContainer.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename osu.Game/Online/API/Requests/Responses/{APICommentsController.cs => CommentBundle.cs} (98%) diff --git a/osu.Game/Online/API/Requests/GetCommentsRequest.cs b/osu.Game/Online/API/Requests/GetCommentsRequest.cs index 834a5106a0..7763501860 100644 --- a/osu.Game/Online/API/Requests/GetCommentsRequest.cs +++ b/osu.Game/Online/API/Requests/GetCommentsRequest.cs @@ -8,7 +8,7 @@ using osu.Game.Overlays.Comments; namespace osu.Game.Online.API.Requests { - public class GetCommentsRequest : APIRequest + public class GetCommentsRequest : APIRequest { private readonly long id; private readonly int page; diff --git a/osu.Game/Online/API/Requests/Responses/APICommentsController.cs b/osu.Game/Online/API/Requests/Responses/CommentBundle.cs similarity index 98% rename from osu.Game/Online/API/Requests/Responses/APICommentsController.cs rename to osu.Game/Online/API/Requests/Responses/CommentBundle.cs index ca6062e371..7063581605 100644 --- a/osu.Game/Online/API/Requests/Responses/APICommentsController.cs +++ b/osu.Game/Online/API/Requests/Responses/CommentBundle.cs @@ -7,7 +7,7 @@ using System.Collections.Generic; namespace osu.Game.Online.API.Requests.Responses { - public class APICommentsController + public class CommentBundle { private List comments; diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index 49c479f6e5..62f0ce947b 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -139,7 +139,7 @@ namespace osu.Game.Overlays.Comments api.Queue(request); } - private void onSuccess(APICommentsController response, bool initial) + private void onSuccess(CommentBundle response, bool initial) { loadCancellation = new CancellationTokenSource(); From eb5dad08aa6a8560d544358776c8e6ab3e18e2ea Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 15 Oct 2019 11:25:58 +0300 Subject: [PATCH 59/80] Remove initial filed --- .../Online/API/Requests/Responses/Comment.cs | 2 +- .../Overlays/Comments/CommentsContainer.cs | 36 ++++++++++--------- osu.Game/Overlays/Comments/DrawableComment.cs | 2 +- 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/osu.Game/Online/API/Requests/Responses/Comment.cs b/osu.Game/Online/API/Requests/Responses/Comment.cs index 9d011c49c1..68a4c28726 100644 --- a/osu.Game/Online/API/Requests/Responses/Comment.cs +++ b/osu.Game/Online/API/Requests/Responses/Comment.cs @@ -78,6 +78,6 @@ namespace osu.Game.Online.API.Requests.Responses return WebUtility.HtmlDecode(Regex.Replace(MessageHtml, @"<(.|\n)*?>", string.Empty)); } - public int GetDeletedChildrenCount => ChildComments.Select(c => c.IsDeleted).Count(c => c); + public int DeletedChildrenCount => ChildComments.Count(c => c.IsDeleted); } } diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index 62f0ce947b..824d9822be 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -101,7 +101,7 @@ namespace osu.Game.Overlays.Comments Anchor = Anchor.Centre, Origin = Anchor.Centre, Margin = new MarginPadding(5), - Action = () => getComments(false), + Action = getComments } } } @@ -119,27 +119,31 @@ namespace osu.Game.Overlays.Comments base.LoadComplete(); } - private void onSortChanged(ValueChangedEvent sort) => getComments(); - - private void getComments(bool initial = true) + private void onSortChanged(ValueChangedEvent sort) { - if (initial) - { - currentPage = 1; - loadedTopLevelComments = 0; - deletedChildrenPlaceholder.DeletedCount.Value = 0; - moreButton.IsLoading = true; - content.Clear(); - } + clearComments(); + getComments(); + } + private void getComments() + { request?.Cancel(); loadCancellation?.Cancel(); request = new GetCommentsRequest(type, id, Sort.Value, currentPage++); - request.Success += response => onSuccess(response, initial); + request.Success += response => onSuccess(response); api.Queue(request); } - private void onSuccess(CommentBundle response, bool initial) + private void clearComments() + { + currentPage = 1; + loadedTopLevelComments = 0; + deletedChildrenPlaceholder.DeletedCount.Value = 0; + moreButton.IsLoading = true; + content.Clear(); + } + + private void onSuccess(CommentBundle response) { loadCancellation = new CancellationTokenSource(); @@ -163,9 +167,7 @@ namespace osu.Game.Overlays.Comments { content.Add(loaded); - int deletedComments = response.Comments.Select(c => c.IsDeleted && c.IsTopLevel).Count(c => c); - - deletedChildrenPlaceholder.DeletedCount.Value = initial ? deletedComments : deletedChildrenPlaceholder.DeletedCount.Value + deletedComments; + deletedChildrenPlaceholder.DeletedCount.Value += response.Comments.Count(c => c.IsDeleted && c.IsTopLevel); if (response.HasMore) { diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 13c67b9f5b..b22bd6d426 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -180,7 +180,7 @@ namespace osu.Game.Overlays.Comments } }; - deletedChildrenPlaceholder.DeletedCount.Value = comment.GetDeletedChildrenCount; + deletedChildrenPlaceholder.DeletedCount.Value = comment.DeletedChildrenCount; if (comment.UserId.HasValue) username.AddUserLink(comment.User); From b2885e7b139b8def41fc532181d2d19f4a871fc3 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 15 Oct 2019 11:26:58 +0300 Subject: [PATCH 60/80] Move load() under the ctor --- osu.Game/Overlays/Comments/CommentsContainer.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index 824d9822be..bd1a8562d3 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -113,6 +113,12 @@ namespace osu.Game.Overlays.Comments }); } + [BackgroundDependencyLoader] + private void load() + { + background.Colour = colours.Gray2; + } + protected override void LoadComplete() { Sort.BindValueChanged(onSortChanged, true); @@ -184,12 +190,6 @@ namespace osu.Game.Overlays.Comments }, loadCancellation.Token); } - [BackgroundDependencyLoader] - private void load() - { - background.Colour = colours.Gray2; - } - protected override void Dispose(bool isDisposing) { request?.Cancel(); From 213f00556d30b3f4bededf2c57832bb6e5182802 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 15 Oct 2019 11:30:50 +0300 Subject: [PATCH 61/80] Remove onShowDeletedChanged function --- osu.Game/Overlays/Comments/DrawableComment.cs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index b22bd6d426..59d3d08122 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -244,17 +244,15 @@ namespace osu.Game.Overlays.Comments protected override void LoadComplete() { - ShowDeleted.BindValueChanged(onShowDeletedChanged, true); + ShowDeleted.BindValueChanged(show => + { + if (comment.IsDeleted) + this.FadeTo(show.NewValue ? 1 : 0); + }, true); childrenExpanded.BindValueChanged(expanded => childCommentsVisibilityContainer.FadeTo(expanded.NewValue ? 1 : 0), true); base.LoadComplete(); } - private void onShowDeletedChanged(ValueChangedEvent show) - { - if (comment.IsDeleted) - this.FadeTo(show.NewValue ? 1 : 0); - } - private class ChevronButton : ShowChildrenButton { private readonly SpriteIcon icon; From 96e31b9cca2b62147354b6608c11857280a7cade Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 15 Oct 2019 12:07:01 +0300 Subject: [PATCH 62/80] Add support for deleted comments with message --- .../Online/API/Requests/Responses/Comment.cs | 8 ++----- osu.Game/Overlays/Comments/DrawableComment.cs | 23 +++++++++++++------ 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/osu.Game/Online/API/Requests/Responses/Comment.cs b/osu.Game/Online/API/Requests/Responses/Comment.cs index 68a4c28726..29abaa74e5 100644 --- a/osu.Game/Online/API/Requests/Responses/Comment.cs +++ b/osu.Game/Online/API/Requests/Responses/Comment.cs @@ -70,13 +70,9 @@ namespace osu.Game.Online.API.Requests.Responses public bool IsDeleted => DeletedAt.HasValue; - public string GetMessage() - { - if (IsDeleted) - return @"deleted"; + public bool HasMessage => !string.IsNullOrEmpty(MessageHtml); - return WebUtility.HtmlDecode(Regex.Replace(MessageHtml, @"<(.|\n)*?>", string.Empty)); - } + public string GetMessage => HasMessage ? WebUtility.HtmlDecode(Regex.Replace(MessageHtml, @"<(.|\n)*?>", string.Empty)) : string.Empty; public int DeletedChildrenCount => ChildComments.Count(c => c.IsDeleted); } diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 59d3d08122..89abda92cf 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -198,12 +198,13 @@ namespace osu.Game.Overlays.Comments }); } - if (!comment.IsDeleted) + if (comment.HasMessage) { - var formattedSource = MessageFormatter.FormatText(comment.GetMessage()); + var formattedSource = MessageFormatter.FormatText(comment.GetMessage); message.AddLinks(formattedSource.Text, formattedSource.Links); } - else + + if (comment.IsDeleted) { content.FadeColour(OsuColour.Gray(0.5f)); votePill.Hide(); @@ -297,13 +298,13 @@ namespace osu.Game.Overlays.Comments private class ParentUsername : FillFlowContainer, IHasTooltip { - public string TooltipText => comment.ParentComment?.GetMessage() ?? ""; + public string TooltipText => getParentMessage(); - private readonly Comment comment; + private readonly Comment parentComment; public ParentUsername(Comment comment) { - this.comment = comment; + parentComment = comment.ParentComment; AutoSizeAxes = Axes.Both; Direction = FillDirection.Horizontal; @@ -319,10 +320,18 @@ namespace osu.Game.Overlays.Comments new SpriteText { Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true), - Text = comment.ParentComment?.User?.Username ?? comment.ParentComment?.LegacyName + Text = parentComment?.User?.Username ?? parentComment?.LegacyName } }; } + + private string getParentMessage() + { + if (parentComment == null) + return string.Empty; + + return parentComment.HasMessage ? parentComment.GetMessage : parentComment.IsDeleted ? @"deleted" : string.Empty; + } } private class VotePill : CircularContainer From d321794ef5b0fefbb2330a3f9e35ef42457e0299 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 15 Oct 2019 12:26:16 +0300 Subject: [PATCH 63/80] Make loadedTopLevelComments a local filed --- osu.Game/Overlays/Comments/CommentsContainer.cs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index bd1a8562d3..6ac31b258f 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -12,6 +12,7 @@ using osu.Game.Graphics; using osu.Game.Online.API.Requests.Responses; using System.Threading; using System.Linq; +using osu.Framework.Extensions.IEnumerableExtensions; namespace osu.Game.Overlays.Comments { @@ -32,7 +33,6 @@ namespace osu.Game.Overlays.Comments private GetCommentsRequest request; private CancellationTokenSource loadCancellation; private int currentPage; - private int loadedTopLevelComments; private readonly Box background; private readonly FillFlowContainer content; @@ -143,7 +143,6 @@ namespace osu.Game.Overlays.Comments private void clearComments() { currentPage = 1; - loadedTopLevelComments = 0; deletedChildrenPlaceholder.DeletedCount.Value = 0; moreButton.IsLoading = true; content.Clear(); @@ -177,11 +176,9 @@ namespace osu.Game.Overlays.Comments if (response.HasMore) { - response.Comments.ForEach(comment => - { - if (comment.IsTopLevel) - loadedTopLevelComments++; - }); + int loadedTopLevelComments = 0; + content.Children.OfType().ForEach(p => loadedTopLevelComments += p.Children.OfType().Count()); + moreButton.Current.Value = response.TopLevelCount - loadedTopLevelComments; moreButton.IsLoading = false; } From 7ba15df0c07f193016e3e4f0a71c00ccd7b99c15 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 15 Oct 2019 12:27:32 +0300 Subject: [PATCH 64/80] Convert to method group --- 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 6ac31b258f..abc1b7233d 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -136,7 +136,7 @@ namespace osu.Game.Overlays.Comments request?.Cancel(); loadCancellation?.Cancel(); request = new GetCommentsRequest(type, id, Sort.Value, currentPage++); - request.Success += response => onSuccess(response); + request.Success += onSuccess; api.Queue(request); } From 2543de22bd4f2bf5c8fe95f46944419312cb9361 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 15 Oct 2019 12:47:35 +0300 Subject: [PATCH 65/80] Simplify DeletedChildrenPlaceholder behavior --- .../Comments/DeletedChildrenPlaceholder.cs | 27 +++++++------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/osu.Game/Overlays/Comments/DeletedChildrenPlaceholder.cs b/osu.Game/Overlays/Comments/DeletedChildrenPlaceholder.cs index 21cf01f993..e849691597 100644 --- a/osu.Game/Overlays/Comments/DeletedChildrenPlaceholder.cs +++ b/osu.Game/Overlays/Comments/DeletedChildrenPlaceholder.cs @@ -16,8 +16,6 @@ namespace osu.Game.Overlays.Comments public readonly BindableBool ShowDeleted = new BindableBool(); public readonly BindableInt DeletedCount = new BindableInt(); - private bool canBeShown; - private readonly SpriteText countText; public DeletedChildrenPlaceholder() @@ -42,29 +40,22 @@ namespace osu.Game.Overlays.Comments protected override void LoadComplete() { - DeletedCount.BindValueChanged(onCountChanged, true); - ShowDeleted.BindValueChanged(onShowDeletedChanged, true); + DeletedCount.BindValueChanged(_ => updateDisplay(), true); + ShowDeleted.BindValueChanged(_ => updateDisplay(), true); base.LoadComplete(); } - private void onShowDeletedChanged(ValueChangedEvent showDeleted) + private void updateDisplay() { - if (canBeShown) - this.FadeTo(showDeleted.NewValue ? 0 : 1); - } - - private void onCountChanged(ValueChangedEvent count) - { - canBeShown = count.NewValue != 0; - - if (!canBeShown) + if (DeletedCount.Value != 0) + { + countText.Text = @"deleted comment".ToQuantity(DeletedCount.Value); + this.FadeTo(ShowDeleted.Value ? 0 : 1); + } + else { Hide(); - return; } - - countText.Text = @"deleted comment".ToQuantity(count.NewValue); - Show(); } } } From 14c72f85fa56387b3932908c616c0de68e3aee36 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Tue, 15 Oct 2019 23:40:48 +0300 Subject: [PATCH 66/80] Fix incorrect beatmap set info equality check on non-online set info --- osu.Game/Beatmaps/BeatmapSetInfo.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/BeatmapSetInfo.cs b/osu.Game/Beatmaps/BeatmapSetInfo.cs index 03bc7c7312..90346a8c8b 100644 --- a/osu.Game/Beatmaps/BeatmapSetInfo.cs +++ b/osu.Game/Beatmaps/BeatmapSetInfo.cs @@ -63,6 +63,12 @@ namespace osu.Game.Beatmaps public bool Protected { get; set; } - public bool Equals(BeatmapSetInfo other) => OnlineBeatmapSetID == other?.OnlineBeatmapSetID; + public bool Equals(BeatmapSetInfo other) + { + if (!OnlineBeatmapSetID.HasValue || !(other?.OnlineBeatmapSetID.HasValue ?? false)) + return ReferenceEquals(this, other); + + return OnlineBeatmapSetID == other.OnlineBeatmapSetID; + } } } From 350d139cbf22fef749454d867b3b716f8e947bf4 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 16 Oct 2019 15:54:00 +0900 Subject: [PATCH 67/80] Make chevron icon colour protected --- osu.Game/Graphics/UserInterface/ShowMoreButton.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterface/ShowMoreButton.cs b/osu.Game/Graphics/UserInterface/ShowMoreButton.cs index 854b7abce1..5296b9dd7f 100644 --- a/osu.Game/Graphics/UserInterface/ShowMoreButton.cs +++ b/osu.Game/Graphics/UserInterface/ShowMoreButton.cs @@ -20,7 +20,7 @@ namespace osu.Game.Graphics.UserInterface private Color4 chevronIconColour; - public Color4 ChevronIconColour + protected Color4 ChevronIconColour { get => chevronIconColour; set => chevronIconColour = leftChevron.Colour = rightChevron.Colour = value; From 5ac5e34f8585fc0910ef4d6cf81307ca90e51b47 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 16 Oct 2019 19:32:45 +0900 Subject: [PATCH 68/80] Use a cleaner distance function --- .../Edit/Compose/Components/CircularBeatSnapGrid.cs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/CircularBeatSnapGrid.cs b/osu.Game/Screens/Edit/Compose/Components/CircularBeatSnapGrid.cs index 8492771808..bf363aeb37 100644 --- a/osu.Game/Screens/Edit/Compose/Components/CircularBeatSnapGrid.cs +++ b/osu.Game/Screens/Edit/Compose/Components/CircularBeatSnapGrid.cs @@ -18,13 +18,9 @@ namespace osu.Game.Screens.Edit.Compose.Components protected override void CreateContent(Vector2 centrePosition) { - float maxDistance = Math.Max( - Vector2.Distance(centrePosition, Vector2.Zero), - Math.Max( - Vector2.Distance(centrePosition, new Vector2(DrawWidth, 0)), - Math.Max( - Vector2.Distance(centrePosition, new Vector2(0, DrawHeight)), - Vector2.Distance(centrePosition, DrawSize)))); + float dx = Math.Max(centrePosition.X, DrawWidth - centrePosition.X); + float dy = Math.Max(centrePosition.Y, DrawHeight - centrePosition.Y); + float maxDistance = new Vector2(dx, dy).Length; int requiredCircles = (int)(maxDistance / DistanceSpacing); From 2d4b7dc361ca061fd74cef1654ab86875c58d518 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 16 Oct 2019 19:33:18 +0900 Subject: [PATCH 69/80] Remove redundant code --- .../Screens/Edit/Compose/Components/CircularBeatSnapGrid.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/CircularBeatSnapGrid.cs b/osu.Game/Screens/Edit/Compose/Components/CircularBeatSnapGrid.cs index bf363aeb37..09679f0553 100644 --- a/osu.Game/Screens/Edit/Compose/Components/CircularBeatSnapGrid.cs +++ b/osu.Game/Screens/Edit/Compose/Components/CircularBeatSnapGrid.cs @@ -48,11 +48,7 @@ namespace osu.Game.Screens.Edit.Compose.Components float radius = DistanceSpacing; int radialCount = Math.Max(1, (int)Math.Round(distance / radius)); - if (radialCount <= 0) - return position; - Vector2 normalisedDirection = direction * new Vector2(1f / distance); - return CentrePosition + normalisedDirection * radialCount * radius; } } From b6b8098b989383b0402e2efe48476048f9b05f3f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 16 Oct 2019 19:44:53 +0900 Subject: [PATCH 70/80] Add an arbitrary offset to prevent div-by-0 --- .../Screens/Edit/Compose/Components/CircularBeatSnapGrid.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Screens/Edit/Compose/Components/CircularBeatSnapGrid.cs b/osu.Game/Screens/Edit/Compose/Components/CircularBeatSnapGrid.cs index 09679f0553..5e378f8393 100644 --- a/osu.Game/Screens/Edit/Compose/Components/CircularBeatSnapGrid.cs +++ b/osu.Game/Screens/Edit/Compose/Components/CircularBeatSnapGrid.cs @@ -43,6 +43,10 @@ namespace osu.Game.Screens.Edit.Compose.Components public override Vector2 GetSnapPosition(Vector2 position) { Vector2 direction = position - CentrePosition; + + if (direction == Vector2.Zero) + direction = new Vector2(0.001f, 0.001f); + float distance = direction.Length; float radius = DistanceSpacing; From 79b2c7b480f34c2d122f69aed9a69ae413bf7108 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 16 Oct 2019 20:04:15 +0900 Subject: [PATCH 71/80] Make BeginPlacement() set the hitobject start time --- .../Edit/Blueprints/ManiaPlacementBlueprint.cs | 4 +--- .../Edit/Blueprints/HitCircles/HitCirclePlacementBlueprint.cs | 1 - .../Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs | 2 -- .../Edit/Blueprints/Spinners/SpinnerPlacementBlueprint.cs | 2 -- osu.Game/Rulesets/Edit/PlacementBlueprint.cs | 4 +++- 5 files changed, 4 insertions(+), 9 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaPlacementBlueprint.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaPlacementBlueprint.cs index 3142f22fcd..b28d8bb0e6 100644 --- a/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaPlacementBlueprint.cs @@ -49,10 +49,8 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints if (Column == null) return base.OnMouseDown(e); - HitObject.StartTime = TimeAt(e.ScreenSpaceMousePosition); HitObject.Column = Column.Index; - - BeginPlacement(); + BeginPlacement(TimeAt(e.ScreenSpaceMousePosition)); return true; } diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCirclePlacementBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCirclePlacementBlueprint.cs index 6c08990ad6..bb47c7e464 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCirclePlacementBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCirclePlacementBlueprint.cs @@ -30,7 +30,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles protected override bool OnClick(ClickEvent e) { - HitObject.StartTime = EditorClock.CurrentTime; EndPlacement(); return true; } diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs index fc074ef8af..2fb18bf8ba 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs @@ -104,8 +104,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders private void beginCurve() { BeginPlacement(); - - HitObject.StartTime = EditorClock.CurrentTime; setState(PlacementState.Body); } diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerPlacementBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerPlacementBlueprint.cs index 8319f49cbc..5525b8936e 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerPlacementBlueprint.cs @@ -41,8 +41,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners } else { - HitObject.StartTime = EditorClock.CurrentTime; - isPlacingEnd = true; piece.FadeTo(1f, 150, Easing.OutQuint); diff --git a/osu.Game/Rulesets/Edit/PlacementBlueprint.cs b/osu.Game/Rulesets/Edit/PlacementBlueprint.cs index 290fd8d27d..07283d2245 100644 --- a/osu.Game/Rulesets/Edit/PlacementBlueprint.cs +++ b/osu.Game/Rulesets/Edit/PlacementBlueprint.cs @@ -91,8 +91,10 @@ namespace osu.Game.Rulesets.Edit /// /// Signals that the placement of has started. /// - protected void BeginPlacement() + /// The start time of at the placement point. If null, the current clock time is used. + protected void BeginPlacement(double? startTime = null) { + HitObject.StartTime = startTime ?? EditorClock.CurrentTime; placementHandler.BeginPlacement(HitObject); PlacementBegun = true; } From 405ab07800b204b9cf3b882dfc978378eee1f72c Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Thu, 17 Oct 2019 01:18:29 +0300 Subject: [PATCH 72/80] Check equality by ID -> OnlineBeatmapSetID -> Hash -> ReferenceEquals --- osu.Game/Beatmaps/BeatmapSetInfo.cs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapSetInfo.cs b/osu.Game/Beatmaps/BeatmapSetInfo.cs index 90346a8c8b..a8b83dca38 100644 --- a/osu.Game/Beatmaps/BeatmapSetInfo.cs +++ b/osu.Game/Beatmaps/BeatmapSetInfo.cs @@ -65,10 +65,19 @@ namespace osu.Game.Beatmaps public bool Equals(BeatmapSetInfo other) { - if (!OnlineBeatmapSetID.HasValue || !(other?.OnlineBeatmapSetID.HasValue ?? false)) - return ReferenceEquals(this, other); + if (other == null) + return false; - return OnlineBeatmapSetID == other.OnlineBeatmapSetID; + if (ID != 0 && other.ID != 0) + return ID == other.ID; + + if (OnlineBeatmapSetID.HasValue && other.OnlineBeatmapSetID.HasValue) + return OnlineBeatmapSetID == other.OnlineBeatmapSetID; + + if (!string.IsNullOrEmpty(Hash) && !string.IsNullOrEmpty(other.Hash)) + return Hash == other.Hash; + + return ReferenceEquals(this, other); } } } From 40fc655b50244d0b0d588abb1b97f3ae9cbde831 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Thu, 17 Oct 2019 01:19:50 +0300 Subject: [PATCH 73/80] Add equality check test to ensure correct values --- .../NonVisual/BeatmapSetInfoEqualityTest.cs | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 osu.Game.Tests/NonVisual/BeatmapSetInfoEqualityTest.cs diff --git a/osu.Game.Tests/NonVisual/BeatmapSetInfoEqualityTest.cs b/osu.Game.Tests/NonVisual/BeatmapSetInfoEqualityTest.cs new file mode 100644 index 0000000000..42a3b4cf43 --- /dev/null +++ b/osu.Game.Tests/NonVisual/BeatmapSetInfoEqualityTest.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 NUnit.Framework; +using osu.Game.Beatmaps; + +namespace osu.Game.Tests.NonVisual +{ + [TestFixture] + public class BeatmapSetInfoEqualityTest + { + [Test] + public void TestOnlineWithOnline() + { + var ourInfo = new BeatmapSetInfo { OnlineBeatmapSetID = 123 }; + var otherInfo = new BeatmapSetInfo { OnlineBeatmapSetID = 123 }; + + Assert.AreEqual(ourInfo, otherInfo); + } + + [Test] + public void TestDatabasedWithDatabased() + { + var ourInfo = new BeatmapSetInfo { ID = 123 }; + var otherInfo = new BeatmapSetInfo { ID = 123 }; + + Assert.AreEqual(ourInfo, otherInfo); + } + + [Test] + public void TestDatabasedWithOnline() + { + var ourInfo = new BeatmapSetInfo { ID = 123, OnlineBeatmapSetID = 12 }; + var otherInfo = new BeatmapSetInfo { OnlineBeatmapSetID = 12 }; + + Assert.AreEqual(ourInfo, otherInfo); + } + + [Test] + public void TestCheckNullID() + { + var ourInfo = new BeatmapSetInfo { Status = BeatmapSetOnlineStatus.Loved }; + var otherInfo = new BeatmapSetInfo { Status = BeatmapSetOnlineStatus.Approved }; + + Assert.AreNotEqual(ourInfo, otherInfo); + } + } +} From 9b9138253c13ba60fbb16f1735b1749722e7324a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 17 Oct 2019 11:27:23 +0900 Subject: [PATCH 74/80] Remove finalizer --- osu.Game/Rulesets/RulesetStore.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/osu.Game/Rulesets/RulesetStore.cs b/osu.Game/Rulesets/RulesetStore.cs index 0e6e0b8676..23988ff0ff 100644 --- a/osu.Game/Rulesets/RulesetStore.cs +++ b/osu.Game/Rulesets/RulesetStore.cs @@ -165,11 +165,6 @@ namespace osu.Game.Rulesets } } - ~RulesetStore() - { - Dispose(false); - } - public void Dispose() { Dispose(true); From f92331531c6e183a4644a423d20b6e9df17df2cc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 17 Oct 2019 15:32:02 +0900 Subject: [PATCH 75/80] Rename grid to DistanceSnap to be more in line with its purpose --- ...SnapGrid.cs => TestSceneOsuDistanceSnapGrid.cs} | 12 ++++++------ .../{OsuBeatSnapGrid.cs => OsuDistanceSnapGrid.cs} | 4 ++-- ...eatSnapGrid.cs => TestSceneDistanceSnapGrid.cs} | 14 +++++++------- ...BeatSnapGrid.cs => CircularDistanceSnapGrid.cs} | 4 ++-- .../{BeatSnapGrid.cs => DistanceSnapGrid.cs} | 13 ++++++++----- 5 files changed, 25 insertions(+), 22 deletions(-) rename osu.Game.Rulesets.Osu.Tests/{TestSceneOsuBeatSnapGrid.cs => TestSceneOsuDistanceSnapGrid.cs} (94%) rename osu.Game.Rulesets.Osu/Edit/{OsuBeatSnapGrid.cs => OsuDistanceSnapGrid.cs} (90%) rename osu.Game.Tests/Visual/Editor/{TestSceneBeatSnapGrid.cs => TestSceneDistanceSnapGrid.cs} (93%) rename osu.Game/Screens/Edit/Compose/Components/{CircularBeatSnapGrid.cs => CircularDistanceSnapGrid.cs} (92%) rename osu.Game/Screens/Edit/Compose/Components/{BeatSnapGrid.cs => DistanceSnapGrid.cs} (92%) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuBeatSnapGrid.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuDistanceSnapGrid.cs similarity index 94% rename from osu.Game.Rulesets.Osu.Tests/TestSceneOsuBeatSnapGrid.cs rename to osu.Game.Rulesets.Osu.Tests/TestSceneOsuDistanceSnapGrid.cs index 7399f12372..da7708081b 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuBeatSnapGrid.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuDistanceSnapGrid.cs @@ -20,7 +20,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Tests { - public class TestSceneOsuBeatSnapGrid : ManualInputManagerTestScene + public class TestSceneOsuDistanceSnapGrid : ManualInputManagerTestScene { private const double beat_length = 100; private static readonly Vector2 grid_position = new Vector2(512, 384); @@ -31,9 +31,9 @@ namespace osu.Game.Rulesets.Osu.Tests [Cached] private readonly BindableBeatDivisor beatDivisor = new BindableBeatDivisor(); - private TestOsuBeatSnapGrid grid; + private TestOsuDistanceSnapGrid grid; - public TestSceneOsuBeatSnapGrid() + public TestSceneOsuDistanceSnapGrid() { editorBeatmap = new EditorBeatmap(new OsuBeatmap()); @@ -152,7 +152,7 @@ namespace osu.Game.Rulesets.Osu.Tests RelativeSizeAxes = Axes.Both, Colour = Color4.SlateGray }, - grid = new TestOsuBeatSnapGrid(new HitCircle { Position = grid_position }), + grid = new TestOsuDistanceSnapGrid(new HitCircle { Position = grid_position }), new SnappingCursorContainer { GetSnapPosition = v => grid.GetSnapPosition(grid.ToLocalSpace(v)) } }; }); @@ -197,11 +197,11 @@ namespace osu.Game.Rulesets.Osu.Tests } } - private class TestOsuBeatSnapGrid : OsuBeatSnapGrid + private class TestOsuDistanceSnapGrid : OsuDistanceSnapGrid { public new float DistanceSpacing => base.DistanceSpacing; - public TestOsuBeatSnapGrid(OsuHitObject hitObject) + public TestOsuDistanceSnapGrid(OsuHitObject hitObject) : base(hitObject) { } diff --git a/osu.Game.Rulesets.Osu/Edit/OsuBeatSnapGrid.cs b/osu.Game.Rulesets.Osu/Edit/OsuDistanceSnapGrid.cs similarity index 90% rename from osu.Game.Rulesets.Osu/Edit/OsuBeatSnapGrid.cs rename to osu.Game.Rulesets.Osu/Edit/OsuDistanceSnapGrid.cs index d453e3d062..558993f8b2 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuBeatSnapGrid.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuDistanceSnapGrid.cs @@ -8,14 +8,14 @@ using osu.Game.Screens.Edit.Compose.Components; namespace osu.Game.Rulesets.Osu.Edit { - public class OsuBeatSnapGrid : CircularBeatSnapGrid + public class OsuDistanceSnapGrid : CircularDistanceSnapGrid { /// /// Scoring distance with a speed-adjusted beat length of 1 second. /// private const float base_scoring_distance = 100; - public OsuBeatSnapGrid(OsuHitObject hitObject) + public OsuDistanceSnapGrid(OsuHitObject hitObject) : base(hitObject, hitObject.StackedEndPosition) { } diff --git a/osu.Game.Tests/Visual/Editor/TestSceneBeatSnapGrid.cs b/osu.Game.Tests/Visual/Editor/TestSceneDistanceSnapGrid.cs similarity index 93% rename from osu.Game.Tests/Visual/Editor/TestSceneBeatSnapGrid.cs rename to osu.Game.Tests/Visual/Editor/TestSceneDistanceSnapGrid.cs index 073cec7315..a9e5930478 100644 --- a/osu.Game.Tests/Visual/Editor/TestSceneBeatSnapGrid.cs +++ b/osu.Game.Tests/Visual/Editor/TestSceneDistanceSnapGrid.cs @@ -19,7 +19,7 @@ using osuTK.Graphics; namespace osu.Game.Tests.Visual.Editor { - public class TestSceneBeatSnapGrid : EditorClockTestScene + public class TestSceneDistanceSnapGrid : EditorClockTestScene { private const double beat_length = 100; private static readonly Vector2 grid_position = new Vector2(512, 384); @@ -27,9 +27,9 @@ namespace osu.Game.Tests.Visual.Editor [Cached(typeof(IEditorBeatmap))] private readonly EditorBeatmap editorBeatmap; - private TestBeatSnapGrid grid; + private TestDistanceSnapGrid grid; - public TestSceneBeatSnapGrid() + public TestSceneDistanceSnapGrid() { editorBeatmap = new EditorBeatmap(new OsuBeatmap()); editorBeatmap.ControlPointInfo.TimingPoints.Add(new TimingControlPoint { BeatLength = beat_length }); @@ -112,7 +112,7 @@ namespace osu.Game.Tests.Visual.Editor AddAssert("snap time is now 0.5 beats away", () => Precision.AlmostEquals(beat_length / 2, grid.GetSnapTime(snapPosition), 0.01)); } - private void createGrid(Action func = null, string description = null) + private void createGrid(Action func = null, string description = null) { AddStep($"create grid {description ?? string.Empty}", () => { @@ -123,20 +123,20 @@ namespace osu.Game.Tests.Visual.Editor RelativeSizeAxes = Axes.Both, Colour = Color4.SlateGray }, - grid = new TestBeatSnapGrid(new HitObject(), grid_position) + grid = new TestDistanceSnapGrid(new HitObject(), grid_position) }; func?.Invoke(grid); }); } - private class TestBeatSnapGrid : BeatSnapGrid + private class TestDistanceSnapGrid : DistanceSnapGrid { public new float Velocity = 1; public new float DistanceSpacing => base.DistanceSpacing; - public TestBeatSnapGrid(HitObject hitObject, Vector2 centrePosition) + public TestDistanceSnapGrid(HitObject hitObject, Vector2 centrePosition) : base(hitObject, centrePosition) { } diff --git a/osu.Game/Screens/Edit/Compose/Components/CircularBeatSnapGrid.cs b/osu.Game/Screens/Edit/Compose/Components/CircularDistanceSnapGrid.cs similarity index 92% rename from osu.Game/Screens/Edit/Compose/Components/CircularBeatSnapGrid.cs rename to osu.Game/Screens/Edit/Compose/Components/CircularDistanceSnapGrid.cs index 5e378f8393..3cbf926d4f 100644 --- a/osu.Game/Screens/Edit/Compose/Components/CircularBeatSnapGrid.cs +++ b/osu.Game/Screens/Edit/Compose/Components/CircularDistanceSnapGrid.cs @@ -9,9 +9,9 @@ using osuTK; namespace osu.Game.Screens.Edit.Compose.Components { - public abstract class CircularBeatSnapGrid : BeatSnapGrid + public abstract class CircularDistanceSnapGrid : DistanceSnapGrid { - protected CircularBeatSnapGrid(HitObject hitObject, Vector2 centrePosition) + protected CircularDistanceSnapGrid(HitObject hitObject, Vector2 centrePosition) : base(hitObject, centrePosition) { } diff --git a/osu.Game/Screens/Edit/Compose/Components/BeatSnapGrid.cs b/osu.Game/Screens/Edit/Compose/Components/DistanceSnapGrid.cs similarity index 92% rename from osu.Game/Screens/Edit/Compose/Components/BeatSnapGrid.cs rename to osu.Game/Screens/Edit/Compose/Components/DistanceSnapGrid.cs index 9040843144..299e78b7c0 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BeatSnapGrid.cs +++ b/osu.Game/Screens/Edit/Compose/Components/DistanceSnapGrid.cs @@ -15,7 +15,10 @@ using osuTK; namespace osu.Game.Screens.Edit.Compose.Components { - public abstract class BeatSnapGrid : CompositeDrawable + /// + /// A grid which takes user input and returns a quantized ("snapped") position and time. + /// + public abstract class DistanceSnapGrid : CompositeDrawable { /// /// The velocity of the beatmap at the point of placement in pixels per millisecond. @@ -48,7 +51,7 @@ namespace osu.Game.Screens.Edit.Compose.Components private double startTime; private double beatLength; - protected BeatSnapGrid(HitObject hitObject, Vector2 centrePosition) + protected DistanceSnapGrid(HitObject hitObject, Vector2 centrePosition) { this.hitObject = hitObject; this.CentrePosition = centrePosition; @@ -114,14 +117,14 @@ namespace osu.Game.Screens.Edit.Compose.Components /// /// Snaps a position to this grid. /// - /// The original position in coordinate space local to this . - /// The snapped position in coordinate space local to this . + /// The original position in coordinate space local to this . + /// The snapped position in coordinate space local to this . public abstract Vector2 GetSnapPosition(Vector2 position); /// /// Retrieves the time at a snapped position. /// - /// The snapped position in coordinate space local to this . + /// The snapped position in coordinate space local to this . /// The time at the snapped position. public double GetSnapTime(Vector2 position) => startTime + (position - CentrePosition).Length / Velocity; From f3ed71d3361bd1eb81e23432e457f93c54caa3db Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 17 Oct 2019 16:36:47 +0900 Subject: [PATCH 76/80] Move scoring distance constant to a central/shared location --- osu.Game.Rulesets.Osu/Edit/OsuDistanceSnapGrid.cs | 7 +------ osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs | 8 ++++++++ osu.Game.Rulesets.Osu/Objects/Slider.cs | 7 +------ 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/OsuDistanceSnapGrid.cs b/osu.Game.Rulesets.Osu/Edit/OsuDistanceSnapGrid.cs index 558993f8b2..f701712739 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuDistanceSnapGrid.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuDistanceSnapGrid.cs @@ -10,11 +10,6 @@ namespace osu.Game.Rulesets.Osu.Edit { public class OsuDistanceSnapGrid : CircularDistanceSnapGrid { - /// - /// Scoring distance with a speed-adjusted beat length of 1 second. - /// - private const float base_scoring_distance = 100; - public OsuDistanceSnapGrid(OsuHitObject hitObject) : base(hitObject, hitObject.StackedEndPosition) { @@ -25,7 +20,7 @@ namespace osu.Game.Rulesets.Osu.Edit TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(time); DifficultyControlPoint difficultyPoint = controlPointInfo.DifficultyPointAt(time); - double scoringDistance = base_scoring_distance * difficulty.SliderMultiplier * difficultyPoint.SpeedMultiplier; + double scoringDistance = OsuHitObject.BASE_SCORING_DISTANCE * difficulty.SliderMultiplier * difficultyPoint.SpeedMultiplier; return (float)(scoringDistance / timingPoint.BeatLength); } diff --git a/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs b/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs index 80e013fe68..b506c1f918 100644 --- a/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs +++ b/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs @@ -14,8 +14,16 @@ namespace osu.Game.Rulesets.Osu.Objects { public abstract class OsuHitObject : HitObject, IHasComboInformation, IHasPosition { + /// + /// The radius of hit objects (ie. the radius of a ). + /// public const float OBJECT_RADIUS = 64; + /// + /// Scoring distance with a speed-adjusted beat length of 1 second (ie. the speed slider balls move through their track). + /// + internal const float BASE_SCORING_DISTANCE = 100; + public double TimePreempt = 600; public double TimeFadeIn = 400; diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index 9bed123465..d98d72331a 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -19,11 +19,6 @@ namespace osu.Game.Rulesets.Osu.Objects { public class Slider : OsuHitObject, IHasCurve { - /// - /// Scoring distance with a speed-adjusted beat length of 1 second. - /// - private const float base_scoring_distance = 100; - public double EndTime => StartTime + this.SpanCount() * Path.Distance / Velocity; public double Duration => EndTime - StartTime; @@ -123,7 +118,7 @@ namespace osu.Game.Rulesets.Osu.Objects TimingControlPoint timingPoint = controlPointInfo.TimingPointAt(StartTime); DifficultyControlPoint difficultyPoint = controlPointInfo.DifficultyPointAt(StartTime); - double scoringDistance = base_scoring_distance * difficulty.SliderMultiplier * difficultyPoint.SpeedMultiplier; + double scoringDistance = BASE_SCORING_DISTANCE * difficulty.SliderMultiplier * difficultyPoint.SpeedMultiplier; Velocity = scoringDistance / timingPoint.BeatLength; TickDistance = scoringDistance / difficulty.SliderTickRate * TickDistanceMultiplier; From c4cc960e1564944a18964c606b2b64b8f4d927de Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 17 Oct 2019 18:00:15 +0900 Subject: [PATCH 77/80] Fix mania hitobject selections not moving correctly --- .../Edit/ManiaSelectionHandler.cs | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs b/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs index f576c43e52..2fba0639da 100644 --- a/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs +++ b/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs @@ -65,24 +65,27 @@ namespace osu.Game.Rulesets.Mania.Edit private void performDragMovement(MoveSelectionEvent moveEvent) { + float delta = moveEvent.InstantDelta.Y; + + // When scrolling downwards the anchor position is at the bottom of the screen, however the movement event assumes the anchor is at the top of the screen. + // This causes the delta to assume a positive hitobject position, and which can be corrected for by subtracting the parent height. + if (scrollingInfo.Direction.Value == ScrollingDirection.Down) + delta -= moveEvent.Blueprint.HitObject.Parent.DrawHeight; + foreach (var b in SelectedBlueprints) { var hitObject = b.HitObject; - var objectParent = (HitObjectContainer)hitObject.Parent; - // Using the hitobject position is required since AdjustPosition can be invoked multiple times per frame - // without the position having been updated by the parenting ScrollingHitObjectContainer - hitObject.Y += moveEvent.InstantDelta.Y; + // StartTime could be used to adjust the position if only one movement event was received per frame. + // However this is not the case and ScrollingHitObjectContainer performs movement in UpdateAfterChildren() so the position must also be updated to be valid for further movement events + hitObject.Y += delta; - float targetPosition; + float targetPosition = hitObject.Position.Y; - // If we're scrolling downwards, a position of 0 is actually further away from the hit target - // so we need to flip the vertical coordinate in the hitobject container's space + // The scrolling algorithm always assumes an anchor at the top of the screen, so the position must be flipped when scrolling downwards to reflect a top anchor if (scrollingInfo.Direction.Value == ScrollingDirection.Down) - targetPosition = -hitObject.Position.Y; - else - targetPosition = hitObject.Position.Y; + targetPosition = -targetPosition; objectParent.Remove(hitObject); From 6b0976ff1e2e1d13747f0e6a06114ff52b056b26 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 15 Oct 2019 15:07:06 +0900 Subject: [PATCH 78/80] Remove a weird unicode charcter from file --- osu.Game/Overlays/AccountCreation/ScreenWarning.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/AccountCreation/ScreenWarning.cs b/osu.Game/Overlays/AccountCreation/ScreenWarning.cs index be417f4aac..f91d2e3323 100644 --- a/osu.Game/Overlays/AccountCreation/ScreenWarning.cs +++ b/osu.Game/Overlays/AccountCreation/ScreenWarning.cs @@ -121,7 +121,7 @@ namespace osu.Game.Overlays.AccountCreation multiAccountExplanationText.AddText("? osu! has a policy of "); multiAccountExplanationText.AddText("one account per person!", cp => cp.Colour = colours.Yellow); multiAccountExplanationText.AddText(" Please be aware that creating more than one account per person may result in "); - multiAccountExplanationText.AddText("permanent deactivation of accounts", cp => cp.Colour = colours.Yellow); + multiAccountExplanationText.AddText("permanent deactivation of accounts", cp => cp.Colour = colours.Yellow); multiAccountExplanationText.AddText("."); furtherAssistance.AddText("Need further assistance? Contact us via our "); From 89f50b26f72f56f932df01a99f94f93de621da8e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 18 Oct 2019 17:32:11 +0900 Subject: [PATCH 79/80] Fix hitobject combo colour potentially not getting adjusted --- .../TestSceneHitObjectAccentColour.cs | 143 ++++++++++++++++++ .../Objects/Drawables/DrawableHitObject.cs | 2 +- 2 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs diff --git a/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs b/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs new file mode 100644 index 0000000000..6d7159a825 --- /dev/null +++ b/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs @@ -0,0 +1,143 @@ +// 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 System.Collections.Generic; +using NUnit.Framework; +using osu.Framework.Audio.Sample; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Textures; +using osu.Framework.Testing; +using osu.Game.Audio; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Objects.Types; +using osu.Game.Skinning; +using osu.Game.Tests.Visual; +using osuTK.Graphics; + +namespace osu.Game.Tests.Gameplay +{ + [HeadlessTest] + public class TestSceneHitObjectAccentColour : OsuTestScene + { + private Container skinContainer; + + [SetUp] + public void Setup() => Schedule(() => Child = skinContainer = new SkinProvidingContainer(new TestSkin())); + + [Test] + public void TestChangeComboIndexBeforeLoad() + { + TestDrawableHitObject hitObject = null; + + AddStep("set combo and add hitobject", () => + { + hitObject = new TestDrawableHitObject(); + hitObject.HitObject.ComboIndex = 1; + + skinContainer.Add(hitObject); + }); + + AddAssert("combo colour is green", () => hitObject.AccentColour.Value == Color4.Green); + } + + [Test] + public void TestChangeComboIndexDuringLoad() + { + TestDrawableHitObject hitObject = null; + + AddStep("add hitobject and set combo", () => + { + skinContainer.Add(hitObject = new TestDrawableHitObject()); + hitObject.HitObject.ComboIndex = 1; + }); + + AddAssert("combo colour is green", () => hitObject.AccentColour.Value == Color4.Green); + } + + [Test] + public void TestChangeComboIndexAfterLoad() + { + TestDrawableHitObject hitObject = null; + + AddStep("add hitobject", () => skinContainer.Add(hitObject = new TestDrawableHitObject())); + AddAssert("combo colour is red", () => hitObject.AccentColour.Value == Color4.Red); + + AddStep("change combo", () => hitObject.HitObject.ComboIndex = 1); + AddAssert("combo colour is green", () => hitObject.AccentColour.Value == Color4.Green); + } + + private class TestDrawableHitObject : DrawableHitObject + { + public TestDrawableHitObject() + : base(new TestHitObjectWithCombo()) + { + } + } + + private class TestHitObjectWithCombo : HitObject, IHasComboInformation + { + public bool NewCombo { get; } = false; + public int ComboOffset { get; } = 0; + + public Bindable IndexInCurrentComboBindable { get; } = new Bindable(); + + public int IndexInCurrentCombo + { + get => IndexInCurrentComboBindable.Value; + set => IndexInCurrentComboBindable.Value = value; + } + + public Bindable ComboIndexBindable { get; } = new Bindable(); + + public int ComboIndex + { + get => ComboIndexBindable.Value; + set => ComboIndexBindable.Value = value; + } + + public Bindable LastInComboBindable { get; } = new Bindable(); + + public bool LastInCombo + { + get => LastInComboBindable.Value; + set => LastInComboBindable.Value = value; + } + } + + private class TestSkin : ISkin + { + public readonly List ComboColours = new List + { + Color4.Red, + Color4.Green + }; + + public Drawable GetDrawableComponent(ISkinComponent component) => throw new NotImplementedException(); + + public Texture GetTexture(string componentName) => throw new NotImplementedException(); + + public SampleChannel GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException(); + + public IBindable GetConfig(TLookup lookup) + { + switch (lookup) + { + case GlobalSkinConfiguration global: + switch (global) + { + case GlobalSkinConfiguration.ComboColours: + return SkinUtils.As(new Bindable>(ComboColours)); + } + + break; + } + + throw new NotImplementedException(); + } + } + } +} diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 7f3bfd3b5c..0948452ceb 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -128,7 +128,7 @@ namespace osu.Game.Rulesets.Objects.Drawables if (HitObject is IHasComboInformation combo) { comboIndexBindable = combo.ComboIndexBindable.GetBoundCopy(); - comboIndexBindable.BindValueChanged(_ => updateAccentColour()); + comboIndexBindable.BindValueChanged(_ => updateAccentColour(), true); } updateState(ArmedState.Idle, true); From 07286c0cfc106dfd49fb8370bfe5490ed2bb597f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 18 Oct 2019 18:21:53 +0900 Subject: [PATCH 80/80] Fix editor's clock not being processed unless composer is loaded --- osu.Game/Rulesets/Edit/HitObjectComposer.cs | 3 ++- osu.Game/Screens/Edit/Editor.cs | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Edit/HitObjectComposer.cs b/osu.Game/Rulesets/Edit/HitObjectComposer.cs index a267d7c44d..038d6a320a 100644 --- a/osu.Game/Rulesets/Edit/HitObjectComposer.cs +++ b/osu.Game/Rulesets/Edit/HitObjectComposer.cs @@ -57,7 +57,8 @@ namespace osu.Game.Rulesets.Edit { drawableRulesetWrapper = new DrawableEditRulesetWrapper(CreateDrawableRuleset(Ruleset, workingBeatmap, Array.Empty())) { - Clock = framedClock + Clock = framedClock, + ProcessCustomClock = false }; } catch (Exception e) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 7f08c2f8b9..35408e4003 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -173,6 +173,12 @@ namespace osu.Game.Screens.Edit bottomBackground.Colour = colours.Gray2; } + protected override void Update() + { + base.Update(); + clock.ProcessFrame(); + } + protected override bool OnKeyDown(KeyDownEvent e) { switch (e.Key)