react-native-nitro-player 0.7.0 → 0.7.1-alpha.1

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.
Files changed (110) hide show
  1. package/README.md +47 -46
  2. package/android/src/main/java/com/margelo/nitro/nitroplayer/HybridAndroidAutoMediaLibrary.kt +9 -13
  3. package/android/src/main/java/com/margelo/nitro/nitroplayer/HybridAudioDevices.kt +45 -90
  4. package/android/src/main/java/com/margelo/nitro/nitroplayer/HybridDownloadManager.kt +48 -182
  5. package/android/src/main/java/com/margelo/nitro/nitroplayer/HybridEqualizer.kt +21 -77
  6. package/android/src/main/java/com/margelo/nitro/nitroplayer/HybridPlayerQueue.kt +55 -104
  7. package/android/src/main/java/com/margelo/nitro/nitroplayer/HybridTrackPlayer.kt +113 -123
  8. package/android/src/main/java/com/margelo/nitro/nitroplayer/core/ExoPlayerCore.kt +82 -0
  9. package/android/src/main/java/com/margelo/nitro/nitroplayer/core/ListenerRegistry.kt +48 -0
  10. package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerAndroidAuto.kt +62 -0
  11. package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerCore.kt +153 -1887
  12. package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerListener.kt +122 -0
  13. package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerNotify.kt +44 -0
  14. package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerPlayback.kt +162 -0
  15. package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerQueue.kt +179 -0
  16. package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerQueueBuild.kt +170 -0
  17. package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerSetup.kt +28 -0
  18. package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerTempQueue.kt +121 -0
  19. package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerUrlLoader.kt +98 -0
  20. package/android/src/main/java/com/margelo/nitro/nitroplayer/download/DownloadDatabase.kt +27 -18
  21. package/android/src/main/java/com/margelo/nitro/nitroplayer/equalizer/EqualizerCore.kt +150 -135
  22. package/android/src/main/java/com/margelo/nitro/nitroplayer/media/MediaSessionManager.kt +13 -30
  23. package/android/src/main/java/com/margelo/nitro/nitroplayer/playlist/PlaylistManager.kt +102 -162
  24. package/ios/HybridDownloadManager.swift +32 -26
  25. package/ios/HybridEqualizer.swift +48 -35
  26. package/ios/HybridTrackPlayer.swift +127 -102
  27. package/ios/core/ListenerRegistry.swift +60 -0
  28. package/ios/core/TrackPlayerCore.swift +130 -2356
  29. package/ios/core/TrackPlayerListener.swift +395 -0
  30. package/ios/core/TrackPlayerNotify.swift +52 -0
  31. package/ios/core/TrackPlayerPlayback.swift +274 -0
  32. package/ios/core/TrackPlayerQueue.swift +221 -0
  33. package/ios/core/TrackPlayerQueueBuild.swift +493 -0
  34. package/ios/core/TrackPlayerTempQueue.swift +167 -0
  35. package/ios/core/TrackPlayerUrlLoader.swift +169 -0
  36. package/ios/equalizer/EqualizerCore.swift +63 -123
  37. package/ios/media/MediaSessionManager.swift +32 -49
  38. package/ios/playlist/PlaylistManager.swift +2 -9
  39. package/ios/queue/HybridPlayerQueue.swift +69 -66
  40. package/lib/hooks/useDownloadedTracks.js +16 -13
  41. package/lib/hooks/useEqualizer.d.ts +4 -4
  42. package/lib/hooks/useEqualizer.js +22 -17
  43. package/lib/hooks/useEqualizerPresets.d.ts +3 -3
  44. package/lib/hooks/useEqualizerPresets.js +12 -18
  45. package/lib/specs/AndroidAutoMediaLibrary.nitro.d.ts +2 -2
  46. package/lib/specs/AudioDevices.nitro.d.ts +2 -2
  47. package/lib/specs/DownloadManager.nitro.d.ts +10 -10
  48. package/lib/specs/Equalizer.nitro.d.ts +10 -10
  49. package/lib/specs/TrackPlayer.nitro.d.ts +38 -16
  50. package/lib/types/EqualizerTypes.d.ts +3 -3
  51. package/nitrogen/generated/android/NitroPlayerOnLoad.cpp +2 -0
  52. package/nitrogen/generated/android/c++/JFunc_void_std__vector_TrackItem__std__vector_TrackItem_.hpp +122 -0
  53. package/nitrogen/generated/android/c++/JHybridAndroidAutoMediaLibrarySpec.cpp +31 -6
  54. package/nitrogen/generated/android/c++/JHybridAndroidAutoMediaLibrarySpec.hpp +2 -2
  55. package/nitrogen/generated/android/c++/JHybridAudioDevicesSpec.cpp +16 -3
  56. package/nitrogen/generated/android/c++/JHybridAudioDevicesSpec.hpp +1 -1
  57. package/nitrogen/generated/android/c++/JHybridDownloadManagerSpec.cpp +154 -44
  58. package/nitrogen/generated/android/c++/JHybridDownloadManagerSpec.hpp +10 -10
  59. package/nitrogen/generated/android/c++/JHybridEqualizerSpec.cpp +130 -34
  60. package/nitrogen/generated/android/c++/JHybridEqualizerSpec.hpp +9 -9
  61. package/nitrogen/generated/android/c++/JHybridPlayerQueueSpec.cpp +115 -24
  62. package/nitrogen/generated/android/c++/JHybridPlayerQueueSpec.hpp +8 -8
  63. package/nitrogen/generated/android/c++/JHybridTrackPlayerSpec.cpp +243 -24
  64. package/nitrogen/generated/android/c++/JHybridTrackPlayerSpec.hpp +16 -8
  65. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/Func_void_std__vector_TrackItem__std__vector_TrackItem_.kt +80 -0
  66. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/HybridAndroidAutoMediaLibrarySpec.kt +3 -2
  67. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/HybridAudioDevicesSpec.kt +2 -1
  68. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/HybridDownloadManagerSpec.kt +10 -10
  69. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/HybridEqualizerSpec.kt +10 -9
  70. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/HybridPlayerQueueSpec.kt +9 -8
  71. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/HybridTrackPlayerSpec.kt +45 -8
  72. package/nitrogen/generated/ios/NitroPlayer-Swift-Cxx-Bridge.cpp +74 -18
  73. package/nitrogen/generated/ios/NitroPlayer-Swift-Cxx-Bridge.hpp +380 -151
  74. package/nitrogen/generated/ios/c++/HybridDownloadManagerSpecSwift.hpp +10 -10
  75. package/nitrogen/generated/ios/c++/HybridEqualizerSpecSwift.hpp +12 -9
  76. package/nitrogen/generated/ios/c++/HybridPlayerQueueSpecSwift.hpp +23 -8
  77. package/nitrogen/generated/ios/c++/HybridTrackPlayerSpecSwift.hpp +82 -8
  78. package/nitrogen/generated/ios/swift/Func_void_EqualizerState.swift +46 -0
  79. package/nitrogen/generated/ios/swift/Func_void_std__variant_nitro__NullType__DownloadedPlaylist_.swift +58 -0
  80. package/nitrogen/generated/ios/swift/Func_void_std__variant_nitro__NullType__DownloadedTrack_.swift +58 -0
  81. package/nitrogen/generated/ios/swift/Func_void_std__variant_nitro__NullType__std__string_.swift +58 -0
  82. package/nitrogen/generated/ios/swift/Func_void_std__vector_DownloadedPlaylist_.swift +46 -0
  83. package/nitrogen/generated/ios/swift/Func_void_std__vector_DownloadedTrack_.swift +46 -0
  84. package/nitrogen/generated/ios/swift/Func_void_std__vector_EqualizerBand_.swift +5 -5
  85. package/nitrogen/generated/ios/swift/Func_void_std__vector_TrackItem__std__vector_TrackItem_.swift +46 -0
  86. package/nitrogen/generated/ios/swift/HybridDownloadManagerSpec.swift +10 -10
  87. package/nitrogen/generated/ios/swift/HybridDownloadManagerSpec_cxx.swift +141 -71
  88. package/nitrogen/generated/ios/swift/HybridEqualizerSpec.swift +9 -9
  89. package/nitrogen/generated/ios/swift/HybridEqualizerSpec_cxx.swift +105 -41
  90. package/nitrogen/generated/ios/swift/HybridPlayerQueueSpec.swift +8 -8
  91. package/nitrogen/generated/ios/swift/HybridPlayerQueueSpec_cxx.swift +95 -32
  92. package/nitrogen/generated/ios/swift/HybridTrackPlayerSpec.swift +16 -8
  93. package/nitrogen/generated/ios/swift/HybridTrackPlayerSpec_cxx.swift +267 -32
  94. package/nitrogen/generated/shared/c++/HybridAndroidAutoMediaLibrarySpec.hpp +3 -2
  95. package/nitrogen/generated/shared/c++/HybridAudioDevicesSpec.hpp +2 -1
  96. package/nitrogen/generated/shared/c++/HybridDownloadManagerSpec.hpp +10 -10
  97. package/nitrogen/generated/shared/c++/HybridEqualizerSpec.hpp +10 -9
  98. package/nitrogen/generated/shared/c++/HybridPlayerQueueSpec.hpp +9 -8
  99. package/nitrogen/generated/shared/c++/HybridTrackPlayerSpec.cpp +8 -0
  100. package/nitrogen/generated/shared/c++/HybridTrackPlayerSpec.hpp +16 -8
  101. package/package.json +5 -5
  102. package/src/hooks/useDownloadedTracks.ts +17 -13
  103. package/src/hooks/useEqualizer.ts +26 -21
  104. package/src/hooks/useEqualizerPresets.ts +15 -21
  105. package/src/specs/AndroidAutoMediaLibrary.nitro.ts +2 -2
  106. package/src/specs/AudioDevices.nitro.ts +2 -2
  107. package/src/specs/DownloadManager.nitro.ts +10 -10
  108. package/src/specs/Equalizer.nitro.ts +10 -10
  109. package/src/specs/TrackPlayer.nitro.ts +52 -16
  110. package/src/types/EqualizerTypes.ts +17 -13
