From 0af5de9641564c59086e1851b0bfe4f4a05ab710 Mon Sep 17 00:00:00 2001 From: Zhou Weidong <502333560@qq.com> Date: Tue, 20 Oct 2026 11:47:58 +0800 Subject: [PATCH] =?UTF-8?q?fix(flutter):=20=E6=9B=B4=E5=A4=9A=E9=9D=A2?= =?UTF-8?q?=E6=9D=BF=E5=A2=9E=E5=8A=A0=E5=B0=8F=E7=AA=97=E6=92=AD=E6=94=BE?= =?UTF-8?q?=E5=85=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/player/player_view_actions.dart | 3 + .../player/widgets/player_more_sheet.dart | 11 +++ test/player/player_fullscreen_test.dart | 25 +++++- test/player/player_more_sheet_test.dart | 77 +++++++++++++++++++ 4 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 test/player/player_more_sheet_test.dart diff --git a/lib/pages/player/player_view_actions.dart b/lib/pages/player/player_view_actions.dart index 748cc50..ca874c1 100644 --- a/lib/pages/player/player_view_actions.dart +++ b/lib/pages/player/player_view_actions.dart @@ -35,6 +35,9 @@ extension _PlayerViewActions on _PlayerPageState { }, onClear: _hideChrome, onDownload: () => requestEpisodeDownload(context, episode.id), + onPip: logic.pictureInPicture.isPlatformSupported + ? () => unawaited(logic.enterPip(context)) + : null, ), ), ); diff --git a/lib/pages/player/widgets/player_more_sheet.dart b/lib/pages/player/widgets/player_more_sheet.dart index 53cf4df..49eb80f 100644 --- a/lib/pages/player/widgets/player_more_sheet.dart +++ b/lib/pages/player/widgets/player_more_sheet.dart @@ -35,6 +35,7 @@ class PlayerMoreActions { required this.onSpeedChanged, required this.onClear, required this.onDownload, + this.onPip, }); /// 倍速变化。 @@ -45,6 +46,9 @@ class PlayerMoreActions { /// 离线缓存当前集。 final VoidCallback onDownload; + + /// 进入小窗播放;平台不支持时为 null。 + final VoidCallback? onPip; } /// K29.6 精简版播放页更多面板。 @@ -113,6 +117,13 @@ class _PlayerMoreSheetState extends State { title: l10n.clearPlayback, onTap: _clear, ), + if (widget.actions.onPip != null) + _actionRow( + key: const Key('player-more-pip'), + icon: Icons.picture_in_picture_alt_rounded, + title: l10n.pictureInPicture, + onTap: () => _closeThen(widget.actions.onPip!), + ), _actionRow( key: const Key('player-more-offline'), icon: Icons.download_rounded, diff --git a/test/player/player_fullscreen_test.dart b/test/player/player_fullscreen_test.dart index 6db27eb..9b9d1ee 100644 --- a/test/player/player_fullscreen_test.dart +++ b/test/player/player_fullscreen_test.dart @@ -389,7 +389,6 @@ void main() { Key('player-more-text-size'), Key('player-more-cast'), Key('player-more-timer'), - Key('player-more-pip'), Key('player-more-report'), ]) { expect(find.byKey(removed), findsNothing); @@ -506,6 +505,30 @@ void main() { expect(find.text('720P · Unavailable'), findsOneWidget); }); + testWidgets('should_show_pip_action_when_platform_supported', (tester) async { + await _pumpApp(tester); + await _openSeriesPlayer(tester); + await tester.tap(find.byKey(const Key('player-more'))); + await tester.pumpAndSettle(); + + expect(find.byKey(const Key('player-more-pip')), findsOneWidget); + expect(find.byKey(const Key('player-more-clear')), findsOneWidget); + expect(find.byKey(const Key('player-more-offline')), findsOneWidget); + }, variant: TargetPlatformVariant.only(TargetPlatform.android)); + + testWidgets('should_hide_pip_action_when_platform_unsupported', ( + tester, + ) async { + await _pumpApp(tester); + await _openSeriesPlayer(tester); + await tester.tap(find.byKey(const Key('player-more'))); + await tester.pumpAndSettle(); + + expect(find.byKey(const Key('player-more-pip')), findsNothing); + expect(find.byKey(const Key('player-more-clear')), findsOneWidget); + expect(find.byKey(const Key('player-more-offline')), findsOneWidget); + }, variant: TargetPlatformVariant.only(TargetPlatform.macOS)); + testWidgets('should_enter_clear_screen_from_more_panel', (tester) async { await _pumpApp(tester); await _openSeriesPlayer(tester); diff --git a/test/player/player_more_sheet_test.dart b/test/player/player_more_sheet_test.dart new file mode 100644 index 0000000..3929b53 --- /dev/null +++ b/test/player/player_more_sheet_test.dart @@ -0,0 +1,77 @@ +// Author: fruit.com.cn + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'package:fruitshorts/l10n/app_localizations.dart'; +import 'package:fruitshorts/pages/player/widgets/player_more_sheet.dart'; + +void main() { + testWidgets('should_hide_pip_row_when_platform_unsupported', (tester) async { + await _openSheet(tester); + + expect(find.byKey(const Key('player-more-sheet')), findsOneWidget); + expect(find.byKey(const Key('player-more-clear')), findsOneWidget); + expect(find.byKey(const Key('player-more-offline')), findsOneWidget); + expect(find.byKey(const Key('player-more-pip')), findsNothing); + }); + + testWidgets('should_trigger_pip_and_close_sheet_when_tapped', (tester) async { + var pipCalls = 0; + await _openSheet(tester, onPip: () => pipCalls++); + + expect(find.byKey(const Key('player-more-pip')), findsOneWidget); + expect( + tester.getTopLeft(find.byKey(const Key('player-more-clear'))).dy < + tester.getTopLeft(find.byKey(const Key('player-more-pip'))).dy, + isTrue, + ); + expect( + tester.getTopLeft(find.byKey(const Key('player-more-pip'))).dy < + tester.getTopLeft(find.byKey(const Key('player-more-offline'))).dy, + isTrue, + ); + + await tester.tap(find.byKey(const Key('player-more-pip'))); + await tester.pumpAndSettle(); + + expect(pipCalls, 1); + expect(find.byKey(const Key('player-more-sheet')), findsNothing); + }); +} + +Future _openSheet(WidgetTester tester, {VoidCallback? onPip}) async { + await tester.pumpWidget( + MaterialApp( + supportedLocales: AppLocalizations.supportedLocales, + localizationsDelegates: AppLocalizations.localizationsDelegates, + home: Scaffold( + body: Builder( + builder: (context) => Center( + child: TextButton( + key: const Key('open-more-sheet'), + onPressed: () => showModalBottomSheet( + context: context, + backgroundColor: Colors.transparent, + isScrollControlled: true, + builder: (_) => PlayerMoreSheet( + l10n: AppLocalizations.of(context)!, + state: const PlayerMoreState(speed: 1.0, qualities: ['AUTO']), + actions: PlayerMoreActions( + onSpeedChanged: (_) {}, + onClear: () {}, + onDownload: () {}, + onPip: onPip, + ), + ), + ), + child: const Text('open'), + ), + ), + ), + ), + ), + ); + await tester.tap(find.byKey(const Key('open-more-sheet'))); + await tester.pumpAndSettle(); +}