From c87798fb16c0de650179d9430b35cbd0500daef3 Mon Sep 17 00:00:00 2001 From: Zhou Weidong <502333560@qq.com> Date: Tue, 20 Oct 2026 14:33:35 +0800 Subject: [PATCH] =?UTF-8?q?fix(flutter):=20feed=20=E6=B8=85=E5=B1=8F?= =?UTF-8?q?=E4=BF=9D=E7=95=99=E9=A1=B6=E6=A0=8F=E5=B9=B6=E5=AF=BB=E5=9D=80?= =?UTF-8?q?=E6=81=A2=E5=A4=8D=E6=92=AD=E6=94=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/player/player_logic.dart | 12 +++++- lib/pages/player/player_view.dart | 17 +++----- .../player/widgets/home_feed_overlay.dart | 18 +++----- test/home/k28_a_navigation_test.dart | 43 +++++++++++++++++-- test/player/player_logic_test.dart | 21 +++++++++ 5 files changed, 83 insertions(+), 28 deletions(-) diff --git a/lib/pages/player/player_logic.dart b/lib/pages/player/player_logic.dart index 5920184..5c66f9f 100644 --- a/lib/pages/player/player_logic.dart +++ b/lib/pages/player/player_logic.dart @@ -578,7 +578,11 @@ class PlayerLogic extends ChangeNotifier { await session.playbackSettled; if (scrubbingPlayer != player || session.active != player) return; await player.controller.seekTo(position); - if (session.active == player) await saveCurrentProgress(); + if (session.active == player) { + // 暂停时拖动进度后直接恢复播放,避免画面停在旧位置。 + resumeAfterSeek(); + await saveCurrentProgress(); + } } catch (_) { if (context.mounted && session.active == player) { final l10n = AppLocalizations.of(context)!; @@ -591,6 +595,12 @@ class PlayerLogic extends ChangeNotifier { } } + /// 拖动进度落点后恢复播放;暂停态拖动不应停留在暂停。 + @visibleForTesting + void resumeAfterSeek() { + if (!session.userWantsPlay) session.setUserWantsPlay(true); + } + Future leave(BuildContext context) async { await saveCurrentProgress(); if (context.mounted) Navigator.of(context).pop(); diff --git a/lib/pages/player/player_view.dart b/lib/pages/player/player_view.dart index 3708c22..70a69a4 100644 --- a/lib/pages/player/player_view.dart +++ b/lib/pages/player/player_view.dart @@ -510,17 +510,12 @@ class _PlayerPageState extends State with WidgetsBindingObserver { ), if (widget.homeMode && !_chromeVisible) Positioned( - top: 0, - right: 0, - child: SafeArea( - left: false, - bottom: false, - minimum: const EdgeInsets.only(top: 8, right: 12), - child: ExitClearScreenButton( - key: const Key('home-feed-exit-clear-screen'), - tooltip: l10n.exitClearScreen, - onPressed: () => setState(() => _chromeVisible = true), - ), + right: 12, + bottom: 56, + child: ExitClearScreenButton( + key: const Key('home-feed-exit-clear-screen'), + tooltip: l10n.exitClearScreen, + onPressed: () => setState(() => _chromeVisible = true), ), ), if (widget.homeMode && diff --git a/lib/pages/player/widgets/home_feed_overlay.dart b/lib/pages/player/widgets/home_feed_overlay.dart index 70b5e20..18fd684 100644 --- a/lib/pages/player/widgets/home_feed_overlay.dart +++ b/lib/pages/player/widgets/home_feed_overlay.dart @@ -131,23 +131,17 @@ class _HomeFeedOverlayState extends State { ), if (widget.boosting) Column(children: [const Spacer(), _boostHint(), _fullSeriesBar()]) - else if (widget.visible) + else Column( children: [ _header(context), - Expanded( - child: Align( - alignment: Alignment.bottomRight, - child: Padding( - padding: const EdgeInsets.fromLTRB(0, 0, 10, 12), - child: _rail(), - ), - ), - ), - _bottomInfo(), + const Spacer(), + if (widget.visible) _bottomInfo(), _fullSeriesBar(), ], ), + if (widget.visible && !widget.boosting) + Positioned(right: 10, bottom: 56, child: _rail()), ], ), ); @@ -307,7 +301,7 @@ class _HomeFeedOverlayState extends State { Widget _bottomInfo() { return Padding( - padding: const EdgeInsets.fromLTRB(14, 0, 14, 8), + padding: const EdgeInsets.fromLTRB(14, 0, 56, 8), child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, diff --git a/test/home/k28_a_navigation_test.dart b/test/home/k28_a_navigation_test.dart index 4b417f0..bda1d33 100644 --- a/test/home/k28_a_navigation_test.dart +++ b/test/home/k28_a_navigation_test.dart @@ -114,13 +114,48 @@ void main() { final railBottom = tester .getRect(find.byKey(const Key('rail-share'))) .bottom; - final infoTop = tester - .getRect(find.byKey(const Key('home-feed-series-meta'))) + final seriesTop = tester + .getRect(find.byKey(const Key('home-feed-full-series'))) .top; + final titleRight = tester + .getRect(find.byKey(const Key('home-feed-title'))) + .right; + final railLeft = tester.getRect(find.byKey(const Key('rail-save'))).left; expect(railTop, greaterThan(844 * 0.45)); - expect(railBottom, lessThanOrEqualTo(infoTop)); - expect(infoTop - railBottom, lessThanOrEqualTo(20)); + expect(seriesTop - railBottom, closeTo(12, 1)); + expect(titleRight, lessThanOrEqualTo(railLeft + 2)); + }); + + testWidgets('should_keep_feed_header_and_progress_after_clear', ( + tester, + ) async { + await _pumpApp(tester); + final gesture = await tester.startGesture(const Offset(195, 300)); + await tester.pump(const Duration(milliseconds: 700)); + await tester.pump(); + await gesture.up(); + await tester.pumpAndSettle(); + await tester.tap(find.byKey(const Key('player-more-clear'))); + await tester.pumpAndSettle(); + + expect(find.byKey(const Key('home-feed-refresh')), findsOneWidget); + expect(find.byKey(const Key('home-feed-tab-recommend')), findsOneWidget); + expect(find.byKey(const Key('home-feed-search')), findsOneWidget); + expect(find.byKey(const Key('home-feed-full-series')), findsOneWidget); + expect(find.byKey(const Key('home-feed-progress')), findsOneWidget); + expect(find.byKey(const Key('rail-save')), findsNothing); + expect(find.byKey(const Key('home-feed-title')), findsNothing); + final exit = tester.getRect( + find.byKey(const Key('home-feed-exit-clear-screen')), + ); + expect(exit.right, greaterThan(340)); + expect(exit.center.dy, greaterThan(600)); + + await tester.tap(find.byKey(const Key('home-feed-exit-clear-screen'))); + await tester.pumpAndSettle(); + expect(find.byKey(const Key('rail-save')), findsOneWidget); + expect(find.byKey(const Key('home-feed-title')), findsOneWidget); }); testWidgets('should_boost_feed_on_side_long_press', (tester) async { diff --git a/test/player/player_logic_test.dart b/test/player/player_logic_test.dart index c0235c2..9c42526 100644 --- a/test/player/player_logic_test.dart +++ b/test/player/player_logic_test.dart @@ -215,6 +215,27 @@ void main() { logic.dispose(); await _drain(logic); }); + + test('should_resume_playback_after_seek_when_paused', () async { + final logic = _logic(FakeWatchHistory()); + logic.attach( + PlayerPage(drama: _drama('signal'), initialIndex: 0), + isMounted: () => true, + ); + logic.start( + factory: _RecordingFactory().create, + coordinator: PlaybackCoordinator(), + ); + await _drain(logic); + logic.session.setUserWantsPlay(false); + expect(logic.session.userWantsPlay, isFalse); + + logic.resumeAfterSeek(); + + expect(logic.session.userWantsPlay, isTrue); + logic.dispose(); + await _drain(logic); + }); }); group('history writes', () {