@@ -4,6 +4,7 @@ import androidx.annotation.Keep
4
4
  import com.facebook.proguard.annotations.DoNotStrip
5
5
  import com.margelo.nitro.NitroModules
6
6
  import com.margelo.nitro.core.NullType
7
+ import com.margelo.nitro.core.Promise
7
8
  import com.margelo.nitro.nitroplayer.equalizer.EqualizerCore
8
9
 
9
10
  @DoNotStrip
@@ -12,94 +13,37 @@ class HybridEqualizer : HybridEqualizerSpec() {
12
13
  private val core: EqualizerCore
13
14
 
14
15
  init {
15
- val context =
16
- NitroModules.applicationContext ?: throw IllegalStateException("React Context is not initialized")
17
-
18
- // Get the equalizer core - it will initialize lazily with audio session 0
19
- // and be re-initialized with the proper session when onAudioSessionIdChanged fires
16
+ val context = NitroModules.applicationContext
17
+ ?: throw IllegalStateException("React Context is not initialized")
20
18
  core = EqualizerCore.getInstance(context)
21
19
  core.ensureInitialized()
22
20
  }
23
21
 
24
- @DoNotStrip
25
- @Keep
26
- override fun setEnabled(enabled: Boolean): Boolean = core.setEnabled(enabled)
27
-
28
- @DoNotStrip
29
- @Keep
22
+ // ── Sync reads ────────────────────────────────────────────────────────────
30
23
  override fun isEnabled(): Boolean = core.isEnabled()
31
-
32
- @DoNotStrip
33
- @Keep
34
- override fun getBands(): Array<EqualizerBand> = core.getBands()
35
-
36
- @DoNotStrip
37
- @Keep
38
- override fun setBandGain(
39
- bandIndex: Double,
40
- gainDb: Double,
41
- ): Boolean = core.setBandGain(bandIndex.toInt(), gainDb)
42
-
43
- @DoNotStrip
44
- @Keep
45
- override fun setAllBandGains(gains: DoubleArray): Boolean = core.setAllBandGains(gains)
46
-
47
- @DoNotStrip
48
- @Keep
49
24
  override fun getBandRange(): GainRange = core.getBandRange()
50
-
51
- @DoNotStrip
52
- @Keep
53
25
  override fun getPresets(): Array<EqualizerPreset> = core.getPresets()
54
-
55
- @DoNotStrip
56
- @Keep
57
26
  override fun getBuiltInPresets(): Array<EqualizerPreset> = core.getBuiltInPresets()
58
-
59
- @DoNotStrip
60
- @Keep
61
27
  override fun getCustomPresets(): Array<EqualizerPreset> = core.getCustomPresets()
62
-
63
- @DoNotStrip
64
- @Keep
65
- override fun applyPreset(presetName: String): Boolean = core.applyPreset(presetName)
66
-
67
- @DoNotStrip
68
- @Keep
69
28
  override fun getCurrentPresetName(): Variant_NullType_String {
70
29
  val name = core.getCurrentPresetName()
71
- return if (name != null) {
72
- Variant_NullType_String.create(name)
73
- } else {
74
- Variant_NullType_String.create(NullType.NULL)
75
- }
76
- }
77
-
78
- @DoNotStrip
79
- @Keep
80
- override fun saveCustomPreset(name: String): Boolean = core.saveCustomPreset(name)
81
-
82
- @DoNotStrip
83
- @Keep
84
- override fun deleteCustomPreset(name: String): Boolean = core.deleteCustomPreset(name)
85
-
86
- @DoNotStrip
87
- @Keep
88
- override fun getState(): EqualizerState = core.getState()
89
-
90
- @DoNotStrip
91
- @Keep
92
- override fun reset() = core.reset()
93
-
94
- override fun onEnabledChange(callback: (enabled: Boolean) -> Unit) {
95
- core.addOnEnabledChangeListener(callback)
30
+ return if (name != null) Variant_NullType_String.create(name)
31
+ else Variant_NullType_String.create(NullType.NULL)
96
32
  }
97
33
 
98
- override fun onBandChange(callback: (bands: Array<EqualizerBand>) -> Unit) {
99
- core.addOnBandChangeListener(callback)
100
- }
101
-
102
- override fun onPresetChange(callback: (presetName: Variant_NullType_String?) -> Unit) {
103
- core.addOnPresetChangeListener(callback)
104
- }
34
+ // ── Async mutations (per v2 spec) ─────────────────────────────────────────
35
+ override fun setEnabled(enabled: Boolean): Promise<Unit> = Promise.async { core.setEnabled(enabled) }
36
+ override fun getBands(): Promise<Array<EqualizerBand>> = Promise.async { core.getBands() }
37
+ override fun setBandGain(bandIndex: Double, gainDb: Double): Promise<Unit> = Promise.async { core.setBandGain(bandIndex.toInt(), gainDb) }
38
+ override fun setAllBandGains(gains: DoubleArray): Promise<Unit> = Promise.async { core.setAllBandGains(gains) }
39
+ override fun applyPreset(presetName: String): Promise<Unit> = Promise.async { core.applyPreset(presetName) }
40
+ override fun saveCustomPreset(name: String): Promise<Unit> = Promise.async { core.saveCustomPreset(name) }
41
+ override fun deleteCustomPreset(name: String): Promise<Unit> = Promise.async { core.deleteCustomPreset(name) }
42
+ override fun getState(): Promise<EqualizerState> = Promise.async { core.getState() }
43
+ override fun reset(): Promise<Unit> = Promise.async { core.reset() }
44
+
45
+ // ── Events ────────────────────────────────────────────────────────────────
46
+ override fun onEnabledChange(callback: (enabled: Boolean) -> Unit) = core.addOnEnabledChangeListener(callback)
47
+ override fun onBandChange(callback: (bands: Array<EqualizerBand>) -> Unit) = core.addOnBandChangeListener(callback)
48
+ override fun onPresetChange(callback: (presetName: Variant_NullType_String?) -> Unit) = core.addOnPresetChangeListener(callback)
105
49
  }
