diff --git a/android/src/main/java/com/brentvatne/exoplayer/PictureInPictureUtil.kt b/android/src/main/java/com/brentvatne/exoplayer/PictureInPictureUtil.kt index 3e3088a245..1db7f4be6d 100644 --- a/android/src/main/java/com/brentvatne/exoplayer/PictureInPictureUtil.kt +++ b/android/src/main/java/com/brentvatne/exoplayer/PictureInPictureUtil.kt @@ -43,6 +43,7 @@ object PictureInPictureUtil { val onPictureInPictureModeChanged = Consumer { info -> view.setIsInPictureInPicture(info.isInPictureInPictureMode) + view.setPictureInPictureMode(info.isInPictureInPictureMode) if (!info.isInPictureInPictureMode && activity.lifecycle.currentState == Lifecycle.State.CREATED) { // when user click close button of PIP if (!view.playInBackground) view.setPausedModifier(true) diff --git a/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java index bea60c0980..3faa2b7be1 100644 --- a/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java +++ b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java @@ -246,6 +246,7 @@ public class ReactExoplayerView extends FrameLayout implements protected boolean playInBackground = false; private boolean mReportBandwidth = false; private boolean controls = false; + private int pictureInPictureResizeMode = -1; private boolean showNotificationControls = false; // \ End props @@ -2511,6 +2512,16 @@ public void exitPictureInPictureMode() { } } + public void setPictureInPictureResizeModeModifier(@ResizeMode.Mode int resizeMode) { + this.pictureInPictureResizeMode = resizeMode; + } + + public void setPictureInPictureMode(boolean isInPiP) { + if (exoPlayerView != null && isInPiP && pictureInPictureResizeMode != -1) { + exoPlayerView.setResizeMode(pictureInPictureResizeMode); + } + } + public void setMutedModifier(boolean muted) { this.muted = muted; if (player != null) { diff --git a/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.kt b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.kt index b9e065646b..6b0f68aa71 100644 --- a/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.kt +++ b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.kt @@ -58,6 +58,7 @@ class ReactExoplayerViewManager(private val config: ReactExoplayerConfig) : View private const val PROP_SHOW_NOTIFICATION_CONTROLS = "showNotificationControls" private const val PROP_DEBUG = "debug" private const val PROP_CONTROLS_STYLES = "controlsStyles" + private const val PROP_PICTURE_IN_PICTURE_RESIZE_MODE = "pictureInPictureResizeMode" } override fun getName(): String = REACT_CLASS @@ -258,6 +259,23 @@ class ReactExoplayerViewManager(private val config: ReactExoplayerConfig) : View videoView.setDebug(enableDebug) } + @ReactProp(name = PROP_PICTURE_IN_PICTURE_RESIZE_MODE) + fun setPictureInPictureResizeMode(videoView: ReactExoplayerView, resizeMode: String?) { + val mode = when (resizeMode) { + "none", "contain" -> ResizeMode.RESIZE_MODE_FIT + "cover" -> ResizeMode.RESIZE_MODE_CENTER_CROP + "stretch" -> ResizeMode.RESIZE_MODE_FILL + else -> { + if (resizeMode != null) { + DebugLog.w(TAG, "Unsupported PiP resize mode: $resizeMode - falling back to fit") + } + ResizeMode.RESIZE_MODE_FIT + } + } + + videoView.setPictureInPictureResizeModeModifier(mode) + } + @ReactProp(name = PROP_CONTROLS_STYLES) fun setControlsStyles(videoView: ReactExoplayerView, controlsStyles: ReadableMap?) { val controlsConfig = ControlsConfig.parse(controlsStyles) diff --git a/package.json b/package.json index 26e11ab0d7..d8a5a6a27e 100644 --- a/package.json +++ b/package.json @@ -15,17 +15,27 @@ "devDependencies": { "@expo/config-plugins": "^8.0.5", "@jamesacarr/eslint-formatter-github-actions": "^0.2.0", - "@react-native/eslint-config": "^0.72.2", + "@react-native/eslint-config": "0.81.1", + "@react-native/eslint-plugin": "0.81.1", "@release-it/conventional-changelog": "^7.0.2", "@types/jest": "^28.1.2", "@types/react": "~19.0.0", "@types/react-native-web": "^0.19.1", - "@typescript-eslint/eslint-plugin": "^6.7.4", - "eslint": "^8.19.0", + "@typescript-eslint/eslint-plugin": "^7.18.0", + "@typescript-eslint/parser": "^7.18.0", + "eslint": "^8", + "eslint-config-prettier": "^10.1.8", + "eslint-plugin-eslint-comments": "^3.2.0", + "eslint-plugin-ft-flow": "^3.0.11", "eslint-plugin-jest": "^27.4.2", + "eslint-plugin-prettier": "^5.5.4", + "eslint-plugin-react": "^7.37.5", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-native": "^5.0.0", "husky": "^9.1.7", "jest": "^29.7.0", - "prettier": "^2.4.1", + "ktlint": "^0.0.5", + "prettier": "^3.6.2", "react": "18.2.0", "react-native": "0.78.2", "react-native-web": "0.20.0", diff --git a/src/Video.tsx b/src/Video.tsx index 6d39f24ae3..b20c2f4aa2 100644 --- a/src/Video.tsx +++ b/src/Video.tsx @@ -109,6 +109,7 @@ const Video = forwardRef( localSourceEncryptionKeyScheme, minLoadRetryCount, bufferConfig, + pictureInPictureResizeMode, ...rest }, ref, @@ -905,6 +906,7 @@ const Video = forwardRef( onControlsVisibilityChange ? _onControlsVisibilityChange : undefined } viewType={_viewType} + pictureInPictureResizeMode={pictureInPictureResizeMode} /> {_renderPoster()} diff --git a/src/specs/VideoNativeComponent.ts b/src/specs/VideoNativeComponent.ts index 493736d990..3a70ecce51 100644 --- a/src/specs/VideoNativeComponent.ts +++ b/src/specs/VideoNativeComponent.ts @@ -401,6 +401,7 @@ export interface VideoNativeProps extends ViewProps { onTextTracks?: DirectEventHandler; // android onTextTrackDataChanged?: DirectEventHandler; // iOS onVideoTracks?: DirectEventHandler; // android + pictureInPictureResizeMode?: WithDefault; } type NativeVideoComponentType = HostComponent; diff --git a/src/types/video.ts b/src/types/video.ts index 82861bd667..d889d57ec3 100644 --- a/src/types/video.ts +++ b/src/types/video.ts @@ -91,14 +91,14 @@ export type Drm = Readonly<{ base64Certificate?: boolean; // ios default: false multiDrm?: boolean; // android localSourceEncryptionKeyScheme?: string; // ios - /* eslint-disable @typescript-eslint/no-unused-vars */ + getLicense?: ( spcBase64: string, contentId: string, licenseUrl: string, loadedLicenseUrl: string, ) => string | Promise; // ios - /* eslint-enable @typescript-eslint/no-unused-vars */ + }>; export enum CmcdMode { @@ -351,4 +351,5 @@ export interface ReactVideoProps extends ReactVideoEvents, ViewProps { allowsExternalPlayback?: boolean; // iOS controlsStyles?: ControlsStyles; // Android disableAudioSessionManagement?: boolean; // iOS + pictureInPictureResizeMode?: EnumValues; // Android }