react-native-unified-player 0.3.2 → 0.3.3

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
@@ -65,7 +65,6 @@ const MyPlayerComponent = () => {
65
65
  videoUrl="YOUR_VIDEO_URL_HERE" // Replace with your video URL
66
66
  autoplay={false} // Optional: set to true to autoplay
67
67
  loop={false} // Optional: set to true to loop
68
- // authToken="YOUR_AUTH_TOKEN" // Optional: for protected streams
69
68
  // You can also use direct view props instead of or in addition to event listeners:
70
69
  // onReadyToPlay={() => console.log('View prop: Ready to play')}
71
70
  // onError={(e) => console.log('View prop: Error', e)}
@@ -87,7 +86,6 @@ export default MyPlayerComponent;
87
86
  | `style` | `ViewStyle` | Yes | Apply custom styling |
88
87
  | `autoplay` | `boolean` | No | Autoplay video when loaded |
89
88
  | `loop` | `boolean` | No | Should video loop when finished |
90
- | `authToken` | `string` | No | Optional auth token for protected streams |
91
89
  | `onReadyToPlay` | `() => void` | No | Callback when video is ready to play |
92
90
  | `onError` | `(error: any) => void` | No | Callback when an error occurs |
93
91
  | `onPlaybackComplete` | `() => void` | No | Callback when video playback finishes |
@@ -10,7 +10,7 @@ Pod::Spec.new do |s|
10
10
  s.license = package["license"]
11
11
  s.authors = package["author"]
12
12
 
13
- s.platforms = { :ios => min_ios_version_supported }
13
+ s.platforms = { :ios => "12.0" }
14
14
  s.source = { :git => "https://github.com/blueromans/react-native-unified-player.git", :tag => "#{s.version}" }
15
15
 
16
16
  s.source_files = "ios/**/*.{h,m,mm}"
@@ -12,12 +12,15 @@ class UnifiedPlayerEventEmitter(private val reactContext: ReactApplicationContex
12
12
  private const val TAG = "UnifiedPlayerEventEmitter"
13
13
 
14
14
  // Define all possible event types
15
+ const val EVENT_LOAD_START = "onLoadStart"
15
16
  const val EVENT_READY = "onReadyToPlay"
16
17
  const val EVENT_ERROR = "onError"
17
18
  const val EVENT_PROGRESS = "onProgress"
18
19
  const val EVENT_COMPLETE = "onPlaybackComplete"
19
20
  const val EVENT_STALLED = "onPlaybackStalled"
20
21
  const val EVENT_RESUMED = "onPlaybackResumed"
22
+ const val EVENT_PLAYING = "onPlaying"
23
+ const val EVENT_PAUSED = "onPaused"
21
24
 
22
25
  // Singleton instance for access from other classes
23
26
  private var instance: UnifiedPlayerEventEmitter? = null
@@ -59,4 +62,4 @@ class UnifiedPlayerEventEmitter(private val reactContext: ReactApplicationContex
59
62
  super.onCatalystInstanceDestroy()
60
63
  instance = null
61
64
  }
62
- }
65
+ }
@@ -169,8 +169,4 @@ class UnifiedPlayerModule(private val reactContext: ReactApplicationContext) : R
169
169
  }
170
170
  }
171
171
 
172
- @ReactMethod
173
- fun testMethod(message: String) {
174
- Log.d(TAG, "Test method called with message: $message")
175
- }
176
172
  }
@@ -19,6 +19,15 @@ import com.google.android.exoplayer2.video.VideoSize
19
19
  import com.facebook.react.bridge.WritableMap
20
20
  import com.facebook.react.bridge.ReactContext
21
21
  import com.facebook.react.uimanager.events.RCTEventEmitter
22
+ import com.unifiedplayer.UnifiedPlayerEventEmitter.Companion.EVENT_COMPLETE
23
+ import com.unifiedplayer.UnifiedPlayerEventEmitter.Companion.EVENT_ERROR
24
+ import com.unifiedplayer.UnifiedPlayerEventEmitter.Companion.EVENT_LOAD_START
25
+ import com.unifiedplayer.UnifiedPlayerEventEmitter.Companion.EVENT_PAUSED
26
+ import com.unifiedplayer.UnifiedPlayerEventEmitter.Companion.EVENT_PLAYING
27
+ import com.unifiedplayer.UnifiedPlayerEventEmitter.Companion.EVENT_PROGRESS
28
+ import com.unifiedplayer.UnifiedPlayerEventEmitter.Companion.EVENT_READY
29
+ import com.unifiedplayer.UnifiedPlayerEventEmitter.Companion.EVENT_RESUMED
30
+ import com.unifiedplayer.UnifiedPlayerEventEmitter.Companion.EVENT_STALLED
22
31
 
