react-native-spalla-player 0.13.3 → 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/LICENSE +2 -3
- package/SpallaPlayer.podspec +22 -0
- package/android/build.gradle +22 -58
- package/android/gradle.properties +5 -5
- package/android/src/main/AndroidManifest.xml +1 -2
- package/android/src/main/java/com/spallaplayer/RNSpallaPlayerEvent.kt +19 -0
- package/android/src/main/java/com/spallaplayer/SpallaPlayerModule.fabric.kt +103 -0
- package/android/src/main/java/com/spallaplayer/SpallaPlayerModule.kt +32 -21
- package/android/src/main/java/com/spallaplayer/SpallaPlayerPackage.kt +18 -4
- package/android/src/main/java/com/spallaplayer/SpallaPlayerView.kt +15 -0
- package/android/src/main/java/com/spallaplayer/SpallaPlayerViewManager.fabric.kt +289 -0
- package/android/src/main/java/com/spallaplayer/SpallaPlayerViewManager.kt +25 -27
- package/ios/SpallaPlayerModule.h +17 -0
- package/ios/SpallaPlayerModule.mm +59 -0
- package/ios/SpallaPlayerView.h +14 -0
- package/ios/SpallaPlayerView.mm +158 -0
- package/ios/SpallaPlayerWrapper.swift +12 -8
- package/lib/module/NativeSpallaPlayerModule.js +5 -0
- package/lib/module/NativeSpallaPlayerModule.js.map +1 -0
- package/lib/module/SpallaPlayerViewNativeComponent.js +11 -0
- package/lib/module/SpallaPlayerViewNativeComponent.js.map +1 -0
- package/lib/module/index.js +48 -55
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/NativeSpallaPlayerModule.d.ts +13 -0
- package/lib/typescript/src/NativeSpallaPlayerModule.d.ts.map +1 -0
- package/lib/typescript/src/SpallaPlayerViewNativeComponent.d.ts +33 -0
- package/lib/typescript/src/SpallaPlayerViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/src/components/CastButton.d.ts.map +1 -0
- package/lib/typescript/{module/src → src}/index.d.ts +9 -15
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/package.json +93 -103
- package/src/NativeSpallaPlayerModule.ts +14 -0
- package/src/SpallaPlayerViewNativeComponent.ts +61 -0
- package/src/index.tsx +71 -82
- package/android/src/main/AndroidManifestNew.xml +0 -2
- package/android/src/main/java/com/spallaplayer/SpallaPlayerContainerView.kt +0 -36
- package/ios/RNSpallaPlayer.m +0 -102
- package/ios/RNSpallaPlayer.swift +0 -11
- package/ios/SpallaPlayer-Bridging-Header.h +0 -1
- package/lib/commonjs/components/CastButton.js +0 -49
- package/lib/commonjs/components/CastButton.js.map +0 -1
- package/lib/commonjs/index.js +0 -81
- package/lib/commonjs/index.js.map +0 -1
- package/lib/typescript/commonjs/package.json +0 -1
- package/lib/typescript/commonjs/src/components/CastButton.d.ts.map +0 -1
- package/lib/typescript/commonjs/src/index.d.ts +0 -61
- package/lib/typescript/commonjs/src/index.d.ts.map +0 -1
- package/lib/typescript/module/src/components/CastButton.d.ts +0 -13
- package/lib/typescript/module/src/components/CastButton.d.ts.map +0 -1
- package/lib/typescript/module/src/index.d.ts.map +0 -1
- package/react-native-spalla-player.podspec +0 -44
- /package/lib/{typescript/module → module}/package.json +0 -0
- /package/lib/typescript/{commonjs/src → src}/components/CastButton.d.ts +0 -0
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
package com.spallaplayer
|
|
2
|
+
|
|
3
|
+
import android.util.Log
|
|
4
|
+
import android.view.View
|
|
5
|
+
import com.facebook.react.bridge.Arguments
|
|
6
|
+
import com.facebook.react.bridge.ReactContext
|
|
7
|
+
import com.facebook.react.bridge.ReadableArray
|
|
8
|
+
import com.facebook.react.bridge.WritableMap
|
|
9
|
+
import com.facebook.react.module.annotations.ReactModule
|
|
10
|
+
import com.facebook.react.uimanager.ViewGroupManager
|
|
11
|
+
import com.facebook.react.uimanager.ThemedReactContext
|
|
12
|
+
import com.facebook.react.uimanager.UIManagerHelper
|
|
13
|
+
import com.facebook.react.uimanager.annotations.ReactProp
|
|
14
|
+
import com.spalla.sdk.android.core.player.entities.SpallaPlayerEvent
|
|
15
|
+
import com.spalla.sdk.android.core.player.entities.SpallaPlayerEvent.*
|
|
16
|
+
import com.spalla.sdk.android.core.player.listeners.SpallaPlayerFullScreenListener
|
|
17
|
+
import com.spalla.sdk.android.core.player.listeners.SpallaPlayerListener
|
|
18
|
+
import com.spalla.sdk.android.core.player.view.SpallaPlayerView
|
|
19
|
+
import java.util.Timer
|
|
20
|
+
|
|
21
|
+
// These imports will work because Codegen runs for Fabric builds.
|
|
22
|
+
// Your IDE will show errors on these lines until you build the project.
|
|
23
|
+
import com.facebook.react.viewmanagers.SpallaPlayerViewManagerInterface
|
|
24
|
+
import com.facebook.react.viewmanagers.SpallaPlayerViewManagerDelegate
|
|
25
|
+
|
|
26
|
+
// Implement the Codegen interface for Fabric support
|
|
27
|
+
@ReactModule(name = SpallaPlayerViewManager.REACT_CLASS)
|
|
28
|
+
class SpallaPlayerViewManager() : ViewGroupManager<SpallaPlayerView>(),
|
|
29
|
+
SpallaPlayerViewManagerInterface<SpallaPlayerView>, // Fabric interface
|
|
30
|
+
SpallaPlayerListener, SpallaPlayerFullScreenListener {
|
|
31
|
+
|
|
32
|
+
companion object {
|
|
33
|
+
const val REACT_CLASS = "SpallaPlayerView"
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// The delegate is required for Fabric to handle props and commands.
|
|
37
|
+
private val mDelegate = SpallaPlayerViewManagerDelegate(this)
|
|
38
|
+
|
|
39
|
+
// This method is required by the Fabric architecture.
|
|
40
|
+
override fun getDelegate() = mDelegate
|
|
41
|
+
|
|
42
|
+
private var _playerView: SpallaPlayerView? = null
|
|
43
|
+
private var _reactContext: ReactContext? = null
|
|
44
|
+
//private var _container: SpallaPlayerView? = null
|
|
45
|
+
private var contentId: String? = null
|
|
46
|
+
private var startTime: Double? = null
|
|
47
|
+
private var subtitle: String? = null
|
|
48
|
+
private var loadTimer: Timer? = null
|
|
49
|
+
private var playbackRate: Double = 1.0
|
|
50
|
+
private var hideUI: Boolean? = null
|
|
51
|
+
private var _viewTag: Int = -1
|
|
52
|
+
|
|
53
|
+
override fun getName() = REACT_CLASS
|
|
54
|
+
|
|
55
|
+
override fun createViewInstance(context: ThemedReactContext): SpallaPlayerView {
|
|
56
|
+
_reactContext = context
|
|
57
|
+
//val container = SpallaPlayerContainerView(context)
|
|
58
|
+
val player = SpallaPlayerView(context)
|
|
59
|
+
|
|
60
|
+
// Defer initialization until view is attached to window
|
|
61
|
+
player.addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener {
|
|
62
|
+
override fun onViewAttachedToWindow(view: View) {
|
|
63
|
+
try {
|
|
64
|
+
_playerView = player
|
|
65
|
+
_playerView?.registerPlayerListener(this@SpallaPlayerViewManager)
|
|
66
|
+
_playerView?.registerFullScreenListener(this@SpallaPlayerViewManager)
|
|
67
|
+
// Remove listener to avoid memory leaks
|
|
68
|
+
view.removeOnAttachStateChangeListener(this)
|
|
69
|
+
|
|
70
|
+
checkAndLoadPlayer(player)
|
|
71
|
+
} catch (e: Exception) {
|
|
72
|
+
Log.e("SpallaPlayerViewManager", "Error during view attachment", e)
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
override fun onViewDetachedFromWindow(view: View) {
|
|
77
|
+
_playerView?.pause()
|
|
78
|
+
|
|
79
|
+
}
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
//this._container = container
|
|
83
|
+
//return container
|
|
84
|
+
return player
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
override fun onDropViewInstance(view: SpallaPlayerView) {
|
|
88
|
+
Log.v("RNSpallaPlayerManager", "onDropViewInstance")
|
|
89
|
+
try {
|
|
90
|
+
view.onDestroy()
|
|
91
|
+
} catch (e: Exception) {
|
|
92
|
+
e.printStackTrace()
|
|
93
|
+
}
|
|
94
|
+
super.onDropViewInstance(view)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// --- Prop Setters ---
|
|
98
|
+
@ReactProp(name = "contentId")
|
|
99
|
+
override fun setContentId(view: SpallaPlayerView, value: String?) {
|
|
100
|
+
_viewTag = view.tag as? Int ?: -1
|
|
101
|
+
if (value != null) {
|
|
102
|
+
this.contentId = value
|
|
103
|
+
//add a hacky delay here, so if content and starttime are changed at same time,
|
|
104
|
+
//start time is set first
|
|
105
|
+
view.postDelayed({
|
|
106
|
+
checkAndLoadPlayer(view)
|
|
107
|
+
}, 100L)
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
@ReactProp(name = "muted")
|
|
112
|
+
override fun setMuted(view: SpallaPlayerView, value: Boolean) {
|
|
113
|
+
_playerView?.setMuted(value)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
@ReactProp(name = "startTime")
|
|
117
|
+
override fun setStartTime(view: SpallaPlayerView, value: Double) {
|
|
118
|
+
this.startTime = value
|
|
119
|
+
//checkAndLoadPlayer(view)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
@ReactProp(name = "subtitle")
|
|
123
|
+
override fun setSubtitle(view: SpallaPlayerView, value: String?) {
|
|
124
|
+
this.subtitle = value
|
|
125
|
+
_playerView?.selectSubtitle(subtitle)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
@ReactProp(name = "playbackRate")
|
|
129
|
+
override fun setPlaybackRate(view: SpallaPlayerView, value: Float) {
|
|
130
|
+
if (value > 0) {
|
|
131
|
+
this.playbackRate = value.toDouble()
|
|
132
|
+
_playerView?.selectPlaybackRate(playbackRate)
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
@ReactProp(name = "hideUI")
|
|
137
|
+
override fun setHideUI(view: SpallaPlayerView, value: Boolean) {
|
|
138
|
+
this.hideUI = value
|
|
139
|
+
//checkAndLoadPlayer(view)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
override fun play(view: SpallaPlayerView?) {
|
|
143
|
+
view?.play()
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
override fun pause(view: SpallaPlayerView?) {
|
|
147
|
+
view?.pause()
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
override fun seekTo(
|
|
151
|
+
view: SpallaPlayerView?,
|
|
152
|
+
time: Double
|
|
153
|
+
) {
|
|
154
|
+
view?.seekTo(time)
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
override fun selectSubtitle(
|
|
158
|
+
view: SpallaPlayerView?,
|
|
159
|
+
subtitle: String?
|
|
160
|
+
) {
|
|
161
|
+
view?.selectSubtitle(subtitle)
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
override fun selectPlaybackRate(
|
|
165
|
+
view: SpallaPlayerView?,
|
|
166
|
+
rate: Float
|
|
167
|
+
) {
|
|
168
|
+
view?.selectPlaybackRate(rate.toDouble())
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
override fun unmount(view: SpallaPlayerView?) {
|
|
172
|
+
view?.pause()
|
|
173
|
+
view?.onDestroy()
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
private fun checkAndLoadPlayer(view: SpallaPlayerView) {
|
|
177
|
+
try {
|
|
178
|
+
// Only load if view is attached to window and all required props are set
|
|
179
|
+
if (contentId != null && startTime != null && hideUI != null && view.isAttachedToWindow) {
|
|
180
|
+
view.load(contentId!!, true, startTime!!, subtitle, hideUI!!)
|
|
181
|
+
}
|
|
182
|
+
} catch (e: Exception) {
|
|
183
|
+
Log.e("SpallaPlayerViewManager", "Error loading player", e)
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// --- Command Handling ---
|
|
188
|
+
override fun receiveCommand(
|
|
189
|
+
root: SpallaPlayerView,
|
|
190
|
+
commandId: String,
|
|
191
|
+
args: ReadableArray?
|
|
192
|
+
) {
|
|
193
|
+
mDelegate.receiveCommand(root, commandId, args)
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// --- Event Handling ---
|
|
197
|
+
override fun getExportedCustomBubblingEventTypeConstants(): MutableMap<String, Any> {
|
|
198
|
+
return mutableMapOf(
|
|
199
|
+
"onPlayerEvent" to mapOf(
|
|
200
|
+
"phasedRegistrationNames" to mapOf(
|
|
201
|
+
"bubbled" to "onPlayerEvent"
|
|
202
|
+
)
|
|
203
|
+
)
|
|
204
|
+
)
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
override fun onEvent(event: SpallaPlayerEvent) {
|
|
208
|
+
val map: WritableMap = Arguments.createMap()
|
|
209
|
+
val eventName = "onPlayerEvent"
|
|
210
|
+
|
|
211
|
+
Log.v("RNSpallaPlayerManager", "onEvent: $event")
|
|
212
|
+
when (event) {
|
|
213
|
+
is DurationUpdate -> {
|
|
214
|
+
map.putString("event", "durationUpdate")
|
|
215
|
+
map.putDouble("duration", event.duration)
|
|
216
|
+
}
|
|
217
|
+
Ended -> map.putString("event", "ended")
|
|
218
|
+
is Error -> {
|
|
219
|
+
map.putString("event", "error")
|
|
220
|
+
map.putString("message", event.message)
|
|
221
|
+
}
|
|
222
|
+
Pause -> map.putString("event", "pause")
|
|
223
|
+
Play -> map.putString("event", "play")
|
|
224
|
+
Playing -> map.putString("event", "playing")
|
|
225
|
+
is TimeUpdate -> {
|
|
226
|
+
map.putString("event", "timeUpdate")
|
|
227
|
+
map.putDouble("time", event.currentTime)
|
|
228
|
+
}
|
|
229
|
+
Waiting -> map.putString("event", "buffering")
|
|
230
|
+
is SubtitlesAvailable -> {
|
|
231
|
+
map.putString("event", "subtitlesAvailable")
|
|
232
|
+
val subs = Arguments.createArray()
|
|
233
|
+
event.subtitles.forEach { subs.pushString(it) }
|
|
234
|
+
map.putArray("subtitles", subs)
|
|
235
|
+
}
|
|
236
|
+
is SubtitleSelected -> {
|
|
237
|
+
map.putString("event", "subtitleSelected")
|
|
238
|
+
map.putString("subtitle", event.subtitle)
|
|
239
|
+
}
|
|
240
|
+
is MetadataLoaded -> {
|
|
241
|
+
map.putString("event", "metadataLoaded")
|
|
242
|
+
map.putBoolean("isLive", event.metadata.isLive)
|
|
243
|
+
map.putDouble("duration", event.metadata.duration)
|
|
244
|
+
_playerView?.selectPlaybackRate(playbackRate)
|
|
245
|
+
}
|
|
246
|
+
is PlaybackRateSelected -> {
|
|
247
|
+
map.putString("event", "playbackRateSelected")
|
|
248
|
+
map.putDouble("rate", event.rate)
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
_playerView?.let { view ->
|
|
253
|
+
_reactContext?.let { reactContext ->
|
|
254
|
+
val surfaceId = UIManagerHelper.getSurfaceId(reactContext)
|
|
255
|
+
val eventDispatcher = UIManagerHelper.getEventDispatcherForReactTag(reactContext, view.id)
|
|
256
|
+
eventDispatcher?.dispatchEvent(
|
|
257
|
+
RNSpallaPlayerEvent(surfaceId, view.id, eventName, map)
|
|
258
|
+
)
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
override fun onEnterFullScreen() {
|
|
264
|
+
val map: WritableMap = Arguments.createMap()
|
|
265
|
+
map.putString("event", "enterFullScreen")
|
|
266
|
+
dispatchEvent("onPlayerEvent", map)
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
override fun onExitFullScreen() {
|
|
270
|
+
val map: WritableMap = Arguments.createMap()
|
|
271
|
+
map.putString("event", "exitFullScreen")
|
|
272
|
+
dispatchEvent("onPlayerEvent", map)
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
private fun dispatchEvent(eventName: String, eventData: WritableMap) {
|
|
276
|
+
_playerView?.let { view ->
|
|
277
|
+
_reactContext?.let { reactContext ->
|
|
278
|
+
if (_viewTag != -1) {
|
|
279
|
+
val surfaceId = UIManagerHelper.getSurfaceId(reactContext)
|
|
280
|
+
val eventDispatcher = UIManagerHelper.getEventDispatcherForReactTag(reactContext, view.id)
|
|
281
|
+
eventDispatcher?.dispatchEvent(
|
|
282
|
+
RNSpallaPlayerEvent(surfaceId, _viewTag, eventName, eventData)
|
|
283
|
+
)
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
}
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
package com.spallaplayer
|
|
2
|
-
|
|
3
1
|
import android.util.Log
|
|
4
2
|
import android.view.View
|
|
5
3
|
import com.facebook.react.bridge.Arguments
|
|
@@ -14,14 +12,16 @@ import com.spalla.sdk.android.core.player.entities.SpallaPlayerEvent.*
|
|
|
14
12
|
import com.spalla.sdk.android.core.player.listeners.SpallaPlayerFullScreenListener
|
|
15
13
|
import com.spalla.sdk.android.core.player.listeners.SpallaPlayerListener
|
|
16
14
|
import com.spalla.sdk.android.core.player.view.SpallaPlayerView
|
|
15
|
+
|
|
16
|
+
|
|
17
17
|
import java.util.Timer
|
|
18
18
|
import java.util.TimerTask
|
|
19
19
|
|
|
20
|
-
class
|
|
20
|
+
class SpallaPlayerViewManager() : ViewGroupManager<SpallaPlayerView>(),
|
|
21
21
|
SpallaPlayerListener, SpallaPlayerFullScreenListener {
|
|
22
22
|
private var _playerView: SpallaPlayerView? = null
|
|
23
23
|
private var _reactContext: ReactContext? = null
|
|
24
|
-
private var _container: SpallaPlayerContainerView? = null
|
|
24
|
+
//private var _container: SpallaPlayerContainerView? = null
|
|
25
25
|
|
|
26
26
|
private var contentId: String? = null
|
|
27
27
|
private var startTime: Double? = null
|
|
@@ -32,15 +32,13 @@ class RNSpallaPlayerManager() : ViewGroupManager<SpallaPlayerContainerView>(),
|
|
|
32
32
|
|
|
33
33
|
override fun getName() = "RNSpallaPlayer"
|
|
34
34
|
|
|
35
|
-
override fun createViewInstance(context: ThemedReactContext):
|
|
35
|
+
override fun createViewInstance(context: ThemedReactContext): SpallaPlayerView {
|
|
36
36
|
_reactContext = context
|
|
37
|
-
val
|
|
38
|
-
_playerView =
|
|
37
|
+
val player = SpallaPlayerView(context)
|
|
38
|
+
_playerView = player
|
|
39
39
|
_playerView?.registerPlayerListener(this)
|
|
40
40
|
_playerView?.registerFullScreenListener(this)
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
return container
|
|
41
|
+
return player
|
|
44
42
|
}
|
|
45
43
|
|
|
46
44
|
override fun getExportedCustomBubblingEventTypeConstants(): MutableMap<String, Any> {
|
|
@@ -55,58 +53,58 @@ class RNSpallaPlayerManager() : ViewGroupManager<SpallaPlayerContainerView>(),
|
|
|
55
53
|
return eventMap
|
|
56
54
|
}
|
|
57
55
|
|
|
58
|
-
override fun onDropViewInstance(view:
|
|
56
|
+
override fun onDropViewInstance(view: SpallaPlayerView) {
|
|
59
57
|
Log.v("RNSpallaPlayerManager", "onDropViewInstance")
|
|
60
58
|
|
|
61
59
|
try {
|
|
62
|
-
view.
|
|
60
|
+
view.onDestroy()
|
|
63
61
|
} catch (e: Exception) {
|
|
64
62
|
e.printStackTrace()
|
|
65
63
|
}
|
|
66
64
|
super.onDropViewInstance(view)
|
|
67
65
|
}
|
|
68
66
|
|
|
69
|
-
override fun addView(parent:
|
|
67
|
+
override fun addView(parent: SpallaPlayerView, child: View, index: Int) {
|
|
70
68
|
parent.addView(child, index)
|
|
71
69
|
}
|
|
72
70
|
|
|
73
|
-
override fun removeViewAt(parent:
|
|
71
|
+
override fun removeViewAt(parent: SpallaPlayerView, index: Int) {
|
|
74
72
|
parent.removeViewAt(index)
|
|
75
73
|
}
|
|
76
74
|
|
|
77
|
-
override fun getChildCount(parent:
|
|
75
|
+
override fun getChildCount(parent: SpallaPlayerView): Int {
|
|
78
76
|
return parent.childCount
|
|
79
77
|
}
|
|
80
78
|
|
|
81
|
-
override fun getChildAt(parent:
|
|
79
|
+
override fun getChildAt(parent: SpallaPlayerView, index: Int): View {
|
|
82
80
|
return parent.getChildAt(index)
|
|
83
81
|
}
|
|
84
82
|
|
|
85
83
|
@ReactProp(name = "contentId")
|
|
86
|
-
fun setContentId(view:
|
|
84
|
+
fun setContentId(view: SpallaPlayerView, contentId: String) {
|
|
87
85
|
this.contentId = contentId
|
|
88
86
|
checkAndLoadPlayer(view)
|
|
89
87
|
}
|
|
90
88
|
|
|
91
89
|
@ReactProp(name = "muted")
|
|
92
|
-
fun setMuted(view:
|
|
90
|
+
fun setMuted(view: SpallaPlayerView, muted: Boolean) {
|
|
93
91
|
_playerView?.setMuted(muted)
|
|
94
92
|
}
|
|
95
93
|
|
|
96
94
|
@ReactProp(name = "startTime")
|
|
97
|
-
fun setStartTime(view:
|
|
95
|
+
fun setStartTime(view: SpallaPlayerView, startTime: Double) {
|
|
98
96
|
this.startTime = startTime
|
|
99
97
|
//checkAndLoadPlayer(view)
|
|
100
98
|
}
|
|
101
99
|
|
|
102
100
|
@ReactProp(name = "subtitle")
|
|
103
|
-
fun setSubtitle(view:
|
|
101
|
+
fun setSubtitle(view: SpallaPlayerView, subtitle: String?) {
|
|
104
102
|
this.subtitle = subtitle
|
|
105
103
|
_playerView?.selectSubtitle(subtitle)
|
|
106
104
|
}
|
|
107
105
|
|
|
108
106
|
@ReactProp(name = "playbackRate")
|
|
109
|
-
fun setPlaybackRate(view:
|
|
107
|
+
fun setPlaybackRate(view: SpallaPlayerView, playbackRate: Double) {
|
|
110
108
|
if (playbackRate > 0) {
|
|
111
109
|
this.playbackRate = playbackRate
|
|
112
110
|
_playerView?.selectPlaybackRate(playbackRate)
|
|
@@ -114,14 +112,14 @@ class RNSpallaPlayerManager() : ViewGroupManager<SpallaPlayerContainerView>(),
|
|
|
114
112
|
}
|
|
115
113
|
|
|
116
114
|
@ReactProp(name = "hideUI")
|
|
117
|
-
fun
|
|
115
|
+
fun setHideUI(view: SpallaPlayerView, hideUI: Boolean) {
|
|
118
116
|
this.hideUI = hideUI
|
|
119
117
|
checkAndLoadPlayer(view)
|
|
120
118
|
}
|
|
121
119
|
|
|
122
|
-
private fun checkAndLoadPlayer(view:
|
|
120
|
+
private fun checkAndLoadPlayer(view: SpallaPlayerView) {
|
|
123
121
|
if (contentId != null && startTime != null && hideUI != null) {
|
|
124
|
-
view.
|
|
122
|
+
view.load(contentId!!, true, startTime!!, subtitle, hideUI!!)
|
|
125
123
|
}
|
|
126
124
|
}
|
|
127
125
|
|
|
@@ -196,7 +194,7 @@ class RNSpallaPlayerManager() : ViewGroupManager<SpallaPlayerContainerView>(),
|
|
|
196
194
|
}
|
|
197
195
|
|
|
198
196
|
}
|
|
199
|
-
|
|
197
|
+
_playerView?.let { container ->
|
|
200
198
|
_reactContext?.getJSModule(RCTEventEmitter::class.java)?.receiveEvent(
|
|
201
199
|
container.id,
|
|
202
200
|
"onPlayerEvent",
|
|
@@ -209,7 +207,7 @@ class RNSpallaPlayerManager() : ViewGroupManager<SpallaPlayerContainerView>(),
|
|
|
209
207
|
Log.v("SpallaPlayerViewManager", "onEnterFullScreen")
|
|
210
208
|
val map: WritableMap = Arguments.createMap()
|
|
211
209
|
map.putString("event", "enterFullScreen")
|
|
212
|
-
|
|
210
|
+
_playerView?.let { container ->
|
|
213
211
|
_reactContext?.getJSModule(RCTEventEmitter::class.java)?.receiveEvent(
|
|
214
212
|
container.id,
|
|
215
213
|
"onPlayerEvent",
|
|
@@ -221,7 +219,7 @@ class RNSpallaPlayerManager() : ViewGroupManager<SpallaPlayerContainerView>(),
|
|
|
221
219
|
override fun onExitFullScreen() {
|
|
222
220
|
val map: WritableMap = Arguments.createMap()
|
|
223
221
|
map.putString("event", "exitFullScreen")
|
|
224
|
-
|
|
222
|
+
_playerView?.let { container ->
|
|
225
223
|
_reactContext?.getJSModule(RCTEventEmitter::class.java)?.receiveEvent(
|
|
226
224
|
container.id,
|
|
227
225
|
"onPlayerEvent",
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
//
|
|
2
|
+
// SpallaPlayerModule.h
|
|
3
|
+
// Pods
|
|
4
|
+
//
|
|
5
|
+
// Created by Rogerio Shimizu on 12/19/25.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
#import <Foundation/Foundation.h>
|
|
9
|
+
#import <SpallaPlayerViewSpec/SpallaPlayerViewSpec.h>
|
|
10
|
+
|
|
11
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
12
|
+
|
|
13
|
+
@interface SpallaPlayerModule : NSObject <NativeSpallaPlayerModuleSpec>
|
|
14
|
+
|
|
15
|
+
@end
|
|
16
|
+
|
|
17
|
+
NS_ASSUME_NONNULL_END
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
//
|
|
2
|
+
// SpallaPlayerModule.mm
|
|
3
|
+
// Pods
|
|
4
|
+
//
|
|
5
|
+
// Created by Rogerio Shimizu on 12/19/25.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
#import "SpallaPlayerModule.h"
|
|
9
|
+
#import "SpallaPlayer-Swift.h"
|
|
10
|
+
|
|
11
|
+
@interface SpallaPlayerModule ()
|
|
12
|
+
|
|
13
|
+
@end
|
|
14
|
+
|
|
15
|
+
@implementation SpallaPlayerModule
|
|
16
|
+
|
|
17
|
+
+ (NSString *)moduleName
|
|
18
|
+
{
|
|
19
|
+
return @"SpallaPlayerModule";
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const facebook::react::ObjCTurboModule::InitParams &)params {
|
|
23
|
+
return std::make_shared<facebook::react::NativeSpallaPlayerModuleSpecJSI>(params);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
- (void)initialize:(nonnull NSString *)token applicationId:(nonnull NSString *)applicationId {
|
|
27
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
28
|
+
[SpallaPlayerWrapper initializeWithToken: token applicationId: applicationId];
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
- (void)pause:(NSInteger)tag {
|
|
33
|
+
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
- (void)play:(NSInteger)tag {
|
|
37
|
+
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
- (void)seekTo:(NSInteger)tag time:(double)time {
|
|
41
|
+
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
- (void)selectPlaybackRate:(NSInteger)tag rate:(double)rate {
|
|
45
|
+
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
- (void)selectSubtitle:(NSInteger)tag subtitle:(NSString * _Nullable)subtitle {
|
|
49
|
+
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
- (void)unmount:(NSInteger)tag {
|
|
53
|
+
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
@end
|
|
58
|
+
|
|
59
|
+
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#import <React/RCTViewComponentView.h>
|
|
2
|
+
#import <UIKit/UIKit.h>
|
|
3
|
+
|
|
4
|
+
#ifndef SpallaPlayerViewNativeComponent_h
|
|
5
|
+
#define SpallaPlayerViewNativeComponent_h
|
|
6
|
+
|
|
7
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
8
|
+
|
|
9
|
+
@interface SpallaPlayerView : RCTViewComponentView
|
|
10
|
+
@end
|
|
11
|
+
|
|
12
|
+
NS_ASSUME_NONNULL_END
|
|
13
|
+
|
|
14
|
+
#endif /* SpallaPlayerViewNativeComponent_h */
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
#import "SpallaPlayerView.h"
|
|
2
|
+
|
|
3
|
+
#import <react/renderer/components/SpallaPlayerViewSpec/ComponentDescriptors.h>
|
|
4
|
+
#import <react/renderer/components/SpallaPlayerViewSpec/EventEmitters.h>
|
|
5
|
+
#import <react/renderer/components/SpallaPlayerViewSpec/Props.h>
|
|
6
|
+
#import <react/renderer/components/SpallaPlayerViewSpec/RCTComponentViewHelpers.h>
|
|
7
|
+
|
|
8
|
+
#import "RCTFabricComponentsPlugins.h"
|
|
9
|
+
#import "SpallaPlayer-Swift.h"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
using namespace facebook::react;
|
|
13
|
+
|
|
14
|
+
@interface SpallaPlayerView () <RCTSpallaPlayerViewViewProtocol>
|
|
15
|
+
|
|
16
|
+
@end
|
|
17
|
+
|
|
18
|
+
@implementation SpallaPlayerView {
|
|
19
|
+
SpallaPlayerWrapper * _view;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
+ (ComponentDescriptorProvider)componentDescriptorProvider
|
|
23
|
+
{
|
|
24
|
+
return concreteComponentDescriptorProvider<SpallaPlayerViewComponentDescriptor>();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
- (instancetype)initWithFrame:(CGRect)frame
|
|
28
|
+
{
|
|
29
|
+
if (self = [super initWithFrame:frame]) {
|
|
30
|
+
static const auto defaultProps = std::make_shared<const SpallaPlayerViewProps>();
|
|
31
|
+
_props = defaultProps;
|
|
32
|
+
|
|
33
|
+
[self ensureFreshWrapper];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return self;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
|
|
40
|
+
{
|
|
41
|
+
const auto &oldViewProps = *std::static_pointer_cast<SpallaPlayerViewProps const>(_props);
|
|
42
|
+
const auto &newViewProps = *std::static_pointer_cast<SpallaPlayerViewProps const>(props);
|
|
43
|
+
|
|
44
|
+
BOOL didRefresh = [self ensureFreshWrapper];
|
|
45
|
+
|
|
46
|
+
if (oldViewProps.contentId != newViewProps.contentId || didRefresh) {
|
|
47
|
+
[_view setContentId: [[NSString alloc] initWithUTF8String: newViewProps.contentId.c_str()]];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (oldViewProps.startTime != newViewProps.startTime || didRefresh) {
|
|
51
|
+
[_view setStartTime: [NSNumber numberWithDouble: newViewProps.startTime]];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (oldViewProps.hideUI != newViewProps.hideUI || didRefresh) {
|
|
55
|
+
[_view setHideUI: newViewProps.hideUI];
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (oldViewProps.muted != newViewProps.muted || didRefresh) {
|
|
59
|
+
[_view setMuted: newViewProps.muted];
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (oldViewProps.playbackRate != newViewProps.playbackRate || didRefresh) {
|
|
63
|
+
[_view setPlaybackRate: [NSNumber numberWithDouble: newViewProps.playbackRate]];
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (oldViewProps.subtitle != newViewProps.subtitle || didRefresh) {
|
|
67
|
+
// SpallaPlayerViewProps::subtitle is a std::string (not an optional), so use empty() to check for "no subtitle".
|
|
68
|
+
if (!newViewProps.subtitle.empty()) {
|
|
69
|
+
[_view setSubtitle: [[NSString alloc] initWithUTF8String: newViewProps.subtitle.c_str()]];
|
|
70
|
+
} else {
|
|
71
|
+
[_view setSubtitle: nil];
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
[super updateProps:props oldProps:oldProps];
|
|
76
|
+
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
- (BOOL)ensureFreshWrapper {
|
|
80
|
+
if (_view == nil) {
|
|
81
|
+
_view = [[SpallaPlayerWrapper alloc] init];
|
|
82
|
+
|
|
83
|
+
__weak __typeof(self) weakSelf = self;
|
|
84
|
+
[_view setOnPlayerEvent:^(NSDictionary<NSString *,id> * _Nonnull value) {
|
|
85
|
+
SpallaPlayerViewEventEmitter::OnPlayerEvent event = SpallaPlayerViewEventEmitter::OnPlayerEvent{
|
|
86
|
+
.event = std::string([[value objectForKey:@"event"] UTF8String]),
|
|
87
|
+
.duration = value[@"duration"] != nil ? [value[@"duration"] doubleValue] : 0.0,
|
|
88
|
+
.time = value[@"time"] != nil ? [value[@"time"] doubleValue] : 0.0,
|
|
89
|
+
.rate = value[@"rate"] != nil ? [value[@"rate"] doubleValue] : 0.0,
|
|
90
|
+
.subtitle = value[@"subtitle"] != nil ? std::string([value[@"subtitle"] UTF8String]) : std::string(),
|
|
91
|
+
.isLive = value[@"isLive"] != nil ? [value[@"isLive"] boolValue] : false,
|
|
92
|
+
.error = value[@"error"] != nil ? std::string([value[@"error"] UTF8String]) : std::string()
|
|
93
|
+
|
|
94
|
+
};
|
|
95
|
+
weakSelf.eventEmitter.onPlayerEvent(event);
|
|
96
|
+
}];
|
|
97
|
+
|
|
98
|
+
self.contentView = _view;
|
|
99
|
+
return YES;
|
|
100
|
+
}
|
|
101
|
+
return NO;
|
|
102
|
+
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
- (void)updateState:(const facebook::react::State::Shared &)state
|
|
106
|
+
oldState:(const facebook::react::State::Shared &)oldState {
|
|
107
|
+
[super updateState:state oldState:oldState];
|
|
108
|
+
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
- (void)handleCommand:(const NSString *)commandName args:(const NSArray *)args
|
|
112
|
+
{
|
|
113
|
+
RCTSpallaPlayerViewHandleCommand(self, commandName, args);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
- (void)pause {
|
|
117
|
+
[_view pause];
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
- (void)play {
|
|
121
|
+
[_view play];
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
- (void) seekTo:(double)time {
|
|
125
|
+
[_view seekToTime: time];
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
- (void) selectPlaybackRate:(float)rate {
|
|
129
|
+
[_view selectPlaybackRate: rate];
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
- (void) selectSubtitle:(NSString *)subtitle {
|
|
133
|
+
[_view selectSubtitle: subtitle];
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
- (void) unmount {
|
|
137
|
+
[_view unmount];
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
- (void)prepareForRecycle {
|
|
141
|
+
[super prepareForRecycle];
|
|
142
|
+
|
|
143
|
+
[_view setOnPlayerEvent: nil];
|
|
144
|
+
[_view unmount];
|
|
145
|
+
_view = nil;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
- (const SpallaPlayerViewEventEmitter &)eventEmitter
|
|
149
|
+
{
|
|
150
|
+
return static_cast<const SpallaPlayerViewEventEmitter &>(*_eventEmitter);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
Class<RCTComponentViewProtocol> SpallaPlayerViewCls(void)
|
|
154
|
+
{
|
|
155
|
+
return SpallaPlayerView.class;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
@end
|