expo-video 3.1.0-canary-20260105-6b962e6 → 4.0.0-canary-20260113-0ce2b9c

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 (61) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/android/build.gradle +2 -2
  3. package/android/src/main/java/expo/modules/video/VideoModule.kt +0 -3
  4. package/android/src/main/java/expo/modules/video/player/VideoPlayer.kt +13 -7
  5. package/build/VideoView.d.ts.map +1 -1
  6. package/build/VideoView.js +0 -3
  7. package/build/VideoView.js.map +1 -1
  8. package/build/VideoView.types.d.ts +0 -8
  9. package/build/VideoView.types.d.ts.map +1 -1
  10. package/build/VideoView.types.js.map +1 -1
  11. package/build/VideoView.web.d.ts.map +1 -1
  12. package/build/VideoView.web.js +1 -4
  13. package/build/VideoView.web.js.map +1 -1
  14. package/expo-module.config.json +1 -1
  15. package/ios/VideoModule.swift +0 -6
  16. package/local-maven-repo/host/exp/exponent/expo.modules.video/{3.1.0-canary-20260105-6b962e6/expo.modules.video-3.1.0-canary-20260105-6b962e6-sources.jar → 4.0.0-canary-20260113-0ce2b9c/expo.modules.video-4.0.0-canary-20260113-0ce2b9c-sources.jar} +0 -0
  17. package/local-maven-repo/host/exp/exponent/expo.modules.video/4.0.0-canary-20260113-0ce2b9c/expo.modules.video-4.0.0-canary-20260113-0ce2b9c-sources.jar.md5 +1 -0
  18. package/local-maven-repo/host/exp/exponent/expo.modules.video/4.0.0-canary-20260113-0ce2b9c/expo.modules.video-4.0.0-canary-20260113-0ce2b9c-sources.jar.sha1 +1 -0
  19. package/local-maven-repo/host/exp/exponent/expo.modules.video/4.0.0-canary-20260113-0ce2b9c/expo.modules.video-4.0.0-canary-20260113-0ce2b9c-sources.jar.sha256 +1 -0
  20. package/local-maven-repo/host/exp/exponent/expo.modules.video/4.0.0-canary-20260113-0ce2b9c/expo.modules.video-4.0.0-canary-20260113-0ce2b9c-sources.jar.sha512 +1 -0
  21. package/local-maven-repo/host/exp/exponent/expo.modules.video/4.0.0-canary-20260113-0ce2b9c/expo.modules.video-4.0.0-canary-20260113-0ce2b9c.aar +0 -0
  22. package/local-maven-repo/host/exp/exponent/expo.modules.video/4.0.0-canary-20260113-0ce2b9c/expo.modules.video-4.0.0-canary-20260113-0ce2b9c.aar.md5 +1 -0
  23. package/local-maven-repo/host/exp/exponent/expo.modules.video/4.0.0-canary-20260113-0ce2b9c/expo.modules.video-4.0.0-canary-20260113-0ce2b9c.aar.sha1 +1 -0
  24. package/local-maven-repo/host/exp/exponent/expo.modules.video/4.0.0-canary-20260113-0ce2b9c/expo.modules.video-4.0.0-canary-20260113-0ce2b9c.aar.sha256 +1 -0
  25. package/local-maven-repo/host/exp/exponent/expo.modules.video/4.0.0-canary-20260113-0ce2b9c/expo.modules.video-4.0.0-canary-20260113-0ce2b9c.aar.sha512 +1 -0
  26. package/local-maven-repo/host/exp/exponent/expo.modules.video/{3.1.0-canary-20260105-6b962e6/expo.modules.video-3.1.0-canary-20260105-6b962e6.module → 4.0.0-canary-20260113-0ce2b9c/expo.modules.video-4.0.0-canary-20260113-0ce2b9c.module} +22 -22
  27. package/local-maven-repo/host/exp/exponent/expo.modules.video/4.0.0-canary-20260113-0ce2b9c/expo.modules.video-4.0.0-canary-20260113-0ce2b9c.module.md5 +1 -0
  28. package/local-maven-repo/host/exp/exponent/expo.modules.video/4.0.0-canary-20260113-0ce2b9c/expo.modules.video-4.0.0-canary-20260113-0ce2b9c.module.sha1 +1 -0
  29. package/local-maven-repo/host/exp/exponent/expo.modules.video/4.0.0-canary-20260113-0ce2b9c/expo.modules.video-4.0.0-canary-20260113-0ce2b9c.module.sha256 +1 -0
  30. package/local-maven-repo/host/exp/exponent/expo.modules.video/4.0.0-canary-20260113-0ce2b9c/expo.modules.video-4.0.0-canary-20260113-0ce2b9c.module.sha512 +1 -0
  31. package/local-maven-repo/host/exp/exponent/expo.modules.video/{3.1.0-canary-20260105-6b962e6/expo.modules.video-3.1.0-canary-20260105-6b962e6.pom → 4.0.0-canary-20260113-0ce2b9c/expo.modules.video-4.0.0-canary-20260113-0ce2b9c.pom} +1 -1
  32. package/local-maven-repo/host/exp/exponent/expo.modules.video/4.0.0-canary-20260113-0ce2b9c/expo.modules.video-4.0.0-canary-20260113-0ce2b9c.pom.md5 +1 -0
  33. package/local-maven-repo/host/exp/exponent/expo.modules.video/4.0.0-canary-20260113-0ce2b9c/expo.modules.video-4.0.0-canary-20260113-0ce2b9c.pom.sha1 +1 -0
  34. package/local-maven-repo/host/exp/exponent/expo.modules.video/4.0.0-canary-20260113-0ce2b9c/expo.modules.video-4.0.0-canary-20260113-0ce2b9c.pom.sha256 +1 -0
  35. package/local-maven-repo/host/exp/exponent/expo.modules.video/4.0.0-canary-20260113-0ce2b9c/expo.modules.video-4.0.0-canary-20260113-0ce2b9c.pom.sha512 +1 -0
  36. package/local-maven-repo/host/exp/exponent/expo.modules.video/maven-metadata.xml +4 -4
  37. package/local-maven-repo/host/exp/exponent/expo.modules.video/maven-metadata.xml.md5 +1 -1
  38. package/local-maven-repo/host/exp/exponent/expo.modules.video/maven-metadata.xml.sha1 +1 -1
  39. package/local-maven-repo/host/exp/exponent/expo.modules.video/maven-metadata.xml.sha256 +1 -1
  40. package/local-maven-repo/host/exp/exponent/expo.modules.video/maven-metadata.xml.sha512 +1 -1
  41. package/package.json +3 -3
  42. package/src/VideoView.tsx +0 -6
  43. package/src/VideoView.types.ts +0 -9
  44. package/src/VideoView.web.tsx +1 -4
  45. package/local-maven-repo/host/exp/exponent/expo.modules.video/3.1.0-canary-20260105-6b962e6/expo.modules.video-3.1.0-canary-20260105-6b962e6-sources.jar.md5 +0 -1
  46. package/local-maven-repo/host/exp/exponent/expo.modules.video/3.1.0-canary-20260105-6b962e6/expo.modules.video-3.1.0-canary-20260105-6b962e6-sources.jar.sha1 +0 -1
  47. package/local-maven-repo/host/exp/exponent/expo.modules.video/3.1.0-canary-20260105-6b962e6/expo.modules.video-3.1.0-canary-20260105-6b962e6-sources.jar.sha256 +0 -1
  48. package/local-maven-repo/host/exp/exponent/expo.modules.video/3.1.0-canary-20260105-6b962e6/expo.modules.video-3.1.0-canary-20260105-6b962e6-sources.jar.sha512 +0 -1
  49. package/local-maven-repo/host/exp/exponent/expo.modules.video/3.1.0-canary-20260105-6b962e6/expo.modules.video-3.1.0-canary-20260105-6b962e6.aar +0 -0
  50. package/local-maven-repo/host/exp/exponent/expo.modules.video/3.1.0-canary-20260105-6b962e6/expo.modules.video-3.1.0-canary-20260105-6b962e6.aar.md5 +0 -1
  51. package/local-maven-repo/host/exp/exponent/expo.modules.video/3.1.0-canary-20260105-6b962e6/expo.modules.video-3.1.0-canary-20260105-6b962e6.aar.sha1 +0 -1
  52. package/local-maven-repo/host/exp/exponent/expo.modules.video/3.1.0-canary-20260105-6b962e6/expo.modules.video-3.1.0-canary-20260105-6b962e6.aar.sha256 +0 -1
  53. package/local-maven-repo/host/exp/exponent/expo.modules.video/3.1.0-canary-20260105-6b962e6/expo.modules.video-3.1.0-canary-20260105-6b962e6.aar.sha512 +0 -1
  54. package/local-maven-repo/host/exp/exponent/expo.modules.video/3.1.0-canary-20260105-6b962e6/expo.modules.video-3.1.0-canary-20260105-6b962e6.module.md5 +0 -1
  55. package/local-maven-repo/host/exp/exponent/expo.modules.video/3.1.0-canary-20260105-6b962e6/expo.modules.video-3.1.0-canary-20260105-6b962e6.module.sha1 +0 -1
  56. package/local-maven-repo/host/exp/exponent/expo.modules.video/3.1.0-canary-20260105-6b962e6/expo.modules.video-3.1.0-canary-20260105-6b962e6.module.sha256 +0 -1
  57. package/local-maven-repo/host/exp/exponent/expo.modules.video/3.1.0-canary-20260105-6b962e6/expo.modules.video-3.1.0-canary-20260105-6b962e6.module.sha512 +0 -1
  58. package/local-maven-repo/host/exp/exponent/expo.modules.video/3.1.0-canary-20260105-6b962e6/expo.modules.video-3.1.0-canary-20260105-6b962e6.pom.md5 +0 -1
  59. package/local-maven-repo/host/exp/exponent/expo.modules.video/3.1.0-canary-20260105-6b962e6/expo.modules.video-3.1.0-canary-20260105-6b962e6.pom.sha1 +0 -1
  60. package/local-maven-repo/host/exp/exponent/expo.modules.video/3.1.0-canary-20260105-6b962e6/expo.modules.video-3.1.0-canary-20260105-6b962e6.pom.sha256 +0 -1
  61. package/local-maven-repo/host/exp/exponent/expo.modules.video/3.1.0-canary-20260105-6b962e6/expo.modules.video-3.1.0-canary-20260105-6b962e6.pom.sha512 +0 -1