23
32
  class UnifiedPlayerView(context: Context) : FrameLayout(context) {
24
33
  companion object {
@@ -50,7 +59,7 @@ class UnifiedPlayerView(context: Context) : FrameLayout(context) {
50
59
  event.putDouble("duration", duration.toDouble())
51
60
 
52
61
  Log.d(TAG, "Sending progress event: currentTime=$currentTime, duration=$duration")
53
- sendEvent("topProgress", event)
62
+ sendEvent(EVENT_PROGRESS, event)
54
63
  } else {
55
64
  Log.d(TAG, "Not sending progress event because duration is $duration (raw: ${it.duration})")
56
65
  }
@@ -89,14 +98,15 @@ class UnifiedPlayerView(context: Context) : FrameLayout(context) {
89
98
  when (playbackState) {
90
99
  Player.STATE_READY -> {
91
100
  Log.d(TAG, "ExoPlayer STATE_READY")
92
- sendEvent("topReadyToPlay", Arguments.createMap())
101
+ sendEvent(EVENT_READY, Arguments.createMap())
93
102
  }
94
103
  Player.STATE_ENDED -> {
95
104
  Log.d(TAG, "ExoPlayer STATE_ENDED")
96
- sendEvent("topPlaybackComplete", Arguments.createMap())
105
+ sendEvent(EVENT_COMPLETE, Arguments.createMap())
97
106
  }
98
107
  Player.STATE_BUFFERING -> {
99
108
  Log.d(TAG, "ExoPlayer STATE_BUFFERING")
109
+ sendEvent(EVENT_STALLED, Arguments.createMap())
100
110
  }
101
111
  Player.STATE_IDLE -> {
102
112
  Log.d(TAG, "ExoPlayer STATE_IDLE")
@@ -105,29 +115,28 @@ class UnifiedPlayerView(context: Context) : FrameLayout(context) {
105
115
  }
106
116
 
107
117
  override fun onIsPlayingChanged(isPlaying: Boolean) {
108
- Log.d(TAG, "onIsPlayingChanged: $isPlaying")
118
+ Log.d(TAG, "onIsPlayingChanged: $isPlaying") // Added log
109
119
  if (isPlaying) {
110
- Log.d(TAG, "ExoPlayer isPlaying")
111
- // Use the defined event constant for playback resumed
112
- sendEvent("topPlaybackResumed", Arguments.createMap())
120
+ Log.d(TAG, "ExoPlayer is now playing")
121
+ sendEvent(EVENT_RESUMED, Arguments.createMap())
122
+ sendEvent(EVENT_PLAYING, Arguments.createMap())
113
123
  } else {
114
- Log.d(TAG, "ExoPlayer isPaused")
115
- // Add event emission for pause state
116
- sendEvent("topPlaybackPaused", Arguments.createMap())
124
+ Log.d(TAG, "ExoPlayer is now paused")
125
+ sendEvent(EVENT_PAUSED, Arguments.createMap())
117
126
  }
118
127
  }
119
128
 
120
129
  override fun onPlayerError(error: PlaybackException) {
121
- Log.d(TAG, "ExoPlayer onPlayerError: ${error.message}")
122
- val event = Arguments.createMap().apply {
123
- putString("error", error.message)
124
- }
125
- sendEvent("topError", event)
130
+ Log.e(TAG, "ExoPlayer error: $error")
131
+ val event = Arguments.createMap()
132
+ event.putString("code", "PLAYBACK_ERROR")
133
+ event.putString("message", error.message ?: "Unknown playback error")
134
+ sendEvent(EVENT_ERROR, event)
126
135
  }
127
136
 
128
137
  override fun onMediaItemTransition(mediaItem: MediaItem?, reason: Int) {
129
- Log.d(TAG, "ExoPlayer onMediaItemTransition")
130
- sendEvent("topLoadStart", Arguments.createMap())
138
+ Log.d(TAG, "onMediaItemTransition with reason: $reason")
139
+ sendEvent(EVENT_LOAD_START, Arguments.createMap())
131
140
  }
132
141
 
133
142
  override fun onPlaybackSuppressionReasonChanged(playbackSuppressionReason: Int) {
@@ -238,8 +247,9 @@ class UnifiedPlayerView(context: Context) : FrameLayout(context) {
238
247
 
239
248
  // Send error event
240
249
  val event = Arguments.createMap()
241
- event.putString("error", "Failed to load video: ${e.message}")
242
- sendEvent("topError", event)
250
+ event.putString("code", "SOURCE_ERROR")
251
+ event.putString("message", "Failed to load video source: $url")
252
+ sendEvent(EVENT_ERROR, event)
243
253
  }
244
254
  }
245
255
 
@@ -323,10 +333,24 @@ class UnifiedPlayerView(context: Context) : FrameLayout(context) {
323
333
  // Log the event for debugging
324
334
  Log.d(TAG, "Sending direct event: $eventName with params: $params")
325
335
 
336
+ // Map event names to their corresponding top event names
337
+ val topEventName = when (eventName) {
338
+ EVENT_READY -> "topReadyToPlay"
339
+ EVENT_ERROR -> "topError"
340
+ EVENT_PROGRESS -> "topProgress"
341
+ EVENT_COMPLETE -> "topPlaybackComplete"
342
+ EVENT_STALLED -> "topPlaybackStalled"
343
+ EVENT_RESUMED -> "topPlaybackResumed"
344
+ EVENT_PLAYING -> "topPlaying"
345
+ EVENT_PAUSED -> "topPlaybackPaused"
346
+ EVENT_LOAD_START -> "topLoadStart"
347
+ else -> "top${eventName.substring(2)}" // Fallback for any other events
348
+ }
349
+
326
350
  // Use the ReactContext to dispatch the event directly to the view
327
351
  val reactContext = context as ReactContext
328
352
  reactContext.getJSModule(RCTEventEmitter::class.java)
329
- .receiveEvent(id, eventName, params)
353
+ .receiveEvent(id, topEventName, params)
330
354
  } catch (e: Exception) {
331
355
  Log.e(TAG, "Error sending event $eventName: ${e.message}", e)
332
356
  }
@@ -37,6 +37,8 @@ class UnifiedPlayerViewManager : SimpleViewManager<UnifiedPlayerView>() {
37
37
  fun setIsPaused(view: UnifiedPlayerView, isPaused: Boolean) {
38
38
  view.setIsPaused(isPaused)
39
39
  }
40
+
41
+
40
42
 
41
43
  // Register direct events
42
44
  override fun getExportedCustomDirectEventTypeConstants(): Map<String, Any> {
@@ -49,7 +51,9 @@ class UnifiedPlayerViewManager : SimpleViewManager<UnifiedPlayerView>() {
49
51
  .put("topProgress", MapBuilder.of("registrationName", "onProgress"))
50
52
  .put("topPlaybackComplete", MapBuilder.of("registrationName", "onPlaybackComplete"))
51
53
  .put("topPlaybackResumed", MapBuilder.of("registrationName", "onPlaybackResumed"))
52
- .put("topPlaybackPaused", MapBuilder.of("registrationName", "onPlaybackPaused"))
54
+ .put("topPlaybackStalled", MapBuilder.of("registrationName", "onPlaybackStalled"))
55
+ .put("topPlaybackPaused", MapBuilder.of("registrationName", "onPaused"))
56
+ .put("topPlaying", MapBuilder.of("registrationName", "onPlaying"))
53
57
  .put("topLoadStart", MapBuilder.of("registrationName", "onLoadStart"))
54
58
  .build()
55
59
  }
@@ -0,0 +1,210 @@
1
+ #import "UnifiedPlayerModule.h"
2
+ #import <React/RCTLog.h>
3
+ #import <React/RCTBridgeModule.h>
4
+ #import <React/RCTEventEmitter.h>
5
+ #import <React/RCTUIManager.h>
6
+ #import <MobileVLCKit/MobileVLCKit.h>
7
+
8
+ @implementation UnifiedPlayerModule
9
+
10
+ // Explicitly name the module to match what's expected in JavaScript
11
+ RCT_EXPORT_MODULE(UnifiedPlayer);
12
+
13
+ + (BOOL)requiresMainQueueSetup {
14
+ return YES;
15
+ }
16
+
17
+ - (NSArray<NSString *> *)supportedEvents {
18
+ return @[
19
+ @"onLoadStart",
20
+ @"onReadyToPlay",
21
+ @"onError",
22
+ @"onProgress",
23
+ @"onPlaybackComplete",
24
+ @"onPlaybackStalled",
25
+ @"onPlaybackResumed",
26
+ @"onPlaying",
27
+ @"onPaused"
28
+ ];
29
+ }
30
+
31
+ - (dispatch_queue_t)methodQueue {
32
+ return dispatch_get_main_queue();
33
+ }
34
+
35
+ // Play video
36
+ RCT_EXPORT_METHOD(play:(nonnull NSNumber *)reactTag
37
+ resolver:(RCTPromiseResolveBlock)resolve
38
+ rejecter:(RCTPromiseRejectBlock)reject) {
39
+ [self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *,UIView *> *viewRegistry) {
40
+ UIView *view = viewRegistry[reactTag];
41
+ if (!view) {
42
+ reject(@"error", @"Invalid view for tag", nil);
43
+ return;
44
+ }
45
+
46
+ // Cast to UnifiedPlayerUIView class
47
+ Class UnifiedPlayerUIViewClass = NSClassFromString(@"UnifiedPlayerUIView");
48
+ if (![view isKindOfClass:UnifiedPlayerUIViewClass]) {
49
+ reject(@"error", @"View is not a UnifiedPlayerUIView", nil);
50
+ return;
51
+ }
52
+
53
+ @try {
54
+ // Use direct ivar access for safety
55
+ VLCMediaPlayer *player = [view valueForKey:@"player"];
56
+ if (player && player.media) {
57
+ [player play];
58
+ resolve(@(YES));
59
+ } else {
60
+ reject(@"error", @"Player or media not initialized", nil);
61
+ }
62
+ } @catch (NSException *exception) {
63
+ reject(@"error", [NSString stringWithFormat:@"Error playing: %@", exception.reason], nil);
64
+ }
65
+ }];
66
+ }
67
+
68
+ // Pause video
69
+ RCT_EXPORT_METHOD(pause:(nonnull NSNumber *)reactTag
70
+ resolver:(RCTPromiseResolveBlock)resolve
71
+ rejecter:(RCTPromiseRejectBlock)reject) {
72
+ [self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *,UIView *> *viewRegistry) {
73
+ UIView *view = viewRegistry[reactTag];
74
+ if (!view) {
75
+ reject(@"error", @"Invalid view for tag", nil);
76
+ return;
77
+ }
78
+
79
+ // Cast to UnifiedPlayerUIView class
80
+ Class UnifiedPlayerUIViewClass = NSClassFromString(@"UnifiedPlayerUIView");
81
+ if (![view isKindOfClass:UnifiedPlayerUIViewClass]) {
82
+ reject(@"error", @"View is not a UnifiedPlayerUIView", nil);
83
+ return;
84
+ }
85
+
86
+ @try {
87
+ // Use direct ivar access for safety
88
+ VLCMediaPlayer *player = [view valueForKey:@"player"];
89
+ if (player) {
90
+ [player pause];
91
+ resolve(@(YES));
92
+ } else {
93
+ reject(@"error", @"Player not initialized", nil);
94
+ }
95
+ } @catch (NSException *exception) {
96
+ reject(@"error", [NSString stringWithFormat:@"Error pausing: %@", exception.reason], nil);
97
+ }
98
+ }];
99
+ }
100
+
101
+ // Seek to specific time
102
+ RCT_EXPORT_METHOD(seekTo:(nonnull NSNumber *)reactTag
103
+ time:(nonnull NSNumber *)time
104
+ resolver:(RCTPromiseResolveBlock)resolve
105
+ rejecter:(RCTPromiseRejectBlock)reject) {
106
+ [self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *,UIView *> *viewRegistry) {
107
+ UIView *view = viewRegistry[reactTag];
108
+ if (!view) {
109
+ reject(@"error", @"Invalid view for tag", nil);
110
+ return;
111
+ }
112
+
113
+ // Cast to UnifiedPlayerUIView class
114
+ Class UnifiedPlayerUIViewClass = NSClassFromString(@"UnifiedPlayerUIView");
115
+ if (![view isKindOfClass:UnifiedPlayerUIViewClass]) {
116
+ reject(@"error", @"View is not a UnifiedPlayerUIView", nil);
117
+ return;
118
+ }
119
+
120
+ @try {
121
+ // Use direct ivar access for safety
122
+ VLCMediaPlayer *player = [view valueForKey:@"player"];
123
+ if (player && player.media) {
124
+ float timeValue = [time floatValue];
125
+ float duration = player.media.length.intValue / 1000.0f;
126
+ float position = duration > 0 ? timeValue / duration : 0;
127
+ position = MAX(0, MIN(1, position)); // Ensure position is between 0 and 1
128
+
129
+ [player setPosition:position];
130
+ resolve(@(YES));
131
+ } else {
132
+ reject(@"error", @"Player or media not initialized", nil);
133
+ }
134
+ } @catch (NSException *exception) {
135
+ reject(@"error", [NSString stringWithFormat:@"Error seeking: %@", exception.reason], nil);
136
+ }
137
+ }];
138
+ }
139
+
140
+ // Get current playback time
141
+ RCT_EXPORT_METHOD(getCurrentTime:(nonnull NSNumber *)reactTag
142
+ resolver:(RCTPromiseResolveBlock)resolve
143
+ rejecter:(RCTPromiseRejectBlock)reject) {
144
+ [self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *,UIView *> *viewRegistry) {
145
+ UIView *view = viewRegistry[reactTag];
146
+ if (!view) {
147
+ reject(@"error", @"Invalid view for tag", nil);
148
+ return;
149
+ }
150
+
151
+ // Cast to UnifiedPlayerUIView class
152
+ Class UnifiedPlayerUIViewClass = NSClassFromString(@"UnifiedPlayerUIView");
153
+ if (![view isKindOfClass:UnifiedPlayerUIViewClass]) {
154
+ reject(@"error", @"View is not a UnifiedPlayerUIView", nil);
155
+ return;
156
+ }
157
+
158
+ // Use direct method call with proper type safety
159
+ float currentTime = 0;
160
+ @try {
161
+ // Use direct ivar access for safety
162
+ VLCMediaPlayer *player = [view valueForKey:@"player"];
163
+ if (player) {
164
+ currentTime = player.time.intValue / 1000.0f;
165
+ resolve(@(currentTime));
166
+ } else {
167
+ reject(@"error", @"Player not initialized", nil);
168
+ }
169
+ } @catch (NSException *exception) {
170
+ reject(@"error", [NSString stringWithFormat:@"Error getting current time: %@", exception.reason], nil);
171
+ }
172
+ }];
173
+ }
174
+
175
+ // Get video duration
176
+ RCT_EXPORT_METHOD(getDuration:(nonnull NSNumber *)reactTag
177
+ resolver:(RCTPromiseResolveBlock)resolve
178
+ rejecter:(RCTPromiseRejectBlock)reject) {
179
+ [self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *,UIView *> *viewRegistry) {
180
+ UIView *view = viewRegistry[reactTag];
181
+ if (!view) {
182
+ reject(@"error", @"Invalid view for tag", nil);
183
+ return;
184
+ }
185
+
186
+ // Cast to UnifiedPlayerUIView class
187
+ Class UnifiedPlayerUIViewClass = NSClassFromString(@"UnifiedPlayerUIView");
188
+ if (![view isKindOfClass:UnifiedPlayerUIViewClass]) {
189
+ reject(@"error", @"View is not a UnifiedPlayerUIView", nil);
190
+ return;
191
+ }
192
+
193
+ // Use direct method call with proper type safety
194
+ float duration = 0;
195
+ @try {
196
+ // Use direct ivar access for safety
197
+ VLCMediaPlayer *player = [view valueForKey:@"player"];
198
+ if (player && player.media) {
199
+ duration = player.media.length.intValue / 1000.0f;
200
+ resolve(@(duration));
201
+ } else {
202
+ reject(@"error", @"Player or media not initialized", nil);
203
+ }
204
+ } @catch (NSException *exception) {
205
+ reject(@"error", [NSString stringWithFormat:@"Error getting duration: %@", exception.reason], nil);
206
+ }
207
+ }];
208
+ }
209
+
210
+ @end
@@ -5,125 +5,41 @@
5
5
  #import <React/RCTUIManager.h>
6
6
  #import <React/RCTBridge.h>
7
7
  #import <React/RCTUIManagerUtils.h>
8
+ #import <React/RCTComponent.h>
8
9
  #import <MobileVLCKit/MobileVLCKit.h>
10
+ #import "UnifiedPlayerModule.h"
9
11
 
10
12
  // Forward declarations
11
13
  @interface UnifiedPlayerUIView : UIView <VLCMediaPlayerDelegate>
12
14
  @property (nonatomic, strong) VLCMediaPlayer *player;
13
15
  @property (nonatomic, copy) NSString *videoUrlString;
14
- @property (nonatomic, copy) NSString *authToken;
15
16
  @property (nonatomic, assign) BOOL autoplay;
16
17
  @property (nonatomic, assign) BOOL loop;
17
- @property (nonatomic, assign) BOOL isPaused; // Add isPaused property
18
+ @property (nonatomic, assign) BOOL isPaused;
18
19
  @property (nonatomic, strong) NSArray *mediaOptions;
19
20
  @property (nonatomic, weak) RCTBridge *bridge;
20
21
  @property (nonatomic, assign) VLCMediaPlayerState previousState;
21
22
  @property (nonatomic, assign) BOOL hasRenderedVideo;
22
23
 
24
+ // Event callbacks
25
+ @property (nonatomic, copy) RCTDirectEventBlock onLoadStart;
26
+ @property (nonatomic, copy) RCTDirectEventBlock onReadyToPlay;
27
+ @property (nonatomic, copy) RCTDirectEventBlock onError;
28
+ @property (nonatomic, copy) RCTDirectEventBlock onProgress;
29
+ @property (nonatomic, copy) RCTDirectEventBlock onPlaybackComplete;
30
+ @property (nonatomic, copy) RCTDirectEventBlock onPlaybackStalled;
31
+ @property (nonatomic, copy) RCTDirectEventBlock onPlaybackResumed;
32
+ @property (nonatomic, copy) RCTDirectEventBlock onPlaying;
33
+ @property (nonatomic, copy) RCTDirectEventBlock onPaused;
34
+
23
35
  - (void)setupWithVideoUrlString:(NSString *)videoUrlString;
24
36
  - (void)play;
25
37
  - (void)pause;
26
- - (void)seekToTime:(float)time;
38
+ - (void)seekToTime:(NSNumber *)timeNumber;
27
39
  - (float)getCurrentTime;
28
40
  - (float)getDuration;
29
41
  @end
30
42
 
31
- // UnifiedPlayerModule - Module for handling control methods
32
- @interface UnifiedPlayerModule : RCTEventEmitter <RCTBridgeModule>
33
- @end
34
-
35
- @implementation UnifiedPlayerModule
36
-
37
- RCT_EXPORT_MODULE();
38
-
39
- - (NSArray<NSString *> *)supportedEvents {
40
- return @[
41
- @"onReadyToPlay",
42
- @"onError",
43
- @"onProgress",
44
- @"onPlaybackComplete",
45
- @"onPlaybackStalled",
46
- @"onPlaybackResumed",
47
- @"onBuffering",
48
- @"onPlaying",
49
- @"onPaused",
50
- @"onStopped"
51
- ];
52
- }
53
-
54
- - (dispatch_queue_t)methodQueue {
55
- return dispatch_get_main_queue();
56
- }
57
-
58
- // Play video
59
- RCT_EXPORT_METHOD(play:(nonnull NSNumber *)reactTag) {
60
- [self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *,UIView *> *viewRegistry) {
61
- UnifiedPlayerUIView *view = (UnifiedPlayerUIView *)viewRegistry[reactTag];
62
- if (![view isKindOfClass:[UnifiedPlayerUIView class]]) {
63
- RCTLogError(@"Invalid view for tag %@", reactTag);
64
- return;
65
- }
66
- [view play];
67
- }];
68
- }
69
-
70
- // Pause video
71
- RCT_EXPORT_METHOD(pause:(nonnull NSNumber *)reactTag) {
72
- [self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *,UIView *> *viewRegistry) {
73
- UnifiedPlayerUIView *view = (UnifiedPlayerUIView *)viewRegistry[reactTag];
74
- if (![view isKindOfClass:[UnifiedPlayerUIView class]]) {
75
- RCTLogError(@"Invalid view for tag %@", reactTag);
76
- return;
77
- }
78
- [view pause];
79
- }];
80
- }
81
-
82
- // Seek to specific time
83
- RCT_EXPORT_METHOD(seekTo:(nonnull NSNumber *)reactTag time:(nonnull NSNumber *)time) {
84
- [self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *,UIView *> *viewRegistry) {
85
- UnifiedPlayerUIView *view = (UnifiedPlayerUIView *)viewRegistry[reactTag];
86
- if (![view isKindOfClass:[UnifiedPlayerUIView class]]) {
87
- RCTLogError(@"Invalid view for tag %@", reactTag);
88
- return;
89
- }
90
- [view seekToTime:[time floatValue]];
91
- }];
92
- }
93
-
94
- // Get current playback time
95
- RCT_EXPORT_METHOD(getCurrentTime:(nonnull NSNumber *)reactTag
96
- resolver:(RCTPromiseResolveBlock)resolve
97
- rejecter:(RCTPromiseRejectBlock)reject) {
98
- [self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *,UIView *> *viewRegistry) {
99
- UnifiedPlayerUIView *view = (UnifiedPlayerUIView *)viewRegistry[reactTag];
100
- if (![view isKindOfClass:[UnifiedPlayerUIView class]]) {
101
- reject(@"error", @"Invalid view for tag", nil);
102
- return;
103
- }
104
- resolve(@([view getCurrentTime]));
105
- }];
106
- }
107
-
108
- // Get video duration
109
- RCT_EXPORT_METHOD(getDuration:(nonnull NSNumber *)reactTag
110
- resolver:(RCTPromiseResolveBlock)resolve
111
- rejecter:(RCTPromiseRejectBlock)reject) {
112
- [self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *,UIView *> *viewRegistry) {
113
- UnifiedPlayerUIView *view = (UnifiedPlayerUIView *)viewRegistry[reactTag];
114
- if (![view isKindOfClass:[UnifiedPlayerUIView class]]) {
115
- reject(@"error", @"Invalid view for tag", nil);
116
- return;
117
- }
118
- resolve(@([view getDuration]));
119
- }];
120
- }
121
-
122
- @end
123
-
124
- // Global event emitter instance
125
- static UnifiedPlayerModule *eventEmitter = nil;
126
-
127
43
  // Main player view implementation
