diff --git a/lib/pages/player/widgets/comment_tile.dart b/lib/pages/player/widgets/comment_tile.dart index bfc2719..74462dc 100644 --- a/lib/pages/player/widgets/comment_tile.dart +++ b/lib/pages/player/widgets/comment_tile.dart @@ -9,20 +9,11 @@ import '../../../core/theme/app_dimens.dart'; import '../../../core/widgets/remote_image.dart'; import '../../../l10n/app_localizations.dart'; -const String _deleteAction = 'delete'; -const String _reportAction = 'report'; - /// 评论条目的交互回调集合。 class CommentInteractionHandlers { - const CommentInteractionHandlers({ - required this.onReply, - required this.onDelete, - required this.onReport, - }); + const CommentInteractionHandlers({required this.onReply}); final ValueChanged onReply; - final Future Function(DramaComment) onDelete; - final Future Function(DramaComment) onReport; } /// 单条评论或回复的展示与操作行。 @@ -56,51 +47,13 @@ class CommentTile extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: Text( - name, - style: const TextStyle( - color: AppColors.muted, - fontSize: 12, - fontWeight: FontWeight.w400, - ), - ), - ), - SizedBox.square( - dimension: 28, - child: PopupMenuButton( - key: Key('comment-menu-${comment.id}'), - tooltip: l10n.more, - padding: EdgeInsets.zero, - iconSize: 18, - icon: const Icon( - Icons.more_horiz_rounded, - color: AppColors.subtle, - ), - onSelected: (value) { - if (value == _deleteAction) { - handlers.onDelete(comment); - } else if (value == _reportAction) { - handlers.onReport(comment); - } - }, - itemBuilder: (_) => [ - if (comment.mine) - PopupMenuItem( - value: _deleteAction, - child: Text(l10n.deleteComment), - ), - PopupMenuItem( - value: _reportAction, - child: Text(l10n.reportComment), - ), - ], - ), - ), - ], + Text( + name, + style: const TextStyle( + color: AppColors.muted, + fontSize: 12, + fontWeight: FontWeight.w400, + ), ), const SizedBox(height: 2), Text( diff --git a/lib/pages/player/widgets/drama_comments_sheet.dart b/lib/pages/player/widgets/drama_comments_sheet.dart index 0d27c83..f6d8bef 100644 --- a/lib/pages/player/widgets/drama_comments_sheet.dart +++ b/lib/pages/player/widgets/drama_comments_sheet.dart @@ -17,7 +17,6 @@ import '../../../core/theme/app_colors.dart'; import '../../../core/widgets/auth_gate.dart'; import '../../../core/widgets/empty_state.dart'; import '../../../l10n/app_localizations.dart'; -import '../../interaction/widgets/report_dialog.dart'; import 'comment_tile.dart'; const double _minSheetHeight = 280; @@ -34,7 +33,7 @@ const double _replyBannerHeight = 46; const double _expandedInputRadius = 12; const double _postButtonHeight = 32; -/// 服务端评论底部弹窗:匿名列表、游标翻页、回复、举报和本人删除。 +/// 服务端评论底部弹窗:匿名列表、游标翻页、回复与登录发布。 class DramaCommentsSheet extends StatefulWidget { const DramaCommentsSheet({super.key, required this.drama}); @@ -122,39 +121,6 @@ class _DramaCommentsSheetState extends State { _inputFocus.requestFocus(); } - Future _confirmDelete(DramaComment comment) async { - final l10n = AppLocalizations.of(context)!; - final confirmed = await showDialog( - context: context, - builder: (dialogContext) => AlertDialog( - title: Text(l10n.deleteCommentTitle), - content: Text(l10n.deleteCommentMessage), - actions: [ - TextButton( - onPressed: () => Navigator.of(dialogContext).pop(false), - child: Text(l10n.cancel), - ), - FilledButton( - key: const Key('comment-delete-confirm'), - onPressed: () => Navigator.of(dialogContext).pop(true), - child: Text(l10n.delete), - ), - ], - ), - ); - if (confirmed != true || !mounted) return; - final result = await _controller.delete(comment); - if (!result.isSuccess) { - if (!mounted) return; - _showMessage( - result.errorMessage ?? - AppLocalizations.of(context)!.commentDeleteFailed, - ); - return; - } - await _refreshCount(); - } - Future _refreshCount() async { final request = ++_countRequest; try { @@ -167,25 +133,6 @@ class _DramaCommentsSheetState extends State { } } - Future _report(DramaComment comment) async { - if (!await ensureSignedIn(context) || !mounted) return; - final l10n = AppLocalizations.of(context)!; - final draft = await showReportDialog(context, title: l10n.reportComment); - if (draft == null || !mounted) return; - unawaited(context.read().lightImpact()); - final result = await _controller.report( - comment, - reason: draft.reason, - description: draft.description, - ); - if (!mounted) return; - _showMessage( - result.isSuccess - ? l10n.reportSubmitted - : result.errorMessage ?? l10n.reportFailed, - ); - } - void _showMessage(String message) { ScaffoldMessenger.of( context, @@ -474,11 +421,7 @@ class _DramaCommentsSheetState extends State { return _CommentThread( comment: _controller.comments[index], controller: _controller, - handlers: CommentInteractionHandlers( - onReply: _beginReply, - onDelete: _confirmDelete, - onReport: _report, - ), + handlers: CommentInteractionHandlers(onReply: _beginReply), ); }, ); diff --git a/test/comment/drama_comments_sheet_test.dart b/test/comment/drama_comments_sheet_test.dart index 530f220..135b2e9 100644 --- a/test/comment/drama_comments_sheet_test.dart +++ b/test/comment/drama_comments_sheet_test.dart @@ -6,7 +6,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:fruitshorts/core/data/models/comment.dart'; import 'package:fruitshorts/core/data/models/drama.dart'; -import 'package:fruitshorts/core/data/models/interaction.dart'; import 'package:fruitshorts/core/data/remote/api_client.dart'; import 'package:fruitshorts/core/data/remote/auth_api.dart'; import 'package:fruitshorts/core/data/repositories/comment_repository.dart'; @@ -383,13 +382,32 @@ void main() { 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_report_and_delete_actions', (tester) async { + final repository = FakeCommentRepository( + pages: [ + CommentPage( + comments: [ + commentFixture(id: '10', content: 'My comment', mine: true), + ], + ), + ], ); + + await _pumpSheet(tester, repository: repository); + + expect( + find.byWidgetPredicate( + (widget) => + widget.key is ValueKey && + (widget.key! as ValueKey).value.startsWith('comment-menu-'), + ), + findsNothing, + ); + expect(find.text('Delete comment'), findsNothing); + expect(find.text('Report comment'), findsNothing); + expect(find.byIcon(Icons.more_horiz_rounded), findsNothing); }); testWidgets('should_size_short_list_to_content', (tester) async { @@ -442,8 +460,14 @@ void main() { ); await _pumpSheet(tester, repository: repository); - final scrolledComment = find.byKey(const Key('comment-item-12')); - final before = tester.getTopLeft(scrolledComment).dy; + final scrollable = find + .descendant( + of: find.byKey(const Key('comment-list')), + matching: find.byType(Scrollable), + ) + .first; + final position = tester.state(scrollable).position; + expect(position.maxScrollExtent, greaterThan(0)); await tester.drag( find.byKey(const Key('comment-list')), @@ -451,7 +475,7 @@ void main() { ); await tester.pumpAndSettle(); - expect(tester.getTopLeft(scrolledComment).dy, lessThan(before)); + expect(position.pixels, greaterThan(0)); expect( tester.getSize(find.byKey(const Key('player-comments-sheet'))).height, 520, @@ -597,136 +621,11 @@ void main() { expect(find.byKey(const Key('comment-list-error')), findsOneWidget); expect(find.byKey(const Key('comment-list-retry')), findsOneWidget); }); - - testWidgets('should_report_comment_and_show_success_when_submitted', ( - tester, - ) async { - final repository = FakeCommentRepository( - pages: [ - CommentPage( - comments: [commentFixture(id: '10', content: 'Report me')], - ), - ], - ); - final interactions = FakeInteractionRepository(); - final haptics = FakeHaptics(); - - await _pumpSheet( - tester, - repository: repository, - interactions: interactions, - haptics: haptics, - ); - await tester.tap(find.byKey(const Key('comment-menu-10'))); - await tester.pumpAndSettle(); - await tester.tap(find.text('Report comment')); - await tester.pumpAndSettle(); - await tester.tap(find.byKey(const Key('report-submit'))); - await tester.pumpAndSettle(); - - expect( - interactions.reports.single.targetType, - InteractionTargetType.comment, - ); - expect(interactions.reports.single.targetId, '10'); - expect(interactions.reports.single.reasonCode, 'SPAM'); - expect(haptics.lightImpacts, 1); - expect(find.text('Report submitted. Thank you.'), findsOneWidget); - }); - - testWidgets('should_show_backend_message_when_comment_report_is_duplicated', ( - tester, - ) async { - final repository = FakeCommentRepository( - pages: [ - CommentPage( - comments: [commentFixture(id: '10', content: 'Report me')], - ), - ], - ); - final interactions = FakeInteractionRepository() - ..reportError = const ApiException(200003, '你已举报过该内容,我们正在处理'); - - await _pumpSheet( - tester, - repository: repository, - interactions: interactions, - ); - await tester.tap(find.byKey(const Key('comment-menu-10'))); - await tester.pumpAndSettle(); - await tester.tap(find.text('Report comment')); - await tester.pumpAndSettle(); - await tester.tap(find.byKey(const Key('report-submit'))); - await tester.pumpAndSettle(); - - expect(find.text('你已举报过该内容,我们正在处理'), findsOneWidget); - }); - - testWidgets('should_open_auth_gate_without_reporting_when_signed_out', ( - tester, - ) async { - SharedPreferencesAsyncPlatform.instance = - InMemorySharedPreferencesAsync.empty(); - final repository = FakeCommentRepository( - pages: [ - CommentPage( - comments: [commentFixture(id: '10', content: 'Report me')], - ), - ], - ); - final interactions = FakeInteractionRepository(); - - await _pumpSheet( - tester, - repository: repository, - interactions: interactions, - ); - await tester.tap(find.byKey(const Key('comment-menu-10'))); - await tester.pumpAndSettle(); - await tester.tap(find.text('Report comment')); - await tester.pumpAndSettle(); - - expect(find.text('Sign in to continue'), findsOneWidget); - expect(interactions.reports, isEmpty); - }); - - testWidgets('should_show_backend_message_when_reporting_own_comment', ( - tester, - ) async { - final repository = FakeCommentRepository( - pages: [ - CommentPage( - comments: [ - commentFixture(id: '10', content: 'My comment', mine: true), - ], - ), - ], - ); - final interactions = FakeInteractionRepository() - ..reportError = const ApiException(400, '不能举报自己发布的内容'); - - await _pumpSheet( - tester, - repository: repository, - interactions: interactions, - ); - await tester.tap(find.byKey(const Key('comment-menu-10'))); - await tester.pumpAndSettle(); - expect(find.text('Delete comment'), findsOneWidget); - expect(find.text('Report comment'), findsOneWidget); - await tester.tap(find.text('Report comment')); - await tester.pumpAndSettle(); - await tester.tap(find.byKey(const Key('report-submit'))); - await tester.pumpAndSettle(); - - expect(find.text('不能举报自己发布的内容'), findsOneWidget); - }); } Future _pumpSheet( WidgetTester tester, { required FakeCommentRepository repository, - FakeInteractionRepository? interactions, FakeHaptics? haptics, }) async { final auth = await _auth(); @@ -735,7 +634,7 @@ Future _pumpSheet( providers: [ Provider.value(value: repository), Provider.value( - value: interactions ?? FakeInteractionRepository(), + value: FakeInteractionRepository(), ), ChangeNotifierProvider.value(value: auth), Provider.value(value: haptics ?? FakeHaptics()),