react-native-unified-player 0.2.3 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,135 +1,118 @@
1
- # React Native Your Unified Player
1
+ # react-native-unified-player
2
2
 
3
- A powerful React Native component that provides a unified interface for playing both MP4 videos and WebRTC streams. Built with Fabric and the new React Native architecture.
3
+ Unified Player
4
+
5
+ A React Native component for playing videos via URL, built with Fabric.
4
6
 
5
7
  ## Features
6
8
 
7
- - 🎥 Support for MP4 video playback
8
- - 🌐 WebRTC streaming capabilities
9
- - 🔄 Unified interface for both video types
9
+ - 🎥 Play videos from a URL source
10
10
  - 📱 Native performance with Fabric architecture
11
- - 🎛️ Comprehensive playback controls
12
- - 📊 Event handling for player states
13
- - 🔍 Support for different resize modes
14
- - 🎚️ Volume and mute controls
15
- - ⏯️ Play/pause functionality
11
+ - 📊 Event handling for player states (Ready, Error, Progress, Complete, Stalled, Resumed)
12
+ - 🎛️ Control playback with methods (Play, Pause, Seek, Get Current Time, Get Duration)
13
+ - 🔄 Optional autoplay and loop
16
14
 
17
15
  ## Installation
18
16
 
19
17
  ```bash
20
- yarn add react-native-your-unified-player
18
+ yarn add react-native-unified-player
21
19
  ```
22
20
 
23
21
  or
24
22
 
25
23
  ```bash
26
- npm install react-native-your-unified-player
24
+ npm install react-native-unified-player
27
25
  ```
28
26
 
29
27
  ## Usage
30
28
 
31
29
  ### Basic Usage
32
30
 
33
- ```jsx
34
- import { YourUnifiedPlayerView } from 'react-native-your-unified-player';
35
-
36
- // For MP4 video
37
- <YourUnifiedPlayerView
38
- source={{
39
- type: 'url',
40
- uri: 'https://example.com/video.mp4'
41
- }}
42
- style={{ width: '100%', height: 300 }}
43
- paused={false}
44
- muted={false}
45
- volume={1.0}
46
- resizeMode="contain"
47
- onUrlLoad={({ duration, naturalSize }) => {
48
- console.log('Video loaded:', duration, naturalSize);
49
- }}
50
- onError={({ error, code }) => {
51
- console.error('Player error:', error, code);
52
- }}
53
- />
54
-
55
- // For WebRTC stream
56
- <YourUnifiedPlayerView
57
- source={{
58
- type: 'webrtc',
59
- signalingUrl: 'wss://example.com/signaling',
60
- iceServers: [
61
- { urls: 'stun:stun.l.google.com:19302' }
62
- ]
63
- }}
64
- style={{ width: '100%', height: 300 }}
65
- onWebRTCConnected={({ connectionInfo }) => {
66
- console.log('WebRTC connected:', connectionInfo);
67
- }}
68
- onWebRTCDisconnected={({ code, reason }) => {
69
- console.log('WebRTC disconnected:', code, reason);
70
- }}
71
- />
72
- ```
73
-
74
- ### Props
75
-
76
- #### Common Props
77
-
78
- | Prop | Type | Default | Description |
79
- |------|------|---------|-------------|
80
- | `paused` | `boolean` | `false` | Controls playback state |
81
- | `muted` | `boolean` | `false` | Controls audio mute state |
82
- | `volume` | `number` | `1.0` | Controls audio volume (0.0 to 1.0) |
83
- | `resizeMode` | `'contain' \| 'cover' \| 'stretch'` | `'contain'` | Controls how the video fits in the view |
84
-
85
- #### Source Props
86
-
87
- For MP4 videos:
88
- ```typescript
89
- {
90
- type: 'url';
91
- uri: string;
92
- }
93
- ```
94
-
95
- For WebRTC streams:
96
31
  ```typescript
97
- {
98
- type: 'webrtc';
99
- signalingUrl: string;
100
- streamConfig?: object;
101
- iceServers?: ReadonlyArray<{ urls: string | ReadonlyArray<string> }>;
102
- }
103
- }
32
+ import { UnifiedPlayerView, UnifiedPlayer, UnifiedPlayerEventTypes, UnifiedPlayerEvents } from 'react-native-unified-player';
33
+ import React, { useRef, useEffect } from 'react';
34
+ import { View } from 'react-native';
35
+
36
+ const MyPlayerComponent = () => {
37
+ const playerRef = useRef(null);
38
+
39
+ // Example of using event listeners (optional)
40
+ useEffect(() => {
41
+ const readyListener = UnifiedPlayerEvents.addListener(UnifiedPlayerEventTypes.READY, () => {
42
+ console.log('Player is ready to play');
43
+ // You can call UnifiedPlayer methods here, e.g., UnifiedPlayer.play(playerRef.current.getNativeTag());
44
+ });
45
+
46
+ const errorListener = UnifiedPlayerEvents.addListener(UnifiedPlayerEventTypes.ERROR, (error) => {
47
+ console.error('Player error:', error);
48
+ });
49
+
50
+ // Add other listeners as needed (PROGRESS, COMPLETE, STALLED, RESUMED)
51
+
52
+ return () => {
53
+ // Clean up listeners on unmount
54
+ readyListener.remove();
55
+ errorListener.remove();
56
+ // Remove other listeners
57
+ };
58
+ }, []);
59
+
60
+ return (
61
+ <View style={{ flex: 1 }}>
62
+ <UnifiedPlayerView
63
+ ref={playerRef}
64
+ style={{ width: '100%', height: 300 }} // Example style
65
+ videoUrl="YOUR_VIDEO_URL_HERE" // Replace with your video URL
66
+ autoplay={false} // Optional: set to true to autoplay
67
+ loop={false} // Optional: set to true to loop
68
+ // authToken="YOUR_AUTH_TOKEN" // Optional: for protected streams
69
+ // You can also use direct view props instead of or in addition to event listeners:
70
+ // onReadyToPlay={() => console.log('View prop: Ready to play')}
71
+ // onError={(e) => console.log('View prop: Error', e)}
72
+ // onPlaybackComplete={() => console.log('View prop: Playback complete')}
73
+ // onProgress={(data) => console.log('View prop: Progress', data)}
74
+ />
75
+ </View>
76
+ );
77
+ };
78
+
79
+ export default MyPlayerComponent;
104
80
  ```
