@stepincto/expo-video 1.0.4 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/android/src/main/java/expo/modules/video/FullscreenPlayerActivity.kt +46 -4
  2. package/android/src/main/java/expo/modules/video/VideoModule.kt +6 -0
  3. package/android/src/main/java/expo/modules/video/VideoView.kt +13 -0
  4. package/android/src/main/java/expo/modules/video/enums/FullscreenOrientation.kt +26 -0
  5. package/android/src/main/java/expo/modules/video/records/FullscreenOptions.kt +12 -0
  6. package/android/src/main/java/expo/modules/video/utils/FullscreenActivityOrientationHelper.kt +120 -0
  7. package/build/VideoModule.d.ts.map +1 -1
  8. package/build/VideoModule.js +24 -1
  9. package/build/VideoModule.js.map +1 -1
  10. package/build/VideoView.d.ts.map +1 -1
  11. package/build/VideoView.js +10 -3
  12. package/build/VideoView.js.map +1 -1
  13. package/build/VideoView.types.d.ts +47 -0
  14. package/build/VideoView.types.d.ts.map +1 -1
  15. package/build/VideoView.types.js.map +1 -1
  16. package/build/VideoView.web.d.ts.map +1 -1
  17. package/build/VideoView.web.js +3 -2
  18. package/build/VideoView.web.js.map +1 -1
  19. package/build/index.d.ts +1 -1
  20. package/build/index.d.ts.map +1 -1
  21. package/build/index.js.map +1 -1
  22. package/expo-module.config.json +7 -1
  23. package/ios/Cache/CachableRequest.swift +2 -41
  24. package/ios/Cache/CachedResource.swift +1 -1
  25. package/ios/Cache/MediaFileHandle.swift +10 -8
  26. package/ios/Cache/MediaInfo.swift +41 -6
  27. package/ios/Cache/VideoCacheManager.swift +53 -6
  28. package/ios/Enums/FullscreenOrientation.swift +34 -0
  29. package/ios/OrientationAVPlayerViewController.swift +231 -0
  30. package/ios/Records/FullscreenOptions.swift +12 -0
  31. package/ios/VideoAsset.swift +4 -1
  32. package/ios/VideoModule.swift +8 -0
  33. package/ios/VideoView.swift +19 -50
  34. package/package.json +3 -4
  35. package/src/VideoModule.ts +28 -1
  36. package/src/VideoView.tsx +28 -3
  37. package/src/VideoView.types.ts +57 -0
  38. package/src/VideoView.web.tsx +4 -2
  39. package/src/index.ts +7 -1
@@ -1,6 +1,7 @@
1
1
  package expo.modules.video
2
2
 
3
3
  import android.app.Activity
4
+ import android.content.pm.ActivityInfo
4
5
  import android.content.res.Configuration
5
6
  import android.os.Build
6
7
  import android.os.Bundle
@@ -12,6 +13,8 @@ import android.widget.ImageButton
12
13
  import androidx.media3.ui.PlayerView
13
14
  import expo.modules.kotlin.exception.CodedException
14
15
  import expo.modules.video.player.VideoPlayer
16
+ import expo.modules.video.records.FullscreenOptions
17
+ import expo.modules.video.utils.FullscreenActivityOrientationHelper
15
18
  import expo.modules.video.utils.applyPiPParams
16
19
  import expo.modules.video.utils.applyRectHint
17
20
  import expo.modules.video.utils.calculatePiPAspectRatio
@@ -26,22 +29,49 @@ class FullscreenPlayerActivity : Activity() {
26
29
  private lateinit var videoView: VideoView
27
30
  private var didFinish = false
28
31
  private var wasAutoPaused = false
32
+ private lateinit var options: FullscreenOptions
33
+ private lateinit var orientationHelper: FullscreenActivityOrientationHelper
29
34
 
30
35
  override fun onCreate(savedInstanceState: Bundle?) {
31
36
  super.onCreate(savedInstanceState)
32
- setContentView(R.layout.fullscreen_player_activity)
33
- mContentView = findViewById(R.id.enclosing_layout)
34
- playerView = findViewById(R.id.player_view)
35
37
 
36
38
  try {
37
39
  videoViewId = intent.getStringExtra(VideoManager.INTENT_PLAYER_KEY)
38
40
  ?: throw FullScreenVideoViewNotFoundException()
41
+
42
+ options = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
43
+ intent.getSerializableExtra(INTENT_FULLSCREEN_OPTIONS_KEY, FullscreenOptions::class.java)
44
+ ?: FullscreenOptions()
45
+ } else {
46
+ @Suppress("DEPRECATION")
47
+ (intent.getSerializableExtra(INTENT_FULLSCREEN_OPTIONS_KEY) as? FullscreenOptions)
48
+ ?: FullscreenOptions()
49
+ }
50
+
39
51
  videoView = VideoManager.getVideoView(videoViewId)
52
+
53
+ orientationHelper = FullscreenActivityOrientationHelper(
54
+ this,
55
+ options,
56
+ onShouldAutoExit = {
57
+ finish()
58
+ },
59
+ onShouldReleaseOrientation = {
60
+ requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
61
+ }
62
+ )
63
+ orientationHelper.startOrientationEventListener()
40
64
  } catch (e: CodedException) {
41
65
  Log.e("ExpoVideo", "${e.message}", e)
42
66
  finish()
43
67
  return
44
68
  }
69
+
70
+ setContentView(R.layout.fullscreen_player_activity)
71
+ mContentView = findViewById(R.id.enclosing_layout)
72
+ playerView = findViewById(R.id.player_view)
73
+ requestedOrientation = options.orientation.toActivityOrientation()
74
+
45
75
  videoPlayer = videoView.videoPlayer
46
76
  videoPlayer?.changePlayerView(playerView)
47
77
  VideoManager.registerFullscreenPlayerActivity(hashCode().toString(), this)
@@ -83,7 +113,8 @@ class FullscreenPlayerActivity : Activity() {
83
113
  }
84
114
 
85
115
  override fun onResume() {
86
- playerView.useController = videoView.useNativeControls
116
+ orientationHelper.startOrientationEventListener()
117
+ playerView.useController = true
87
118
  super.onResume()
88
119
  }
89
120
 
@@ -95,6 +126,7 @@ class FullscreenPlayerActivity : Activity() {
95
126
  videoPlayer?.player?.pause()
96
127
  }
97
128
  }
129
+ orientationHelper.stopOrientationEventListener()
98
130
  super.onPause()
99
131
  }
100
132
 
@@ -102,6 +134,7 @@ class FullscreenPlayerActivity : Activity() {
102
134
  super.onDestroy()
103
135
  videoView.exitFullscreen()
104
136
  VideoManager.unregisterFullscreenPlayerActivity(hashCode().toString())
137
+ orientationHelper.stopOrientationEventListener()
105
138
  }
106
139
 
107
140
  private fun setupFullscreenButton() {
@@ -142,4 +175,13 @@ class FullscreenPlayerActivity : Activity() {
142
175
  )
143
176
  }
144
177
  }
178
+
179
+ override fun onConfigurationChanged(newConfig: Configuration) {
180
+ super.onConfigurationChanged(newConfig)
181
+ orientationHelper.onConfigurationChanged(newConfig)
182
+ }
183
+
184
+ companion object {
185
+ const val INTENT_FULLSCREEN_OPTIONS_KEY = "fullscreen_options"
186
+ }
145
187
  }
@@ -20,6 +20,7 @@ import expo.modules.video.enums.AudioMixingMode
20
20
  import expo.modules.video.enums.ContentFit
21
21
  import expo.modules.video.player.VideoPlayer
22
22
  import expo.modules.video.records.BufferOptions
23
+ import expo.modules.video.records.FullscreenOptions
23
24
  import expo.modules.video.records.SubtitleTrack
24
25
  import expo.modules.video.records.AudioTrack
25
26
  import expo.modules.video.records.VideoSource
@@ -381,6 +382,11 @@ private inline fun <reified T : VideoView> ViewDefinitionBuilder<T>.VideoViewCom
381
382
  Prop("allowsFullscreen") { view: T, allowsFullscreen: Boolean? ->
382
383
  view.allowsFullscreen = allowsFullscreen ?: true
383
384
  }
