From 5b7a8bd7750729dec9cd55c28b4984fd50e3b536 Mon Sep 17 00:00:00 2001 From: Zhou Weidong <502333560@qq.com> Date: Mon, 19 Oct 2026 17:29:01 +0800 Subject: [PATCH] =?UTF-8?q?fix(player):=20=E5=85=B1=E4=BA=AB=E6=B8=85?= =?UTF-8?q?=E5=B1=8F=E7=8A=B6=E6=80=81=E5=B9=B6=E5=B7=A6=E8=B4=B4=E9=9B=86?= =?UTF-8?q?=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/player/player_view.dart | 43 ++++++++--------- .../player/widgets/home_feed_overlay.dart | 47 +++++++------------ test/home/home_preview_layout_test.dart | 7 +++ test/player/player_fullscreen_test.dart | 31 ++++++++++++ 4 files changed, 78 insertions(+), 50 deletions(-) diff --git a/lib/pages/player/player_view.dart b/lib/pages/player/player_view.dart index f71462b..aae3c20 100644 --- a/lib/pages/player/player_view.dart +++ b/lib/pages/player/player_view.dart @@ -71,7 +71,7 @@ class PlayerPage extends StatefulWidget { class _PlayerPageState extends State with WidgetsBindingObserver { late final PlayerLogic logic; - bool _feedChromeVisible = true; + bool _chromeVisible = true; @override void initState() { @@ -190,7 +190,7 @@ class _PlayerPageState extends State with WidgetsBindingObserver { children: [ const ColoredBox(color: AppColors.ink), ?video, - if (!logic.chromeHidden && (!widget.homeMode || _feedChromeVisible)) + if (!logic.chromeHidden && (!widget.homeMode || _chromeVisible)) IgnorePointer( key: widget.homeMode ? const Key('home-feed-scrim') : null, child: const DecoratedBox( @@ -209,7 +209,7 @@ class _PlayerPageState extends State with WidgetsBindingObserver { ), ), ), - if (widget.homeMode && _feedChromeVisible && !logic.chromeHidden) + if (widget.homeMode && _chromeVisible && !logic.chromeHidden) Positioned.fill( child: GestureDetector( key: const Key('home-feed-video-toggle'), @@ -317,7 +317,7 @@ class _PlayerPageState extends State with WidgetsBindingObserver { if (logic.pip || logic.pipPreparing) const SizedBox.expand() else if (widget.homeMode) - _feedChromeVisible + _chromeVisible ? HomeFeedOverlay( l10n: l10n, drama: drama, @@ -359,7 +359,7 @@ class _PlayerPageState extends State with WidgetsBindingObserver { onShare: () => logic.shareDrama(context, drama), onEpisodes: () => logic.showEpisodes(context), onDownload: () => requestEpisodeDownload(context, episode.id), - onClear: () => setState(() => _feedChromeVisible = false), + onClear: () => setState(() => _chromeVisible = false), onSearch: widget.onSearch ?? () => logic.showDiscover(context), onPip: logic.pictureInPicture.isPlatformSupported @@ -384,6 +384,9 @@ class _PlayerPageState extends State with WidgetsBindingObserver { ? () => unawaited(logic.playNextEpisode()) : null, playing: logic.session.userWantsPlay, + controlsVisible: _chromeVisible, + onClear: () => setState(() => _chromeVisible = false), + onExitClear: () => setState(() => _chromeVisible = true), onTogglePlay: () => logic.session.setUserWantsPlay(!logic.session.userWantsPlay), // 收藏/点赞要对到具体账号:未登录先引导登录(首页/详情仍可匿名浏览) @@ -427,7 +430,7 @@ class _PlayerPageState extends State with WidgetsBindingObserver { ? (position) => logic.seekTo(context, videoPort!, position) : null, ), - if (widget.homeMode && !_feedChromeVisible) + if (widget.homeMode && !_chromeVisible) Positioned.fill( child: GestureDetector( key: const Key('home-feed-video-tap'), @@ -436,7 +439,7 @@ class _PlayerPageState extends State with WidgetsBindingObserver { logic.session.setUserWantsPlay(!logic.session.userWantsPlay), ), ), - if (widget.homeMode && !_feedChromeVisible) + if (widget.homeMode && !_chromeVisible) Positioned( top: 0, right: 0, @@ -447,7 +450,7 @@ class _PlayerPageState extends State with WidgetsBindingObserver { child: ExitClearScreenButton( key: const Key('home-feed-exit-clear-screen'), tooltip: l10n.exitClearScreen, - onPressed: () => setState(() => _feedChromeVisible = true), + onPressed: () => setState(() => _chromeVisible = true), ), ), ), @@ -599,7 +602,10 @@ class _PlaybackOverlay extends StatefulWidget { required this.liked, required this.saved, required this.playing, + required this.controlsVisible, required this.onTogglePlay, + required this.onClear, + required this.onExitClear, required this.onBack, required this.onEpisodes, required this.onComments, @@ -620,7 +626,10 @@ class _PlaybackOverlay extends StatefulWidget { final bool liked; final bool saved; final bool playing; + final bool controlsVisible; final VoidCallback onTogglePlay; + final VoidCallback onClear; + final VoidCallback onExitClear; final VoidCallback? onBack; final VoidCallback onEpisodes; final VoidCallback onComments; @@ -638,14 +647,6 @@ class _PlaybackOverlay extends StatefulWidget { } class _PlaybackOverlayState extends State<_PlaybackOverlay> { - bool _controlsVisible = true; - - void _onVideoTap() { - widget.onTogglePlay(); - } - - void _clearScreen() => setState(() => _controlsVisible = false); - @override Widget build(BuildContext context) { return SafeArea( @@ -655,10 +656,10 @@ class _PlaybackOverlayState extends State<_PlaybackOverlay> { child: GestureDetector( key: const Key('player-video-tap'), behavior: HitTestBehavior.opaque, - onTap: _onVideoTap, + onTap: widget.onTogglePlay, ), ), - if (_controlsVisible) + if (widget.controlsVisible) Column( key: const Key('player-controls-visible'), children: [ @@ -766,14 +767,14 @@ class _PlaybackOverlayState extends State<_PlaybackOverlay> { ), ], ), - if (!_controlsVisible) + if (!widget.controlsVisible) Positioned( top: 8, right: 12, child: ExitClearScreenButton( key: const Key('player-exit-clear-screen'), tooltip: widget.l10n.exitClearScreen, - onPressed: () => setState(() => _controlsVisible = true), + onPressed: widget.onExitClear, ), ), if (!widget.playing) @@ -828,7 +829,7 @@ class _PlaybackOverlayState extends State<_PlaybackOverlay> { key: const Key('player-clear-screen'), tooltip: widget.l10n.clearScreen, icon: Icons.fullscreen_rounded, - onPressed: _clearScreen, + onPressed: widget.onClear, ), const SizedBox(width: 8), _TopAction( diff --git a/lib/pages/player/widgets/home_feed_overlay.dart b/lib/pages/player/widgets/home_feed_overlay.dart index 292d4ed..77b35da 100644 --- a/lib/pages/player/widgets/home_feed_overlay.dart +++ b/lib/pages/player/widgets/home_feed_overlay.dart @@ -167,38 +167,27 @@ class HomeFeedOverlay extends StatelessWidget { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - Row( + Wrap( + spacing: 6, + runSpacing: 4, + crossAxisAlignment: WrapCrossAlignment.center, children: [ - Expanded( - child: Wrap( - spacing: 6, - runSpacing: 4, - children: [ - if (genre.isNotEmpty) - _tag( - genre, - background: AppColors.blue, - foreground: AppColors.onPrimary, - ), - if (drama.category.isNotEmpty && drama.category != genre) - _tag( - drama.category, - background: const Color(0xFF333333), - foreground: const Color(0xFFDDDDDD), - ), - ], + if (genre.isNotEmpty) + _tag( + genre, + background: AppColors.blue, + foreground: AppColors.onPrimary, ), - ), - const SizedBox(width: 8), - Flexible( - child: Text( - l10n.episodeOfTotal(episode.number, drama.episodeCount), - key: const Key('home-feed-episode'), - maxLines: 1, - overflow: TextOverflow.ellipsis, - textAlign: TextAlign.right, - style: const TextStyle(color: Color(0xFFBBBBBB), fontSize: 9), + if (drama.category.isNotEmpty && drama.category != genre) + _tag( + drama.category, + background: const Color(0xFF333333), + foreground: const Color(0xFFDDDDDD), ), + Text( + l10n.episodeOfTotal(episode.number, drama.episodeCount), + key: const Key('home-feed-episode'), + style: const TextStyle(color: Color(0xFFBBBBBB), fontSize: 9), ), ], ), diff --git a/test/home/home_preview_layout_test.dart b/test/home/home_preview_layout_test.dart index df22998..6d267ae 100644 --- a/test/home/home_preview_layout_test.dart +++ b/test/home/home_preview_layout_test.dart @@ -54,6 +54,13 @@ void main() { expect(find.byKey(const Key('home-feed-title')), findsOneWidget); expect(find.byKey(const Key('home-feed-info-card')), findsOneWidget); expect(find.byKey(const Key('home-feed-episode')), findsOneWidget); + final cardRect = tester.getRect( + find.byKey(const Key('home-feed-info-card')), + ); + final episodeRect = tester.getRect( + find.byKey(const Key('home-feed-episode')), + ); + expect(episodeRect.left, lessThan(cardRect.center.dx)); expect(find.byKey(const Key('home-feed-follow-series')), findsOneWidget); expect(find.byKey(const Key('home-feed-episodes')), findsOneWidget); for (final key in const [Key('home-feed-search'), Key('home-feed-more')]) { diff --git a/test/player/player_fullscreen_test.dart b/test/player/player_fullscreen_test.dart index 46737d5..b27f2a1 100644 --- a/test/player/player_fullscreen_test.dart +++ b/test/player/player_fullscreen_test.dart @@ -216,6 +216,37 @@ void main() { expect(tester.takeException(), isNull); }); + testWidgets('should_keep_series_clear_state_when_swiping_next_episode', ( + tester, + ) async { + await _pumpApp(tester); + await tester.binding.handlePopRoute(); + await tester.pumpAndSettle(); + await tester.binding.handlePopRoute(); + await tester.pumpAndSettle(); + await tester.tap(find.byKey(const Key('drawer-open-series'))); + await tester.pumpAndSettle(); + await tester.tap(find.byKey(const Key('detail-cta'))); + await tester.pumpAndSettle(); + + await tester.tap(find.byKey(const Key('player-clear-screen'))); + await tester.pump(); + expect(find.byKey(const Key('player-controls-top')), findsNothing); + + await tester.drag(find.byType(PageView), const Offset(0, -550)); + await tester.pumpAndSettle(); + + expect(find.byKey(const Key('player-controls-top')), findsNothing); + expect(find.byKey(const Key('player-controls-bottom')), findsNothing); + expect(find.byKey(const Key('player-exit-clear-screen')), findsOneWidget); + + await tester.tap(find.byKey(const Key('player-exit-clear-screen'))); + await tester.pump(); + expect(find.byKey(const Key('player-controls-top')), findsOneWidget); + expect(find.byKey(const Key('player-controls-bottom')), findsOneWidget); + expect(find.byKey(const Key('player-exit-clear-screen')), findsNothing); + }); + testWidgets('should_clear_and_restore_home_feed_chrome', (tester) async { await _pumpApp(tester); await tester.tap(find.byKey(const Key('tab-home')));