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

+77 -81
View File
@@ -3,7 +3,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../../../core/data/models/comment.dart'; import '../../../core/data/models/comment.dart';
import '../../../core/data/services/comment_controller.dart';
import '../../../core/formatting/localized_date_time.dart'; import '../../../core/formatting/localized_date_time.dart';
import '../../../core/theme/app_colors.dart'; import '../../../core/theme/app_colors.dart';
import '../../../core/theme/app_dimens.dart'; import '../../../core/theme/app_dimens.dart';
@@ -17,13 +16,11 @@ const String _reportAction = 'report';
class CommentInteractionHandlers { class CommentInteractionHandlers {
const CommentInteractionHandlers({ const CommentInteractionHandlers({
required this.onReply, required this.onReply,
required this.onLike,
required this.onDelete, required this.onDelete,
required this.onReport, required this.onReport,
}); });
final ValueChanged<DramaComment> onReply; final ValueChanged<DramaComment> onReply;
final Future<void> Function(DramaComment) onLike;
final Future<void> Function(DramaComment) onDelete; final Future<void> Function(DramaComment) onDelete;
final Future<void> Function(DramaComment) onReport; final Future<void> Function(DramaComment) onReport;
} }
@@ -33,13 +30,11 @@ class CommentTile extends StatelessWidget {
const CommentTile({ const CommentTile({
super.key, super.key,
required this.comment, required this.comment,
required this.controller,
required this.handlers, required this.handlers,
this.isReply = false, this.isReply = false,
}); });
final DramaComment comment; final DramaComment comment;
final CommentController controller;
final CommentInteractionHandlers handlers; final CommentInteractionHandlers handlers;
final bool isReply; final bool isReply;
@@ -51,66 +46,68 @@ 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: 12), padding: const EdgeInsets.only(top: 12, bottom: 14),
child: Row( child: Row(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
_avatar(), _avatar(),
const SizedBox(width: 10), const SizedBox(width: 12),
Expanded( Expanded(
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Row( Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Expanded( Expanded(
child: Text( child: Text(
name, name,
style: const TextStyle( style: const TextStyle(
color: AppColors.cream, color: AppColors.muted,
fontSize: 13, fontSize: 12,
fontWeight: FontWeight.w700, fontWeight: FontWeight.w400,
), ),
), ),
), ),
if (comment.createdAt != null) SizedBox.square(
Text( dimension: 28,
formatLocalizedDateTime(context, comment.createdAt!), child: PopupMenuButton<String>(
style: const TextStyle( key: Key('comment-menu-${comment.id}'),
tooltip: l10n.more,
padding: EdgeInsets.zero,
iconSize: 18,
icon: const Icon(
Icons.more_horiz_rounded,
color: AppColors.subtle, color: AppColors.subtle,
fontSize: 11,
), ),
), onSelected: (value) {
const SizedBox(width: 4), if (value == _deleteAction) {
PopupMenuButton<String>( handlers.onDelete(comment);
key: Key('comment-menu-${comment.id}'), } else if (value == _reportAction) {
tooltip: l10n.more, handlers.onReport(comment);
onSelected: (value) { }
if (value == _deleteAction) { },
handlers.onDelete(comment); itemBuilder: (_) => [
} else if (value == _reportAction) { if (comment.mine)
handlers.onReport(comment); PopupMenuItem(
} value: _deleteAction,
}, child: Text(l10n.deleteComment),
itemBuilder: (_) => [ ),
if (comment.mine)
PopupMenuItem( PopupMenuItem(
value: _deleteAction, value: _reportAction,
child: Text(l10n.deleteComment), child: Text(l10n.reportComment),
), ),
PopupMenuItem( ],
value: _reportAction, ),
child: Text(l10n.reportComment),
),
],
), ),
], ],
), ),
const SizedBox(height: 2),
Text( Text(
comment.content, comment.content,
style: const TextStyle( style: const TextStyle(
color: AppColors.cream, color: AppColors.cream,
fontSize: 14, fontSize: 16,
height: 1.4, height: 1.4,
), ),
), ),
@@ -126,48 +123,11 @@ class CommentTile extends StatelessWidget {
), ),
), ),
), ),
Row( if (comment.createdAt != null || !isReply)
children: [ Padding(
TextButton.icon( padding: const EdgeInsets.only(top: 6),
key: Key('comment-like-${comment.id}'), child: _metadata(context, l10n),
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)
? null
: () => handlers.onLike(comment),
icon: Icon(
comment.liked
? Icons.favorite_rounded
: Icons.favorite_border_rounded,
size: 16,
),
label: Text(
'${comment.likeCount}',
style: const TextStyle(fontSize: 11),
),
),
if (!isReply)
TextButton(
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),
child: Text(l10n.reply),
),
],
),
], ],
), ),
), ),
@@ -177,14 +137,14 @@ class CommentTile extends StatelessWidget {
} }
Widget _avatar() { Widget _avatar() {
final size = isReply ? 24.0 : 32.0; final size = isReply ? 28.0 : 40.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 ? 14 : 18, size: isReply ? 16 : 22,
color: AppColors.cream, color: AppColors.cream,
), ),
); );
@@ -197,4 +157,40 @@ class CommentTile extends StatelessWidget {
), ),
); );
} }
Widget _metadata(BuildContext context, AppLocalizations l10n) {
final createdAt = comment.createdAt;
return Row(
children: [
if (createdAt != null)
Text(
formatLocalizedDateTime(context, createdAt),
style: const TextStyle(color: AppColors.subtle, fontSize: 12),
),
if (createdAt != null && !isReply) ...[
const SizedBox(width: 8),
const Text(
'·',
style: TextStyle(color: AppColors.muted, fontSize: 12),
),
const SizedBox(width: 8),
],
if (!isReply)
TextButton(
key: Key('comment-reply-${comment.id}'),
style: TextButton.styleFrom(
foregroundColor: AppColors.muted,
padding: EdgeInsets.zero,
minimumSize: const Size(0, 24),
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
),
onPressed: () => handlers.onReply(comment),
child: Text(
l10n.reply,
style: const TextStyle(fontSize: 12, fontWeight: FontWeight.w400),
),
),
],
);
}
} }
+114 -119
View File
@@ -23,12 +23,14 @@ 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 = 12; const double _composerRadius = 22;
const double _composerHeight = 52; const double _composerHeight = 44;
const double _sendButtonSize = 40; const double _sendButtonSize = 38;
const double _sheetRadius = 20; const double _sheetRadius = 20;
const double _headerHeight = 44;
const double _replyIndent = 52;
/// 服务端评论底部弹窗:匿名列表、游标翻页、回复、点赞和本人删除。 /// 服务端评论底部弹窗:匿名列表、游标翻页、回复、举报和本人删除。
class DramaCommentsSheet extends StatefulWidget { class DramaCommentsSheet extends StatefulWidget {
const DramaCommentsSheet({super.key, required this.drama}); const DramaCommentsSheet({super.key, required this.drama});
@@ -98,17 +100,6 @@ class _DramaCommentsSheetState extends State<DramaCommentsSheet> {
_inputFocus.requestFocus(); _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 { Future<void> _confirmDelete(DramaComment comment) async {
final l10n = AppLocalizations.of(context)!; final l10n = AppLocalizations.of(context)!;
final confirmed = await showDialog<bool>( final confirmed = await showDialog<bool>(
@@ -203,48 +194,40 @@ class _DramaCommentsSheetState extends State<DramaCommentsSheet> {
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Center( SizedBox(
child: Container( height: _headerHeight,
key: const Key('player-comments-drag-handle'), width: double.infinity,
width: 36, child: Stack(
height: 4, alignment: Alignment.center,
decoration: BoxDecoration( children: [
color: AppColors.border, Text(
borderRadius: BorderRadius.circular(999),
),
),
),
const SizedBox(height: 8),
Row(
children: [
Expanded(
child: Text(
count == null ? l10n.comments : l10n.commentsWithCount(count), 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( style: const TextStyle(
color: AppColors.onSurface, color: AppColors.onSurface,
fontSize: 15, fontSize: 16,
fontWeight: FontWeight.w700, fontWeight: FontWeight.w600,
), ),
), ),
), Positioned(
IconButton( left: 0,
key: const Key('player-comments-close'), child: SizedBox.square(
tooltip: l10n.close, dimension: 44,
onPressed: () => Navigator.pop(context), child: IconButton(
visualDensity: VisualDensity.compact, key: const Key('player-comments-close'),
icon: const Icon(Icons.close_rounded, size: 20), tooltip: l10n.close,
), padding: EdgeInsets.zero,
], onPressed: () => Navigator.pop(context),
), icon: const Icon(
Text( Icons.keyboard_arrow_down_rounded,
widget.drama.title, size: 24,
maxLines: 1, color: AppColors.cream,
overflow: TextOverflow.ellipsis, ),
style: const TextStyle( ),
color: AppColors.muted, ),
fontSize: 12, ),
fontWeight: FontWeight.w500, ],
), ),
), ),
const SizedBox(height: 8), const SizedBox(height: 8),
@@ -290,7 +273,6 @@ class _DramaCommentsSheetState extends State<DramaCommentsSheet> {
controller: _controller, controller: _controller,
handlers: CommentInteractionHandlers( handlers: CommentInteractionHandlers(
onReply: _beginReply, onReply: _beginReply,
onLike: _like,
onDelete: _confirmDelete, onDelete: _confirmDelete,
onReport: _report, onReport: _report,
), ),
@@ -349,9 +331,7 @@ class _DramaCommentsSheetState extends State<DramaCommentsSheet> {
hintText: hint, hintText: hint,
hintStyle: const TextStyle(color: AppColors.muted, fontSize: 14), hintStyle: const TextStyle(color: AppColors.muted, fontSize: 14),
counterText: '', counterText: '',
filled: true, contentPadding: const EdgeInsets.symmetric(horizontal: 16),
fillColor: AppColors.commentInput,
contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14),
isDense: true, isDense: true,
border: clear, border: clear,
enabledBorder: clear, enabledBorder: clear,
@@ -361,48 +341,56 @@ class _DramaCommentsSheetState extends State<DramaCommentsSheet> {
Widget _composer(AppLocalizations l10n) { Widget _composer(AppLocalizations l10n) {
final signedIn = context.watch<AuthController>().isSignedIn; final signedIn = context.watch<AuthController>().isSignedIn;
return Row( return Container(
children: [ key: const Key('comment-composer'),
Expanded( height: _composerHeight,
child: SizedBox( padding: const EdgeInsets.only(right: 3),
height: _composerHeight, decoration: BoxDecoration(
child: TextField( color: AppColors.commentInput,
key: const Key('comment-input'), borderRadius: BorderRadius.circular(_composerRadius),
controller: _input, ),
focusNode: _inputFocus, child: Row(
readOnly: !signedIn, children: [
canRequestFocus: signedIn, Expanded(
maxLength: _maxCommentLength, child: SizedBox(
maxLines: 1, height: _composerHeight,
textAlignVertical: TextAlignVertical.center, child: TextField(
style: const TextStyle(color: AppColors.cream, fontSize: 14), key: const Key('comment-input'),
cursorColor: AppColors.blue, controller: _input,
decoration: _composerDecoration( focusNode: _inputFocus,
signedIn ? l10n.writeComment : l10n.commentLoginHint, 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(),
), ),
), ),
), SizedBox.square(
const SizedBox(width: 8), dimension: _sendButtonSize,
SizedBox.square( child: IconButton.filled(
dimension: _sendButtonSize, key: const Key('comment-post'),
child: IconButton.filled( tooltip: l10n.postComment,
key: const Key('comment-post'), padding: EdgeInsets.zero,
tooltip: l10n.postComment, iconSize: 18,
padding: EdgeInsets.zero, onPressed: _controller.submitting ? null : _post,
iconSize: 18, icon: _controller.submitting
onPressed: _controller.submitting ? null : _post, ? const SizedBox.square(
icon: _controller.submitting dimension: 16,
? const SizedBox.square( child: CircularProgressIndicator(strokeWidth: 2),
dimension: 16, )
child: CircularProgressIndicator(strokeWidth: 2), : const Icon(Icons.send_rounded),
) ),
: const Icon(Icons.send_rounded),
), ),
), ],
], ),
); );
} }
} }
@@ -425,39 +413,51 @@ class _CommentThread extends StatelessWidget {
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
CommentTile( CommentTile(comment: comment, handlers: handlers),
comment: comment,
controller: controller,
handlers: handlers,
),
if (comment.replyCount > 0 || replies.isNotEmpty) if (comment.replyCount > 0 || replies.isNotEmpty)
Padding( Padding(
padding: const EdgeInsets.only(left: 42, bottom: 4), padding: const EdgeInsets.only(left: _replyIndent, 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( style: TextButton.styleFrom(
foregroundColor: AppColors.blue, foregroundColor: AppColors.muted,
textStyle: const TextStyle( padding: EdgeInsets.zero,
fontSize: 12, minimumSize: const Size(0, 24),
fontWeight: FontWeight.w600,
),
padding: const EdgeInsets.symmetric(horizontal: 4),
minimumSize: const Size(0, 28),
tapTargetSize: MaterialTapTargetSize.shrinkWrap, tapTargetSize: MaterialTapTargetSize.shrinkWrap,
), ),
child: Text( child: Row(
expanded mainAxisSize: MainAxisSize.min,
? AppLocalizations.of(context)!.hideReplies children: [
: AppLocalizations.of( Container(width: 16, height: 1, color: AppColors.border),
context, const SizedBox(width: 8),
)!.viewReplies(comment.replyCount), 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) if (expanded)
Padding( Padding(
padding: const EdgeInsets.only(left: 28), padding: const EdgeInsets.only(left: _replyIndent),
child: Column( child: Column(
children: [ children: [
if (controller.repliesLoading(comment.id)) if (controller.repliesLoading(comment.id))
@@ -468,7 +468,6 @@ class _CommentThread extends StatelessWidget {
for (final reply in replies) for (final reply in replies)
CommentTile( CommentTile(
comment: reply, comment: reply,
controller: controller,
handlers: handlers, handlers: handlers,
isReply: true, isReply: true,
), ),
@@ -480,10 +479,6 @@ class _CommentThread extends StatelessWidget {
], ],
), ),
), ),
const Padding(
padding: EdgeInsets.only(left: 42),
child: Divider(height: 1, color: AppColors.border),
),
], ],
); );
} }
+82 -44
View File
@@ -129,7 +129,10 @@ void main() {
await _pumpSheet(tester, repository: repository); await _pumpSheet(tester, repository: repository);
expect(find.text('Great episode'), findsOneWidget); expect(find.text('Great episode'), findsOneWidget);
expect(find.byKey(const Key('comment-list-load-more')), findsOneWidget); expect(find.byKey(const Key('comment-list-load-more')), findsOneWidget);
expect(find.byKey(const Key('comment-count-label')), findsNothing); expect(
tester.widget<Text>(find.byKey(const Key('comment-count-label'))).data,
'Comments',
);
await tester.tap(find.byKey(const Key('comment-list-load-more'))); await tester.tap(find.byKey(const Key('comment-list-load-more')));
await tester.pumpAndSettle(); await tester.pumpAndSettle();
@@ -209,30 +212,89 @@ void main() {
expect( expect(
tester.getSize(find.byKey(const Key('comment-post'))), tester.getSize(find.byKey(const Key('comment-post'))),
const Size(40, 40), const Size(38, 38),
); );
expect(tester.getSize(find.byKey(const Key('comment-input'))).height, 52); expect(tester.getSize(find.byKey(const Key('comment-input'))).height, 44);
expect(find.byKey(const Key('player-comments-drag-handle')), findsNothing);
expect( expect(
find.byKey(const Key('player-comments-drag-handle')), tester.getSize(find.byKey(const Key('player-comments-close'))),
const Size(44, 44),
);
expect(
find.descendant(
of: find.byKey(const Key('player-comments-close')),
matching: find.byIcon(Icons.keyboard_arrow_down_rounded),
),
findsOneWidget, findsOneWidget,
); );
final title = tester.widget<Text>(
find.byKey(const Key('comment-count-label')),
);
expect(title.style?.fontSize, 16);
expect(title.style?.fontWeight, FontWeight.w600);
expect(
tester.getCenter(find.byKey(const Key('comment-count-label'))).dx,
closeTo(
tester.getCenter(find.byKey(const Key('player-comments-sheet'))).dx,
0.5,
),
);
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, 16); expect(avatar.radius, 20);
final body = tester.widget<Text>(find.text('Great episode')); final body = tester.widget<Text>(find.text('Great episode'));
expect(body.style?.fontSize, 14); expect(body.style?.fontSize, 16);
expect(body.style?.height, 1.4); expect(body.style?.height, 1.4);
expect( final composer = tester.widget<Container>(
tester find.byKey(const Key('comment-composer')),
.widget<TextField>(find.byKey(const Key('comment-input')))
.decoration
?.fillColor,
AppColors.commentInput,
); );
final decoration = composer.decoration! as BoxDecoration;
expect(decoration.color, AppColors.commentInput);
expect(decoration.borderRadius, BorderRadius.circular(22));
expect(
find.descendant(
of: find.byKey(const Key('comment-menu-10')),
matching: find.byIcon(Icons.more_horiz_rounded),
),
findsOneWidget,
);
});
testWidgets('should_hide_comment_like_controls', (tester) async {
final repository = FakeCommentRepository(
pages: [
CommentPage(
comments: [commentFixture(id: '10', content: 'No likes shown')],
),
],
);
await _pumpSheet(tester, repository: repository);
expect(
find.byWidgetPredicate(
(widget) =>
widget.key is ValueKey<String> &&
(widget.key! as ValueKey<String>).value.startsWith('comment-like-'),
),
findsNothing,
);
expect(find.byIcon(Icons.favorite_rounded), findsNothing);
expect(find.byIcon(Icons.favorite_border_rounded), findsNothing);
});
testWidgets('should_close_sheet_from_down_arrow', (tester) async {
final repository = FakeCommentRepository(pages: [const CommentPage()]);
await _pumpSheet(tester, repository: repository);
await tester.tap(find.byKey(const Key('player-comments-close')));
await tester.pumpAndSettle();
expect(find.byKey(const Key('player-comments-sheet')), findsNothing);
}); });
testWidgets('should_show_review_badge_and_server_replaced_content', ( testWidgets('should_show_review_badge_and_server_replaced_content', (
@@ -306,34 +368,6 @@ void main() {
expect(find.byKey(const Key('comment-list-retry')), findsOneWidget); expect(find.byKey(const Key('comment-list-retry')), findsOneWidget);
}); });
testWidgets('should_update_comment_like_count_when_server_returns_count', (
tester,
) async {
final repository = FakeCommentRepository(
pages: [
CommentPage(
comments: [commentFixture(id: '10', content: 'Like me')],
),
],
);
final interactions = FakeInteractionRepository()
..nextLikeResult = const LikeToggleResult(liked: true, count: 7);
final haptics = FakeHaptics();
await _pumpSheet(
tester,
repository: repository,
interactions: interactions,
haptics: haptics,
);
await tester.tap(find.byKey(const Key('comment-like-10')));
await tester.pumpAndSettle();
expect(interactions.likeTargets, ['COMMENT:10']);
expect(haptics.lightImpacts, 1);
expect(find.text('7'), findsOneWidget);
});
testWidgets('should_report_comment_and_show_success_when_submitted', ( testWidgets('should_report_comment_and_show_success_when_submitted', (
tester, tester,
) async { ) async {
@@ -480,10 +514,14 @@ Future<AuthController> _pumpSheet(
locale: const Locale('en'), locale: const Locale('en'),
localizationsDelegates: AppLocalizations.localizationsDelegates, localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales, supportedLocales: AppLocalizations.supportedLocales,
home: const Scaffold( initialRoute: '/comments',
backgroundColor: AppColors.ink, routes: {
body: DramaCommentsSheet(drama: _drama), '/': (_) => const Scaffold(backgroundColor: AppColors.ink),
), '/comments': (_) => const Scaffold(
backgroundColor: AppColors.ink,
body: DramaCommentsSheet(drama: _drama),
),
},
), ),
), ),
); );