feat(pip): add Picture-in-Picture support for Android and iOS#995
Open
aviadlevy wants to merge 1 commit into
Open
feat(pip): add Picture-in-Picture support for Android and iOS#995aviadlevy wants to merge 1 commit into
aviadlevy wants to merge 1 commit into
Conversation
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<bool> 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 DonutWare#494.
Author
|
Found a small thing I missed - when minimized and then home is pressed it's not getting into pip, just exit. I'll be able to tackle it on Sunday |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds Picture-in-Picture (PiP) support for the Flutter-rendered video players (
libMPV/libMDK) on Android, with the iOS plumbing in place but untested. The standalone native ExoPlayerVideoPlayerActivityis intentionally out of scope.Behavior
Architecture
lib/wrappers/pip_manager.dart— newPipManagerwrapper hidespackage:pipbehind a narrowPipClientinterface so it can be unit-tested without the native plugin. Exposesenable/enter/disable/disposeand aStream<bool>for the current PiP state. 9 unit tests.lib/providers/pip_provider.dart—pipManagerProvider+pipStateProvider.VideoPlayerintegration listens to the auto-enter preference and re-applies it live if the user toggles the setting mid-playback.Platform plumbing
pubspec.yaml: addpip: ^0.0.3(only file inlib/that importspackage:pipis the wrapper).android/app/src/main/AndroidManifest.xml: addandroid:supportsPictureInPicture="true"toMainActivity.configChangesalready coversscreenSize|smallestScreenSize|screenLayout.ios/Runner/Info.plist: addaudiotoUIBackgroundModes(required for iOS PiP perpackage:pipdocs).Decisions taken during implementation
…more button, landscape-only — phone portrait was overflowing the row (RIGHT OVERFLOWED BY 46 PIXELS). Portrait users access PiP via the Home button + the auto-enter setting.Icons.picture_in_picture_alt_outlined(rather than an IconsaxPlusLinear equivalent) — matches the de-facto Flutter standard used by other video apps (frosty, mydia) and YouTube/Netflix; the universal "rectangle-with-corner-rectangle" glyph is more discoverable than a generic maximize icon.PlayerStatedoes not currently expose video width/height. Plumbing real ratios through every backend was deferred to keep the PR focused.VideoPlayerActivity(ExoPlayer/Compose) already hassupportsPictureInPicturein its manifest but no logic; wiring that needs a separate Kotlin-side change and would have doubled the PR's surface area.Never / Always / Only with headphonesfrom the original discussion. Smaller surface, easier to maintain; can be expanded later if there's demand.Caveats & known limitations
Info.plistchange is in, but I do not have an iOS dev environment. The flow should work perpackage:pipdocs but should be validated by someone with an iPhone before being treated as supported.Implementation notes
This PR was implemented with the help of an AI coding assistant (Claude Code). All decisions, UX trade-offs, and code review were human-driven; the AI handled mechanical edits and the wrapper/test scaffolding. Generated code follows the project's existing conventions (
dart format --line-length 120, sparse comments, freezed for settings).Issue Being Fixed
Picture-in-Picture has been requested multiple times across several discussions. This PR addresses the mobile (Android) portion of those asks.
enableDoubleTapSeeksetting). The PiP part — assumed mobile based on context — is addressed.Screenshots / Recordings
Tested On
Checklist
pip ^0.0.3is a 0.0.x release with limited maintenance history; flagging as a known trade-off. Cross-platform (Android/iOS) by design. Open to swapping for a more mature alternative if maintainers prefer.