merge: 合并 K30-C 评论面板视觉重做
This commit is contained in:
commit
edcd25fe68
4 files changed
+89
-28
No files matched your search
@@ -55,6 +55,9 @@ abstract final class AppColors {
|
|||||||
static const raised = Color(0xFFFFF1E5);
|
static const raised = Color(0xFFFFF1E5);
|
||||||
static const quick = Color(0xFFFFF0E1);
|
static const quick = Color(0xFFFFF0E1);
|
||||||
static const input = Color(0xFFFFF4EA);
|
static const input = Color(0xFFFFF4EA);
|
||||||
|
|
||||||
|
/// 评论输入框底色。
|
||||||
|
static const commentInput = Color(0xFFF5EFE8);
|
||||||
static const goldCard = Color(0xFFFFF4DF);
|
static const goldCard = Color(0xFFFFF4DF);
|
||||||
|
|
||||||
/// 正文颜色。
|
/// 正文颜色。
|
||||||
|
|||||||
@@ -51,12 +51,12 @@ class CommentTile extends StatelessWidget {
|
|||||||
: comment.nickname;
|
: comment.nickname;
|
||||||
return Padding(
|
return Padding(
|
||||||
key: Key('comment-item-${comment.id}'),
|
key: Key('comment-item-${comment.id}'),
|
||||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||||
child: Row(
|
child: Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
_avatar(),
|
_avatar(),
|
||||||
const SizedBox(width: 12),
|
const SizedBox(width: 10),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
@@ -67,8 +67,9 @@ class CommentTile extends StatelessWidget {
|
|||||||
child: Text(
|
child: Text(
|
||||||
name,
|
name,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
color: AppColors.muted,
|
color: AppColors.cream,
|
||||||
fontSize: 12,
|
fontSize: 13,
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -77,7 +78,7 @@ class CommentTile extends StatelessWidget {
|
|||||||
formatLocalizedDateTime(context, comment.createdAt!),
|
formatLocalizedDateTime(context, comment.createdAt!),
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
color: AppColors.subtle,
|
color: AppColors.subtle,
|
||||||
fontSize: 10,
|
fontSize: 11,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 4),
|
const SizedBox(width: 4),
|
||||||
@@ -109,8 +110,8 @@ class CommentTile extends StatelessWidget {
|
|||||||
comment.content,
|
comment.content,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
color: AppColors.cream,
|
color: AppColors.cream,
|
||||||
fontSize: 13,
|
fontSize: 14,
|
||||||
height: 1.2,
|
height: 1.4,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (comment.isPending)
|
if (comment.isPending)
|
||||||
@@ -129,6 +130,12 @@ class CommentTile extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
TextButton.icon(
|
TextButton.icon(
|
||||||
key: Key('comment-like-${comment.id}'),
|
key: Key('comment-like-${comment.id}'),
|
||||||
|
style: TextButton.styleFrom(
|
||||||
|
foregroundColor: AppColors.muted,
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 4),
|
||||||
|
minimumSize: const Size(0, 28),
|
||||||
|
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||||
|
),
|
||||||
onPressed: controller.likingComment(comment.id)
|
onPressed: controller.likingComment(comment.id)
|
||||||
? null
|
? null
|
||||||
: () => handlers.onLike(comment),
|
: () => handlers.onLike(comment),
|
||||||
@@ -138,11 +145,24 @@ class CommentTile extends StatelessWidget {
|
|||||||
: Icons.favorite_border_rounded,
|
: Icons.favorite_border_rounded,
|
||||||
size: 16,
|
size: 16,
|
||||||
),
|
),
|
||||||
label: Text('${comment.likeCount}'),
|
label: Text(
|
||||||
|
'${comment.likeCount}',
|
||||||
|
style: const TextStyle(fontSize: 11),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
if (!isReply)
|
if (!isReply)
|
||||||
TextButton(
|
TextButton(
|
||||||
key: Key('comment-reply-${comment.id}'),
|
key: Key('comment-reply-${comment.id}'),
|
||||||
|
style: TextButton.styleFrom(
|
||||||
|
foregroundColor: AppColors.blue,
|
||||||
|
textStyle: const TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 4),
|
||||||
|
minimumSize: const Size(0, 28),
|
||||||
|
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||||
|
),
|
||||||
onPressed: () => handlers.onReply(comment),
|
onPressed: () => handlers.onReply(comment),
|
||||||
child: Text(l10n.reply),
|
child: Text(l10n.reply),
|
||||||
),
|
),
|
||||||
@@ -157,14 +177,14 @@ class CommentTile extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _avatar() {
|
Widget _avatar() {
|
||||||
final size = isReply ? 22.0 : 28.0;
|
final size = isReply ? 24.0 : 32.0;
|
||||||
if (comment.avatarUrl.isEmpty) {
|
if (comment.avatarUrl.isEmpty) {
|
||||||
return CircleAvatar(
|
return CircleAvatar(
|
||||||
radius: size / 2,
|
radius: size / 2,
|
||||||
backgroundColor: AppColors.raised,
|
backgroundColor: AppColors.raised,
|
||||||
child: Icon(
|
child: Icon(
|
||||||
Icons.person_rounded,
|
Icons.person_rounded,
|
||||||
size: isReply ? 13 : 16,
|
size: isReply ? 14 : 18,
|
||||||
color: AppColors.cream,
|
color: AppColors.cream,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -22,9 +22,9 @@ import 'comment_tile.dart';
|
|||||||
const double _minSheetHeight = 280;
|
const double _minSheetHeight = 280;
|
||||||
const double _maxSheetHeight = 520;
|
const double _maxSheetHeight = 520;
|
||||||
const int _maxCommentLength = 300;
|
const int _maxCommentLength = 300;
|
||||||
const double _composerRadius = 20;
|
const double _composerRadius = 22;
|
||||||
const double _composerHeight = 40;
|
const double _composerHeight = 44;
|
||||||
const double _sendButtonSize = 32;
|
const double _sendButtonSize = 36;
|
||||||
const double _sheetRadius = 20;
|
const double _sheetRadius = 20;
|
||||||
|
|
||||||
/// 服务端评论底部弹窗:匿名列表、游标翻页、回复、点赞和本人删除。
|
/// 服务端评论底部弹窗:匿名列表、游标翻页、回复、点赞和本人删除。
|
||||||
@@ -195,6 +195,18 @@ class _DramaCommentsSheetState extends State<DramaCommentsSheet> {
|
|||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
|
Center(
|
||||||
|
child: Container(
|
||||||
|
key: const Key('player-comments-drag-handle'),
|
||||||
|
width: 36,
|
||||||
|
height: 4,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: AppColors.border,
|
||||||
|
borderRadius: BorderRadius.circular(999),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
@@ -203,8 +215,8 @@ class _DramaCommentsSheetState extends State<DramaCommentsSheet> {
|
|||||||
key: count == null ? null : const Key('comment-count-label'),
|
key: count == null ? null : const Key('comment-count-label'),
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
color: AppColors.onSurface,
|
color: AppColors.onSurface,
|
||||||
fontSize: 18,
|
fontSize: 15,
|
||||||
fontWeight: FontWeight.w800,
|
fontWeight: FontWeight.w700,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -212,7 +224,8 @@ class _DramaCommentsSheetState extends State<DramaCommentsSheet> {
|
|||||||
key: const Key('player-comments-close'),
|
key: const Key('player-comments-close'),
|
||||||
tooltip: l10n.close,
|
tooltip: l10n.close,
|
||||||
onPressed: () => Navigator.pop(context),
|
onPressed: () => Navigator.pop(context),
|
||||||
icon: const Icon(Icons.close_rounded),
|
visualDensity: VisualDensity.compact,
|
||||||
|
icon: const Icon(Icons.close_rounded, size: 20),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -326,11 +339,11 @@ class _DramaCommentsSheetState extends State<DramaCommentsSheet> {
|
|||||||
);
|
);
|
||||||
return InputDecoration(
|
return InputDecoration(
|
||||||
hintText: hint,
|
hintText: hint,
|
||||||
hintStyle: const TextStyle(color: AppColors.muted, fontSize: 13),
|
hintStyle: const TextStyle(color: AppColors.muted, fontSize: 14),
|
||||||
counterText: '',
|
counterText: '',
|
||||||
filled: true,
|
filled: true,
|
||||||
fillColor: AppColors.raised,
|
fillColor: AppColors.commentInput,
|
||||||
contentPadding: const EdgeInsets.symmetric(horizontal: 12),
|
contentPadding: const EdgeInsets.symmetric(horizontal: 14),
|
||||||
isDense: true,
|
isDense: true,
|
||||||
border: clear,
|
border: clear,
|
||||||
enabledBorder: clear,
|
enabledBorder: clear,
|
||||||
@@ -349,7 +362,8 @@ class _DramaCommentsSheetState extends State<DramaCommentsSheet> {
|
|||||||
focusNode: _inputFocus,
|
focusNode: _inputFocus,
|
||||||
maxLength: _maxCommentLength,
|
maxLength: _maxCommentLength,
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
style: const TextStyle(color: AppColors.cream, fontSize: 13),
|
textAlignVertical: TextAlignVertical.center,
|
||||||
|
style: const TextStyle(color: AppColors.cream, fontSize: 14),
|
||||||
cursorColor: AppColors.blue,
|
cursorColor: AppColors.blue,
|
||||||
decoration: _composerDecoration(l10n.writeComment),
|
decoration: _composerDecoration(l10n.writeComment),
|
||||||
onSubmitted: (_) => _post(),
|
onSubmitted: (_) => _post(),
|
||||||
@@ -402,10 +416,20 @@ class _CommentThread extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
if (comment.replyCount > 0 || replies.isNotEmpty)
|
if (comment.replyCount > 0 || replies.isNotEmpty)
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(left: 44, bottom: 8),
|
padding: const EdgeInsets.only(left: 42, bottom: 4),
|
||||||
child: TextButton(
|
child: TextButton(
|
||||||
key: Key('comment-replies-${comment.id}'),
|
key: Key('comment-replies-${comment.id}'),
|
||||||
onPressed: () => _toggleReplies(context),
|
onPressed: () => _toggleReplies(context),
|
||||||
|
style: TextButton.styleFrom(
|
||||||
|
foregroundColor: AppColors.blue,
|
||||||
|
textStyle: const TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 4),
|
||||||
|
minimumSize: const Size(0, 28),
|
||||||
|
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||||
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
expanded
|
expanded
|
||||||
? AppLocalizations.of(context)!.hideReplies
|
? AppLocalizations.of(context)!.hideReplies
|
||||||
@@ -440,7 +464,10 @@ class _CommentThread extends StatelessWidget {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const Divider(height: 1, color: AppColors.outlineVariantDark),
|
const Padding(
|
||||||
|
padding: EdgeInsets.only(left: 42),
|
||||||
|
child: Divider(height: 1, color: AppColors.border),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ void main() {
|
|||||||
expect(tester.widget<TextField>(input).focusNode?.hasFocus, isFalse);
|
expect(tester.widget<TextField>(input).focusNode?.hasFocus, isFalse);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('should_use_compact_comment_sizes', (tester) async {
|
testWidgets('should_use_polished_comment_sizes', (tester) async {
|
||||||
final repository = FakeCommentRepository(
|
final repository = FakeCommentRepository(
|
||||||
pages: [
|
pages: [
|
||||||
CommentPage(
|
CommentPage(
|
||||||
@@ -142,19 +142,30 @@ void main() {
|
|||||||
|
|
||||||
expect(
|
expect(
|
||||||
tester.getSize(find.byKey(const Key('comment-post'))),
|
tester.getSize(find.byKey(const Key('comment-post'))),
|
||||||
const Size(32, 32),
|
const Size(36, 36),
|
||||||
|
);
|
||||||
|
expect(tester.getSize(find.byKey(const Key('comment-input'))).height, 44);
|
||||||
|
expect(
|
||||||
|
find.byKey(const Key('player-comments-drag-handle')),
|
||||||
|
findsOneWidget,
|
||||||
);
|
);
|
||||||
expect(tester.getSize(find.byKey(const Key('comment-input'))).height, 40);
|
|
||||||
final avatar = tester.widget<CircleAvatar>(
|
final avatar = tester.widget<CircleAvatar>(
|
||||||
find.descendant(
|
find.descendant(
|
||||||
of: find.byKey(const Key('comment-item-10')),
|
of: find.byKey(const Key('comment-item-10')),
|
||||||
matching: find.byType(CircleAvatar),
|
matching: find.byType(CircleAvatar),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
expect(avatar.radius, 14);
|
expect(avatar.radius, 16);
|
||||||
final body = tester.widget<Text>(find.text('Great episode'));
|
final body = tester.widget<Text>(find.text('Great episode'));
|
||||||
expect(body.style?.fontSize, 13);
|
expect(body.style?.fontSize, 14);
|
||||||
expect(body.style?.height, 1.2);
|
expect(body.style?.height, 1.4);
|
||||||
|
expect(
|
||||||
|
tester
|
||||||
|
.widget<TextField>(find.byKey(const Key('comment-input')))
|
||||||
|
.decoration
|
||||||
|
?.fillColor,
|
||||||
|
AppColors.commentInput,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('should_show_review_badge_and_server_replaced_content', (
|
testWidgets('should_show_review_badge_and_server_replaced_content', (
|
||||||
|
|||||||
Reference in new issue
Block a user