Skip to content

Commit

Permalink
feat(web): implement web pip method and event (#4370)
Browse files Browse the repository at this point in the history
Co-authored-by: Olivier Bouillet <[email protected]>
  • Loading branch information
YangJonghun and freeboub authored Jan 18, 2025
1 parent 449dfb6 commit 8dc10fd
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 5 deletions.
2 changes: 1 addition & 1 deletion docs/pages/component/events.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ Example:

### `onPictureInPictureStatusChanged`

<PlatformsList types={['iOS', 'Android']} />
<PlatformsList types={['iOS', 'Android', 'web']} />

Callback function that is called when picture in picture becomes active or inactive.

Expand Down
4 changes: 2 additions & 2 deletions docs/pages/component/methods.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ Future:

### `enterPictureInPicture`

<PlatformsList types={['Android', 'iOS']} />
<PlatformsList types={['Android', 'iOS', 'web']} />

`enterPictureInPicture()`

Expand Down Expand Up @@ -114,7 +114,7 @@ NOTE: Video ads cannot start when you are using the PIP on iOS (more info availa

### `exitPictureInPicture`

<PlatformsList types={['Android', 'iOS']} />
<PlatformsList types={['Android', 'iOS', 'web']} />

`exitPictureInPicture()`

Expand Down
53 changes: 51 additions & 2 deletions src/Video.web.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ const Video = forwardRef<VideoRef, ReactVideoProps>(
onVolumeChange,
onEnd,
onPlaybackStateChanged,
onPictureInPictureStatusChanged,
},
ref,
) => {
Expand Down Expand Up @@ -180,6 +181,31 @@ const Video = forwardRef<VideoRef, ReactVideoProps>(
[setFullScreen],
);

const enterPictureInPicture = useCallback(() => {
try {
if (!nativeRef.current) {
console.error('Video Component is not mounted');
} else {
nativeRef.current.requestPictureInPicture();
}
} catch (e) {
console.error(e);
}
}, []);

const exitPictureInPicture = useCallback(() => {
if (
nativeRef.current &&
nativeRef.current === document.pictureInPictureElement
) {
try {
document.exitPictureInPicture();
} catch (e) {
console.error(e);
}
}
}, []);

useImperativeHandle(
ref,
() => ({
Expand All @@ -193,8 +219,8 @@ const Video = forwardRef<VideoRef, ReactVideoProps>(
dismissFullscreenPlayer,
setFullScreen,
save: unsupported,
enterPictureInPicture: unsupported,
exitPictureInPicture: unsupported,
enterPictureInPicture,
exitPictureInPicture,
restoreUserInterfaceForPictureInPictureStopCompleted: unsupported,
nativeHtmlVideoRef: nativeRef,
}),
Expand All @@ -210,6 +236,8 @@ const Video = forwardRef<VideoRef, ReactVideoProps>(
presentFullscreenPlayer,
dismissFullscreenPlayer,
setFullScreen,
enterPictureInPicture,
exitPictureInPicture,
],
);

Expand Down Expand Up @@ -254,6 +282,27 @@ const Video = forwardRef<VideoRef, ReactVideoProps>(
nativeRef.current.playbackRate = rate;
}, [rate]);

useEffect(() => {
if (
typeof onPictureInPictureStatusChanged !== 'function' ||
!nativeRef.current
) {
return;
}
const onEnterPip = () =>
onPictureInPictureStatusChanged({isActive: true});
const onLeavePip = () =>
onPictureInPictureStatusChanged({isActive: false});

const video = nativeRef.current;
video.addEventListener('enterpictureinpicture', onEnterPip);
video.addEventListener('leavepictureinpicture', onLeavePip);
return () => {
video.removeEventListener('enterpictureinpicture', onEnterPip);
video.removeEventListener('leavepictureinpicture', onLeavePip);
};
}, [onPictureInPictureStatusChanged]);

useMediaSession(src?.metadata, nativeRef, showNotificationControls);

return (
Expand Down

0 comments on commit 8dc10fd

Please sign in to comment.