From c2cfe405228f42c8cbbfce8733421cbad46ff420 Mon Sep 17 00:00:00 2001 From: aviadlevy Date: Tue, 19 May 2026 22:24:01 +0300 Subject: [PATCH] feat(pip): add Picture-in-Picture support for Android and iOS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds the long-requested PiP feature for the Flutter-side video players (libMPV/libMDK). Native ExoPlayer activity is out of scope. Behavior: - The PiP icon button in the player controls is always visible on Android/iOS and lets users manually enter PiP at any time. - A new 'Auto Picture-in-Picture' setting (Settings → Player) controls only whether the OS should also auto-enter PiP when the app is backgrounded from the player. Defaults to on. - While in PiP, the controls overlay hides so only the video surface is captured for the PiP window. - Lifecycle: on player dispose, auto-enter is turned off so the user is not auto-PiP'd when backgrounding from unrelated screens. Architecture: - New PipManager wrapper (lib/wrappers/pip_manager.dart) hides package:pip behind a narrow PipClient interface so it can be unit-tested without the native plugin. Exposes enable/enter/disable/ dispose and a Stream for the current PiP state. 9 unit tests. - Riverpod providers (lib/providers/pip_provider.dart): pipManagerProvider and pipStateProvider. - VideoPlayer integration listens to the auto-enter preference and re-applies it live if the user toggles the setting mid-playback. Platform plumbing: - pubspec: add pip ^0.0.3. - Android manifest: supportsPictureInPicture=true on MainActivity. configChanges already covers screenSize|smallestScreenSize|screenLayout. - iOS Info.plist: add 'audio' to UIBackgroundModes (required for iOS PiP per package:pip docs). Caveats: - PiP aspect ratio is hardcoded 16:9. PlayerState does not currently expose video width/height; plumbing real ratios through every backend is deferred. - The native player (separate VideoPlayerActivity) already has supportsPictureInPicture in its manifest but no logic — out of scope. Closes #494. --- android/app/src/main/AndroidManifest.xml | 1 + ios/Runner/Info.plist | 1 + lib/l10n/app_en.arb | 16 ++ .../settings/video_player_settings.dart | 1 + .../video_player_settings.freezed.dart | 53 ++++-- .../settings/video_player_settings.g.dart | 2 + lib/providers/pip_provider.dart | 14 ++ .../video_player_settings_provider.dart | 2 + .../settings/player_settings_page.dart | 12 ++ lib/screens/video_player/video_player.dart | 28 ++- .../video_player/video_player_controls.dart | 29 ++- lib/wrappers/pip_manager.dart | 148 +++++++++++++++ pubspec.lock | 8 + pubspec.yaml | 1 + test/pip_manager_test.dart | 170 ++++++++++++++++++ 15 files changed, 471 insertions(+), 15 deletions(-) create mode 100644 lib/providers/pip_provider.dart create mode 100644 lib/wrappers/pip_manager.dart create mode 100644 test/pip_manager_test.dart diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 284196fc6..c2083ad9e 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -38,6 +38,7 @@ android:theme="@style/LaunchTheme" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:hardwareAccelerated="true" + android:supportsPictureInPicture="true" android:windowSoftInputMode="adjustResize">