105
81
 
106
- ### Events
82
+ ## Props
107
83
 
108
- #### URL Events
109
- - `onUrlLoad`: Fired when the video is loaded
110
- - `onUrlProgress`: Fired during video playback
111
- - `onUrlEnd`: Fired when video playback ends
112
- - `onUrlReadyForDisplay`: Fired when the video is ready to display
84
+ | Prop | Type | Required | Description |
85
+ |------|------|----------|-------------|
86
+ | `videoUrl` | `string` | Yes | Video source URL |
87
+ | `style` | `ViewStyle` | Yes | Apply custom styling |
88
+ | `autoplay` | `boolean` | No | Autoplay video when loaded |
89
+ | `loop` | `boolean` | No | Should video loop when finished |
90
+ | `authToken` | `string` | No | Optional auth token for protected streams |
91
+ | `onReadyToPlay` | `() => void` | No | Callback when video is ready to play |
92
+ | `onError` | `(error: any) => void` | No | Callback when an error occurs |
93
+ | `onPlaybackComplete` | `() => void` | No | Callback when video playback finishes |
94
+ | `onProgress` | `(data: { currentTime: number; duration: number }) => void` | No | Callback for playback progress |
113
95
 
114
- #### WebRTC Events
115
- - `onWebRTCConnected`: Fired when WebRTC connection is established
116
- - `onWebRTCDisconnected`: Fired when WebRTC connection is lost
117
- - `onWebRTCStats`: Fired with WebRTC connection statistics
96
+ ## Events
118
97
 
119
- #### Common Events
120
- - `onError`: Fired when an error occurs
98
+ Events can be listened to using `UnifiedPlayerEvents.addListener(eventType, listener)`. The available event types are defined in `UnifiedPlayerEventTypes`.
121
99
 
122
- ### Commands
100
+ - `UnifiedPlayerEventTypes.READY` ('onReadyToPlay'): Fired when the player is ready to play.
101
+ - `UnifiedPlayerEventTypes.ERROR` ('onError'): Fired when an error occurs.
102
+ - `UnifiedPlayerEventTypes.PROGRESS` ('onProgress'): Fired during playback with current time and duration (`{ currentTime: number; duration: number }`).
103
+ - `UnifiedPlayerEventTypes.COMPLETE` ('onPlaybackComplete'): Fired when video playback finishes.
104
+ - `UnifiedPlayerEventTypes.STALLED` ('onPlaybackStalled'): Fired when playback stalls.
105
+ - `UnifiedPlayerEventTypes.RESUMED` ('onPlaybackResumed'): Fired when playback resumes after stalling.
123
106
 
