osu/osu.Game/Overlays/Comments/DrawableComment.cs

364 lines
14 KiB
C#
Raw Normal View History

// 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.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;
2019-10-08 16:09:02 +00:00
using osu.Framework.Graphics.Cursor;
2019-10-08 16:18:46 +00:00
using osu.Framework.Bindables;
2019-10-08 16:56:43 +00:00
using osu.Framework.Graphics.Shapes;
using osuTK.Graphics;
2019-10-09 08:07:56 +00:00
using System.Linq;
namespace osu.Game.Overlays.Comments
{
public class DrawableComment : CompositeDrawable
{
private const int avatar_size = 40;
private const int margin = 10;
2019-10-08 12:39:03 +00:00
private const int child_margin = 20;
2019-10-09 08:07:56 +00:00
private const int chevron_margin = 30;
private const int message_padding = 40;
2019-10-08 13:00:34 +00:00
private const int duration = 200;
2019-10-09 09:18:49 +00:00
private const float separator_height = 1.5f;
public readonly BindableBool ShowDeleted = new BindableBool();
2019-10-08 13:00:34 +00:00
2019-10-08 16:18:46 +00:00
private readonly BindableBool childExpanded = new BindableBool(true);
2019-10-08 13:00:34 +00:00
private readonly Container childCommentsVisibilityContainer;
2019-10-09 09:18:49 +00:00
private readonly Comment comment;
public DrawableComment(Comment comment)
{
LinkFlowContainer username;
2019-10-08 12:39:03 +00:00
FillFlowContainer childCommentsContainer;
2019-10-09 08:32:17 +00:00
FillFlowContainer info;
2019-10-09 09:18:49 +00:00
TextFlowContainer message;
GridContainer content;
VotePill votePill;
this.comment = comment;
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;
2019-10-09 09:18:49 +00:00
Masking = true;
2019-10-08 12:39:03 +00:00
InternalChild = new FillFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
2019-10-08 12:39:03 +00:00
Direction = FillDirection.Vertical,
Children = new Drawable[]
{
2019-10-09 09:18:49 +00:00
content = new GridContainer
{
2019-10-08 12:39:03 +00:00
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Margin = new MarginPadding(margin),
ColumnDimensions = new[]
{
new Dimension(GridSizeMode.AutoSize),
new Dimension(),
},
RowDimensions = new[]
{
2019-10-08 12:39:03 +00:00
new Dimension(GridSizeMode.AutoSize)
},
2019-10-08 12:39:03 +00:00
Content = new[]
{
2019-10-08 12:39:03 +00:00
new Drawable[]
{
2019-10-08 16:56:43 +00:00
new FillFlowContainer
{
2019-10-08 16:56:43 +00:00
AutoSizeAxes = Axes.Both,
2019-10-08 12:39:03 +00:00
Margin = new MarginPadding { Horizontal = margin },
2019-10-08 16:56:43 +00:00
Direction = FillDirection.Horizontal,
Spacing = new Vector2(5, 0),
Children = new Drawable[]
{
2019-10-09 09:18:49 +00:00
votePill = new VotePill(comment.VotesCount)
2019-10-08 16:56:43 +00:00
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
2019-10-09 09:18:49 +00:00
AlwaysPresent = true,
2019-10-08 16:56:43 +00:00
},
new UpdateableAvatar(comment.User)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(avatar_size),
Masking = true,
CornerRadius = avatar_size / 2,
},
}
},
2019-10-08 12:39:03 +00:00
new FillFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
2019-10-09 09:18:49 +00:00
Spacing = new Vector2(0, 3),
2019-10-08 12:39:03 +00:00
Children = new Drawable[]
{
2019-10-09 09:18:49 +00:00
new FillFlowContainer
2019-10-08 12:39:03 +00:00
{
2019-10-09 09:18:49 +00:00
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Spacing = new Vector2(7, 0),
2019-10-08 16:09:02 +00:00
Children = new Drawable[]
{
2019-10-09 09:18:49 +00:00
username = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true))
2019-10-08 16:09:02 +00:00
{
AutoSizeAxes = Axes.Both,
},
2019-10-09 09:18:49 +00:00
new ParentUsername(comment),
new SpriteText
2019-10-09 08:07:56 +00:00
{
2019-10-09 09:18:49 +00:00
Alpha = comment.IsDeleted? 1 : 0,
Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true),
Text = @"deleted",
2019-10-09 08:07:56 +00:00
}
2019-10-08 16:09:02 +00:00
}
2019-10-08 12:39:03 +00:00
},
2019-10-09 09:18:49 +00:00
message = new TextFlowContainer(s => s.Font = OsuFont.GetFont(size: 14))
2019-10-08 12:39:03 +00:00
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
2019-10-09 08:07:56 +00:00
Padding = new MarginPadding { Right = message_padding }
2019-10-08 13:00:34 +00:00
},
2019-10-09 09:18:49 +00:00
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 } },
}
}
2019-10-08 13:00:34 +00:00
}
}
}
}
},
2019-10-08 13:00:34 +00:00
childCommentsVisibilityContainer = new Container
{
2019-10-08 12:39:03 +00:00
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
2019-10-08 13:00:34 +00:00
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
}
}
}
};
2019-10-08 19:46:42 +00:00
if (comment.UserId == null)
username.AddText(comment.LegacyName);
else
username.AddUserLink(comment.User);
2019-10-08 12:39:03 +00:00
2019-10-09 08:32:17 +00:00
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}"
});
}
2019-10-09 09:18:49 +00:00
if (!comment.IsDeleted)
message.Text = comment.GetMessage();
else
2019-10-08 12:39:03 +00:00
{
2019-10-09 09:18:49 +00:00
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)));
2019-10-08 16:18:46 +00:00
}
2019-10-08 13:00:34 +00:00
2019-10-08 16:18:46 +00:00
protected override void LoadComplete()
{
2019-10-09 09:18:49 +00:00
ShowDeleted.BindValueChanged(onShowDeletedChanged, true);
2019-10-08 16:18:46 +00:00
childExpanded.BindValueChanged(onChildExpandedChanged, true);
base.LoadComplete();
}
private void onChildExpandedChanged(ValueChangedEvent<bool> expanded)
{
childCommentsVisibilityContainer.ClearTransforms();
if (expanded.NewValue)
childCommentsVisibilityContainer.AutoSizeAxes = Axes.Y;
else
{
childCommentsVisibilityContainer.AutoSizeAxes = Axes.None;
childCommentsVisibilityContainer.ResizeHeightTo(0, duration, Easing.OutQuint);
}
2019-10-08 13:00:34 +00:00
}
2019-10-09 09:18:49 +00:00
private void onShowDeletedChanged(ValueChangedEvent<bool> show)
{
if (comment.IsDeleted)
{
if (show.NewValue)
AutoSizeAxes = Axes.Y;
else
{
AutoSizeAxes = Axes.None;
this.ResizeHeightTo(0);
}
}
}
2019-10-09 08:07:56 +00:00
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<bool> expanded)
{
icon.Icon = expanded.NewValue ? FontAwesome.Solid.ChevronUp : FontAwesome.Solid.ChevronDown;
}
}
private class RepliesButton : ShowChildsButton
2019-10-08 13:00:34 +00:00
{
private readonly SpriteText text;
private readonly int count;
public RepliesButton(int count)
{
this.count = count;
Alpha = count == 0 ? 0 : 1;
Child = text = new SpriteText
{
2019-10-08 17:44:01 +00:00
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold),
2019-10-08 13:00:34 +00:00
};
2019-10-08 16:18:46 +00:00
}
2019-10-08 13:00:34 +00:00
2019-10-09 08:07:56 +00:00
protected override void OnExpandedChanged(ValueChangedEvent<bool> expanded)
2019-10-08 16:18:46 +00:00
{
text.Text = $@"{(expanded.NewValue ? "[+]" : "[-]")} replies ({count})";
2019-10-08 13:00:34 +00:00
}
}
2019-10-08 16:09:02 +00:00
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 ?? comment.ParentComment?.LegacyName
2019-10-08 16:09:02 +00:00
}
};
}
}
2019-10-08 16:56:43 +00:00
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}"
}
};
}
}
}
}