react-native-tpstreams 0.2.0 → 0.2.2
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/README.md +107 -6
- package/android/build.gradle +1 -1
- package/android/src/main/java/com/tpstreams/TPStreamsRNPlayerView.kt +110 -1
- package/android/src/main/java/com/tpstreams/TPStreamsRNPlayerViewManager.kt +68 -17
- package/lib/module/TPStreamsPlayer.js +159 -0
- package/lib/module/TPStreamsPlayer.js.map +1 -0
- package/lib/module/TPStreamsPlayerViewNativeComponent.ts +62 -1
- package/lib/module/index.js +5 -1
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/TPStreamsPlayer.d.ts +32 -0
- package/lib/typescript/src/TPStreamsPlayer.d.ts.map +1 -0
- package/lib/typescript/src/TPStreamsPlayerViewNativeComponent.d.ts +46 -1
- package/lib/typescript/src/TPStreamsPlayerViewNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +3 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/TPStreamsPlayer.tsx +221 -0
- package/src/TPStreamsPlayerViewNativeComponent.ts +62 -1
- package/src/index.tsx +6 -1
package/README.md
CHANGED
|
@@ -2,24 +2,33 @@
|
|
|
2
2
|
|
|
3
3
|
Video player component for TPStreams
|
|
4
4
|
|
|
5
|
+
---
|
|
6
|
+
|
|
5
7
|
## Installation
|
|
6
8
|
|
|
7
9
|
```sh
|
|
8
10
|
npm install react-native-tpstreams
|
|
9
11
|
```
|
|
10
12
|
|
|
11
|
-
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Getting Started
|
|
16
|
+
|
|
17
|
+
### Initialize TPStreams
|
|
12
18
|
|
|
13
|
-
|
|
19
|
+
First, initialize TPStreams with your organization ID. This should be done **only once** at your app's entry point (e.g., App.js or index.js):
|
|
14
20
|
|
|
15
21
|
```js
|
|
16
22
|
import { TPStreams } from "react-native-tpstreams";
|
|
17
23
|
|
|
18
24
|
// Initialize with your organization ID
|
|
25
|
+
// Do this only once at your app's entry point
|
|
19
26
|
TPStreams.initialize('YOUR_ORGANIZATION_ID');
|
|
20
27
|
```
|
|
21
28
|
|
|
22
|
-
|
|
29
|
+
### Add the Player Component
|
|
30
|
+
|
|
31
|
+
Then add the player component to your app:
|
|
23
32
|
|
|
24
33
|
```js
|
|
25
34
|
import { TPStreamsPlayerView } from "react-native-tpstreams";
|
|
@@ -32,6 +41,100 @@ import { TPStreamsPlayerView } from "react-native-tpstreams";
|
|
|
32
41
|
/>
|
|
33
42
|
```
|
|
34
43
|
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Player Methods
|
|
47
|
+
|
|
48
|
+
- `play()`: Starts video playback.
|
|
49
|
+
|
|
50
|
+
- `pause()`: Pauses video playback.
|
|
51
|
+
|
|
52
|
+
- `seekTo(positionMs: number)`: Seeks to position in milliseconds.
|
|
53
|
+
|
|
54
|
+
- `setPlaybackSpeed(speed: number)`: Sets playback speed (e.g., 0.5, 1.0, 2.0).
|
|
55
|
+
|
|
56
|
+
- `getCurrentPosition()`: Gets current position in milliseconds. Returns `Promise<number>`.
|
|
57
|
+
|
|
58
|
+
- `getDuration()`: Gets video duration in milliseconds. Returns `Promise<number>`.
|
|
59
|
+
|
|
60
|
+
- `isPlaying()`: Checks if video is currently playing. Returns `Promise<boolean>`.
|
|
61
|
+
|
|
62
|
+
- `getPlaybackSpeed()`: Gets current playback speed. Returns `Promise<number>`.
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## Player Events
|
|
67
|
+
|
|
68
|
+
- `onPlayerStateChanged(state: number)`: Fires when player state changes.
|
|
69
|
+
|
|
70
|
+
- `onIsPlayingChanged(isPlaying: boolean)`: Fires when playing state changes.
|
|
71
|
+
|
|
72
|
+
- `onPlaybackSpeedChanged(speed: number)`: Fires when playback speed changes.
|
|
73
|
+
|
|
74
|
+
- `onIsLoadingChanged(isLoading: boolean)`: Fires when loading state changes.
|
|
75
|
+
|
|
76
|
+
- `onError(error: {message: string, code: number, details?: string})`: Fires when an error occurs.
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Example
|
|
81
|
+
|
|
82
|
+
```js
|
|
83
|
+
import { useRef } from 'react';
|
|
84
|
+
import { View, Button } from 'react-native';
|
|
85
|
+
import { TPStreamsPlayerView } from 'react-native-tpstreams';
|
|
86
|
+
import type { TPStreamsPlayerRef } from 'react-native-tpstreams';
|
|
87
|
+
|
|
88
|
+
function TPStreamsPlayerExample() {
|
|
89
|
+
const playerRef = useRef<TPStreamsPlayerRef>(null);
|
|
90
|
+
|
|
91
|
+
const handlePlay = () => {
|
|
92
|
+
playerRef.current?.play();
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const handlePause = () => {
|
|
96
|
+
playerRef.current?.pause();
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const handleSeek = () => {
|
|
100
|
+
playerRef.current?.seekTo(30000); // 30 seconds
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const checkPosition = async () => {
|
|
104
|
+
try {
|
|
105
|
+
const position = await playerRef.current?.getCurrentPosition();
|
|
106
|
+
console.log(`Current position: ${position}ms`);
|
|
107
|
+
} catch (error) {
|
|
108
|
+
console.error('Error getting position:', error);
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
return (
|
|
113
|
+
<View>
|
|
114
|
+
<TPStreamsPlayerView
|
|
115
|
+
ref={playerRef}
|
|
116
|
+
videoId="YOUR_VIDEO_ID"
|
|
117
|
+
accessToken="YOUR_ACCESS_TOKEN"
|
|
118
|
+
style={{ height: 250 }}
|
|
119
|
+
onPlayerStateChanged={(state) => console.log(`Player state: ${state}`)}
|
|
120
|
+
onIsPlayingChanged={(isPlaying) => console.log(`Is playing: ${isPlaying}`)}
|
|
121
|
+
onPlaybackSpeedChanged={(speed) => console.log(`Speed changed: ${speed}x`)}
|
|
122
|
+
onIsLoadingChanged={(isLoading) => console.log(`Loading: ${isLoading}`)}
|
|
123
|
+
onError={(error) => console.error('Player error:', error)}
|
|
124
|
+
/>
|
|
125
|
+
|
|
126
|
+
<Button title="Play" onPress={handlePlay} />
|
|
127
|
+
<Button title="Pause" onPress={handlePause} />
|
|
128
|
+
<Button title="Seek to 30s" onPress={handleSeek} />
|
|
129
|
+
<Button title="2x Speed" onPress={() => playerRef.current?.setPlaybackSpeed(2.0)} />
|
|
130
|
+
<Button title="Get Position" onPress={checkPosition} />
|
|
131
|
+
</View>
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
35
138
|
## Contributing
|
|
36
139
|
|
|
37
140
|
See the [contributing guide](CONTRIBUTING.md) to learn how to contribute to the repository and the development workflow.
|
|
@@ -40,6 +143,4 @@ See the [contributing guide](CONTRIBUTING.md) to learn how to contribute to the
|
|
|
40
143
|
|
|
41
144
|
MIT
|
|
42
145
|
|
|
43
|
-
---
|
|
44
|
-
|
|
45
|
-
Made with [create-react-native-library](https://github.com/callstack/react-native-builder-bob)
|
|
146
|
+
---
|
package/android/build.gradle
CHANGED
|
@@ -84,7 +84,7 @@ def kotlin_version = getExtOrDefault("kotlinVersion")
|
|
|
84
84
|
dependencies {
|
|
85
85
|
implementation "com.facebook.react:react-android"
|
|
86
86
|
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
|
87
|
-
implementation "com.tpstreams:tpstreams-player:0.0.
|
|
87
|
+
implementation "com.tpstreams:tpstreams-player:0.0.2"
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
react {
|
|
@@ -2,14 +2,20 @@ package com.tpstreams
|
|
|
2
2
|
|
|
3
3
|
import android.util.Log
|
|
4
4
|
import android.widget.FrameLayout
|
|
5
|
+
import com.facebook.react.bridge.Arguments
|
|
6
|
+
import com.facebook.react.bridge.ReactContext
|
|
5
7
|
import com.facebook.react.uimanager.ThemedReactContext
|
|
8
|
+
import com.facebook.react.uimanager.events.RCTEventEmitter
|
|
6
9
|
import com.tpstreams.player.TPStreamsPlayer
|
|
7
10
|
import com.tpstreams.player.TPStreamsPlayerView
|
|
11
|
+
import androidx.media3.common.Player
|
|
12
|
+
import androidx.media3.common.PlaybackParameters
|
|
13
|
+
import androidx.media3.common.PlaybackException
|
|
8
14
|
|
|
9
15
|
class TPStreamsRNPlayerView(context: ThemedReactContext) : FrameLayout(context) {
|
|
10
|
-
|
|
11
16
|
private val playerView: TPStreamsPlayerView = TPStreamsPlayerView(context)
|
|
12
17
|
private var player: TPStreamsPlayer? = null
|
|
18
|
+
private val reactContext: ReactContext = context
|
|
13
19
|
|
|
14
20
|
private var videoId: String? = null
|
|
15
21
|
private var accessToken: String? = null
|
|
@@ -18,6 +24,31 @@ class TPStreamsRNPlayerView(context: ThemedReactContext) : FrameLayout(context)
|
|
|
18
24
|
addView(playerView, LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT))
|
|
19
25
|
}
|
|
20
26
|
|
|
27
|
+
// Emit React Native events
|
|
28
|
+
private fun emitEvent(eventName: String, data: Map<String, Any>) {
|
|
29
|
+
val event = Arguments.createMap()
|
|
30
|
+
data.forEach { (key, value) ->
|
|
31
|
+
when (value) {
|
|
32
|
+
is Int -> event.putInt(key, value)
|
|
33
|
+
is Double -> event.putDouble(key, value)
|
|
34
|
+
is Boolean -> event.putBoolean(key, value)
|
|
35
|
+
is String -> event.putString(key, value)
|
|
36
|
+
else -> Log.w("TPStreamsRN", "Unsupported type for event data: ${value::class.java}")
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
reactContext.getJSModule(RCTEventEmitter::class.java)
|
|
40
|
+
.receiveEvent(id, eventName, event)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
private fun sendErrorEvent(message: String, code: Int = 0, details: String? = null) {
|
|
44
|
+
val event = Arguments.createMap()
|
|
45
|
+
event.putString("message", message)
|
|
46
|
+
event.putInt("code", code)
|
|
47
|
+
details?.let { event.putString("details", it) }
|
|
48
|
+
reactContext.getJSModule(RCTEventEmitter::class.java)
|
|
49
|
+
.receiveEvent(id, "onError", event)
|
|
50
|
+
}
|
|
51
|
+
|
|
21
52
|
fun setVideoId(videoId: String?) {
|
|
22
53
|
this.videoId = videoId
|
|
23
54
|
tryCreatePlayer()
|
|
@@ -34,13 +65,91 @@ class TPStreamsRNPlayerView(context: ThemedReactContext) : FrameLayout(context)
|
|
|
34
65
|
|
|
35
66
|
try {
|
|
36
67
|
player = TPStreamsPlayer.create(context, videoId!!, accessToken!!)
|
|
68
|
+
|
|
69
|
+
// Add player event listeners
|
|
70
|
+
player?.addListener(createPlayerListener())
|
|
71
|
+
|
|
37
72
|
playerView.player = player
|
|
38
73
|
playerView.showController()
|
|
74
|
+
|
|
75
|
+
// Send initial events
|
|
76
|
+
emitEvent("onPlayerStateChanged", mapOf("playbackState" to 0))
|
|
77
|
+
emitEvent("onIsPlayingChanged", mapOf("isPlaying" to false))
|
|
78
|
+
emitEvent("onPlaybackSpeedChanged", mapOf("speed" to 1.0))
|
|
79
|
+
emitEvent("onIsLoadingChanged", mapOf("isLoading" to false))
|
|
39
80
|
} catch (e: Exception) {
|
|
40
81
|
Log.e("TPStreamsRN", "Error creating player", e)
|
|
82
|
+
sendErrorEvent("Error creating player", 1001, e.message)
|
|
41
83
|
}
|
|
42
84
|
}
|
|
43
85
|
|
|
86
|
+
private fun createPlayerListener(): Player.Listener {
|
|
87
|
+
return object : Player.Listener {
|
|
88
|
+
override fun onPlaybackStateChanged(playbackState: Int) {
|
|
89
|
+
emitEvent("onPlayerStateChanged", mapOf("playbackState" to playbackState))
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
override fun onIsPlayingChanged(isPlaying: Boolean) {
|
|
93
|
+
emitEvent("onIsPlayingChanged", mapOf("isPlaying" to isPlaying))
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
override fun onPlaybackParametersChanged(playbackParameters: PlaybackParameters) {
|
|
97
|
+
emitEvent("onPlaybackSpeedChanged", mapOf("speed" to playbackParameters.speed.toDouble()))
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
override fun onIsLoadingChanged(isLoading: Boolean) {
|
|
101
|
+
emitEvent("onIsLoadingChanged", mapOf("isLoading" to isLoading))
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
override fun onPlayerError(error: PlaybackException) {
|
|
105
|
+
Log.e("TPStreamsRN", "Player error", error)
|
|
106
|
+
sendErrorEvent("Playback error", error.errorCode, error.message)
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Player control methods
|
|
112
|
+
fun play() {
|
|
113
|
+
player?.play()
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
fun pause() {
|
|
117
|
+
player?.pause()
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
fun seekTo(positionMs: Long) {
|
|
121
|
+
player?.seekTo(positionMs)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
fun setPlaybackSpeed(speed: Float) {
|
|
125
|
+
player?.setPlaybackSpeed(speed)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Player information methods with event emission
|
|
129
|
+
fun getCurrentPosition(): Long {
|
|
130
|
+
val position = player?.currentPosition ?: 0L
|
|
131
|
+
emitEvent("onCurrentPosition", mapOf("position" to position.toDouble()))
|
|
132
|
+
return position
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
fun getDuration(): Long {
|
|
136
|
+
val duration = player?.duration ?: 0L
|
|
137
|
+
emitEvent("onDuration", mapOf("duration" to duration.toDouble()))
|
|
138
|
+
return duration
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
fun isPlaying(): Boolean {
|
|
142
|
+
val playing = player?.isPlaying ?: false
|
|
143
|
+
emitEvent("onIsPlaying", mapOf("isPlaying" to playing))
|
|
144
|
+
return playing
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
fun getPlaybackSpeed(): Float {
|
|
148
|
+
val speed = player?.playbackParameters?.speed ?: 1.0f
|
|
149
|
+
emitEvent("onPlaybackSpeed", mapOf("speed" to speed.toDouble()))
|
|
150
|
+
return speed
|
|
151
|
+
}
|
|
152
|
+
|
|
44
153
|
override fun onDetachedFromWindow() {
|
|
45
154
|
super.onDetachedFromWindow()
|
|
46
155
|
try {
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
package com.tpstreams
|
|
2
2
|
|
|
3
|
-
import com.facebook.react.bridge.ReadableMap
|
|
4
3
|
import com.facebook.react.module.annotations.ReactModule
|
|
5
4
|
import com.facebook.react.uimanager.SimpleViewManager
|
|
6
5
|
import com.facebook.react.uimanager.ThemedReactContext
|
|
@@ -8,39 +7,91 @@ import com.facebook.react.uimanager.ViewManagerDelegate
|
|
|
8
7
|
import com.facebook.react.uimanager.annotations.ReactProp
|
|
9
8
|
import com.facebook.react.viewmanagers.TPStreamsRNPlayerViewManagerInterface
|
|
10
9
|
import com.facebook.react.viewmanagers.TPStreamsRNPlayerViewManagerDelegate
|
|
10
|
+
import com.facebook.react.common.MapBuilder
|
|
11
11
|
|
|
12
12
|
@ReactModule(name = TPStreamsRNPlayerViewManager.NAME)
|
|
13
13
|
class TPStreamsRNPlayerViewManager : SimpleViewManager<TPStreamsRNPlayerView>(),
|
|
14
14
|
TPStreamsRNPlayerViewManagerInterface<TPStreamsRNPlayerView> {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
|
|
16
|
+
companion object {
|
|
17
|
+
const val NAME = "TPStreamsRNPlayerView"
|
|
18
|
+
|
|
19
|
+
// Event names
|
|
20
|
+
private const val EVENT_CURRENT_POSITION = "onCurrentPosition"
|
|
21
|
+
private const val EVENT_DURATION = "onDuration"
|
|
22
|
+
private const val EVENT_IS_PLAYING = "onIsPlaying"
|
|
23
|
+
private const val EVENT_PLAYBACK_SPEED = "onPlaybackSpeed"
|
|
24
|
+
private const val EVENT_PLAYER_STATE_CHANGED = "onPlayerStateChanged"
|
|
25
|
+
private const val EVENT_IS_PLAYING_CHANGED = "onIsPlayingChanged"
|
|
26
|
+
private const val EVENT_PLAYBACK_SPEED_CHANGED = "onPlaybackSpeedChanged"
|
|
27
|
+
private const val EVENT_IS_LOADING_CHANGED = "onIsLoadingChanged"
|
|
28
|
+
private const val EVENT_ERROR = "onError"
|
|
19
29
|
}
|
|
30
|
+
|
|
31
|
+
private val mDelegate: ViewManagerDelegate<TPStreamsRNPlayerView> =
|
|
32
|
+
TPStreamsRNPlayerViewManagerDelegate(this)
|
|
20
33
|
|
|
21
|
-
override fun getDelegate(): ViewManagerDelegate<TPStreamsRNPlayerView>?
|
|
22
|
-
return mDelegate
|
|
23
|
-
}
|
|
34
|
+
override fun getDelegate(): ViewManagerDelegate<TPStreamsRNPlayerView>? = mDelegate
|
|
24
35
|
|
|
25
|
-
override fun getName(): String
|
|
26
|
-
return NAME
|
|
27
|
-
}
|
|
36
|
+
override fun getName(): String = NAME
|
|
28
37
|
|
|
29
|
-
|
|
30
|
-
return
|
|
38
|
+
override fun getExportedCustomDirectEventTypeConstants(): Map<String, Any> {
|
|
39
|
+
return MapBuilder.builder<String, Any>()
|
|
40
|
+
.put(EVENT_CURRENT_POSITION, MapBuilder.of("registrationName", EVENT_CURRENT_POSITION))
|
|
41
|
+
.put(EVENT_DURATION, MapBuilder.of("registrationName", EVENT_DURATION))
|
|
42
|
+
.put(EVENT_IS_PLAYING, MapBuilder.of("registrationName", EVENT_IS_PLAYING))
|
|
43
|
+
.put(EVENT_PLAYBACK_SPEED, MapBuilder.of("registrationName", EVENT_PLAYBACK_SPEED))
|
|
44
|
+
.put(EVENT_PLAYER_STATE_CHANGED, MapBuilder.of("registrationName", EVENT_PLAYER_STATE_CHANGED))
|
|
45
|
+
.put(EVENT_IS_PLAYING_CHANGED, MapBuilder.of("registrationName", EVENT_IS_PLAYING_CHANGED))
|
|
46
|
+
.put(EVENT_PLAYBACK_SPEED_CHANGED, MapBuilder.of("registrationName", EVENT_PLAYBACK_SPEED_CHANGED))
|
|
47
|
+
.put(EVENT_IS_LOADING_CHANGED, MapBuilder.of("registrationName", EVENT_IS_LOADING_CHANGED))
|
|
48
|
+
.put(EVENT_ERROR, MapBuilder.of("registrationName", EVENT_ERROR))
|
|
49
|
+
.build()
|
|
31
50
|
}
|
|
32
51
|
|
|
52
|
+
public override fun createViewInstance(context: ThemedReactContext): TPStreamsRNPlayerView =
|
|
53
|
+
TPStreamsRNPlayerView(context)
|
|
54
|
+
|
|
33
55
|
@ReactProp(name = "videoId")
|
|
34
56
|
override fun setVideoId(view: TPStreamsRNPlayerView, videoId: String?) {
|
|
35
|
-
|
|
57
|
+
view.setVideoId(videoId)
|
|
36
58
|
}
|
|
37
59
|
|
|
38
60
|
@ReactProp(name = "accessToken")
|
|
39
61
|
override fun setAccessToken(view: TPStreamsRNPlayerView, accessToken: String?) {
|
|
40
|
-
|
|
62
|
+
view.setAccessToken(accessToken)
|
|
41
63
|
}
|
|
42
64
|
|
|
43
|
-
|
|
44
|
-
|
|
65
|
+
// Command implementations
|
|
66
|
+
override fun play(view: TPStreamsRNPlayerView) {
|
|
67
|
+
view.play()
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
override fun pause(view: TPStreamsRNPlayerView) {
|
|
71
|
+
view.pause()
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
override fun seekTo(view: TPStreamsRNPlayerView, positionMs: Double) {
|
|
75
|
+
view.seekTo(positionMs.toLong())
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
override fun setPlaybackSpeed(view: TPStreamsRNPlayerView, speed: Float) {
|
|
79
|
+
view.setPlaybackSpeed(speed)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
override fun getCurrentPosition(view: TPStreamsRNPlayerView) {
|
|
83
|
+
view.getCurrentPosition()
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
override fun getDuration(view: TPStreamsRNPlayerView) {
|
|
87
|
+
view.getDuration()
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
override fun isPlaying(view: TPStreamsRNPlayerView) {
|
|
91
|
+
view.isPlaying()
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
override fun getPlaybackSpeed(view: TPStreamsRNPlayerView) {
|
|
95
|
+
view.getPlaybackSpeed()
|
|
45
96
|
}
|
|
46
97
|
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { forwardRef, useImperativeHandle, useRef, useCallback } from 'react';
|
|
4
|
+
import TPStreamsPlayerNative, { Commands } from './TPStreamsPlayerViewNativeComponent';
|
|
5
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
6
|
+
// Create a unique ID for each instance to track promises
|
|
7
|
+
let nextInstanceId = 0;
|
|
8
|
+
|
|
9
|
+
// Type for tracking promises waiting to be resolved
|
|
10
|
+
|
|
11
|
+
// Return type for player API methods
|
|
12
|
+
|
|
13
|
+
// Prop types for the player component
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* TPStreamsPlayerView - React component wrapper for TPStreamsPlayerNative
|
|
17
|
+
* Provides a simple imperative API for controlling the player
|
|
18
|
+
*/
|
|
19
|
+
const TPStreamsPlayerView = /*#__PURE__*/forwardRef((props, ref) => {
|
|
20
|
+
const {
|
|
21
|
+
videoId,
|
|
22
|
+
accessToken,
|
|
23
|
+
style,
|
|
24
|
+
onPlayerStateChanged,
|
|
25
|
+
onIsPlayingChanged,
|
|
26
|
+
onPlaybackSpeedChanged,
|
|
27
|
+
onIsLoadingChanged,
|
|
28
|
+
onError,
|
|
29
|
+
...restProps
|
|
30
|
+
} = props;
|
|
31
|
+
const nativeRef = useRef(null);
|
|
32
|
+
const instanceId = useRef(nextInstanceId++);
|
|
33
|
+
const promiseMap = useRef({});
|
|
34
|
+
|
|
35
|
+
// Event handlers that resolve promises
|
|
36
|
+
const onCurrentPosition = useCallback(event => {
|
|
37
|
+
const key = `position-${instanceId.current}`;
|
|
38
|
+
const handler = promiseMap.current[key];
|
|
39
|
+
if (handler) {
|
|
40
|
+
handler.resolve(event.nativeEvent.position);
|
|
41
|
+
delete promiseMap.current[key];
|
|
42
|
+
}
|
|
43
|
+
}, []);
|
|
44
|
+
const onDuration = useCallback(event => {
|
|
45
|
+
const key = `duration-${instanceId.current}`;
|
|
46
|
+
const handler = promiseMap.current[key];
|
|
47
|
+
if (handler) {
|
|
48
|
+
handler.resolve(event.nativeEvent.duration);
|
|
49
|
+
delete promiseMap.current[key];
|
|
50
|
+
}
|
|
51
|
+
}, []);
|
|
52
|
+
const onIsPlaying = useCallback(event => {
|
|
53
|
+
const key = `isPlaying-${instanceId.current}`;
|
|
54
|
+
const handler = promiseMap.current[key];
|
|
55
|
+
if (handler) {
|
|
56
|
+
handler.resolve(event.nativeEvent.isPlaying);
|
|
57
|
+
delete promiseMap.current[key];
|
|
58
|
+
}
|
|
59
|
+
}, []);
|
|
60
|
+
const onPlaybackSpeed = useCallback(event => {
|
|
61
|
+
const key = `playbackSpeed-${instanceId.current}`;
|
|
62
|
+
const handler = promiseMap.current[key];
|
|
63
|
+
if (handler) {
|
|
64
|
+
handler.resolve(event.nativeEvent.speed);
|
|
65
|
+
delete promiseMap.current[key];
|
|
66
|
+
}
|
|
67
|
+
}, []);
|
|
68
|
+
|
|
69
|
+
// Player event handlers
|
|
70
|
+
const handlePlayerStateChanged = useCallback(event => {
|
|
71
|
+
onPlayerStateChanged?.(event.nativeEvent.playbackState);
|
|
72
|
+
}, [onPlayerStateChanged]);
|
|
73
|
+
const handleIsPlayingChanged = useCallback(event => {
|
|
74
|
+
onIsPlayingChanged?.(event.nativeEvent.isPlaying);
|
|
75
|
+
}, [onIsPlayingChanged]);
|
|
76
|
+
const handlePlaybackSpeedChanged = useCallback(event => {
|
|
77
|
+
onPlaybackSpeedChanged?.(event.nativeEvent.speed);
|
|
78
|
+
}, [onPlaybackSpeedChanged]);
|
|
79
|
+
const handleIsLoadingChanged = useCallback(event => {
|
|
80
|
+
onIsLoadingChanged?.(event.nativeEvent.isLoading);
|
|
81
|
+
}, [onIsLoadingChanged]);
|
|
82
|
+
const handleError = useCallback(event => {
|
|
83
|
+
const {
|
|
84
|
+
message,
|
|
85
|
+
code,
|
|
86
|
+
details
|
|
87
|
+
} = event.nativeEvent;
|
|
88
|
+
|
|
89
|
+
// Reject any pending promises with this error
|
|
90
|
+
Object.entries(promiseMap.current).forEach(([key, handler]) => {
|
|
91
|
+
handler.reject(new Error(`${message}: ${details || 'Unknown error'}`));
|
|
92
|
+
delete promiseMap.current[key];
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// Forward the error to the client if they provided an onError handler
|
|
96
|
+
onError?.({
|
|
97
|
+
message,
|
|
98
|
+
code,
|
|
99
|
+
details
|
|
100
|
+
});
|
|
101
|
+
}, [onError]);
|
|
102
|
+
|
|
103
|
+
// Helper to create promise-based API methods
|
|
104
|
+
const createPromiseMethod = useCallback((command, eventKey) => {
|
|
105
|
+
return () => new Promise((resolve, reject) => {
|
|
106
|
+
if (nativeRef.current) {
|
|
107
|
+
const key = `${eventKey}-${instanceId.current}`;
|
|
108
|
+
promiseMap.current[key] = {
|
|
109
|
+
resolve,
|
|
110
|
+
reject
|
|
111
|
+
};
|
|
112
|
+
command(nativeRef.current);
|
|
113
|
+
|
|
114
|
+
// Set a timeout to reject the promise if it's not resolved in time
|
|
115
|
+
setTimeout(() => {
|
|
116
|
+
if (promiseMap.current[key]) {
|
|
117
|
+
reject(new Error(`Timeout getting ${eventKey}`));
|
|
118
|
+
delete promiseMap.current[key];
|
|
119
|
+
}
|
|
120
|
+
}, 5000);
|
|
121
|
+
} else {
|
|
122
|
+
reject(new Error('Player is not initialized'));
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
}, []);
|
|
126
|
+
useImperativeHandle(ref, () => ({
|
|
127
|
+
play: () => nativeRef.current && Commands.play(nativeRef.current),
|
|
128
|
+
pause: () => nativeRef.current && Commands.pause(nativeRef.current),
|
|
129
|
+
seekTo: positionMs => nativeRef.current && Commands.seekTo(nativeRef.current, positionMs),
|
|
130
|
+
setPlaybackSpeed: speed => nativeRef.current && Commands.setPlaybackSpeed(nativeRef.current, speed),
|
|
131
|
+
getCurrentPosition: createPromiseMethod(Commands.getCurrentPosition, 'position'),
|
|
132
|
+
getDuration: createPromiseMethod(Commands.getDuration, 'duration'),
|
|
133
|
+
isPlaying: createPromiseMethod(Commands.isPlaying, 'isPlaying'),
|
|
134
|
+
getPlaybackSpeed: createPromiseMethod(Commands.getPlaybackSpeed, 'speed')
|
|
135
|
+
}), [createPromiseMethod]);
|
|
136
|
+
|
|
137
|
+
// Create native props object with the correct types
|
|
138
|
+
const nativeProps = {
|
|
139
|
+
...restProps,
|
|
140
|
+
videoId,
|
|
141
|
+
accessToken,
|
|
142
|
+
style,
|
|
143
|
+
onCurrentPosition,
|
|
144
|
+
onDuration,
|
|
145
|
+
onIsPlaying,
|
|
146
|
+
onPlaybackSpeed,
|
|
147
|
+
onPlayerStateChanged: handlePlayerStateChanged,
|
|
148
|
+
onIsPlayingChanged: handleIsPlayingChanged,
|
|
149
|
+
onPlaybackSpeedChanged: handlePlaybackSpeedChanged,
|
|
150
|
+
onIsLoadingChanged: handleIsLoadingChanged,
|
|
151
|
+
onError: handleError
|
|
152
|
+
};
|
|
153
|
+
return /*#__PURE__*/_jsx(TPStreamsPlayerNative, {
|
|
154
|
+
...nativeProps,
|
|
155
|
+
ref: nativeRef
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
export default TPStreamsPlayerView;
|
|
159
|
+
//# sourceMappingURL=TPStreamsPlayer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["forwardRef","useImperativeHandle","useRef","useCallback","TPStreamsPlayerNative","Commands","jsx","_jsx","nextInstanceId","TPStreamsPlayerView","props","ref","videoId","accessToken","style","onPlayerStateChanged","onIsPlayingChanged","onPlaybackSpeedChanged","onIsLoadingChanged","onError","restProps","nativeRef","instanceId","promiseMap","onCurrentPosition","event","key","current","handler","resolve","nativeEvent","position","onDuration","duration","onIsPlaying","isPlaying","onPlaybackSpeed","speed","handlePlayerStateChanged","playbackState","handleIsPlayingChanged","handlePlaybackSpeedChanged","handleIsLoadingChanged","isLoading","handleError","message","code","details","Object","entries","forEach","reject","Error","createPromiseMethod","command","eventKey","Promise","setTimeout","play","pause","seekTo","positionMs","setPlaybackSpeed","getCurrentPosition","getDuration","getPlaybackSpeed","nativeProps"],"sourceRoot":"../../src","sources":["TPStreamsPlayer.tsx"],"mappings":"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","ignoreList":[]}
|
|
@@ -1,9 +1,70 @@
|
|
|
1
1
|
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
|
|
2
2
|
import type { ViewProps } from 'react-native';
|
|
3
|
+
import type {
|
|
4
|
+
Double,
|
|
5
|
+
Float,
|
|
6
|
+
Int32,
|
|
7
|
+
} from 'react-native/Libraries/Types/CodegenTypes';
|
|
8
|
+
import type { HostComponent } from 'react-native';
|
|
9
|
+
import type { DirectEventHandler } from 'react-native/Libraries/Types/CodegenTypes';
|
|
10
|
+
import codegenNativeCommands from 'react-native/Libraries/Utilities/codegenNativeCommands';
|
|
3
11
|
|
|
4
|
-
interface
|
|
12
|
+
export interface ErrorEvent {
|
|
13
|
+
message: string;
|
|
14
|
+
code: Int32;
|
|
15
|
+
details?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface NativeProps extends ViewProps {
|
|
5
19
|
videoId?: string;
|
|
6
20
|
accessToken?: string;
|
|
21
|
+
|
|
22
|
+
// Event props for receiving data from native methods
|
|
23
|
+
onCurrentPosition?: DirectEventHandler<{ position: Double }>;
|
|
24
|
+
onDuration?: DirectEventHandler<{ duration: Double }>;
|
|
25
|
+
onIsPlaying?: DirectEventHandler<{ isPlaying: boolean }>;
|
|
26
|
+
onPlaybackSpeed?: DirectEventHandler<{ speed: Float }>;
|
|
27
|
+
|
|
28
|
+
// Player event props
|
|
29
|
+
onPlayerStateChanged?: DirectEventHandler<{ playbackState: Int32 }>;
|
|
30
|
+
onIsPlayingChanged?: DirectEventHandler<{ isPlaying: boolean }>;
|
|
31
|
+
onPlaybackSpeedChanged?: DirectEventHandler<{ speed: Double }>;
|
|
32
|
+
onIsLoadingChanged?: DirectEventHandler<{ isLoading: boolean }>;
|
|
33
|
+
onError?: DirectEventHandler<ErrorEvent>;
|
|
7
34
|
}
|
|
8
35
|
|
|
36
|
+
interface TPStreamsPlayerViewCommands {
|
|
37
|
+
play: (viewRef: React.ElementRef<HostComponent<NativeProps>>) => void;
|
|
38
|
+
pause: (viewRef: React.ElementRef<HostComponent<NativeProps>>) => void;
|
|
39
|
+
seekTo: (
|
|
40
|
+
viewRef: React.ElementRef<HostComponent<NativeProps>>,
|
|
41
|
+
positionMs: Double
|
|
42
|
+
) => void;
|
|
43
|
+
setPlaybackSpeed: (
|
|
44
|
+
viewRef: React.ElementRef<HostComponent<NativeProps>>,
|
|
45
|
+
speed: Float
|
|
46
|
+
) => void;
|
|
47
|
+
getCurrentPosition: (
|
|
48
|
+
viewRef: React.ElementRef<HostComponent<NativeProps>>
|
|
49
|
+
) => void;
|
|
50
|
+
getDuration: (viewRef: React.ElementRef<HostComponent<NativeProps>>) => void;
|
|
51
|
+
isPlaying: (viewRef: React.ElementRef<HostComponent<NativeProps>>) => void;
|
|
52
|
+
getPlaybackSpeed: (
|
|
53
|
+
viewRef: React.ElementRef<HostComponent<NativeProps>>
|
|
54
|
+
) => void;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export const Commands = codegenNativeCommands<TPStreamsPlayerViewCommands>({
|
|
58
|
+
supportedCommands: [
|
|
59
|
+
'play',
|
|
60
|
+
'pause',
|
|
61
|
+
'seekTo',
|
|
62
|
+
'setPlaybackSpeed',
|
|
63
|
+
'getCurrentPosition',
|
|
64
|
+
'getDuration',
|
|
65
|
+
'isPlaying',
|
|
66
|
+
'getPlaybackSpeed',
|
|
67
|
+
],
|
|
68
|
+
});
|
|
69
|
+
|
|
9
70
|
export default codegenNativeComponent<NativeProps>('TPStreamsRNPlayerView');
|
package/lib/module/index.js
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
import { NativeModules } from 'react-native';
|
|
4
|
-
|
|
4
|
+
// Export the native component with a different name to avoid conflicts
|
|
5
|
+
export { default as TPStreamsPlayerNative } from './TPStreamsPlayerViewNativeComponent';
|
|
5
6
|
export * from './TPStreamsPlayerViewNativeComponent';
|
|
7
|
+
|
|
8
|
+
// Export the wrapper component as TPStreamsPlayerView
|
|
9
|
+
export { default as TPStreamsPlayerView } from "./TPStreamsPlayer.js";
|
|
6
10
|
const TPStreamsModule = NativeModules.TPStreams;
|
|
7
11
|
export const TPStreams = {
|
|
8
12
|
initialize: organizationId => {
|
package/lib/module/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["NativeModules","default","TPStreamsPlayerView","TPStreamsModule","TPStreams","initialize","organizationId"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,SAASA,aAAa,QAAQ,cAAc;AAC5C,SAASC,OAAO,IAAIC,
|
|
1
|
+
{"version":3,"names":["NativeModules","default","TPStreamsPlayerNative","TPStreamsPlayerView","TPStreamsModule","TPStreams","initialize","organizationId"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,SAASA,aAAa,QAAQ,cAAc;AAC5C;AACA,SAASC,OAAO,IAAIC,qBAAqB,QAAQ,sCAAsC;AACvF,cAAc,sCAAsC;;AAEpD;AACA,SAASD,OAAO,IAAIE,mBAAmB,QAAQ,sBAAmB;AAGlE,MAAMC,eAAe,GAAGJ,aAAa,CAACK,SAAS;AAE/C,OAAO,MAAMA,SAAS,GAAG;EACvBC,UAAU,EAAGC,cAAsB,IAAW;IAC5CH,eAAe,CAACE,UAAU,CAACC,cAAc,CAAC;EAC5C;AACF,CAAC","ignoreList":[]}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import type { ViewProps } from 'react-native';
|
|
3
|
+
export interface TPStreamsPlayerRef {
|
|
4
|
+
play: () => void;
|
|
5
|
+
pause: () => void;
|
|
6
|
+
seekTo: (positionMs: number) => void;
|
|
7
|
+
setPlaybackSpeed: (speed: number) => void;
|
|
8
|
+
getCurrentPosition: () => Promise<number>;
|
|
9
|
+
getDuration: () => Promise<number>;
|
|
10
|
+
isPlaying: () => Promise<boolean>;
|
|
11
|
+
getPlaybackSpeed: () => Promise<number>;
|
|
12
|
+
}
|
|
13
|
+
export interface TPStreamsPlayerProps extends ViewProps {
|
|
14
|
+
videoId?: string;
|
|
15
|
+
accessToken?: string;
|
|
16
|
+
onPlayerStateChanged?: (state: number) => void;
|
|
17
|
+
onIsPlayingChanged?: (isPlaying: boolean) => void;
|
|
18
|
+
onPlaybackSpeedChanged?: (speed: number) => void;
|
|
19
|
+
onIsLoadingChanged?: (isLoading: boolean) => void;
|
|
20
|
+
onError?: (error: {
|
|
21
|
+
message: string;
|
|
22
|
+
code: number;
|
|
23
|
+
details?: string;
|
|
24
|
+
}) => void;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* TPStreamsPlayerView - React component wrapper for TPStreamsPlayerNative
|
|
28
|
+
* Provides a simple imperative API for controlling the player
|
|
29
|
+
*/
|
|
30
|
+
declare const TPStreamsPlayerView: import("react").ForwardRefExoticComponent<TPStreamsPlayerProps & import("react").RefAttributes<TPStreamsPlayerRef>>;
|
|
31
|
+
export default TPStreamsPlayerView;
|
|
32
|
+
//# sourceMappingURL=TPStreamsPlayer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TPStreamsPlayer.d.ts","sourceRoot":"","sources":["../../../src/TPStreamsPlayer.tsx"],"names":[],"mappings":";AAQA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAc9C,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,MAAM,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,gBAAgB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,kBAAkB,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IAC1C,WAAW,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACnC,SAAS,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IAClC,gBAAgB,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;CACzC;AAGD,MAAM,WAAW,oBAAqB,SAAQ,SAAS;IACrD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oBAAoB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/C,kBAAkB,CAAC,EAAE,CAAC,SAAS,EAAE,OAAO,KAAK,IAAI,CAAC;IAClD,sBAAsB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACjD,kBAAkB,CAAC,EAAE,CAAC,SAAS,EAAE,OAAO,KAAK,IAAI,CAAC;IAClD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE;QAChB,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,KAAK,IAAI,CAAC;CACZ;AAED;;;GAGG;AACH,QAAA,MAAM,mBAAmB,qHAsKvB,CAAC;AAEH,eAAe,mBAAmB,CAAC"}
|
|
@@ -1,9 +1,54 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
1
2
|
/// <reference types="react-native/types/modules/Codegen" />
|
|
2
3
|
import type { ViewProps } from 'react-native';
|
|
3
|
-
|
|
4
|
+
import type { Double, Float, Int32 } from 'react-native/Libraries/Types/CodegenTypes';
|
|
5
|
+
import type { HostComponent } from 'react-native';
|
|
6
|
+
import type { DirectEventHandler } from 'react-native/Libraries/Types/CodegenTypes';
|
|
7
|
+
export interface ErrorEvent {
|
|
8
|
+
message: string;
|
|
9
|
+
code: Int32;
|
|
10
|
+
details?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface NativeProps extends ViewProps {
|
|
4
13
|
videoId?: string;
|
|
5
14
|
accessToken?: string;
|
|
15
|
+
onCurrentPosition?: DirectEventHandler<{
|
|
16
|
+
position: Double;
|
|
17
|
+
}>;
|
|
18
|
+
onDuration?: DirectEventHandler<{
|
|
19
|
+
duration: Double;
|
|
20
|
+
}>;
|
|
21
|
+
onIsPlaying?: DirectEventHandler<{
|
|
22
|
+
isPlaying: boolean;
|
|
23
|
+
}>;
|
|
24
|
+
onPlaybackSpeed?: DirectEventHandler<{
|
|
25
|
+
speed: Float;
|
|
26
|
+
}>;
|
|
27
|
+
onPlayerStateChanged?: DirectEventHandler<{
|
|
28
|
+
playbackState: Int32;
|
|
29
|
+
}>;
|
|
30
|
+
onIsPlayingChanged?: DirectEventHandler<{
|
|
31
|
+
isPlaying: boolean;
|
|
32
|
+
}>;
|
|
33
|
+
onPlaybackSpeedChanged?: DirectEventHandler<{
|
|
34
|
+
speed: Double;
|
|
35
|
+
}>;
|
|
36
|
+
onIsLoadingChanged?: DirectEventHandler<{
|
|
37
|
+
isLoading: boolean;
|
|
38
|
+
}>;
|
|
39
|
+
onError?: DirectEventHandler<ErrorEvent>;
|
|
40
|
+
}
|
|
41
|
+
interface TPStreamsPlayerViewCommands {
|
|
42
|
+
play: (viewRef: React.ElementRef<HostComponent<NativeProps>>) => void;
|
|
43
|
+
pause: (viewRef: React.ElementRef<HostComponent<NativeProps>>) => void;
|
|
44
|
+
seekTo: (viewRef: React.ElementRef<HostComponent<NativeProps>>, positionMs: Double) => void;
|
|
45
|
+
setPlaybackSpeed: (viewRef: React.ElementRef<HostComponent<NativeProps>>, speed: Float) => void;
|
|
46
|
+
getCurrentPosition: (viewRef: React.ElementRef<HostComponent<NativeProps>>) => void;
|
|
47
|
+
getDuration: (viewRef: React.ElementRef<HostComponent<NativeProps>>) => void;
|
|
48
|
+
isPlaying: (viewRef: React.ElementRef<HostComponent<NativeProps>>) => void;
|
|
49
|
+
getPlaybackSpeed: (viewRef: React.ElementRef<HostComponent<NativeProps>>) => void;
|
|
6
50
|
}
|
|
51
|
+
export declare const Commands: TPStreamsPlayerViewCommands;
|
|
7
52
|
declare const _default: import("react-native/Libraries/Utilities/codegenNativeComponent").NativeComponentType<NativeProps>;
|
|
8
53
|
export default _default;
|
|
9
54
|
//# sourceMappingURL=TPStreamsPlayerViewNativeComponent.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TPStreamsPlayerViewNativeComponent.d.ts","sourceRoot":"","sources":["../../../src/TPStreamsPlayerViewNativeComponent.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"TPStreamsPlayerViewNativeComponent.d.ts","sourceRoot":"","sources":["../../../src/TPStreamsPlayerViewNativeComponent.ts"],"names":[],"mappings":";;AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,KAAK,EACV,MAAM,EACN,KAAK,EACL,KAAK,EACN,MAAM,2CAA2C,CAAC;AACnD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2CAA2C,CAAC;AAGpF,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,KAAK,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,WAAY,SAAQ,SAAS;IAC5C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IAGrB,iBAAiB,CAAC,EAAE,kBAAkB,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC7D,UAAU,CAAC,EAAE,kBAAkB,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACtD,WAAW,CAAC,EAAE,kBAAkB,CAAC;QAAE,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IACzD,eAAe,CAAC,EAAE,kBAAkB,CAAC;QAAE,KAAK,EAAE,KAAK,CAAA;KAAE,CAAC,CAAC;IAGvD,oBAAoB,CAAC,EAAE,kBAAkB,CAAC;QAAE,aAAa,EAAE,KAAK,CAAA;KAAE,CAAC,CAAC;IACpE,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;QAAE,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAChE,sBAAsB,CAAC,EAAE,kBAAkB,CAAC;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/D,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;QAAE,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAChE,OAAO,CAAC,EAAE,kBAAkB,CAAC,UAAU,CAAC,CAAC;CAC1C;AAED,UAAU,2BAA2B;IACnC,IAAI,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,UAAU,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC,KAAK,IAAI,CAAC;IACtE,KAAK,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,UAAU,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC,KAAK,IAAI,CAAC;IACvE,MAAM,EAAE,CACN,OAAO,EAAE,KAAK,CAAC,UAAU,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC,EACrD,UAAU,EAAE,MAAM,KACf,IAAI,CAAC;IACV,gBAAgB,EAAE,CAChB,OAAO,EAAE,KAAK,CAAC,UAAU,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC,EACrD,KAAK,EAAE,KAAK,KACT,IAAI,CAAC;IACV,kBAAkB,EAAE,CAClB,OAAO,EAAE,KAAK,CAAC,UAAU,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC,KAClD,IAAI,CAAC;IACV,WAAW,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,UAAU,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC,KAAK,IAAI,CAAC;IAC7E,SAAS,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,UAAU,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC,KAAK,IAAI,CAAC;IAC3E,gBAAgB,EAAE,CAChB,OAAO,EAAE,KAAK,CAAC,UAAU,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC,KAClD,IAAI,CAAC;CACX;AAED,eAAO,MAAM,QAAQ,6BAWnB,CAAC;;AAEH,wBAA4E"}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
export { default as
|
|
1
|
+
export { default as TPStreamsPlayerNative } from './TPStreamsPlayerViewNativeComponent';
|
|
2
2
|
export * from './TPStreamsPlayerViewNativeComponent';
|
|
3
|
+
export { default as TPStreamsPlayerView } from './TPStreamsPlayer';
|
|
4
|
+
export type { TPStreamsPlayerRef } from './TPStreamsPlayer';
|
|
3
5
|
export declare const TPStreams: {
|
|
4
6
|
initialize: (organizationId: string) => void;
|
|
5
7
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,IAAI,qBAAqB,EAAE,MAAM,sCAAsC,CAAC;AACxF,cAAc,sCAAsC,CAAC;AAGrD,OAAO,EAAE,OAAO,IAAI,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACnE,YAAY,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAI5D,eAAO,MAAM,SAAS;iCACS,MAAM,KAAG,IAAI;CAG3C,CAAC"}
|
package/package.json
CHANGED
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { forwardRef, useImperativeHandle, useRef, useCallback } from 'react';
|
|
2
|
+
import TPStreamsPlayerNative, {
|
|
3
|
+
Commands,
|
|
4
|
+
} from './TPStreamsPlayerViewNativeComponent';
|
|
5
|
+
import type {
|
|
6
|
+
NativeProps,
|
|
7
|
+
ErrorEvent,
|
|
8
|
+
} from './TPStreamsPlayerViewNativeComponent';
|
|
9
|
+
import type { ViewProps } from 'react-native';
|
|
10
|
+
|
|
11
|
+
// Create a unique ID for each instance to track promises
|
|
12
|
+
let nextInstanceId = 0;
|
|
13
|
+
|
|
14
|
+
// Type for tracking promises waiting to be resolved
|
|
15
|
+
type PromiseMap = {
|
|
16
|
+
[key: string]: {
|
|
17
|
+
resolve: (value: any) => void;
|
|
18
|
+
reject: (reason?: any) => void;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
// Return type for player API methods
|
|
23
|
+
export interface TPStreamsPlayerRef {
|
|
24
|
+
play: () => void;
|
|
25
|
+
pause: () => void;
|
|
26
|
+
seekTo: (positionMs: number) => void;
|
|
27
|
+
setPlaybackSpeed: (speed: number) => void;
|
|
28
|
+
getCurrentPosition: () => Promise<number>;
|
|
29
|
+
getDuration: () => Promise<number>;
|
|
30
|
+
isPlaying: () => Promise<boolean>;
|
|
31
|
+
getPlaybackSpeed: () => Promise<number>;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Prop types for the player component
|
|
35
|
+
export interface TPStreamsPlayerProps extends ViewProps {
|
|
36
|
+
videoId?: string;
|
|
37
|
+
accessToken?: string;
|
|
38
|
+
onPlayerStateChanged?: (state: number) => void;
|
|
39
|
+
onIsPlayingChanged?: (isPlaying: boolean) => void;
|
|
40
|
+
onPlaybackSpeedChanged?: (speed: number) => void;
|
|
41
|
+
onIsLoadingChanged?: (isLoading: boolean) => void;
|
|
42
|
+
onError?: (error: {
|
|
43
|
+
message: string;
|
|
44
|
+
code: number;
|
|
45
|
+
details?: string;
|
|
46
|
+
}) => void;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* TPStreamsPlayerView - React component wrapper for TPStreamsPlayerNative
|
|
51
|
+
* Provides a simple imperative API for controlling the player
|
|
52
|
+
*/
|
|
53
|
+
const TPStreamsPlayerView = forwardRef<
|
|
54
|
+
TPStreamsPlayerRef,
|
|
55
|
+
TPStreamsPlayerProps
|
|
56
|
+
>((props, ref) => {
|
|
57
|
+
const {
|
|
58
|
+
videoId,
|
|
59
|
+
accessToken,
|
|
60
|
+
style,
|
|
61
|
+
onPlayerStateChanged,
|
|
62
|
+
onIsPlayingChanged,
|
|
63
|
+
onPlaybackSpeedChanged,
|
|
64
|
+
onIsLoadingChanged,
|
|
65
|
+
onError,
|
|
66
|
+
...restProps
|
|
67
|
+
} = props;
|
|
68
|
+
|
|
69
|
+
const nativeRef = useRef(null);
|
|
70
|
+
const instanceId = useRef<number>(nextInstanceId++);
|
|
71
|
+
const promiseMap = useRef<PromiseMap>({});
|
|
72
|
+
|
|
73
|
+
// Event handlers that resolve promises
|
|
74
|
+
const onCurrentPosition = useCallback((event: any) => {
|
|
75
|
+
const key = `position-${instanceId.current}`;
|
|
76
|
+
const handler = promiseMap.current[key];
|
|
77
|
+
if (handler) {
|
|
78
|
+
handler.resolve(event.nativeEvent.position);
|
|
79
|
+
delete promiseMap.current[key];
|
|
80
|
+
}
|
|
81
|
+
}, []);
|
|
82
|
+
|
|
83
|
+
const onDuration = useCallback((event: any) => {
|
|
84
|
+
const key = `duration-${instanceId.current}`;
|
|
85
|
+
const handler = promiseMap.current[key];
|
|
86
|
+
if (handler) {
|
|
87
|
+
handler.resolve(event.nativeEvent.duration);
|
|
88
|
+
delete promiseMap.current[key];
|
|
89
|
+
}
|
|
90
|
+
}, []);
|
|
91
|
+
|
|
92
|
+
const onIsPlaying = useCallback((event: any) => {
|
|
93
|
+
const key = `isPlaying-${instanceId.current}`;
|
|
94
|
+
const handler = promiseMap.current[key];
|
|
95
|
+
if (handler) {
|
|
96
|
+
handler.resolve(event.nativeEvent.isPlaying);
|
|
97
|
+
delete promiseMap.current[key];
|
|
98
|
+
}
|
|
99
|
+
}, []);
|
|
100
|
+
|
|
101
|
+
const onPlaybackSpeed = useCallback((event: any) => {
|
|
102
|
+
const key = `playbackSpeed-${instanceId.current}`;
|
|
103
|
+
const handler = promiseMap.current[key];
|
|
104
|
+
if (handler) {
|
|
105
|
+
handler.resolve(event.nativeEvent.speed);
|
|
106
|
+
delete promiseMap.current[key];
|
|
107
|
+
}
|
|
108
|
+
}, []);
|
|
109
|
+
|
|
110
|
+
// Player event handlers
|
|
111
|
+
const handlePlayerStateChanged = useCallback(
|
|
112
|
+
(event: any) => {
|
|
113
|
+
onPlayerStateChanged?.(event.nativeEvent.playbackState);
|
|
114
|
+
},
|
|
115
|
+
[onPlayerStateChanged]
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
const handleIsPlayingChanged = useCallback(
|
|
119
|
+
(event: any) => {
|
|
120
|
+
onIsPlayingChanged?.(event.nativeEvent.isPlaying);
|
|
121
|
+
},
|
|
122
|
+
[onIsPlayingChanged]
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
const handlePlaybackSpeedChanged = useCallback(
|
|
126
|
+
(event: any) => {
|
|
127
|
+
onPlaybackSpeedChanged?.(event.nativeEvent.speed);
|
|
128
|
+
},
|
|
129
|
+
[onPlaybackSpeedChanged]
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
const handleIsLoadingChanged = useCallback(
|
|
133
|
+
(event: any) => {
|
|
134
|
+
onIsLoadingChanged?.(event.nativeEvent.isLoading);
|
|
135
|
+
},
|
|
136
|
+
[onIsLoadingChanged]
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
const handleError = useCallback(
|
|
140
|
+
(event: { nativeEvent: ErrorEvent }) => {
|
|
141
|
+
const { message, code, details } = event.nativeEvent;
|
|
142
|
+
|
|
143
|
+
// Reject any pending promises with this error
|
|
144
|
+
Object.entries(promiseMap.current).forEach(([key, handler]) => {
|
|
145
|
+
handler.reject(new Error(`${message}: ${details || 'Unknown error'}`));
|
|
146
|
+
delete promiseMap.current[key];
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
// Forward the error to the client if they provided an onError handler
|
|
150
|
+
onError?.({ message, code, details });
|
|
151
|
+
},
|
|
152
|
+
[onError]
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
// Helper to create promise-based API methods
|
|
156
|
+
const createPromiseMethod = useCallback(
|
|
157
|
+
(command: (ref: any) => void, eventKey: string) => {
|
|
158
|
+
return () =>
|
|
159
|
+
new Promise<any>((resolve, reject) => {
|
|
160
|
+
if (nativeRef.current) {
|
|
161
|
+
const key = `${eventKey}-${instanceId.current}`;
|
|
162
|
+
promiseMap.current[key] = { resolve, reject };
|
|
163
|
+
command(nativeRef.current);
|
|
164
|
+
|
|
165
|
+
// Set a timeout to reject the promise if it's not resolved in time
|
|
166
|
+
setTimeout(() => {
|
|
167
|
+
if (promiseMap.current[key]) {
|
|
168
|
+
reject(new Error(`Timeout getting ${eventKey}`));
|
|
169
|
+
delete promiseMap.current[key];
|
|
170
|
+
}
|
|
171
|
+
}, 5000);
|
|
172
|
+
} else {
|
|
173
|
+
reject(new Error('Player is not initialized'));
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
},
|
|
177
|
+
[]
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
useImperativeHandle(
|
|
181
|
+
ref,
|
|
182
|
+
() => ({
|
|
183
|
+
play: () => nativeRef.current && Commands.play(nativeRef.current),
|
|
184
|
+
pause: () => nativeRef.current && Commands.pause(nativeRef.current),
|
|
185
|
+
seekTo: (positionMs: number) =>
|
|
186
|
+
nativeRef.current && Commands.seekTo(nativeRef.current, positionMs),
|
|
187
|
+
setPlaybackSpeed: (speed: number) =>
|
|
188
|
+
nativeRef.current &&
|
|
189
|
+
Commands.setPlaybackSpeed(nativeRef.current, speed),
|
|
190
|
+
getCurrentPosition: createPromiseMethod(
|
|
191
|
+
Commands.getCurrentPosition,
|
|
192
|
+
'position'
|
|
193
|
+
),
|
|
194
|
+
getDuration: createPromiseMethod(Commands.getDuration, 'duration'),
|
|
195
|
+
isPlaying: createPromiseMethod(Commands.isPlaying, 'isPlaying'),
|
|
196
|
+
getPlaybackSpeed: createPromiseMethod(Commands.getPlaybackSpeed, 'speed'),
|
|
197
|
+
}),
|
|
198
|
+
[createPromiseMethod]
|
|
199
|
+
);
|
|
200
|
+
|
|
201
|
+
// Create native props object with the correct types
|
|
202
|
+
const nativeProps: NativeProps = {
|
|
203
|
+
...restProps,
|
|
204
|
+
videoId,
|
|
205
|
+
accessToken,
|
|
206
|
+
style,
|
|
207
|
+
onCurrentPosition,
|
|
208
|
+
onDuration,
|
|
209
|
+
onIsPlaying,
|
|
210
|
+
onPlaybackSpeed,
|
|
211
|
+
onPlayerStateChanged: handlePlayerStateChanged,
|
|
212
|
+
onIsPlayingChanged: handleIsPlayingChanged,
|
|
213
|
+
onPlaybackSpeedChanged: handlePlaybackSpeedChanged,
|
|
214
|
+
onIsLoadingChanged: handleIsLoadingChanged,
|
|
215
|
+
onError: handleError,
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
return <TPStreamsPlayerNative {...nativeProps} ref={nativeRef} />;
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
export default TPStreamsPlayerView;
|
|
@@ -1,9 +1,70 @@
|
|
|
1
1
|
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
|
|
2
2
|
import type { ViewProps } from 'react-native';
|
|
3
|
+
import type {
|
|
4
|
+
Double,
|
|
5
|
+
Float,
|
|
6
|
+
Int32,
|
|
7
|
+
} from 'react-native/Libraries/Types/CodegenTypes';
|
|
8
|
+
import type { HostComponent } from 'react-native';
|
|
9
|
+
import type { DirectEventHandler } from 'react-native/Libraries/Types/CodegenTypes';
|
|
10
|
+
import codegenNativeCommands from 'react-native/Libraries/Utilities/codegenNativeCommands';
|
|
3
11
|
|
|
4
|
-
interface
|
|
12
|
+
export interface ErrorEvent {
|
|
13
|
+
message: string;
|
|
14
|
+
code: Int32;
|
|
15
|
+
details?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface NativeProps extends ViewProps {
|
|
5
19
|
videoId?: string;
|
|
6
20
|
accessToken?: string;
|
|
21
|
+
|
|
22
|
+
// Event props for receiving data from native methods
|
|
23
|
+
onCurrentPosition?: DirectEventHandler<{ position: Double }>;
|
|
24
|
+
onDuration?: DirectEventHandler<{ duration: Double }>;
|
|
25
|
+
onIsPlaying?: DirectEventHandler<{ isPlaying: boolean }>;
|
|
26
|
+
onPlaybackSpeed?: DirectEventHandler<{ speed: Float }>;
|
|
27
|
+
|
|
28
|
+
// Player event props
|
|
29
|
+
onPlayerStateChanged?: DirectEventHandler<{ playbackState: Int32 }>;
|
|
30
|
+
onIsPlayingChanged?: DirectEventHandler<{ isPlaying: boolean }>;
|
|
31
|
+
onPlaybackSpeedChanged?: DirectEventHandler<{ speed: Double }>;
|
|
32
|
+
onIsLoadingChanged?: DirectEventHandler<{ isLoading: boolean }>;
|
|
33
|
+
onError?: DirectEventHandler<ErrorEvent>;
|
|
7
34
|
}
|
|
8
35
|
|
|
36
|
+
interface TPStreamsPlayerViewCommands {
|
|
37
|
+
play: (viewRef: React.ElementRef<HostComponent<NativeProps>>) => void;
|
|
38
|
+
pause: (viewRef: React.ElementRef<HostComponent<NativeProps>>) => void;
|
|
39
|
+
seekTo: (
|
|
40
|
+
viewRef: React.ElementRef<HostComponent<NativeProps>>,
|
|
41
|
+
positionMs: Double
|
|
42
|
+
) => void;
|
|
43
|
+
setPlaybackSpeed: (
|
|
44
|
+
viewRef: React.ElementRef<HostComponent<NativeProps>>,
|
|
45
|
+
speed: Float
|
|
46
|
+
) => void;
|
|
47
|
+
getCurrentPosition: (
|
|
48
|
+
viewRef: React.ElementRef<HostComponent<NativeProps>>
|
|
49
|
+
) => void;
|
|
50
|
+
getDuration: (viewRef: React.ElementRef<HostComponent<NativeProps>>) => void;
|
|
51
|
+
isPlaying: (viewRef: React.ElementRef<HostComponent<NativeProps>>) => void;
|
|
52
|
+
getPlaybackSpeed: (
|
|
53
|
+
viewRef: React.ElementRef<HostComponent<NativeProps>>
|
|
54
|
+
) => void;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export const Commands = codegenNativeCommands<TPStreamsPlayerViewCommands>({
|
|
58
|
+
supportedCommands: [
|
|
59
|
+
'play',
|
|
60
|
+
'pause',
|
|
61
|
+
'seekTo',
|
|
62
|
+
'setPlaybackSpeed',
|
|
63
|
+
'getCurrentPosition',
|
|
64
|
+
'getDuration',
|
|
65
|
+
'isPlaying',
|
|
66
|
+
'getPlaybackSpeed',
|
|
67
|
+
],
|
|
68
|
+
});
|
|
69
|
+
|
|
9
70
|
export default codegenNativeComponent<NativeProps>('TPStreamsRNPlayerView');
|
package/src/index.tsx
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import { NativeModules } from 'react-native';
|
|
2
|
-
|
|
2
|
+
// Export the native component with a different name to avoid conflicts
|
|
3
|
+
export { default as TPStreamsPlayerNative } from './TPStreamsPlayerViewNativeComponent';
|
|
3
4
|
export * from './TPStreamsPlayerViewNativeComponent';
|
|
4
5
|
|
|
6
|
+
// Export the wrapper component as TPStreamsPlayerView
|
|
7
|
+
export { default as TPStreamsPlayerView } from './TPStreamsPlayer';
|
|
8
|
+
export type { TPStreamsPlayerRef } from './TPStreamsPlayer';
|
|
9
|
+
|
|
5
10
|
const TPStreamsModule = NativeModules.TPStreams;
|
|
6
11
|
|
|
7
12
|
export const TPStreams = {
|