128
44
  @implementation UnifiedPlayerUIView
129
45
 
@@ -235,17 +151,38 @@ static UnifiedPlayerModule *eventEmitter = nil;
235
151
  }
236
152
 
237
153
  - (void)sendProgressEvent:(float)currentTime duration:(float)duration {
238
- NSDictionary *event = @{
239
- @"currentTime": @(currentTime),
240
- @"duration": @(duration)
241
- };
242
-
243
- if (eventEmitter != nil) {
244
- [eventEmitter sendEventWithName:@"onProgress" body:event];
154
+ if (self.onProgress) {
155
+ self.onProgress(@{
156
+ @"currentTime": @(currentTime),
157
+ @"duration": @(duration)
158
+ });
245
159
  }
246
160
  }
247
161
 
248
162
  - (void)sendEvent:(NSString *)eventName body:(NSDictionary *)body {
163
+ // Map event names to their corresponding callback properties
164
+ if ([eventName isEqualToString:@"onLoadStart"] && self.onLoadStart) {
165
+ self.onLoadStart(body);
166
+ } else if ([eventName isEqualToString:@"onReadyToPlay"] && self.onReadyToPlay) {
167
+ self.onReadyToPlay(body);
168
+ } else if ([eventName isEqualToString:@"onError"] && self.onError) {
169
+ self.onError(body);
170
+ } else if ([eventName isEqualToString:@"onProgress"] && self.onProgress) {
171
+ self.onProgress(body);
172
+ } else if ([eventName isEqualToString:@"onPlaybackComplete"] && self.onPlaybackComplete) {
173
+ self.onPlaybackComplete(body);
174
+ } else if ([eventName isEqualToString:@"onPlaybackStalled"] && self.onPlaybackStalled) {
175
+ self.onPlaybackStalled(body);
176
+ } else if ([eventName isEqualToString:@"onPlaybackResumed"] && self.onPlaybackResumed) {
177
+ self.onPlaybackResumed(body);
178
+ } else if ([eventName isEqualToString:@"onPlaying"] && self.onPlaying) {
179
+ self.onPlaying(body);
180
+ } else if ([eventName isEqualToString:@"onPaused"] && self.onPaused) {
181
+ self.onPaused(body);
182
+ }
183
+
184
+ // Also send events through the module for backward compatibility
185
+ UnifiedPlayerModule *eventEmitter = [self.bridge moduleForClass:[UnifiedPlayerModule class]];
249
186
  if (eventEmitter != nil) {
250
187
  [eventEmitter sendEventWithName:eventName body:body];
251
188
  }
@@ -256,6 +193,8 @@ static UnifiedPlayerModule *eventEmitter = nil;
256
193
  _videoUrlString = [videoUrlString copy];
257
194
 
258
195
  if (videoUrlString) {
196
+ // Send onLoadStart event when we set a video URL, before loading starts
197
+ [self sendEvent:@"onLoadStart" body:@{}];
259
198
  [self loadVideo];
260
199
  } else {
261
200
  [_player stop];
@@ -301,10 +240,6 @@ static UnifiedPlayerModule *eventEmitter = nil;
301
240
  // Create VLC media options array
302
241
  NSMutableArray *mediaOptions = [NSMutableArray array];
303
242
 
304
- // Add auth token if available
305
- if (self->_authToken.length > 0) {
306
- [mediaOptions addObject:[NSString stringWithFormat:@"http-header-fields=Authorization: Bearer %@", self->_authToken]];
307
- }
308
243
 
309
244
  // Add default network caching options for streaming
310
245
  BOOL isStreaming = [videoURL.scheme hasPrefix:@"http"] ||
@@ -422,9 +357,11 @@ static UnifiedPlayerModule *eventEmitter = nil;
422
357
  RCTLogInfo(@"[UnifiedPlayerViewManager] pause called");
423
358
  }
424
359
 
425
- - (void)seekToTime:(float)time {
360
+ - (void)seekToTime:(NSNumber *)timeNumber {
361
+ float time = [timeNumber floatValue];
426
362
  // VLC uses a 0-1 position value for seeking
427
- float position = time / [self getDuration];
363
+ float duration = [self getDuration];
364
+ float position = duration > 0 ? time / duration : 0;
428
365
  position = MAX(0, MIN(1, position)); // Ensure position is between 0 and 1
429
366
 
430
367
  [_player setPosition:position];
@@ -462,15 +399,6 @@ static UnifiedPlayerModule *eventEmitter = nil;
462
399
  }
463
400
  }
464
401
 
465
- - (void)setAuthToken:(NSString *)authToken {
466
- if (_authToken != authToken) {
467
- _authToken = [authToken copy];
468
- // If we already have a URL, reload with the new auth token
469
- if (_videoUrlString) {
470
- [self loadVideo];
471
- }
472
- }
473
- }
474
402
 
475
403
  #pragma mark - VLCMediaPlayerDelegate
476
404
 
@@ -495,12 +423,17 @@ static UnifiedPlayerModule *eventEmitter = nil;
495
423
  _player.hasVideoOut ? @"YES" : @"NO");
496
424
 
497
425
  // Check video tracks
498
- NSInteger videoTrackCount = _player.numberOfVideoTracks;
499
- RCTLogInfo(@"[UnifiedPlayerViewManager] Video track count: %ld", (long)videoTrackCount);
500
-
501
- if (videoTrackCount > 0) {
502
- RCTLogInfo(@"[UnifiedPlayerViewManager] Current video track index: %d", _player.currentVideoTrackIndex);
503
- RCTLogInfo(@"[UnifiedPlayerViewManager] Video track names: %@", _player.videoTrackNames);
426
+ NSArray *videoTracks = [_player.media tracksInformation];
427
+ if (videoTracks.count > 0) {
428
+ RCTLogInfo(@"[UnifiedPlayerViewManager] Video tracks found: %lu", (unsigned long)videoTracks.count);
429
+
430
+ // Send ready event the first time we start playing
431
+ if (!_hasRenderedVideo) {
432
+ [self sendEvent:@"onReadyToPlay" body:@{}];
433
+ }
434
+
435
+ // Send playing event when we actually start playing
436
+ [self sendEvent:@"onPlaying" body:@{}];
504
437
 
505
438
  // Trigger a delayed drawable update to help with rendering
506
439
  if (!_hasRenderedVideo && _player.videoSize.width > 0) {
@@ -513,14 +446,15 @@ static UnifiedPlayerModule *eventEmitter = nil;
513
446
  }
514
447
 
515
448
  // Check for buffer state transitions
516
- if ((state == VLCMediaPlayerStateBuffering && _previousState != VLCMediaPlayerStateBuffering) ||
517
- (state == VLCMediaPlayerStatePlaying && _previousState == VLCMediaPlayerStateBuffering)) {
518
- [self handleBufferingStatusChange];
449
+ if (_previousState == VLCMediaPlayerStateBuffering && state == VLCMediaPlayerStatePlaying) {
450
+ // We've recovered from buffering
451
+ [self sendEvent:@"onPlaybackResumed" body:@{}];
519
452
  }
520
453
 
521
- // Save the current state for next time
454
+ // Store the current state for future comparisons
522
455
  _previousState = state;
523
456
 
457
+ // React to state changes
524
458
  switch (state) {
525
459
  case VLCMediaPlayerStateOpening:
526
460
  RCTLogInfo(@"[UnifiedPlayerViewManager] VLCMediaPlayerStateOpening");
@@ -528,20 +462,11 @@ static UnifiedPlayerModule *eventEmitter = nil;
528
462
 
529
463
  case VLCMediaPlayerStateBuffering:
530
464
  RCTLogInfo(@"[UnifiedPlayerViewManager] VLCMediaPlayerStateBuffering");
531
- [self sendEvent:@"onBuffering" body:@{
532
- @"isPlaying": @(_player.isPlaying),
533
- @"duration": @([self getDuration])
534
- }];
535
- break;
536
-
465
+ [self sendEvent:@"onPlaybackStalled" body:@{}];
466
+ break;
467
+
537
468
  case VLCMediaPlayerStatePlaying:
538
469
  RCTLogInfo(@"[UnifiedPlayerViewManager] VLCMediaPlayerStatePlaying");
539
- [self sendEvent:@"onPlaying" body:@{
540
- @"target": @(1),
541
- @"duration": @([self getDuration] * 1000), // Convert to ms for consistency
542
- @"seekable": @(YES)
543
- }];
544
- [self sendEvent:@"onReadyToPlay" body:@{}];
545
470
  break;
546
471
 
547
472
  case VLCMediaPlayerStatePaused:
@@ -551,7 +476,7 @@ static UnifiedPlayerModule *eventEmitter = nil;
551
476
 
552
477
  case VLCMediaPlayerStateStopped:
553
478
  RCTLogInfo(@"[UnifiedPlayerViewManager] VLCMediaPlayerStateStopped");
554
- [self sendEvent:@"onStopped" body:@{}];
479
+ // We don't emit onStopped event as it's not in our unified event list
555
480
  break;
556
481
 
557
482
  case VLCMediaPlayerStateEnded:
@@ -561,9 +486,9 @@ static UnifiedPlayerModule *eventEmitter = nil;
561
486
  // Handle looping
562
487
  if (_loop) {
563
488
  [_player stop];
564
- [_player play];
565
- }
566
- break;
489
+ [_player play];
490
+ }
491
+ break;
567
492
 
568
493
  case VLCMediaPlayerStateError:
569
494
  RCTLogInfo(@"[UnifiedPlayerViewManager] VLCMediaPlayerStateError");
@@ -575,7 +500,7 @@ static UnifiedPlayerModule *eventEmitter = nil;
575
500
  break;
576
501
 
577
502
  default:
578
- break;
503
+ break;
579
504
  }
580
505
  }
581
506
 
@@ -644,12 +569,6 @@ RCT_EXPORT_MODULE(UnifiedPlayerView)
644
569
  {
645
570
  UnifiedPlayerUIView *playerView = [[UnifiedPlayerUIView alloc] init];
646
571
  playerView.bridge = self.bridge;
647
-
648
- // Store the event emitter for sending events
649
- if (eventEmitter == nil) {
650
- eventEmitter = [self.bridge moduleForClass:[UnifiedPlayerModule class]];
651
- }
652
-
653
572
  return playerView;
654
573
  }
655
574
 
@@ -671,12 +590,6 @@ RCT_CUSTOM_VIEW_PROPERTY(loop, BOOL, UnifiedPlayerUIView)
671
590
  view.loop = [RCTConvert BOOL:json];
672
591
  }
673
592
 
674
- // Auth token property
675
- RCT_CUSTOM_VIEW_PROPERTY(authToken, NSString, UnifiedPlayerUIView)
676
- {
677
- view.authToken = [RCTConvert NSString:json];
678
- }
679
-
680
593
  // Media options property
681
594
  RCT_CUSTOM_VIEW_PROPERTY(mediaOptions, NSArray, UnifiedPlayerUIView)
682
595
  {
@@ -689,4 +602,15 @@ RCT_CUSTOM_VIEW_PROPERTY(isPaused, BOOL, UnifiedPlayerUIView)
689
602
  view.isPaused = [RCTConvert BOOL:json];
690
603
  }
691
604
 
605
+ // Event handlers
606
+ RCT_EXPORT_VIEW_PROPERTY(onLoadStart, RCTDirectEventBlock);
607
+ RCT_EXPORT_VIEW_PROPERTY(onReadyToPlay, RCTDirectEventBlock);
608
+ RCT_EXPORT_VIEW_PROPERTY(onError, RCTDirectEventBlock);
609
+ RCT_EXPORT_VIEW_PROPERTY(onProgress, RCTDirectEventBlock);
610
+ RCT_EXPORT_VIEW_PROPERTY(onPlaybackComplete, RCTDirectEventBlock);
611
+ RCT_EXPORT_VIEW_PROPERTY(onPlaybackStalled, RCTDirectEventBlock);
612
+ RCT_EXPORT_VIEW_PROPERTY(onPlaybackResumed, RCTDirectEventBlock);
613
+ RCT_EXPORT_VIEW_PROPERTY(onPlaying, RCTDirectEventBlock);
614
+ RCT_EXPORT_VIEW_PROPERTY(onPaused, RCTDirectEventBlock);
615
+
692
616
  @end
@@ -27,14 +27,20 @@ const UnifiedPlayerModule = NativeModules.UnifiedPlayer;
27
27
 
28
28
  // Export event types for reference
29
29
  export const UnifiedPlayerEventTypes = {
30
+ LOAD_START: 'onLoadStart',
30
31
  READY: 'onReadyToPlay',
31
32
  ERROR: 'onError',
32
33
  PROGRESS: 'onProgress',
33
34
  COMPLETE: 'onPlaybackComplete',
34
35
  STALLED: 'onPlaybackStalled',
35
- RESUMED: 'onPlaybackResumed'
36
+ RESUMED: 'onPlaybackResumed',
37
+ PLAYING: 'onPlaying',
38
+ PAUSED: 'onPaused'
36
39
  };
37
40
 
41
+ // Export events emitter for event listeners
42
+ export const UnifiedPlayerEvents = NativeModules.UnifiedPlayer;
43
+
38
44
  /**
39
45
  * UnifiedPlayerView component for video playback
40
46
  */
@@ -52,41 +58,62 @@ export const UnifiedPlayer = {
52
58
  /**
53
59
  * Start playback
54
60
  * @param viewTag - The tag of the player view
61
+ * @returns Promise resolving to true if successful
55
62
  */
56
63
  play: viewTag => {
57
64
  try {
58
65
  console.log('UnifiedPlayer.play called with viewTag:', viewTag);
59
- UnifiedPlayerModule.play(viewTag);
60
- console.log('Native play method called successfully');
66
+ return UnifiedPlayerModule.play(viewTag).then(result => {
67
+ console.log('Native play method called successfully');
68
+ return result;
69
+ }).catch(error => {
70
+ console.log('Error calling play:', error instanceof Error ? error.message : String(error));
71
+ throw error;
72
+ });
61
73
  } catch (error) {
62
74
  console.log('Error calling play:', error instanceof Error ? error.message : String(error));
75
+ return Promise.reject(error);
63
76
  }
64
77
  },
65
78
  /**
66
79
  * Pause playback
67
80
  * @param viewTag - The tag of the player view
81
+ * @returns Promise resolving to true if successful
68
82
  */
69
83
  pause: viewTag => {
70
84
  try {
71
85
  console.log('UnifiedPlayer.pause called with viewTag:', viewTag);
72
- UnifiedPlayerModule.pause(viewTag);
73
- console.log('Native pause method called successfully');
86
+ return UnifiedPlayerModule.pause(viewTag).then(result => {
87
+ console.log('Native pause method called successfully');
88
+ return result;
89
+ }).catch(error => {
90
+ console.log('Error calling pause:', error instanceof Error ? error.message : String(error));
91
+ throw error;
92
+ });
74
93
  } catch (error) {
75
94
  console.log('Error calling pause:', error instanceof Error ? error.message : String(error));
95
+ return Promise.reject(error);
76
96
  }
77
97
  },
78
98
  /**
79
99
  * Seek to a specific time
80
100
  * @param viewTag - The tag of the player view
81
101
  * @param time - Time in seconds to seek to
102
+ * @returns Promise resolving to true if successful
82
103
  */
83
104
  seekTo: (viewTag, time) => {
84
105
  try {
85
106
  console.log('UnifiedPlayer.seekTo called with viewTag:', viewTag, 'time:', time);
86
- UnifiedPlayerModule.seekTo(viewTag, time);
87
- console.log('Native seekTo method called successfully');
107
+ return UnifiedPlayerModule.seekTo(viewTag, time).then(result => {
108
+ console.log('Native seekTo method called successfully');
109
+ return result;
110
+ }).catch(error => {
111
+ console.log('Error calling seekTo:', error instanceof Error ? error.message : String(error));
112
+ throw error;
113
+ });
88
114
  } catch (error) {
89
115
  console.log('Error calling seekTo:', error instanceof Error ? error.message : String(error));
116
+ return Promise.reject(error);
90
117
  }
91
118
  },
92
119
  /**
@@ -1 +1 @@
1
- {"version":3,"names":["forwardRef","requireNativeComponent","UIManager","NativeModules","Platform","jsx","_jsx","LINKING_ERROR","select","ios","default","getViewManagerConfig","UnifiedPlayer","Error","NativeUnifiedPlayerView","UnifiedPlayerModule","UnifiedPlayerEventTypes","READY","ERROR","PROGRESS","COMPLETE","STALLED","RESUMED","UnifiedPlayerView","props","ref","play","viewTag","console","log","error","message","String","pause","seekTo","time","getCurrentTime","Promise","reject","getDuration"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["forwardRef","requireNativeComponent","UIManager","NativeModules","Platform","jsx","_jsx","LINKING_ERROR","select","ios","default","getViewManagerConfig","UnifiedPlayer","Error","NativeUnifiedPlayerView","UnifiedPlayerModule","UnifiedPlayerEventTypes","LOAD_START","READY","ERROR","PROGRESS","COMPLETE","STALLED","RESUMED","PLAYING","PAUSED","UnifiedPlayerEvents","UnifiedPlayerView","props","ref","play","viewTag","console","log","then","result","catch","error","message","String","Promise","reject","pause","seekTo","time","getCurrentTime","getDuration"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":"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","ignoreList":[]}
@@ -5,6 +5,7 @@ export type UnifiedPlayerProps = {
5
5
  autoplay?: boolean;
6
6
  loop?: boolean;
7
7
  isPaused?: boolean;
8
+ onLoadStart?: () => void;
8
9
  onReadyToPlay?: () => void;
9
10
  onError?: (error: any) => void;
10
11
  onPlaybackComplete?: () => void;
@@ -12,15 +13,23 @@ export type UnifiedPlayerProps = {
12
13
  currentTime: number;
13
14
  duration: number;
14
15
  }) => void;
16
+ onPlaybackStalled?: () => void;
17
+ onPlaybackResumed?: () => void;
18
+ onPaused?: () => void;
19
+ onPlaying?: () => void;
15
20
  };
16
21
  export declare const UnifiedPlayerEventTypes: {
22
+ LOAD_START: string;
17
23
  READY: string;
18
24
  ERROR: string;
19
25
  PROGRESS: string;
20
26
  COMPLETE: string;
21
27
  STALLED: string;
22
28
  RESUMED: string;
29
+ PLAYING: string;
30
+ PAUSED: string;
23
31
  };
32
+ export declare const UnifiedPlayerEvents: any;
24
33
  /**
25
34
  * UnifiedPlayerView component for video playback
26
35
  */
@@ -32,19 +41,22 @@ export declare const UnifiedPlayer: {
32
41
  /**
33
42
  * Start playback
34
43
  * @param viewTag - The tag of the player view
44
+ * @returns Promise resolving to true if successful
35
45
  */
36
- play: (viewTag: number) => void;
46
+ play: (viewTag: number) => Promise<boolean>;
37
47
  /**
38
48
  * Pause playback
39
49
  * @param viewTag - The tag of the player view
50
+ * @returns Promise resolving to true if successful
40
51
  */
41
- pause: (viewTag: number) => void;
52
+ pause: (viewTag: number) => Promise<boolean>;
42
53
  /**
43
54
  * Seek to a specific time
44
55
  * @param viewTag - The tag of the player view
45
56
  * @param time - Time in seconds to seek to
57
+ * @returns Promise resolving to true if successful
46
58
  */
47
- seekTo: (viewTag: number, time: number) => void;
59
+ seekTo: (viewTag: number, time: number) => Promise<boolean>;
48
60
  /**
49
61
  * Get current playback time
50
62
  * @param viewTag - The tag of the player view
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AACA,OAAO,EAKL,KAAK,SAAS,EACf,MAAM,cAAc,CAAC;AAkBtB,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,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;AAYF,eAAO,MAAM,uBAAuB;;;;;;;CAOnC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,iBAAiB,8LAK5B,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,aAAa;IACxB;;;OAGG;oBACa,MAAM,KAAG,IAAI;IAa7B;;;OAGG;qBACc,MAAM,KAAG,IAAI;IAa9B;;;;OAIG;sBACe,MAAM,QAAQ,MAAM,KAAG,IAAI;IAkB7C;;;;OAIG;8BACuB,MAAM,KAAG,OAAO,CAAC,MAAM,CAAC;IAalD;;;;OAIG;2BACoB,MAAM,KAAG,OAAO,CAAC,MAAM,CAAC;CAYhD,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AACA,OAAO,EAKL,KAAK,SAAS,EACf,MAAM,cAAc,CAAC;AAkBtB,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,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IAGzB,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;IAGvE,iBAAiB,CAAC,EAAE,MAAM,IAAI,CAAC;IAG/B,iBAAiB,CAAC,EAAE,MAAM,IAAI,CAAC;IAG/B,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IAGtB,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;CACxB,CAAC;AAYF,eAAO,MAAM,uBAAuB;;;;;;;;;;CAUnC,CAAC;AAGF,eAAO,MAAM,mBAAmB,KAA8B,CAAC;AAE/D;;GAEG;AACH,eAAO,MAAM,iBAAiB,8LAK5B,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,aAAa;IACxB;;;;OAIG;oBACa,MAAM,KAAG,OAAO,CAAC,OAAO,CAAC;IAwBzC;;;;OAIG;qBACc,MAAM,KAAG,OAAO,CAAC,OAAO,CAAC;IAwB1C;;;;;OAKG;sBACe,MAAM,QAAQ,MAAM,KAAG,OAAO,CAAC,OAAO,CAAC;IA6BzD;;;;OAIG;8BACuB,MAAM,KAAG,OAAO,CAAC,MAAM,CAAC;IAalD;;;;OAIG;2BACoB,MAAM,KAAG,OAAO,CAAC,MAAM,CAAC;CAYhD,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-unified-player",
3
- "version": "0.3.2",
3
+ "version": "0.3.3",
4
4
  "description": "Unified Player",
5
5
  "source": "./src/index.tsx",
6
6
  "main": "./lib/module/index.js",
package/src/index.tsx CHANGED
@@ -39,6 +39,9 @@ export type UnifiedPlayerProps = {
39
39
  // Is the player currently paused
40
40
  isPaused?: boolean;
41
41
 
42
+ // Callback when video begins loading
43
+ onLoadStart?: () => void;
44
+
42
45
  // Callback when video is ready to play
43
46
  onReadyToPlay?: () => void;
44
47
 
@@ -50,6 +53,18 @@ export type UnifiedPlayerProps = {
50
53
 
51
54
  // Callback for playback progress
52
55
  onProgress?: (data: { currentTime: number; duration: number }) => void;
56
+
57
+ // Callback when playback is stalled (buffering)
58
+ onPlaybackStalled?: () => void;
59
+
60
+ // Callback when playback resumes after stalling
61
+ onPlaybackResumed?: () => void;
62
+
63
+ // Callback when playback is paused
64
+ onPaused?: () => void;
65
+
66
+ // Callback when playback is playing
67
+ onPlaying?: () => void;
53
68
  };
54
69
 
55
70
  // Native component registration
@@ -63,14 +78,20 @@ const UnifiedPlayerModule = NativeModules.UnifiedPlayer;
63
78
 
64
79
  // Export event types for reference
65
80
  export const UnifiedPlayerEventTypes = {
81
+ LOAD_START: 'onLoadStart',
66
82
  READY: 'onReadyToPlay',
67
83
  ERROR: 'onError',
68
84
  PROGRESS: 'onProgress',
69
85
  COMPLETE: 'onPlaybackComplete',
70
86
  STALLED: 'onPlaybackStalled',
71
87
  RESUMED: 'onPlaybackResumed',
88
+ PLAYING: 'onPlaying',
89
+ PAUSED: 'onPaused',
72
90
  };
73
91
 
92
+ // Export events emitter for event listeners
93
+ export const UnifiedPlayerEvents = NativeModules.UnifiedPlayer;
94
+
74
95
  /**
75
96
  * UnifiedPlayerView component for video playback
76
97
  */
@@ -88,34 +109,58 @@ export const UnifiedPlayer = {
88
109
  /**
89
110
  * Start playback
90
111
  * @param viewTag - The tag of the player view
112
+ * @returns Promise resolving to true if successful
91
113
  */
92
- play: (viewTag: number): void => {
114
+ play: (viewTag: number): Promise<boolean> => {
93
115
  try {
94
116
  console.log('UnifiedPlayer.play called with viewTag:', viewTag);
95
- UnifiedPlayerModule.play(viewTag);
96
- console.log('Native play method called successfully');
117
+ return UnifiedPlayerModule.play(viewTag)
118
+ .then((result: boolean) => {
119
+ console.log('Native play method called successfully');
120
+ return result;
121
+ })
122
+ .catch((error: any) => {
123
+ console.log(
124
+ 'Error calling play:',
125
+ error instanceof Error ? error.message : String(error)
126
+ );
127
+ throw error;
128
+ });
97
129
  } catch (error) {
98
130
  console.log(
99
131
  'Error calling play:',
100
132
  error instanceof Error ? error.message : String(error)
101
133
  );
134
+ return Promise.reject(error);
102
135
  }
103
136
  },
104
137
 
105
138
  /**
106
139
  * Pause playback
107
140
  * @param viewTag - The tag of the player view
141
+ * @returns Promise resolving to true if successful
108
142
  */
109
- pause: (viewTag: number): void => {
143
+ pause: (viewTag: number): Promise<boolean> => {
110
144
  try {
111
145
  console.log('UnifiedPlayer.pause called with viewTag:', viewTag);
112
- UnifiedPlayerModule.pause(viewTag);
113
- console.log('Native pause method called successfully');
146
+ return UnifiedPlayerModule.pause(viewTag)
147
+ .then((result: boolean) => {
148
+ console.log('Native pause method called successfully');
149
+ return result;
150
+ })
151
+ .catch((error: any) => {
152
+ console.log(
153
+ 'Error calling pause:',
154
+ error instanceof Error ? error.message : String(error)
155
+ );
156
+ throw error;
157
+ });
114
158
  } catch (error) {
115
159
  console.log(
116
160
  'Error calling pause:',
117
161
  error instanceof Error ? error.message : String(error)
118
162
  );
163
+ return Promise.reject(error);
119
164
  }
120
165
  },
121
166
 
@@ -123,8 +168,9 @@ export const UnifiedPlayer = {
123
168
  * Seek to a specific time
124
169
  * @param viewTag - The tag of the player view
125
170
  * @param time - Time in seconds to seek to
171
+ * @returns Promise resolving to true if successful
126
172
  */
127
- seekTo: (viewTag: number, time: number): void => {
173
+ seekTo: (viewTag: number, time: number): Promise<boolean> => {
128
174
  try {
129
175
  console.log(
130
176
  'UnifiedPlayer.seekTo called with viewTag:',
@@ -132,13 +178,24 @@ export const UnifiedPlayer = {
132
178
  'time:',
133
179
  time
134
180
  );
135
- UnifiedPlayerModule.seekTo(viewTag, time);
136
- console.log('Native seekTo method called successfully');
181
+ return UnifiedPlayerModule.seekTo(viewTag, time)
182
+ .then((result: boolean) => {
183
+ console.log('Native seekTo method called successfully');
184
+ return result;
185
+ })
186
+ .catch((error: any) => {
187
+ console.log(
188
+ 'Error calling seekTo:',
189
+ error instanceof Error ? error.message : String(error)
190
+ );
191
+ throw error;
192
+ });
137
193
  } catch (error) {
138
194
  console.log(
139
195
  'Error calling seekTo:',
140
196
  error instanceof Error ? error.message : String(error)
141
197
  );
198
+ return Promise.reject(error);
142
199
  }
143
200
  },
144
201