fix(player): 评论面板按参考图重做

This commit is contained in:
Zhou Weidong committed 2026-10-21 11:52:59 +08:00
1 parent bdd3a53632
commit 7862e0be09
3 files changed
+273 -244

No files matched your search

+114 -119
View File
@@ -23,12 +23,14 @@ import 'comment_tile.dart';
const double _minSheetHeight = 280;
const double _maxSheetHeight = 520;
const int _maxCommentLength = 300;
const double _composerRadius = 12;
const double _composerHeight = 52;
const double _sendButtonSize = 40;
const double _composerRadius = 22;
const double _composerHeight = 44;
const double _sendButtonSize = 38;
const double _sheetRadius = 20;
const double _headerHeight = 44;
const double _replyIndent = 52;
/// 服务端评论底部弹窗:匿名列表、游标翻页、回复、点赞和本人删除。
/// 服务端评论底部弹窗:匿名列表、游标翻页、回复、举报和本人删除。
class DramaCommentsSheet extends StatefulWidget {
const DramaCommentsSheet({super.key, required this.drama});
@@ -98,17 +100,6 @@ class _DramaCommentsSheetState extends State<DramaCommentsSheet> {
_inputFocus.requestFocus();
}
Future<void> _like(DramaComment comment) async {
if (!await ensureSignedIn(context) || !mounted) return;
unawaited(context.read<Haptics>().lightImpact());
final result = await _controller.toggleLike(comment);
if (!result.isSuccess && mounted) {
_showMessage(
result.errorMessage ?? AppLocalizations.of(context)!.commentPostFailed,
);
}
}
Future<void> _confirmDelete(DramaComment comment) async {
final l10n = AppLocalizations.of(context)!;
final confirmed = await showDialog<bool>(
@@ -203,48 +194,40 @@ class _DramaCommentsSheetState extends State<DramaCommentsSheet> {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
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(
children: [
Expanded(
child: Text(
SizedBox(
height: _headerHeight,
width: double.infinity,
child: Stack(
alignment: Alignment.center,
children: [
Text(
count == null ? l10n.comments : l10n.commentsWithCount(count),
key: count == null ? null : const Key('comment-count-label'),
key: const Key('comment-count-label'),
textAlign: TextAlign.center,
style: const TextStyle(
color: AppColors.onSurface,
fontSize: 15,
fontWeight: FontWeight.w700,
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
),
IconButton(
key: const Key('player-comments-close'),
tooltip: l10n.close,
onPressed: () => Navigator.pop(context),
visualDensity: VisualDensity.compact,
icon: const Icon(Icons.close_rounded, size: 20),
),
],
),
Text(
widget.drama.title,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: const TextStyle(
color: AppColors.muted,
fontSize: 12,
fontWeight: FontWeight.w500,
Positioned(
left: 0,
child: SizedBox.square(
dimension: 44,
child: IconButton(
key: const Key('player-comments-close'),
tooltip: l10n.close,
padding: EdgeInsets.zero,
onPressed: () => Navigator.pop(context),
icon: const Icon(
Icons.keyboard_arrow_down_rounded,
size: 24,
color: AppColors.cream,
),
),
),
),
],
),
),
const SizedBox(height: 8),
@@ -290,7 +273,6 @@ class _DramaCommentsSheetState extends State<DramaCommentsSheet> {
controller: _controller,
handlers: CommentInteractionHandlers(
onReply: _beginReply,
onLike: _like,
onDelete: _confirmDelete,
onReport: _report,
),
@@ -349,9 +331,7 @@ class _DramaCommentsSheetState extends State<DramaCommentsSheet> {
hintText: hint,
hintStyle: const TextStyle(color: AppColors.muted, fontSize: 14),
counterText: '',
filled: true,
fillColor: AppColors.commentInput,
contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14),
contentPadding: const EdgeInsets.symmetric(horizontal: 16),
isDense: true,
border: clear,
enabledBorder: clear,
@@ -361,48 +341,56 @@ class _DramaCommentsSheetState extends State<DramaCommentsSheet> {
Widget _composer(AppLocalizations l10n) {
final signedIn = context.watch<AuthController>().isSignedIn;
return Row(
children: [
Expanded(
child: SizedBox(
height: _composerHeight,
child: TextField(
key: const Key('comment-input'),
controller: _input,
focusNode: _inputFocus,
readOnly: !signedIn,
canRequestFocus: signedIn,
maxLength: _maxCommentLength,
maxLines: 1,
textAlignVertical: TextAlignVertical.center,
style: const TextStyle(color: AppColors.cream, fontSize: 14),
cursorColor: AppColors.blue,
decoration: _composerDecoration(
signedIn ? l10n.writeComment : l10n.commentLoginHint,
return Container(
key: const Key('comment-composer'),
height: _composerHeight,
padding: const EdgeInsets.only(right: 3),
decoration: BoxDecoration(
color: AppColors.commentInput,
borderRadius: BorderRadius.circular(_composerRadius),
),
child: Row(
children: [
Expanded(
child: SizedBox(
height: _composerHeight,
child: TextField(
key: const Key('comment-input'),
controller: _input,
focusNode: _inputFocus,
readOnly: !signedIn,
canRequestFocus: signedIn,
maxLength: _maxCommentLength,
maxLines: 1,
textAlignVertical: TextAlignVertical.center,
style: const TextStyle(color: AppColors.cream, fontSize: 14),
cursorColor: AppColors.blue,
decoration: _composerDecoration(
signedIn ? l10n.writeComment : l10n.commentLoginHint,
),
onTap: signedIn ? null : _authenticateForComment,
onSubmitted: (_) => _post(),
),
onTap: signedIn ? null : _authenticateForComment,
onSubmitted: (_) => _post(),
),
),
),
const SizedBox(width: 8),
SizedBox.square(
dimension: _sendButtonSize,
child: IconButton.filled(
key: const Key('comment-post'),
tooltip: l10n.postComment,
padding: EdgeInsets.zero,
iconSize: 18,
onPressed: _controller.submitting ? null : _post,
icon: _controller.submitting
? const SizedBox.square(
dimension: 16,
child: CircularProgressIndicator(strokeWidth: 2),
)
: const Icon(Icons.send_rounded),
SizedBox.square(
dimension: _sendButtonSize,
child: IconButton.filled(
key: const Key('comment-post'),
tooltip: l10n.postComment,
padding: EdgeInsets.zero,
iconSize: 18,
onPressed: _controller.submitting ? null : _post,
icon: _controller.submitting
? const SizedBox.square(
dimension: 16,
child: CircularProgressIndicator(strokeWidth: 2),
)
: const Icon(Icons.send_rounded),
),
),
),
],
],
),
);
}
}
@@ -425,39 +413,51 @@ class _CommentThread extends StatelessWidget {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
CommentTile(
comment: comment,
controller: controller,
handlers: handlers,
),
CommentTile(comment: comment, handlers: handlers),
if (comment.replyCount > 0 || replies.isNotEmpty)
Padding(
padding: const EdgeInsets.only(left: 42, bottom: 4),
padding: const EdgeInsets.only(left: _replyIndent, bottom: 4),
child: TextButton(
key: Key('comment-replies-${comment.id}'),
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),
foregroundColor: AppColors.muted,
padding: EdgeInsets.zero,
minimumSize: const Size(0, 24),
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
),
child: Text(
expanded
? AppLocalizations.of(context)!.hideReplies
: AppLocalizations.of(
context,
)!.viewReplies(comment.replyCount),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Container(width: 16, height: 1, color: AppColors.border),
const SizedBox(width: 8),
Text(
expanded
? AppLocalizations.of(context)!.hideReplies
: AppLocalizations.of(
context,
)!.viewReplies(comment.replyCount),
style: const TextStyle(
color: AppColors.muted,
fontSize: 12,
fontWeight: FontWeight.w400,
),
),
const SizedBox(width: 4),
Icon(
expanded
? Icons.keyboard_arrow_up_rounded
: Icons.keyboard_arrow_down_rounded,
size: 14,
color: AppColors.muted,
),
],
),
),
),
if (expanded)
Padding(
padding: const EdgeInsets.only(left: 28),
padding: const EdgeInsets.only(left: _replyIndent),
child: Column(
children: [
if (controller.repliesLoading(comment.id))
@@ -468,7 +468,6 @@ class _CommentThread extends StatelessWidget {
for (final reply in replies)
CommentTile(
comment: reply,
controller: controller,
handlers: handlers,
isReply: true,
),
@@ -480,10 +479,6 @@ class _CommentThread extends StatelessWidget {
],
),
),
const Padding(
padding: EdgeInsets.only(left: 42),
child: Divider(height: 1, color: AppColors.border),
),
],
);
}