@@ -1,11 +1,15 @@
1
+ @file:Suppress("ktlint:standard:max-line-length")
2
+
1
3
  package com.margelo.nitro.nitroplayer
2
4
 
3
5
  import androidx.annotation.Keep
4
- import com.facebook.jni.HybridData
5
6
  import com.facebook.proguard.annotations.DoNotStrip
6
7
  import com.margelo.nitro.NitroModules
7
8
  import com.margelo.nitro.core.NullType
9
+ import com.margelo.nitro.core.Promise
8
10
  import com.margelo.nitro.nitroplayer.core.TrackPlayerCore
11
+ import com.margelo.nitro.nitroplayer.core.loadPlaylist
12
+ import com.margelo.nitro.nitroplayer.core.updatePlaylist
9
13
  import com.margelo.nitro.nitroplayer.playlist.PlaylistManager
10
14
  import java.util.UUID
11
15
  import com.margelo.nitro.nitroplayer.playlist.Playlist as InternalPlaylist
@@ -17,7 +21,8 @@ class HybridPlayerQueue : HybridPlayerQueueSpec() {
17
21
  private val playlistManager: PlaylistManager
18
22
 
19
23
  init {
20
- val context = NitroModules.applicationContext ?: throw IllegalStateException("React Context is not initialized")
24
+ val context = NitroModules.applicationContext
25
+ ?: throw IllegalStateException("React Context is not initialized")
21
26
  core = TrackPlayerCore.getInstance(context)
22
27
  playlistManager = core.getPlaylistManager()
23
28
  }
@@ -25,143 +30,89 @@ class HybridPlayerQueue : HybridPlayerQueueSpec() {
25
30
  private val playlistsChangeListeners = java.util.concurrent.CopyOnWriteArrayList<() -> Unit>()
26
31
  private val playlistChangeListeners = java.util.concurrent.ConcurrentHashMap<String, () -> Unit>()
27
32
 
28
- @DoNotStrip
29
- @Keep
30
- override fun createPlaylist(
31
- name: String,
32
- description: String?,
33
- artwork: String?,
34
- ): String = playlistManager.createPlaylist(name, description, artwork)
35
-
36
- @DoNotStrip
37
- @Keep
38
- override fun deletePlaylist(playlistId: String) {
33
+ // ── Playlist CRUD ─────────────────────────────────────────────────────────
34
+
35
+ override fun createPlaylist(name: String, description: String?, artwork: String?): Promise<String> =
36
+ Promise.async { playlistManager.createPlaylist(name, description, artwork) }
37
+
38
+ override fun deletePlaylist(playlistId: String): Promise<Unit> = Promise.async {
39
39
  playlistManager.deletePlaylist(playlistId)
40
40
  }
41
41
 
42
- @DoNotStrip
43
- @Keep
44
- override fun updatePlaylist(
45
- playlistId: String,
46
- name: String?,
47
- description: String?,
48
- artwork: String?,
49
- ) {
42
+ override fun updatePlaylist(playlistId: String, name: String?, description: String?, artwork: String?): Promise<Unit> = Promise.async {
50
43
  playlistManager.updatePlaylist(playlistId, name, description, artwork)
44
+ core.updatePlaylist(playlistId)
51
45
  }
52
46
 
53
- @DoNotStrip
54
- @Keep
55
47
  override fun getPlaylist(playlistId: String): Variant_NullType_Playlist {
56
48
  val playlist = playlistManager.getPlaylist(playlistId)
57
- return if (playlist != null) {
58
- Variant_NullType_Playlist.create(playlist.toPlaylist())
59
- } else {
60
- Variant_NullType_Playlist.create(NullType.NULL)
61
- }
49
+ return if (playlist != null) Variant_NullType_Playlist.create(playlist.toPlaylist())
50
+ else Variant_NullType_Playlist.create(NullType.NULL)
62
51
  }
63
52
 
64
- @DoNotStrip
65
- @Keep
66
53
  override fun getAllPlaylists(): Array<Playlist> =
67
- playlistManager
68
- .getAllPlaylists()
69
- .map {
70
- it.toPlaylist()
71
- }.toTypedArray()
72
-
73
- @DoNotStrip
74
- @Keep
75
- override fun addTrackToPlaylist(
76
- playlistId: String,
77
- track: TrackItem,
78
- index: Double?,
79
- ) {
80
- val insertIndex = index?.toInt()
81
- playlistManager.addTrackToPlaylist(playlistId, track, insertIndex)
54
+ playlistManager.getAllPlaylists().map { it.toPlaylist() }.toTypedArray()
55
+
56
+ // ── Track mutations ───────────────────────────────────────────────────────
57
+
58
+ override fun addTrackToPlaylist(playlistId: String, track: TrackItem, index: Double?): Promise<Unit> = Promise.async {
59
+ playlistManager.addTrackToPlaylist(playlistId, track, index?.toInt())
60
+ core.updatePlaylist(playlistId)
82
61
  }
83
62
 
84
- @DoNotStrip
85
- @Keep
86
- override fun addTracksToPlaylist(
87
- playlistId: String,
88
- tracks: Array<TrackItem>,
89
- index: Double?,
90
- ) {
91
- val insertIndex = index?.toInt()
92
- playlistManager.addTracksToPlaylist(playlistId, tracks.toList(), insertIndex)
63
+ override fun addTracksToPlaylist(playlistId: String, tracks: Array<TrackItem>, index: Double?): Promise<Unit> = Promise.async {
64
+ playlistManager.addTracksToPlaylist(playlistId, tracks.toList(), index?.toInt())
65
+ core.updatePlaylist(playlistId)
93
66
  }
94
67
 
95
- @DoNotStrip
96
- @Keep
97
- override fun removeTrackFromPlaylist(
98
- playlistId: String,
99
- trackId: String,
100
- ) {
68
+ override fun removeTrackFromPlaylist(playlistId: String, trackId: String): Promise<Unit> = Promise.async {
101
69
  playlistManager.removeTrackFromPlaylist(playlistId, trackId)
70
+ core.updatePlaylist(playlistId)
102
71
  }
103
72
 
104
- @DoNotStrip
105
- @Keep
106
- override fun reorderTrackInPlaylist(
107
- playlistId: String,
108
- trackId: String,
109
- newIndex: Double,
110
- ) {
73
+ override fun reorderTrackInPlaylist(playlistId: String, trackId: String, newIndex: Double): Promise<Unit> = Promise.async {
111
74
  playlistManager.reorderTrackInPlaylist(playlistId, trackId, newIndex.toInt())
75
+ core.updatePlaylist(playlistId)
112
76
  }
113
77
 
114
- @DoNotStrip
115
- @Keep
116
- override fun loadPlaylist(playlistId: String) {
117
- playlistManager.loadPlaylist(playlistId)
78
+ // ── Playback control ──────────────────────────────────────────────────────
79
+
80
+ override fun loadPlaylist(playlistId: String): Promise<Unit> = Promise.async {
81
+ core.loadPlaylist(playlistId)
118
82
  }
119
83
 
120
- @DoNotStrip
121
- @Keep
122
84
  override fun getCurrentPlaylistId(): Variant_NullType_String {
123
- val playlistId = playlistManager.getCurrentPlaylistId()
124
- return if (playlistId != null) {
125
- Variant_NullType_String.create(playlistId)
126
- } else {
127
- Variant_NullType_String.create(NullType.NULL)
128
- }
85
+ val id = core.getCurrentPlaylistId()
86
+ return if (id != null) Variant_NullType_String.create(id)
87
+ else Variant_NullType_String.create(NullType.NULL)
129
88
  }
130
89
 
131
- @DoNotStrip
132
- @Keep
90
+ // ── Events ────────────────────────────────────────────────────────────────
91
+
133
92
  override fun onPlaylistsChanged(callback: (playlists: Array<Playlist>, operation: QueueOperation?) -> Unit) {
134
- // Add new listener and store the cleanup function
135
- val removeListener =
136
- playlistManager.addPlaylistsChangeListener { playlists, operation ->
137
- callback(playlists.map { it.toPlaylist() }.toTypedArray(), operation)
138
- }
93
+ val removeListener = playlistManager.addPlaylistsChangeListener { playlists, operation ->
94
+ callback(playlists.map { it.toPlaylist() }.toTypedArray(), operation)
95
+ }
139
96
  playlistsChangeListeners.add(removeListener)
140
97
  }
141
98
 
142
- @DoNotStrip
143
- @Keep
144
99
  override fun onPlaylistChanged(callback: (playlistId: String, playlist: Playlist, operation: QueueOperation?) -> Unit) {
145
- // Listen to all playlists and filter by playlistId
146
100
  val listenerId = UUID.randomUUID().toString()
147
-
148
- // For each playlist, add a listener
149
101
  playlistManager.getAllPlaylists().forEach { internalPlaylist ->
150
- val removeListener =
151
- playlistManager.addPlaylistChangeListener(internalPlaylist.id) { playlist, operation ->
152
- callback(playlist.id, playlist.toPlaylist(), operation)
153
- }
102
+ val removeListener = playlistManager.addPlaylistChangeListener(internalPlaylist.id) { playlist, operation ->
103
+ callback(playlist.id, playlist.toPlaylist(), operation)
104
+ }
154
105
  playlistChangeListeners[listenerId] = removeListener
155
106
  }
156
107
  }
157
108
 
158
- // Helper to convert internal Playlist to generated Playlist type
159
- private fun InternalPlaylist.toPlaylist(): Playlist =
160
- Playlist(
161
- id = this.id,
162
- name = this.name,
163
- description = this.description?.let { Variant_NullType_String.create(it) },
164
- artwork = this.artwork?.let { Variant_NullType_String.create(it) },
165
- tracks = this.tracks.toTypedArray(),
166
- )
109
+ // ── Helper ────────────────────────────────────────────────────────────────
110
+
111
+ private fun InternalPlaylist.toPlaylist(): Playlist = Playlist(
112
+ id = this.id,
113
+ name = this.name,
114
+ description = this.description?.let { Variant_NullType_String.create(it) },
115
+ artwork = this.artwork?.let { Variant_NullType_String.create(it) },
116
+ tracks = this.tracks.toTypedArray(),
117
+ )
167
118
  }
@@ -1,3 +1,5 @@
1
+ @file:Suppress("ktlint:standard:max-line-length")
2
+
1
3
  package com.margelo.nitro.nitroplayer
2
4
 
3
5
  import androidx.annotation.Keep
@@ -5,169 +7,157 @@ import com.facebook.proguard.annotations.DoNotStrip
5
7
  import com.margelo.nitro.NitroModules
6
8
  import com.margelo.nitro.core.Promise
7
9
  import com.margelo.nitro.nitroplayer.core.TrackPlayerCore
10
+ import com.margelo.nitro.nitroplayer.core.addToUpNext
11
+ import com.margelo.nitro.nitroplayer.core.clearPlayNext
12
+ import com.margelo.nitro.nitroplayer.core.clearUpNext
13
+ import com.margelo.nitro.nitroplayer.core.configure
14
+ import com.margelo.nitro.nitroplayer.core.getActualQueue
15
+ import com.margelo.nitro.nitroplayer.core.getCurrentTrackIndex
16
+ import com.margelo.nitro.nitroplayer.core.getNextTracks
17
+ import com.margelo.nitro.nitroplayer.core.getPlayBackSpeed
18
+ import com.margelo.nitro.nitroplayer.core.getPlayNextQueue
19
+ import com.margelo.nitro.nitroplayer.core.getRepeatMode
20
+ import com.margelo.nitro.nitroplayer.core.getState
21
+ import com.margelo.nitro.nitroplayer.core.getTracksById
22
+ import com.margelo.nitro.nitroplayer.core.getTracksNeedingUrls
23
+ import com.margelo.nitro.nitroplayer.core.getUpNextQueue
24
+ import com.margelo.nitro.nitroplayer.core.pause
25
+ import com.margelo.nitro.nitroplayer.core.play
26
+ import com.margelo.nitro.nitroplayer.core.playNext
27
+ import com.margelo.nitro.nitroplayer.core.playSong
28
+ import com.margelo.nitro.nitroplayer.core.removeFromPlayNext
29
+ import com.margelo.nitro.nitroplayer.core.removeFromUpNext
30
+ import com.margelo.nitro.nitroplayer.core.reorderTemporaryTrack
31
+ import com.margelo.nitro.nitroplayer.core.seek
32
+ import com.margelo.nitro.nitroplayer.core.setPlayBackSpeed
33
+ import com.margelo.nitro.nitroplayer.core.setRepeatMode
34
+ import com.margelo.nitro.nitroplayer.core.setVolume
35
+ import com.margelo.nitro.nitroplayer.core.skipToIndex
36
+ import com.margelo.nitro.nitroplayer.core.skipToNext
37
+ import com.margelo.nitro.nitroplayer.core.skipToPrevious
38
+ import com.margelo.nitro.nitroplayer.core.updateTracks
8
39
 
9
40
  @DoNotStrip
10
41
  @Keep
11
42
  class HybridTrackPlayer : HybridTrackPlayerSpec() {
12
43
  private val core: TrackPlayerCore
13
44
 
45
+ // Track listener IDs for cleanup in dispose()
46
+ private val listenerIds = mutableListOf<Pair<String, Long>>()
47
+
14
48
  init {
15
- val context =
16
- NitroModules.applicationContext ?: throw IllegalStateException("React Context is not initialized")
49
+ val context = NitroModules.applicationContext
50
+ ?: throw IllegalStateException("React Context is not initialized")
17
51
  core = TrackPlayerCore.getInstance(context)
18
52
  }
19
53
 
20
- @DoNotStrip
21
- @Keep
22
- override fun play() {
23
- core.play()
24
- }
54
+ // ── Playback ─────────────────────────────────────────────────────────────
25
55
 
26
- @DoNotStrip
27
- @Keep
28
- override fun pause() {
29
- core.pause()
30
- }
56
+ override fun play(): Promise<Unit> = Promise.async { core.play() }
57
+ override fun pause(): Promise<Unit> = Promise.async { core.pause() }
58
+ override fun seek(position: Double): Promise<Unit> = Promise.async { core.seek(position) }
59
+ override fun skipToNext(): Promise<Unit> = Promise.async { core.skipToNext() }
60
+ override fun skipToPrevious(): Promise<Unit> = Promise.async { core.skipToPrevious() }
61
+ override fun playSong(songId: String, fromPlaylist: String?): Promise<Unit> = Promise.async { core.playSong(songId, fromPlaylist) }
62
+ override fun skipToIndex(index: Double): Promise<Boolean> = Promise.async { core.skipToIndex(index.toInt()) }
31
63
 
32
- override fun playSong(
33
- songId: String,
34
- fromPlaylist: String?,
35
- ): Promise<Unit> =
36
- Promise.async {
37
- core.playSong(songId, fromPlaylist)
38
- }
64
+ override fun setRepeatMode(mode: RepeatMode): Promise<Unit> = Promise.async { core.setRepeatMode(mode) }
65
+ override fun getRepeatMode(): RepeatMode = core.getRepeatMode()
39
66
 
40
- @DoNotStrip
41
- @Keep
42
- override fun skipToNext() {
43
- core.skipToNext()
44
- }
67
+ override fun setVolume(volume: Double): Promise<Unit> = Promise.async { core.setVolume(volume) }
45
68
 
46
- @DoNotStrip
47
- @Keep
48
- override fun skipToPrevious() {
49
- core.skipToPrevious()
50
- }
69
+ override fun configure(config: PlayerConfig): Promise<Unit> = Promise.async { core.configure(config) }
51
70
 
52
- @DoNotStrip
53
- @Keep
54
- override fun seek(position: Double) {
55
- core.seek(position)
56
- }
71
+ // ── Queue / state reads ───────────────────────────────────────────────────
57
72
 
58
- override fun addToUpNext(trackId: String): Promise<Unit> =
59
- Promise.async {
60
- core.addToUpNext(trackId)
61
- }
73
+ override fun getActualQueue(): Promise<Array<TrackItem>> = Promise.async { core.getActualQueue().toTypedArray() }
74
+ override fun getState(): Promise<PlayerState> = Promise.async { core.getState() }
75
+ override fun getTracksById(trackIds: Array<String>): Promise<Array<TrackItem>> = Promise.async { core.getTracksById(trackIds.toList()).toTypedArray() }
76
+ override fun getTracksNeedingUrls(): Promise<Array<TrackItem>> = Promise.async { core.getTracksNeedingUrls().toTypedArray() }
77
+ override fun getNextTracks(count: Double): Promise<Array<TrackItem>> = Promise.async { core.getNextTracks(count.toInt()).toTypedArray() }
78
+ override fun getCurrentTrackIndex(): Promise<Double> = Promise.async { core.getCurrentTrackIndex().toDouble() }
62
79
 
63
- override fun playNext(trackId: String): Promise<Unit> =
64
- Promise.async {
65
- core.playNext(trackId)
66
- }
80
+ // ── URL updates ───────────────────────────────────────────────────────────
67
81
 
68
- override fun getActualQueue(): Promise<Array<TrackItem>> =
69
- Promise.async {
70
- core.getActualQueue().toTypedArray()
71
- }
82
+ override fun updateTracks(tracks: Array<TrackItem>): Promise<Unit> = Promise.async { core.updateTracks(tracks.toList()) }
72
83
 
73
- override fun getState(): Promise<PlayerState> =
74
- Promise.async {
75
- core.getState()
76
- }
84
+ // ── Temporary queue ───────────────────────────────────────────────────────
77
85
 
78
- @DoNotStrip
79
- @Keep
80
- override fun setRepeatMode(mode: RepeatMode): Boolean = core.setRepeatMode(mode)
86
+ override fun addToUpNext(trackId: String): Promise<Unit> = Promise.async { core.addToUpNext(trackId) }
87
+ override fun playNext(trackId: String): Promise<Unit> = Promise.async { core.playNext(trackId) }
88
+ override fun removeFromPlayNext(trackId: String): Promise<Boolean> = Promise.async { core.removeFromPlayNext(trackId) }
89
+ override fun removeFromUpNext(trackId: String): Promise<Boolean> = Promise.async { core.removeFromUpNext(trackId) }
90
+ override fun clearPlayNext(): Promise<Unit> = Promise.async { core.clearPlayNext() }
91
+ override fun clearUpNext(): Promise<Unit> = Promise.async { core.clearUpNext() }
92
+ override fun reorderTemporaryTrack(trackId: String, newIndex: Double): Promise<Boolean> = Promise.async { core.reorderTemporaryTrack(trackId, newIndex.toInt()) }
93
+ override fun getPlayNextQueue(): Promise<Array<TrackItem>> = Promise.async { core.getPlayNextQueue().toTypedArray() }
94
+ override fun getUpNextQueue(): Promise<Array<TrackItem>> = Promise.async { core.getUpNextQueue().toTypedArray() }
81
95
 
82
- @DoNotStrip
83
- @Keep
84
- override fun getRepeatMode(): RepeatMode = core.getRepeatMode()
96
+ // ── Playback speed ────────────────────────────────────────────────────────
97
+
98
+ override fun setPlaybackSpeed(speed: Double): Promise<Unit> = Promise.async { core.setPlayBackSpeed(speed) }
99
+ override fun getPlaybackSpeed(): Promise<Double> = Promise.async { core.getPlayBackSpeed() }
100
+
101
+ // ── Android Auto ──────────────────────────────────────────────────────────
102
+
103
+ override fun isAndroidAutoConnected(): Boolean = core.isAndroidAutoConnected()
104
+
105
+ // ── Event listeners ───────────────────────────────────────────────────────
85
106
 
86
107
  override fun onChangeTrack(callback: (track: TrackItem, reason: Reason?) -> Unit) {
87
- core.addOnChangeTrackListener(callback)
108
+ val id = core.addOnChangeTrackListener(callback)
109
+ listenerIds += "onChangeTrack" to id
88
110
  }
89
111
 
90
112
  override fun onPlaybackStateChange(callback: (state: TrackPlayerState, reason: Reason?) -> Unit) {
91
- core.addOnPlaybackStateChangeListener(callback)
113
+ val id = core.addOnPlaybackStateChangeListener(callback)
114
+ listenerIds += "onPlaybackStateChange" to id
92
115
  }
93
116
 
94
117
  override fun onSeek(callback: (position: Double, totalDuration: Double) -> Unit) {
95
- core.addOnSeekListener(callback)
118
+ val id = core.addOnSeekListener(callback)
119
+ listenerIds += "onSeek" to id
96
120
  }
97
121
 
98
122
  override fun onPlaybackProgressChange(callback: (position: Double, totalDuration: Double, isManuallySeeked: Boolean?) -> Unit) {
99
- core.addOnPlaybackProgressChangeListener(callback)
100
- }
101
-
102
- @DoNotStrip
103
- @Keep
104
- override fun configure(config: PlayerConfig) {
105
- core.configure(
106
- androidAutoEnabled = config.androidAutoEnabled,
107
- carPlayEnabled = config.carPlayEnabled,
108
- showInNotification = config.showInNotification,
109
- lookaheadCount = config.lookaheadCount?.toInt(),
110
- )
123
+ val id = core.addOnPlaybackProgressChangeListener(callback)
124
+ listenerIds += "onPlaybackProgressChange" to id
111
125
  }
112
126
 
113
- @Keep
114
- override fun onAndroidAutoConnectionChange(callback: (Boolean) -> Unit) {
115
- core.onAndroidAutoConnectionChange = callback
127
+ override fun onAndroidAutoConnectionChange(callback: (connected: Boolean) -> Unit) {
128
+ val id = core.addOnAndroidAutoConnectionListener(callback)
129
+ listenerIds += "onAndroidAutoConnectionChange" to id
116
130
  }
117
131
 
118
- @Keep
119
- override fun isAndroidAutoConnected(): Boolean = core.isAndroidAutoConnected()
120
-
121
- @DoNotStrip
122
- @Keep
123
- override fun setVolume(volume: Double): Boolean = core.setVolume(volume)
124
-
125
- @DoNotStrip
126
- @Keep
127
- override fun skipToIndex(index: Double): Promise<Boolean> =
128
- Promise.async {
129
- core.skipToIndex(index.toInt())
130
- }
131
-
132
- override fun updateTracks(tracks: Array<TrackItem>): Promise<Unit> =
133
- Promise.async {
134
- core.updateTracks(tracks.toList())
135
- }
136
-
137
- override fun getTracksById(trackIds: Array<String>): Promise<Array<TrackItem>> =
138
- Promise.async {
139
- core.getTracksById(trackIds.toList()).toTypedArray()
140
- }
141
-
142
- override fun getTracksNeedingUrls(): Promise<Array<TrackItem>> =
143
- Promise.async {
144
- core.getTracksNeedingUrls().toTypedArray()
145
- }
146
-
147
- override fun getNextTracks(count: Double): Promise<Array<TrackItem>> =
148
- Promise.async {
149
- core.getNextTracks(count.toInt()).toTypedArray()
150
- }
151
-
152
- override fun getCurrentTrackIndex(): Promise<Double> =
153
- Promise.async {
154
- core.getCurrentTrackIndex().toDouble()
155
- }
156
-
157
- override fun setPlaybackSpeed(speed: Double): Promise<Unit> =
158
- Promise.async {
159
- core.setPlayBackSpeed(speed)
160
- Unit
132
+ override fun onTracksNeedUpdate(callback: (tracks: Array<TrackItem>, lookahead: Double) -> Unit) {
133
+ val id = core.addOnTracksNeedUpdateListener { tracks, lookahead ->
134
+ callback(tracks.toTypedArray(), lookahead.toDouble())
161
135
  }
136
+ listenerIds += "onTracksNeedUpdate" to id
137
+ }
162
138
 
163
- override fun getPlaybackSpeed(): Promise<Double> =
164
- Promise.async {
165
- core.getPlayBackSpeed()
139
+ override fun onTemporaryQueueChange(callback: (playNextQueue: Array<TrackItem>, upNextQueue: Array<TrackItem>) -> Unit) {
140
+ val id = core.addOnTemporaryQueueChangeListener { pn, un ->
141
+ callback(pn.toTypedArray(), un.toTypedArray())
166
142
  }
143
+ listenerIds += "onTemporaryQueueChange" to id
144
+ }
167
145
 
168
- override fun onTracksNeedUpdate(callback: (tracks: Array<TrackItem>, lookahead: Double) -> Unit) {
169
- core.addOnTracksNeedUpdateListener { tracks, lookahead ->
170
- callback(tracks.toTypedArray(), lookahead.toDouble())
146
+ // ── Cleanup ───────────────────────────────────────────────────────────────
147
+
148
+ override fun dispose() {
149
+ super.dispose()
150
+ listenerIds.forEach { (type, id) ->
151
+ when (type) {
152
+ "onChangeTrack" -> core.removeOnChangeTrackListener(id)
153
+ "onPlaybackStateChange" -> core.removeOnPlaybackStateChangeListener(id)
154
+ "onSeek" -> core.removeOnSeekListener(id)
155
+ "onPlaybackProgressChange" -> core.removeOnPlaybackProgressChangeListener(id)
156
+ "onAndroidAutoConnectionChange" -> core.removeOnAndroidAutoConnectionListener(id)
157
+ "onTracksNeedUpdate" -> core.removeOnTracksNeedUpdateListener(id)
158
+ "onTemporaryQueueChange" -> core.removeOnTemporaryQueueChangeListener(id)
159
+ }
171
160
  }
161
+ listenerIds.clear()
172
162
  }
173
163
  }