react-native-spalla-player 0.13.4 → 0.14.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.
|
@@ -1,36 +1,62 @@
|
|
|
1
1
|
package com.spallaplayer
|
|
2
2
|
|
|
3
3
|
import android.content.Context
|
|
4
|
+
import android.util.Log
|
|
4
5
|
import android.widget.FrameLayout
|
|
5
6
|
import com.spalla.sdk.android.core.player.view.SpallaPlayerView
|
|
6
7
|
import android.view.ViewGroup;
|
|
8
|
+
import androidx.core.view.isNotEmpty
|
|
7
9
|
|
|
8
10
|
class SpallaPlayerContainerView(context: Context) : ViewGroup(context) {
|
|
9
|
-
|
|
11
|
+
val spallaPlayerView: SpallaPlayerView = SpallaPlayerView(context)
|
|
12
|
+
private var isAttachedToWindow = false
|
|
10
13
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
init {
|
|
15
|
+
addView(spallaPlayerView)
|
|
16
|
+
requestLayout()
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
|
|
20
|
+
val containerWidth = r - l
|
|
21
|
+
val containerHeight = b - t
|
|
22
|
+
|
|
23
|
+
Log.d("SpallaPlayerContainerView", "Layout: container=${containerWidth}x${containerHeight}")
|
|
24
|
+
|
|
25
|
+
for (i in 0 until childCount) {
|
|
26
|
+
val child = getChildAt(i)
|
|
27
|
+
child.layout(0, 0, containerWidth, containerHeight)
|
|
15
28
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
29
|
+
if (child is SpallaPlayerView) {
|
|
30
|
+
// Schedule multiple layout passes to catch the async initialization
|
|
31
|
+
repeat(3) { index ->
|
|
32
|
+
child.post {
|
|
33
|
+
child.requestLayout()
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
20
38
|
}
|
|
21
|
-
}
|
|
22
39
|
|
|
23
|
-
override fun
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
40
|
+
override fun onAttachedToWindow() {
|
|
41
|
+
super.onAttachedToWindow()
|
|
42
|
+
isAttachedToWindow = true
|
|
43
|
+
// Ensure proper initialization when attached to window
|
|
44
|
+
post {
|
|
45
|
+
requestLayout()
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
|
|
50
|
+
val width = MeasureSpec.getSize(widthMeasureSpec)
|
|
51
|
+
val height = MeasureSpec.getSize(heightMeasureSpec)
|
|
52
|
+
for (i in 0 until childCount) {
|
|
53
|
+
val child = getChildAt(i)
|
|
54
|
+
child.measure(
|
|
55
|
+
MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
|
|
56
|
+
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)
|
|
57
|
+
)
|
|
58
|
+
}
|
|
59
|
+
setMeasuredDimension(width, height)
|
|
32
60
|
}
|
|
33
|
-
setMeasuredDimension(width, height)
|
|
34
|
-
}
|
|
35
61
|
|
|
36
62
|
}
|
|
@@ -14,180 +14,186 @@ import com.spalla.sdk.android.core.player.view.SpallaPlayerView
|
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
class SpallaPlayerModule(reactContext: ReactApplicationContext) :
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
override fun getName(): String {
|
|
27
|
-
return "RNSpallaPlayer"
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
override fun onHostResume() {
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
override fun onHostPause() {
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
override fun onHostDestroy() {
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
@ReactMethod
|
|
41
|
-
fun play(tag: Int) {
|
|
42
|
-
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
|
|
43
|
-
val uiManager = UIManagerHelper.getUIManager(_reactContext, UIManagerType.FABRIC)
|
|
44
|
-
if (uiManager is UIManager) {
|
|
45
|
-
uiManager.resolveView(tag)?.let { view ->
|
|
46
|
-
if (view is SpallaPlayerContainerView) {
|
|
47
|
-
view.spallaPlayerView.play()
|
|
48
|
-
} else {
|
|
49
|
-
throw ClassCastException(
|
|
50
|
-
"Cannot play: view with tag #$tag is not a SpallaPlayerView"
|
|
51
|
-
)
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
} else {
|
|
56
|
-
val uiManager: UIManagerModule? =
|
|
57
|
-
_reactContext.getNativeModule(UIManagerModule::class.java)
|
|
58
|
-
uiManager?.prependUIBlock { nativeViewHierarchyManager: NativeViewHierarchyManager ->
|
|
59
|
-
val playerView = nativeViewHierarchyManager.resolveView(tag)
|
|
60
|
-
if (playerView is SpallaPlayerContainerView) {
|
|
61
|
-
playerView.spallaPlayerView.play()
|
|
62
|
-
} else {
|
|
63
|
-
throw ClassCastException(
|
|
64
|
-
String.format(
|
|
65
|
-
"Cannot play: view with tag #%d is not a SpallaPlayerView",
|
|
66
|
-
tag
|
|
67
|
-
)
|
|
68
|
-
)
|
|
69
|
-
}
|
|
70
|
-
}
|
|
17
|
+
ReactContextBaseJavaModule(reactContext),
|
|
18
|
+
LifecycleEventListener {
|
|
19
|
+
private val _reactContext: ReactApplicationContext
|
|
20
|
+
|
|
21
|
+
init {
|
|
22
|
+
reactContext.addLifecycleEventListener(this)
|
|
23
|
+
_reactContext = reactContext
|
|
71
24
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
if (uiManager is UIManager) {
|
|
79
|
-
uiManager.resolveView(tag)?.let { view ->
|
|
80
|
-
if (view is SpallaPlayerContainerView) {
|
|
81
|
-
view.spallaPlayerView.pause()
|
|
82
|
-
} else {
|
|
83
|
-
throw ClassCastException(
|
|
84
|
-
"Cannot pause: view with tag #$tag is not a SpallaPlayerView"
|
|
85
|
-
)
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
} else {
|
|
90
|
-
val uiManager: UIManagerModule? =
|
|
91
|
-
_reactContext.getNativeModule(UIManagerModule::class.java)
|
|
92
|
-
uiManager?.prependUIBlock { nativeViewHierarchyManager: NativeViewHierarchyManager ->
|
|
93
|
-
val playerView = nativeViewHierarchyManager.resolveView(tag)
|
|
94
|
-
if (playerView is SpallaPlayerContainerView) {
|
|
95
|
-
playerView.spallaPlayerView.pause()
|
|
96
|
-
} else {
|
|
97
|
-
throw ClassCastException(
|
|
98
|
-
String.format(
|
|
99
|
-
"Cannot play: view with tag #%d is not a SpallaPplayerView",
|
|
100
|
-
tag
|
|
101
|
-
)
|
|
102
|
-
)
|
|
103
|
-
}
|
|
104
|
-
}
|
|
25
|
+
|
|
26
|
+
override fun getName(): String {
|
|
27
|
+
return "RNSpallaPlayer"
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
override fun onHostResume() {
|
|
105
31
|
}
|
|
106
32
|
|
|
33
|
+
override fun onHostPause() {
|
|
107
34
|
|
|
108
|
-
|
|
35
|
+
}
|
|
109
36
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
if (
|
|
116
|
-
|
|
37
|
+
override fun onHostDestroy() {
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
@ReactMethod
|
|
41
|
+
fun play(tag: Int) {
|
|
42
|
+
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
|
|
43
|
+
val uiManager = UIManagerHelper.getUIManager(_reactContext, UIManagerType.FABRIC)
|
|
44
|
+
if (uiManager is UIManager) {
|
|
45
|
+
uiManager.resolveView(tag)?.let { view ->
|
|
46
|
+
if (view is SpallaPlayerContainerView) {
|
|
47
|
+
view.post {
|
|
48
|
+
view.spallaPlayerView.play()
|
|
49
|
+
}
|
|
50
|
+
} else {
|
|
51
|
+
throw ClassCastException(
|
|
52
|
+
"Cannot play: view with tag #$tag is not a SpallaPlayerView"
|
|
53
|
+
)
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
117
57
|
} else {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
58
|
+
val uiManager: UIManagerModule? =
|
|
59
|
+
_reactContext.getNativeModule(UIManagerModule::class.java)
|
|
60
|
+
uiManager?.prependUIBlock { nativeViewHierarchyManager: NativeViewHierarchyManager ->
|
|
61
|
+
val playerView = nativeViewHierarchyManager.resolveView(tag)
|
|
62
|
+
if (playerView is SpallaPlayerContainerView) {
|
|
63
|
+
playerView.spallaPlayerView.play()
|
|
64
|
+
} else {
|
|
65
|
+
throw ClassCastException(
|
|
66
|
+
String.format(
|
|
67
|
+
"Cannot play: view with tag #%d is not a SpallaPlayerView",
|
|
68
|
+
tag
|
|
69
|
+
)
|
|
70
|
+
)
|
|
71
|
+
}
|
|
72
|
+
}
|
|
124
73
|
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
@ReactMethod
|
|
77
|
+
fun pause(tag: Int) {
|
|
78
|
+
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
|
|
79
|
+
val uiManager = UIManagerHelper.getUIManager(_reactContext, UIManagerType.FABRIC)
|
|
80
|
+
if (uiManager is UIManager) {
|
|
81
|
+
uiManager.resolveView(tag)?.let { view ->
|
|
82
|
+
if (view is SpallaPlayerContainerView) {
|
|
83
|
+
view.post {
|
|
84
|
+
view.spallaPlayerView.pause()
|
|
85
|
+
}
|
|
86
|
+
} else {
|
|
87
|
+
throw ClassCastException(
|
|
88
|
+
"Cannot pause: view with tag #$tag is not a SpallaPlayerView"
|
|
89
|
+
)
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
135
93
|
} else {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
94
|
+
val uiManager: UIManagerModule? =
|
|
95
|
+
_reactContext.getNativeModule(UIManagerModule::class.java)
|
|
96
|
+
uiManager?.prependUIBlock { nativeViewHierarchyManager: NativeViewHierarchyManager ->
|
|
97
|
+
val playerView = nativeViewHierarchyManager.resolveView(tag)
|
|
98
|
+
if (playerView is SpallaPlayerContainerView) {
|
|
99
|
+
playerView.spallaPlayerView.pause()
|
|
100
|
+
} else {
|
|
101
|
+
throw ClassCastException(
|
|
102
|
+
String.format(
|
|
103
|
+
"Cannot play: view with tag #%d is not a SpallaPplayerView",
|
|
104
|
+
tag
|
|
105
|
+
)
|
|
106
|
+
)
|
|
107
|
+
}
|
|
108
|
+
}
|
|
142
109
|
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
@ReactMethod
|
|
115
|
+
fun seekTo(tag: Int, time: Double) {
|
|
116
|
+
_reactContext.getNativeModule(UIManagerModule::class.java)!!
|
|
117
|
+
.prependUIBlock { nativeViewHierarchyManager: NativeViewHierarchyManager ->
|
|
118
|
+
val playerView = nativeViewHierarchyManager.resolveView(tag)
|
|
119
|
+
if (playerView is SpallaPlayerContainerView) {
|
|
120
|
+
playerView.spallaPlayerView.seekTo(time)
|
|
121
|
+
} else {
|
|
122
|
+
throw ClassCastException(
|
|
123
|
+
String.format(
|
|
124
|
+
"Cannot play: view with tag #%d is not a SpallaPplayerView",
|
|
125
|
+
tag
|
|
126
|
+
)
|
|
127
|
+
)
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
@ReactMethod
|
|
133
|
+
fun selectSubtitle(tag: Int, subtitle: String?) {
|
|
134
|
+
_reactContext.getNativeModule(UIManagerModule::class.java)!!
|
|
135
|
+
.prependUIBlock { nativeViewHierarchyManager: NativeViewHierarchyManager ->
|
|
136
|
+
val playerView = nativeViewHierarchyManager.resolveView(tag)
|
|
137
|
+
if (playerView is SpallaPlayerContainerView) {
|
|
138
|
+
playerView.spallaPlayerView.selectSubtitle(subtitle)
|
|
139
|
+
} else {
|
|
140
|
+
throw ClassCastException(
|
|
141
|
+
String.format(
|
|
142
|
+
"Cannot play: view with tag #%d is not a SpallaPplayerView",
|
|
143
|
+
tag
|
|
144
|
+
)
|
|
145
|
+
)
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
@ReactMethod
|
|
151
|
+
fun selectPlaybackRate(tag: Int, rate: Double) {
|
|
152
|
+
_reactContext.getNativeModule(UIManagerModule::class.java)!!
|
|
153
|
+
.prependUIBlock { nativeViewHierarchyManager: NativeViewHierarchyManager ->
|
|
154
|
+
val playerView = nativeViewHierarchyManager.resolveView(tag)
|
|
155
|
+
if (playerView is SpallaPlayerContainerView) {
|
|
156
|
+
playerView.spallaPlayerView.selectPlaybackRate(rate)
|
|
157
|
+
} else {
|
|
158
|
+
throw ClassCastException(
|
|
159
|
+
String.format(
|
|
160
|
+
"Cannot play: view with tag #%d is not a SpallaPplayerView",
|
|
161
|
+
tag
|
|
162
|
+
)
|
|
163
|
+
)
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
@ReactMethod
|
|
169
|
+
fun unmount(tag: Int) {
|
|
170
|
+
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
|
|
171
|
+
val uiManager = UIManagerHelper.getUIManager(_reactContext, UIManagerType.FABRIC)
|
|
172
|
+
if (uiManager is UIManager) {
|
|
173
|
+
uiManager.resolveView(tag)?.let { view ->
|
|
174
|
+
if (view is SpallaPlayerContainerView) {
|
|
175
|
+
view.post {
|
|
176
|
+
view.spallaPlayerView.pause()
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
153
181
|
} else {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
182
|
+
val uiManager: UIManagerModule? =
|
|
183
|
+
_reactContext.getNativeModule(UIManagerModule::class.java)
|
|
184
|
+
uiManager?.prependUIBlock { nativeViewHierarchyManager: NativeViewHierarchyManager ->
|
|
185
|
+
val playerView = nativeViewHierarchyManager.resolveView(tag)
|
|
186
|
+
if (playerView is SpallaPlayerContainerView) {
|
|
187
|
+
playerView.spallaPlayerView.pause()
|
|
188
|
+
}
|
|
189
|
+
}
|
|
160
190
|
}
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
@ReactMethod
|
|
165
|
-
fun unmount(tag: Int) {
|
|
166
|
-
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
|
|
167
|
-
val uiManager = UIManagerHelper.getUIManager(_reactContext, UIManagerType.FABRIC)
|
|
168
|
-
if (uiManager is UIManager) {
|
|
169
|
-
uiManager.resolveView(tag)?.let { view ->
|
|
170
|
-
if (view is SpallaPlayerContainerView) {
|
|
171
|
-
view.spallaPlayerView.pause()
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
} else {
|
|
176
|
-
val uiManager: UIManagerModule? =
|
|
177
|
-
_reactContext.getNativeModule(UIManagerModule::class.java)
|
|
178
|
-
uiManager?.prependUIBlock { nativeViewHierarchyManager: NativeViewHierarchyManager ->
|
|
179
|
-
val playerView = nativeViewHierarchyManager.resolveView(tag)
|
|
180
|
-
if (playerView is SpallaPlayerContainerView) {
|
|
181
|
-
playerView.spallaPlayerView.pause()
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
191
|
}
|
|
185
|
-
}
|
|
186
192
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
193
|
+
@ReactMethod
|
|
194
|
+
fun initialize(token: String, applicationId: String?) {
|
|
195
|
+
SpallaSDK.initialize(_reactContext, token)
|
|
196
|
+
}
|
|
191
197
|
|
|
192
198
|
|
|
193
199
|
}
|
|
@@ -18,216 +18,232 @@ import java.util.Timer
|
|
|
18
18
|
import java.util.TimerTask
|
|
19
19
|
|
|
20
20
|
class RNSpallaPlayerManager() : ViewGroupManager<SpallaPlayerContainerView>(),
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
@ReactProp(name = "muted")
|
|
92
|
-
fun setMuted(view: SpallaPlayerContainerView, muted: Boolean) {
|
|
93
|
-
_playerView?.setMuted(muted)
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
@ReactProp(name = "startTime")
|
|
97
|
-
fun setStartTime(view: SpallaPlayerContainerView, startTime: Double) {
|
|
98
|
-
this.startTime = startTime
|
|
99
|
-
//checkAndLoadPlayer(view)
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
@ReactProp(name = "subtitle")
|
|
103
|
-
fun setSubtitle(view: SpallaPlayerContainerView, subtitle: String?) {
|
|
104
|
-
this.subtitle = subtitle
|
|
105
|
-
_playerView?.selectSubtitle(subtitle)
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
@ReactProp(name = "playbackRate")
|
|
109
|
-
fun setPlaybackRate(view: SpallaPlayerContainerView, playbackRate: Double) {
|
|
110
|
-
if (playbackRate > 0) {
|
|
111
|
-
this.playbackRate = playbackRate
|
|
112
|
-
_playerView?.selectPlaybackRate(playbackRate)
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
@ReactProp(name = "hideUI")
|
|
117
|
-
fun setPlaybackRate(view: SpallaPlayerContainerView, hideUI: Boolean) {
|
|
118
|
-
this.hideUI = hideUI
|
|
119
|
-
checkAndLoadPlayer(view)
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
private fun checkAndLoadPlayer(view: SpallaPlayerContainerView) {
|
|
123
|
-
if (contentId != null && startTime != null && hideUI != null) {
|
|
124
|
-
view.spallaPlayerView.load(contentId!!, true, startTime!!, subtitle, hideUI!!)
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
private fun startLoadTimer(view: SpallaPlayerView) {
|
|
129
|
-
// Cancel any existing timer
|
|
130
|
-
loadTimer?.cancel()
|
|
131
|
-
|
|
132
|
-
// Start a new timer to check if all required properties are set
|
|
133
|
-
loadTimer = Timer()
|
|
134
|
-
loadTimer?.schedule(object : TimerTask() {
|
|
135
|
-
override fun run() {
|
|
21
|
+
SpallaPlayerListener, SpallaPlayerFullScreenListener {
|
|
22
|
+
private var _playerView: SpallaPlayerView? = null
|
|
23
|
+
private var _reactContext: ReactContext? = null
|
|
24
|
+
private var _container: SpallaPlayerContainerView? = null
|
|
25
|
+
|
|
26
|
+
private var contentId: String? = null
|
|
27
|
+
private var startTime: Double? = null
|
|
28
|
+
private var subtitle: String? = null
|
|
29
|
+
private var loadTimer: Timer? = null
|
|
30
|
+
private var playbackRate: Double = 1.0
|
|
31
|
+
private var hideUI: Boolean? = null
|
|
32
|
+
|
|
33
|
+
override fun getName() = "RNSpallaPlayer"
|
|
34
|
+
|
|
35
|
+
override fun createViewInstance(context: ThemedReactContext): SpallaPlayerContainerView {
|
|
36
|
+
_reactContext = context
|
|
37
|
+
val container = SpallaPlayerContainerView(context)
|
|
38
|
+
_playerView = container.spallaPlayerView
|
|
39
|
+
_playerView?.registerPlayerListener(this)
|
|
40
|
+
_playerView?.registerFullScreenListener(this)
|
|
41
|
+
this._container = container
|
|
42
|
+
|
|
43
|
+
return container
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
override fun getExportedCustomBubblingEventTypeConstants(): MutableMap<String, Any> {
|
|
47
|
+
val eventMap = mutableMapOf<String, Any>()
|
|
48
|
+
|
|
49
|
+
eventMap["onPlayerEvent"] = mapOf(
|
|
50
|
+
"phasedRegistrationNames" to mapOf(
|
|
51
|
+
"bubbled" to "onPlayerEvent"
|
|
52
|
+
)
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
return eventMap
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
override fun onDropViewInstance(view: SpallaPlayerContainerView) {
|
|
59
|
+
Log.v("RNSpallaPlayerManager", "onDropViewInstance")
|
|
60
|
+
view.post {
|
|
61
|
+
try {
|
|
62
|
+
loadTimer?.cancel()
|
|
63
|
+
view.spallaPlayerView.onDestroy()
|
|
64
|
+
} catch (e: Exception) {
|
|
65
|
+
e.printStackTrace()
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
super.onDropViewInstance(view)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
override fun addView(parent: SpallaPlayerContainerView, child: View, index: Int) {
|
|
72
|
+
parent.addView(child, index)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
override fun removeViewAt(parent: SpallaPlayerContainerView, index: Int) {
|
|
76
|
+
parent.removeViewAt(index)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
override fun getChildCount(parent: SpallaPlayerContainerView): Int {
|
|
80
|
+
return parent.childCount
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
override fun getChildAt(parent: SpallaPlayerContainerView, index: Int): View {
|
|
84
|
+
return parent.getChildAt(index)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
@ReactProp(name = "contentId")
|
|
88
|
+
fun setContentId(view: SpallaPlayerContainerView, contentId: String) {
|
|
89
|
+
this.contentId = contentId
|
|
90
|
+
//delay initialization for a bit
|
|
136
91
|
loadTimer?.cancel()
|
|
137
|
-
loadTimer =
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
92
|
+
loadTimer = Timer()
|
|
93
|
+
loadTimer?.schedule(object : TimerTask() {
|
|
94
|
+
override fun run() {
|
|
95
|
+
checkAndLoadPlayer(view)
|
|
96
|
+
}
|
|
97
|
+
}, 100)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
@ReactProp(name = "muted")
|
|
101
|
+
fun setMuted(view: SpallaPlayerContainerView, muted: Boolean) {
|
|
102
|
+
_playerView?.setMuted(muted)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
@ReactProp(name = "startTime")
|
|
106
|
+
fun setStartTime(view: SpallaPlayerContainerView, startTime: Double) {
|
|
107
|
+
this.startTime = startTime
|
|
108
|
+
//checkAndLoadPlayer(view)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
@ReactProp(name = "subtitle")
|
|
112
|
+
fun setSubtitle(view: SpallaPlayerContainerView, subtitle: String?) {
|
|
113
|
+
this.subtitle = subtitle
|
|
114
|
+
_playerView?.selectSubtitle(subtitle)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
@ReactProp(name = "playbackRate")
|
|
118
|
+
fun setPlaybackRate(view: SpallaPlayerContainerView, playbackRate: Double) {
|
|
119
|
+
if (playbackRate > 0) {
|
|
120
|
+
this.playbackRate = playbackRate
|
|
121
|
+
_playerView?.selectPlaybackRate(playbackRate)
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
@ReactProp(name = "hideUI")
|
|
126
|
+
fun setHideUI(view: SpallaPlayerContainerView, hideUI: Boolean) {
|
|
127
|
+
this.hideUI = hideUI
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
private fun checkAndLoadPlayer(view: SpallaPlayerContainerView) {
|
|
131
|
+
if (contentId != null && startTime != null && hideUI != null) {
|
|
132
|
+
view.post {
|
|
133
|
+
view.spallaPlayerView.load(contentId!!, true, startTime!!, subtitle, hideUI!!)
|
|
134
|
+
}
|
|
175
135
|
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
override fun onEvent(event: SpallaPlayerEvent) {
|
|
139
|
+
val map: WritableMap = Arguments.createMap()
|
|
140
|
+
|
|
141
|
+
Log.v("RNSpallaPlayerManager", "onEvent: $event")
|
|
142
|
+
when (event) {
|
|
143
|
+
is DurationUpdate -> {
|
|
144
|
+
map.putString("event", "durationUpdate")
|
|
145
|
+
map.putDouble("duration", event.duration)
|
|
146
|
+
requestLayout()
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
Ended -> map.putString("event", "ended")
|
|
150
|
+
is Error -> {
|
|
151
|
+
map.putString("event", "error")
|
|
152
|
+
map.putString("message", event.message)
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
Pause -> map.putString("event", "pause")
|
|
156
|
+
Play -> map.putString("event", "play")
|
|
157
|
+
Playing -> map.putString("event", "playing")
|
|
158
|
+
is TimeUpdate -> {
|
|
159
|
+
map.putString("event", "timeUpdate")
|
|
160
|
+
map.putDouble("time", event.currentTime)
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
Waiting -> map.putString("event", "buffering")
|
|
164
|
+
is SubtitlesAvailable -> {
|
|
165
|
+
map.putString("event", "subtitlesAvailable")
|
|
166
|
+
|
|
167
|
+
var subs = Arguments.createArray()
|
|
168
|
+
event.subtitles.forEach {
|
|
169
|
+
subs.pushString(it)
|
|
170
|
+
}
|
|
171
|
+
map.putArray("subtitles", subs)
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
is SubtitleSelected -> {
|
|
175
|
+
map.putString("event", "subtitleSelected")
|
|
176
|
+
map.putString("subtitle", event.subtitle)
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
is MetadataLoaded -> {
|
|
180
|
+
map.putString("event", "metadataLoaded")
|
|
181
|
+
map.putBoolean("isLive", event.metadata.isLive)
|
|
182
|
+
map.putDouble("duration", event.metadata.duration)
|
|
183
|
+
|
|
184
|
+
// make sure current playback rate is applied if set initially
|
|
185
|
+
_playerView?.selectPlaybackRate(playbackRate)
|
|
186
|
+
requestLayout()
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
is PlaybackRateSelected -> {
|
|
190
|
+
map.putString("event", "playbackRateSelected")
|
|
191
|
+
map.putDouble("rate", event.rate)
|
|
192
|
+
requestLayout()
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
}
|
|
196
|
+
_container?.let { container ->
|
|
197
|
+
_reactContext?.getJSModule(RCTEventEmitter::class.java)?.receiveEvent(
|
|
198
|
+
container.id,
|
|
199
|
+
"onPlayerEvent",
|
|
200
|
+
map
|
|
201
|
+
)
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
override fun onEnterFullScreen() {
|
|
206
|
+
Log.v("SpallaPlayerViewManager", "onEnterFullScreen")
|
|
207
|
+
val map: WritableMap = Arguments.createMap()
|
|
208
|
+
map.putString("event", "enterFullScreen")
|
|
209
|
+
_container?.let { container ->
|
|
210
|
+
_reactContext?.getJSModule(RCTEventEmitter::class.java)?.receiveEvent(
|
|
211
|
+
container.id,
|
|
212
|
+
"onPlayerEvent",
|
|
213
|
+
map
|
|
214
|
+
)
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
override fun onExitFullScreen() {
|
|
219
|
+
val map: WritableMap = Arguments.createMap()
|
|
220
|
+
map.putString("event", "exitFullScreen")
|
|
221
|
+
_container?.let { container ->
|
|
222
|
+
_reactContext?.getJSModule(RCTEventEmitter::class.java)?.receiveEvent(
|
|
223
|
+
container.id,
|
|
224
|
+
"onPlayerEvent",
|
|
225
|
+
map
|
|
226
|
+
)
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
fun requestLayout() {
|
|
231
|
+
_playerView?.post(measureAndLayout)
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
private val measureAndLayout = Runnable {
|
|
235
|
+
_playerView?.let {
|
|
236
|
+
it.measure(
|
|
237
|
+
View.MeasureSpec.makeMeasureSpec(it.width, View.MeasureSpec.EXACTLY),
|
|
238
|
+
View.MeasureSpec.makeMeasureSpec(it.height, View.MeasureSpec.EXACTLY)
|
|
239
|
+
)
|
|
240
|
+
it.layout(
|
|
241
|
+
it.left,
|
|
242
|
+
it.top,
|
|
243
|
+
it.right,
|
|
244
|
+
it.bottom
|
|
245
|
+
)
|
|
246
|
+
}
|
|
247
|
+
}
|
|
232
248
|
|
|
233
249
|
}
|