From d081cff3e4548a319d447fcbb8667fc4d0bcb6cc Mon Sep 17 00:00:00 2001 From: Zhou Weidong <502333560@qq.com> Date: Wed, 21 Oct 2026 13:04:29 +0800 Subject: [PATCH] =?UTF-8?q?fix(player):=20=E8=AF=84=E8=AE=BA=E9=9D=A2?= =?UTF-8?q?=E6=9D=BF=E4=BF=9D=E6=8C=81=E9=AB=98=E5=BA=A6=E5=B9=B6=E4=B8=A4?= =?UTF-8?q?=E6=AE=B5=E5=BC=8F=E6=94=B6=E8=B5=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/player/player_logic.dart | 2 + .../player/widgets/drama_comments_sheet.dart | 128 +++++++++++------- test/comment/drama_comments_sheet_test.dart | 49 +++++++ 3 files changed, 128 insertions(+), 51 deletions(-) diff --git a/lib/pages/player/player_logic.dart b/lib/pages/player/player_logic.dart index 1f887e5..43b248a 100644 --- a/lib/pages/player/player_logic.dart +++ b/lib/pages/player/player_logic.dart @@ -810,6 +810,8 @@ class PlayerLogic extends ChangeNotifier { isScrollControlled: true, backgroundColor: Colors.transparent, showDragHandle: false, + isDismissible: false, + enableDrag: false, builder: (_) => DramaCommentsSheet(drama: drama), ); } finally { diff --git a/lib/pages/player/widgets/drama_comments_sheet.dart b/lib/pages/player/widgets/drama_comments_sheet.dart index 083c30d..99cb453 100644 --- a/lib/pages/player/widgets/drama_comments_sheet.dart +++ b/lib/pages/player/widgets/drama_comments_sheet.dart @@ -178,6 +178,14 @@ class _DramaCommentsSheetState extends State { ).showSnackBar(SnackBar(content: Text(message))); } + void _handleDismissLayerTap() { + if (_inputFocus.hasFocus || _keyboardHeight(context) > 0) { + _inputFocus.unfocus(); + return; + } + Navigator.pop(context); + } + @override Widget build(BuildContext context) { final screenLimit = MediaQuery.sizeOf(context).height - 24; @@ -194,61 +202,80 @@ class _DramaCommentsSheetState extends State { availableHeight, ); _measureSheetWithoutKeyboard(keyboardHeight); - return AnimatedPadding( - duration: const Duration(milliseconds: 200), - curve: Curves.easeOut, - padding: EdgeInsets.only(bottom: keyboardHeight), - child: GestureDetector( - behavior: HitTestBehavior.translucent, - onTap: inputFocused ? _inputFocus.unfocus : null, - child: SizedBox( - key: _sheetMeasureKey, - child: Container( - key: const Key('player-comments-sheet'), - decoration: const BoxDecoration( - color: AppColors.card, - borderRadius: BorderRadius.vertical( - top: Radius.circular(_sheetRadius), - ), - ), - child: SafeArea( - top: false, - child: ListenableBuilder( - listenable: _controller, - builder: (context, _) { - final minHeight = _controller.comments.isEmpty - ? (_minSheetHeight < maxHeight - ? _minSheetHeight - : maxHeight) - : 0.0; - return AnimatedSize( - duration: const Duration(milliseconds: 200), - curve: Curves.easeOut, - alignment: Alignment.bottomCenter, - child: ConstrainedBox( - key: const Key('comment-sheet-constraints'), - constraints: keyboardOpen - ? BoxConstraints.tightFor(height: keyboardPanelHeight) - : BoxConstraints( - minHeight: minHeight, - maxHeight: maxHeight, - ), - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 16), - child: _content( - context, - expanded: expanded, - keyboardHeight: keyboardHeight, - ), - ), + return Stack( + fit: StackFit.expand, + children: [ + Positioned.fill( + child: GestureDetector( + key: const Key('player-comments-dismiss-layer'), + behavior: HitTestBehavior.opaque, + onTap: _handleDismissLayerTap, + ), + ), + Align( + alignment: Alignment.bottomCenter, + child: AnimatedPadding( + duration: const Duration(milliseconds: 200), + curve: Curves.easeOut, + padding: EdgeInsets.only(bottom: keyboardHeight), + child: GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () {}, + child: SizedBox( + key: _sheetMeasureKey, + child: Container( + key: const Key('player-comments-sheet'), + decoration: const BoxDecoration( + color: AppColors.card, + borderRadius: BorderRadius.vertical( + top: Radius.circular(_sheetRadius), ), - ); - }, + ), + child: SafeArea( + top: false, + child: ListenableBuilder( + listenable: _controller, + builder: (context, _) { + final minHeight = _controller.comments.isEmpty + ? (_minSheetHeight < maxHeight + ? _minSheetHeight + : maxHeight) + : 0.0; + return AnimatedSize( + duration: const Duration(milliseconds: 200), + curve: Curves.easeOut, + alignment: Alignment.bottomCenter, + child: ConstrainedBox( + key: const Key('comment-sheet-constraints'), + constraints: keyboardOpen + ? BoxConstraints.tightFor( + height: keyboardPanelHeight, + ) + : BoxConstraints( + minHeight: minHeight, + maxHeight: maxHeight, + ), + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 16, + ), + child: _content( + context, + expanded: expanded, + keyboardHeight: keyboardHeight, + ), + ), + ), + ); + }, + ), + ), + ), ), ), ), ), - ), + ], ); } @@ -509,7 +536,6 @@ class _DramaCommentsSheetState extends State { focused: focused, ), onTap: signedIn ? null : _authenticateForComment, - onTapOutside: (_) => _inputFocus.unfocus(), onSubmitted: focused ? null : (_) => _post(), ), ), diff --git a/test/comment/drama_comments_sheet_test.dart b/test/comment/drama_comments_sheet_test.dart index 2ea4107..383c1bf 100644 --- a/test/comment/drama_comments_sheet_test.dart +++ b/test/comment/drama_comments_sheet_test.dart @@ -307,12 +307,14 @@ void main() { final sheet = find.byKey(const Key('player-comments-sheet')); final list = find.byKey(const Key('comment-list')); + final heightBeforeKeyboard = tester.getSize(sheet).height; tester.view.viewInsets = const FakeViewPadding(bottom: 180); await tester.pump(); await tester.pump(const Duration(milliseconds: 200)); expect(sheet, findsOneWidget); expect(list, findsOneWidget); + expect(tester.getSize(sheet).height, closeTo(heightBeforeKeyboard, 0.1)); expect(find.byKey(const Key('comment-count-label')), findsOneWidget); final field = tester.widget( find.byKey(const Key('comment-input')), @@ -378,6 +380,7 @@ void main() { ); expect(collapsedField.maxLines, 1); expect(tester.getSize(find.byKey(const Key('comment-input'))).height, 44); + expect(tester.getSize(sheet).height, closeTo(heightBeforeKeyboard, 0.1)); expect(tester.getSize(sheet).height, lessThan(520)); final editableAfterKeyboard = tester.state( find.descendant( @@ -402,6 +405,52 @@ void main() { ); }); + testWidgets('should_dismiss_from_outside_in_two_steps', (tester) async { + tester.view.physicalSize = const Size(390, 844); + tester.view.devicePixelRatio = 1; + addTearDown(tester.view.resetPhysicalSize); + addTearDown(tester.view.resetDevicePixelRatio); + addTearDown(tester.view.resetViewInsets); + final repository = FakeCommentRepository( + pages: [ + CommentPage( + comments: [commentFixture(id: '10', content: 'A comment')], + ), + ], + ); + + await _pumpSheet(tester, repository: repository); + final sheet = find.byKey(const Key('player-comments-sheet')); + final input = find.byKey(const Key('comment-input')); + expect( + find.byKey(const Key('player-comments-dismiss-layer')), + findsOneWidget, + ); + + tester.view.viewInsets = const FakeViewPadding(bottom: 180); + await tester.tap(input); + await tester.pumpAndSettle(); + expect(sheet, findsOneWidget); + expect(tester.widget(input).focusNode?.hasFocus, isTrue); + + await tester.tap(find.byKey(const Key('comment-list'))); + await tester.pump(); + expect(sheet, findsOneWidget); + + await tester.tapAt(const Offset(20, 20)); + await tester.pump(); + expect(sheet, findsOneWidget); + expect(tester.widget(input).focusNode?.hasFocus, isFalse); + + tester.view.viewInsets = const FakeViewPadding(); + await tester.pumpAndSettle(); + expect(sheet, findsOneWidget); + + await tester.tapAt(const Offset(20, 20)); + await tester.pumpAndSettle(); + expect(sheet, findsNothing); + }); + testWidgets('should_use_polished_comment_sizes', (tester) async { final repository = FakeCommentRepository( pages: [