package/CHANGELOG.md CHANGED
@@ -4,6 +4,8 @@
4
4
 
5
5
  ### 🛠 Breaking changes
6
6
 
7
+ - Remove the `allowsFullscreen` prop. ([#41606](https://github.com/expo/expo/pull/41606) by [@behenate](https://github.com/behenate))
8
+
7
9
  ### 🎉 New features
8
10
 
9
11
  - [Android][iOS] Add `seek tolerance` and `scrubbingModeOptions` properties to the player. ([#40203](https://github.com/expo/expo/pull/40203) by [@behenate](https://github.com/behenate))
@@ -17,6 +19,9 @@
17
19
  - [Web] Fix crash on older versions of Safari. ([#41101](https://github.com/expo/expo/pull/41101) by [@CamWass](https://github.com/CamWass))
18
20
  - [Web] Fix video pausing when entering fullscreen in electron apps. ([#40989](https://github.com/expo/expo/pull/40989) by [@behenate](https://github.com/behenate))
19
21
  - [Android] Fix crashes when exiting PiP with one than more `VideoView` present on the screen. ([#41090](https://github.com/expo/expo/pull/41090) by [@behenate](https://github.com/behenate))
22
+ - [Android] Fix rare crashes related to VideoPlayer listeners. ([#41608](https://github.com/expo/expo/pull/41608) by [@behenate](https://github.com/behenate))
23
+ - Fix `fullscreenOptions.enable` and `allowsFullscreen` props issues. ([#41600](https://github.com/expo/expo/pull/41600) by [@behenate](https://github.com/behenate))
24
+ - [Android] Fix player duration property refreshing too late. ([#41609](https://github.com/expo/expo/pull/41609) by [@behenate](https://github.com/behenate))
20
25
 
21
26
  ### 💡 Others
22
27
 
@@ -4,13 +4,13 @@ plugins {
4
4
  }
5
5
 
6
6
  group = 'host.exp.exponent'
7
- version = '3.1.0-canary-20260105-6b962e6'
7
+ version = '4.0.0-canary-20260113-0ce2b9c'
8
8
 
9
9
  android {
10
10
  namespace "expo.modules.video"
11
11
  defaultConfig {
12
12
  versionCode 1
13
- versionName '3.1.0-canary-20260105-6b962e6'
13
+ versionName '4.0.0-canary-20260113-0ce2b9c'
14
14
  }
15
15
  }
16
16
 
@@ -404,9 +404,6 @@ private inline fun <reified T : VideoView> ViewDefinitionBuilder<T>.VideoViewCom
404
404
  Prop("startsPictureInPictureAutomatically") { view: T, autoEnterPiP: Boolean? ->
405
405
  view.autoEnterPiP = autoEnterPiP ?: false
406
406
  }
407
- Prop("allowsFullscreen") { view: T, allowsFullscreen: Boolean? ->
408
- view.allowsFullscreen = allowsFullscreen ?: true
409
- }
410
407
  Prop("fullscreenOptions") { view: T, fullscreenOptions: FullscreenOptions? ->
411
408
  if (fullscreenOptions != null) {
412
409
  view.fullscreenOptions = fullscreenOptions
@@ -58,7 +58,7 @@ class VideoPlayer(val context: Context, appContext: AppContext, source: VideoSou
58
58
  private var renderersFactory = DefaultRenderersFactory(context)
59
59
  .forceEnableMediaCodecAsynchronousQueueing()
60
60
  .setEnableDecoderFallback(true)
61
- private var listeners: MutableList<WeakReference<VideoPlayerListener>> = mutableListOf()
61
+ private val listeners: MutableList<WeakReference<VideoPlayerListener>> = mutableListOf()
62
62
  private val currentVideoViewRef = MutableWeakReference<VideoView?>(null) { new, old ->
63
63
  sendEvent(PlayerEvent.TargetViewChanged(new, old))
64
64
  }
@@ -239,12 +239,13 @@ class VideoPlayer(val context: Context, appContext: AppContext, source: VideoSou
239
239
  val newCurrentSubtitleTrack = subtitles.currentSubtitleTrack
240
240
  val newCurrentAudioTrack = audioTracks.currentAudioTrack
241
241
  availableVideoTracks = tracks.toVideoTracks()
242
+ refreshPlaybackInfo()
242
243
 
243
244
  if (isLoadingNewSource) {
244
245
  sendEvent(
245
246
  PlayerEvent.VideoSourceLoaded(
246
247
  commitedSource,
247
- this@VideoPlayer.player.duration / 1000.0,
248
+ duration.toDouble(),
248
249
  availableVideoTracks,
249
250
  newSubtitleTracks,
250
251
  newAudioTracks
@@ -481,19 +482,24 @@ class VideoPlayer(val context: Context, appContext: AppContext, source: VideoSou
481
482
  }
482
483
 
483
484
  fun addListener(videoPlayerListener: VideoPlayerListener) {
484
- if (listeners.all { it.get() != videoPlayerListener }) {
485
- listeners.add(WeakReference(videoPlayerListener))
485
+ synchronized(listeners) {
486
+ if (listeners.all { it.get() != videoPlayerListener }) {
487
+ listeners.add(WeakReference(videoPlayerListener))
488
+ }
486
489
  }
487
490
  }
488
491
 
489
492
  fun removeListener(videoPlayerListener: VideoPlayerListener) {
490
- listeners.removeAll { it.get() == videoPlayerListener }
493
+ synchronized(listeners) {
494
+ listeners.removeAll { it.get() == videoPlayerListener }
495
+ }
491
496
  }
492
497
 
493
498
  private fun sendEvent(event: PlayerEvent) {
499
+ val listenersSnapshot = synchronized(listeners) {
500
+ listeners.mapNotNull { it.get() }
501
+ }
494
502
  // Emits to the native listeners
495
- val listenersSnapshot = listeners.toList().mapNotNull { it.get() }
496
-
497
503
  event.emit(this, listenersSnapshot)
498
504
 
499
505
  // Emits to the JS side
@@ -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;;OAEG;IACH,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;CAepB"}
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;;OAEG;IACH,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"}
@@ -56,9 +56,6 @@ export class VideoView extends PureComponent {
56
56
  render() {
57
57
  const { player, ...props } = this.props;
58
58
  const playerId = player ? getPlayerId(player) : null;
59
- if (props.allowsFullscreen !== undefined) {
60
- console.warn('The `allowsFullscreen` prop is deprecated and will be removed in a future release. Use `fullscreenOptions` prop instead.');
61
- }
62
59
  if (NativeTextureVideoView && this.props.surfaceType === 'textureView') {
63
60
  return <NativeTextureVideoView {...props} player={playerId} ref={this.nativeRef}/>;
64
61
  }
@@ -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;;OAEG;IACH,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,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAErD,IAAI,KAAK,CAAC,gBAAgB,KAAK,SAAS,EAAE,CAAC;YACzC,OAAO,CAAC,IAAI,CACV,0HAA0H,CAC3H,CAAC;QACJ,CAAC;QAED,IAAI,sBAAsB,IAAI,IAAI,CAAC,KAAK,CAAC,WAAW,KAAK,aAAa,EAAE,CAAC;YACvE,OAAO,CAAC,sBAAsB,CAAC,IAAI,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,EAAG,CAAC;QACtF,CAAC;QACD,OAAO,CAAC,eAAe,CAAC,IAAI,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,EAAG,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 /**\n * A reference to the underlying native view. On web it is a reference to the HTMLVideoElement.\n */\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 = player ? getPlayerId(player) : null;\n\n if (props.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 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;;OAEG;IACH,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,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAErD,IAAI,sBAAsB,IAAI,IAAI,CAAC,KAAK,CAAC,WAAW,KAAK,aAAa,EAAE,CAAC;YACvE,OAAO,CAAC,sBAAsB,CAAC,IAAI,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,EAAG,CAAC;QACtF,CAAC;QACD,OAAO,CAAC,eAAe,CAAC,IAAI,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,EAAG,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 /**\n * A reference to the underlying native view. On web it is a reference to the HTMLVideoElement.\n */\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 = player ? getPlayerId(player) : null;\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"]}
@@ -34,13 +34,6 @@ export interface VideoViewProps extends ViewProps {
34
34
  * @default 'contain'
35
35
  */
36
36
  contentFit?: VideoContentFit;
37
- /**
38
- * Determines whether fullscreen mode is allowed or not.
39
- *
40
- * > Note: This option has been deprecated in favor of the `fullscreenOptions` prop and will be disabled in the future.
41
- * @default true
42
- */
43
- allowsFullscreen?: boolean;
44
37
  /**
45
38
  * Determines the fullscreen mode options.
46
39
  */
@@ -183,7 +176,6 @@ export type FullscreenOrientation = 'default' | 'portrait' | 'portraitUp' | 'por
183
176
  export type FullscreenOptions = {
184
177
  /**
185
178
  * Specifies whether the fullscreen mode should be available to the user. When `false`, the fullscreen button will be hidden in the player.
186
- * Equivalent to the `allowsFullscreen` prop.
187
179
  * @default true
188
180
  */
189
181
  enable: boolean;
@@ -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,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IAE5B;;;;;OAKG;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;;;;;;;;;OASG;IACH,WAAW,CAAC,EAAE,WAAW,GAAG,iBAAiB,CAAC;IAE9C;;;;;;;;;OASG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC;AAED;;;;;;;;;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,EAAE,OAAO,CAAC;IAChB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,qBAAqB,CAAC;IACpC;;;;;;;;;;OAUG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B,CAAC"}
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,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IAE5B;;;;;OAKG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IAEzB;;;;OAIG;IACH,UAAU,CAAC,EAAE,eAAe,CAAC;IAE7B;;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;;;;;;;;;OASG;IACH,WAAW,CAAC,EAAE,WAAW,GAAG,iBAAiB,CAAC;IAE9C;;;;;;;;;OASG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC;AAED;;;;;;;;;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;;;OAGG;IACH,MAAM,EAAE,OAAO,CAAC;IAChB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,qBAAqB,CAAC;IACpC;;;;;;;;;;OAUG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B,CAAC"}
@@ -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 | null;\n\n /**\n * Determines whether native controls should be displayed or not.\n *\n * > **Note**: Due to platform limitations, the native controls are always enabled in fullscreen mode.\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` (default), does not use CORS at all. If set to `'anonymous'`, the video will be loaded with CORS enabled.\n * Note that some videos may not play if CORS is enabled, depending on the CDN settings.\n * If you encounter issues, consider adjusting the `crossOrigin` property.\n *\n *\n * @platform web\n * @default undefined\n */\n crossOrigin?: 'anonymous' | 'use-credentials';\n\n /**\n * Use Audio Nodes for sound playback. When the same player is playing in multiple video views the audio won't increase in volume\n * as the number of players increases.\n *\n * > **Note**: This property is experimental, when enabled it is known to break audio for some sources. Do not change this property at runtime.\n *\n * @experimental\n * @default false\n * @platform web\n */\n useAudioNodePlayback?: boolean;\n}\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"]}
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 | null;\n\n /**\n * Determines whether native controls should be displayed or not.\n *\n * > **Note**: Due to platform limitations, the native controls are always enabled in fullscreen mode.\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 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` (default), does not use CORS at all. If set to `'anonymous'`, the video will be loaded with CORS enabled.\n * Note that some videos may not play if CORS is enabled, depending on the CDN settings.\n * If you encounter issues, consider adjusting the `crossOrigin` property.\n *\n *\n * @platform web\n * @default undefined\n */\n crossOrigin?: 'anonymous' | 'use-credentials';\n\n /**\n * Use Audio Nodes for sound playback. When the same player is playing in multiple video views the audio won't increase in volume\n * as the number of players increases.\n *\n * > **Note**: This property is experimental, when enabled it is known to break audio for some sources. Do not change this property at runtime.\n *\n * @experimental\n * @default false\n * @platform web\n */\n useAudioNodePlayback?: boolean;\n}\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 * @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"]}
@@ -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;AA6BxD,wBAAgB,2BAA2B,IAAI,OAAO,CAErD;AAED,eAAO,MAAM,SAAS;aAAiC,WAAW;kDA+PhE,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;AA6BxD,wBAAgB,2BAA2B,IAAI,OAAO,CAErD;AAED,eAAO,MAAM,SAAS;aAAiC,WAAW;kDA4PhE,CAAC;AAEH,eAAe,SAAS,CAAC"}
@@ -46,9 +46,6 @@ export const VideoView = forwardRef((props, ref) => {
46
46
  }, [props.useAudioNodePlayback]);
47
47
  useImperativeHandle(ref, () => ({
48
48
  enterFullscreen: async () => {
49
- if (!props.allowsFullscreen || !videoRef.current) {
50
- return;
51
- }
52
49
  // Cast the video to any to avoid ts errors. Methods such as webkitRequestFullscreen,
53
50
  // webkitEnterFullScreen, msRequestFullscreen are not typed even though they exist.
54
51
  const video = videoRef.current;
@@ -218,7 +215,7 @@ export const VideoView = forwardRef((props, ref) => {
218
215
  detachAudioNodes();
219
216
  };
220
217
  }, [props.player]);
221
- return (<video controls={props.nativeControls ?? true} controlsList={props.allowsFullscreen ? undefined : 'nofullscreen'} crossOrigin={props.crossOrigin} style={{
218
+ return (<video controls={props.nativeControls ?? true} controlsList={props.fullscreenOptions?.enable ? undefined : 'nofullscreen'} crossOrigin={props.crossOrigin} style={{
222
219
  ...mapStyles(props.style),
223
220
  objectFit: props.contentFit,
224
221
  }} onPlay={() => {
@@ -1 +1 @@
1
- {"version":3,"file":"VideoView.web.js","sourceRoot":"","sources":["../src/VideoView.web.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, { useEffect, useRef, forwardRef, useImperativeHandle } from 'react';\nimport { StyleSheet } from 'react-native';\n\nimport VideoPlayer, { getSourceUri } from './VideoPlayer.web';\nimport type { VideoViewProps } from './VideoView.types';\n\ntype FullscreenChangeListeners = {\n default: () => void;\n safariEnter: () => void;\n safariExit: () => void;\n msListener: () => void;\n};\n\nfunction createAudioContext(): AudioContext | null {\n return typeof window !== 'undefined' ? new window.AudioContext() : null;\n}\n\nfunction createZeroGainNode(audioContext: AudioContext | null): GainNode | null {\n const zeroGainNode = audioContext?.createGain() ?? null;\n\n if (audioContext && zeroGainNode) {\n zeroGainNode.gain.value = 0;\n zeroGainNode.connect(audioContext.destination);\n }\n return zeroGainNode;\n}\n\nfunction mapStyles(style: VideoViewProps['style']): React.CSSProperties {\n const flattenedStyles = StyleSheet.flatten(style);\n // Looking through react-native-web source code they also just pass styles directly without further conversions, so it's just a cast.\n return flattenedStyles as React.CSSProperties;\n}\n\nexport function isPictureInPictureSupported(): boolean {\n return typeof document === 'object' && typeof document.exitPictureInPicture === 'function';\n}\n\nexport const VideoView = forwardRef((props: { player?: VideoPlayer } & VideoViewProps, ref) => {\n const videoRef = useRef<null | HTMLVideoElement>(null);\n const mediaNodeRef = useRef<null | MediaElementAudioSourceNode>(null);\n const hasToSetupAudioContext = useRef(false);\n const fullscreenChangeListeners = useRef<null | FullscreenChangeListeners>(null);\n const isWaitingForFirstFrame = useRef(false);\n const mountedPlayerRef = useRef<null | VideoPlayer>(null);\n\n /**\n * Audio context is used to mute all but one video when multiple video views are playing from one player simultaneously.\n * Using audio context nodes allows muting videos without displaying the mute icon in the video player.\n * We have to keep the context that called createMediaElementSource(videoRef), as the method can't be called\n * for the second time with another context and there is no way to unbind the video and audio context afterward.\n */\n const audioContextRef = useRef<null | AudioContext>(null);\n const zeroGainNodeRef = useRef<null | GainNode>(null);\n\n useEffect(() => {\n if (props.useAudioNodePlayback) {\n maybeSetupAudioContext();\n attachAudioNodes();\n } else {\n detachAudioNodes();\n }\n }, [props.useAudioNodePlayback]);\n\n useImperativeHandle(ref, () => ({\n enterFullscreen: async () => {\n if (!props.allowsFullscreen || !videoRef.current) {\n return;\n }\n // Cast the video to any to avoid ts errors. Methods such as webkitRequestFullscreen,\n // webkitEnterFullScreen, msRequestFullscreen are not typed even though they exist.\n const video = videoRef.current as any;\n\n if (video.requestFullscreen) {\n await video.requestFullscreen();\n } else if (video.webkitRequestFullscreen) {\n // @ts-ignore webkitRequestFullscreen can exist on Apple devices\n await video.webkitRequestFullscreen();\n } else if (video.webkitEnterFullScreen) {\n await video.webkitEnterFullScreen();\n } else if (video.msRequestFullscreen) {\n await video.msRequestFullscreen();\n }\n },\n exitFullscreen: async () => {\n await document.exitFullscreen();\n },\n startPictureInPicture: async () => {\n await videoRef.current?.requestPictureInPicture();\n },\n stopPictureInPicture: async () => {\n try {\n await document.exitPictureInPicture();\n } catch (e) {\n if (e instanceof DOMException && e.name === 'InvalidStateError') {\n console.warn('The VideoView is not in Picture-in-Picture mode.');\n } else {\n throw e;\n }\n }\n },\n nativeRef: videoRef,\n }));\n\n useEffect(() => {\n const onEnter = () => {\n props.onPictureInPictureStart?.();\n };\n const onLeave = () => {\n props.onPictureInPictureStop?.();\n };\n const onLoadStart = () => {\n isWaitingForFirstFrame.current = true;\n };\n const onCanPlay = () => {\n if (isWaitingForFirstFrame.current) {\n props.onFirstFrameRender?.();\n }\n isWaitingForFirstFrame.current = false;\n };\n videoRef.current?.addEventListener('enterpictureinpicture', onEnter);\n videoRef.current?.addEventListener('leavepictureinpicture', onLeave);\n videoRef.current?.addEventListener('loadstart', onLoadStart);\n videoRef.current?.addEventListener('loadeddata', onCanPlay);\n\n return () => {\n videoRef.current?.removeEventListener('enterpictureinpicture', onEnter);\n videoRef.current?.removeEventListener('leavepictureinpicture', onLeave);\n videoRef.current?.removeEventListener('loadstart', onLoadStart);\n videoRef.current?.removeEventListener('loadeddata', onCanPlay);\n };\n }, [videoRef, props.onPictureInPictureStop, props.onPictureInPictureStart]);\n\n // Adds the video view as a candidate for being the audio source for the player (when multiple views play from one\n // player only one will emit audio).\n function attachAudioNodes() {\n if (!props.useAudioNodePlayback) {\n return;\n }\n const audioContext = audioContextRef.current;\n const zeroGainNode = zeroGainNodeRef.current;\n const mediaNode = mediaNodeRef.current;\n\n if (audioContext && zeroGainNode && mediaNode) {\n props.player?.mountAudioNode(audioContext, zeroGainNode, mediaNode);\n } else {\n console.warn(\n \"Couldn't mount audio node, this might affect the audio playback when using multiple video views with the same player.\"\n );\n }\n }\n\n function detachAudioNodes() {\n if (!props.useAudioNodePlayback) {\n return;\n }\n const audioContext = audioContextRef.current;\n const mediaNode = mediaNodeRef.current;\n if (audioContext && mediaNode && videoRef.current) {\n props.player?.unmountAudioNode(videoRef.current, audioContext, mediaNode);\n }\n }\n\n function maybeSetupAudioContext() {\n // Not all browsers support the UserActivation API, so check it exists before we access it.\n // If the API doesn't exist then we'll continue as if the user has been active.\n const userHasNotBeenActive =\n 'userActivation' in navigator && !navigator.userActivation.hasBeenActive;\n\n if (\n !hasToSetupAudioContext.current ||\n userHasNotBeenActive ||\n !videoRef.current ||\n !props.useAudioNodePlayback\n ) {\n return;\n }\n const audioContext = createAudioContext();\n\n detachAudioNodes();\n audioContextRef.current = audioContext;\n zeroGainNodeRef.current = createZeroGainNode(audioContextRef.current);\n mediaNodeRef.current = audioContext\n ? audioContext.createMediaElementSource(videoRef.current)\n : null;\n attachAudioNodes();\n hasToSetupAudioContext.current = false;\n }\n\n function fullscreenListener() {\n if (document.fullscreenElement === videoRef.current) {\n props.onFullscreenEnter?.();\n } else {\n props.onFullscreenExit?.();\n }\n }\n\n function setupFullscreenListener() {\n cleanupFullscreenListener();\n const video = videoRef.current;\n if (!video) return;\n const fullscreenListeners: FullscreenChangeListeners = {\n default: fullscreenListener,\n safariEnter: () => props.onFullscreenEnter?.(),\n safariExit: () => props.onFullscreenExit?.(),\n msListener: fullscreenListener,\n };\n\n fullscreenChangeListeners.current = fullscreenListeners;\n\n // Standard Fullscreen API\n video.addEventListener('fullscreenchange', fullscreenListeners.default);\n\n // Safari (webkit)\n video.addEventListener('webkitbeginfullscreen', fullscreenListeners.safariEnter);\n video.addEventListener('webkitendfullscreen', fullscreenListeners.safariExit);\n\n // IE11 (ms)\n document.addEventListener('MSFullscreenChange', fullscreenListeners.msListener);\n }\n\n function cleanupFullscreenListener() {\n const video = videoRef.current;\n if (!video || !fullscreenChangeListeners.current) return;\n\n video.removeEventListener('fullscreenchange', fullscreenChangeListeners.current.default);\n video.removeEventListener(\n 'webkitbeginfullscreen',\n fullscreenChangeListeners.current?.safariEnter\n );\n video.removeEventListener('webkitendfullscreen', fullscreenChangeListeners.current.safariExit);\n document.removeEventListener(\n 'MSFullscreenChange',\n fullscreenChangeListeners.current.msListener\n );\n }\n\n useEffect(() => {\n videoRef.current && mountedPlayerRef.current?.unmountVideoView(videoRef.current);\n\n if (videoRef.current) {\n props.player?.mountVideoView(videoRef.current);\n }\n setupFullscreenListener();\n attachAudioNodes();\n\n mountedPlayerRef.current = props.player ?? null;\n\n if (props.player == null) {\n videoRef.current?.removeAttribute('src');\n videoRef.current?.load();\n }\n\n return () => {\n if (videoRef.current) {\n props.player?.unmountVideoView(videoRef.current);\n }\n mountedPlayerRef.current = null;\n cleanupFullscreenListener();\n detachAudioNodes();\n };\n }, [props.player]);\n\n return (\n <video\n controls={props.nativeControls ?? true}\n controlsList={props.allowsFullscreen ? undefined : 'nofullscreen'}\n crossOrigin={props.crossOrigin}\n style={{\n ...mapStyles(props.style),\n objectFit: props.contentFit,\n }}\n onPlay={() => {\n maybeSetupAudioContext();\n }}\n // The player can autoplay when muted, unmuting by a user should create the audio context\n onVolumeChange={() => {\n maybeSetupAudioContext();\n }}\n ref={(newRef) => {\n // This is called with a null value before `player.unmountVideoView` is called,\n // we can't assign null to videoRef if we want to unmount it from the player.\n if (newRef && !newRef.isEqualNode(videoRef.current)) {\n videoRef.current = newRef;\n hasToSetupAudioContext.current = props.useAudioNodePlayback ?? false;\n maybeSetupAudioContext();\n }\n }}\n disablePictureInPicture={!props.allowsPictureInPicture}\n playsInline={props.playsInline}\n src={getSourceUri(props.player?.src) ?? undefined}\n />\n );\n});\n\nexport default VideoView;\n"]}
1
+ {"version":3,"file":"VideoView.web.js","sourceRoot":"","sources":["../src/VideoView.web.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,OAAO,CAAC;AAClF,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,OAAoB,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAU9D,SAAS,kBAAkB;IACzB,OAAO,OAAO,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AAC1E,CAAC;AAED,SAAS,kBAAkB,CAAC,YAAiC;IAC3D,MAAM,YAAY,GAAG,YAAY,EAAE,UAAU,EAAE,IAAI,IAAI,CAAC;IAExD,IAAI,YAAY,IAAI,YAAY,EAAE,CAAC;QACjC,YAAY,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;QAC5B,YAAY,CAAC,OAAO,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC;IACjD,CAAC;IACD,OAAO,YAAY,CAAC;AACtB,CAAC;AAED,SAAS,SAAS,CAAC,KAA8B;IAC/C,MAAM,eAAe,GAAG,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAClD,qIAAqI;IACrI,OAAO,eAAsC,CAAC;AAChD,CAAC;AAED,MAAM,UAAU,2BAA2B;IACzC,OAAO,OAAO,QAAQ,KAAK,QAAQ,IAAI,OAAO,QAAQ,CAAC,oBAAoB,KAAK,UAAU,CAAC;AAC7F,CAAC;AAED,MAAM,CAAC,MAAM,SAAS,GAAG,UAAU,CAAC,CAAC,KAAgD,EAAE,GAAG,EAAE,EAAE;IAC5F,MAAM,QAAQ,GAAG,MAAM,CAA0B,IAAI,CAAC,CAAC;IACvD,MAAM,YAAY,GAAG,MAAM,CAAqC,IAAI,CAAC,CAAC;IACtE,MAAM,sBAAsB,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC7C,MAAM,yBAAyB,GAAG,MAAM,CAAmC,IAAI,CAAC,CAAC;IACjF,MAAM,sBAAsB,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC7C,MAAM,gBAAgB,GAAG,MAAM,CAAqB,IAAI,CAAC,CAAC;IAE1D;;;;;OAKG;IACH,MAAM,eAAe,GAAG,MAAM,CAAsB,IAAI,CAAC,CAAC;IAC1D,MAAM,eAAe,GAAG,MAAM,CAAkB,IAAI,CAAC,CAAC;IAEtD,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,KAAK,CAAC,oBAAoB,EAAE,CAAC;YAC/B,sBAAsB,EAAE,CAAC;YACzB,gBAAgB,EAAE,CAAC;QACrB,CAAC;aAAM,CAAC;YACN,gBAAgB,EAAE,CAAC;QACrB,CAAC;IACH,CAAC,EAAE,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC,CAAC;IAEjC,mBAAmB,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC;QAC9B,eAAe,EAAE,KAAK,IAAI,EAAE;YAC1B,qFAAqF;YACrF,mFAAmF;YACnF,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAc,CAAC;YAEtC,IAAI,KAAK,CAAC,iBAAiB,EAAE,CAAC;gBAC5B,MAAM,KAAK,CAAC,iBAAiB,EAAE,CAAC;YAClC,CAAC;iBAAM,IAAI,KAAK,CAAC,uBAAuB,EAAE,CAAC;gBACzC,gEAAgE;gBAChE,MAAM,KAAK,CAAC,uBAAuB,EAAE,CAAC;YACxC,CAAC;iBAAM,IAAI,KAAK,CAAC,qBAAqB,EAAE,CAAC;gBACvC,MAAM,KAAK,CAAC,qBAAqB,EAAE,CAAC;YACtC,CAAC;iBAAM,IAAI,KAAK,CAAC,mBAAmB,EAAE,CAAC;gBACrC,MAAM,KAAK,CAAC,mBAAmB,EAAE,CAAC;YACpC,CAAC;QACH,CAAC;QACD,cAAc,EAAE,KAAK,IAAI,EAAE;YACzB,MAAM,QAAQ,CAAC,cAAc,EAAE,CAAC;QAClC,CAAC;QACD,qBAAqB,EAAE,KAAK,IAAI,EAAE;YAChC,MAAM,QAAQ,CAAC,OAAO,EAAE,uBAAuB,EAAE,CAAC;QACpD,CAAC;QACD,oBAAoB,EAAE,KAAK,IAAI,EAAE;YAC/B,IAAI,CAAC;gBACH,MAAM,QAAQ,CAAC,oBAAoB,EAAE,CAAC;YACxC,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,IAAI,CAAC,YAAY,YAAY,IAAI,CAAC,CAAC,IAAI,KAAK,mBAAmB,EAAE,CAAC;oBAChE,OAAO,CAAC,IAAI,CAAC,kDAAkD,CAAC,CAAC;gBACnE,CAAC;qBAAM,CAAC;oBACN,MAAM,CAAC,CAAC;gBACV,CAAC;YACH,CAAC;QACH,CAAC;QACD,SAAS,EAAE,QAAQ;KACpB,CAAC,CAAC,CAAC;IAEJ,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,OAAO,GAAG,GAAG,EAAE;YACnB,KAAK,CAAC,uBAAuB,EAAE,EAAE,CAAC;QACpC,CAAC,CAAC;QACF,MAAM,OAAO,GAAG,GAAG,EAAE;YACnB,KAAK,CAAC,sBAAsB,EAAE,EAAE,CAAC;QACnC,CAAC,CAAC;QACF,MAAM,WAAW,GAAG,GAAG,EAAE;YACvB,sBAAsB,CAAC,OAAO,GAAG,IAAI,CAAC;QACxC,CAAC,CAAC;QACF,MAAM,SAAS,GAAG,GAAG,EAAE;YACrB,IAAI,sBAAsB,CAAC,OAAO,EAAE,CAAC;gBACnC,KAAK,CAAC,kBAAkB,EAAE,EAAE,CAAC;YAC/B,CAAC;YACD,sBAAsB,CAAC,OAAO,GAAG,KAAK,CAAC;QACzC,CAAC,CAAC;QACF,QAAQ,CAAC,OAAO,EAAE,gBAAgB,CAAC,uBAAuB,EAAE,OAAO,CAAC,CAAC;QACrE,QAAQ,CAAC,OAAO,EAAE,gBAAgB,CAAC,uBAAuB,EAAE,OAAO,CAAC,CAAC;QACrE,QAAQ,CAAC,OAAO,EAAE,gBAAgB,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;QAC7D,QAAQ,CAAC,OAAO,EAAE,gBAAgB,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC;QAE5D,OAAO,GAAG,EAAE;YACV,QAAQ,CAAC,OAAO,EAAE,mBAAmB,CAAC,uBAAuB,EAAE,OAAO,CAAC,CAAC;YACxE,QAAQ,CAAC,OAAO,EAAE,mBAAmB,CAAC,uBAAuB,EAAE,OAAO,CAAC,CAAC;YACxE,QAAQ,CAAC,OAAO,EAAE,mBAAmB,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;YAChE,QAAQ,CAAC,OAAO,EAAE,mBAAmB,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC;QACjE,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,QAAQ,EAAE,KAAK,CAAC,sBAAsB,EAAE,KAAK,CAAC,uBAAuB,CAAC,CAAC,CAAC;IAE5E,kHAAkH;IAClH,oCAAoC;IACpC,SAAS,gBAAgB;QACvB,IAAI,CAAC,KAAK,CAAC,oBAAoB,EAAE,CAAC;YAChC,OAAO;QACT,CAAC;QACD,MAAM,YAAY,GAAG,eAAe,CAAC,OAAO,CAAC;QAC7C,MAAM,YAAY,GAAG,eAAe,CAAC,OAAO,CAAC;QAC7C,MAAM,SAAS,GAAG,YAAY,CAAC,OAAO,CAAC;QAEvC,IAAI,YAAY,IAAI,YAAY,IAAI,SAAS,EAAE,CAAC;YAC9C,KAAK,CAAC,MAAM,EAAE,cAAc,CAAC,YAAY,EAAE,YAAY,EAAE,SAAS,CAAC,CAAC;QACtE,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,IAAI,CACV,uHAAuH,CACxH,CAAC;QACJ,CAAC;IACH,CAAC;IAED,SAAS,gBAAgB;QACvB,IAAI,CAAC,KAAK,CAAC,oBAAoB,EAAE,CAAC;YAChC,OAAO;QACT,CAAC;QACD,MAAM,YAAY,GAAG,eAAe,CAAC,OAAO,CAAC;QAC7C,MAAM,SAAS,GAAG,YAAY,CAAC,OAAO,CAAC;QACvC,IAAI,YAAY,IAAI,SAAS,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;YAClD,KAAK,CAAC,MAAM,EAAE,gBAAgB,CAAC,QAAQ,CAAC,OAAO,EAAE,YAAY,EAAE,SAAS,CAAC,CAAC;QAC5E,CAAC;IACH,CAAC;IAED,SAAS,sBAAsB;QAC7B,2FAA2F;QAC3F,+EAA+E;QAC/E,MAAM,oBAAoB,GACxB,gBAAgB,IAAI,SAAS,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,aAAa,CAAC;QAE3E,IACE,CAAC,sBAAsB,CAAC,OAAO;YAC/B,oBAAoB;YACpB,CAAC,QAAQ,CAAC,OAAO;YACjB,CAAC,KAAK,CAAC,oBAAoB,EAC3B,CAAC;YACD,OAAO;QACT,CAAC;QACD,MAAM,YAAY,GAAG,kBAAkB,EAAE,CAAC;QAE1C,gBAAgB,EAAE,CAAC;QACnB,eAAe,CAAC,OAAO,GAAG,YAAY,CAAC;QACvC,eAAe,CAAC,OAAO,GAAG,kBAAkB,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;QACtE,YAAY,CAAC,OAAO,GAAG,YAAY;YACjC,CAAC,CAAC,YAAY,CAAC,wBAAwB,CAAC,QAAQ,CAAC,OAAO,CAAC;YACzD,CAAC,CAAC,IAAI,CAAC;QACT,gBAAgB,EAAE,CAAC;QACnB,sBAAsB,CAAC,OAAO,GAAG,KAAK,CAAC;IACzC,CAAC;IAED,SAAS,kBAAkB;QACzB,IAAI,QAAQ,CAAC,iBAAiB,KAAK,QAAQ,CAAC,OAAO,EAAE,CAAC;YACpD,KAAK,CAAC,iBAAiB,EAAE,EAAE,CAAC;QAC9B,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,gBAAgB,EAAE,EAAE,CAAC;QAC7B,CAAC;IACH,CAAC;IAED,SAAS,uBAAuB;QAC9B,yBAAyB,EAAE,CAAC;QAC5B,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC;QAC/B,IAAI,CAAC,KAAK;YAAE,OAAO;QACnB,MAAM,mBAAmB,GAA8B;YACrD,OAAO,EAAE,kBAAkB;YAC3B,WAAW,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,iBAAiB,EAAE,EAAE;YAC9C,UAAU,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,gBAAgB,EAAE,EAAE;YAC5C,UAAU,EAAE,kBAAkB;SAC/B,CAAC;QAEF,yBAAyB,CAAC,OAAO,GAAG,mBAAmB,CAAC;QAExD,0BAA0B;QAC1B,KAAK,CAAC,gBAAgB,CAAC,kBAAkB,EAAE,mBAAmB,CAAC,OAAO,CAAC,CAAC;QAExE,kBAAkB;QAClB,KAAK,CAAC,gBAAgB,CAAC,uBAAuB,EAAE,mBAAmB,CAAC,WAAW,CAAC,CAAC;QACjF,KAAK,CAAC,gBAAgB,CAAC,qBAAqB,EAAE,mBAAmB,CAAC,UAAU,CAAC,CAAC;QAE9E,YAAY;QACZ,QAAQ,CAAC,gBAAgB,CAAC,oBAAoB,EAAE,mBAAmB,CAAC,UAAU,CAAC,CAAC;IAClF,CAAC;IAED,SAAS,yBAAyB;QAChC,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC;QAC/B,IAAI,CAAC,KAAK,IAAI,CAAC,yBAAyB,CAAC,OAAO;YAAE,OAAO;QAEzD,KAAK,CAAC,mBAAmB,CAAC,kBAAkB,EAAE,yBAAyB,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACzF,KAAK,CAAC,mBAAmB,CACvB,uBAAuB,EACvB,yBAAyB,CAAC,OAAO,EAAE,WAAW,CAC/C,CAAC;QACF,KAAK,CAAC,mBAAmB,CAAC,qBAAqB,EAAE,yBAAyB,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QAC/F,QAAQ,CAAC,mBAAmB,CAC1B,oBAAoB,EACpB,yBAAyB,CAAC,OAAO,CAAC,UAAU,CAC7C,CAAC;IACJ,CAAC;IAED,SAAS,CAAC,GAAG,EAAE;QACb,QAAQ,CAAC,OAAO,IAAI,gBAAgB,CAAC,OAAO,EAAE,gBAAgB,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAEjF,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;YACrB,KAAK,CAAC,MAAM,EAAE,cAAc,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QACjD,CAAC;QACD,uBAAuB,EAAE,CAAC;QAC1B,gBAAgB,EAAE,CAAC;QAEnB,gBAAgB,CAAC,OAAO,GAAG,KAAK,CAAC,MAAM,IAAI,IAAI,CAAC;QAEhD,IAAI,KAAK,CAAC,MAAM,IAAI,IAAI,EAAE,CAAC;YACzB,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC,KAAK,CAAC,CAAC;YACzC,QAAQ,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC;QAC3B,CAAC;QAED,OAAO,GAAG,EAAE;YACV,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;gBACrB,KAAK,CAAC,MAAM,EAAE,gBAAgB,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;YACnD,CAAC;YACD,gBAAgB,CAAC,OAAO,GAAG,IAAI,CAAC;YAChC,yBAAyB,EAAE,CAAC;YAC5B,gBAAgB,EAAE,CAAC;QACrB,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;IAEnB,OAAO,CACL,CAAC,KAAK,CACJ,QAAQ,CAAC,CAAC,KAAK,CAAC,cAAc,IAAI,IAAI,CAAC,CACvC,YAAY,CAAC,CAAC,KAAK,CAAC,iBAAiB,EAAE,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,cAAc,CAAC,CAC3E,WAAW,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,CAC/B,KAAK,CAAC,CAAC;YACL,GAAG,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC;YACzB,SAAS,EAAE,KAAK,CAAC,UAAU;SAC5B,CAAC,CACF,MAAM,CAAC,CAAC,GAAG,EAAE;YACX,sBAAsB,EAAE,CAAC;QAC3B,CAAC,CAAC;IACF,yFAAyF;IACzF,cAAc,CAAC,CAAC,GAAG,EAAE;YACnB,sBAAsB,EAAE,CAAC;QAC3B,CAAC,CAAC,CACF,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE;YACd,+EAA+E;YAC/E,6EAA6E;YAC7E,IAAI,MAAM,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;gBACpD,QAAQ,CAAC,OAAO,GAAG,MAAM,CAAC;gBAC1B,sBAAsB,CAAC,OAAO,GAAG,KAAK,CAAC,oBAAoB,IAAI,KAAK,CAAC;gBACrE,sBAAsB,EAAE,CAAC;YAC3B,CAAC;QACH,CAAC,CAAC,CACF,uBAAuB,CAAC,CAAC,CAAC,KAAK,CAAC,sBAAsB,CAAC,CACvD,WAAW,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,CAC/B,GAAG,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI,SAAS,CAAC,EAClD,CACH,CAAC;AACJ,CAAC,CAAC,CAAC;AAEH,eAAe,SAAS,CAAC","sourcesContent":["import React, { useEffect, useRef, forwardRef, useImperativeHandle } from 'react';\nimport { StyleSheet } from 'react-native';\n\nimport VideoPlayer, { getSourceUri } from './VideoPlayer.web';\nimport type { VideoViewProps } from './VideoView.types';\n\ntype FullscreenChangeListeners = {\n default: () => void;\n safariEnter: () => void;\n safariExit: () => void;\n msListener: () => void;\n};\n\nfunction createAudioContext(): AudioContext | null {\n return typeof window !== 'undefined' ? new window.AudioContext() : null;\n}\n\nfunction createZeroGainNode(audioContext: AudioContext | null): GainNode | null {\n const zeroGainNode = audioContext?.createGain() ?? null;\n\n if (audioContext && zeroGainNode) {\n zeroGainNode.gain.value = 0;\n zeroGainNode.connect(audioContext.destination);\n }\n return zeroGainNode;\n}\n\nfunction mapStyles(style: VideoViewProps['style']): React.CSSProperties {\n const flattenedStyles = StyleSheet.flatten(style);\n // Looking through react-native-web source code they also just pass styles directly without further conversions, so it's just a cast.\n return flattenedStyles as React.CSSProperties;\n}\n\nexport function isPictureInPictureSupported(): boolean {\n return typeof document === 'object' && typeof document.exitPictureInPicture === 'function';\n}\n\nexport const VideoView = forwardRef((props: { player?: VideoPlayer } & VideoViewProps, ref) => {\n const videoRef = useRef<null | HTMLVideoElement>(null);\n const mediaNodeRef = useRef<null | MediaElementAudioSourceNode>(null);\n const hasToSetupAudioContext = useRef(false);\n const fullscreenChangeListeners = useRef<null | FullscreenChangeListeners>(null);\n const isWaitingForFirstFrame = useRef(false);\n const mountedPlayerRef = useRef<null | VideoPlayer>(null);\n\n /**\n * Audio context is used to mute all but one video when multiple video views are playing from one player simultaneously.\n * Using audio context nodes allows muting videos without displaying the mute icon in the video player.\n * We have to keep the context that called createMediaElementSource(videoRef), as the method can't be called\n * for the second time with another context and there is no way to unbind the video and audio context afterward.\n */\n const audioContextRef = useRef<null | AudioContext>(null);\n const zeroGainNodeRef = useRef<null | GainNode>(null);\n\n useEffect(() => {\n if (props.useAudioNodePlayback) {\n maybeSetupAudioContext();\n attachAudioNodes();\n } else {\n detachAudioNodes();\n }\n }, [props.useAudioNodePlayback]);\n\n useImperativeHandle(ref, () => ({\n enterFullscreen: async () => {\n // Cast the video to any to avoid ts errors. Methods such as webkitRequestFullscreen,\n // webkitEnterFullScreen, msRequestFullscreen are not typed even though they exist.\n const video = videoRef.current as any;\n\n if (video.requestFullscreen) {\n await video.requestFullscreen();\n } else if (video.webkitRequestFullscreen) {\n // @ts-ignore webkitRequestFullscreen can exist on Apple devices\n await video.webkitRequestFullscreen();\n } else if (video.webkitEnterFullScreen) {\n await video.webkitEnterFullScreen();\n } else if (video.msRequestFullscreen) {\n await video.msRequestFullscreen();\n }\n },\n exitFullscreen: async () => {\n await document.exitFullscreen();\n },\n startPictureInPicture: async () => {\n await videoRef.current?.requestPictureInPicture();\n },\n stopPictureInPicture: async () => {\n try {\n await document.exitPictureInPicture();\n } catch (e) {\n if (e instanceof DOMException && e.name === 'InvalidStateError') {\n console.warn('The VideoView is not in Picture-in-Picture mode.');\n } else {\n throw e;\n }\n }\n },\n nativeRef: videoRef,\n }));\n\n useEffect(() => {\n const onEnter = () => {\n props.onPictureInPictureStart?.();\n };\n const onLeave = () => {\n props.onPictureInPictureStop?.();\n };\n const onLoadStart = () => {\n isWaitingForFirstFrame.current = true;\n };\n const onCanPlay = () => {\n if (isWaitingForFirstFrame.current) {\n props.onFirstFrameRender?.();\n }\n isWaitingForFirstFrame.current = false;\n };\n videoRef.current?.addEventListener('enterpictureinpicture', onEnter);\n videoRef.current?.addEventListener('leavepictureinpicture', onLeave);\n videoRef.current?.addEventListener('loadstart', onLoadStart);\n videoRef.current?.addEventListener('loadeddata', onCanPlay);\n\n return () => {\n videoRef.current?.removeEventListener('enterpictureinpicture', onEnter);\n videoRef.current?.removeEventListener('leavepictureinpicture', onLeave);\n videoRef.current?.removeEventListener('loadstart', onLoadStart);\n videoRef.current?.removeEventListener('loadeddata', onCanPlay);\n };\n }, [videoRef, props.onPictureInPictureStop, props.onPictureInPictureStart]);\n\n // Adds the video view as a candidate for being the audio source for the player (when multiple views play from one\n // player only one will emit audio).\n function attachAudioNodes() {\n if (!props.useAudioNodePlayback) {\n return;\n }\n const audioContext = audioContextRef.current;\n const zeroGainNode = zeroGainNodeRef.current;\n const mediaNode = mediaNodeRef.current;\n\n if (audioContext && zeroGainNode && mediaNode) {\n props.player?.mountAudioNode(audioContext, zeroGainNode, mediaNode);\n } else {\n console.warn(\n \"Couldn't mount audio node, this might affect the audio playback when using multiple video views with the same player.\"\n );\n }\n }\n\n function detachAudioNodes() {\n if (!props.useAudioNodePlayback) {\n return;\n }\n const audioContext = audioContextRef.current;\n const mediaNode = mediaNodeRef.current;\n if (audioContext && mediaNode && videoRef.current) {\n props.player?.unmountAudioNode(videoRef.current, audioContext, mediaNode);\n }\n }\n\n function maybeSetupAudioContext() {\n // Not all browsers support the UserActivation API, so check it exists before we access it.\n // If the API doesn't exist then we'll continue as if the user has been active.\n const userHasNotBeenActive =\n 'userActivation' in navigator && !navigator.userActivation.hasBeenActive;\n\n if (\n !hasToSetupAudioContext.current ||\n userHasNotBeenActive ||\n !videoRef.current ||\n !props.useAudioNodePlayback\n ) {\n return;\n }\n const audioContext = createAudioContext();\n\n detachAudioNodes();\n audioContextRef.current = audioContext;\n zeroGainNodeRef.current = createZeroGainNode(audioContextRef.current);\n mediaNodeRef.current = audioContext\n ? audioContext.createMediaElementSource(videoRef.current)\n : null;\n attachAudioNodes();\n hasToSetupAudioContext.current = false;\n }\n\n function fullscreenListener() {\n if (document.fullscreenElement === videoRef.current) {\n props.onFullscreenEnter?.();\n } else {\n props.onFullscreenExit?.();\n }\n }\n\n function setupFullscreenListener() {\n cleanupFullscreenListener();\n const video = videoRef.current;\n if (!video) return;\n const fullscreenListeners: FullscreenChangeListeners = {\n default: fullscreenListener,\n safariEnter: () => props.onFullscreenEnter?.(),\n safariExit: () => props.onFullscreenExit?.(),\n msListener: fullscreenListener,\n };\n\n fullscreenChangeListeners.current = fullscreenListeners;\n\n // Standard Fullscreen API\n video.addEventListener('fullscreenchange', fullscreenListeners.default);\n\n // Safari (webkit)\n video.addEventListener('webkitbeginfullscreen', fullscreenListeners.safariEnter);\n video.addEventListener('webkitendfullscreen', fullscreenListeners.safariExit);\n\n // IE11 (ms)\n document.addEventListener('MSFullscreenChange', fullscreenListeners.msListener);\n }\n\n function cleanupFullscreenListener() {\n const video = videoRef.current;\n if (!video || !fullscreenChangeListeners.current) return;\n\n video.removeEventListener('fullscreenchange', fullscreenChangeListeners.current.default);\n video.removeEventListener(\n 'webkitbeginfullscreen',\n fullscreenChangeListeners.current?.safariEnter\n );\n video.removeEventListener('webkitendfullscreen', fullscreenChangeListeners.current.safariExit);\n document.removeEventListener(\n 'MSFullscreenChange',\n fullscreenChangeListeners.current.msListener\n );\n }\n\n useEffect(() => {\n videoRef.current && mountedPlayerRef.current?.unmountVideoView(videoRef.current);\n\n if (videoRef.current) {\n props.player?.mountVideoView(videoRef.current);\n }\n setupFullscreenListener();\n attachAudioNodes();\n\n mountedPlayerRef.current = props.player ?? null;\n\n if (props.player == null) {\n videoRef.current?.removeAttribute('src');\n videoRef.current?.load();\n }\n\n return () => {\n if (videoRef.current) {\n props.player?.unmountVideoView(videoRef.current);\n }\n mountedPlayerRef.current = null;\n cleanupFullscreenListener();\n detachAudioNodes();\n };\n }, [props.player]);\n\n return (\n <video\n controls={props.nativeControls ?? true}\n controlsList={props.fullscreenOptions?.enable ? undefined : 'nofullscreen'}\n crossOrigin={props.crossOrigin}\n style={{\n ...mapStyles(props.style),\n objectFit: props.contentFit,\n }}\n onPlay={() => {\n maybeSetupAudioContext();\n }}\n // The player can autoplay when muted, unmuting by a user should create the audio context\n onVolumeChange={() => {\n maybeSetupAudioContext();\n }}\n ref={(newRef) => {\n // This is called with a null value before `player.unmountVideoView` is called,\n // we can't assign null to videoRef if we want to unmount it from the player.\n if (newRef && !newRef.isEqualNode(videoRef.current)) {\n videoRef.current = newRef;\n hasToSetupAudioContext.current = props.useAudioNodePlayback ?? false;\n maybeSetupAudioContext();\n }\n }}\n disablePictureInPicture={!props.allowsPictureInPicture}\n playsInline={props.playsInline}\n src={getSourceUri(props.player?.src) ?? undefined}\n />\n );\n});\n\nexport default VideoView;\n"]}
@@ -8,7 +8,7 @@
8
8
  "publication": {
9
9
  "groupId": "host.exp.exponent",
10
10
  "artifactId": "expo.modules.video",
11
- "version": "3.1.0-canary-20260105-6b962e6",
11
+ "version": "4.0.0-canary-20260113-0ce2b9c",
12
12
  "repository": "local-maven-repo"
13
13
  }
14
14
  }
@@ -59,12 +59,6 @@ public final class VideoModule: Module {
59
59
  )
60
60
  }
61
61
 
62
- Prop("allowsFullscreen") { (view, allowsFullscreen: Bool?) in
63
- #if !os(tvOS)
64
- view.playerViewController.setValue(allowsFullscreen ?? true, forKey: "allowsEnteringFullScreen")
65
- #endif
66
- }
67
-
68
62
  Prop("fullscreenOptions") {(view, options: FullscreenOptions?) in
69
63
  #if !os(tvOS)
70
64
  view.playerViewController.fullscreenOrientation = options?.orientation.toUIInterfaceOrientationMask() ?? .all
@@ -0,0 +1 @@
1
+ 7ad828f8048d4de909217816ffb7de7d0f9af167e394e907303ab7bb268594646e8496caf7d02d7a00c09430b9778bffa756909099048f7326e4d2ab02b9baa2
@@ -0,0 +1 @@
1
+ 165542915e8f2c66531e661d5b3d7583d444a4306dcb85879807b36180a80356f6b03d653b0eda757a67111fd9516f4097e12284f75e48961659505fff86f19a
@@ -3,7 +3,7 @@
3
3
  "component": {
4
4
  "group": "host.exp.exponent",
5
5
  "module": "expo.modules.video",
6
- "version": "3.1.0-canary-20260105-6b962e6",
6
+ "version": "4.0.0-canary-20260113-0ce2b9c",
7
7
  "attributes": {
8
8
  "org.gradle.status": "release"
9
9
  }
@@ -24,13 +24,13 @@
24
24
  },
25
25
  "files": [
26
26
  {
27
- "name": "expo.modules.video-3.1.0-canary-20260105-6b962e6.aar",
28
- "url": "expo.modules.video-3.1.0-canary-20260105-6b962e6.aar",
29
- "size": 544848,
30
- "sha512": "3b7933241b900baa96a245a26ea32935672d50e6a6423e9e58ab28401d272783a646d561caf3f5adb111ba38270942b546a6d1daafbc5af448348796425e831d",
31
- "sha256": "72f03dcf61c90d058e1168fac769b4edf313e3a61c3082beafed09a131856037",
32
- "sha1": "4d60710a1944bc624612125922f662e2f4c83210",
33
- "md5": "58fc9b743a27b172f762029627edce8b"
27
+ "name": "expo.modules.video-4.0.0-canary-20260113-0ce2b9c.aar",
28
+ "url": "expo.modules.video-4.0.0-canary-20260113-0ce2b9c.aar",
29
+ "size": 542363,
30
+ "sha512": "165542915e8f2c66531e661d5b3d7583d444a4306dcb85879807b36180a80356f6b03d653b0eda757a67111fd9516f4097e12284f75e48961659505fff86f19a",
31
+ "sha256": "c6f7e9432a12e920c31dd07657bc4cc69883abbdeaa19c7805036f6b582c5a82",
32
+ "sha1": "c950508730cf76a8c77f81fff15cd7a733d3604f",
33
+ "md5": "ac7e27d1ea99e01e1eaff1a3899cab1d"
34
34
  }
35
35
  ]
36
36
  },
@@ -113,13 +113,13 @@
113
113
  ],
114
114
  "files": [
115
115
  {
116
- "name": "expo.modules.video-3.1.0-canary-20260105-6b962e6.aar",
117
- "url": "expo.modules.video-3.1.0-canary-20260105-6b962e6.aar",
118
- "size": 544848,
119
- "sha512": "3b7933241b900baa96a245a26ea32935672d50e6a6423e9e58ab28401d272783a646d561caf3f5adb111ba38270942b546a6d1daafbc5af448348796425e831d",
120
- "sha256": "72f03dcf61c90d058e1168fac769b4edf313e3a61c3082beafed09a131856037",
121
- "sha1": "4d60710a1944bc624612125922f662e2f4c83210",
122
- "md5": "58fc9b743a27b172f762029627edce8b"
116
+ "name": "expo.modules.video-4.0.0-canary-20260113-0ce2b9c.aar",
117
+ "url": "expo.modules.video-4.0.0-canary-20260113-0ce2b9c.aar",
118
+ "size": 542363,
119
+ "sha512": "165542915e8f2c66531e661d5b3d7583d444a4306dcb85879807b36180a80356f6b03d653b0eda757a67111fd9516f4097e12284f75e48961659505fff86f19a",
120
+ "sha256": "c6f7e9432a12e920c31dd07657bc4cc69883abbdeaa19c7805036f6b582c5a82",
121
+ "sha1": "c950508730cf76a8c77f81fff15cd7a733d3604f",
122
+ "md5": "ac7e27d1ea99e01e1eaff1a3899cab1d"
123
123
  }
124
124
  ]
125
125
  },
@@ -133,13 +133,13 @@
133
133
  },
134
134
  "files": [
135
135
  {
136
- "name": "expo.modules.video-3.1.0-canary-20260105-6b962e6-sources.jar",
137
- "url": "expo.modules.video-3.1.0-canary-20260105-6b962e6-sources.jar",
138
- "size": 71260,
139
- "sha512": "14794ea0abb4143ed97ce267818f74e91ba3d34c0847532e4fe783703392382fdc2c4087c2b4031c9be065bfdb58dce679ed00cea46d2e35a2051fc5b86d33e0",
140
- "sha256": "d9e5f2bd9bc14f5efa6e69cd1b42d2cd8ca648ee3a531ccf1759ed7e35dbd690",
141
- "sha1": "5a918f84af8ffe923a0002d90139e5a25c109a8f",
142
- "md5": "eb0f69a6e6f23e094da3ba4d1c01a5d7"
136
+ "name": "expo.modules.video-4.0.0-canary-20260113-0ce2b9c-sources.jar",
137
+ "url": "expo.modules.video-4.0.0-canary-20260113-0ce2b9c-sources.jar",
138
+ "size": 71261,
139
+ "sha512": "7ad828f8048d4de909217816ffb7de7d0f9af167e394e907303ab7bb268594646e8496caf7d02d7a00c09430b9778bffa756909099048f7326e4d2ab02b9baa2",
140
+ "sha256": "f7798fa9932249902cd7ac8ca950d9a12e80a5876a66a56aaf9b946910829267",
141
+ "sha1": "7f4065dc48d6583efd7f9023bc4dc9d411c59734",
142
+ "md5": "6b1d68e0bd503c5b5eecfa7cd3129f64"
143
143
  }
144
144
  ]
145
145
  }
@@ -0,0 +1 @@
1
+ 6297fb581d42314029c9c5b41c2c0c7884e6983902ab50b16be8139c2c40c9294794805484acc230949588371a0b14463c1d5613c70cca27ca9efb164b5a2939
@@ -9,7 +9,7 @@
9
9
  <modelVersion>4.0.0</modelVersion>
10
10
  <groupId>host.exp.exponent</groupId>
11
11
  <artifactId>expo.modules.video</artifactId>
12
- <version>3.1.0-canary-20260105-6b962e6</version>
12
+ <version>4.0.0-canary-20260113-0ce2b9c</version>
13
13
  <packaging>aar</packaging>
14
14
  <name>expo.modules.video</name>
15
15
  <url>https://github.com/expo/expo</url>
@@ -0,0 +1 @@
1
+ 655f248e2b404bc8d6451e51b9d844b208561d156dd90293c6b6a6f21a6065b20365414195999cd503ec4f78b03ad27476d87e8836f1a98c9a1845f40ba9d42b
@@ -3,11 +3,11 @@
3
3
  <groupId>host.exp.exponent</groupId>
4
4
  <artifactId>expo.modules.video</artifactId>
5
5
  <versioning>
6
- <latest>3.1.0-canary-20260105-6b962e6</latest>
7
- <release>3.1.0-canary-20260105-6b962e6</release>
6
+ <latest>4.0.0-canary-20260113-0ce2b9c</latest>
7
+ <release>4.0.0-canary-20260113-0ce2b9c</release>
8
8
  <versions>
9
- <version>3.1.0-canary-20260105-6b962e6</version>
9
+ <version>4.0.0-canary-20260113-0ce2b9c</version>
10
10
  </versions>
11
- <lastUpdated>20260105102035</lastUpdated>
11
+ <lastUpdated>20260113181529</lastUpdated>
12
12
  </versioning>
13
13
  </metadata>
@@ -1 +1 @@
1
- eba382e0e536fb1e608ccddc7ece220d
1
+ 1cf18b18667426a4f671868d6957d9bd
@@ -1 +1 @@
1
- ed7c099790be90a148226b34ca64872f0c7792be
1
+ e63141a7eb621b5eed20e42dafb52abbe184a6a1
@@ -1 +1 @@
1
- 0a720492a0bfc0398d8c9fd4f0c5029a9131ab726c3aa3bbba88861235bd0b41
1
+ 150d1a834667a0cd64df8b44a73f2223157f63b73eb41feb34f2371b3cc165b4
@@ -1 +1 @@
1
- 1f3c5df4e6090a5ccb08be4f0ed80ce9ea4b40bf45bca23473e176188395ec3daaabf2ef385438f539084000f2ba34d90c09d94916ec3090ec33147b1fceb928
1
+ 1e92d0fe07188456e255a68fee2878bd56046d41cfd345c82d0765a8208ead0e20a817c060090f682d1d917cb4f853b465bf1431258d94fa47d5dac9aff33743
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "expo-video",
3
3
  "title": "Expo Video",
4
- "version": "3.1.0-canary-20260105-6b962e6",
4
+ "version": "4.0.0-canary-20260113-0ce2b9c",
5
5
  "description": "A cross-platform, performant video component for React Native and Expo with Web support",
6
6
  "main": "build/index.js",
7
7
  "types": "build/index.d.ts",
@@ -31,10 +31,10 @@
31
31
  "license": "MIT",
32
32
  "dependencies": {},
33
33
  "devDependencies": {
34
- "expo-module-scripts": "5.1.0-canary-20260105-6b962e6"
34
+ "expo-module-scripts": "5.1.0-canary-20260113-0ce2b9c"
35
35
  },
36
36
  "peerDependencies": {
37
- "expo": "55.0.0-canary-20260105-6b962e6",
37
+ "expo": "55.0.0-canary-20260113-0ce2b9c",
38
38
  "react": "*",
39
39
  "react-native": "*"
40
40
  }
package/src/VideoView.tsx CHANGED
@@ -67,12 +67,6 @@ export class VideoView extends PureComponent<VideoViewProps> {
67
67
  const { player, ...props } = this.props;
68
68
  const playerId = player ? getPlayerId(player) : null;
69
69
 
70
- if (props.allowsFullscreen !== undefined) {
71
- console.warn(
72
- 'The `allowsFullscreen` prop is deprecated and will be removed in a future release. Use `fullscreenOptions` prop instead.'
73
- );
74
- }
75
-
76
70
  if (NativeTextureVideoView && this.props.surfaceType === 'textureView') {
77
71
  return <NativeTextureVideoView {...props} player={playerId} ref={this.nativeRef} />;
78
72
  }
@@ -41,14 +41,6 @@ export interface VideoViewProps extends ViewProps {
41
41
  */
42
42
  contentFit?: VideoContentFit;
43
43
 
44
- /**
45
- * Determines whether fullscreen mode is allowed or not.
46
- *
47
- * > Note: This option has been deprecated in favor of the `fullscreenOptions` prop and will be disabled in the future.
48
- * @default true
49
- */
50
- allowsFullscreen?: boolean;
51
-
52
44
  /**
53
45
  * Determines the fullscreen mode options.
54
46
  */
@@ -213,7 +205,6 @@ export type FullscreenOrientation =
213
205
  export type FullscreenOptions = {
214
206
  /**
215
207
  * Specifies whether the fullscreen mode should be available to the user. When `false`, the fullscreen button will be hidden in the player.
216
- * Equivalent to the `allowsFullscreen` prop.
217
208
  * @default true
218
209
  */
219
210
  enable: boolean;
@@ -63,9 +63,6 @@ export const VideoView = forwardRef((props: { player?: VideoPlayer } & VideoView
63
63
 
64
64
  useImperativeHandle(ref, () => ({
65
65
  enterFullscreen: async () => {
66
- if (!props.allowsFullscreen || !videoRef.current) {
67
- return;
68
- }
69
66
  // Cast the video to any to avoid ts errors. Methods such as webkitRequestFullscreen,
70
67
  // webkitEnterFullScreen, msRequestFullscreen are not typed even though they exist.
71
68
  const video = videoRef.current as any;
@@ -263,7 +260,7 @@ export const VideoView = forwardRef((props: { player?: VideoPlayer } & VideoView
263
260
  return (
264
261
  <video
265
262
  controls={props.nativeControls ?? true}
266
- controlsList={props.allowsFullscreen ? undefined : 'nofullscreen'}
263
+ controlsList={props.fullscreenOptions?.enable ? undefined : 'nofullscreen'}
267
264
  crossOrigin={props.crossOrigin}
268
265
  style={{
269
266
  ...mapStyles(props.style),
@@ -1 +0,0 @@
1
- 14794ea0abb4143ed97ce267818f74e91ba3d34c0847532e4fe783703392382fdc2c4087c2b4031c9be065bfdb58dce679ed00cea46d2e35a2051fc5b86d33e0
@@ -1 +0,0 @@
1
- 3b7933241b900baa96a245a26ea32935672d50e6a6423e9e58ab28401d272783a646d561caf3f5adb111ba38270942b546a6d1daafbc5af448348796425e831d
@@ -1 +0,0 @@
1
- f6700aa7389222db7a83fcfd43dea488b01bd4ad9b3cc76f5c381de3de49d97d73dc0da173654dad358a46bd95dfcd70e62f58813d2fd72bc48d6e1108c9b80c
@@ -1 +0,0 @@
1
- 408cd7fc4a2b474da1b4c1d466faf4b15def890a33204c5029e29dff738cbac123feba8dfeb1bd2a8c6b44f8b71872fb7575fd70e60b27874abea718c6cf32eb