@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.
Files changed (54) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/GraniteVideo.podspec +72 -0
  3. package/android/README.md +232 -0
  4. package/android/build.gradle +117 -0
  5. package/android/gradle.properties +8 -0
  6. package/android/src/main/AndroidManifest.xml +2 -0
  7. package/android/src/main/java/run/granite/video/GraniteVideoModule.kt +70 -0
  8. package/android/src/main/java/run/granite/video/GraniteVideoPackage.kt +43 -0
  9. package/android/src/main/java/run/granite/video/GraniteVideoView.kt +384 -0
  10. package/android/src/main/java/run/granite/video/GraniteVideoViewManager.kt +318 -0
  11. package/android/src/main/java/run/granite/video/event/GraniteVideoEvents.kt +273 -0
  12. package/android/src/main/java/run/granite/video/event/VideoEventDispatcher.kt +66 -0
  13. package/android/src/main/java/run/granite/video/event/VideoEventListenerAdapter.kt +157 -0
  14. package/android/src/main/java/run/granite/video/provider/GraniteVideoProvider.kt +346 -0
  15. package/android/src/media3/AndroidManifest.xml +9 -0
  16. package/android/src/media3/java/run/granite/video/provider/media3/ExoPlayerProvider.kt +386 -0
  17. package/android/src/media3/java/run/granite/video/provider/media3/Media3ContentProvider.kt +29 -0
  18. package/android/src/media3/java/run/granite/video/provider/media3/Media3Initializer.kt +25 -0
  19. package/android/src/media3/java/run/granite/video/provider/media3/factory/ExoPlayerFactory.kt +32 -0
  20. package/android/src/media3/java/run/granite/video/provider/media3/factory/MediaSourceFactory.kt +61 -0
  21. package/android/src/media3/java/run/granite/video/provider/media3/factory/TrackSelectorFactory.kt +26 -0
  22. package/android/src/media3/java/run/granite/video/provider/media3/factory/VideoSurfaceFactory.kt +62 -0
  23. package/android/src/media3/java/run/granite/video/provider/media3/listener/ExoPlayerEventListener.kt +104 -0
  24. package/android/src/media3/java/run/granite/video/provider/media3/scheduler/ProgressScheduler.kt +56 -0
  25. package/android/src/test/java/run/granite/video/GraniteVideoViewRobolectricTest.kt +598 -0
  26. package/android/src/test/java/run/granite/video/event/VideoEventListenerAdapterTest.kt +319 -0
  27. package/android/src/test/java/run/granite/video/helpers/FakeGraniteVideoProvider.kt +161 -0
  28. package/android/src/test/java/run/granite/video/helpers/TestProgressScheduler.kt +42 -0
  29. package/android/src/test/java/run/granite/video/provider/GraniteVideoRegistryTest.kt +232 -0
  30. package/android/src/test/java/run/granite/video/provider/ProviderContractTest.kt +174 -0
  31. package/android/src/test/java/run/granite/video/provider/media3/listener/ExoPlayerEventListenerTest.kt +243 -0
  32. package/android/src/test/resources/kotest.properties +2 -0
  33. package/dist/module/GraniteVideo.js +458 -0
  34. package/dist/module/GraniteVideo.js.map +1 -0
  35. package/dist/module/GraniteVideoNativeComponent.ts +265 -0
  36. package/dist/module/index.js +7 -0
  37. package/dist/module/index.js.map +1 -0
  38. package/dist/module/package.json +1 -0
  39. package/dist/module/types.js +4 -0
  40. package/dist/module/types.js.map +1 -0
  41. package/dist/typescript/GraniteVideo.d.ts +12 -0
  42. package/dist/typescript/GraniteVideoNativeComponent.d.ts +189 -0
  43. package/dist/typescript/index.d.ts +5 -0
  44. package/dist/typescript/types.d.ts +328 -0
  45. package/ios/GraniteVideoComponentsProvider.h +10 -0
  46. package/ios/GraniteVideoProvider.swift +280 -0
  47. package/ios/GraniteVideoView.h +15 -0
  48. package/ios/GraniteVideoView.mm +661 -0
  49. package/ios/Providers/AVPlayerProvider.swift +541 -0
  50. package/package.json +106 -0
  51. package/src/GraniteVideo.tsx +575 -0
  52. package/src/GraniteVideoNativeComponent.ts +265 -0
  53. package/src/index.ts +8 -0
  54. package/src/types.ts +464 -0
