expo-gliph-player 1.3.14 → 1.3.16

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.
@@ -148,33 +148,40 @@ class GliphPlayerModule(
148
148
  }
149
149
  }
150
150
 
151
- @ReactMethod
152
- override fun skip(index: Double, initialPosition: Double, promise: Promise) {
153
- scope.launch {
154
- try {
155
- playerService?.skip(index.toInt(), if (initialPosition < 0) -1.0 else initialPosition)
156
- promise.resolve(null)
157
- } catch (e: Exception) { promise.reject("skip_error", e.message, e) }
151
+ @ReactMethod
152
+ override fun skip(index: Double, initialPosition: Double, autoPlay: Boolean, promise: Promise) {
153
+ scope.launch {
154
+ try {
155
+ val pos = if (initialPosition < 0) -1.0 else initialPosition
156
+ playerService?.skip(index.toInt(), pos, autoPlay)
157
+ promise.resolve(null)
158
+ } catch (e: Exception) {
159
+ promise.reject("skip_error", e.message, e)
160
+ }
161
+ }
158
162
  }
159
- }
160
163
 
161
164
  @ReactMethod
162
- override fun skipToNext(initialPosition: Double, promise: Promise) {
165
+ override fun skipToNext(initialPosition: Double, autoPlay: Boolean, promise: Promise) {
163
166
  scope.launch {
164
167
  try {
165
- playerService?.skipToNext(if (initialPosition < 0) -1.0 else initialPosition)
168
+ playerService?.skipToNext(if (initialPosition < 0) -1.0 else initialPosition, autoPlay)
166
169
  promise.resolve(null)
167
- } catch (e: Exception) { promise.reject("skip_error", e.message, e) }
170
+ } catch (e: Exception) {
171
+ promise.reject("skip_error", e.message, e)
172
+ }
168
173
  }
169
174
  }
170
175
 
171
176
  @ReactMethod
172
- override fun skipToPrevious(initialPosition: Double, promise: Promise) {
177
+ override fun skipToPrevious(initialPosition: Double, autoPlay: Boolean, promise: Promise) {
173
178
  scope.launch {
174
179
  try {
175
- playerService?.skipToPrevious(if (initialPosition < 0) -1.0 else initialPosition)
180
+ playerService?.skipToPrevious(if (initialPosition < 0) -1.0 else initialPosition, autoPlay)
176
181
  promise.resolve(null)
177
- } catch (e: Exception) { promise.reject("skip_error", e.message, e) }
182
+ } catch (e: Exception) {
183
+ promise.reject("skip_error", e.message, e)
184
+ }
178
185
  }
179
186
  }
180
187
 
@@ -357,4 +364,4 @@ class GliphPlayerModule(
357
364
  }
358
365
 
359
366
  override fun getName() = NAME
360
- }
367
+ }
@@ -12,6 +12,7 @@ import android.os.IBinder
12
12
  import androidx.media3.common.*
13
13
  import androidx.media3.common.util.UnstableApi
14
14
  import androidx.media3.exoplayer.ExoPlayer
15
+ import androidx.media3.exoplayer.DefaultLoadControl
15
16
  import androidx.media3.exoplayer.source.DefaultMediaSourceFactory
16
17
  import androidx.media3.session.*
17
18
  import androidx.core.app.NotificationCompat