385
+ Prop("fullscreenOptions") { view: T, fullscreenOptions: FullscreenOptions? ->
386
+ if (fullscreenOptions != null) {
387
+ view.fullscreenOptions = fullscreenOptions
388
+ }
389
+ }
384
390
  Prop("requiresLinearPlayback") { view: T, requiresLinearPlayback: Boolean? ->
385
391
  val linearPlayback = requiresLinearPlayback ?: false
386
392
  view.playerView.applyRequiresLinearPlayback(linearPlayback)
@@ -32,6 +32,7 @@ import expo.modules.video.records.AudioTrack
32
32
  import expo.modules.video.records.SubtitleTrack
33
33
  import expo.modules.video.records.VideoSource
34
34
  import expo.modules.video.records.VideoTrack
35
+ import expo.modules.video.records.FullscreenOptions
35
36
  import expo.modules.video.utils.applyPiPParams
36
37
  import expo.modules.video.utils.applyRectHint
37
38
  import expo.modules.video.utils.calculatePiPAspectRatio
@@ -132,6 +133,17 @@ open class VideoView(context: Context, appContext: AppContext, useTextureView: B
132
133
  field = value
133
134
  }
134
135
 
136
+ var fullscreenOptions: FullscreenOptions = FullscreenOptions()
137
+ set(value) {
138
+ field = value
139
+ if (value.enable) {
140
+ playerView.setFullscreenButtonClickListener { enterFullscreen() }
141
+ } else {
142
+ playerView.setFullscreenButtonClickListener(null)
143
+ playerView.setFullscreenButtonVisibility(false)
144
+ }
145
+ }
146
+
135
147
  private val mLayoutRunnable = Runnable {
136
148
  measure(
137
149
  MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
@@ -172,6 +184,7 @@ open class VideoView(context: Context, appContext: AppContext, useTextureView: B
172
184
  fun enterFullscreen() {
173
185
  val intent = Intent(context, FullscreenPlayerActivity::class.java)
174
186
  intent.putExtra(VideoManager.INTENT_PLAYER_KEY, videoViewId)
187
+ intent.putExtra(FullscreenPlayerActivity.INTENT_FULLSCREEN_OPTIONS_KEY, fullscreenOptions)
175
188
  // Set before starting the activity to avoid entering PiP unintentionally
176
189
  isInFullscreen = true
177
190
  currentActivity.startActivity(intent)
@@ -0,0 +1,26 @@
1
+ package expo.modules.video.enums
2
+
3
+ import android.content.pm.ActivityInfo
4
+ import expo.modules.kotlin.types.Enumerable
5
+
6
+ enum class FullscreenOrientation(val value: String) : Enumerable {
7
+ LANDSCAPE("landscape"),
8
+ PORTRAIT("portrait"),
9
+ LANDSCAPE_LEFT("landscapeLeft"),
10
+ LANDSCAPE_RIGHT("landscapeRight"),
11
+ PORTRAIT_UP("portraitUp"),
12
+ PORTRAIT_DOWN("portraitDown"),
13
+ DEFAULT("default");
14
+
15
+ fun toActivityOrientation(): Int {
16
+ return when (this) {
17
+ LANDSCAPE -> ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE
18
+ PORTRAIT -> ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT
19
+ LANDSCAPE_LEFT -> ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
20
+ LANDSCAPE_RIGHT -> ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE
21
+ PORTRAIT_UP -> ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
22
+ PORTRAIT_DOWN -> ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT
23
+ DEFAULT -> ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
24
+ }
25
+ }
26
+ }
@@ -0,0 +1,12 @@
1
+ package expo.modules.video.records
2
+
3
+ import expo.modules.kotlin.records.Field
4
+ import expo.modules.kotlin.records.Record
5
+ import expo.modules.video.enums.FullscreenOrientation
6
+ import java.io.Serializable
7
+
8
+ data class FullscreenOptions(
9
+ @Field val enable: Boolean = true,
10
+ @Field val orientation: FullscreenOrientation = FullscreenOrientation.DEFAULT,
11
+ @Field val autoExitOnRotate: Boolean = false
12
+ ) : Record, Serializable
@@ -0,0 +1,120 @@
1
+ package expo.modules.video.utils
2
+
3
+ import android.content.Context
4
+ import android.content.res.Configuration
5
+ import android.hardware.SensorManager
6
+ import android.provider.Settings
7
+ import android.view.OrientationEventListener
8
+ import expo.modules.video.enums.FullscreenOrientation
9
+ import expo.modules.video.records.FullscreenOptions
10
+
11
+ /**
12
+ * Helper for the auto-exit fullscreen functionality. Once the user has rotated the phone to the desired orientation, the orientation lock should be released, so that once rotation to a perpendicular orientation is detected, the fullscreen can be exited.
13
+ */
14
+ class FullscreenActivityOrientationHelper(val context: Context, val options: FullscreenOptions, val onShouldAutoExit: (() -> Unit), val onShouldReleaseOrientation: (() -> Unit)) {
15
+ private var userHasRotatedToVideoOrientation = false
16
+ private val isLockedToLandscape = options.orientation == FullscreenOrientation.LANDSCAPE ||
17
+ options.orientation == FullscreenOrientation.LANDSCAPE_LEFT ||
18
+ options.orientation == FullscreenOrientation.LANDSCAPE_RIGHT
19
+
20
+ private val isLockedToPortrait = options.orientation == FullscreenOrientation.PORTRAIT ||
21
+ options.orientation == FullscreenOrientation.PORTRAIT_UP ||
22
+ options.orientation == FullscreenOrientation.PORTRAIT_DOWN
23
+
24
+ /**
25
+ * Checks if the system's auto-rotation setting is currently enabled.
26
+ * Returns true if auto-rotation is unlocked (enabled), false otherwise (locked or error).
27
+ */
28
+ val isAutoRotationEnabled: Boolean
29
+ get() {
30
+ return try {
31
+ val rotationStatus = Settings.System.getInt(
32
+ context.contentResolver,
33
+ Settings.System.ACCELEROMETER_ROTATION,
34
+ 0
35
+ )
36
+ rotationStatus == 1
37
+ } catch (e: Exception) {
38
+ false
39
+ }
40
+ }
41
+
42
+ /* Orientation listener running while the activity orientation is locked. The goal of the listener is to detect if the user has rotated the phone to the desired orientation.
43
+ Once they have done that auto-exit can be activated. That's when we can disable the lock and wait for the device to be rotated to portrait.
44
+ When the screen starts rotating we receive a configuration change and can send a signal to exit fullscreen.
45
+ It's better to unlock and wait for config change instead of trying to detect orientation based on angles, because the angles update faster than the phone rotation.
46
+ */
47
+ private val orientationEventListener by lazy {
48
+ object : OrientationEventListener(context, SensorManager.SENSOR_DELAY_NORMAL) {
49
+ override fun onOrientationChanged(orientation: Int) {
50
+ // Use narrower ranges to determine the orientation. Using a 90 degree range is too sensitive to small tilts.
51
+ val newPhysicalOrientation = when {
52
+ (orientation >= 0 && orientation <= 10) || (orientation >= 350 && orientation < 360) -> {
53
+ Configuration.ORIENTATION_PORTRAIT
54
+ }
55
+
56
+ (orientation >= 80 && orientation <= 100) -> {
57
+ Configuration.ORIENTATION_LANDSCAPE
58
+ }
59
+
60
+ (orientation >= 170 && orientation <= 190) -> {
61
+ Configuration.ORIENTATION_PORTRAIT
62
+ }
63
+
64
+ (orientation >= 260 && orientation <= 280) -> {
65
+ Configuration.ORIENTATION_LANDSCAPE
66
+ }
67
+
68
+ else -> {
69
+ Configuration.ORIENTATION_UNDEFINED
70
+ }
71
+ }
72
+
73
+ if (!options.autoExitOnRotate) {
74
+ return
75
+ }
76
+
77
+ val canReleaseFromLandscape = newPhysicalOrientation == Configuration.ORIENTATION_PORTRAIT && isLockedToLandscape && userHasRotatedToVideoOrientation
78
+ val canReleaseFromPortrait = newPhysicalOrientation == Configuration.ORIENTATION_LANDSCAPE && isLockedToPortrait && userHasRotatedToVideoOrientation
79
+
80
+ if (canReleaseFromPortrait || canReleaseFromLandscape) {
81
+ if (!isAutoRotationEnabled) {
82
+ return
83
+ }
84
+ onShouldReleaseOrientation()
85
+ this@FullscreenActivityOrientationHelper.stopOrientationEventListener()
86
+ }
87
+
88
+ val hasRotatedToVideoOrientationPortrait = newPhysicalOrientation == Configuration.ORIENTATION_PORTRAIT && isLockedToPortrait && !userHasRotatedToVideoOrientation
89
+ val hasRotatedToVideoOrientationLandscape = newPhysicalOrientation == Configuration.ORIENTATION_LANDSCAPE && isLockedToLandscape && !userHasRotatedToVideoOrientation
90
+
91
+ if (hasRotatedToVideoOrientationPortrait || hasRotatedToVideoOrientationLandscape) {
92
+ userHasRotatedToVideoOrientation = true
93
+ }
94
+ }
95
+ }
96
+ }
97
+
98
+ fun onConfigurationChanged(newConfig: Configuration) {
99
+ val orientation = newConfig.orientation
100
+ if (!options.autoExitOnRotate) {
101
+ return
102
+ }
103
+
104
+ if (isLockedToPortrait && orientation == Configuration.ORIENTATION_LANDSCAPE) {
105
+ onShouldAutoExit()
106
+ } else if (isLockedToLandscape && orientation == Configuration.ORIENTATION_PORTRAIT) {
107
+ onShouldAutoExit()
108
+ }
109
+ }
110
+
111
+ fun startOrientationEventListener() {
112
+ if (orientationEventListener.canDetectOrientation()) {
113
+ orientationEventListener.enable()
114
+ }
115
+ }
116
+
117
+ fun stopOrientationEventListener() {
118
+ orientationEventListener.disable()
119
+ }
120
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"VideoModule.d.ts","sourceRoot":"","sources":["../src/VideoModule.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,wBAAgB,2BAA2B,IAAI,OAAO,CAErD;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC,CAEpD;AAED;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEvE;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,IAAI,MAAM,CAEjD;AAED,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAEtE;AAED,wBAAsB,yBAAyB,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAEjG;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAEhE"}
1
+ {"version":3,"file":"VideoModule.d.ts","sourceRoot":"","sources":["../src/VideoModule.ts"],"names":[],"mappings":"AAIA;;;;;;GAMG;AACH,wBAAgB,2BAA2B,IAAI,OAAO,CAErD;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC,CAEpD;AAED;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEvE;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,IAAI,MAAM,CAEjD;AAOD,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAsBtE;AAED,wBAAsB,yBAAyB,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAEjG;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAEhE"}
@@ -1,4 +1,5 @@
1
1
  import NativeVideoModule from './NativeVideoModule';
2
+ const globalCacheOperations = new Map(); // stores the promises that are currently caching files
2
3
  /**
3
4
  * Returns whether the current device supports Picture in Picture (PiP) mode.
4
5
  *
@@ -41,8 +42,30 @@ export function setVideoCacheSizeAsync(sizeBytes) {
41
42
  export function getCurrentVideoCacheSize() {
42
43
  return NativeVideoModule.getCurrentVideoCacheSize();
43
44
  }
45
+ // export async function preCacheVideoAsync(url: string): Promise<boolean> {
46
+ // return NativeVideoModule.preCacheVideoAsync(url);
47
+ // }
48
+ // Modify the existing function
44
49
  export async function preCacheVideoAsync(url) {
45
- return NativeVideoModule.preCacheVideoAsync(url);
50
+ // If already caching, return the existing promise
51
+ if (globalCacheOperations.has(url)) {
52
+ return await globalCacheOperations.get(url);
53
+ }
54
+ // Start new caching operation with proper error handling
55
+ const cachingPromise = NativeVideoModule.preCacheVideoAsync(url).catch((error) => {
56
+ // Ensure cleanup happens even on native errors
57
+ globalCacheOperations.delete(url);
58
+ throw error;
59
+ });
60
+ globalCacheOperations.set(url, cachingPromise);
61
+ try {
62
+ const result = await cachingPromise;
63
+ return result;
64
+ }
65
+ finally {
66
+ // Always cleanup, even if the promise was already cleaned up in catch
67
+ globalCacheOperations.delete(url);
68
+ }
46
69
  }
47
70
  export async function preCacheVideoPartialAsync(url, chunkSize) {
48
71
  return NativeVideoModule.preCacheVideoPartialAsync(url, chunkSize);
@@ -1 +1 @@
1
- {"version":3,"file":"VideoModule.js","sourceRoot":"","sources":["../src/VideoModule.ts"],"names":[],"mappings":"AAAA,OAAO,iBAAiB,MAAM,qBAAqB,CAAC;AAEpD;;;;;;GAMG;AACH,MAAM,UAAU,2BAA2B;IACzC,OAAO,iBAAiB,CAAC,2BAA2B,EAAE,CAAC;AACzD,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,oBAAoB;IAClC,OAAO,iBAAiB,CAAC,oBAAoB,EAAE,CAAC;AAClD,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,sBAAsB,CAAC,SAAiB;IACtD,OAAO,iBAAiB,CAAC,sBAAsB,CAAC,SAAS,CAAC,CAAC;AAC7D,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,wBAAwB;IACtC,OAAO,iBAAiB,CAAC,wBAAwB,EAAE,CAAC;AACtD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,GAAW;IAClD,OAAO,iBAAiB,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC;AACnD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAAC,GAAW,EAAE,SAAkB;IAC7E,OAAO,iBAAiB,CAAC,yBAAyB,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;AACrE,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,GAAW;IAC5C,OAAO,iBAAiB,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC;AACnD,CAAC","sourcesContent":["import NativeVideoModule from './NativeVideoModule';\n\n/**\n * Returns whether the current device supports Picture in Picture (PiP) mode.\n *\n * @returns A `boolean` which is `true` if the device supports PiP mode, and `false` otherwise.\n * @platform android\n * @platform ios\n */\nexport function isPictureInPictureSupported(): boolean {\n return NativeVideoModule.isPictureInPictureSupported();\n}\n\n/**\n * Clears all video cache.\n * > This function can be called only if there are no existing `VideoPlayer` instances.\n *\n * @returns A promise that fulfills after the cache has been cleaned.\n * @platform android\n * @platform ios\n */\nexport function clearVideoCacheAsync(): Promise<void> {\n return NativeVideoModule.clearVideoCacheAsync();\n}\n\n/**\n * Sets desired video cache size in bytes. The default video cache size is 1GB. Value set by this function is persistent.\n * The cache size is not guaranteed to be exact and the actual cache size may be slightly larger. The cache is evicted on a least-recently-used basis.\n * > This function can be called only if there are no existing `VideoPlayer` instances.\n *\n * @returns A promise that fulfills after the cache size has been set.\n * @platform android\n * @platform ios\n */\nexport function setVideoCacheSizeAsync(sizeBytes: number): Promise<void> {\n return NativeVideoModule.setVideoCacheSizeAsync(sizeBytes);\n}\n\n/**\n * Returns the space currently occupied by the video cache in bytes.\n *\n * @platform android\n * @platform ios\n */\nexport function getCurrentVideoCacheSize(): number {\n return NativeVideoModule.getCurrentVideoCacheSize();\n}\n\nexport async function preCacheVideoAsync(url: string): Promise<boolean> {\n return NativeVideoModule.preCacheVideoAsync(url);\n}\n\nexport async function preCacheVideoPartialAsync(url: string, chunkSize?: number): Promise<boolean> {\n return NativeVideoModule.preCacheVideoPartialAsync(url, chunkSize);\n}\n\nexport function isVideoCachedAsync(url: string): Promise<boolean> {\n return NativeVideoModule.isVideoCachedAsync(url);\n}\n"]}
1
+ {"version":3,"file":"VideoModule.js","sourceRoot":"","sources":["../src/VideoModule.ts"],"names":[],"mappings":"AAAA,OAAO,iBAAiB,MAAM,qBAAqB,CAAC;AAEpD,MAAM,qBAAqB,GAAG,IAAI,GAAG,EAA4B,CAAC,CAAC,uDAAuD;AAE1H;;;;;;GAMG;AACH,MAAM,UAAU,2BAA2B;IACzC,OAAO,iBAAiB,CAAC,2BAA2B,EAAE,CAAC;AACzD,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,oBAAoB;IAClC,OAAO,iBAAiB,CAAC,oBAAoB,EAAE,CAAC;AAClD,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,sBAAsB,CAAC,SAAiB;IACtD,OAAO,iBAAiB,CAAC,sBAAsB,CAAC,SAAS,CAAC,CAAC;AAC7D,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,wBAAwB;IACtC,OAAO,iBAAiB,CAAC,wBAAwB,EAAE,CAAC;AACtD,CAAC;AAED,4EAA4E;AAC5E,sDAAsD;AACtD,IAAI;AAEJ,+BAA+B;AAC/B,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,GAAW;IAClD,kDAAkD;IAClD,IAAI,qBAAqB,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;QACnC,OAAO,MAAM,qBAAqB,CAAC,GAAG,CAAC,GAAG,CAAE,CAAC;IAC/C,CAAC;IAED,yDAAyD;IACzD,MAAM,cAAc,GAAG,iBAAiB,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;QAC/E,+CAA+C;QAC/C,qBAAqB,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAClC,MAAM,KAAK,CAAC;IACd,CAAC,CAAC,CAAC;IAEH,qBAAqB,CAAC,GAAG,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;IAE/C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC;QACpC,OAAO,MAAM,CAAC;IAChB,CAAC;YAAS,CAAC;QACT,sEAAsE;QACtE,qBAAqB,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACpC,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAAC,GAAW,EAAE,SAAkB;IAC7E,OAAO,iBAAiB,CAAC,yBAAyB,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;AACrE,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,GAAW;IAC5C,OAAO,iBAAiB,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC;AACnD,CAAC","sourcesContent":["import NativeVideoModule from './NativeVideoModule';\n\nconst globalCacheOperations = new Map<string, Promise<boolean>>(); // stores the promises that are currently caching files\n\n/**\n * Returns whether the current device supports Picture in Picture (PiP) mode.\n *\n * @returns A `boolean` which is `true` if the device supports PiP mode, and `false` otherwise.\n * @platform android\n * @platform ios\n */\nexport function isPictureInPictureSupported(): boolean {\n return NativeVideoModule.isPictureInPictureSupported();\n}\n\n/**\n * Clears all video cache.\n * > This function can be called only if there are no existing `VideoPlayer` instances.\n *\n * @returns A promise that fulfills after the cache has been cleaned.\n * @platform android\n * @platform ios\n */\nexport function clearVideoCacheAsync(): Promise<void> {\n return NativeVideoModule.clearVideoCacheAsync();\n}\n\n/**\n * Sets desired video cache size in bytes. The default video cache size is 1GB. Value set by this function is persistent.\n * The cache size is not guaranteed to be exact and the actual cache size may be slightly larger. The cache is evicted on a least-recently-used basis.\n * > This function can be called only if there are no existing `VideoPlayer` instances.\n *\n * @returns A promise that fulfills after the cache size has been set.\n * @platform android\n * @platform ios\n */\nexport function setVideoCacheSizeAsync(sizeBytes: number): Promise<void> {\n return NativeVideoModule.setVideoCacheSizeAsync(sizeBytes);\n}\n\n/**\n * Returns the space currently occupied by the video cache in bytes.\n *\n * @platform android\n * @platform ios\n */\nexport function getCurrentVideoCacheSize(): number {\n return NativeVideoModule.getCurrentVideoCacheSize();\n}\n\n// export async function preCacheVideoAsync(url: string): Promise<boolean> {\n// return NativeVideoModule.preCacheVideoAsync(url);\n// }\n\n// Modify the existing function\nexport async function preCacheVideoAsync(url: string): Promise<boolean> {\n // If already caching, return the existing promise\n if (globalCacheOperations.has(url)) {\n return await globalCacheOperations.get(url)!;\n }\n\n // Start new caching operation with proper error handling\n const cachingPromise = NativeVideoModule.preCacheVideoAsync(url).catch((error) => {\n // Ensure cleanup happens even on native errors\n globalCacheOperations.delete(url);\n throw error;\n });\n \n globalCacheOperations.set(url, cachingPromise);\n\n try {\n const result = await cachingPromise;\n return result;\n } finally {\n // Always cleanup, even if the promise was already cleaned up in catch\n globalCacheOperations.delete(url);\n }\n}\n\nexport async function preCacheVideoPartialAsync(url: string, chunkSize?: number): Promise<boolean> {\n return NativeVideoModule.preCacheVideoPartialAsync(url, chunkSize);\n}\n\nexport function isVideoCachedAsync(url: string): Promise<boolean> {\n return NativeVideoModule.isVideoCachedAsync(url);\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"VideoView.d.ts","sourceRoot":"","sources":["../src/VideoView.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,aAAa,EAAa,MAAM,OAAO,CAAC;AAK5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAExD;;;;;;;;;GASG;AACH,wBAAgB,2BAA2B,IAAI,OAAO,CAErD;AAED,qBAAa,SAAU,SAAQ,aAAa,CAAC,cAAc,CAAC;IAC1D,SAAS,iCAAoB;IAE7B;;OAEG;IACG,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAItC;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAIrC;;;;;;;;;OASG;IACG,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC;IAI5C;;;;;OAKG;IACG,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC;IAI3C,MAAM,IAAI,SAAS;CASpB"}
1
+ {"version":3,"file":"VideoView.d.ts","sourceRoot":"","sources":["../src/VideoView.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,aAAa,EAAa,MAAM,OAAO,CAAC;AAK5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAExD;;;;;;;;;GASG;AACH,wBAAgB,2BAA2B,IAAI,OAAO,CAErD;AAED,qBAAa,SAAU,SAAQ,aAAa,CAAC,cAAc,CAAC;IAC1D,SAAS,iCAAoB;IAE7B;;OAEG;IACG,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAItC;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAIrC;;;;;;;;;OASG;IACG,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC;IAI5C;;;;;OAKG;IACG,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC;IAI3C,MAAM,IAAI,SAAS;CAkCpB"}
@@ -52,12 +52,19 @@ export class VideoView extends PureComponent {
52
52
  return await this.nativeRef.current?.stopPictureInPicture();
53
53
  }
54
54
  render() {
55
- const { player, ...props } = this.props;
55
+ const { player, allowsFullscreen, ...props } = this.props;
56
56
  const playerId = getPlayerId(player);
57
+ if (allowsFullscreen !== undefined) {
58
+ console.warn('The `allowsFullscreen` prop is deprecated and will be removed in a future release. Use `fullscreenOptions` prop instead.');
59
+ }
60
+ const fullscreenOptions = {
61
+ enable: allowsFullscreen,
62
+ ...props.fullscreenOptions,
63
+ };
57
64
  if (NativeTextureVideoView && this.props.surfaceType === 'textureView') {
58
- return _jsx(NativeTextureVideoView, { ...props, player: playerId, ref: this.nativeRef });
65
+ return (_jsx(NativeTextureVideoView, { ...props, fullscreenOptions: fullscreenOptions, player: playerId, ref: this.nativeRef }));
59
66
  }
60
- return _jsx(NativeVideoView, { ...props, player: playerId, ref: this.nativeRef });
67
+ return (_jsx(NativeVideoView, { ...props, fullscreenOptions: fullscreenOptions, player: playerId, ref: this.nativeRef }));
61
68
  }
62
69
  }
63
70
  // Temporary solution to pass the shared object ID instead of the player object.
@@ -1 +1 @@
1
- {"version":3,"file":"VideoView.js","sourceRoot":"","sources":["../src/VideoView.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAa,aAAa,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAE5D,OAAO,iBAAiB,MAAM,qBAAqB,CAAC;AACpD,OAAO,eAAe,EAAE,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAI5E;;;;;;;;;GASG;AACH,MAAM,UAAU,2BAA2B;IACzC,OAAO,iBAAiB,CAAC,2BAA2B,EAAE,CAAC;AACzD,CAAC;AAED,MAAM,OAAO,SAAU,SAAQ,aAA6B;IAC1D,SAAS,GAAG,SAAS,EAAO,CAAC;IAE7B;;OAEG;IACH,KAAK,CAAC,eAAe;QACnB,OAAO,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,eAAe,EAAE,CAAC;IACzD,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,cAAc;QAClB,OAAO,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,cAAc,EAAE,CAAC;IACxD,CAAC;IAED;;;;;;;;;OASG;IACH,KAAK,CAAC,qBAAqB;QACzB,OAAO,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,qBAAqB,EAAE,CAAC;IAC/D,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,oBAAoB;QACxB,OAAO,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,oBAAoB,EAAE,CAAC;IAC9D,CAAC;IAED,MAAM;QACJ,MAAM,EAAE,MAAM,EAAE,GAAG,KAAK,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC;QACxC,MAAM,QAAQ,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;QAErC,IAAI,sBAAsB,IAAI,IAAI,CAAC,KAAK,CAAC,WAAW,KAAK,aAAa,EAAE,CAAC;YACvE,OAAO,KAAC,sBAAsB,OAAK,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,IAAI,CAAC,SAAS,GAAI,CAAC;QACtF,CAAC;QACD,OAAO,KAAC,eAAe,OAAK,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,IAAI,CAAC,SAAS,GAAI,CAAC;IAC/E,CAAC;CACF;AAED,gFAAgF;AAChF,gEAAgE;AAChE,yEAAyE;AACzE,SAAS,WAAW,CAAC,MAA4B;IAC/C,IAAI,MAAM,YAAY,iBAAiB,CAAC,WAAW,EAAE,CAAC;QACpD,mBAAmB;QACnB,OAAO,MAAM,CAAC,yBAAyB,CAAC;IAC1C,CAAC;IACD,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC/B,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC","sourcesContent":["import { ReactNode, PureComponent, createRef } from 'react';\n\nimport NativeVideoModule from './NativeVideoModule';\nimport NativeVideoView, { NativeTextureVideoView } from './NativeVideoView';\nimport type { VideoPlayer } from './VideoPlayer.types';\nimport type { VideoViewProps } from './VideoView.types';\n\n/**\n * Returns whether the current device supports Picture in Picture (PiP) mode.\n *\n * > **Note:** All major web browsers support Picture in Picture (PiP) mode except Firefox.\n * > For more information, see [MDN web docs](https://developer.mozilla.org/en-US/docs/Web/API/Picture-in-Picture_API#browser_compatibility).\n * @returns A `boolean` which is `true` if the device supports PiP mode, and `false` otherwise.\n * @platform android\n * @platform ios\n * @platform web\n */\nexport function isPictureInPictureSupported(): boolean {\n return NativeVideoModule.isPictureInPictureSupported();\n}\n\nexport class VideoView extends PureComponent<VideoViewProps> {\n nativeRef = createRef<any>();\n\n /**\n * Enters fullscreen mode.\n */\n async enterFullscreen(): Promise<void> {\n return await this.nativeRef.current?.enterFullscreen();\n }\n\n /**\n * Exits fullscreen mode.\n */\n async exitFullscreen(): Promise<void> {\n return await this.nativeRef.current?.exitFullscreen();\n }\n\n /**\n * Enters Picture in Picture (PiP) mode. Throws an exception if the device does not support PiP.\n * > **Note:** Only one player can be in Picture in Picture (PiP) mode at a time.\n *\n * > **Note:** The `supportsPictureInPicture` property of the [config plugin](#configuration-in-app-config)\n * > has to be configured for the PiP to work.\n * @platform android\n * @platform ios\n * @platform web\n */\n async startPictureInPicture(): Promise<void> {\n return await this.nativeRef.current?.startPictureInPicture();\n }\n\n /**\n * Exits Picture in Picture (PiP) mode.\n * @platform android\n * @platform ios\n * @platform web\n */\n async stopPictureInPicture(): Promise<void> {\n return await this.nativeRef.current?.stopPictureInPicture();\n }\n\n render(): ReactNode {\n const { player, ...props } = this.props;\n const playerId = getPlayerId(player);\n\n if (NativeTextureVideoView && this.props.surfaceType === 'textureView') {\n return <NativeTextureVideoView {...props} player={playerId} ref={this.nativeRef} />;\n }\n return <NativeVideoView {...props} player={playerId} ref={this.nativeRef} />;\n }\n}\n\n// Temporary solution to pass the shared object ID instead of the player object.\n// We can't really pass it as an object in the old architecture.\n// Technically we can in the new architecture, but it's not possible yet.\nfunction getPlayerId(player: number | VideoPlayer): number | null {\n if (player instanceof NativeVideoModule.VideoPlayer) {\n // @ts-expect-error\n return player.__expo_shared_object_id__;\n }\n if (typeof player === 'number') {\n return player;\n }\n return null;\n}\n"]}
1
+ {"version":3,"file":"VideoView.js","sourceRoot":"","sources":["../src/VideoView.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAa,aAAa,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAE5D,OAAO,iBAAiB,MAAM,qBAAqB,CAAC;AACpD,OAAO,eAAe,EAAE,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAI5E;;;;;;;;;GASG;AACH,MAAM,UAAU,2BAA2B;IACzC,OAAO,iBAAiB,CAAC,2BAA2B,EAAE,CAAC;AACzD,CAAC;AAED,MAAM,OAAO,SAAU,SAAQ,aAA6B;IAC1D,SAAS,GAAG,SAAS,EAAO,CAAC;IAE7B;;OAEG;IACH,KAAK,CAAC,eAAe;QACnB,OAAO,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,eAAe,EAAE,CAAC;IACzD,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,cAAc;QAClB,OAAO,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,cAAc,EAAE,CAAC;IACxD,CAAC;IAED;;;;;;;;;OASG;IACH,KAAK,CAAC,qBAAqB;QACzB,OAAO,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,qBAAqB,EAAE,CAAC;IAC/D,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,oBAAoB;QACxB,OAAO,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,oBAAoB,EAAE,CAAC;IAC9D,CAAC;IAED,MAAM;QACJ,MAAM,EAAE,MAAM,EAAE,gBAAgB,EAAE,GAAG,KAAK,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC;QAC1D,MAAM,QAAQ,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;QAErC,IAAI,gBAAgB,KAAK,SAAS,EAAE,CAAC;YACnC,OAAO,CAAC,IAAI,CACV,0HAA0H,CAC3H,CAAC;QACJ,CAAC;QAED,MAAM,iBAAiB,GAAG;YACxB,MAAM,EAAE,gBAAgB;YACxB,GAAG,KAAK,CAAC,iBAAiB;SAC3B,CAAC;QAEF,IAAI,sBAAsB,IAAI,IAAI,CAAC,KAAK,CAAC,WAAW,KAAK,aAAa,EAAE,CAAC;YACvE,OAAO,CACL,KAAC,sBAAsB,OACjB,KAAK,EACT,iBAAiB,EAAE,iBAAiB,EACpC,MAAM,EAAE,QAAQ,EAChB,GAAG,EAAE,IAAI,CAAC,SAAS,GACnB,CACH,CAAC;QACJ,CAAC;QACD,OAAO,CACL,KAAC,eAAe,OACV,KAAK,EACT,iBAAiB,EAAE,iBAAiB,EACpC,MAAM,EAAE,QAAQ,EAChB,GAAG,EAAE,IAAI,CAAC,SAAS,GACnB,CACH,CAAC;IACJ,CAAC;CACF;AAED,gFAAgF;AAChF,gEAAgE;AAChE,yEAAyE;AACzE,SAAS,WAAW,CAAC,MAA4B;IAC/C,IAAI,MAAM,YAAY,iBAAiB,CAAC,WAAW,EAAE,CAAC;QACpD,mBAAmB;QACnB,OAAO,MAAM,CAAC,yBAAyB,CAAC;IAC1C,CAAC;IACD,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC/B,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC","sourcesContent":["import { ReactNode, PureComponent, createRef } from 'react';\n\nimport NativeVideoModule from './NativeVideoModule';\nimport NativeVideoView, { NativeTextureVideoView } from './NativeVideoView';\nimport type { VideoPlayer } from './VideoPlayer.types';\nimport type { VideoViewProps } from './VideoView.types';\n\n/**\n * Returns whether the current device supports Picture in Picture (PiP) mode.\n *\n * > **Note:** All major web browsers support Picture in Picture (PiP) mode except Firefox.\n * > For more information, see [MDN web docs](https://developer.mozilla.org/en-US/docs/Web/API/Picture-in-Picture_API#browser_compatibility).\n * @returns A `boolean` which is `true` if the device supports PiP mode, and `false` otherwise.\n * @platform android\n * @platform ios\n * @platform web\n */\nexport function isPictureInPictureSupported(): boolean {\n return NativeVideoModule.isPictureInPictureSupported();\n}\n\nexport class VideoView extends PureComponent<VideoViewProps> {\n nativeRef = createRef<any>();\n\n /**\n * Enters fullscreen mode.\n */\n async enterFullscreen(): Promise<void> {\n return await this.nativeRef.current?.enterFullscreen();\n }\n\n /**\n * Exits fullscreen mode.\n */\n async exitFullscreen(): Promise<void> {\n return await this.nativeRef.current?.exitFullscreen();\n }\n\n /**\n * Enters Picture in Picture (PiP) mode. Throws an exception if the device does not support PiP.\n * > **Note:** Only one player can be in Picture in Picture (PiP) mode at a time.\n *\n * > **Note:** The `supportsPictureInPicture` property of the [config plugin](#configuration-in-app-config)\n * > has to be configured for the PiP to work.\n * @platform android\n * @platform ios\n * @platform web\n */\n async startPictureInPicture(): Promise<void> {\n return await this.nativeRef.current?.startPictureInPicture();\n }\n\n /**\n * Exits Picture in Picture (PiP) mode.\n * @platform android\n * @platform ios\n * @platform web\n */\n async stopPictureInPicture(): Promise<void> {\n return await this.nativeRef.current?.stopPictureInPicture();\n }\n\n render(): ReactNode {\n const { player, allowsFullscreen, ...props } = this.props;\n const playerId = getPlayerId(player);\n\n if (allowsFullscreen !== undefined) {\n console.warn(\n 'The `allowsFullscreen` prop is deprecated and will be removed in a future release. Use `fullscreenOptions` prop instead.'\n );\n }\n\n const fullscreenOptions = {\n enable: allowsFullscreen,\n ...props.fullscreenOptions,\n };\n\n if (NativeTextureVideoView && this.props.surfaceType === 'textureView') {\n return (\n <NativeTextureVideoView\n {...props}\n fullscreenOptions={fullscreenOptions}\n player={playerId}\n ref={this.nativeRef}\n />\n );\n }\n return (\n <NativeVideoView\n {...props}\n fullscreenOptions={fullscreenOptions}\n player={playerId}\n ref={this.nativeRef}\n />\n );\n }\n}\n\n// Temporary solution to pass the shared object ID instead of the player object.\n// We can't really pass it as an object in the old architecture.\n// Technically we can in the new architecture, but it's not possible yet.\nfunction getPlayerId(player: number | VideoPlayer): number | null {\n if (player instanceof NativeVideoModule.VideoPlayer) {\n // @ts-expect-error\n return player.__expo_shared_object_id__;\n }\n if (typeof player === 'number') {\n return player;\n }\n return null;\n}\n"]}
@@ -16,6 +16,47 @@ export type VideoContentFit = 'contain' | 'cover' | 'fill';
16
16
  * @platform android
17
17
  */
18
18
  export type SurfaceType = 'textureView' | 'surfaceView';
19
+ /**
20
+ * Describes the orientation of the video in fullscreen mode. Available values are:
21
+ * - `default`: The video is displayed in any of the available device rotations.
22
+ * - `portrait`: The video is displayed in one of two available portrait orientations and rotates between them.
23
+ * - `portraitUp`: The video is displayed in the portrait orientation - the notch of the phone points upwards.
24
+ * - `portraitDown`: The video is displayed in the portrait orientation - the notch of the phone points downwards.
25
+ * - `landscape`: The video is displayed in one of two available landscape orientations and rotates between them.
26
+ * - `landscapeLeft`: The video is displayed in the left landscape orientation - the notch of the phone is in the left palm of the user.
27
+ * - `landscapeRight`: The video is displayed in the right landscape orientation - the notch of the phone is in the right palm of the user.
28
+ */
29
+ export type FullscreenOrientation = 'default' | 'portrait' | 'portraitUp' | 'portraitDown' | 'landscape' | 'landscapeLeft' | 'landscapeRight';
30
+ /**
31
+ * Describes the options for fullscreen video mode.
32
+ */
33
+ export type FullscreenOptions = {
34
+ /**
35
+ * Specifies whether the fullscreen mode should be available to the user. When `false`, the fullscreen button will be hidden in the player.
36
+ * Equivalent to the `allowsFullscreen` prop.
37
+ * @default true
38
+ */
39
+ enable?: boolean;
40
+ /**
41
+ * Specifies the orientation of the video in fullscreen mode.
42
+ * @default 'default'
43
+ * @platform android
44
+ * @platform ios
45
+ */
46
+ orientation?: FullscreenOrientation;
47
+ /**
48
+ * Specifies whether the app should exit fullscreen mode when the device is rotated to a different orientation than the one specified in the `orientation` prop.
49
+ * For example, if the `orientation` prop is set to `landscape` and the device is rotated to `portrait`, the app will exit fullscreen mode.
50
+ *
51
+ * > This prop will have no effect if the `orientation` prop is set to `default`.
52
+ * > The `VideoView` will never auto-exit fullscreen when the device auto-rotate feature has been disabled in settings.
53
+ *
54
+ * @default false
55
+ * @platform android
56
+ * @platform ios
57
+ */
58
+ autoExitOnRotate?: boolean;
59
+ };
19
60
  export interface VideoViewProps extends ViewProps {
20
61
  /**
21
62
  * A video player instance. Use [`useVideoPlayer()`](#usevideoplayersource-setup) hook to create one.
@@ -34,9 +75,15 @@ export interface VideoViewProps extends ViewProps {
34
75
  contentFit?: VideoContentFit;
35
76
  /**
36
77
  * Determines whether fullscreen mode is allowed or not.
78
+ *
79
+ * > Note: This option has been deprecated in favor of the `fullscreenOptions` prop and will be disabled in the future.
37
80
  * @default true
38
81
  */
39
82
  allowsFullscreen?: boolean;
83
+ /**
84
+ * Determines the fullscreen mode options.
85
+ */
86
+ fullscreenOptions?: FullscreenOptions;
40
87
  /**
41
88
  * Determines whether the timecodes should be displayed or not.
42
89
  * @default true
@@ -1 +1 @@
1
- {"version":3,"file":"VideoView.types.d.ts","sourceRoot":"","sources":["../src/VideoView.types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD;;;;;GAKG;AACH,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,OAAO,GAAG,MAAM,CAAC;AAE3D;;;;;;;GAOG;AACH,MAAM,MAAM,WAAW,GAAG,aAAa,GAAG,aAAa,CAAC;AAExD,MAAM,WAAW,cAAe,SAAQ,SAAS;IAC/C;;OAEG;IACH,MAAM,EAAE,WAAW,CAAC;IAEpB;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IAEzB;;;;OAIG;IACH,UAAU,CAAC,EAAE,eAAe,CAAC;IAE7B;;;OAGG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAE3B;;;;OAIG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IAEzB;;;;;OAKG;IACH,sBAAsB,CAAC,EAAE,OAAO,CAAC;IAEjC;;;;;OAKG;IACH,WAAW,CAAC,EAAE,WAAW,CAAC;IAE1B;;;;OAIG;IACH,eAAe,CAAC,EAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,EAAE,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAE/C;;;;;OAKG;IACH,uBAAuB,CAAC,EAAE,MAAM,IAAI,CAAC;IAErC;;;;;OAKG;IACH,sBAAsB,CAAC,EAAE,MAAM,IAAI,CAAC;IAEpC;;;;;;;OAOG;IACH,sBAAsB,CAAC,EAAE,OAAO,CAAC;IAEjC;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB;;;;;;;;;;OAUG;IACH,mCAAmC,CAAC,EAAE,OAAO,CAAC;IAE9C;;;;;OAKG;IACH,wBAAwB,CAAC,EAAE,OAAO,CAAC;IAEnC;;OAEG;IACH,iBAAiB,CAAC,EAAE,MAAM,IAAI,CAAC;IAE/B;;OAEG;IACH,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;IAE9B;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,MAAM,IAAI,CAAC;IAEhC;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,WAAW,GAAG,iBAAiB,CAAC;CAC/C"}
1
+ {"version":3,"file":"VideoView.types.d.ts","sourceRoot":"","sources":["../src/VideoView.types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD;;;;;GAKG;AACH,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,OAAO,GAAG,MAAM,CAAC;AAE3D;;;;;;;GAOG;AACH,MAAM,MAAM,WAAW,GAAG,aAAa,GAAG,aAAa,CAAC;AAExD;;;;;;;;;GASG;AACH,MAAM,MAAM,qBAAqB,GAC7B,SAAS,GACT,UAAU,GACV,YAAY,GACZ,cAAc,GACd,WAAW,GACX,eAAe,GACf,gBAAgB,CAAC;AAErB;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B;;;;OAIG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,qBAAqB,CAAC;IACpC;;;;;;;;;;OAUG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B,CAAC;AAEF,MAAM,WAAW,cAAe,SAAQ,SAAS;IAC/C;;OAEG;IACH,MAAM,EAAE,WAAW,CAAC;IAEpB;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IAEzB;;;;OAIG;IACH,UAAU,CAAC,EAAE,eAAe,CAAC;IAE7B;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAE3B;;OAEG;IACH,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IAEtC;;;;OAIG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IAEzB;;;;;OAKG;IACH,sBAAsB,CAAC,EAAE,OAAO,CAAC;IAEjC;;;;;OAKG;IACH,WAAW,CAAC,EAAE,WAAW,CAAC;IAE1B;;;;OAIG;IACH,eAAe,CAAC,EAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,EAAE,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAE/C;;;;;OAKG;IACH,uBAAuB,CAAC,EAAE,MAAM,IAAI,CAAC;IAErC;;;;;OAKG;IACH,sBAAsB,CAAC,EAAE,MAAM,IAAI,CAAC;IAEpC;;;;;;;OAOG;IACH,sBAAsB,CAAC,EAAE,OAAO,CAAC;IAEjC;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB;;;;;;;;;;OAUG;IACH,mCAAmC,CAAC,EAAE,OAAO,CAAC;IAE9C;;;;;OAKG;IACH,wBAAwB,CAAC,EAAE,OAAO,CAAC;IAEnC;;OAEG;IACH,iBAAiB,CAAC,EAAE,MAAM,IAAI,CAAC;IAE/B;;OAEG;IACH,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;IAE9B;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,MAAM,IAAI,CAAC;IAEhC;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,WAAW,GAAG,iBAAiB,CAAC;CAC/C"}
@@ -1 +1 @@
1
- {"version":3,"file":"VideoView.types.js","sourceRoot":"","sources":["../src/VideoView.types.ts"],"names":[],"mappings":"","sourcesContent":["import { ViewProps } from 'react-native';\n\nimport type { VideoPlayer } from './VideoPlayer.types';\n\n/**\n * Describes how a video should be scaled to fit in a container.\n * - `contain`: The video maintains its aspect ratio and fits inside the container, with possible letterboxing/pillarboxing.\n * - `cover`: The video maintains its aspect ratio and covers the entire container, potentially cropping some portions.\n * - `fill`: The video stretches/squeezes to completely fill the container, potentially causing distortion.\n */\nexport type VideoContentFit = 'contain' | 'cover' | 'fill';\n\n/**\n * Describes the type of the surface used to render the video.\n * - `surfaceView`: Uses the `SurfaceView` to render the video. This value should be used in the majority of cases. Provides significantly lower power consumption, better performance, and more features.\n * - `textureView`: Uses the `TextureView` to render the video. Should be used in cases where the SurfaceView is not supported or causes issues (for example, overlapping video views).\n *\n * You can learn more about surface types in the official [ExoPlayer documentation](https://developer.android.com/media/media3/ui/playerview#surfacetype).\n * @platform android\n */\nexport type SurfaceType = 'textureView' | 'surfaceView';\n\nexport interface VideoViewProps extends ViewProps {\n /**\n * A video player instance. Use [`useVideoPlayer()`](#usevideoplayersource-setup) hook to create one.\n */\n player: VideoPlayer;\n\n /**\n * Determines whether native controls should be displayed or not.\n * @default true\n */\n nativeControls?: boolean;\n\n /**\n * Describes how the video should be scaled to fit in the container.\n * Options are `'contain'`, `'cover'`, and `'fill'`.\n * @default 'contain'\n */\n contentFit?: VideoContentFit;\n\n /**\n * Determines whether fullscreen mode is allowed or not.\n * @default true\n */\n allowsFullscreen?: boolean;\n\n /**\n * Determines whether the timecodes should be displayed or not.\n * @default true\n * @platform ios\n */\n showsTimecodes?: boolean;\n\n /**\n * Determines whether the player allows the user to skip media content.\n * @default false\n * @platform android\n * @platform ios\n */\n requiresLinearPlayback?: boolean;\n\n /**\n * Determines the type of the surface used to render the video.\n * > This prop should not be changed at runtime.\n * @default 'surfaceView'\n * @platform android\n */\n surfaceType?: SurfaceType;\n\n /**\n * Determines the position offset of the video inside the container.\n * @default { dx: 0, dy: 0 }\n * @platform ios\n */\n contentPosition?: { dx?: number; dy?: number };\n\n /**\n * A callback to call after the video player enters Picture in Picture (PiP) mode.\n * @platform android\n * @platform ios\n * @platform web\n */\n onPictureInPictureStart?: () => void;\n\n /**\n * A callback to call after the video player exits Picture in Picture (PiP) mode.\n * @platform android\n * @platform ios\n * @platform web\n */\n onPictureInPictureStop?: () => void;\n\n /**\n * Determines whether the player allows Picture in Picture (PiP) mode.\n * > **Note:** The `supportsPictureInPicture` property of the [config plugin](#configuration-in-app-config)\n * > has to be configured for the PiP to work.\n * @platform android\n * @platform ios\n * @platform web\n */\n allowsPictureInPicture?: boolean;\n\n /**\n * Determines whether a video should be played \"inline\", that is, within the element's playback area.\n * @platform web\n */\n playsInline?: boolean;\n\n /**\n * Determines whether the player should start Picture in Picture (PiP) automatically when the app is in the background.\n * > **Note:** Only one player can be in Picture in Picture (PiP) mode at a time.\n *\n * > **Note:** The `supportsPictureInPicture` property of the [config plugin](#configuration-in-app-config)\n * > has to be configured for the PiP to work.\n *\n * @default false\n * @platform android 12+\n * @platform ios\n */\n startsPictureInPictureAutomatically?: boolean;\n\n /**\n * Specifies whether to perform video frame analysis (Live Text in videos).\n * Check official [Apple documentation](https://developer.apple.com/documentation/avkit/avplayerviewcontroller/allowsvideoframeanalysis) for more details.\n * @default true\n * @platform ios 16.0+\n */\n allowsVideoFrameAnalysis?: boolean;\n\n /**\n * A callback to call after the video player enters fullscreen mode.\n */\n onFullscreenEnter?: () => void;\n\n /**\n * A callback to call after the video player exits fullscreen mode.\n */\n onFullscreenExit?: () => void;\n\n /**\n * A callback to call after the mounted `VideoPlayer` has rendered the first frame into the `VideoView`.\n * This event can be used to hide any cover images that conceal the initial loading of the player.\n * > **Note:** This event may also be called during playback when the current video track changes (for example when the player switches video quality).\n */\n onFirstFrameRender?: () => void;\n\n /**\n * Determines whether the player should use the default ExoPlayer shutter that covers the `VideoView` before the first video frame is rendered.\n * Setting this property to `false` makes the Android behavior the same as iOS.\n *\n * @platform android\n * @default false\n */\n useExoShutter?: boolean;\n\n /**\n * Determines the [cross origin policy](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/crossorigin) used by the underlying native view on web.\n * If undefined, does not use CORS at all.\n *\n * @platform web\n * @default undefined\n */\n crossOrigin?: 'anonymous' | 'use-credentials';\n}\n"]}
1
+ {"version":3,"file":"VideoView.types.js","sourceRoot":"","sources":["../src/VideoView.types.ts"],"names":[],"mappings":"","sourcesContent":["import { ViewProps } from 'react-native';\n\nimport type { VideoPlayer } from './VideoPlayer.types';\n\n/**\n * Describes how a video should be scaled to fit in a container.\n * - `contain`: The video maintains its aspect ratio and fits inside the container, with possible letterboxing/pillarboxing.\n * - `cover`: The video maintains its aspect ratio and covers the entire container, potentially cropping some portions.\n * - `fill`: The video stretches/squeezes to completely fill the container, potentially causing distortion.\n */\nexport type VideoContentFit = 'contain' | 'cover' | 'fill';\n\n/**\n * Describes the type of the surface used to render the video.\n * - `surfaceView`: Uses the `SurfaceView` to render the video. This value should be used in the majority of cases. Provides significantly lower power consumption, better performance, and more features.\n * - `textureView`: Uses the `TextureView` to render the video. Should be used in cases where the SurfaceView is not supported or causes issues (for example, overlapping video views).\n *\n * You can learn more about surface types in the official [ExoPlayer documentation](https://developer.android.com/media/media3/ui/playerview#surfacetype).\n * @platform android\n */\nexport type SurfaceType = 'textureView' | 'surfaceView';\n\n/**\n * Describes the orientation of the video in fullscreen mode. Available values are:\n * - `default`: The video is displayed in any of the available device rotations.\n * - `portrait`: The video is displayed in one of two available portrait orientations and rotates between them.\n * - `portraitUp`: The video is displayed in the portrait orientation - the notch of the phone points upwards.\n * - `portraitDown`: The video is displayed in the portrait orientation - the notch of the phone points downwards.\n * - `landscape`: The video is displayed in one of two available landscape orientations and rotates between them.\n * - `landscapeLeft`: The video is displayed in the left landscape orientation - the notch of the phone is in the left palm of the user.\n * - `landscapeRight`: The video is displayed in the right landscape orientation - the notch of the phone is in the right palm of the user.\n */\nexport type FullscreenOrientation =\n | 'default'\n | 'portrait'\n | 'portraitUp'\n | 'portraitDown'\n | 'landscape'\n | 'landscapeLeft'\n | 'landscapeRight';\n\n/**\n * Describes the options for fullscreen video mode.\n */\nexport type FullscreenOptions = {\n /**\n * Specifies whether the fullscreen mode should be available to the user. When `false`, the fullscreen button will be hidden in the player.\n * Equivalent to the `allowsFullscreen` prop.\n * @default true\n */\n enable?: boolean;\n /**\n * Specifies the orientation of the video in fullscreen mode.\n * @default 'default'\n * @platform android\n * @platform ios\n */\n orientation?: FullscreenOrientation;\n /**\n * Specifies whether the app should exit fullscreen mode when the device is rotated to a different orientation than the one specified in the `orientation` prop.\n * For example, if the `orientation` prop is set to `landscape` and the device is rotated to `portrait`, the app will exit fullscreen mode.\n *\n * > This prop will have no effect if the `orientation` prop is set to `default`.\n * > The `VideoView` will never auto-exit fullscreen when the device auto-rotate feature has been disabled in settings.\n *\n * @default false\n * @platform android\n * @platform ios\n */\n autoExitOnRotate?: boolean;\n};\n\nexport interface VideoViewProps extends ViewProps {\n /**\n * A video player instance. Use [`useVideoPlayer()`](#usevideoplayersource-setup) hook to create one.\n */\n player: VideoPlayer;\n\n /**\n * Determines whether native controls should be displayed or not.\n * @default true\n */\n nativeControls?: boolean;\n\n /**\n * Describes how the video should be scaled to fit in the container.\n * Options are `'contain'`, `'cover'`, and `'fill'`.\n * @default 'contain'\n */\n contentFit?: VideoContentFit;\n\n /**\n * Determines whether fullscreen mode is allowed or not.\n *\n * > Note: This option has been deprecated in favor of the `fullscreenOptions` prop and will be disabled in the future.\n * @default true\n */\n allowsFullscreen?: boolean;\n\n /**\n * Determines the fullscreen mode options.\n */\n fullscreenOptions?: FullscreenOptions;\n\n /**\n * Determines whether the timecodes should be displayed or not.\n * @default true\n * @platform ios\n */\n showsTimecodes?: boolean;\n\n /**\n * Determines whether the player allows the user to skip media content.\n * @default false\n * @platform android\n * @platform ios\n */\n requiresLinearPlayback?: boolean;\n\n /**\n * Determines the type of the surface used to render the video.\n * > This prop should not be changed at runtime.\n * @default 'surfaceView'\n * @platform android\n */\n surfaceType?: SurfaceType;\n\n /**\n * Determines the position offset of the video inside the container.\n * @default { dx: 0, dy: 0 }\n * @platform ios\n */\n contentPosition?: { dx?: number; dy?: number };\n\n /**\n * A callback to call after the video player enters Picture in Picture (PiP) mode.\n * @platform android\n * @platform ios\n * @platform web\n */\n onPictureInPictureStart?: () => void;\n\n /**\n * A callback to call after the video player exits Picture in Picture (PiP) mode.\n * @platform android\n * @platform ios\n * @platform web\n */\n onPictureInPictureStop?: () => void;\n\n /**\n * Determines whether the player allows Picture in Picture (PiP) mode.\n * > **Note:** The `supportsPictureInPicture` property of the [config plugin](#configuration-in-app-config)\n * > has to be configured for the PiP to work.\n * @platform android\n * @platform ios\n * @platform web\n */\n allowsPictureInPicture?: boolean;\n\n /**\n * Determines whether a video should be played \"inline\", that is, within the element's playback area.\n * @platform web\n */\n playsInline?: boolean;\n\n /**\n * Determines whether the player should start Picture in Picture (PiP) automatically when the app is in the background.\n * > **Note:** Only one player can be in Picture in Picture (PiP) mode at a time.\n *\n * > **Note:** The `supportsPictureInPicture` property of the [config plugin](#configuration-in-app-config)\n * > has to be configured for the PiP to work.\n *\n * @default false\n * @platform android 12+\n * @platform ios\n */\n startsPictureInPictureAutomatically?: boolean;\n\n /**\n * Specifies whether to perform video frame analysis (Live Text in videos).\n * Check official [Apple documentation](https://developer.apple.com/documentation/avkit/avplayerviewcontroller/allowsvideoframeanalysis) for more details.\n * @default true\n * @platform ios 16.0+\n */\n allowsVideoFrameAnalysis?: boolean;\n\n /**\n * A callback to call after the video player enters fullscreen mode.\n */\n onFullscreenEnter?: () => void;\n\n /**\n * A callback to call after the video player exits fullscreen mode.\n */\n onFullscreenExit?: () => void;\n\n /**\n * A callback to call after the mounted `VideoPlayer` has rendered the first frame into the `VideoView`.\n * This event can be used to hide any cover images that conceal the initial loading of the player.\n * > **Note:** This event may also be called during playback when the current video track changes (for example when the player switches video quality).\n */\n onFirstFrameRender?: () => void;\n\n /**\n * Determines whether the player should use the default ExoPlayer shutter that covers the `VideoView` before the first video frame is rendered.\n * Setting this property to `false` makes the Android behavior the same as iOS.\n *\n * @platform android\n * @default false\n */\n useExoShutter?: boolean;\n\n /**\n * Determines the [cross origin policy](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/crossorigin) used by the underlying native view on web.\n * If undefined, does not use CORS at all.\n *\n * @platform web\n * @default undefined\n */\n crossOrigin?: 'anonymous' | 'use-credentials';\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"VideoView.web.d.ts","sourceRoot":"","sources":["../src/VideoView.web.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA6D,MAAM,OAAO,CAAC;AAGlF,OAAO,WAA6B,MAAM,mBAAmB,CAAC;AAC9D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAsBxD,wBAAgB,2BAA2B,IAAI,OAAO,CAErD;AAED,eAAO,MAAM,SAAS;aAAiC,WAAW;kDAqLhE,CAAC;AAEH,eAAe,SAAS,CAAC"}
1
+ {"version":3,"file":"VideoView.web.d.ts","sourceRoot":"","sources":["../src/VideoView.web.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA6D,MAAM,OAAO,CAAC;AAGlF,OAAO,WAA6B,MAAM,mBAAmB,CAAC;AAC9D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAsBxD,wBAAgB,2BAA2B,IAAI,OAAO,CAErD;AAED,eAAO,MAAM,SAAS;aAAiC,WAAW;kDAuLhE,CAAC;AAEH,eAAe,SAAS,CAAC"}
@@ -23,6 +23,7 @@ export function isPictureInPictureSupported() {
23
23
  }
24
24
  export const VideoView = forwardRef((props, ref) => {
25
25
  const videoRef = useRef(null);
26
+ const fullscreenEnabled = props.fullscreenOptions?.enable ?? props.allowsFullscreen ?? true;
26
27
  const mediaNodeRef = useRef(null);
27
28
  const hasToSetupAudioContext = useRef(false);
28
29
  const fullscreenChangeListener = useRef(null);
@@ -37,7 +38,7 @@ export const VideoView = forwardRef((props, ref) => {
37
38
  const zeroGainNodeRef = useRef(null);
38
39
  useImperativeHandle(ref, () => ({
39
40
  enterFullscreen: async () => {
40
- if (!props.allowsFullscreen) {
41
+ if (!fullscreenEnabled) {
41
42
  return;
42
43
  }
43
44
  await videoRef.current?.requestFullscreen();
@@ -157,7 +158,7 @@ export const VideoView = forwardRef((props, ref) => {
157
158
  detachAudioNodes();
158
159
  };
159
160
  }, [props.player]);
160
- return (_jsx("video", { controls: props.nativeControls ?? true, controlsList: props.allowsFullscreen ? undefined : 'nofullscreen', crossOrigin: props.crossOrigin, style: {
161
+ return (_jsx("video", { controls: props.nativeControls ?? true, controlsList: fullscreenEnabled ? undefined : 'nofullscreen', crossOrigin: props.crossOrigin, style: {
161
162
  ...mapStyles(props.style),
162
163
  objectFit: props.contentFit,
163
164
  }, onPlay: () => {