@@ -0,0 +1,273 @@
1
+ package run.granite.video.event
2
+
3
+ import com.facebook.react.bridge.Arguments
4
+ import com.facebook.react.bridge.WritableMap
5
+ import com.facebook.react.uimanager.events.Event
6
+ import run.granite.video.provider.GraniteVideoLoadData
7
+ import run.granite.video.provider.GraniteVideoErrorData
8
+ import run.granite.video.provider.GraniteVideoProgressData
9
+
10
+ class GraniteVideoLoadStartEvent(
11
+ surfaceId: Int,
12
+ viewId: Int,
13
+ private val isNetwork: Boolean,
14
+ private val type: String,
15
+ private val uri: String
16
+ ) : Event<GraniteVideoLoadStartEvent>(surfaceId, viewId) {
17
+ override fun getEventName(): String = "topVideoLoadStart"
18
+ override fun getEventData(): WritableMap = Arguments.createMap().apply {
19
+ putBoolean("isNetwork", isNetwork)
20
+ putString("type", type)
21
+ putString("uri", uri)
22
+ }
23
+ }
24
+
25
+ class GraniteVideoLoadEvent(
26
+ surfaceId: Int,
27
+ viewId: Int,
28
+ private val data: GraniteVideoLoadData
29
+ ) : Event<GraniteVideoLoadEvent>(surfaceId, viewId) {
30
+ override fun getEventName(): String = "topVideoLoad"
31
+ override fun getEventData(): WritableMap = Arguments.createMap().apply {
32
+ putDouble("currentTime", data.currentTime)
33
+ putDouble("duration", data.duration)
34
+
35
+ val naturalSize = Arguments.createMap().apply {
36
+ putDouble("width", data.naturalWidth)
37
+ putDouble("height", data.naturalHeight)
38
+ putString("orientation", data.orientation)
39
+ }
40
+ putMap("naturalSize", naturalSize)
41
+ }
42
+ }
43
+
44
+ class GraniteVideoErrorEvent(
45
+ surfaceId: Int,
46
+ viewId: Int,
47
+ private val error: GraniteVideoErrorData
48
+ ) : Event<GraniteVideoErrorEvent>(surfaceId, viewId) {
49
+ override fun getEventName(): String = "topVideoError"
50
+ override fun getEventData(): WritableMap = Arguments.createMap().apply {
51
+ val errorMap = Arguments.createMap().apply {
52
+ putInt("code", error.code)
53
+ putString("domain", error.domain)
54
+ putString("localizedDescription", error.localizedDescription)
55
+ putString("localizedFailureReason", "")
56
+ putString("localizedRecoverySuggestion", "")
57
+ putString("errorString", error.errorString)
58
+ }
59
+ putMap("error", errorMap)
60
+ }
61
+ }
62
+
63
+ class GraniteVideoProgressEvent(
64
+ surfaceId: Int,
65
+ viewId: Int,
66
+ private val data: GraniteVideoProgressData
67
+ ) : Event<GraniteVideoProgressEvent>(surfaceId, viewId) {
68
+ override fun getEventName(): String = "topVideoProgress"
69
+ override fun getEventData(): WritableMap = Arguments.createMap().apply {
70
+ putDouble("currentTime", data.currentTime)
71
+ putDouble("playableDuration", data.playableDuration)
72
+ putDouble("seekableDuration", data.seekableDuration)
73
+ }
74
+ }
75
+
76
+ class GraniteVideoSeekEvent(
77
+ surfaceId: Int,
78
+ viewId: Int,
79
+ private val currentTime: Double,
80
+ private val seekTime: Double
81
+ ) : Event<GraniteVideoSeekEvent>(surfaceId, viewId) {
82
+ override fun getEventName(): String = "topVideoSeek"
83
+ override fun getEventData(): WritableMap = Arguments.createMap().apply {
84
+ putDouble("currentTime", currentTime)
85
+ putDouble("seekTime", seekTime)
86
+ }
87
+ }
88
+
89
+ class GraniteVideoEndEvent(
90
+ surfaceId: Int,
91
+ viewId: Int
92
+ ) : Event<GraniteVideoEndEvent>(surfaceId, viewId) {
93
+ override fun getEventName(): String = "topVideoEnd"
94
+ override fun getEventData(): WritableMap = Arguments.createMap()
95
+ }
96
+
97
+ class GraniteVideoBufferEvent(
98
+ surfaceId: Int,
99
+ viewId: Int,
100
+ private val isBuffering: Boolean
101
+ ) : Event<GraniteVideoBufferEvent>(surfaceId, viewId) {
102
+ override fun getEventName(): String = "topVideoBuffer"
103
+ override fun getEventData(): WritableMap = Arguments.createMap().apply {
104
+ putBoolean("isBuffering", isBuffering)
105
+ }
106
+ }
107
+
108
+ class GraniteVideoBandwidthUpdateEvent(
109
+ surfaceId: Int,
110
+ viewId: Int,
111
+ private val bitrate: Double,
112
+ private val width: Int,
113
+ private val height: Int
114
+ ) : Event<GraniteVideoBandwidthUpdateEvent>(surfaceId, viewId) {
115
+ override fun getEventName(): String = "topVideoBandwidthUpdate"
116
+ override fun getEventData(): WritableMap = Arguments.createMap().apply {
117
+ putDouble("bitrate", bitrate)
118
+ putInt("width", width)
119
+ putInt("height", height)
120
+ }
121
+ }
122
+
123
+ class GraniteVideoPlaybackStateChangedEvent(
124
+ surfaceId: Int,
125
+ viewId: Int,
126
+ private val isPlaying: Boolean,
127
+ private val isSeeking: Boolean,
128
+ private val isLooping: Boolean
129
+ ) : Event<GraniteVideoPlaybackStateChangedEvent>(surfaceId, viewId) {
130
+ override fun getEventName(): String = "topVideoPlaybackStateChanged"
131
+ override fun getEventData(): WritableMap = Arguments.createMap().apply {
132
+ putBoolean("isPlaying", isPlaying)
133
+ putBoolean("isSeeking", isSeeking)
134
+ putBoolean("isLooping", isLooping)
135
+ }
136
+ }
137
+
138
+ class GraniteVideoPlaybackRateChangeEvent(
139
+ surfaceId: Int,
140
+ viewId: Int,
141
+ private val rate: Float
142
+ ) : Event<GraniteVideoPlaybackRateChangeEvent>(surfaceId, viewId) {
143
+ override fun getEventName(): String = "topVideoPlaybackRateChange"
144
+ override fun getEventData(): WritableMap = Arguments.createMap().apply {
145
+ putDouble("playbackRate", rate.toDouble())
146
+ }
147
+ }
148
+
149
+ class GraniteVideoVolumeChangeEvent(
150
+ surfaceId: Int,
151
+ viewId: Int,
152
+ private val volume: Float
153
+ ) : Event<GraniteVideoVolumeChangeEvent>(surfaceId, viewId) {
154
+ override fun getEventName(): String = "topVideoVolumeChange"
155
+ override fun getEventData(): WritableMap = Arguments.createMap().apply {
156
+ putDouble("volume", volume.toDouble())
157
+ }
158
+ }
159
+
160
+ class GraniteVideoIdleEvent(
161
+ surfaceId: Int,
162
+ viewId: Int
163
+ ) : Event<GraniteVideoIdleEvent>(surfaceId, viewId) {
164
+ override fun getEventName(): String = "topVideoIdle"
165
+ override fun getEventData(): WritableMap = Arguments.createMap()
166
+ }
167
+
168
+ class GraniteVideoReadyForDisplayEvent(
169
+ surfaceId: Int,
170
+ viewId: Int
171
+ ) : Event<GraniteVideoReadyForDisplayEvent>(surfaceId, viewId) {
172
+ override fun getEventName(): String = "topVideoReadyForDisplay"
173
+ override fun getEventData(): WritableMap = Arguments.createMap()
174
+ }
175
+
176
+ class GraniteVideoAudioFocusChangedEvent(
177
+ surfaceId: Int,
178
+ viewId: Int,
179
+ private val hasAudioFocus: Boolean
180
+ ) : Event<GraniteVideoAudioFocusChangedEvent>(surfaceId, viewId) {
181
+ override fun getEventName(): String = "topVideoAudioFocusChanged"
182
+ override fun getEventData(): WritableMap = Arguments.createMap().apply {
183
+ putBoolean("hasAudioFocus", hasAudioFocus)
184
+ }
185
+ }
186
+
187
+ class GraniteVideoAudioBecomingNoisyEvent(
188
+ surfaceId: Int,
189
+ viewId: Int
190
+ ) : Event<GraniteVideoAudioBecomingNoisyEvent>(surfaceId, viewId) {
191
+ override fun getEventName(): String = "topVideoAudioBecomingNoisy"
192
+ override fun getEventData(): WritableMap = Arguments.createMap()
193
+ }
194
+
195
+ class GraniteVideoFullscreenPlayerWillPresentEvent(
196
+ surfaceId: Int,
197
+ viewId: Int
198
+ ) : Event<GraniteVideoFullscreenPlayerWillPresentEvent>(surfaceId, viewId) {
199
+ override fun getEventName(): String = "topVideoFullscreenPlayerWillPresent"
200
+ override fun getEventData(): WritableMap = Arguments.createMap()
201
+ }
202
+
203
+ class GraniteVideoFullscreenPlayerDidPresentEvent(
204
+ surfaceId: Int,
205
+ viewId: Int
206
+ ) : Event<GraniteVideoFullscreenPlayerDidPresentEvent>(surfaceId, viewId) {
207
+ override fun getEventName(): String = "topVideoFullscreenPlayerDidPresent"
208
+ override fun getEventData(): WritableMap = Arguments.createMap()
209
+ }
210
+
211
+ class GraniteVideoFullscreenPlayerWillDismissEvent(
212
+ surfaceId: Int,
213
+ viewId: Int
214
+ ) : Event<GraniteVideoFullscreenPlayerWillDismissEvent>(surfaceId, viewId) {
215
+ override fun getEventName(): String = "topVideoFullscreenPlayerWillDismiss"
216
+ override fun getEventData(): WritableMap = Arguments.createMap()
217
+ }
218
+
219
+ class GraniteVideoFullscreenPlayerDidDismissEvent(
220
+ surfaceId: Int,
221
+ viewId: Int
222
+ ) : Event<GraniteVideoFullscreenPlayerDidDismissEvent>(surfaceId, viewId) {
223
+ override fun getEventName(): String = "topVideoFullscreenPlayerDidDismiss"
224
+ override fun getEventData(): WritableMap = Arguments.createMap()
225
+ }
226
+
227
+ class GraniteVideoPictureInPictureStatusChangedEvent(
228
+ surfaceId: Int,
229
+ viewId: Int,
230
+ private val isActive: Boolean
231
+ ) : Event<GraniteVideoPictureInPictureStatusChangedEvent>(surfaceId, viewId) {
232
+ override fun getEventName(): String = "topVideoPictureInPictureStatusChanged"
233
+ override fun getEventData(): WritableMap = Arguments.createMap().apply {
234
+ putBoolean("isActive", isActive)
235
+ }
236
+ }
237
+
238
+ class GraniteVideoControlsVisibilityChangeEvent(
239
+ surfaceId: Int,
240
+ viewId: Int,
241
+ private val isVisible: Boolean
242
+ ) : Event<GraniteVideoControlsVisibilityChangeEvent>(surfaceId, viewId) {
243
+ override fun getEventName(): String = "topVideoControlsVisibilityChange"
244
+ override fun getEventData(): WritableMap = Arguments.createMap().apply {
245
+ putBoolean("isVisible", isVisible)
246
+ }
247
+ }
248
+
249
+ class GraniteVideoAspectRatioEvent(
250
+ surfaceId: Int,
251
+ viewId: Int,
252
+ private val width: Double,
253
+ private val height: Double
254
+ ) : Event<GraniteVideoAspectRatioEvent>(surfaceId, viewId) {
255
+ override fun getEventName(): String = "topVideoAspectRatio"
256
+ override fun getEventData(): WritableMap = Arguments.createMap().apply {
257
+ putDouble("width", width)
258
+ putDouble("height", height)
259
+ }
260
+ }
261
+
262
+ class GraniteVideoOnTransferEndEvent(
263
+ surfaceId: Int,
264
+ viewId: Int,
265
+ private val uri: String,
266
+ private val bytesTransferred: Long
267
+ ) : Event<GraniteVideoOnTransferEndEvent>(surfaceId, viewId) {
268
+ override fun getEventName(): String = "topVideoTransferEnd"
269
+ override fun getEventData(): WritableMap = Arguments.createMap().apply {
270
+ putString("uri", uri)
271
+ putLong("bytesTransferred", bytesTransferred)
272
+ }
273
+ }
@@ -0,0 +1,66 @@
1
+ package run.granite.video.event
2
+
3
+ import android.view.View
4
+ import com.facebook.react.bridge.ReactContext
5
+ import com.facebook.react.uimanager.UIManagerHelper
6
+ import com.facebook.react.uimanager.events.Event
7
+ import com.facebook.react.uimanager.events.EventDispatcher
8
+
9
+ /**
10
+ * Interface for dispatching video events to React Native.
11
+ * Uses modern Event-based dispatching compatible with RN 0.84+.
12
+ */
13
+ interface VideoEventDispatcher {
14
+ /**
15
+ * Dispatch an event to React Native.
16
+ * @param event The Event object to dispatch.
17
+ */
18
+ fun dispatchEvent(event: Event<*>)
19
+
20
+ /**
21
+ * Get the surface ID for creating events.
22
+ * @return The surface ID for this view.
23
+ */
24
+ fun getSurfaceId(): Int
25
+ }
26
+
27
+ /**
28
+ * Modern implementation using UIManagerHelper EventDispatcher.
29
+ * Compatible with React Native 0.84+.
30
+ */
31
+ class ModernVideoEventDispatcher(
32
+ private val view: View
33
+ ) : VideoEventDispatcher {
34
+
35
+ private fun getEventDispatcher(): EventDispatcher? {
36
+ val reactContext = view.context as? ReactContext ?: return null
37
+ return UIManagerHelper.getEventDispatcherForReactTag(reactContext, view.id)
38
+ }
39
+
40
+ override fun dispatchEvent(event: Event<*>) {
41
+ getEventDispatcher()?.dispatchEvent(event)
42
+ }
43
+
44
+ override fun getSurfaceId(): Int = UIManagerHelper.getSurfaceId(view)
45
+ }
46
+
47
+ /**
48
+ * Factory interface for creating VideoEventDispatcher instances.
49
+ */
50
+ interface VideoEventDispatcherFactory {
51
+ /**
52
+ * Create a VideoEventDispatcher for the given view.
53
+ * @param view The view to dispatch events for.
54
+ * @return A new VideoEventDispatcher instance.
55
+ */
56
+ fun create(view: View): VideoEventDispatcher
57
+ }
58
+
59
+ /**
60
+ * Default factory implementation.
61
+ */
62
+ class DefaultVideoEventDispatcherFactory : VideoEventDispatcherFactory {
63
+ override fun create(view: View): VideoEventDispatcher {
64
+ return ModernVideoEventDispatcher(view)
65
+ }
66
+ }
@@ -0,0 +1,157 @@
1
+ package run.granite.video.event
2
+
3
+ import run.granite.video.GraniteVideoEventListener
4
+ import run.granite.video.provider.GraniteVideoErrorData
5
+ import run.granite.video.provider.GraniteVideoLoadData
6
+ import run.granite.video.provider.GraniteVideoProgressData
7
+
8
+ /**
9
+ * Adapter that bridges GraniteVideoEventListener to VideoEventDispatcher.
10
+ * Separated from ViewManager for testability.
11
+ */
12
+ class VideoEventListenerAdapter(
13
+ private val dispatcher: VideoEventDispatcher,
14
+ private val viewIdProvider: () -> Int
15
+ ) : GraniteVideoEventListener {
16
+
17
+ private val viewId: Int
18
+ get() = viewIdProvider()
19
+
20
+ override fun onLoadStart(isNetwork: Boolean, type: String, uri: String) {
21
+ dispatcher.dispatchEvent(
22
+ GraniteVideoLoadStartEvent(dispatcher.getSurfaceId(), viewId, isNetwork, type, uri)
23
+ )
24
+ }
25
+
26
+ override fun onLoad(data: GraniteVideoLoadData) {
27
+ dispatcher.dispatchEvent(
28
+ GraniteVideoLoadEvent(dispatcher.getSurfaceId(), viewId, data)
29
+ )
30
+ }
31
+
32
+ override fun onError(error: GraniteVideoErrorData) {
33
+ dispatcher.dispatchEvent(
34
+ GraniteVideoErrorEvent(dispatcher.getSurfaceId(), viewId, error)
35
+ )
36
+ }
37
+
38
+ override fun onProgress(data: GraniteVideoProgressData) {
39
+ dispatcher.dispatchEvent(
40
+ GraniteVideoProgressEvent(dispatcher.getSurfaceId(), viewId, data)
41
+ )
42
+ }
43
+
44
+ override fun onSeek(currentTime: Double, seekTime: Double) {
45
+ dispatcher.dispatchEvent(
46
+ GraniteVideoSeekEvent(dispatcher.getSurfaceId(), viewId, currentTime, seekTime)
47
+ )
48
+ }
49
+
50
+ override fun onEnd() {
51
+ dispatcher.dispatchEvent(
52
+ GraniteVideoEndEvent(dispatcher.getSurfaceId(), viewId)
53
+ )
54
+ }
55
+
56
+ override fun onBuffer(isBuffering: Boolean) {
57
+ dispatcher.dispatchEvent(
58
+ GraniteVideoBufferEvent(dispatcher.getSurfaceId(), viewId, isBuffering)
59
+ )
60
+ }
61
+
62
+ override fun onBandwidthUpdate(bitrate: Double, width: Int, height: Int) {
63
+ dispatcher.dispatchEvent(
64
+ GraniteVideoBandwidthUpdateEvent(dispatcher.getSurfaceId(), viewId, bitrate, width, height)
65
+ )
66
+ }
67
+
68
+ override fun onPlaybackStateChanged(isPlaying: Boolean, isSeeking: Boolean, isLooping: Boolean) {
69
+ dispatcher.dispatchEvent(
70
+ GraniteVideoPlaybackStateChangedEvent(dispatcher.getSurfaceId(), viewId, isPlaying, isSeeking, isLooping)
71
+ )
72
+ }
73
+
74
+ override fun onPlaybackRateChange(rate: Float) {
75
+ dispatcher.dispatchEvent(
76
+ GraniteVideoPlaybackRateChangeEvent(dispatcher.getSurfaceId(), viewId, rate)
77
+ )
78
+ }
79
+
80
+ override fun onVolumeChange(volume: Float) {
81
+ dispatcher.dispatchEvent(
82
+ GraniteVideoVolumeChangeEvent(dispatcher.getSurfaceId(), viewId, volume)
83
+ )
84
+ }
85
+
86
+ override fun onIdle() {
87
+ dispatcher.dispatchEvent(
88
+ GraniteVideoIdleEvent(dispatcher.getSurfaceId(), viewId)
89
+ )
90
+ }
91
+
92
+ override fun onReadyForDisplay() {
93
+ dispatcher.dispatchEvent(
94
+ GraniteVideoReadyForDisplayEvent(dispatcher.getSurfaceId(), viewId)
95
+ )
96
+ }
97
+
98
+ override fun onAudioFocusChanged(hasAudioFocus: Boolean) {
99
+ dispatcher.dispatchEvent(
100
+ GraniteVideoAudioFocusChangedEvent(dispatcher.getSurfaceId(), viewId, hasAudioFocus)
101
+ )
102
+ }
103
+
104
+ override fun onAudioBecomingNoisy() {
105
+ dispatcher.dispatchEvent(
106
+ GraniteVideoAudioBecomingNoisyEvent(dispatcher.getSurfaceId(), viewId)
107
+ )
108
+ }
109
+
110
+ override fun onFullscreenPlayerWillPresent() {
111
+ dispatcher.dispatchEvent(
112
+ GraniteVideoFullscreenPlayerWillPresentEvent(dispatcher.getSurfaceId(), viewId)
113
+ )
114
+ }
115
+
116
+ override fun onFullscreenPlayerDidPresent() {
117
+ dispatcher.dispatchEvent(
118
+ GraniteVideoFullscreenPlayerDidPresentEvent(dispatcher.getSurfaceId(), viewId)
119
+ )
120
+ }
121
+
122
+ override fun onFullscreenPlayerWillDismiss() {
123
+ dispatcher.dispatchEvent(
124
+ GraniteVideoFullscreenPlayerWillDismissEvent(dispatcher.getSurfaceId(), viewId)
125
+ )
126
+ }
127
+
128
+ override fun onFullscreenPlayerDidDismiss() {
129
+ dispatcher.dispatchEvent(
130
+ GraniteVideoFullscreenPlayerDidDismissEvent(dispatcher.getSurfaceId(), viewId)
131
+ )
132
+ }
133
+
134
+ override fun onPictureInPictureStatusChanged(isActive: Boolean) {
135
+ dispatcher.dispatchEvent(
136
+ GraniteVideoPictureInPictureStatusChangedEvent(dispatcher.getSurfaceId(), viewId, isActive)
137
+ )
138
+ }
139
+
140
+ override fun onControlsVisibilityChanged(isVisible: Boolean) {
141
+ dispatcher.dispatchEvent(
142
+ GraniteVideoControlsVisibilityChangeEvent(dispatcher.getSurfaceId(), viewId, isVisible)
143
+ )
144
+ }
145
+
146
+ override fun onAspectRatioChanged(width: Double, height: Double) {
147
+ dispatcher.dispatchEvent(
148
+ GraniteVideoAspectRatioEvent(dispatcher.getSurfaceId(), viewId, width, height)
149
+ )
150
+ }
151
+
152
+ override fun onTransferEnd(uri: String, bytesTransferred: Long) {
153
+ dispatcher.dispatchEvent(
154
+ GraniteVideoOnTransferEndEvent(dispatcher.getSurfaceId(), viewId, uri, bytesTransferred)
155
+ )
156
+ }
157
+ }