124
- The component supports the following commands:
107
+ ## Methods
125
108
 
126
- ```typescript
127
- // Seek to a specific time in the video
128
- seekUrl(viewRef: React.RefObject<YourUnifiedPlayerView>, timeSeconds: number): void;
109
+ Control playback using the `UnifiedPlayer` object and the native tag of the `UnifiedPlayerView` instance (obtained via `ref.current.getNativeTag()`).
129
110
 
130
- // Send a message through WebRTC data channel
131
- sendWebRTCMessage(viewRef: React.RefObject<YourUnifiedPlayerView>, message: string): void;
132
- ```
111
+ - `UnifiedPlayer.play(viewTag: number)`: Starts video playback.
112
+ - `UnifiedPlayer.pause(viewTag: number)`: Pauses video playback.
113
+ - `UnifiedPlayer.seekTo(viewTag: number, time: number)`: Seeks to a specific time in seconds.
114
+ - `UnifiedPlayer.getCurrentTime(viewTag: number): Promise<number>`: Gets the current playback time in seconds.
115
+ - `UnifiedPlayer.getDuration(viewTag: number): Promise<number>`: Gets the duration of the video in seconds.
133
116
 
134
117
  ## Development
135
118
 
@@ -42,6 +42,7 @@ class UnifiedPlayerModule(private val reactContext: ReactApplicationContext) : R
42
42
  @ReactMethod
43
43
  fun pause(viewId: Int) {
44
44
  try {
45
+ Log.d(TAG, "pause called in module for viewId: $viewId") // Add this log
45
46
  Log.d(TAG, "Pause command received for view $viewId")
46
47
  reactContext.runOnUiQueueThread {
47
48
  getPlayerView(viewId)?.pause()
@@ -90,4 +91,9 @@ class UnifiedPlayerModule(private val reactContext: ReactApplicationContext) : R
90
91
  promise.reject("ERROR", "Failed to get duration: ${e.message}")
91
92
  }
92
93
  }
93
- }
94
+
95
+ @ReactMethod
96
+ fun testMethod(message: String) {
97
+ Log.d(TAG, "Test method called with message: $message")
98
+ }
99
+ }
@@ -4,6 +4,8 @@ import android.annotation.SuppressLint
4
4
  import android.content.Context
5
5
  import android.graphics.Color
6
6
  import android.util.Log
7
+ import android.os.Handler
8
+ import android.os.Looper
7
9
  import android.view.Gravity
8
10
  import android.widget.FrameLayout
9
11
  import com.facebook.react.bridge.Arguments
