react-native-spalla-player 1.0.0 → 1.0.1
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/android/src/main/java/com/spallaplayer/SpallaPlayerModule.kt +63 -160
- package/android/src/main/java/com/spallaplayer/SpallaPlayerPackage.kt +2 -4
- package/android/src/main/java/com/spallaplayer/SpallaPlayerViewManager.kt +160 -101
- package/package.json +1 -1
- package/android/src/main/java/com/spallaplayer/SpallaPlayerModule.fabric.kt +0 -103
- package/android/src/main/java/com/spallaplayer/SpallaPlayerView.kt +0 -15
- package/android/src/main/java/com/spallaplayer/SpallaPlayerViewManager.fabric.kt +0 -289
|
@@ -1,204 +1,107 @@
|
|
|
1
1
|
package com.spallaplayer
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
import android.util.Log
|
|
4
4
|
import com.facebook.react.bridge.ReactApplicationContext
|
|
5
5
|
import com.facebook.react.bridge.ReactContextBaseJavaModule
|
|
6
6
|
import com.facebook.react.bridge.ReactMethod
|
|
7
7
|
import com.facebook.react.bridge.UIManager
|
|
8
|
-
import com.facebook.react.uimanager.NativeViewHierarchyManager
|
|
9
8
|
import com.facebook.react.uimanager.UIManagerHelper
|
|
10
|
-
import com.facebook.react.uimanager.UIManagerModule
|
|
11
9
|
import com.facebook.react.uimanager.common.UIManagerType
|
|
12
10
|
import com.spalla.sdk.android.core.SpallaSDK
|
|
13
11
|
import com.spalla.sdk.android.core.player.view.SpallaPlayerView
|
|
14
12
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
LifecycleEventListener {
|
|
19
|
-
private val _reactContext: ReactApplicationContext
|
|
13
|
+
class SpallaPlayerModule(
|
|
14
|
+
val reactContext: ReactApplicationContext
|
|
15
|
+
): ReactContextBaseJavaModule(reactContext) {
|
|
20
16
|
|
|
21
17
|
companion object {
|
|
22
|
-
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
init {
|
|
27
|
-
reactContext.addLifecycleEventListener(this)
|
|
28
|
-
_reactContext = reactContext
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
private fun isFabric(): Boolean {
|
|
32
|
-
val uiManager = UIManagerHelper.getUIManager(this._reactContext, UIManagerType.FABRIC)
|
|
33
|
-
// In Fabric, the UIManager is an instance of "FabricUIManager"
|
|
34
|
-
return uiManager?.javaClass?.simpleName == "FabricUIManager"
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
override fun getName(): String {
|
|
38
|
-
return "RNSpallaPlayer"
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
override fun onHostResume() {
|
|
18
|
+
val REACT_NAME: String = "SpallaPlayerModule"
|
|
42
19
|
}
|
|
43
20
|
|
|
44
|
-
override fun
|
|
21
|
+
override fun getName() = REACT_NAME
|
|
45
22
|
|
|
23
|
+
@ReactMethod
|
|
24
|
+
fun play(tag: Double) {
|
|
25
|
+
reactContext.runOnUiQueueThread {
|
|
26
|
+
val view = getSpallaPlayerView(tag)
|
|
27
|
+
view?.play()
|
|
28
|
+
}
|
|
46
29
|
}
|
|
47
30
|
|
|
48
|
-
|
|
31
|
+
@ReactMethod
|
|
32
|
+
fun pause(tag: Double) {
|
|
33
|
+
reactContext.runOnUiQueueThread {
|
|
34
|
+
val view = getSpallaPlayerView(tag)
|
|
35
|
+
view?.pause()
|
|
36
|
+
}
|
|
49
37
|
}
|
|
50
38
|
|
|
51
39
|
@ReactMethod
|
|
52
|
-
fun
|
|
53
|
-
|
|
54
|
-
val
|
|
55
|
-
|
|
56
|
-
uiManager.resolveView(tag)?.let { view ->
|
|
57
|
-
if (view is SpallaPlayerView) {
|
|
58
|
-
view.play()
|
|
59
|
-
} else {
|
|
60
|
-
throw ClassCastException(
|
|
61
|
-
"Cannot play: view with tag #$tag is not a SpallaPlayerView"
|
|
62
|
-
)
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
} else {
|
|
67
|
-
val uiManager: UIManagerModule? =
|
|
68
|
-
_reactContext.getNativeModule(UIManagerModule::class.java)
|
|
69
|
-
uiManager?.prependUIBlock { nativeViewHierarchyManager: NativeViewHierarchyManager ->
|
|
70
|
-
val playerView = nativeViewHierarchyManager.resolveView(tag)
|
|
71
|
-
if (playerView is SpallaPlayerView) {
|
|
72
|
-
playerView.play()
|
|
73
|
-
} else {
|
|
74
|
-
throw ClassCastException(
|
|
75
|
-
String.format(
|
|
76
|
-
"Cannot play: view with tag #%d is not a SpallaPlayerView",
|
|
77
|
-
tag
|
|
78
|
-
)
|
|
79
|
-
)
|
|
80
|
-
}
|
|
81
|
-
}
|
|
40
|
+
fun seekTo(tag: Double, time: Double) {
|
|
41
|
+
reactContext.runOnUiQueueThread {
|
|
42
|
+
val view = getSpallaPlayerView(tag)
|
|
43
|
+
view?.seekTo(time)
|
|
82
44
|
}
|
|
83
45
|
}
|
|
84
46
|
|
|
85
47
|
@ReactMethod
|
|
86
|
-
fun
|
|
87
|
-
|
|
88
|
-
val
|
|
89
|
-
|
|
90
|
-
uiManager.resolveView(tag)?.let { view ->
|
|
91
|
-
if (view is SpallaPlayerView) {
|
|
92
|
-
view.pause()
|
|
93
|
-
} else {
|
|
94
|
-
throw ClassCastException(
|
|
95
|
-
"Cannot pause: view with tag #$tag is not a SpallaPlayerView"
|
|
96
|
-
)
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
} else {
|
|
101
|
-
val uiManager: UIManagerModule? =
|
|
102
|
-
_reactContext.getNativeModule(UIManagerModule::class.java)
|
|
103
|
-
uiManager?.prependUIBlock { nativeViewHierarchyManager: NativeViewHierarchyManager ->
|
|
104
|
-
val playerView = nativeViewHierarchyManager.resolveView(tag)
|
|
105
|
-
if (playerView is SpallaPlayerView) {
|
|
106
|
-
playerView.pause()
|
|
107
|
-
} else {
|
|
108
|
-
throw ClassCastException(
|
|
109
|
-
String.format(
|
|
110
|
-
"Cannot play: view with tag #%d is not a SpallaPplayerView",
|
|
111
|
-
tag
|
|
112
|
-
)
|
|
113
|
-
)
|
|
114
|
-
}
|
|
115
|
-
}
|
|
48
|
+
fun selectSubtitle(tag: Double, subtitle: String?) {
|
|
49
|
+
reactContext.runOnUiQueueThread {
|
|
50
|
+
val view = getSpallaPlayerView(tag)
|
|
51
|
+
view?.selectSubtitle(subtitle)
|
|
116
52
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
53
|
}
|
|
120
54
|
|
|
121
55
|
@ReactMethod
|
|
122
|
-
fun
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
playerView.seekTo(time)
|
|
128
|
-
} else {
|
|
129
|
-
throw ClassCastException(
|
|
130
|
-
String.format(
|
|
131
|
-
"Cannot play: view with tag #%d is not a SpallaPplayerView",
|
|
132
|
-
tag
|
|
133
|
-
)
|
|
134
|
-
)
|
|
135
|
-
}
|
|
136
|
-
}
|
|
56
|
+
fun selectPlaybackRate(tag: Double, rate: Double) {
|
|
57
|
+
reactContext.runOnUiQueueThread {
|
|
58
|
+
val view = getSpallaPlayerView(tag)
|
|
59
|
+
view?.selectPlaybackRate(rate)
|
|
60
|
+
}
|
|
137
61
|
}
|
|
138
62
|
|
|
139
63
|
@ReactMethod
|
|
140
|
-
fun
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
} else {
|
|
147
|
-
throw ClassCastException(
|
|
148
|
-
String.format(
|
|
149
|
-
"Cannot play: view with tag #%d is not a SpallaPplayerView",
|
|
150
|
-
tag
|
|
151
|
-
)
|
|
152
|
-
)
|
|
153
|
-
}
|
|
154
|
-
}
|
|
64
|
+
fun unmount(tag: Double) {
|
|
65
|
+
try {
|
|
66
|
+
pause(tag)
|
|
67
|
+
} catch (e: Exception) {
|
|
68
|
+
Log.e("SpallaPlayerModule", "Error in unmount method", e)
|
|
69
|
+
}
|
|
155
70
|
}
|
|
156
71
|
|
|
157
72
|
@ReactMethod
|
|
158
|
-
fun
|
|
159
|
-
|
|
160
|
-
.
|
|
161
|
-
|
|
162
|
-
if (playerView is SpallaPlayerView) {
|
|
163
|
-
playerView.selectPlaybackRate(rate)
|
|
164
|
-
} else {
|
|
165
|
-
throw ClassCastException(
|
|
166
|
-
String.format(
|
|
167
|
-
"Cannot play: view with tag #%d is not a SpallaPplayerView",
|
|
168
|
-
tag
|
|
169
|
-
)
|
|
170
|
-
)
|
|
171
|
-
}
|
|
73
|
+
fun initialize(token: String?, applicationId: String?) {
|
|
74
|
+
try {
|
|
75
|
+
if (token.isNullOrBlank()) {
|
|
76
|
+
throw IllegalArgumentException("Token cannot be null or empty")
|
|
172
77
|
}
|
|
78
|
+
SpallaSDK.initialize(reactContext, token)
|
|
79
|
+
} catch (e: Exception) {
|
|
80
|
+
Log.e("SpallaPlayerModule", "Failed to initialize SpallaSDK", e)
|
|
81
|
+
}
|
|
173
82
|
}
|
|
174
83
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
val uiManager = UIManagerHelper.getUIManager(_reactContext, UIManagerType.FABRIC)
|
|
84
|
+
fun getSpallaPlayerView(tag: Double): SpallaPlayerView? {
|
|
85
|
+
try {
|
|
86
|
+
val uiManager = UIManagerHelper.getUIManager(reactContext, UIManagerType.FABRIC)
|
|
179
87
|
if (uiManager is UIManager) {
|
|
180
|
-
uiManager.resolveView(tag)
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
val playerView = nativeViewHierarchyManager.resolveView(tag)
|
|
191
|
-
if (playerView is SpallaPlayerView) {
|
|
192
|
-
playerView.pause()
|
|
88
|
+
val view = uiManager.resolveView(tag.toInt())
|
|
89
|
+
if (view is SpallaPlayerView) {
|
|
90
|
+
return view
|
|
91
|
+
} else if (view != null) {
|
|
92
|
+
Log.e(
|
|
93
|
+
"SpallaPlayerModule",
|
|
94
|
+
"Cannot play: view with tag #$tag is not a SpallaPlayerView"
|
|
95
|
+
)
|
|
96
|
+
} else {
|
|
97
|
+
Log.e("SpallaPlayerModule", "Cannot find view with tag #$tag")
|
|
193
98
|
}
|
|
99
|
+
} else {
|
|
100
|
+
Log.e("SpallaPlayerModule", "UIManager is not available")
|
|
194
101
|
}
|
|
102
|
+
} catch (e: Exception) {
|
|
103
|
+
Log.e("SpallaPlayerModule", "Error in play method", e)
|
|
195
104
|
}
|
|
105
|
+
return null
|
|
196
106
|
}
|
|
197
|
-
|
|
198
|
-
@ReactMethod
|
|
199
|
-
fun initialize(token: String, applicationId: String?) {
|
|
200
|
-
SpallaSDK.initialize(_reactContext, token)
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
|
|
204
107
|
}
|
|
@@ -3,8 +3,6 @@ package com.spallaplayer
|
|
|
3
3
|
import com.facebook.react.ReactPackage
|
|
4
4
|
import com.facebook.react.bridge.NativeModule
|
|
5
5
|
import com.facebook.react.bridge.ReactApplicationContext
|
|
6
|
-
import com.facebook.react.module.model.ReactModuleInfo
|
|
7
|
-
import com.facebook.react.module.model.ReactModuleInfoProvider
|
|
8
6
|
import com.facebook.react.uimanager.ViewManager
|
|
9
7
|
import com.spallaplayer.components.RNGoogleCastButtonManager
|
|
10
8
|
import java.util.ArrayList
|
|
@@ -19,12 +17,12 @@ class SpallaPlayerViewPackage : ReactPackage {
|
|
|
19
17
|
|
|
20
18
|
@Deprecated("Migrate to [BaseReactPackage] and implement [getModule] instead.")
|
|
21
19
|
override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
|
|
22
|
-
return listOf(
|
|
20
|
+
return listOf(SpallaPlayerModule(reactContext))
|
|
23
21
|
}
|
|
24
22
|
|
|
25
23
|
override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? {
|
|
26
24
|
return when (name) {
|
|
27
|
-
SpallaPlayerModule.
|
|
25
|
+
SpallaPlayerModule.REACT_NAME -> SpallaPlayerModule(reactContext)
|
|
28
26
|
else -> null
|
|
29
27
|
}
|
|
30
28
|
}
|
|
@@ -1,61 +1,92 @@
|
|
|
1
|
+
package com.spallaplayer
|
|
2
|
+
|
|
1
3
|
import android.util.Log
|
|
2
4
|
import android.view.View
|
|
3
5
|
import com.facebook.react.bridge.Arguments
|
|
4
6
|
import com.facebook.react.bridge.ReactContext
|
|
7
|
+
import com.facebook.react.bridge.ReadableArray
|
|
5
8
|
import com.facebook.react.bridge.WritableMap
|
|
9
|
+
import com.facebook.react.module.annotations.ReactModule
|
|
6
10
|
import com.facebook.react.uimanager.ViewGroupManager
|
|
7
11
|
import com.facebook.react.uimanager.ThemedReactContext
|
|
12
|
+
import com.facebook.react.uimanager.UIManagerHelper
|
|
13
|
+
import com.facebook.react.uimanager.ViewManagerDelegate
|
|
8
14
|
import com.facebook.react.uimanager.annotations.ReactProp
|
|
9
|
-
import com.facebook.react.uimanager.events.RCTEventEmitter
|
|
10
15
|
import com.spalla.sdk.android.core.player.entities.SpallaPlayerEvent
|
|
11
16
|
import com.spalla.sdk.android.core.player.entities.SpallaPlayerEvent.*
|
|
12
17
|
import com.spalla.sdk.android.core.player.listeners.SpallaPlayerFullScreenListener
|
|
13
18
|
import com.spalla.sdk.android.core.player.listeners.SpallaPlayerListener
|
|
14
19
|
import com.spalla.sdk.android.core.player.view.SpallaPlayerView
|
|
15
|
-
|
|
16
|
-
|
|
17
20
|
import java.util.Timer
|
|
18
|
-
import java.util.TimerTask
|
|
19
21
|
|
|
22
|
+
// These imports will work because Codegen runs for Fabric builds.
|
|
23
|
+
// Your IDE will show errors on these lines until you build the project.
|
|
24
|
+
import com.facebook.react.viewmanagers.SpallaPlayerViewManagerInterface
|
|
25
|
+
import com.facebook.react.viewmanagers.SpallaPlayerViewManagerDelegate
|
|
26
|
+
|
|
27
|
+
// Implement the Codegen interface for Fabric support
|
|
28
|
+
@ReactModule(name = SpallaPlayerViewManager.REACT_CLASS)
|
|
20
29
|
class SpallaPlayerViewManager() : ViewGroupManager<SpallaPlayerView>(),
|
|
30
|
+
SpallaPlayerViewManagerInterface<SpallaPlayerView>, // Fabric interface
|
|
21
31
|
SpallaPlayerListener, SpallaPlayerFullScreenListener {
|
|
32
|
+
|
|
33
|
+
companion object {
|
|
34
|
+
const val REACT_CLASS = "SpallaPlayerView"
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// The delegate is required for Fabric to handle props and commands.
|
|
38
|
+
private val mDelegate = SpallaPlayerViewManagerDelegate(this)
|
|
39
|
+
|
|
40
|
+
// This method is required by the Fabric architecture.
|
|
41
|
+
override fun getDelegate(): ViewManagerDelegate<SpallaPlayerView> = mDelegate
|
|
42
|
+
|
|
22
43
|
private var _playerView: SpallaPlayerView? = null
|
|
23
44
|
private var _reactContext: ReactContext? = null
|
|
24
|
-
//private var _container:
|
|
25
|
-
|
|
45
|
+
//private var _container: SpallaPlayerView? = null
|
|
26
46
|
private var contentId: String? = null
|
|
27
47
|
private var startTime: Double? = null
|
|
28
48
|
private var subtitle: String? = null
|
|
29
49
|
private var loadTimer: Timer? = null
|
|
30
50
|
private var playbackRate: Double = 1.0
|
|
31
51
|
private var hideUI: Boolean? = null
|
|
52
|
+
private var _viewTag: Int = -1
|
|
32
53
|
|
|
33
|
-
override fun getName() =
|
|
54
|
+
override fun getName() = REACT_CLASS
|
|
34
55
|
|
|
35
56
|
override fun createViewInstance(context: ThemedReactContext): SpallaPlayerView {
|
|
36
57
|
_reactContext = context
|
|
58
|
+
//val container = SpallaPlayerContainerView(context)
|
|
37
59
|
val player = SpallaPlayerView(context)
|
|
38
|
-
_playerView = player
|
|
39
|
-
_playerView?.registerPlayerListener(this)
|
|
40
|
-
_playerView?.registerFullScreenListener(this)
|
|
41
|
-
return player
|
|
42
|
-
}
|
|
43
60
|
|
|
44
|
-
|
|
45
|
-
|
|
61
|
+
// Defer initialization until view is attached to window
|
|
62
|
+
player.addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener {
|
|
63
|
+
override fun onViewAttachedToWindow(view: View) {
|
|
64
|
+
try {
|
|
65
|
+
_playerView = player
|
|
66
|
+
_playerView?.registerPlayerListener(this@SpallaPlayerViewManager)
|
|
67
|
+
_playerView?.registerFullScreenListener(this@SpallaPlayerViewManager)
|
|
68
|
+
// Remove listener to avoid memory leaks
|
|
69
|
+
view.removeOnAttachStateChangeListener(this)
|
|
70
|
+
|
|
71
|
+
checkAndLoadPlayer(player)
|
|
72
|
+
} catch (e: Exception) {
|
|
73
|
+
Log.e("SpallaPlayerViewManager", "Error during view attachment", e)
|
|
74
|
+
}
|
|
75
|
+
}
|
|
46
76
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
)
|
|
77
|
+
override fun onViewDetachedFromWindow(view: View) {
|
|
78
|
+
_playerView?.pause()
|
|
79
|
+
|
|
80
|
+
}
|
|
81
|
+
})
|
|
52
82
|
|
|
53
|
-
|
|
83
|
+
//this._container = container
|
|
84
|
+
//return container
|
|
85
|
+
return player
|
|
54
86
|
}
|
|
55
87
|
|
|
56
88
|
override fun onDropViewInstance(view: SpallaPlayerView) {
|
|
57
89
|
Log.v("RNSpallaPlayerManager", "onDropViewInstance")
|
|
58
|
-
|
|
59
90
|
try {
|
|
60
91
|
view.onDestroy()
|
|
61
92
|
} catch (e: Exception) {
|
|
@@ -64,83 +95,119 @@ class SpallaPlayerViewManager() : ViewGroupManager<SpallaPlayerView>(),
|
|
|
64
95
|
super.onDropViewInstance(view)
|
|
65
96
|
}
|
|
66
97
|
|
|
67
|
-
|
|
68
|
-
parent.addView(child, index)
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
override fun removeViewAt(parent: SpallaPlayerView, index: Int) {
|
|
72
|
-
parent.removeViewAt(index)
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
override fun getChildCount(parent: SpallaPlayerView): Int {
|
|
76
|
-
return parent.childCount
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
override fun getChildAt(parent: SpallaPlayerView, index: Int): View {
|
|
80
|
-
return parent.getChildAt(index)
|
|
81
|
-
}
|
|
82
|
-
|
|
98
|
+
// --- Prop Setters ---
|
|
83
99
|
@ReactProp(name = "contentId")
|
|
84
|
-
fun setContentId(view: SpallaPlayerView,
|
|
85
|
-
|
|
86
|
-
|
|
100
|
+
override fun setContentId(view: SpallaPlayerView, value: String?) {
|
|
101
|
+
_viewTag = view.tag as? Int ?: -1
|
|
102
|
+
if (value != null) {
|
|
103
|
+
this.contentId = value
|
|
104
|
+
//add a hacky delay here, so if content and starttime are changed at same time,
|
|
105
|
+
//start time is set first
|
|
106
|
+
view.postDelayed({
|
|
107
|
+
checkAndLoadPlayer(view)
|
|
108
|
+
}, 100L)
|
|
109
|
+
}
|
|
87
110
|
}
|
|
88
111
|
|
|
89
112
|
@ReactProp(name = "muted")
|
|
90
|
-
fun setMuted(view: SpallaPlayerView,
|
|
91
|
-
_playerView?.setMuted(
|
|
113
|
+
override fun setMuted(view: SpallaPlayerView, value: Boolean) {
|
|
114
|
+
_playerView?.setMuted(value)
|
|
92
115
|
}
|
|
93
116
|
|
|
94
117
|
@ReactProp(name = "startTime")
|
|
95
|
-
fun setStartTime(view: SpallaPlayerView,
|
|
96
|
-
this.startTime =
|
|
118
|
+
override fun setStartTime(view: SpallaPlayerView, value: Double) {
|
|
119
|
+
this.startTime = value
|
|
97
120
|
//checkAndLoadPlayer(view)
|
|
98
121
|
}
|
|
99
122
|
|
|
100
123
|
@ReactProp(name = "subtitle")
|
|
101
|
-
fun setSubtitle(view: SpallaPlayerView,
|
|
102
|
-
this.subtitle =
|
|
124
|
+
override fun setSubtitle(view: SpallaPlayerView, value: String?) {
|
|
125
|
+
this.subtitle = value
|
|
103
126
|
_playerView?.selectSubtitle(subtitle)
|
|
104
127
|
}
|
|
105
128
|
|
|
106
129
|
@ReactProp(name = "playbackRate")
|
|
107
|
-
fun setPlaybackRate(view: SpallaPlayerView,
|
|
108
|
-
if (
|
|
109
|
-
this.playbackRate =
|
|
130
|
+
override fun setPlaybackRate(view: SpallaPlayerView, value: Float) {
|
|
131
|
+
if (value > 0) {
|
|
132
|
+
this.playbackRate = value.toDouble()
|
|
110
133
|
_playerView?.selectPlaybackRate(playbackRate)
|
|
111
134
|
}
|
|
112
135
|
}
|
|
113
136
|
|
|
114
137
|
@ReactProp(name = "hideUI")
|
|
115
|
-
fun setHideUI(view: SpallaPlayerView,
|
|
116
|
-
this.hideUI =
|
|
117
|
-
checkAndLoadPlayer(view)
|
|
138
|
+
override fun setHideUI(view: SpallaPlayerView, value: Boolean) {
|
|
139
|
+
this.hideUI = value
|
|
140
|
+
//checkAndLoadPlayer(view)
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
override fun play(view: SpallaPlayerView?) {
|
|
144
|
+
view?.play()
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
override fun pause(view: SpallaPlayerView?) {
|
|
148
|
+
view?.pause()
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
override fun seekTo(
|
|
152
|
+
view: SpallaPlayerView?,
|
|
153
|
+
time: Double
|
|
154
|
+
) {
|
|
155
|
+
view?.seekTo(time)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
override fun selectSubtitle(
|
|
159
|
+
view: SpallaPlayerView?,
|
|
160
|
+
subtitle: String?
|
|
161
|
+
) {
|
|
162
|
+
view?.selectSubtitle(subtitle)
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
override fun selectPlaybackRate(
|
|
166
|
+
view: SpallaPlayerView?,
|
|
167
|
+
rate: Float
|
|
168
|
+
) {
|
|
169
|
+
view?.selectPlaybackRate(rate.toDouble())
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
override fun unmount(view: SpallaPlayerView?) {
|
|
173
|
+
view?.pause()
|
|
174
|
+
view?.onDestroy()
|
|
118
175
|
}
|
|
119
176
|
|
|
120
177
|
private fun checkAndLoadPlayer(view: SpallaPlayerView) {
|
|
121
|
-
|
|
122
|
-
|
|
178
|
+
try {
|
|
179
|
+
// Only load if view is attached to window and all required props are set
|
|
180
|
+
if (contentId != null && startTime != null && hideUI != null && view.isAttachedToWindow) {
|
|
181
|
+
view.load(contentId!!, true, startTime!!, subtitle, hideUI!!)
|
|
182
|
+
}
|
|
183
|
+
} catch (e: Exception) {
|
|
184
|
+
Log.e("SpallaPlayerViewManager", "Error loading player", e)
|
|
123
185
|
}
|
|
124
186
|
}
|
|
125
187
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
188
|
+
// --- Command Handling ---
|
|
189
|
+
override fun receiveCommand(
|
|
190
|
+
root: SpallaPlayerView,
|
|
191
|
+
commandId: String,
|
|
192
|
+
args: ReadableArray?
|
|
193
|
+
) {
|
|
194
|
+
mDelegate.receiveCommand(root, commandId, args)
|
|
195
|
+
}
|
|
129
196
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
}, 300) // Delay of 200ms to allow all properties to be set
|
|
197
|
+
// --- Event Handling ---
|
|
198
|
+
override fun getExportedCustomBubblingEventTypeConstants(): MutableMap<String, Any> {
|
|
199
|
+
return mutableMapOf(
|
|
200
|
+
"onPlayerEvent" to mapOf(
|
|
201
|
+
"phasedRegistrationNames" to mapOf(
|
|
202
|
+
"bubbled" to "onPlayerEvent"
|
|
203
|
+
)
|
|
204
|
+
)
|
|
205
|
+
)
|
|
140
206
|
}
|
|
141
207
|
|
|
142
208
|
override fun onEvent(event: SpallaPlayerEvent) {
|
|
143
209
|
val map: WritableMap = Arguments.createMap()
|
|
210
|
+
val eventName = "onPlayerEvent"
|
|
144
211
|
|
|
145
212
|
Log.v("RNSpallaPlayerManager", "onEvent: $event")
|
|
146
213
|
when (event) {
|
|
@@ -148,13 +215,11 @@ class SpallaPlayerViewManager() : ViewGroupManager<SpallaPlayerView>(),
|
|
|
148
215
|
map.putString("event", "durationUpdate")
|
|
149
216
|
map.putDouble("duration", event.duration)
|
|
150
217
|
}
|
|
151
|
-
|
|
152
218
|
Ended -> map.putString("event", "ended")
|
|
153
219
|
is Error -> {
|
|
154
220
|
map.putString("event", "error")
|
|
155
221
|
map.putString("message", event.message)
|
|
156
222
|
}
|
|
157
|
-
|
|
158
223
|
Pause -> map.putString("event", "pause")
|
|
159
224
|
Play -> map.putString("event", "play")
|
|
160
225
|
Playing -> map.putString("event", "playing")
|
|
@@ -162,69 +227,63 @@ class SpallaPlayerViewManager() : ViewGroupManager<SpallaPlayerView>(),
|
|
|
162
227
|
map.putString("event", "timeUpdate")
|
|
163
228
|
map.putDouble("time", event.currentTime)
|
|
164
229
|
}
|
|
165
|
-
|
|
166
230
|
Waiting -> map.putString("event", "buffering")
|
|
167
231
|
is SubtitlesAvailable -> {
|
|
168
232
|
map.putString("event", "subtitlesAvailable")
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
event.subtitles.forEach {
|
|
172
|
-
subs.pushString(it)
|
|
173
|
-
}
|
|
233
|
+
val subs = Arguments.createArray()
|
|
234
|
+
event.subtitles.forEach { subs.pushString(it) }
|
|
174
235
|
map.putArray("subtitles", subs)
|
|
175
236
|
}
|
|
176
|
-
|
|
177
237
|
is SubtitleSelected -> {
|
|
178
238
|
map.putString("event", "subtitleSelected")
|
|
179
239
|
map.putString("subtitle", event.subtitle)
|
|
180
240
|
}
|
|
181
|
-
|
|
182
241
|
is MetadataLoaded -> {
|
|
183
242
|
map.putString("event", "metadataLoaded")
|
|
184
243
|
map.putBoolean("isLive", event.metadata.isLive)
|
|
185
244
|
map.putDouble("duration", event.metadata.duration)
|
|
186
|
-
|
|
187
|
-
// make sure current playback rate is applied if set initially
|
|
188
245
|
_playerView?.selectPlaybackRate(playbackRate)
|
|
189
246
|
}
|
|
190
|
-
|
|
191
247
|
is PlaybackRateSelected -> {
|
|
192
248
|
map.putString("event", "playbackRateSelected")
|
|
193
249
|
map.putDouble("rate", event.rate)
|
|
194
250
|
}
|
|
195
|
-
|
|
196
251
|
}
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
252
|
+
|
|
253
|
+
_playerView?.let { view ->
|
|
254
|
+
_reactContext?.let { reactContext ->
|
|
255
|
+
val surfaceId = UIManagerHelper.getSurfaceId(reactContext)
|
|
256
|
+
val eventDispatcher = UIManagerHelper.getEventDispatcherForReactTag(reactContext, view.id)
|
|
257
|
+
eventDispatcher?.dispatchEvent(
|
|
258
|
+
RNSpallaPlayerEvent(surfaceId, view.id, eventName, map)
|
|
259
|
+
)
|
|
260
|
+
}
|
|
203
261
|
}
|
|
204
262
|
}
|
|
205
263
|
|
|
206
264
|
override fun onEnterFullScreen() {
|
|
207
|
-
Log.v("SpallaPlayerViewManager", "onEnterFullScreen")
|
|
208
265
|
val map: WritableMap = Arguments.createMap()
|
|
209
266
|
map.putString("event", "enterFullScreen")
|
|
210
|
-
|
|
211
|
-
_reactContext?.getJSModule(RCTEventEmitter::class.java)?.receiveEvent(
|
|
212
|
-
container.id,
|
|
213
|
-
"onPlayerEvent",
|
|
214
|
-
map
|
|
215
|
-
)
|
|
216
|
-
}
|
|
267
|
+
dispatchEvent("onPlayerEvent", map)
|
|
217
268
|
}
|
|
218
269
|
|
|
219
270
|
override fun onExitFullScreen() {
|
|
220
271
|
val map: WritableMap = Arguments.createMap()
|
|
221
272
|
map.putString("event", "exitFullScreen")
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
273
|
+
dispatchEvent("onPlayerEvent", map)
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
private fun dispatchEvent(eventName: String, eventData: WritableMap) {
|
|
277
|
+
_playerView?.let { view ->
|
|
278
|
+
_reactContext?.let { reactContext ->
|
|
279
|
+
if (_viewTag != -1) {
|
|
280
|
+
val surfaceId = UIManagerHelper.getSurfaceId(reactContext)
|
|
281
|
+
val eventDispatcher = UIManagerHelper.getEventDispatcherForReactTag(reactContext, view.id)
|
|
282
|
+
eventDispatcher?.dispatchEvent(
|
|
283
|
+
RNSpallaPlayerEvent(surfaceId, _viewTag, eventName, eventData)
|
|
284
|
+
)
|
|
285
|
+
}
|
|
286
|
+
}
|
|
228
287
|
}
|
|
229
288
|
}
|
|
230
289
|
|
package/package.json
CHANGED
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
package com.spallaplayer
|
|
2
|
-
|
|
3
|
-
import android.util.Log
|
|
4
|
-
import com.facebook.react.bridge.ReactApplicationContext
|
|
5
|
-
import com.facebook.react.bridge.ReactContextBaseJavaModule
|
|
6
|
-
import com.facebook.react.bridge.ReactMethod
|
|
7
|
-
import com.facebook.react.bridge.UIManager
|
|
8
|
-
import com.facebook.react.uimanager.UIManagerHelper
|
|
9
|
-
import com.facebook.react.uimanager.common.UIManagerType
|
|
10
|
-
import com.spalla.sdk.android.core.SpallaSDK
|
|
11
|
-
import com.spalla.sdk.android.core.player.view.SpallaPlayerView
|
|
12
|
-
|
|
13
|
-
class SpallaPlayerModuleFabric(
|
|
14
|
-
val reactContext: ReactApplicationContext
|
|
15
|
-
): ReactContextBaseJavaModule(reactContext) {
|
|
16
|
-
|
|
17
|
-
override fun getName() = "SpallaPlayerModule"
|
|
18
|
-
|
|
19
|
-
@ReactMethod
|
|
20
|
-
fun play(tag: Double) {
|
|
21
|
-
reactContext.runOnUiQueueThread {
|
|
22
|
-
val view = getSpallaPlayerView(tag)
|
|
23
|
-
view?.play()
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
@ReactMethod
|
|
28
|
-
fun pause(tag: Double) {
|
|
29
|
-
reactContext.runOnUiQueueThread {
|
|
30
|
-
val view = getSpallaPlayerView(tag)
|
|
31
|
-
view?.pause()
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
@ReactMethod
|
|
36
|
-
fun seekTo(tag: Double, time: Double) {
|
|
37
|
-
reactContext.runOnUiQueueThread {
|
|
38
|
-
val view = getSpallaPlayerView(tag)
|
|
39
|
-
view?.seekTo(time)
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
@ReactMethod
|
|
44
|
-
fun selectSubtitle(tag: Double, subtitle: String?) {
|
|
45
|
-
reactContext.runOnUiQueueThread {
|
|
46
|
-
val view = getSpallaPlayerView(tag)
|
|
47
|
-
view?.selectSubtitle(subtitle)
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
@ReactMethod
|
|
52
|
-
fun selectPlaybackRate(tag: Double, rate: Double) {
|
|
53
|
-
reactContext.runOnUiQueueThread {
|
|
54
|
-
val view = getSpallaPlayerView(tag)
|
|
55
|
-
view?.selectPlaybackRate(rate)
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
@ReactMethod
|
|
60
|
-
fun unmount(tag: Double) {
|
|
61
|
-
try {
|
|
62
|
-
pause(tag)
|
|
63
|
-
} catch (e: Exception) {
|
|
64
|
-
Log.e("SpallaPlayerModule", "Error in unmount method", e)
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
@ReactMethod
|
|
69
|
-
fun initialize(token: String?, applicationId: String?) {
|
|
70
|
-
try {
|
|
71
|
-
if (token.isNullOrBlank()) {
|
|
72
|
-
throw IllegalArgumentException("Token cannot be null or empty")
|
|
73
|
-
}
|
|
74
|
-
SpallaSDK.initialize(reactContext, token)
|
|
75
|
-
} catch (e: Exception) {
|
|
76
|
-
Log.e("SpallaPlayerModule", "Failed to initialize SpallaSDK", e)
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
fun getSpallaPlayerView(tag: Double): SpallaPlayerView? {
|
|
81
|
-
try {
|
|
82
|
-
val uiManager = UIManagerHelper.getUIManager(reactContext, UIManagerType.FABRIC)
|
|
83
|
-
if (uiManager is UIManager) {
|
|
84
|
-
val view = uiManager.resolveView(tag.toInt())
|
|
85
|
-
if (view is SpallaPlayerView) {
|
|
86
|
-
return view
|
|
87
|
-
} else if (view != null) {
|
|
88
|
-
Log.e(
|
|
89
|
-
"SpallaPlayerModule",
|
|
90
|
-
"Cannot play: view with tag #$tag is not a SpallaPlayerView"
|
|
91
|
-
)
|
|
92
|
-
} else {
|
|
93
|
-
Log.e("SpallaPlayerModule", "Cannot find view with tag #$tag")
|
|
94
|
-
}
|
|
95
|
-
} else {
|
|
96
|
-
Log.e("SpallaPlayerModule", "UIManager is not available")
|
|
97
|
-
}
|
|
98
|
-
} catch (e: Exception) {
|
|
99
|
-
Log.e("SpallaPlayerModule", "Error in play method", e)
|
|
100
|
-
}
|
|
101
|
-
return null
|
|
102
|
-
}
|
|
103
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
package com.spallaplayer
|
|
2
|
-
|
|
3
|
-
import android.content.Context
|
|
4
|
-
import android.util.AttributeSet
|
|
5
|
-
import android.view.View
|
|
6
|
-
|
|
7
|
-
class SpallaPlayerView : View {
|
|
8
|
-
constructor(context: Context?) : super(context)
|
|
9
|
-
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
|
|
10
|
-
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(
|
|
11
|
-
context,
|
|
12
|
-
attrs,
|
|
13
|
-
defStyleAttr
|
|
14
|
-
)
|
|
15
|
-
}
|
|
@@ -1,289 +0,0 @@
|
|
|
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
|
-
}
|