@granite-js/video 1.0.0
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.
- package/CHANGELOG.md +7 -0
- package/GraniteVideo.podspec +72 -0
- package/android/README.md +232 -0
- package/android/build.gradle +117 -0
- package/android/gradle.properties +8 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/java/run/granite/video/GraniteVideoModule.kt +70 -0
- package/android/src/main/java/run/granite/video/GraniteVideoPackage.kt +43 -0
- package/android/src/main/java/run/granite/video/GraniteVideoView.kt +384 -0
- package/android/src/main/java/run/granite/video/GraniteVideoViewManager.kt +318 -0
- package/android/src/main/java/run/granite/video/event/GraniteVideoEvents.kt +273 -0
- package/android/src/main/java/run/granite/video/event/VideoEventDispatcher.kt +66 -0
- package/android/src/main/java/run/granite/video/event/VideoEventListenerAdapter.kt +157 -0
- package/android/src/main/java/run/granite/video/provider/GraniteVideoProvider.kt +346 -0
- package/android/src/media3/AndroidManifest.xml +9 -0
- package/android/src/media3/java/run/granite/video/provider/media3/ExoPlayerProvider.kt +386 -0
- package/android/src/media3/java/run/granite/video/provider/media3/Media3ContentProvider.kt +29 -0
- package/android/src/media3/java/run/granite/video/provider/media3/Media3Initializer.kt +25 -0
- package/android/src/media3/java/run/granite/video/provider/media3/factory/ExoPlayerFactory.kt +32 -0
- package/android/src/media3/java/run/granite/video/provider/media3/factory/MediaSourceFactory.kt +61 -0
- package/android/src/media3/java/run/granite/video/provider/media3/factory/TrackSelectorFactory.kt +26 -0
- package/android/src/media3/java/run/granite/video/provider/media3/factory/VideoSurfaceFactory.kt +62 -0
- package/android/src/media3/java/run/granite/video/provider/media3/listener/ExoPlayerEventListener.kt +104 -0
- package/android/src/media3/java/run/granite/video/provider/media3/scheduler/ProgressScheduler.kt +56 -0
- package/android/src/test/java/run/granite/video/GraniteVideoViewRobolectricTest.kt +598 -0
- package/android/src/test/java/run/granite/video/event/VideoEventListenerAdapterTest.kt +319 -0
- package/android/src/test/java/run/granite/video/helpers/FakeGraniteVideoProvider.kt +161 -0
- package/android/src/test/java/run/granite/video/helpers/TestProgressScheduler.kt +42 -0
- package/android/src/test/java/run/granite/video/provider/GraniteVideoRegistryTest.kt +232 -0
- package/android/src/test/java/run/granite/video/provider/ProviderContractTest.kt +174 -0
- package/android/src/test/java/run/granite/video/provider/media3/listener/ExoPlayerEventListenerTest.kt +243 -0
- package/android/src/test/resources/kotest.properties +2 -0
- package/dist/module/GraniteVideo.js +458 -0
- package/dist/module/GraniteVideo.js.map +1 -0
- package/dist/module/GraniteVideoNativeComponent.ts +265 -0
- package/dist/module/index.js +7 -0
- package/dist/module/index.js.map +1 -0
- package/dist/module/package.json +1 -0
- package/dist/module/types.js +4 -0
- package/dist/module/types.js.map +1 -0
- package/dist/typescript/GraniteVideo.d.ts +12 -0
- package/dist/typescript/GraniteVideoNativeComponent.d.ts +189 -0
- package/dist/typescript/index.d.ts +5 -0
- package/dist/typescript/types.d.ts +328 -0
- package/ios/GraniteVideoComponentsProvider.h +10 -0
- package/ios/GraniteVideoProvider.swift +280 -0
- package/ios/GraniteVideoView.h +15 -0
- package/ios/GraniteVideoView.mm +661 -0
- package/ios/Providers/AVPlayerProvider.swift +541 -0
- package/package.json +106 -0
- package/src/GraniteVideo.tsx +575 -0
- package/src/GraniteVideoNativeComponent.ts +265 -0
- package/src/index.ts +8 -0
- package/src/types.ts +464 -0
package/android/src/media3/java/run/granite/video/provider/media3/listener/ExoPlayerEventListener.kt
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
package run.granite.video.provider.media3.listener
|
|
2
|
+
|
|
3
|
+
import androidx.media3.common.PlaybackException
|
|
4
|
+
import androidx.media3.common.Player
|
|
5
|
+
import androidx.media3.common.VideoSize
|
|
6
|
+
import androidx.media3.common.util.UnstableApi
|
|
7
|
+
import run.granite.video.provider.GraniteVideoDelegate
|
|
8
|
+
import run.granite.video.provider.GraniteVideoErrorData
|
|
9
|
+
import run.granite.video.provider.GraniteVideoLoadData
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Callback interface for playback state changes.
|
|
13
|
+
*/
|
|
14
|
+
interface PlaybackStateProvider {
|
|
15
|
+
val isPlaying: Boolean
|
|
16
|
+
val isSeeking: Boolean
|
|
17
|
+
val isLooping: Boolean
|
|
18
|
+
val currentTime: Double
|
|
19
|
+
val duration: Double
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* ExoPlayer event listener that delegates events to GraniteVideoDelegate.
|
|
24
|
+
* Separated from ExoPlayerProvider for testability.
|
|
25
|
+
*/
|
|
26
|
+
@UnstableApi
|
|
27
|
+
class ExoPlayerEventListener(
|
|
28
|
+
private val delegateProvider: () -> GraniteVideoDelegate?,
|
|
29
|
+
private val stateProvider: PlaybackStateProvider,
|
|
30
|
+
private val onPlayingChanged: (Boolean) -> Unit = {},
|
|
31
|
+
private val onVideoSizeChanged: (Int, Int) -> Unit = { _, _ -> }
|
|
32
|
+
) : Player.Listener {
|
|
33
|
+
|
|
34
|
+
private val delegate: GraniteVideoDelegate?
|
|
35
|
+
get() = delegateProvider()
|
|
36
|
+
|
|
37
|
+
override fun onPlaybackStateChanged(playbackState: Int) {
|
|
38
|
+
when (playbackState) {
|
|
39
|
+
Player.STATE_IDLE -> {
|
|
40
|
+
delegate?.onIdle()
|
|
41
|
+
}
|
|
42
|
+
Player.STATE_BUFFERING -> {
|
|
43
|
+
delegate?.onBuffer(true)
|
|
44
|
+
}
|
|
45
|
+
Player.STATE_READY -> {
|
|
46
|
+
delegate?.onBuffer(false)
|
|
47
|
+
delegate?.onReadyForDisplay()
|
|
48
|
+
delegate?.onLoad(
|
|
49
|
+
GraniteVideoLoadData(
|
|
50
|
+
currentTime = stateProvider.currentTime,
|
|
51
|
+
duration = stateProvider.duration,
|
|
52
|
+
naturalWidth = 0.0, // Will be updated in onVideoSizeChanged
|
|
53
|
+
naturalHeight = 0.0,
|
|
54
|
+
orientation = "landscape"
|
|
55
|
+
)
|
|
56
|
+
)
|
|
57
|
+
}
|
|
58
|
+
Player.STATE_ENDED -> {
|
|
59
|
+
delegate?.onEnd()
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
override fun onIsPlayingChanged(isPlaying: Boolean) {
|
|
65
|
+
onPlayingChanged(isPlaying)
|
|
66
|
+
delegate?.onPlaybackStateChanged(
|
|
67
|
+
isPlaying = isPlaying,
|
|
68
|
+
isSeeking = stateProvider.isSeeking,
|
|
69
|
+
isLooping = stateProvider.isLooping
|
|
70
|
+
)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
override fun onPlayerError(error: PlaybackException) {
|
|
74
|
+
delegate?.onError(
|
|
75
|
+
GraniteVideoErrorData(
|
|
76
|
+
code = error.errorCode,
|
|
77
|
+
domain = "ExoPlayer",
|
|
78
|
+
localizedDescription = error.message ?: "Unknown error",
|
|
79
|
+
errorString = error.errorCodeName
|
|
80
|
+
)
|
|
81
|
+
)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
override fun onVideoSizeChanged(videoSize: VideoSize) {
|
|
85
|
+
val width = videoSize.width
|
|
86
|
+
val height = videoSize.height
|
|
87
|
+
|
|
88
|
+
if (width > 0 && height > 0) {
|
|
89
|
+
onVideoSizeChanged(width, height)
|
|
90
|
+
delegate?.onAspectRatioChanged(width.toDouble(), height.toDouble())
|
|
91
|
+
|
|
92
|
+
// Update load data with actual dimensions
|
|
93
|
+
delegate?.onLoad(
|
|
94
|
+
GraniteVideoLoadData(
|
|
95
|
+
currentTime = stateProvider.currentTime,
|
|
96
|
+
duration = stateProvider.duration,
|
|
97
|
+
naturalWidth = width.toDouble(),
|
|
98
|
+
naturalHeight = height.toDouble(),
|
|
99
|
+
orientation = if (width > height) "landscape" else "portrait"
|
|
100
|
+
)
|
|
101
|
+
)
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
package/android/src/media3/java/run/granite/video/provider/media3/scheduler/ProgressScheduler.kt
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
package run.granite.video.provider.media3.scheduler
|
|
2
|
+
|
|
3
|
+
import android.os.Handler
|
|
4
|
+
import android.os.Looper
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Interface for scheduling periodic progress updates.
|
|
8
|
+
* Abstracted to allow for testability.
|
|
9
|
+
*/
|
|
10
|
+
interface ProgressScheduler {
|
|
11
|
+
/**
|
|
12
|
+
* Schedule a periodic action.
|
|
13
|
+
* @param intervalMs The interval in milliseconds.
|
|
14
|
+
* @param action The action to execute periodically.
|
|
15
|
+
*/
|
|
16
|
+
fun schedule(intervalMs: Long, action: () -> Unit)
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Cancel any scheduled actions.
|
|
20
|
+
*/
|
|
21
|
+
fun cancel()
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Default implementation using Android Handler.
|
|
26
|
+
*/
|
|
27
|
+
class HandlerProgressScheduler(
|
|
28
|
+
private val handler: Handler = Handler(Looper.getMainLooper())
|
|
29
|
+
) : ProgressScheduler {
|
|
30
|
+
|
|
31
|
+
private var runnable: Runnable? = null
|
|
32
|
+
private var intervalMs: Long = 0
|
|
33
|
+
private var action: (() -> Unit)? = null
|
|
34
|
+
|
|
35
|
+
override fun schedule(intervalMs: Long, action: () -> Unit) {
|
|
36
|
+
cancel()
|
|
37
|
+
|
|
38
|
+
this.intervalMs = intervalMs
|
|
39
|
+
this.action = action
|
|
40
|
+
|
|
41
|
+
runnable = object : Runnable {
|
|
42
|
+
override fun run() {
|
|
43
|
+
action()
|
|
44
|
+
handler.postDelayed(this, intervalMs)
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
handler.post(runnable!!)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
override fun cancel() {
|
|
52
|
+
runnable?.let { handler.removeCallbacks(it) }
|
|
53
|
+
runnable = null
|
|
54
|
+
action = null
|
|
55
|
+
}
|
|
56
|
+
}
|