this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

[Video] Use `expo-video` from fork (#5159)

authored by

Hailey and committed by
GitHub
93c171b4 6d8ed5c3

+7 -652
+1 -1
app.config.js
··· 191 191 'expo-build-properties', 192 192 { 193 193 ios: { 194 - deploymentTarget: '14.0', 194 + deploymentTarget: '15.1', 195 195 newArchEnabled: false, 196 196 }, 197 197 android: {
+1 -1
package.json
··· 139 139 "expo-system-ui": "~3.0.4", 140 140 "expo-task-manager": "~11.8.1", 141 141 "expo-updates": "~0.25.14", 142 - "expo-video": "^1.2.4", 142 + "expo-video": "https://github.com/bluesky-social/expo/raw/main/packages/expo-video/expo-video-v1.2.4.tgz", 143 143 "expo-web-browser": "~13.0.3", 144 144 "fast-text-encoding": "^1.0.6", 145 145 "history": "^5.3.0",
-608
patches/expo-video+1.2.4.patch
··· 1 - diff --git a/node_modules/expo-video/android/src/main/java/expo/modules/video/PlayerEvent.kt b/node_modules/expo-video/android/src/main/java/expo/modules/video/PlayerEvent.kt 2 - index 473f964..f37aff9 100644 3 - --- a/node_modules/expo-video/android/src/main/java/expo/modules/video/PlayerEvent.kt 4 - +++ b/node_modules/expo-video/android/src/main/java/expo/modules/video/PlayerEvent.kt 5 - @@ -41,6 +41,11 @@ sealed class PlayerEvent { 6 - override val name = "playToEnd" 7 - } 8 - 9 - + data class PlayerTimeRemainingChanged(val timeRemaining: Double): PlayerEvent() { 10 - + override val name = "timeRemainingChange" 11 - + override val arguments = arrayOf(timeRemaining) 12 - + } 13 - + 14 - fun emit(player: VideoPlayer, listeners: List<VideoPlayerListener>) { 15 - when (this) { 16 - is StatusChanged -> listeners.forEach { it.onStatusChanged(player, status, oldStatus, error) } 17 - @@ -49,6 +54,7 @@ sealed class PlayerEvent { 18 - is SourceChanged -> listeners.forEach { it.onSourceChanged(player, source, oldSource) } 19 - is PlaybackRateChanged -> listeners.forEach { it.onPlaybackRateChanged(player, rate, oldRate) } 20 - is PlayedToEnd -> listeners.forEach { it.onPlayedToEnd(player) } 21 - + is PlayerTimeRemainingChanged -> listeners.forEach { it.onPlayerTimeRemainingChanged(player, timeRemaining) } 22 - } 23 - } 24 - } 25 - diff --git a/node_modules/expo-video/android/src/main/java/expo/modules/video/PlayerViewExtension.kt b/node_modules/expo-video/android/src/main/java/expo/modules/video/PlayerViewExtension.kt 26 - index 9905e13..47342ff 100644 27 - --- a/node_modules/expo-video/android/src/main/java/expo/modules/video/PlayerViewExtension.kt 28 - +++ b/node_modules/expo-video/android/src/main/java/expo/modules/video/PlayerViewExtension.kt 29 - @@ -11,6 +11,7 @@ internal fun PlayerView.applyRequiresLinearPlayback(requireLinearPlayback: Boole 30 - setShowPreviousButton(!requireLinearPlayback) 31 - setShowNextButton(!requireLinearPlayback) 32 - setTimeBarInteractive(requireLinearPlayback) 33 - + setShowSubtitleButton(true) 34 - } 35 - 36 - @androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class) 37 - @@ -27,7 +28,8 @@ internal fun PlayerView.setTimeBarInteractive(interactive: Boolean) { 38 - 39 - @androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class) 40 - internal fun PlayerView.setFullscreenButtonVisibility(visible: Boolean) { 41 - - val fullscreenButton = findViewById<android.widget.ImageButton>(androidx.media3.ui.R.id.exo_fullscreen) 42 - + val fullscreenButton = 43 - + findViewById<android.widget.ImageButton>(androidx.media3.ui.R.id.exo_fullscreen) 44 - fullscreenButton?.visibility = if (visible) { 45 - android.view.View.VISIBLE 46 - } else { 47 - diff --git a/node_modules/expo-video/android/src/main/java/expo/modules/video/ProgressTracker.kt b/node_modules/expo-video/android/src/main/java/expo/modules/video/ProgressTracker.kt 48 - new file mode 100644 49 - index 0000000..0249e23 50 - --- /dev/null 51 - +++ b/node_modules/expo-video/android/src/main/java/expo/modules/video/ProgressTracker.kt 52 - @@ -0,0 +1,29 @@ 53 - +import android.os.Handler 54 - +import android.os.Looper 55 - +import androidx.annotation.OptIn 56 - +import androidx.media3.common.util.UnstableApi 57 - +import expo.modules.video.PlayerEvent 58 - +import expo.modules.video.VideoPlayer 59 - +import kotlin.math.floor 60 - + 61 - +@OptIn(UnstableApi::class) 62 - +class ProgressTracker(private val videoPlayer: VideoPlayer) : Runnable { 63 - + private val handler: Handler = Handler(Looper.getMainLooper()) 64 - + private val player = videoPlayer.player 65 - + 66 - + init { 67 - + handler.post(this) 68 - + } 69 - + 70 - + override fun run() { 71 - + val currentPosition = player.currentPosition 72 - + val duration = player.duration 73 - + val timeRemaining = floor(((duration - currentPosition) / 1000).toDouble()) 74 - + videoPlayer.sendEvent(PlayerEvent.PlayerTimeRemainingChanged(timeRemaining)) 75 - + handler.postDelayed(this, 1000 /* ms */) 76 - + } 77 - + 78 - + fun remove() { 79 - + handler.removeCallbacks(this) 80 - + } 81 - +} 82 - \ No newline at end of file 83 - diff --git a/node_modules/expo-video/android/src/main/java/expo/modules/video/VideoManager.kt b/node_modules/expo-video/android/src/main/java/expo/modules/video/VideoManager.kt 84 - index 4b6c6d8..e20f51a 100644 85 - --- a/node_modules/expo-video/android/src/main/java/expo/modules/video/VideoManager.kt 86 - +++ b/node_modules/expo-video/android/src/main/java/expo/modules/video/VideoManager.kt 87 - @@ -1,5 +1,6 @@ 88 - package expo.modules.video 89 - 90 - +import android.provider.MediaStore.Video 91 - import androidx.annotation.OptIn 92 - import androidx.media3.common.util.UnstableApi 93 - import expo.modules.kotlin.AppContext 94 - @@ -15,6 +16,8 @@ object VideoManager { 95 - // Keeps track of all existing VideoPlayers, and whether they are attached to a VideoView 96 - private var videoPlayersToVideoViews = mutableMapOf<VideoPlayer, MutableList<VideoView>>() 97 - 98 - + private var previouslyPlayingViews: MutableList<VideoView>? = null 99 - + 100 - private lateinit var audioFocusManager: AudioFocusManager 101 - 102 - fun onModuleCreated(appContext: AppContext) { 103 - @@ -69,16 +72,24 @@ object VideoManager { 104 - return videoPlayersToVideoViews[videoPlayer]?.isNotEmpty() ?: false 105 - } 106 - 107 - - fun onAppForegrounded() = Unit 108 - + fun onAppForegrounded() { 109 - + val previouslyPlayingViews = this.previouslyPlayingViews ?: return 110 - + for (videoView in previouslyPlayingViews) { 111 - + val player = videoView.videoPlayer?.player ?: continue 112 - + player.play() 113 - + } 114 - + this.previouslyPlayingViews = null 115 - + } 116 - 117 - fun onAppBackgrounded() { 118 - + val previouslyPlayingViews = mutableListOf<VideoView>() 119 - for (videoView in videoViews.values) { 120 - - if (videoView.videoPlayer?.staysActiveInBackground == false && 121 - - !videoView.willEnterPiP && 122 - - !videoView.isInFullscreen 123 - - ) { 124 - - videoView.videoPlayer?.player?.pause() 125 - + val player = videoView.videoPlayer?.player ?: continue 126 - + if (player.isPlaying) { 127 - + player.pause() 128 - + previouslyPlayingViews.add(videoView) 129 - } 130 - } 131 - + this.previouslyPlayingViews = previouslyPlayingViews 132 - } 133 - } 134 - diff --git a/node_modules/expo-video/android/src/main/java/expo/modules/video/VideoModule.kt b/node_modules/expo-video/android/src/main/java/expo/modules/video/VideoModule.kt 135 - index ec3da2a..5a1397a 100644 136 - --- a/node_modules/expo-video/android/src/main/java/expo/modules/video/VideoModule.kt 137 - +++ b/node_modules/expo-video/android/src/main/java/expo/modules/video/VideoModule.kt 138 - @@ -43,7 +43,9 @@ class VideoModule : Module() { 139 - View(VideoView::class) { 140 - Events( 141 - "onPictureInPictureStart", 142 - - "onPictureInPictureStop" 143 - + "onPictureInPictureStop", 144 - + "onEnterFullscreen", 145 - + "onExitFullscreen" 146 - ) 147 - 148 - Prop("player") { view: VideoView, player: VideoPlayer -> 149 - diff --git a/node_modules/expo-video/android/src/main/java/expo/modules/video/VideoPlayer.kt b/node_modules/expo-video/android/src/main/java/expo/modules/video/VideoPlayer.kt 150 - index 58f00af..5ad8237 100644 151 - --- a/node_modules/expo-video/android/src/main/java/expo/modules/video/VideoPlayer.kt 152 - +++ b/node_modules/expo-video/android/src/main/java/expo/modules/video/VideoPlayer.kt 153 - @@ -1,5 +1,6 @@ 154 - package expo.modules.video 155 - 156 - +import ProgressTracker 157 - import android.content.Context 158 - import android.view.SurfaceView 159 - import androidx.media3.common.MediaItem 160 - @@ -35,11 +36,13 @@ class VideoPlayer(val context: Context, appContext: AppContext, source: VideoSou 161 - .Builder(context, renderersFactory) 162 - .setLooper(context.mainLooper) 163 - .build() 164 - + var progressTracker: ProgressTracker? = null 165 - 166 - val serviceConnection = PlaybackServiceConnection(WeakReference(player)) 167 - 168 - var playing by IgnoreSameSet(false) { new, old -> 169 - sendEvent(PlayerEvent.IsPlayingChanged(new, old)) 170 - + addOrRemoveProgressTracker() 171 - } 172 - 173 - var uncommittedSource: VideoSource? = source 174 - @@ -141,6 +144,9 @@ class VideoPlayer(val context: Context, appContext: AppContext, source: VideoSou 175 - } 176 - 177 - override fun close() { 178 - + this.progressTracker?.remove() 179 - + this.progressTracker = null 180 - + 181 - appContext?.reactContext?.unbindService(serviceConnection) 182 - serviceConnection.playbackServiceBinder?.service?.unregisterPlayer(player) 183 - VideoManager.unregisterVideoPlayer(this@VideoPlayer) 184 - @@ -228,7 +234,7 @@ class VideoPlayer(val context: Context, appContext: AppContext, source: VideoSou 185 - listeners.removeAll { it.get() == videoPlayerListener } 186 - } 187 - 188 - - private fun sendEvent(event: PlayerEvent) { 189 - + fun sendEvent(event: PlayerEvent) { 190 - // Emits to the native listeners 191 - event.emit(this, listeners.mapNotNull { it.get() }) 192 - // Emits to the JS side 193 - @@ -240,4 +246,13 @@ class VideoPlayer(val context: Context, appContext: AppContext, source: VideoSou 194 - sendEvent(eventName, *args) 195 - } 196 - } 197 - + 198 - + private fun addOrRemoveProgressTracker() { 199 - + this.progressTracker?.remove() 200 - + if (this.playing) { 201 - + this.progressTracker = ProgressTracker(this) 202 - + } else { 203 - + this.progressTracker = null 204 - + } 205 - + } 206 - } 207 - diff --git a/node_modules/expo-video/android/src/main/java/expo/modules/video/VideoPlayerListener.kt b/node_modules/expo-video/android/src/main/java/expo/modules/video/VideoPlayerListener.kt 208 - index f654254..dcfe3f0 100644 209 - --- a/node_modules/expo-video/android/src/main/java/expo/modules/video/VideoPlayerListener.kt 210 - +++ b/node_modules/expo-video/android/src/main/java/expo/modules/video/VideoPlayerListener.kt 211 - @@ -15,4 +15,5 @@ interface VideoPlayerListener { 212 - fun onSourceChanged(player: VideoPlayer, source: VideoSource?, oldSource: VideoSource?) {} 213 - fun onPlaybackRateChanged(player: VideoPlayer, rate: Float, oldRate: Float?) {} 214 - fun onPlayedToEnd(player: VideoPlayer) {} 215 - + fun onPlayerTimeRemainingChanged(player: VideoPlayer, timeRemaining: Double) {} 216 - } 217 - diff --git a/node_modules/expo-video/android/src/main/java/expo/modules/video/VideoView.kt b/node_modules/expo-video/android/src/main/java/expo/modules/video/VideoView.kt 218 - index a951d80..3932535 100644 219 - --- a/node_modules/expo-video/android/src/main/java/expo/modules/video/VideoView.kt 220 - +++ b/node_modules/expo-video/android/src/main/java/expo/modules/video/VideoView.kt 221 - @@ -36,6 +36,8 @@ class VideoView(context: Context, appContext: AppContext) : ExpoView(context, ap 222 - val playerView: PlayerView = PlayerView(context.applicationContext) 223 - val onPictureInPictureStart by EventDispatcher<Unit>() 224 - val onPictureInPictureStop by EventDispatcher<Unit>() 225 - + val onEnterFullscreen by EventDispatcher() 226 - + val onExitFullscreen by EventDispatcher() 227 - 228 - var willEnterPiP: Boolean = false 229 - var isInFullscreen: Boolean = false 230 - @@ -154,6 +156,7 @@ class VideoView(context: Context, appContext: AppContext) : ExpoView(context, ap 231 - @Suppress("DEPRECATION") 232 - currentActivity.overridePendingTransition(0, 0) 233 - } 234 - + onEnterFullscreen(mapOf()) 235 - isInFullscreen = true 236 - } 237 - 238 - @@ -162,6 +165,7 @@ class VideoView(context: Context, appContext: AppContext) : ExpoView(context, ap 239 - val fullScreenButton: ImageButton = playerView.findViewById(androidx.media3.ui.R.id.exo_fullscreen) 240 - fullScreenButton.setImageResource(androidx.media3.ui.R.drawable.exo_icon_fullscreen_enter) 241 - videoPlayer?.changePlayerView(playerView) 242 - + this.onExitFullscreen(mapOf()) 243 - isInFullscreen = false 244 - } 245 - 246 - diff --git a/node_modules/expo-video/build/VideoPlayer.types.d.ts b/node_modules/expo-video/build/VideoPlayer.types.d.ts 247 - index a09fcfe..46cbae7 100644 248 - --- a/node_modules/expo-video/build/VideoPlayer.types.d.ts 249 - +++ b/node_modules/expo-video/build/VideoPlayer.types.d.ts 250 - @@ -128,6 +128,8 @@ export type VideoPlayerEvents = { 251 - * Handler for an event emitted when the current media source of the player changes. 252 - */ 253 - sourceChange(newSource: VideoSource, previousSource: VideoSource): void; 254 - + 255 - + timeRemainingChange(timeRemaining: number): void; 256 - }; 257 - /** 258 - * Describes the current status of the player. 259 - @@ -136,7 +138,7 @@ export type VideoPlayerEvents = { 260 - * - `readyToPlay`: The player has loaded enough data to start playing or to continue playback. 261 - * - `error`: The player has encountered an error while loading or playing the video. 262 - */ 263 - -export type VideoPlayerStatus = 'idle' | 'loading' | 'readyToPlay' | 'error'; 264 - +export type VideoPlayerStatus = 'idle' | 'loading' | 'readyToPlay' | 'error' | 'waitingToPlayAtSpecifiedRate'; 265 - export type VideoSource = string | { 266 - /** 267 - * The URI of the video. 268 - diff --git a/node_modules/expo-video/build/VideoView.types.d.ts b/node_modules/expo-video/build/VideoView.types.d.ts 269 - index cb9ca6d..ed8bb7e 100644 270 - --- a/node_modules/expo-video/build/VideoView.types.d.ts 271 - +++ b/node_modules/expo-video/build/VideoView.types.d.ts 272 - @@ -89,5 +89,8 @@ export interface VideoViewProps extends ViewProps { 273 - * @platform ios 16.0+ 274 - */ 275 - allowsVideoFrameAnalysis?: boolean; 276 - + 277 - + onEnterFullscreen?: () => void; 278 - + onExitFullscreen?: () => void; 279 - } 280 - //# sourceMappingURL=VideoView.types.d.ts.map 281 - \ No newline at end of file 282 - diff --git a/node_modules/expo-video/ios/Enums/PlayerStatus.swift b/node_modules/expo-video/ios/Enums/PlayerStatus.swift 283 - index 6af69ca..189fbbe 100644 284 - --- a/node_modules/expo-video/ios/Enums/PlayerStatus.swift 285 - +++ b/node_modules/expo-video/ios/Enums/PlayerStatus.swift 286 - @@ -6,5 +6,8 @@ internal enum PlayerStatus: String, Enumerable { 287 - case idle 288 - case loading 289 - case readyToPlay 290 - + case waitingToPlayAtSpecifiedRate 291 - + case unlikeToKeepUp 292 - + case playbackBufferEmpty 293 - case error 294 - } 295 - diff --git a/node_modules/expo-video/ios/VideoManager.swift b/node_modules/expo-video/ios/VideoManager.swift 296 - index 094a8b0..16e7081 100644 297 - --- a/node_modules/expo-video/ios/VideoManager.swift 298 - +++ b/node_modules/expo-video/ios/VideoManager.swift 299 - @@ -12,6 +12,7 @@ class VideoManager { 300 - 301 - private var videoViews = NSHashTable<VideoView>.weakObjects() 302 - private var videoPlayers = NSHashTable<VideoPlayer>.weakObjects() 303 - + private var previouslyPlayingPlayers: [VideoPlayer]? 304 - 305 - func register(videoPlayer: VideoPlayer) { 306 - videoPlayers.add(videoPlayer) 307 - @@ -33,63 +34,70 @@ class VideoManager { 308 - for videoPlayer in videoPlayers.allObjects { 309 - videoPlayer.setTracksEnabled(true) 310 - } 311 - + 312 - + if let previouslyPlayingPlayers = self.previouslyPlayingPlayers { 313 - + previouslyPlayingPlayers.forEach { player in 314 - + player.pointer.play() 315 - + } 316 - + } 317 - } 318 - 319 - func onAppBackgrounded() { 320 - + var previouslyPlayingPlayers: [VideoPlayer] = [] 321 - for videoView in videoViews.allObjects { 322 - guard let player = videoView.player else { 323 - continue 324 - } 325 - - if player.staysActiveInBackground == true { 326 - - player.setTracksEnabled(videoView.isInPictureInPicture) 327 - - } else if !videoView.isInPictureInPicture { 328 - + if player.isPlaying { 329 - player.pointer.pause() 330 - + previouslyPlayingPlayers.append(player) 331 - } 332 - } 333 - + self.previouslyPlayingPlayers = previouslyPlayingPlayers 334 - } 335 - 336 - // MARK: - Audio Session Management 337 - 338 - internal func setAppropriateAudioSessionOrWarn() { 339 - - let audioSession = AVAudioSession.sharedInstance() 340 - - var audioSessionCategoryOptions: AVAudioSession.CategoryOptions = [] 341 - - 342 - - let isAnyPlayerPlaying = videoPlayers.allObjects.contains { player in 343 - - player.isPlaying 344 - - } 345 - - let areAllPlayersMuted = videoPlayers.allObjects.allSatisfy { player in 346 - - player.isMuted 347 - - } 348 - - let needsPiPSupport = videoViews.allObjects.contains { view in 349 - - view.allowPictureInPicture 350 - - } 351 - - let anyPlayerShowsNotification = videoPlayers.allObjects.contains { player in 352 - - player.showNowPlayingNotification 353 - - } 354 - - // The notification won't be shown if we allow the audio to mix with others 355 - - let shouldAllowMixing = (!isAnyPlayerPlaying || areAllPlayersMuted) && !anyPlayerShowsNotification 356 - - let isOutputtingAudio = !areAllPlayersMuted && isAnyPlayerPlaying 357 - - let shouldUpdateToAllowMixing = !audioSession.categoryOptions.contains(.mixWithOthers) && shouldAllowMixing 358 - - 359 - - if shouldAllowMixing { 360 - - audioSessionCategoryOptions.insert(.mixWithOthers) 361 - - } 362 - - 363 - - if isOutputtingAudio || needsPiPSupport || shouldUpdateToAllowMixing || anyPlayerShowsNotification { 364 - - do { 365 - - try audioSession.setCategory(.playback, mode: .moviePlayback) 366 - - } catch { 367 - - log.warn("Failed to set audio session category. This might cause issues with audio playback and Picture in Picture. \(error.localizedDescription)") 368 - - } 369 - - } 370 - - 371 - - // Make sure audio session is active if any video is playing 372 - - if isAnyPlayerPlaying { 373 - - do { 374 - - try audioSession.setActive(true) 375 - - } catch { 376 - - log.warn("Failed to activate the audio session. This might cause issues with audio playback. \(error.localizedDescription)") 377 - - } 378 - - } 379 - +// let audioSession = AVAudioSession.sharedInstance() 380 - +// var audioSessionCategoryOptions: AVAudioSession.CategoryOptions = [] 381 - +// 382 - +// let isAnyPlayerPlaying = videoPlayers.allObjects.contains { player in 383 - +// player.isPlaying 384 - +// } 385 - +// let areAllPlayersMuted = videoPlayers.allObjects.allSatisfy { player in 386 - +// player.isMuted 387 - +// } 388 - +// let needsPiPSupport = videoViews.allObjects.contains { view in 389 - +// view.allowPictureInPicture 390 - +// } 391 - +// let anyPlayerShowsNotification = videoPlayers.allObjects.contains { player in 392 - +// player.showNowPlayingNotification 393 - +// } 394 - +// // The notification won't be shown if we allow the audio to mix with others 395 - +// let shouldAllowMixing = (!isAnyPlayerPlaying || areAllPlayersMuted) && !anyPlayerShowsNotification 396 - +// let isOutputtingAudio = !areAllPlayersMuted && isAnyPlayerPlaying 397 - +// let shouldUpdateToAllowMixing = !audioSession.categoryOptions.contains(.mixWithOthers) && shouldAllowMixing 398 - +// 399 - +// if shouldAllowMixing { 400 - +// audioSessionCategoryOptions.insert(.mixWithOthers) 401 - +// } 402 - +// 403 - +// if isOutputtingAudio || needsPiPSupport || shouldUpdateToAllowMixing || anyPlayerShowsNotification { 404 - +// do { 405 - +// try audioSession.setCategory(.playback, mode: .moviePlayback) 406 - +// } catch { 407 - +// log.warn("Failed to set audio session category. This might cause issues with audio playback and Picture in Picture. \(error.localizedDescription)") 408 - +// } 409 - +// } 410 - +// 411 - +// // Make sure audio session is active if any video is playing 412 - +// if isAnyPlayerPlaying { 413 - +// do { 414 - +// try audioSession.setActive(true) 415 - +// } catch { 416 - +// log.warn("Failed to activate the audio session. This might cause issues with audio playback. \(error.localizedDescription)") 417 - +// } 418 - +// } 419 - } 420 - } 421 - diff --git a/node_modules/expo-video/ios/VideoModule.swift b/node_modules/expo-video/ios/VideoModule.swift 422 - index c537a12..e4a918f 100644 423 - --- a/node_modules/expo-video/ios/VideoModule.swift 424 - +++ b/node_modules/expo-video/ios/VideoModule.swift 425 - @@ -16,7 +16,9 @@ public final class VideoModule: Module { 426 - View(VideoView.self) { 427 - Events( 428 - "onPictureInPictureStart", 429 - - "onPictureInPictureStop" 430 - + "onPictureInPictureStop", 431 - + "onEnterFullscreen", 432 - + "onExitFullscreen" 433 - ) 434 - 435 - Prop("player") { (view, player: VideoPlayer?) in 436 - diff --git a/node_modules/expo-video/ios/VideoPlayer.swift b/node_modules/expo-video/ios/VideoPlayer.swift 437 - index 3315b88..733ab1f 100644 438 - --- a/node_modules/expo-video/ios/VideoPlayer.swift 439 - +++ b/node_modules/expo-video/ios/VideoPlayer.swift 440 - @@ -185,6 +185,10 @@ internal final class VideoPlayer: SharedRef<AVPlayer>, Hashable, VideoPlayerObse 441 - safeEmit(event: "sourceChange", arguments: newVideoPlayerItem?.videoSource, oldVideoPlayerItem?.videoSource) 442 - } 443 - 444 - + func onPlayerTimeRemainingChanged(player: AVPlayer, timeRemaining: Double) { 445 - + safeEmit(event: "timeRemainingChange", arguments: timeRemaining) 446 - + } 447 - + 448 - func safeEmit<each A: AnyArgument>(event: String, arguments: repeat each A) { 449 - if self.appContext != nil { 450 - self.emit(event: event, arguments: repeat each arguments) 451 - diff --git a/node_modules/expo-video/ios/VideoPlayerObserver.swift b/node_modules/expo-video/ios/VideoPlayerObserver.swift 452 - index d289e26..7de8cbf 100644 453 - --- a/node_modules/expo-video/ios/VideoPlayerObserver.swift 454 - +++ b/node_modules/expo-video/ios/VideoPlayerObserver.swift 455 - @@ -21,6 +21,7 @@ protocol VideoPlayerObserverDelegate: AnyObject { 456 - func onItemChanged(player: AVPlayer, oldVideoPlayerItem: VideoPlayerItem?, newVideoPlayerItem: VideoPlayerItem?) 457 - func onIsMutedChanged(player: AVPlayer, oldIsMuted: Bool?, newIsMuted: Bool) 458 - func onPlayerItemStatusChanged(player: AVPlayer, oldStatus: AVPlayerItem.Status?, newStatus: AVPlayerItem.Status) 459 - + func onPlayerTimeRemainingChanged(player: AVPlayer, timeRemaining: Double) 460 - } 461 - 462 - // Default implementations for the delegate 463 - @@ -33,6 +34,7 @@ extension VideoPlayerObserverDelegate { 464 - func onItemChanged(player: AVPlayer, oldVideoPlayerItem: VideoPlayerItem?, newVideoPlayerItem: VideoPlayerItem?) {} 465 - func onIsMutedChanged(player: AVPlayer, oldIsMuted: Bool?, newIsMuted: Bool) {} 466 - func onPlayerItemStatusChanged(player: AVPlayer, oldStatus: AVPlayerItem.Status?, newStatus: AVPlayerItem.Status) {} 467 - + func onPlayerTimeRemainingChanged(player: AVPlayer, timeRemaining: Double) {} 468 - } 469 - 470 - // Wrapper used to store WeakReferences to the observer delegate 471 - @@ -91,6 +93,7 @@ class VideoPlayerObserver { 472 - private var playerVolumeObserver: NSKeyValueObservation? 473 - private var playerCurrentItemObserver: NSKeyValueObservation? 474 - private var playerIsMutedObserver: NSKeyValueObservation? 475 - + private var playerPeriodicTimeObserver: Any? 476 - 477 - // Current player item observers 478 - private var playbackBufferEmptyObserver: NSKeyValueObservation? 479 - @@ -152,6 +155,9 @@ class VideoPlayerObserver { 480 - playerVolumeObserver?.invalidate() 481 - playerIsMutedObserver?.invalidate() 482 - playerCurrentItemObserver?.invalidate() 483 - + if let playerPeriodicTimeObserver = self.playerPeriodicTimeObserver { 484 - + player?.removeTimeObserver(playerPeriodicTimeObserver) 485 - + } 486 - } 487 - 488 - private func initializeCurrentPlayerItemObservers(player: AVPlayer, playerItem: AVPlayerItem) { 489 - @@ -265,23 +271,24 @@ class VideoPlayerObserver { 490 - if player.timeControlStatus != .waitingToPlayAtSpecifiedRate && player.status == .readyToPlay && currentItem?.isPlaybackBufferEmpty != true { 491 - status = .readyToPlay 492 - } else if player.timeControlStatus == .waitingToPlayAtSpecifiedRate { 493 - - status = .loading 494 - + status = .waitingToPlayAtSpecifiedRate 495 - } 496 - 497 - if isPlaying != (player.timeControlStatus == .playing) { 498 - isPlaying = player.timeControlStatus == .playing 499 - + addPeriodicTimeObserverIfNeeded() 500 - } 501 - } 502 - 503 - private func onIsBufferEmptyChanged(_ playerItem: AVPlayerItem, _ change: NSKeyValueObservedChange<Bool>) { 504 - if playerItem.isPlaybackBufferEmpty { 505 - - status = .loading 506 - + status = .playbackBufferEmpty 507 - } 508 - } 509 - 510 - private func onPlayerLikelyToKeepUpChanged(_ playerItem: AVPlayerItem, _ change: NSKeyValueObservedChange<Bool>) { 511 - if !playerItem.isPlaybackLikelyToKeepUp && playerItem.isPlaybackBufferEmpty { 512 - - status = .loading 513 - + status = .unlikeToKeepUp 514 - } else if playerItem.isPlaybackLikelyToKeepUp { 515 - status = .readyToPlay 516 - } 517 - @@ -310,4 +317,28 @@ class VideoPlayerObserver { 518 - } 519 - } 520 - } 521 - + 522 - + private func onPlayerTimeRemainingChanged(_ player: AVPlayer, _ timeRemaining: Double) { 523 - + delegates.forEach { delegate in 524 - + delegate.value?.onPlayerTimeRemainingChanged(player: player, timeRemaining: timeRemaining) 525 - + } 526 - + } 527 - + 528 - + private func addPeriodicTimeObserverIfNeeded() { 529 - + guard self.playerPeriodicTimeObserver == nil, let player = self.player else { 530 - + return 531 - + } 532 - + 533 - + if isPlaying { 534 - + // Add the time update listener 535 - + playerPeriodicTimeObserver = player.addPeriodicTimeObserver(forInterval: CMTimeMakeWithSeconds(1.0, preferredTimescale: Int32(NSEC_PER_SEC)), queue: nil) { event in 536 - + guard let duration = player.currentItem?.duration else { 537 - + return 538 - + } 539 - + 540 - + let timeRemaining = (duration.seconds - event.seconds).rounded() 541 - + self.onPlayerTimeRemainingChanged(player, timeRemaining) 542 - + } 543 - + } 544 - + } 545 - } 546 - diff --git a/node_modules/expo-video/ios/VideoView.swift b/node_modules/expo-video/ios/VideoView.swift 547 - index f4579e4..10c5908 100644 548 - --- a/node_modules/expo-video/ios/VideoView.swift 549 - +++ b/node_modules/expo-video/ios/VideoView.swift 550 - @@ -41,6 +41,8 @@ public final class VideoView: ExpoView, AVPlayerViewControllerDelegate { 551 - 552 - let onPictureInPictureStart = EventDispatcher() 553 - let onPictureInPictureStop = EventDispatcher() 554 - + let onEnterFullscreen = EventDispatcher() 555 - + let onExitFullscreen = EventDispatcher() 556 - 557 - public override var bounds: CGRect { 558 - didSet { 559 - @@ -163,6 +165,7 @@ public final class VideoView: ExpoView, AVPlayerViewControllerDelegate { 560 - _ playerViewController: AVPlayerViewController, 561 - willBeginFullScreenPresentationWithAnimationCoordinator coordinator: UIViewControllerTransitionCoordinator 562 - ) { 563 - + onEnterFullscreen() 564 - isFullscreen = true 565 - } 566 - 567 - @@ -179,6 +182,7 @@ public final class VideoView: ExpoView, AVPlayerViewControllerDelegate { 568 - if wasPlaying { 569 - self.player?.pointer.play() 570 - } 571 - + self.onExitFullscreen() 572 - self.isFullscreen = false 573 - } 574 - } 575 - diff --git a/node_modules/expo-video/src/VideoPlayer.types.ts b/node_modules/expo-video/src/VideoPlayer.types.ts 576 - index aaf4b63..5ff6b7a 100644 577 - --- a/node_modules/expo-video/src/VideoPlayer.types.ts 578 - +++ b/node_modules/expo-video/src/VideoPlayer.types.ts 579 - @@ -151,6 +151,8 @@ export type VideoPlayerEvents = { 580 - * Handler for an event emitted when the current media source of the player changes. 581 - */ 582 - sourceChange(newSource: VideoSource, previousSource: VideoSource): void; 583 - + 584 - + timeRemainingChange(timeRemaining: number): void; 585 - }; 586 - 587 - /** 588 - @@ -160,7 +162,7 @@ export type VideoPlayerEvents = { 589 - * - `readyToPlay`: The player has loaded enough data to start playing or to continue playback. 590 - * - `error`: The player has encountered an error while loading or playing the video. 591 - */ 592 - -export type VideoPlayerStatus = 'idle' | 'loading' | 'readyToPlay' | 'error'; 593 - +export type VideoPlayerStatus = 'idle' | 'loading' | 'readyToPlay' | 'error' | 'waitingToPlayAtSpecifiedRate'; 594 - 595 - export type VideoSource = 596 - | string 597 - diff --git a/node_modules/expo-video/src/VideoView.types.ts b/node_modules/expo-video/src/VideoView.types.ts 598 - index 29fe5db..e1fbf59 100644 599 - --- a/node_modules/expo-video/src/VideoView.types.ts 600 - +++ b/node_modules/expo-video/src/VideoView.types.ts 601 - @@ -100,4 +100,7 @@ export interface VideoViewProps extends ViewProps { 602 - * @platform ios 16.0+ 603 - */ 604 - allowsVideoFrameAnalysis?: boolean; 605 - + 606 - + onEnterFullscreen?: () => void; 607 - + onExitFullscreen?: () => void; 608 - }
-31
patches/expo-video+1.2.4.patch.md
··· 1 - ## uwu woad beawing, do not wemove 2 - 3 - ## `expo-video` Patch 4 - 5 - ### `onEnterFullScreen`/`onExitFullScreen` 6 - 7 - Adds two props to `VideoView`: `onEnterFullscreen` and `onExitFullscreen` which do exactly what they say on 8 - the tin. 9 - 10 - ### Removing audio session management 11 - 12 - This patch also removes the audio session management that Expo does on its own, as we handle audio session management 13 - ourselves. 14 - 15 - ### Pausing/playing on background/foreground 16 - 17 - Instead of handling the pausing/playing of videos in React, we'll handle them here. There's some logic that we do not 18 - need (around PIP mode) that we can remove, and just pause any playing players on background and then resume them on 19 - foreground. 20 - 21 - ### Additional `statusChange` Events 22 - 23 - `expo-video` uses the `loading` status for a variety of cases where the video is not actually "loading". We're making 24 - those status events more specific here, so that we can determine if a video is truly loading or not. These statuses are: 25 - 26 - - `waitingToPlayAtSpecifiedRate` 27 - - `unlikelyToKeepUp` 28 - - `playbackBufferEmpty` 29 - 30 - It's unlikely we will ever need to pay attention to these statuses, so they are not being include in the TypeScript 31 - types.
+2 -2
src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerNative.tsx
··· 56 56 contentFit="cover" 57 57 nativeControls={isFullscreen} 58 58 accessibilityIgnoresInvertColors 59 - onEnterFullscreen={() => { 59 + onFullscreenEnter={() => { 60 60 PlatformInfo.setAudioCategory(AudioCategory.Playback) 61 61 PlatformInfo.setAudioActive(true) 62 62 player.muted = false 63 63 setIsFullscreen(true) 64 64 }} 65 - onExitFullscreen={() => { 65 + onFullscreenExit={() => { 66 66 PlatformInfo.setAudioCategory(AudioCategory.Ambient) 67 67 PlatformInfo.setAudioActive(false) 68 68 player.muted = true
+3 -9
yarn.lock
··· 9917 9917 lodash.memoize "^4.1.2" 9918 9918 lodash.uniq "^4.5.0" 9919 9919 9920 - caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001517, caniuse-lite@^1.0.30001520: 9921 - version "1.0.30001655" 9922 - resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001655.tgz" 9923 - integrity sha512-jRGVy3iSGO5Uutn2owlb5gR6qsGngTw9ZTb4ali9f3glshcNmJ2noam4Mo9zia5P9Dk3jNNydy7vQjuE5dQmfg== 9924 - 9925 - caniuse-lite@^1.0.30001587: 9920 + caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001517, caniuse-lite@^1.0.30001520, caniuse-lite@^1.0.30001587: 9926 9921 version "1.0.30001655" 9927 9922 resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001655.tgz" 9928 9923 integrity sha512-jRGVy3iSGO5Uutn2owlb5gR6qsGngTw9ZTb4ali9f3glshcNmJ2noam4Mo9zia5P9Dk3jNNydy7vQjuE5dQmfg== ··· 12419 12414 ignore "^5.3.1" 12420 12415 resolve-from "^5.0.0" 12421 12416 12422 - expo-video@^1.2.4: 12417 + "expo-video@https://github.com/bluesky-social/expo/raw/main/packages/expo-video/expo-video-v1.2.4.tgz": 12423 12418 version "1.2.4" 12424 - resolved "https://registry.yarnpkg.com/expo-video/-/expo-video-1.2.4.tgz#787342aded4295a1b6864f59227d178b93e1bb53" 12425 - integrity sha512-pBK9mt7vYAbuPQjCSQxHQ7xrNjbmRheJep7JIStEg57O183/JRfP2blKuXniiSt1HBdZYPdoQnGRa3jGMXB9pg== 12419 + resolved "https://github.com/bluesky-social/expo/raw/main/packages/expo-video/expo-video-v1.2.4.tgz#ebb6a672a385f9a059ca614fd148f7803d4267fc" 12426 12420 12427 12421 expo-web-browser@~13.0.3: 12428 12422 version "13.0.3"