Skip to content

Commit

Permalink
feat(pipconfigplayerviewconfig): move PictureInPictureConfig to Playe…
Browse files Browse the repository at this point in the history
…rViewConfig
  • Loading branch information
rolandkakonyi committed Oct 19, 2023
1 parent c68292b commit c6dc947
Show file tree
Hide file tree
Showing 9 changed files with 81 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@ class RNPlayerView(val context: ReactApplicationContext) :
View.OnLayoutChangeListener,
RNPictureInPictureDelegate {

data class RNPlayerViewConfig(
val playerViewConfig: PlayerViewConfig?,
val pictureInPictureConfig: RNPictureInPictureHandler.PictureInPictureConfig?,
)
init {
// React Native has a bug that dynamically added views sometimes aren't laid out again properly.
// Since we dynamically add and remove SurfaceView under the hood this caused the player
Expand Down Expand Up @@ -145,15 +149,10 @@ class RNPlayerView(val context: ReactApplicationContext) :
*/
var pictureInPictureHandler: RNPictureInPictureHandler? = null

/**
* Configuration for picture in picture behaviors.
*/
var pictureInPictureConfig: RNPictureInPictureHandler.PictureInPictureConfig? = null

/**
* Configures the visual presentation and behaviour of the [playerView].
*/
var config: PlayerViewConfig? = null
var config: RNPlayerViewConfig? = null

/**
* Whether this view should pause video playback when activity's onPause is called.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,14 +183,9 @@ class RNPlayerViewManager(private val context: ReactApplicationContext) : Simple
}
}

@ReactProp(name = "pictureInPictureConfig")
fun setPictureInPictureConfig(view: RNPlayerView, pictureInPictureConfig: ReadableMap?) {
view.pictureInPictureConfig = JsonConverter.toPictureInPictureConfig(pictureInPictureConfig)
}

@ReactProp(name = "config")
fun setConfig(view: RNPlayerView, config: ReadableMap?) {
view.config = if (config != null) JsonConverter.toPlayerViewConfig(config) else null
view.config = if (config != null) JsonConverter.toRNPlayerViewConfig(config) else null
}

private fun attachFullscreenBridge(view: RNPlayerView, fullscreenBridgeId: NativeId) {
Expand Down Expand Up @@ -253,7 +248,7 @@ class RNPlayerViewManager(private val context: ReactApplicationContext) : Simple
Handler(Looper.getMainLooper()).post {
val player = getPlayerModule()?.getPlayer(playerId)
val playbackConfig = playerConfig?.getMap("playbackConfig")
val isPictureInPictureEnabled = view.pictureInPictureConfig?.isEnabled == true ||
val isPictureInPictureEnabled = view.config?.pictureInPictureConfig?.isEnabled == true ||
playbackConfig?.getBooleanOrNull("isPictureInPictureEnabled") == true
val pictureInPictureHandler = view.pictureInPictureHandler ?: RNPictureInPictureHandler(context)
view.pictureInPictureHandler = pictureInPictureHandler
Expand All @@ -270,7 +265,7 @@ class RNPlayerViewManager(private val context: ReactApplicationContext) : Simple
val playerView = PlayerView(
currentActivity,
player,
view.config ?: PlayerViewConfig(),
view.config?.playerViewConfig ?: PlayerViewConfig(),
)
playerView.layoutParams = LayoutParams(
LayoutParams.MATCH_PARENT,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import com.bitmovin.player.api.ui.ScalingMode
import com.bitmovin.player.api.ui.StyleConfig
import com.bitmovin.player.api.ui.UiConfig
import com.bitmovin.player.reactnative.BitmovinCastManagerOptions
import com.bitmovin.player.reactnative.RNPlayerView
import com.bitmovin.player.reactnative.extensions.getBooleanOrNull
import com.bitmovin.player.reactnative.extensions.getName
import com.bitmovin.player.reactnative.extensions.getOrDefault
Expand Down Expand Up @@ -1160,6 +1161,11 @@ class JsonConverter {
?: true,
),
)

fun toRNPlayerViewConfig(json: ReadableMap) = RNPlayerView.RNPlayerViewConfig(
playerViewConfig = toPlayerViewConfig(json),
pictureInPictureConfig = toPictureInPictureConfig(json.getMap("pictureInPictureConfig")),
)
}
}

Expand Down
26 changes: 18 additions & 8 deletions example/src/screens/BasicPictureInPicture.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import {
PlayerView,
SourceType,
AudioSession,
PictureInPictureConfig,
PictureInPictureEnterEvent,
PictureInPictureExitEvent,
PlayerViewConfig,
} from 'bitmovin-player-react-native';
import { useTVGestures } from '../hooks';
import { SafeAreaView } from 'react-native-safe-area-context';
Expand All @@ -34,11 +34,13 @@ export default function BasicPictureInPicture({
useState(false);
const [isInPictureInPicture, setIsInPictureInPicture] = useState(false);

const pictureInPictureConfig: PictureInPictureConfig = {
// Enable picture in picture UI option on player controls.
isEnabled: true,
// Enable entering picture in picture mode when transitioning the application to the background
shouldEnterOnBackground: true,
const config: PlayerViewConfig = {
pictureInPictureConfig: {
// Enable picture in picture UI option on player controls.
isEnabled: true,
// Enable entering picture in picture mode when transitioning the application to the background
shouldEnterOnBackground: true,
},
};

const player = usePlayer({
Expand Down Expand Up @@ -115,12 +117,20 @@ export default function BasicPictureInPicture({
);

return (
<SafeAreaView edges={['bottom', 'left', 'right']} style={styles.container}>
<SafeAreaView
edges={['bottom', 'left', 'right']}
style={
// On Android, we need to remove the padding from the container when in PiP mode.
Platform.OS === 'android' && isInPictureInPicture
? [styles.container, { padding: 0 }]
: styles.container
}
>
<PlayerView
player={player}
style={styles.player}
isPictureInPictureRequested={isPictureInPictureRequested}
pictureInPictureConfig={pictureInPictureConfig}
config={config}
onPictureInPictureAvailabilityChanged={onEvent}
onPictureInPictureEnter={onPictureInPictureEnterEvent}
onPictureInPictureEntered={onEvent}
Expand Down
47 changes: 38 additions & 9 deletions ios/RCTConvert+BitmovinPlayer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1122,20 +1122,33 @@ extension RCTConvert {
}

/**
Utility method to instantiate a `UiConfig` from a JS object.
Utility method to instantiate a `RNPlayerViewConfig` from a JS object.
- Parameter json: JS object
- Returns: The produced `UiConfig` object
*/
static func playerViewConfig(_ json: Any?) -> RNPlayerViewConfig? {
guard let json = json as? [String: Any?],
let uiConfigJson = json["uiConfig"] as? [String: Any?] else {
static func rnPlayerViewConfig(_ json: Any?) -> RNPlayerViewConfig? {
guard let json = json as? [String: Any?] else {
return nil
}

return RNPlayerViewConfig(
uiConfig: UiConfig(
playbackSpeedSelectionEnabled: uiConfigJson["playbackSpeedSelectionEnabled"] as? Bool ?? true
)
uiConfig: rnUiConfig(json["uiConfig"]),
pictureInPictureConfig: pictureInPictureConfig(json["pictureInPictureConfig"])
)
}

/**
Utility method to instantiate a `RNUiConfig` from a JS object.
- Parameter json: JS object
- Returns: The produced `RNUiConfig` object
*/
static func rnUiConfig(_ json: Any?) -> RNUiConfig? {
guard let json = json as? [String: Any?] else {
return nil
}

return RNUiConfig(
playbackSpeedSelectionEnabled: json["playbackSpeedSelectionEnabled"] as? Bool ?? true
)
}
}
Expand All @@ -1146,12 +1159,28 @@ internal struct RNPlayerViewConfig {
/**
* The react native specific ui configuration.
*/
let uiConfig: UiConfig
let uiConfig: RNUiConfig?

/**
* Picture in picture config
*/
let pictureInPictureConfig: PictureInPictureConfig?

/**
* PlayerView config considering all properties
*/
var playerViewConfig: PlayerViewConfig {
let config = PlayerViewConfig()
if let pictureInPictureConfig {
config.pictureInPictureConfig = pictureInPictureConfig
}
return config
}
}

/**
* React native specific UiConfig.
*/
internal struct UiConfig {
internal struct RNUiConfig {
let playbackSpeedSelectionEnabled: Bool
}
1 change: 0 additions & 1 deletion ios/RNPlayerView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ public class RNPlayerView: UIView {
@objc var onCastTimeUpdated: RCTBubblingEventBlock?
@objc var onCastWaitingForDevice: RCTBubblingEventBlock?
@objc var onPictureInPictureAvailabilityChanged: RCTBubblingEventBlock?
@objc var pictureInPictureConfig: [String: Any]?
@objc var config: [String: Any]?

/// The `PlayerView` subview.
Expand Down
11 changes: 4 additions & 7 deletions ios/RNPlayerViewManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,17 @@ public class RNPlayerViewManager: RCTViewManager {
else {
return
}
let playerViewConfig = RCTConvert.rnPlayerViewConfig(view.config)
#if os(iOS)
if player.config.styleConfig.userInterfaceType == .bitmovin {
let bitmovinUserInterfaceConfig = player
.config
.styleConfig
.userInterfaceConfig as? BitmovinUserInterfaceConfig ?? BitmovinUserInterfaceConfig()
player.config.styleConfig.userInterfaceConfig = bitmovinUserInterfaceConfig
if let config = RCTConvert.playerViewConfig(view.config) {
if let uiConfig = playerViewConfig?.uiConfig {
bitmovinUserInterfaceConfig
.playbackSpeedSelectionEnabled = config.uiConfig.playbackSpeedSelectionEnabled
.playbackSpeedSelectionEnabled = uiConfig.playbackSpeedSelectionEnabled
}

if let customMessageHandlerBridgeId = self.customMessageHandlerBridgeId,
Expand All @@ -56,14 +57,10 @@ public class RNPlayerViewManager: RCTViewManager {
playerView.player = player
previousPictureInPictureAvailableValue = playerView.isPictureInPictureAvailable
} else {
let playerViewConfig = PlayerViewConfig()
if let pictureInPictureConfig = RCTConvert.pictureInPictureConfig(view.pictureInPictureConfig) {
playerViewConfig.pictureInPictureConfig = pictureInPictureConfig
}
view.playerView = PlayerView(
player: player,
frame: view.bounds,
playerViewConfig: playerViewConfig
playerViewConfig: playerViewConfig?.playerViewConfig ?? PlayerViewConfig()
)
previousPictureInPictureAvailableValue = false
}
Expand Down
8 changes: 0 additions & 8 deletions src/components/PlayerView/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import { FullscreenHandler, CustomMessageHandler } from '../../ui';
import { FullscreenHandlerBridge } from '../../ui/fullscreenhandlerbridge';
import { CustomMessageHandlerBridge } from '../../ui/custommessagehandlerbridge';
import { ScalingMode } from '../../styleConfig';
import { PictureInPictureConfig } from './pictureInPictureConfig';
import { PlayerViewConfig } from './playerViewConfig';

/**
Expand All @@ -38,11 +37,6 @@ export interface BasePlayerViewProps {
*/
style?: ViewStyle;

/**
* Provides options to configure Picture in Picture playback.
*/
pictureInPictureConfig?: PictureInPictureConfig;

/**
* Configures the visual presentation and behaviour of the `PlayerView`.
* The value must not be altered after setting it initially.
Expand Down Expand Up @@ -123,7 +117,6 @@ export function PlayerView({
isFullscreenRequested = false,
scalingMode,
isPictureInPictureRequested = false,
pictureInPictureConfig,
...props
}: PlayerViewProps) {
// Workaround React Native UIManager commands not sent until UI refresh
Expand Down Expand Up @@ -223,7 +216,6 @@ export function PlayerView({
style={nativeViewStyle}
fullscreenBridge={fullscreenBridge.current}
customMessageHandlerBridge={customMessageHandlerBridge.current}
pictureInPictureConfig={pictureInPictureConfig}
config={config}
onAdBreakFinished={proxy(props.onAdBreakFinished)}
onAdBreakStarted={proxy(props.onAdBreakStarted)}
Expand Down
7 changes: 7 additions & 0 deletions src/components/PlayerView/playerViewConfig.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { PictureInPictureConfig } from './pictureInPictureConfig';

/**
* Configures the visual presentation and behaviour of the `PlayerView`.
*/
Expand All @@ -12,6 +14,11 @@ export interface PlayerViewConfig {
* Configuring the `uiConfig` only has an effect if the {@link StyleConfig.userInterfaceType} is set to {@link UserInterfaceType.Bitmovin}.
*/
uiConfig: UiConfig;

/**
* Provides options to configure Picture in Picture playback.
*/
pictureInPictureConfig?: PictureInPictureConfig;
}

/**
Expand Down

0 comments on commit c6dc947

Please sign in to comment.