mirror of
https://github.com/ppy/osu.git
synced 2024-11-06 06:57:39 +08:00
Remove CommentsPage component
This commit is contained in:
parent
f1c97451d9
commit
56c41a614a
@ -27,8 +27,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
typeof(OverlaySortTabControl<>),
|
||||
typeof(ShowChildrenButton),
|
||||
typeof(DeletedCommentsCounter),
|
||||
typeof(VotePill),
|
||||
typeof(CommentsPage),
|
||||
typeof(VotePill)
|
||||
};
|
||||
|
||||
protected override bool UseOnlineAPI => true;
|
||||
|
@ -1,232 +0,0 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Game.Overlays.Comments;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Users;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics;
|
||||
using osuTK;
|
||||
using JetBrains.Annotations;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Online
|
||||
{
|
||||
public class TestSceneCommentsPage : OsuTestScene
|
||||
{
|
||||
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||
{
|
||||
typeof(DrawableComment),
|
||||
typeof(CommentsPage),
|
||||
};
|
||||
|
||||
[Cached]
|
||||
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple);
|
||||
|
||||
private readonly BindableBool showDeleted = new BindableBool();
|
||||
private readonly Container content;
|
||||
|
||||
private TestCommentsPage commentsPage;
|
||||
|
||||
public TestSceneCommentsPage()
|
||||
{
|
||||
Add(new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Y,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Direction = FillDirection.Vertical,
|
||||
Spacing = new Vector2(0, 10),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Container
|
||||
{
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Width = 200,
|
||||
Child = new OsuCheckbox
|
||||
{
|
||||
Current = showDeleted,
|
||||
LabelText = @"Show Deleted"
|
||||
}
|
||||
},
|
||||
content = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestAppendDuplicatedComment()
|
||||
{
|
||||
AddStep("Create page", () => createPage(getCommentBundle()));
|
||||
AddAssert("Dictionary length is 10", () => commentsPage?.DictionaryLength == 10);
|
||||
AddStep("Append existing comment", () => commentsPage?.AppendComments(getCommentSubBundle()));
|
||||
AddAssert("Dictionary length is 10", () => commentsPage?.DictionaryLength == 10);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestEmptyBundle()
|
||||
{
|
||||
AddStep("Create page", () => createPage(getEmptyCommentBundle()));
|
||||
AddAssert("Dictionary length is 0", () => commentsPage?.DictionaryLength == 0);
|
||||
}
|
||||
|
||||
private void createPage(CommentBundle commentBundle)
|
||||
{
|
||||
commentsPage = null;
|
||||
content.Clear();
|
||||
content.Add(commentsPage = new TestCommentsPage(commentBundle)
|
||||
{
|
||||
ShowDeleted = { BindTarget = showDeleted }
|
||||
});
|
||||
}
|
||||
|
||||
private CommentBundle getEmptyCommentBundle() => new CommentBundle
|
||||
{
|
||||
Comments = new List<Comment>(),
|
||||
};
|
||||
|
||||
private CommentBundle getCommentBundle() => new CommentBundle
|
||||
{
|
||||
Comments = new List<Comment>
|
||||
{
|
||||
new Comment
|
||||
{
|
||||
Id = 1,
|
||||
Message = "Simple test comment",
|
||||
LegacyName = "TestUser1",
|
||||
CreatedAt = DateTimeOffset.Now,
|
||||
VotesCount = 5
|
||||
},
|
||||
new Comment
|
||||
{
|
||||
Id = 100,
|
||||
Message = "This comment has \"load replies\" button because it has unloaded replies",
|
||||
LegacyName = "TestUser1100",
|
||||
CreatedAt = DateTimeOffset.Now,
|
||||
VotesCount = 5,
|
||||
RepliesCount = 2,
|
||||
},
|
||||
new Comment
|
||||
{
|
||||
Id = 111,
|
||||
Message = "This comment has \"Show More\" button because it has unloaded replies, but some of them are loaded",
|
||||
LegacyName = "TestUser1111",
|
||||
CreatedAt = DateTimeOffset.Now,
|
||||
VotesCount = 100,
|
||||
RepliesCount = 2,
|
||||
},
|
||||
new Comment
|
||||
{
|
||||
Id = 112,
|
||||
ParentId = 111,
|
||||
Message = "I'm here to make my parent work",
|
||||
LegacyName = "someone",
|
||||
CreatedAt = DateTimeOffset.Now,
|
||||
VotesCount = 2,
|
||||
},
|
||||
new Comment
|
||||
{
|
||||
Id = 2,
|
||||
Message = "This comment has been deleted :( but visible for admins",
|
||||
LegacyName = "TestUser2",
|
||||
CreatedAt = DateTimeOffset.Now,
|
||||
DeletedAt = DateTimeOffset.Now,
|
||||
VotesCount = 5
|
||||
},
|
||||
new Comment
|
||||
{
|
||||
Id = 3,
|
||||
Message = "This comment is a top level",
|
||||
LegacyName = "TestUser3",
|
||||
CreatedAt = DateTimeOffset.Now,
|
||||
RepliesCount = 2,
|
||||
},
|
||||
new Comment
|
||||
{
|
||||
Id = 4,
|
||||
ParentId = 3,
|
||||
Message = "And this is a reply",
|
||||
RepliesCount = 1,
|
||||
LegacyName = "TestUser1",
|
||||
CreatedAt = DateTimeOffset.Now,
|
||||
},
|
||||
new Comment
|
||||
{
|
||||
Id = 15,
|
||||
ParentId = 4,
|
||||
Message = "Reply to reply",
|
||||
LegacyName = "TestUser1",
|
||||
CreatedAt = DateTimeOffset.Now,
|
||||
},
|
||||
new Comment
|
||||
{
|
||||
Id = 6,
|
||||
ParentId = 3,
|
||||
LegacyName = "TestUser11515",
|
||||
CreatedAt = DateTimeOffset.Now,
|
||||
DeletedAt = DateTimeOffset.Now,
|
||||
},
|
||||
new Comment
|
||||
{
|
||||
Id = 5,
|
||||
Message = "This comment is voted and edited",
|
||||
LegacyName = "BigBrainUser",
|
||||
CreatedAt = DateTimeOffset.Now,
|
||||
EditedAt = DateTimeOffset.Now,
|
||||
VotesCount = 1000,
|
||||
EditedById = 1,
|
||||
}
|
||||
},
|
||||
IncludedComments = new List<Comment>(),
|
||||
UserVotes = new List<long>
|
||||
{
|
||||
5
|
||||
},
|
||||
Users = new List<User>
|
||||
{
|
||||
new User
|
||||
{
|
||||
Id = 1,
|
||||
Username = "Good_Admin"
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
private CommentBundle getCommentSubBundle() => new CommentBundle
|
||||
{
|
||||
Comments = new List<Comment>
|
||||
{
|
||||
new Comment
|
||||
{
|
||||
Id = 1,
|
||||
Message = "Simple test comment",
|
||||
LegacyName = "TestUser1",
|
||||
CreatedAt = DateTimeOffset.Now,
|
||||
VotesCount = 5
|
||||
},
|
||||
},
|
||||
IncludedComments = new List<Comment>(),
|
||||
};
|
||||
|
||||
private class TestCommentsPage : CommentsPage
|
||||
{
|
||||
public TestCommentsPage(CommentBundle commentBundle)
|
||||
: base(commentBundle)
|
||||
{
|
||||
}
|
||||
|
||||
public new void AppendComments([NotNull] CommentBundle bundle) => base.AppendComments(bundle);
|
||||
|
||||
public int DictionaryLength => CommentDictionary.Count;
|
||||
}
|
||||
}
|
||||
}
|
@ -9,10 +9,12 @@ using osu.Framework.Graphics;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using System.Threading;
|
||||
using System.Linq;
|
||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||
using osu.Game.Users;
|
||||
using System.Collections.Generic;
|
||||
using JetBrains.Annotations;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
|
||||
namespace osu.Game.Overlays.Comments
|
||||
{
|
||||
@ -30,7 +32,6 @@ namespace osu.Game.Overlays.Comments
|
||||
private IAPIProvider api { get; set; }
|
||||
|
||||
private GetCommentsRequest request;
|
||||
private CancellationTokenSource loadCancellation;
|
||||
private int currentPage;
|
||||
|
||||
private FillFlowContainer content;
|
||||
@ -151,9 +152,8 @@ namespace osu.Game.Overlays.Comments
|
||||
return;
|
||||
|
||||
request?.Cancel();
|
||||
loadCancellation?.Cancel();
|
||||
request = new GetCommentsRequest(id.Value, type.Value, Sort.Value, currentPage++, 0);
|
||||
request.Success += onSuccess;
|
||||
request.Success += response => Schedule(() => onSuccess(response));
|
||||
api.PerformAsync(request);
|
||||
}
|
||||
|
||||
@ -166,44 +166,132 @@ namespace osu.Game.Overlays.Comments
|
||||
content.Clear();
|
||||
}
|
||||
|
||||
private readonly Dictionary<long, DrawableComment> commentDictionary = new Dictionary<long, DrawableComment>();
|
||||
|
||||
private void onSuccess(CommentBundle response)
|
||||
{
|
||||
loadCancellation = new CancellationTokenSource();
|
||||
|
||||
LoadComponentAsync(new CommentsPage(response)
|
||||
if (!response.Comments.Any())
|
||||
{
|
||||
ShowDeleted = { BindTarget = ShowDeleted },
|
||||
Sort = { BindTarget = Sort },
|
||||
Type = { BindTarget = type },
|
||||
CommentableId = { BindTarget = id }
|
||||
}, loaded =>
|
||||
content.Add(new NoCommentsPlaceholder());
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
content.Add(loaded);
|
||||
appendComments(response);
|
||||
|
||||
deletedCommentsCounter.Count.Value += response.Comments.Count(c => c.IsDeleted && c.IsTopLevel);
|
||||
}
|
||||
|
||||
if (response.HasMore)
|
||||
if (response.HasMore)
|
||||
{
|
||||
int loadedTopLevelComments = 0;
|
||||
content.Children.OfType<DrawableComment>().ForEach(p => loadedTopLevelComments++);
|
||||
|
||||
moreButton.Current.Value = response.TopLevelCount - loadedTopLevelComments;
|
||||
moreButton.IsLoading = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
moreButton.Hide();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Appends retrieved comments to the subtree rooted of comments in this page.
|
||||
/// </summary>
|
||||
/// <param name="bundle">The bundle of comments to add.</param>
|
||||
private void appendComments([NotNull] CommentBundle bundle)
|
||||
{
|
||||
var orphaned = new List<Comment>();
|
||||
|
||||
foreach (var comment in bundle.Comments.Concat(bundle.IncludedComments))
|
||||
{
|
||||
// Exclude possible duplicated comments.
|
||||
if (commentDictionary.ContainsKey(comment.Id))
|
||||
continue;
|
||||
|
||||
addNewComment(comment);
|
||||
}
|
||||
|
||||
// Comments whose parents were seen later than themselves can now be added.
|
||||
foreach (var o in orphaned)
|
||||
addNewComment(o);
|
||||
|
||||
void addNewComment(Comment comment)
|
||||
{
|
||||
var drawableComment = getDrawableComment(comment);
|
||||
|
||||
if (comment.ParentId == null)
|
||||
{
|
||||
int loadedTopLevelComments = 0;
|
||||
content.Children.OfType<FillFlowContainer>().ForEach(p => loadedTopLevelComments += p.Children.OfType<DrawableComment>().Count());
|
||||
|
||||
moreButton.Current.Value = response.TopLevelCount - loadedTopLevelComments;
|
||||
moreButton.IsLoading = false;
|
||||
// Comments that have no parent are added as top-level comments to the flow.
|
||||
content.Add(drawableComment);
|
||||
}
|
||||
else if (commentDictionary.TryGetValue(comment.ParentId.Value, out var parentDrawable))
|
||||
{
|
||||
// The comment's parent has already been seen, so the parent<-> child links can be added.
|
||||
comment.ParentComment = parentDrawable.Comment;
|
||||
parentDrawable.Replies.Add(drawableComment);
|
||||
}
|
||||
else
|
||||
{
|
||||
moreButton.Hide();
|
||||
// The comment's parent has not been seen yet, so keep it orphaned for the time being. This can occur if the comments arrive out of order.
|
||||
// Since this comment has now been seen, any further children can be added to it without being orphaned themselves.
|
||||
orphaned.Add(comment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
commentCounter.Current.Value = response.Total;
|
||||
}, loadCancellation.Token);
|
||||
private DrawableComment getDrawableComment(Comment comment)
|
||||
{
|
||||
if (commentDictionary.TryGetValue(comment.Id, out var existing))
|
||||
return existing;
|
||||
|
||||
return commentDictionary[comment.Id] = new DrawableComment(comment)
|
||||
{
|
||||
ShowDeleted = { BindTarget = ShowDeleted },
|
||||
Sort = { BindTarget = Sort },
|
||||
RepliesRequested = onCommentRepliesRequested
|
||||
};
|
||||
}
|
||||
|
||||
private void onCommentRepliesRequested(DrawableComment drawableComment, int page)
|
||||
{
|
||||
var request = new GetCommentsRequest(id.Value, type.Value, Sort.Value, page, drawableComment.Comment.Id);
|
||||
|
||||
request.Success += response => Schedule(() => appendComments(response));
|
||||
|
||||
api.PerformAsync(request);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
request?.Cancel();
|
||||
loadCancellation?.Cancel();
|
||||
base.Dispose(isDisposing);
|
||||
}
|
||||
|
||||
private class NoCommentsPlaceholder : CompositeDrawable
|
||||
{
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
Height = 80;
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AddRangeInternal(new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = colourProvider.Background4
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Margin = new MarginPadding { Left = 50 },
|
||||
Text = @"No comments yet."
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,161 +0,0 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using System.Linq;
|
||||
using osu.Game.Online.API.Requests;
|
||||
using osu.Game.Online.API;
|
||||
using System.Collections.Generic;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace osu.Game.Overlays.Comments
|
||||
{
|
||||
public class CommentsPage : CompositeDrawable
|
||||
{
|
||||
public readonly BindableBool ShowDeleted = new BindableBool();
|
||||
public readonly Bindable<CommentsSortCriteria> Sort = new Bindable<CommentsSortCriteria>();
|
||||
public readonly Bindable<CommentableType> Type = new Bindable<CommentableType>();
|
||||
public readonly BindableLong CommentableId = new BindableLong();
|
||||
|
||||
[Resolved]
|
||||
private IAPIProvider api { get; set; }
|
||||
|
||||
private readonly CommentBundle commentBundle;
|
||||
private FillFlowContainer flow;
|
||||
|
||||
public CommentsPage(CommentBundle commentBundle)
|
||||
{
|
||||
this.commentBundle = commentBundle;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
|
||||
AddRangeInternal(new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = colourProvider.Background5
|
||||
},
|
||||
flow = new FillFlowContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Vertical,
|
||||
}
|
||||
});
|
||||
|
||||
if (!commentBundle.Comments.Any())
|
||||
{
|
||||
flow.Add(new NoCommentsPlaceholder());
|
||||
return;
|
||||
}
|
||||
|
||||
AppendComments(commentBundle);
|
||||
}
|
||||
|
||||
private DrawableComment getDrawableComment(Comment comment)
|
||||
{
|
||||
if (CommentDictionary.TryGetValue(comment.Id, out var existing))
|
||||
return existing;
|
||||
|
||||
return CommentDictionary[comment.Id] = new DrawableComment(comment)
|
||||
{
|
||||
ShowDeleted = { BindTarget = ShowDeleted },
|
||||
Sort = { BindTarget = Sort },
|
||||
RepliesRequested = onCommentRepliesRequested
|
||||
};
|
||||
}
|
||||
|
||||
private void onCommentRepliesRequested(DrawableComment drawableComment, int page)
|
||||
{
|
||||
var request = new GetCommentsRequest(CommentableId.Value, Type.Value, Sort.Value, page, drawableComment.Comment.Id);
|
||||
|
||||
request.Success += response => Schedule(() => AppendComments(response));
|
||||
|
||||
api.PerformAsync(request);
|
||||
}
|
||||
|
||||
protected readonly Dictionary<long, DrawableComment> CommentDictionary = new Dictionary<long, DrawableComment>();
|
||||
|
||||
/// <summary>
|
||||
/// Appends retrieved comments to the subtree rooted of comments in this page.
|
||||
/// </summary>
|
||||
/// <param name="bundle">The bundle of comments to add.</param>
|
||||
protected void AppendComments([NotNull] CommentBundle bundle)
|
||||
{
|
||||
var orphaned = new List<Comment>();
|
||||
|
||||
foreach (var comment in bundle.Comments.Concat(bundle.IncludedComments))
|
||||
{
|
||||
// Exclude possible duplicated comments.
|
||||
if (CommentDictionary.ContainsKey(comment.Id))
|
||||
continue;
|
||||
|
||||
addNewComment(comment);
|
||||
}
|
||||
|
||||
// Comments whose parents were seen later than themselves can now be added.
|
||||
foreach (var o in orphaned)
|
||||
addNewComment(o);
|
||||
|
||||
void addNewComment(Comment comment)
|
||||
{
|
||||
var drawableComment = getDrawableComment(comment);
|
||||
|
||||
if (comment.ParentId == null)
|
||||
{
|
||||
// Comments that have no parent are added as top-level comments to the flow.
|
||||
flow.Add(drawableComment);
|
||||
}
|
||||
else if (CommentDictionary.TryGetValue(comment.ParentId.Value, out var parentDrawable))
|
||||
{
|
||||
// The comment's parent has already been seen, so the parent<-> child links can be added.
|
||||
comment.ParentComment = parentDrawable.Comment;
|
||||
parentDrawable.Replies.Add(drawableComment);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The comment's parent has not been seen yet, so keep it orphaned for the time being. This can occur if the comments arrive out of order.
|
||||
// Since this comment has now been seen, any further children can be added to it without being orphaned themselves.
|
||||
orphaned.Add(comment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class NoCommentsPlaceholder : CompositeDrawable
|
||||
{
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
Height = 80;
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AddRangeInternal(new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = colourProvider.Background4
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Margin = new MarginPadding { Left = 50 },
|
||||
Text = @"No comments yet."
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user