@@ -28,9 +30,28 @@ class UnifiedPlayerView(context: Context) : FrameLayout(context) {
28
30
  private var loop: Boolean = false
29
31
  private var playerView: PlayerView
30
32
  private var player: ExoPlayer? = null
31
- private var isPlaying = false
32
33
  private var currentProgress = 0
33
34
 
35
+ private val progressHandler = Handler(Looper.getMainLooper())
36
+ private val progressRunnable: Runnable = object : Runnable {
37
+ override fun run() {
38
+ player?.let {
39
+ val currentTime = it.currentPosition.toFloat() / 1000f
40
+ val duration = it.duration.toFloat() / 1000f
41
+
42
+ if (duration > 0) {
43
+ val event = Arguments.createMap().apply {
44
+ putDouble("currentTime", currentTime.toDouble())
45
+ putDouble("duration", duration.toDouble())
46
+ }
47
+ sendEvent(UnifiedPlayerEventEmitter.EVENT_PROGRESS, event)
48
+ }
49
+ }
50
+ // Schedule the next update
51
+ progressHandler.postDelayed(this, 250) // Update every 250ms
52
+ }
53
+ }
54
+
34
55
  init {
35
56
  setBackgroundColor(Color.BLACK)
36
57
 
@@ -51,12 +72,6 @@ class UnifiedPlayerView(context: Context) : FrameLayout(context) {
51
72
  // Add logging for playerView dimensions and post play call
52
73
  playerView.post {
53
74
  Log.d(TAG, "PlayerView dimensions after addView: width=${playerView.width}, height=${playerView.height}")
54
- // Post play call to ensure PlayerView is laid out
55
- if (autoplay) {
56
- player?.play()
57
- isPlaying = true
58
- Log.d(TAG, "Autoplay: player?.play() called after layout")
59
- }
60
75
  }
61
76
 
62
77
  player?.addListener(object : Player.Listener {
@@ -66,7 +81,6 @@ class UnifiedPlayerView(context: Context) : FrameLayout(context) {
66
81
  Player.STATE_READY -> {
67
82
  Log.d(TAG, "ExoPlayer STATE_READY")
68
83
  sendEvent("onReadyToPlay", Arguments.createMap())
69
- // Removed custom autoplay logic, relying on player?.playWhenReady
70
84
  }
71
85
  Player.STATE_ENDED -> {
72
86
  Log.d(TAG, "ExoPlayer STATE_ENDED")
@@ -208,16 +222,23 @@ class UnifiedPlayerView(context: Context) : FrameLayout(context) {
208
222
  player?.repeatMode = if (loop) Player.REPEAT_MODE_ALL else Player.REPEAT_MODE_OFF
209
223
  }
210
224
 
225
+ fun setIsPaused(isPaused: Boolean) {
226
+ Log.d(TAG, "setIsPaused called with value: $isPaused")
227
+ if (isPaused) {
228
+ player?.pause()
229
+ } else {
230
+ player?.play()
231
+ }
232
+ }
233
+
211
234
  fun play() {
212
235
  Log.d(TAG, "Play called")
213
236
  player?.play()
214
- isPlaying = true
215
237
  }
216
238
 
217
239
  fun pause() {
218
- Log.d(TAG, "Pause called")
240
+ Log.d(TAG, "Pause called from module") // Add this log
219
241
  player?.pause()
220
- isPlaying = false
221
242
  }
222
243
 
223
244
  fun seekTo(time: Float) {
@@ -250,16 +271,13 @@ class UnifiedPlayerView(context: Context) : FrameLayout(context) {
250
271
  super.onAttachedToWindow()
251
272
  Log.d(TAG, "UnifiedPlayerView onAttachedToWindow")
252
273
  playerView.setPlayer(player)
253
- // Autoplay logic can remain in post block or be moved here
254
- if (autoplay) {
255
- player?.play()
256
- isPlaying = true
257
- Log.d(TAG, "Autoplay: player?.play() called in onAttachedToWindow")
258
- }
274
+ progressHandler.post(progressRunnable) // Start progress updates
259
275
  }
260
276
 
261
277
  override fun onDetachedFromWindow() {
262
278
  super.onDetachedFromWindow()
279
+ Log.d(TAG, "UnifiedPlayerView onDetachedFromWindow")
280
+ progressHandler.removeCallbacks(progressRunnable) // Stop progress updates
263
281
  player?.release()
264
282
  }
265
283
  }
@@ -30,4 +30,9 @@ class UnifiedPlayerViewManager : SimpleViewManager<UnifiedPlayerView>() {
30
30
  fun setLoop(view: UnifiedPlayerView, loop: Boolean) {
31
31
  view.setLoop(loop)
32
32
  }
33
+
34
+ @ReactProp(name = "isPaused")
35
+ fun setIsPaused(view: UnifiedPlayerView, isPaused: Boolean) {
36
+ view.setIsPaused(isPaused)
37
+ }
33
38
  }
@@ -14,6 +14,7 @@
14
14
  @property (nonatomic, copy) NSString *authToken;
15
15
  @property (nonatomic, assign) BOOL autoplay;
16
16
  @property (nonatomic, assign) BOOL loop;
17
+ @property (nonatomic, assign) BOOL isPaused; // Add isPaused property
17
18
  @property (nonatomic, strong) NSArray *mediaOptions;
18
19
  @property (nonatomic, weak) RCTBridge *bridge;
19
20
  @property (nonatomic, assign) VLCMediaPlayerState previousState;
@@ -446,6 +447,21 @@ static UnifiedPlayerModule *eventEmitter = nil;
446
447
  _loop = loop;
447
448
  }
448
449
 
450
+ - (void)setIsPaused:(BOOL)isPaused {
451
+ if (_isPaused != isPaused) {
452
+ _isPaused = isPaused;
453
+ if (_player) {
454
+ if (_isPaused && _player.isPlaying) {
455
+ [_player pause];
456
+ RCTLogInfo(@"[UnifiedPlayerViewManager] Paused via isPaused prop");
457
+ } else if (!_isPaused && !_player.isPlaying) {
458
+ [_player play];
459
+ RCTLogInfo(@"[UnifiedPlayerViewManager] Played via isPaused prop");
460
+ }
461
+ }
462
+ }
463
+ }
464
+
449
465
  - (void)setAuthToken:(NSString *)authToken {
450
466
  if (_authToken != authToken) {
451
467
  _authToken = [authToken copy];
@@ -667,4 +683,10 @@ RCT_CUSTOM_VIEW_PROPERTY(mediaOptions, NSArray, UnifiedPlayerUIView)
667
683
  view.mediaOptions = [RCTConvert NSArray:json];
668
684
  }
669
685
 
686
+ // isPaused property
687
+ RCT_CUSTOM_VIEW_PROPERTY(isPaused, BOOL, UnifiedPlayerUIView)
688
+ {
689
+ view.isPaused = [RCTConvert BOOL:json];
690
+ }
691
+
670
692
  @end
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
 
3
- import { requireNativeComponent, UIManager, Platform, NativeModules, NativeEventEmitter } from 'react-native';
3
+ import { forwardRef } from 'react'; // Import from 'react'
4
+ import { requireNativeComponent, UIManager, Platform, NativeModules, NativeEventEmitter } from 'react-native'; // Import from 'react-native'
4
5
  import { jsx as _jsx } from "react/jsx-runtime";
5
6
  const LINKING_ERROR = `The package 'react-native-unified-player' doesn't seem to be linked. Make sure: \n\n` + Platform.select({
6
7
  ios: "- You have run 'pod install'\n",
@@ -14,6 +15,8 @@ const LINKING_ERROR = `The package 'react-native-unified-player' doesn't seem to
14
15
  // Name of the native component
15
16
  const ComponentName = 'UnifiedPlayerView';
16
17
 
18
+ // Props for the native component including ref
19
+
17
20
  // Native component import
18
21
  const NativeUnifiedPlayerView = UIManager.getViewManagerConfig(ComponentName) != null ? requireNativeComponent(ComponentName) : () => {
19
22
  throw new Error(LINKING_ERROR);
@@ -21,15 +24,18 @@ const NativeUnifiedPlayerView = UIManager.getViewManagerConfig(ComponentName) !=
21
24
 
22
25
  // Native module for additional control methods
23
26
  const UnifiedPlayerModule = NativeModules.UnifiedPlayerModule;
27
+ // Native module for events
28
+ const UnifiedPlayerEventEmitterModule = NativeModules.UnifiedPlayerEvents;
24
29
 
25
30
  /**
26
31
  * UnifiedPlayerView component for video playback
27
32
  */
28
- export const UnifiedPlayerView = props => {
33
+ export const UnifiedPlayerView = /*#__PURE__*/forwardRef((props, ref) => {
29
34
  return /*#__PURE__*/_jsx(NativeUnifiedPlayerView, {
30
- ...props
35
+ ...props,
36
+ ref: ref
31
37
  });
32
- };
38
+ });
33
39
 
34
40
  /**
35
41
  * API methods for controlling playback
@@ -66,13 +72,19 @@ export const UnifiedPlayer = {
66
72
  return UnifiedPlayerModule.getDuration(viewTag);
67
73
  }
68
74
  return Promise.resolve(0);
75
+ },
76
+ // Test method
77
+ testMethod: message => {
78
+ if (UnifiedPlayerModule?.testMethod) {
79
+ UnifiedPlayerModule.testMethod(message);
80
+ }
69
81
  }
70
82
  };
71
83
 
72
84
  // Events emitter for native events
73
85
  let eventEmitter = null;
74
- if (UnifiedPlayerModule) {
75
- eventEmitter = new NativeEventEmitter(UnifiedPlayerModule);
86
+ if (UnifiedPlayerEventEmitterModule) {
87
+ eventEmitter = new NativeEventEmitter(UnifiedPlayerEventEmitterModule);
76
88
  }
77
89
  export const UnifiedPlayerEvents = {
78
90
  addListener: (eventType, listener) => {
@@ -1 +1 @@
1
- {"version":3,"names":["requireNativeComponent","UIManager","Platform","NativeModules","NativeEventEmitter","jsx","_jsx","LINKING_ERROR","select","ios","default","ComponentName","NativeUnifiedPlayerView","getViewManagerConfig","Error","UnifiedPlayerModule","UnifiedPlayerView","props","UnifiedPlayer","play","viewTag","pause","seekTo","time","getCurrentTime","Promise","resolve","getDuration","eventEmitter","UnifiedPlayerEvents","addListener","eventType","listener","remove","UnifiedPlayerEventTypes","READY","ERROR","PROGRESS","COMPLETE","STALLED","RESUMED"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,SACEA,sBAAsB,EACtBC,SAAS,EACTC,QAAQ,EAERC,aAAa,EACbC,kBAAkB,QACb,cAAc;AAAC,SAAAC,GAAA,IAAAC,IAAA;AAEtB,MAAMC,aAAa,GACjB,sFAAsF,GACtFL,QAAQ,CAACM,MAAM,CAAC;EAAEC,GAAG,EAAE,gCAAgC;EAAEC,OAAO,EAAE;AAAG,CAAC,CAAC,GACvE,sDAAsD,GACtD,+BAA+B;;AAEjC;AACA;AACA;;AA8BA;AACA,MAAMC,aAAa,GAAG,mBAAmB;;AAEzC;AACA,MAAMC,uBAAuB,GAC3BX,SAAS,CAACY,oBAAoB,CAACF,aAAa,CAAC,IAAI,IAAI,GACjDX,sBAAsB,CAAqBW,aAAa,CAAC,GACzD,MAAM;EACJ,MAAM,IAAIG,KAAK,CAACP,aAAa,CAAC;AAChC,CAAC;;AAEP;AACA,MAAMQ,mBAAmB,GAAGZ,aAAa,CAACY,mBAAmB;;AAE7D;AACA;AACA;AACA,OAAO,MAAMC,iBAAiB,GAAIC,KAAyB,IAAK;EAC9D,oBAAOX,IAAA,CAACM,uBAAuB;IAAA,GAAKK;EAAK,CAAG,CAAC;AAC/C,CAAC;;AAED;AACA;AACA;AACA,OAAO,MAAMC,aAAa,GAAG;EAC3B;EACAC,IAAI,EAAGC,OAAe,IAAK;IACzB,IAAIL,mBAAmB,EAAEI,IAAI,EAAE;MAC7BJ,mBAAmB,CAACI,IAAI,CAACC,OAAO,CAAC;IACnC;EACF,CAAC;EAED;EACAC,KAAK,EAAGD,OAAe,IAAK;IAC1B,IAAIL,mBAAmB,EAAEM,KAAK,EAAE;MAC9BN,mBAAmB,CAACM,KAAK,CAACD,OAAO,CAAC;IACpC;EACF,CAAC;EAED;EACAE,MAAM,EAAEA,CAACF,OAAe,EAAEG,IAAY,KAAK;IACzC,IAAIR,mBAAmB,EAAEO,MAAM,EAAE;MAC/BP,mBAAmB,CAACO,MAAM,CAACF,OAAO,EAAEG,IAAI,CAAC;IAC3C;EACF,CAAC;EAED;EACAC,cAAc,EAAGJ,OAAe,IAAsB;IACpD,IAAIL,mBAAmB,EAAES,cAAc,EAAE;MACvC,OAAOT,mBAAmB,CAACS,cAAc,CAACJ,OAAO,CAAC;IACpD;IACA,OAAOK,OAAO,CAACC,OAAO,CAAC,CAAC,CAAC;EAC3B,CAAC;EAED;EACAC,WAAW,EAAGP,OAAe,IAAsB;IACjD,IAAIL,mBAAmB,EAAEY,WAAW,EAAE;MACpC,OAAOZ,mBAAmB,CAACY,WAAW,CAACP,OAAO,CAAC;IACjD;IACA,OAAOK,OAAO,CAACC,OAAO,CAAC,CAAC,CAAC;EAC3B;AACF,CAAC;;AAED;AACA,IAAIE,YAAuC,GAAG,IAAI;AAElD,IAAIb,mBAAmB,EAAE;EACvBa,YAAY,GAAG,IAAIxB,kBAAkB,CAACW,mBAAmB,CAAC;AAC5D;AAEA,OAAO,MAAMc,mBAAmB,GAAG;EACjCC,WAAW,EAAEA,CAACC,SAAiB,EAAEC,QAAiC,KAAK;IACrE,IAAIJ,YAAY,EAAE;MAChB,OAAOA,YAAY,CAACE,WAAW,CAACC,SAAS,EAAEC,QAAQ,CAAC;IACtD;IACA,OAAO;MAAEC,MAAM,EAAEA,CAAA,KAAM,CAAC;IAAE,CAAC;EAC7B;AACF,CAAC;;AAED;AACA,OAAO,MAAMC,uBAAuB,GAAG;EACrCC,KAAK,EAAE,eAAe;EACtBC,KAAK,EAAE,SAAS;EAChBC,QAAQ,EAAE,YAAY;EACtBC,QAAQ,EAAE,oBAAoB;EAC9BC,OAAO,EAAE,mBAAmB;EAC5BC,OAAO,EAAE;AACX,CAAC","ignoreList":[]}
1
+ {"version":3,"names":["forwardRef","requireNativeComponent","UIManager","Platform","NativeModules","NativeEventEmitter","jsx","_jsx","LINKING_ERROR","select","ios","default","ComponentName","NativeUnifiedPlayerView","getViewManagerConfig","Error","UnifiedPlayerModule","UnifiedPlayerEventEmitterModule","UnifiedPlayerEvents","UnifiedPlayerView","props","ref","UnifiedPlayer","play","viewTag","pause","seekTo","time","getCurrentTime","Promise","resolve","getDuration","testMethod","message","eventEmitter","addListener","eventType","listener","remove","UnifiedPlayerEventTypes","READY","ERROR","PROGRESS","COMPLETE","STALLED","RESUMED"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":"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","ignoreList":[]}
@@ -7,6 +7,7 @@ export type UnifiedPlayerProps = {
7
7
  style: ViewStyle;
8
8
  autoplay?: boolean;
9
9
  loop?: boolean;
10
+ isPaused?: boolean;
10
11
  authToken?: string;
11
12
  onReadyToPlay?: () => void;
12
13
  onError?: (error: any) => void;
@@ -19,7 +20,7 @@ export type UnifiedPlayerProps = {
19
20
  /**
20
21
  * UnifiedPlayerView component for video playback
21
22
  */
22
- export declare const UnifiedPlayerView: (props: UnifiedPlayerProps) => import("react/jsx-runtime").JSX.Element;
23
+ export declare const UnifiedPlayerView: import("react").ForwardRefExoticComponent<UnifiedPlayerProps & import("react").RefAttributes<never>>;
23
24
  /**
24
25
  * API methods for controlling playback
25
26
  */
@@ -29,6 +30,7 @@ export declare const UnifiedPlayer: {
29
30
  seekTo: (viewTag: number, time: number) => void;
30
31
  getCurrentTime: (viewTag: number) => Promise<number>;
31
32
  getDuration: (viewTag: number) => Promise<number>;
33
+ testMethod: (message: string) => void;
32
34
  };
33
35
  export declare const UnifiedPlayerEvents: {
34
36
  addListener: (eventType: string, listener: (...args: any[]) => any) => import("react-native").EmitterSubscription | {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,SAAS,EAGf,MAAM,cAAc,CAAC;AAQtB;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAE/B,QAAQ,EAAE,MAAM,CAAC;IAGjB,KAAK,EAAE,SAAS,CAAC;IAGjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IAGnB,IAAI,CAAC,EAAE,OAAO,CAAC;IAGf,SAAS,CAAC,EAAE,MAAM,CAAC;IAGnB,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;IAG3B,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC;IAG/B,kBAAkB,CAAC,EAAE,MAAM,IAAI,CAAC;IAGhC,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;CACxE,CAAC;AAgBF;;GAEG;AACH,eAAO,MAAM,iBAAiB,GAAI,OAAO,kBAAkB,4CAE1D,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,aAAa;oBAER,MAAM;qBAOL,MAAM;sBAOL,MAAM,QAAQ,MAAM;8BAOZ,MAAM,KAAG,OAAO,CAAC,MAAM,CAAC;2BAQ3B,MAAM,KAAG,OAAO,CAAC,MAAM,CAAC;CAMhD,CAAC;AASF,eAAO,MAAM,mBAAmB;6BACL,MAAM,YAAY,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG;;;CAMnE,CAAC;AAGF,eAAO,MAAM,uBAAuB;;;;;;;CAOnC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AACA,OAAO,EAIL,KAAK,SAAS,EAGf,MAAM,cAAc,CAAC;AAQtB;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAE/B,QAAQ,EAAE,MAAM,CAAC;IAGjB,KAAK,EAAE,SAAS,CAAC;IAGjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IAGnB,IAAI,CAAC,EAAE,OAAO,CAAC;IAGf,QAAQ,CAAC,EAAE,OAAO,CAAC;IAGnB,SAAS,CAAC,EAAE,MAAM,CAAC;IAGnB,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;IAG3B,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC;IAG/B,kBAAkB,CAAC,EAAE,MAAM,IAAI,CAAC;IAGhC,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;CACxE,CAAC;AAuBF;;GAEG;AACH,eAAO,MAAM,iBAAiB,sGAK5B,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,aAAa;oBAER,MAAM;qBAOL,MAAM;sBAOL,MAAM,QAAQ,MAAM;8BAOZ,MAAM,KAAG,OAAO,CAAC,MAAM,CAAC;2BAQ3B,MAAM,KAAG,OAAO,CAAC,MAAM,CAAC;0BAQzB,MAAM;CAK7B,CAAC;AASF,eAAO,MAAM,mBAAmB;6BACL,MAAM,YAAY,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG;;;CAMnE,CAAC;AAGF,eAAO,MAAM,uBAAuB;;;;;;;CAOnC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-unified-player",
3
- "version": "0.2.3",
3
+ "version": "0.3.0",
4
4
  "description": "Unified Player",
5
5
  "source": "./src/index.tsx",
6
6
  "main": "./lib/module/index.js",
@@ -86,6 +86,9 @@
86
86
  "react": "*",
87
87
  "react-native": "*"
88
88
  },
89
+ "workspaces": [
90
+ "example"
91
+ ],
89
92
  "packageManager": "yarn@3.6.1",
90
93
  "jest": {
91
94
  "preset": "react-native",
package/src/index.tsx CHANGED
@@ -1,3 +1,4 @@
1
+ import { type Ref, type ElementRef, forwardRef } from 'react'; // Import from 'react'
1
2
  import {
2
3
  requireNativeComponent,
3
4
  UIManager,
@@ -5,7 +6,7 @@ import {
5
6
  type ViewStyle,
6
7
  NativeModules,
7
8
  NativeEventEmitter,
8
- } from 'react-native';
9
+ } from 'react-native'; // Import from 'react-native'
9
10
 
10
11
  const LINKING_ERROR =
11
12
  `The package 'react-native-unified-player' doesn't seem to be linked. Make sure: \n\n` +
@@ -29,6 +30,9 @@ export type UnifiedPlayerProps = {
29
30
  // Should video loop when finished
30
31
  loop?: boolean;
31
32
 
33
+ // Is the player currently paused
34
+ isPaused?: boolean;
35
+
32
36
  // Optional auth token for protected streams
33
37
  authToken?: string;
34
38
 
@@ -48,23 +52,33 @@ export type UnifiedPlayerProps = {
48
52
  // Name of the native component
49
53
  const ComponentName = 'UnifiedPlayerView';
50
54
 
55
+ // Props for the native component including ref
56
+ type NativeUnifiedPlayerViewProps = UnifiedPlayerProps & {
57
+ ref?: Ref<ElementRef<typeof NativeUnifiedPlayerView>>;
58
+ };
59
+
51
60
  // Native component import
52
61
  const NativeUnifiedPlayerView =
53
62
  UIManager.getViewManagerConfig(ComponentName) != null
54
- ? requireNativeComponent<UnifiedPlayerProps>(ComponentName)
63
+ ? requireNativeComponent<NativeUnifiedPlayerViewProps>(ComponentName)
55
64
  : () => {
56
65
  throw new Error(LINKING_ERROR);
57
66
  };
58
67
 
59
68
  // Native module for additional control methods
60
69
  const UnifiedPlayerModule = NativeModules.UnifiedPlayerModule;
70
+ // Native module for events
71
+ const UnifiedPlayerEventEmitterModule = NativeModules.UnifiedPlayerEvents;
61
72
 
62
73
  /**
63
74
  * UnifiedPlayerView component for video playback
64
75
  */
65
- export const UnifiedPlayerView = (props: UnifiedPlayerProps) => {
66
- return <NativeUnifiedPlayerView {...props} />;
67
- };
76
+ export const UnifiedPlayerView = forwardRef<
77
+ ElementRef<typeof NativeUnifiedPlayerView>,
78
+ UnifiedPlayerProps
79
+ >((props, ref) => {
80
+ return <NativeUnifiedPlayerView {...props} ref={ref} />;
81
+ });
68
82
 
69
83
  /**
70
84
  * API methods for controlling playback
@@ -106,13 +120,20 @@ export const UnifiedPlayer = {
106
120
  }
107
121
  return Promise.resolve(0);
108
122
  },
123
+
124
+ // Test method
125
+ testMethod: (message: string) => {
126
+ if (UnifiedPlayerModule?.testMethod) {
127
+ UnifiedPlayerModule.testMethod(message);
128
+ }
129
+ },
109
130
  };
110
131
 
111
132
  // Events emitter for native events
112
133
  let eventEmitter: NativeEventEmitter | null = null;
113
134
 
114
- if (UnifiedPlayerModule) {
115
- eventEmitter = new NativeEventEmitter(UnifiedPlayerModule);
135
+ if (UnifiedPlayerEventEmitterModule) {
136
+ eventEmitter = new NativeEventEmitter(UnifiedPlayerEventEmitterModule);
116
137
  }
117
138
 
118
139
  export const UnifiedPlayerEvents = {