@@ -127,8 +128,8 @@ class GliphPlayerService : MediaLibraryService() {
127
128
  when (intent?.action) {
128
129
  ACTION_PLAY -> play()
129
130
  ACTION_PAUSE -> pause()
130
- ACTION_SKIP_NEXT -> skipToNext(-1.0)
131
- ACTION_SKIP_PREVIOUS -> skipToPrevious(-1.0)
131
+ ACTION_SKIP_NEXT -> skipToNext(-1.0, true)
132
+ ACTION_SKIP_PREVIOUS -> skipToPrevious(-1.0, true)
132
133
  ACTION_STOP -> {
133
134
  stop()
134
135
  stopSelf()
@@ -163,29 +164,39 @@ class GliphPlayerService : MediaLibraryService() {
163
164
  // ── Init ────────────────────────────────────────────────────────────────────
164
165
 
165
166
  private fun initPlayer(opts: ReadableMap? = null) {
166
- val minBufferMs = (getDouble(opts, "minBuffer", 15.0) * 1000).toInt()
167
- val maxBufferMs = (getDouble(opts, "maxBuffer", 50.0) * 1000).toInt()
168
- val playBufferMs = (getDouble(opts, "playBuffer", 2.5) * 1000).toInt()
169
- val backBufferMs = (getDouble(opts, "backBuffer", 0.0) * 1000).toInt()
170
-
171
- val loadControl = androidx.media3.exoplayer.DefaultLoadControl.Builder()
172
- .setBufferDurationsMs(minBufferMs, maxBufferMs, playBufferMs, playBufferMs)
173
- .setBackBuffer(backBufferMs, /* retainBackBufferFromKeyframe= */ false)
174
- .build()
167
+ val playBufferSec = getDouble(opts, "playBuffer", 2.5)
168
+ val minBufferSec = getDouble(opts, "minBuffer", 15.0)
169
+ val maxBufferSec = getDouble(opts, "maxBuffer", 50.0)
170
+ val backBufferSec = getDouble(opts, "backBuffer", 0.0)
171
+
172
+ val playBufferMs = (playBufferSec * 1000).toInt() // 2500ms
173
+ var minBufferMs = (minBufferSec * 1000).toInt() // 15000ms
174
+ val maxBufferMs = (maxBufferSec * 1000).toInt() // 50000ms
175
+ val backBufferMs = (backBufferSec * 1000).toInt() // 0ms
176
+
177
+ if (minBufferMs < playBufferMs) {
178
+ Log.w("GliphPlayer", "minBufferMs ($minBufferMs) < playBufferMs ($playBufferMs), adjusting...")
179
+ minBufferMs = playBufferMs
180
+ }
181
+
182
+ val loadControl = DefaultLoadControl.Builder()
183
+ .setBufferDurationsMs(minBufferMs, maxBufferMs, playBufferMs, playBufferMs)
184
+ .setBackBuffer(backBufferMs, false)
185
+ .build()
175
186
 
176
187
  player = ExoPlayer.Builder(this)
177
- .setMediaSourceFactory(DefaultMediaSourceFactory(this))
178
- .setLoadControl(loadControl)
179
- .setHandleAudioBecomingNoisy(true)
180
- .setWakeMode(C.WAKE_MODE_NETWORK)
181
- .setAudioAttributes(
182
- AudioAttributes.Builder()
183
- .setUsage(C.USAGE_MEDIA)
184
- .setContentType(C.AUDIO_CONTENT_TYPE_MUSIC)
185
- .build(),
186
- /* handleAudioFocus= */ true
187
- )
188
- .build()
188
+ .setMediaSourceFactory(DefaultMediaSourceFactory(this))
189
+ .setLoadControl(loadControl)
190
+ .setHandleAudioBecomingNoisy(true)
191
+ .setWakeMode(C.WAKE_MODE_NETWORK)
192
+ .setAudioAttributes(
193
+ AudioAttributes.Builder()
194
+ .setUsage(C.USAGE_MEDIA)
195
+ .setContentType(C.AUDIO_CONTENT_TYPE_MUSIC)
196
+ .build(),
197
+ true
198
+ )
199
+ .build()
189
200
 
190
201
  player.addListener(playerListener)
191
202
 
@@ -384,7 +395,7 @@ class GliphPlayerService : MediaLibraryService() {
384
395
  insertBeforeIndex
385
396
  }
386
397
 
387
- val wasEmpty = queue.isEmpty() // ✅ Сохраняем состояние ДО добавления
398
+ val wasEmpty = queue.isEmpty()
388
399
  val mediaItems = mutableListOf<MediaItem>()
389
400
 
390
401
  for (i in 0 until tracks.size()) {
@@ -400,7 +411,6 @@ class GliphPlayerService : MediaLibraryService() {
400
411
  player.addMediaItems(insertBeforeIndex, mediaItems)
401
412
  }
402
413
 
403
- // ✅ Если очередь была пуста - отправляем событие
404
414
  if (wasEmpty && queue.isNotEmpty()) {
405
415
  emitActiveTrackChanged()
406
416
  }
@@ -432,42 +442,57 @@ class GliphPlayerService : MediaLibraryService() {
432
442
  }
433
443
  }
434
444
 
435
- // ✅ ИСПРАВЛЕНО: Добавлено событие
436
- fun skip(index: Int, initialPosition: Double) {
437
- val lastIndex = player.currentMediaItemIndex
438
- player.seekTo(index, if (initialPosition >= 0) (initialPosition * 1000).toLong() else C.TIME_UNSET)
439
- player.play()
445
+ fun skip(index: Int, initialPosition: Double, autoPlay: Boolean = true) {
446
+ val lastIndex = player.currentMediaItemIndex
440
447
 
441
- // ✅ Отправляем событие
442
- emitActiveTrackChanged(lastIndex)
443
- emitPlaybackState("playing")
444
- }
448
+ if (index < 0 || index >= queue.size) {
449
+ Log.e("GliphPlayer", "skip: index $index out of bounds")
450
+ return
451
+ }
445
452
 
446
- // ✅ ИСПРАВЛЕНО: Добавлено событие
447
- fun skipToNext(initialPosition: Double) {
453
+ player.seekTo(index, if (initialPosition >= 0) (initialPosition * 1000).toLong() else C.TIME_UNSET)
454
+
455
+ if (autoPlay) {
456
+ player.playWhenReady = true
457
+
458
+ if (player.playbackState == Player.STATE_IDLE) {
459
+ player.prepare()
460
+ }
461
+
462
+ player.play()
463
+ emitPlaybackState("playing")
464
+ }
465
+
466
+ emitActiveTrackChanged(lastIndex)
467
+ }
468
+
469
+ fun skipToNext(initialPosition: Double, autoPlay: Boolean = true) {
448
470
  if (player.hasNextMediaItem()) {
449
471
  val lastIndex = player.currentMediaItemIndex
450
472
  player.seekToNextMediaItem()
451
473
  if (initialPosition >= 0) player.seekTo((initialPosition * 1000).toLong())
452
- player.play()
453
474
 
454
- // ✅ Отправляем событие
475
+ if (autoPlay) {
476
+ player.play()
477
+ }
478
+
455
479
  emitActiveTrackChanged(lastIndex)
456
- emitPlaybackState("playing")
480
+ emitPlaybackState(if (autoPlay) "playing" else "paused")
457
481
  }
458
482
  }
459
483
 
460
- // ✅ ИСПРАВЛЕНО: Добавлено событие
461
- fun skipToPrevious(initialPosition: Double) {
484
+ fun skipToPrevious(initialPosition: Double, autoPlay: Boolean = true) {
462
485
  if (player.hasPreviousMediaItem()) {
463
486
  val lastIndex = player.currentMediaItemIndex
464
487
  player.seekToPreviousMediaItem()
465
488
  if (initialPosition >= 0) player.seekTo((initialPosition * 1000).toLong())
466
- player.play()
467
489
 
468
- // ✅ Отправляем событие
490
+ if (autoPlay) {
491
+ player.play()
492
+ }
493
+
469
494
  emitActiveTrackChanged(lastIndex)
470
- emitPlaybackState("playing")
495
+ emitPlaybackState(if (autoPlay) "playing" else "paused")
471
496
  }
472
497
  }
473
498
 
@@ -480,17 +505,14 @@ class GliphPlayerService : MediaLibraryService() {
480
505
 
481
506
  // ── Playback control ────────────────────────────────────────────────────────
482
507
 
483
- // ✅ ИСПРАВЛЕНО: Добавлены события
484
508
  fun play() {
485
509
  if (player.playbackState == Player.STATE_IDLE) {
486
510
  player.prepare()
487
511
  }
488
512
  player.play()
489
513
 
490
- // ✅ Отправляем состояние
491
514
  emitPlaybackState("playing")
492
515
 
493
- // ✅ Если есть активный трек - отправляем его
494
516
  if (player.currentMediaItemIndex >= 0 && player.currentMediaItemIndex < queue.size) {
495
517
  emitActiveTrackChanged()
496
518
  }
@@ -498,34 +520,28 @@ class GliphPlayerService : MediaLibraryService() {
498
520
  updateMediaNotification()
499
521
  }
500
522
 
501
- // ✅ ИСПРАВЛЕНО: Добавлено событие
502
523
  fun pause() {
503
524
  player.pause()
504
525
 
505
- // ✅ Отправляем состояние
506
526
  emitPlaybackState("paused")
507
527
 
508
528
  updateMediaNotification()
509
529
  }
510
530
 
511
- // ✅ ИСПРАВЛЕНО: Добавлено событие
512
531
  fun stop() {
513
532
  player.stop()
514
533
 
515
- // ✅ Отправляем состояние
516
534
  emitPlaybackState("stopped")
517
535
 
518
536
  updateMediaNotification()
519
537
  }
520
538
 
521
- // ✅ ИСПРАВЛЕНО: Добавлены события
522
539
  fun reset() {
523
540
  val lastIndex = player.currentMediaItemIndex
524
541
  player.stop()
525
542
  player.clearMediaItems()
526
543
  queue.clear()
527
544
 
528
- // ✅ Отправляем событие об очистке
529
545
  val map = Arguments.createMap()
530
546
  map.putInt("index", -1)
531
547
  map.putNull("track")
@@ -766,12 +782,10 @@ class GliphPlayerService : MediaLibraryService() {
766
782
  updateMediaNotification()
767
783
 
768
784
  if (playbackState == Player.STATE_ENDED) {
769
- // ✅ Отправляем track-ended
770
785
  val map = Arguments.createMap()
771
786
  map.putInt("index", player.currentMediaItemIndex)
772
787
  eventEmitter?.invoke("playback-track-ended", map)
773
788
 
774
- // ✅ Отправляем queue-ended
775
789
  val queueMap = Arguments.createMap()
776
790
  queueMap.putInt("index", player.currentMediaItemIndex)
777
791
  queueMap.putDouble("position", player.currentPosition / 1000.0)
@@ -785,7 +799,6 @@ class GliphPlayerService : MediaLibraryService() {
785
799
  }
786
800
 
787
801
  override fun onMediaItemTransition(mediaItem: MediaItem?, reason: Int) {
788
- // ✅ Отправляем track-ended для предыдущего трека
789
802
  if (reason == Player.MEDIA_ITEM_TRANSITION_REASON_AUTO ||
790
803
  reason == Player.MEDIA_ITEM_TRANSITION_REASON_REPEAT) {
791
804
  val endedMap = Arguments.createMap()
@@ -811,7 +824,6 @@ class GliphPlayerService : MediaLibraryService() {
811
824
  map.putNull("lastTrack")
812
825
  }
813
826
 
814
- // ✅ Отправляем active-track-changed
815
827
  eventEmitter?.invoke("playback-active-track-changed", map)
816
828
  lastIndex = newIndex
817
829
  updateMediaNotification()
@@ -20,12 +20,16 @@ public typealias RCTPromiseRejectBlock = (String?, String?, Error?) -> Void
20
20
  private var playerItems: [AVPlayerItem] = []
21
21
  private var queue: [[String: Any]] = []
22
22
  private var currentIndex: Int = -1
23
- private var repeatMode: Int = 0
23
+ private var repeatMode: Int = 0 // 0=off, 1=track, 2=queue
24
24
  private var isSetup = false
25
25
  private var progressTimer: Timer?
26
26
  private var progressInterval: TimeInterval = 1.0
27
27
  private var options: [String: Any] = [:]
28
28
 
29
+ // ✅ AVPlayerLooper для повтора трека
30
+ private var playerLooper: AVPlayerLooper?
31
+ private var templateItem: AVPlayerItem?
32
+
29
33
  private let eventEmitter: EventEmitter
30
34
  private var timeObserver: Any?
31
35
  private var playerObservations: [NSKeyValueObservation] = []
@@ -162,6 +166,7 @@ public typealias RCTPromiseRejectBlock = (String?, String?, Error?) -> Void
162
166
  @objc public func skipToIndex(
163
167
  _ index: Int,
164
168
  initialPosition: Double,
169
+ autoPlay: Bool = true,
165
170
  resolve: @escaping RCTPromiseResolveBlock,
166
171
  reject: @escaping RCTPromiseRejectBlock
167
172
  ) {
@@ -176,7 +181,10 @@ public typealias RCTPromiseRejectBlock = (String?, String?, Error?) -> Void
176
181
  if initialPosition >= 0 {
177
182
  player?.seek(to: CMTime(seconds: initialPosition, preferredTimescale: 1000))
178
183
  }
179
- player?.play()
184
+
185
+ if autoPlay {
186
+ player?.play()
187
+ }
180
188
 
181
189
  emitActiveTrackChanged(lastIndex: lastIndex)
182
190
 
@@ -185,6 +193,7 @@ public typealias RCTPromiseRejectBlock = (String?, String?, Error?) -> Void
185
193
 
186
194
  @objc public func skipToNext(
187
195
  initialPosition: Double,
196
+ autoPlay: Bool = true,
188
197
  resolve: @escaping RCTPromiseResolveBlock,
189
198
  reject: @escaping RCTPromiseRejectBlock
190
199
  ) {
@@ -192,11 +201,12 @@ public typealias RCTPromiseRejectBlock = (String?, String?, Error?) -> Void
192
201
  guard next < queue.count else {
193
202
  reject("skip_error", "No next track", nil); return
194
203
  }
195
- skipToIndex(next, initialPosition: initialPosition, resolve: resolve, reject: reject)
204
+ skipToIndex(next, initialPosition: initialPosition, autoPlay: autoPlay, resolve: resolve, reject: reject)
196
205
  }
197
206
 
198
207
  @objc public func skipToPrevious(
199
208
  initialPosition: Double,
209
+ autoPlay: Bool = true,
200
210
  resolve: @escaping RCTPromiseResolveBlock,
201
211
  reject: @escaping RCTPromiseRejectBlock
202
212
  ) {
@@ -204,7 +214,7 @@ public typealias RCTPromiseRejectBlock = (String?, String?, Error?) -> Void
204
214
  guard prev >= 0 else {
205
215
  reject("skip_error", "No previous track", nil); return
206
216
  }
207
- skipToIndex(prev, initialPosition: initialPosition, resolve: resolve, reject: reject)
217
+ skipToIndex(prev, initialPosition: initialPosition, autoPlay: autoPlay, resolve: resolve, reject: reject)
208
218
  }
209
219
 
210
220
  @objc public func moveFrom(
@@ -254,6 +264,12 @@ public typealias RCTPromiseRejectBlock = (String?, String?, Error?) -> Void
254
264
 
255
265
  @objc public func reset(resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
256
266
  player?.pause()
267
+
268
+ // ✅ Уничтожаем looper
269
+ playerLooper?.disableLooping()
270
+ playerLooper = nil
271
+ templateItem = nil
272
+
257
273
  player?.removeAllItems()
258
274
  queue.removeAll()
259
275
  playerItems.removeAll()
@@ -298,8 +314,23 @@ public typealias RCTPromiseRejectBlock = (String?, String?, Error?) -> Void
298
314
 
299
315
  @objc public func getRate() -> Float { return player?.rate ?? 1.0 }
300
316
 
317
+ // ✅ ИСПРАВЛЕНО: пересоздаём очередь при смене режима
301
318
  @objc public func setRepeatMode(_ mode: Int, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
319
+ let oldMode = repeatMode
302
320
  repeatMode = mode
321
+
322
+ // ✅ Пересоздаём очередь с учётом нового режима
323
+ if oldMode != mode {
324
+ let wasPlaying = player?.timeControlStatus == .playing
325
+ rebuildPlayerQueue()
326
+ if wasPlaying {
327
+ player?.play()
328
+ }
329
+ }
330
+
331
+ // ✅ Отправляем событие
332
+ eventEmitter("playback-repeat-mode-changed", ["mode": mode])
333
+
303
334
  resolve(nil)
304
335
  }
305
336
 
@@ -414,12 +445,40 @@ public typealias RCTPromiseRejectBlock = (String?, String?, Error?) -> Void
414
445
  ])
415
446
  }
416
447
 
448
+ // ✅ ИСПРАВЛЕНО: добавлен AVPlayerLooper для повторения трека
417
449
  private func rebuildPlayerQueue() {
418
450
  guard let player = player else { return }
451
+
452
+ // ✅ Уничтожаем старый looper
453
+ playerLooper?.disableLooping()
454
+ playerLooper = nil
455
+ templateItem = nil
456
+
419
457
  player.removeAllItems()
420
458
  playerItems.removeAll()
421
459
 
422
460
  let startIndex = max(0, currentIndex)
461
+
462
+ // ✅ РЕЖИМ ПОВТОРА ТРЕКА (RepeatMode.Track = 1)
463
+ if repeatMode == 1 && startIndex < queue.count {
464
+ let track = queue[startIndex]
465
+ guard let urlString = track["url"] as? String,
466
+ let url = URL(string: urlString) else { return }
467
+
468
+ // ✅ Создаём template item
469
+ let item = AVPlayerItem(url: url)
470
+ templateItem = item
471
+ playerItems.append(item)
472
+
473
+ // ✅ Создаём looper для бесконечного повтора
474
+ playerLooper = AVPlayerLooper(player: player, templateItem: item)
475
+
476
+ currentIndex = startIndex
477
+ updateNowPlayingInfo()
478
+ return
479
+ }
480
+
481
+ // ✅ ОБЫЧНАЯ ОЧЕРЕДЬ (RepeatMode.Off / RepeatMode.Queue)
423
482
  for i in startIndex..<queue.count {
424
483
  let track = queue[i]
425
484
  guard let urlString = track["url"] as? String,
@@ -528,7 +587,7 @@ public typealias RCTPromiseRejectBlock = (String?, String?, Error?) -> Void
528
587
  guard let self = self else { return .commandFailed }
529
588
  let next = self.currentIndex + 1
530
589
  if next < self.queue.count {
531
- self.skipToIndex(next, initialPosition: -1, resolve: { _ in }, reject: { _, _, _ in })
590
+ self.skipToIndex(next, initialPosition: -1, autoPlay: true, resolve: { _ in }, reject: { _, _, _ in })
532
591
  }
533
592
  self.eventEmitter("remote-next", nil)
534
593
  return .success
@@ -540,7 +599,7 @@ public typealias RCTPromiseRejectBlock = (String?, String?, Error?) -> Void
540
599
  guard let self = self else { return .commandFailed }
541
600
  let prev = self.currentIndex - 1
542
601
  if prev >= 0 {
543
- self.skipToIndex(prev, initialPosition: -1, resolve: { _ in }, reject: { _, _, _ in })
602
+ self.skipToIndex(prev, initialPosition: -1, autoPlay: true, resolve: { _ in }, reject: { _, _, _ in })
544
603
  }
545
604
  self.eventEmitter("remote-previous", nil)
546
605
  return .success
@@ -626,25 +685,24 @@ public typealias RCTPromiseRejectBlock = (String?, String?, Error?) -> Void
626
685
  }
627
686
  }
628
687
 
688
+ // ✅ ИСПРАВЛЕНО: AVPlayerLooper сам обрабатывает повтор трека
629
689
  @objc private func playerItemDidFinish(_ notification: Notification) {
630
690
  guard let finishedItem = notification.object as? AVPlayerItem,
631
691
  finishedItem === player?.currentItem else { return }
632
692
 
693
+ // ✅ Если режим повтора трека - AVPlayerLooper сам обрабатывает, выходим
694
+ if repeatMode == 1 {
695
+ return
696
+ }
697
+
633
698
  let nextIndex = currentIndex + 1
634
699
  let currentPosition = CMTimeGetSeconds(player?.currentTime() ?? .zero)
635
700
 
636
- // ✅ 1. Отправляем событие окончания ТЕКУЩЕГО трека
637
701
  eventEmitter("playback-track-ended", [
638
702
  "index": currentIndex,
639
703
  "position": currentPosition
640
704
  ])
641
705
 
642
- if repeatMode == 1 {
643
- player?.seek(to: .zero)
644
- player?.play()
645
- return
646
- }
647
-
648
706
  if nextIndex < queue.count {
649
707
  currentIndex = nextIndex
650
708
  updateNowPlayingInfo()
@@ -655,6 +713,7 @@ public typealias RCTPromiseRejectBlock = (String?, String?, Error?) -> Void
655
713
  "lastPosition": 0.0,
656
714
  ])
657
715
  } else if repeatMode == 2 {
716
+ // ✅ ПОВТОР ВСЕЙ ОЧЕРЕДИ
658
717
  currentIndex = 0
659
718
  rebuildPlayerQueue()
660
719
  player?.play()
@@ -41,6 +41,7 @@ RCT_EXPORT_MODULE(RNGliphPlayer)
41
41
  @"playback-queue-ended",
42
42
  @"playback-progress-updated",
43
43
  @"playback-metadata-received",
44
+ @"playback-repeat-mode-changed",
44
45
  @"remote-play",
45
46
  @"remote-pause",
46
47
  @"remote-stop",
@@ -96,21 +97,34 @@ RCT_EXPORT_METHOD(removeUpcomingTracks:(RCTPromiseResolveBlock)resolve
96
97
 
97
98
  RCT_EXPORT_METHOD(skip:(double)index
98
99
  initialPosition:(double)initialPosition
100
+ autoPlay:(BOOL)autoPlay
99
101
  resolve:(RCTPromiseResolveBlock)resolve
100
102
  reject:(RCTPromiseRejectBlock)reject) {
101
- [_player skipToIndex:(NSInteger)index initialPosition:initialPosition resolve:resolve reject:reject];
103
+ [_player skipToIndex:(NSInteger)index
104
+ initialPosition:initialPosition
105
+ autoPlay:autoPlay
106
+ resolve:resolve
107
+ reject:reject];
102
108
  }
103
109
 
104
110
  RCT_EXPORT_METHOD(skipToNext:(double)initialPosition
111
+ autoPlay:(BOOL)autoPlay
105
112
  resolve:(RCTPromiseResolveBlock)resolve
106
113
  reject:(RCTPromiseRejectBlock)reject) {
107
- [_player skipToNextWithInitialPosition:initialPosition resolve:resolve reject:reject];
114
+ [_player skipToNextWithInitialPosition:initialPosition
115
+ autoPlay:autoPlay
116
+ resolve:resolve
117
+ reject:reject];
108
118
  }
109
119
 
110
120
  RCT_EXPORT_METHOD(skipToPrevious:(double)initialPosition
121
+ autoPlay:(BOOL)autoPlay
111
122
  resolve:(RCTPromiseResolveBlock)resolve
112
123
  reject:(RCTPromiseRejectBlock)reject) {
113
- [_player skipToPreviousWithInitialPosition:initialPosition resolve:resolve reject:reject];
124
+ [_player skipToPreviousWithInitialPosition:initialPosition
125
+ autoPlay:autoPlay
126
+ resolve:resolve
127
+ reject:reject];
114
128
  }
115
129
 
116
130
  RCT_EXPORT_METHOD(move:(double)fromIndex