react-native-audio-browser 0.2.0-next.11 → 0.2.0-next.13

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 (416) hide show
  1. package/README.md +14 -4
  2. package/android/build.gradle +20 -1
  3. package/android/src/main/java/com/audiobrowser/AudioBrowser.kt +115 -26
  4. package/android/src/main/java/com/audiobrowser/browser/BrowserManager.kt +262 -188
  5. package/android/src/main/java/com/audiobrowser/browser/BrowserUrlResolution.kt +23 -3
  6. package/android/src/main/java/com/audiobrowser/browser/InertStyleDiagnostic.kt +267 -0
  7. package/android/src/main/java/com/audiobrowser/browser/JsonModels.kt +95 -58
  8. package/android/src/main/java/com/audiobrowser/browser/SectionScope.kt +68 -26
  9. package/android/src/main/java/com/audiobrowser/browser/StyleResolver.kt +60 -0
  10. package/android/src/main/java/com/audiobrowser/extension/ResolvedTrackExt.kt +19 -7
  11. package/android/src/main/java/com/audiobrowser/extension/TappedTrack.kt +20 -0
  12. package/android/src/main/java/com/audiobrowser/extension/TrackIdentity.kt +15 -0
  13. package/android/src/main/java/com/audiobrowser/model/PlayerUpdateOptions.kt +1 -1
  14. package/android/src/main/java/com/audiobrowser/player/MediaSessionCallback.kt +120 -67
  15. package/android/src/main/java/com/audiobrowser/player/NowPlayingUpdater.kt +21 -24
  16. package/android/src/main/java/com/audiobrowser/player/PlaybackStateStore.kt +109 -74
  17. package/android/src/main/java/com/audiobrowser/player/Player.kt +51 -30
  18. package/android/src/main/java/com/audiobrowser/player/PlayerCapabilitiesExt.kt +2 -15
  19. package/android/src/main/java/com/audiobrowser/player/ShuffleOrderLedBy.kt +30 -0
  20. package/android/src/main/java/com/audiobrowser/util/BrowserPathHelper.kt +44 -40
  21. package/android/src/main/java/com/audiobrowser/util/MediaExtrasBuilder.kt +28 -23
  22. package/android/src/main/java/com/audiobrowser/util/StyleWire.kt +108 -0
  23. package/android/src/main/java/com/audiobrowser/util/TrackFactory.kt +52 -53
  24. package/android/src/test/java/com/audiobrowser/TestFixtures.kt +74 -41
  25. package/android/src/test/java/com/audiobrowser/browser/BrowserManagerFavoritesTest.kt +153 -0
  26. package/android/src/test/java/com/audiobrowser/browser/BrowserManagerTest.kt +229 -50
  27. package/android/src/test/java/com/audiobrowser/browser/BrowserUrlResolutionTest.kt +38 -0
  28. package/android/src/test/java/com/audiobrowser/browser/InertStyleDiagnosticTest.kt +277 -0
  29. package/android/src/test/java/com/audiobrowser/browser/JsonArtworkTest.kt +1 -1
  30. package/android/src/test/java/com/audiobrowser/browser/JsonStyleTest.kt +147 -0
  31. package/android/src/test/java/com/audiobrowser/browser/SectionScopeTest.kt +128 -53
  32. package/android/src/test/java/com/audiobrowser/browser/StyleResolverTest.kt +154 -0
  33. package/android/src/test/java/com/audiobrowser/extension/TappedTrackTest.kt +43 -0
  34. package/android/src/test/java/com/audiobrowser/extension/TrackIdentityTest.kt +41 -0
  35. package/android/src/test/java/com/audiobrowser/player/CapabilityControlsTest.kt +1 -2
  36. package/android/src/test/java/com/audiobrowser/player/NowPlayingUpdaterTest.kt +42 -2
  37. package/android/src/test/java/com/audiobrowser/player/PlaybackStateStoreTrackJsonTest.kt +55 -0
  38. package/android/src/test/java/com/audiobrowser/player/ShuffleOrderLedByTest.kt +79 -0
  39. package/android/src/test/java/com/audiobrowser/util/BrowserPathHelperTest.kt +41 -16
  40. package/android/src/test/java/com/audiobrowser/util/MediaExtrasBuilderTest.kt +161 -0
  41. package/android/src/test/java/com/audiobrowser/util/TrackFactoryMediaIdTest.kt +7 -7
  42. package/ios/Browser/BrowserConfig.swift +102 -5
  43. package/ios/Browser/BrowserManager+URLResolution.swift +18 -14
  44. package/ios/Browser/BrowserManager.swift +229 -180
  45. package/ios/Browser/BrowserPathHelper.swift +44 -44
  46. package/ios/Browser/InertStyleDiagnostic.swift +279 -0
  47. package/ios/Browser/JsonModels.swift +258 -106
  48. package/ios/Browser/SearchDrillIn.swift +6 -6
  49. package/ios/Browser/SectionPresentation.swift +64 -0
  50. package/ios/Browser/SectionScope.swift +58 -24
  51. package/ios/Browser/StyleResolver.swift +58 -0
  52. package/ios/Browser/TabBarEntries.swift +9 -3
  53. package/ios/Browser/TrackIdTemplate.swift +37 -0
  54. package/ios/CarPlay/CarPlayArtworkResolver.swift +8 -7
  55. package/ios/CarPlay/CarPlayController.swift +227 -85
  56. package/ios/CarPlay/CarPlayImageLoader.swift +38 -18
  57. package/ios/CarPlay/CarPlayListItemFactory.swift +289 -84
  58. package/ios/CarPlay/CarPlayNowPlayingManager.swift +15 -12
  59. package/ios/Extension/Capability+RemoteCommand.swift +1 -1
  60. package/ios/Extension/PlayerCapabilities+Favorite.swift +1 -15
  61. package/ios/Extension/ResolvedTrack+Copying.swift +11 -15
  62. package/ios/Extension/Section+Copying.swift +31 -0
  63. package/ios/Extension/Track+Copying.swift +6 -12
  64. package/ios/Extension/Track+Identity.swift +18 -0
  65. package/ios/Extension/UIApplication+ActiveScene.swift +27 -0
  66. package/ios/Http/HttpClient.swift +8 -2
  67. package/ios/HybridAudioBrowser.swift +166 -45
  68. package/ios/Model/NitroTypeStubs.swift +106 -21
  69. package/ios/Model/PlayerUpdateOptions.swift +7 -0
  70. package/ios/Player/MediaIntentCriteria.swift +13 -5
  71. package/ios/Player/MediaLoader.swift +33 -9
  72. package/ios/Player/NowPlayingUpdater.swift +54 -6
  73. package/ios/Player/PlaybackCoordinator.swift +13 -6
  74. package/ios/Player/PlaybackTimer.swift +8 -2
  75. package/ios/Player/QueueManager.swift +36 -10
  76. package/ios/Player/RetryManager.swift +4 -3
  77. package/ios/Player/ShuffleOrder.swift +23 -0
  78. package/ios/Player/SleepTimerHandling.swift +13 -0
  79. package/ios/RemoteCommand/RemoteCommandController.swift +53 -18
  80. package/ios/Tests/BrowserPathHelperTests.swift +50 -20
  81. package/ios/Tests/CarPlayArtworkResolverTests.swift +24 -41
  82. package/ios/Tests/InertStyleDiagnosticTests.swift +200 -0
  83. package/ios/Tests/JsonModelsTests.swift +150 -1
  84. package/ios/Tests/PlaybackStateStoreTests.swift +4 -3
  85. package/ios/Tests/QueueManagerTests.swift +72 -6
  86. package/ios/Tests/RemoteCommandControllerTests.swift +16 -0
  87. package/ios/Tests/ResolvedTrackCopyingTests.swift +37 -35
  88. package/ios/Tests/SearchDrillInTests.swift +16 -16
  89. package/ios/Tests/SectionPresentationTests.swift +90 -0
  90. package/ios/Tests/SectionScopeTests.swift +87 -55
  91. package/ios/Tests/StyleResolverTests.swift +127 -0
  92. package/ios/Tests/Support/TestTypes.swift +7 -0
  93. package/ios/Tests/TabBarEntriesTests.swift +18 -18
  94. package/ios/Tests/TrackIdTemplateTests.swift +67 -0
  95. package/ios/Tests/TrackIdentityTests.swift +20 -0
  96. package/ios/Tests/TrackSelectorTests.swift +168 -33
  97. package/ios/TrackPlayer.swift +57 -34
  98. package/ios/TrackSelector.swift +45 -30
  99. package/ios/Util/ArtworkImageFetcher.swift +16 -1
  100. package/ios/Util/NetworkMonitor.swift +43 -26
  101. package/ios/Util/SFSymbolRenderer.swift +24 -2
  102. package/ios/Util/SVGProcessor.swift +9 -2
  103. package/lib/commonjs/AudioBrowser.js +11 -0
  104. package/lib/commonjs/AudioBrowser.js.map +1 -1
  105. package/lib/commonjs/features/browser-config.js +11 -8
  106. package/lib/commonjs/features/browser-config.js.map +1 -1
  107. package/lib/commonjs/features/browser.js +2 -2
  108. package/lib/commonjs/features/favorites.js +13 -10
  109. package/lib/commonjs/features/favorites.js.map +1 -1
  110. package/lib/commonjs/features/playback/controls.js +4 -2
  111. package/lib/commonjs/features/playback/controls.js.map +1 -1
  112. package/lib/commonjs/features/playback/progress.js +2 -1
  113. package/lib/commonjs/features/playback/progress.js.map +1 -1
  114. package/lib/commonjs/features/playback/rate.js +8 -1
  115. package/lib/commonjs/features/playback/rate.js.map +1 -1
  116. package/lib/commonjs/features/playback/state.js +2 -3
  117. package/lib/commonjs/features/playback/state.js.map +1 -1
  118. package/lib/commonjs/features/player/options.js.map +1 -1
  119. package/lib/commonjs/features/player/setup.js +3 -1
  120. package/lib/commonjs/features/player/setup.js.map +1 -1
  121. package/lib/commonjs/features/player/validateOptions.js +2 -0
  122. package/lib/commonjs/features/player/validateOptions.js.map +1 -1
  123. package/lib/commonjs/features/queue/activeTrack.js +14 -3
  124. package/lib/commonjs/features/queue/activeTrack.js.map +1 -1
  125. package/lib/commonjs/features/queue/queue.js +11 -4
  126. package/lib/commonjs/features/queue/queue.js.map +1 -1
  127. package/lib/commonjs/utils/LazyNativeEmitter.js +21 -10
  128. package/lib/commonjs/utils/LazyNativeEmitter.js.map +1 -1
  129. package/lib/commonjs/utils/NativeUpdatedValue.js +31 -13
  130. package/lib/commonjs/utils/NativeUpdatedValue.js.map +1 -1
  131. package/lib/commonjs/utils/getTrackIdentity.js +24 -0
  132. package/lib/commonjs/utils/getTrackIdentity.js.map +1 -0
  133. package/lib/commonjs/utils/useNativeValueRefreshedBy.js +33 -0
  134. package/lib/commonjs/utils/useNativeValueRefreshedBy.js.map +1 -0
  135. package/lib/commonjs/web/NativeAudioBrowser.js +32 -24
  136. package/lib/commonjs/web/NativeAudioBrowser.js.map +1 -1
  137. package/lib/commonjs/web/TrackPlayer/QueueManager.js +14 -0
  138. package/lib/commonjs/web/TrackPlayer/QueueManager.js.map +1 -1
  139. package/lib/commonjs/web/browser/BrowserManager.js +144 -87
  140. package/lib/commonjs/web/browser/BrowserManager.js.map +1 -1
  141. package/lib/commonjs/web/browser/FavoriteManager.js +30 -21
  142. package/lib/commonjs/web/browser/FavoriteManager.js.map +1 -1
  143. package/lib/commonjs/web/browser/assertBrowsePageShape.js +2 -2
  144. package/lib/commonjs/web/browser/assertBrowsePageShape.js.map +1 -1
  145. package/lib/commonjs/web/browser/classifyTrackNavigation.js +9 -9
  146. package/lib/commonjs/web/browser/classifyTrackNavigation.js.map +1 -1
  147. package/lib/commonjs/web/browser/sections.js +89 -0
  148. package/lib/commonjs/web/browser/sections.js.map +1 -0
  149. package/lib/commonjs/web/player/NowPlayingManager.js +4 -3
  150. package/lib/commonjs/web/player/NowPlayingManager.js.map +1 -1
  151. package/lib/commonjs/web/util/BrowserPathHelper.js +56 -11
  152. package/lib/commonjs/web/util/BrowserPathHelper.js.map +1 -1
  153. package/lib/module/AudioBrowser.js +1 -0
  154. package/lib/module/AudioBrowser.js.map +1 -1
  155. package/lib/module/features/browser-config.js +11 -8
  156. package/lib/module/features/browser-config.js.map +1 -1
  157. package/lib/module/features/browser.js +2 -2
  158. package/lib/module/features/favorites.js +13 -10
  159. package/lib/module/features/favorites.js.map +1 -1
  160. package/lib/module/features/playback/controls.js +4 -2
  161. package/lib/module/features/playback/controls.js.map +1 -1
  162. package/lib/module/features/playback/progress.js +2 -1
  163. package/lib/module/features/playback/progress.js.map +1 -1
  164. package/lib/module/features/playback/rate.js +8 -1
  165. package/lib/module/features/playback/rate.js.map +1 -1
  166. package/lib/module/features/playback/state.js +2 -3
  167. package/lib/module/features/playback/state.js.map +1 -1
  168. package/lib/module/features/player/options.js.map +1 -1
  169. package/lib/module/features/player/setup.js +3 -1
  170. package/lib/module/features/player/setup.js.map +1 -1
  171. package/lib/module/features/player/validateOptions.js +2 -0
  172. package/lib/module/features/player/validateOptions.js.map +1 -1
  173. package/lib/module/features/queue/activeTrack.js +14 -3
  174. package/lib/module/features/queue/activeTrack.js.map +1 -1
  175. package/lib/module/features/queue/queue.js +11 -4
  176. package/lib/module/features/queue/queue.js.map +1 -1
  177. package/lib/module/utils/LazyNativeEmitter.js +21 -10
  178. package/lib/module/utils/LazyNativeEmitter.js.map +1 -1
  179. package/lib/module/utils/NativeUpdatedValue.js +31 -13
  180. package/lib/module/utils/NativeUpdatedValue.js.map +1 -1
  181. package/lib/module/utils/getTrackIdentity.js +20 -0
  182. package/lib/module/utils/getTrackIdentity.js.map +1 -0
  183. package/lib/module/utils/useNativeValueRefreshedBy.js +29 -0
  184. package/lib/module/utils/useNativeValueRefreshedBy.js.map +1 -0
  185. package/lib/module/web/NativeAudioBrowser.js +32 -24
  186. package/lib/module/web/NativeAudioBrowser.js.map +1 -1
  187. package/lib/module/web/TrackPlayer/QueueManager.js +14 -0
  188. package/lib/module/web/TrackPlayer/QueueManager.js.map +1 -1
  189. package/lib/module/web/browser/BrowserManager.js +144 -87
  190. package/lib/module/web/browser/BrowserManager.js.map +1 -1
  191. package/lib/module/web/browser/FavoriteManager.js +31 -21
  192. package/lib/module/web/browser/FavoriteManager.js.map +1 -1
  193. package/lib/module/web/browser/assertBrowsePageShape.js +2 -2
  194. package/lib/module/web/browser/assertBrowsePageShape.js.map +1 -1
  195. package/lib/module/web/browser/classifyTrackNavigation.js +9 -9
  196. package/lib/module/web/browser/classifyTrackNavigation.js.map +1 -1
  197. package/lib/module/web/browser/sections.js +83 -0
  198. package/lib/module/web/browser/sections.js.map +1 -0
  199. package/lib/module/web/player/NowPlayingManager.js +4 -3
  200. package/lib/module/web/player/NowPlayingManager.js.map +1 -1
  201. package/lib/module/web/util/BrowserPathHelper.js +56 -11
  202. package/lib/module/web/util/BrowserPathHelper.js.map +1 -1
  203. package/lib/typescript/src/AudioBrowser.d.ts +1 -0
  204. package/lib/typescript/src/AudioBrowser.d.ts.map +1 -1
  205. package/lib/typescript/src/features/browser-config.d.ts.map +1 -1
  206. package/lib/typescript/src/features/browser.d.ts +2 -2
  207. package/lib/typescript/src/features/favorites.d.ts +13 -10
  208. package/lib/typescript/src/features/favorites.d.ts.map +1 -1
  209. package/lib/typescript/src/features/playback/controls.d.ts +4 -2
  210. package/lib/typescript/src/features/playback/controls.d.ts.map +1 -1
  211. package/lib/typescript/src/features/playback/progress.d.ts.map +1 -1
  212. package/lib/typescript/src/features/playback/rate.d.ts +8 -1
  213. package/lib/typescript/src/features/playback/rate.d.ts.map +1 -1
  214. package/lib/typescript/src/features/playback/state.d.ts +2 -3
  215. package/lib/typescript/src/features/playback/state.d.ts.map +1 -1
  216. package/lib/typescript/src/features/playback/trackPlaybackTime.d.ts +1 -1
  217. package/lib/typescript/src/features/playback/trackPlaybackTime.d.ts.map +1 -1
  218. package/lib/typescript/src/features/player/options.d.ts +21 -19
  219. package/lib/typescript/src/features/player/options.d.ts.map +1 -1
  220. package/lib/typescript/src/features/player/setup.d.ts.map +1 -1
  221. package/lib/typescript/src/features/player/validateOptions.d.ts +1 -8
  222. package/lib/typescript/src/features/player/validateOptions.d.ts.map +1 -1
  223. package/lib/typescript/src/features/queue/activeTrack.d.ts +8 -1
  224. package/lib/typescript/src/features/queue/activeTrack.d.ts.map +1 -1
  225. package/lib/typescript/src/features/queue/queue.d.ts +5 -2
  226. package/lib/typescript/src/features/queue/queue.d.ts.map +1 -1
  227. package/lib/typescript/src/types/browser-native.d.ts +2 -2
  228. package/lib/typescript/src/types/browser-native.d.ts.map +1 -1
  229. package/lib/typescript/src/types/browser-nodes.d.ts +361 -126
  230. package/lib/typescript/src/types/browser-nodes.d.ts.map +1 -1
  231. package/lib/typescript/src/types/browser.d.ts +33 -53
  232. package/lib/typescript/src/types/browser.d.ts.map +1 -1
  233. package/lib/typescript/src/utils/LazyNativeEmitter.d.ts +16 -17
  234. package/lib/typescript/src/utils/LazyNativeEmitter.d.ts.map +1 -1
  235. package/lib/typescript/src/utils/NativeUpdatedValue.d.ts +24 -19
  236. package/lib/typescript/src/utils/NativeUpdatedValue.d.ts.map +1 -1
  237. package/lib/typescript/src/utils/getTrackIdentity.d.ts +18 -0
  238. package/lib/typescript/src/utils/getTrackIdentity.d.ts.map +1 -0
  239. package/lib/typescript/src/utils/useNativeValueRefreshedBy.d.ts +21 -0
  240. package/lib/typescript/src/utils/useNativeValueRefreshedBy.d.ts.map +1 -0
  241. package/nitrogen/generated/android/AudioBrowser+autolinking.cmake +0 -1
  242. package/nitrogen/generated/android/c++/{JFavoritesMatchMode.hpp → JArtworkRendering.hpp} +15 -15
  243. package/nitrogen/generated/android/c++/JArtworkRequestConfig.hpp +8 -3
  244. package/nitrogen/generated/android/c++/JBrowseResult.hpp +16 -4
  245. package/nitrogen/generated/android/c++/JCarPlayPlayingIndicatorLocation.hpp +58 -0
  246. package/nitrogen/generated/android/c++/JCardImage.hpp +58 -0
  247. package/nitrogen/generated/android/c++/JFavoriteChangedEvent.hpp +8 -3
  248. package/nitrogen/generated/android/c++/JFormatNowPlayingParams.hpp +8 -3
  249. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_RequestConfig___Track.hpp +8 -3
  250. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__optional_NowPlayingUpdate____FormatNowPlayingParams.hpp +8 -3
  251. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__optional_std__string____Track.hpp +8 -3
  252. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____Track.hpp +8 -3
  253. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_std__vector_Track______SearchParams.hpp +8 -2
  254. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_void_____TrackLoadEvent.hpp +8 -2
  255. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError__std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError_______BrowserSourceCallbackParam.hpp +16 -4
  256. package/nitrogen/generated/android/c++/JFunc_void_FavoriteChangedEvent.hpp +8 -3
  257. package/nitrogen/generated/android/c++/JFunc_void_Options.hpp +2 -5
  258. package/nitrogen/generated/android/c++/JFunc_void_PlaybackActiveTrackChangedEvent.hpp +8 -3
  259. package/nitrogen/generated/android/c++/JFunc_void_std__optional_ResolvedTrack_.hpp +15 -3
  260. package/nitrogen/generated/android/c++/JFunc_void_std__vector_Track_.hpp +8 -2
  261. package/nitrogen/generated/android/c++/JGridTile.hpp +61 -0
  262. package/nitrogen/generated/android/c++/JHybridAudioBrowserSpec.cpp +33 -14
  263. package/nitrogen/generated/android/c++/JIOSOptions.hpp +9 -3
  264. package/nitrogen/generated/android/c++/JImageShape.hpp +58 -0
  265. package/nitrogen/generated/android/c++/JMediaRequestConfig.hpp +8 -3
  266. package/nitrogen/generated/android/c++/JNativeBrowserConfiguration.hpp +22 -10
  267. package/nitrogen/generated/android/c++/JNativeRouteEntry.hpp +14 -2
  268. package/nitrogen/generated/android/c++/JNativeSetupPlayerOptions.hpp +10 -7
  269. package/nitrogen/generated/android/c++/JNativeUpdateOptions.hpp +2 -5
  270. package/nitrogen/generated/android/c++/JNitroIOSUpdateOptions.hpp +9 -3
  271. package/nitrogen/generated/android/c++/JOptions.hpp +2 -5
  272. package/nitrogen/generated/android/c++/JPlaybackActiveTrackChangedEvent.hpp +8 -3
  273. package/nitrogen/generated/android/c++/JPlayerCapabilities.hpp +5 -11
  274. package/nitrogen/generated/android/c++/JResolvedTrack.hpp +55 -51
  275. package/nitrogen/generated/android/c++/JSection.hpp +120 -0
  276. package/nitrogen/generated/android/c++/JSectionStyle.hpp +96 -0
  277. package/nitrogen/generated/android/c++/JStyleDisplay.hpp +58 -0
  278. package/nitrogen/generated/android/c++/JTrack.hpp +23 -48
  279. package/nitrogen/generated/android/c++/JTrackLoadEvent.hpp +8 -2
  280. package/nitrogen/generated/android/c++/JTrackStyle.hpp +46 -18
  281. package/nitrogen/generated/android/c++/JVariant_ResolvedTrack_BrowseError_Promise_BrowseResult_.hpp +16 -4
  282. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{FavoritesMatchMode.kt → ArtworkRendering.kt} +5 -5
  283. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/CarPlayPlayingIndicatorLocation.kt +23 -0
  284. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/CardImage.kt +23 -0
  285. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/GridTile.kt +24 -0
  286. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/IOSOptions.kt +6 -3
  287. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ImageShape.kt +23 -0
  288. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NativeBrowserConfiguration.kt +5 -5
  289. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NitroIOSUpdateOptions.kt +6 -3
  290. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlayerCapabilities.kt +2 -2
  291. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ResolvedTrack.kt +12 -18
  292. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{FavoriteConfig.kt → Section.kt} +18 -6
  293. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/SectionStyle.kt +59 -0
  294. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/StyleDisplay.kt +23 -0
  295. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Track.kt +6 -15
  296. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/TrackStyle.kt +35 -5
  297. package/nitrogen/generated/ios/AudioBrowser-Swift-Cxx-Bridge.hpp +158 -82
  298. package/nitrogen/generated/ios/AudioBrowser-Swift-Cxx-Umbrella.hpp +25 -10
  299. package/nitrogen/generated/ios/c++/HybridAudioBrowserSpecSwift.hpp +25 -10
  300. package/nitrogen/generated/ios/swift/ArtworkRendering.swift +40 -0
  301. package/nitrogen/generated/ios/swift/CarPlayPlayingIndicatorLocation.swift +40 -0
  302. package/nitrogen/generated/ios/swift/CardImage.swift +40 -0
  303. package/nitrogen/generated/ios/swift/GridTile.swift +44 -0
  304. package/nitrogen/generated/ios/swift/IOSOptions.swift +7 -2
  305. package/nitrogen/generated/ios/swift/ImageShape.swift +40 -0
  306. package/nitrogen/generated/ios/swift/NativeBrowserConfiguration.swift +5 -5
  307. package/nitrogen/generated/ios/swift/NitroIOSUpdateOptions.swift +12 -1
  308. package/nitrogen/generated/ios/swift/PlayerCapabilities.swift +8 -27
  309. package/nitrogen/generated/ios/swift/ResolvedTrack.swift +54 -83
  310. package/nitrogen/generated/ios/swift/Section.swift +100 -0
  311. package/nitrogen/generated/ios/swift/SectionStyle.swift +133 -0
  312. package/nitrogen/generated/ios/swift/StyleDisplay.swift +40 -0
  313. package/nitrogen/generated/ios/swift/Track.swift +20 -73
  314. package/nitrogen/generated/ios/swift/TrackStyle.swift +86 -22
  315. package/nitrogen/generated/shared/c++/{FavoritesMatchMode.hpp → ArtworkRendering.hpp} +17 -17
  316. package/nitrogen/generated/shared/c++/CarPlayPlayingIndicatorLocation.hpp +76 -0
  317. package/nitrogen/generated/shared/c++/CardImage.hpp +76 -0
  318. package/nitrogen/generated/shared/c++/GridTile.hpp +80 -0
  319. package/nitrogen/generated/shared/c++/IOSOptions.hpp +9 -2
  320. package/nitrogen/generated/shared/c++/ImageShape.hpp +76 -0
  321. package/nitrogen/generated/shared/c++/NativeBrowserConfiguration.hpp +6 -6
  322. package/nitrogen/generated/shared/c++/NitroIOSUpdateOptions.hpp +9 -2
  323. package/nitrogen/generated/shared/c++/PlayerCapabilities.hpp +6 -9
  324. package/nitrogen/generated/shared/c++/ResolvedTrack.hpp +30 -38
  325. package/nitrogen/generated/shared/c++/Section.hpp +106 -0
  326. package/nitrogen/generated/shared/c++/SectionStyle.hpp +126 -0
  327. package/nitrogen/generated/shared/c++/StyleDisplay.hpp +76 -0
  328. package/nitrogen/generated/shared/c++/Track.hpp +15 -31
  329. package/nitrogen/generated/shared/c++/TrackStyle.hpp +73 -34
  330. package/package.json +7 -2
  331. package/src/AudioBrowser.ts +1 -0
  332. package/src/features/browser-config.test.ts +21 -6
  333. package/src/features/browser-config.ts +11 -8
  334. package/src/features/browser.test.ts +1 -1
  335. package/src/features/browser.ts +2 -2
  336. package/src/features/favorites.ts +13 -10
  337. package/src/features/hook-wiring.test.ts +63 -15
  338. package/src/features/playback/controls.ts +4 -2
  339. package/src/features/playback/progress.ts +2 -1
  340. package/src/features/playback/rate.ts +8 -1
  341. package/src/features/playback/state.ts +2 -3
  342. package/src/features/playback/trackPlaybackTime.ts +1 -1
  343. package/src/features/player/options.ts +27 -19
  344. package/src/features/player/setup.test.ts +12 -3
  345. package/src/features/player/setup.ts +3 -1
  346. package/src/features/player/validateOptions.ts +2 -0
  347. package/src/features/queue/activeTrack.ts +14 -3
  348. package/src/features/queue/queue.ts +11 -4
  349. package/src/nitro-stub-drift.test.ts +40 -0
  350. package/src/public-surface.test.ts +40 -0
  351. package/src/specs/audio-browser.nitro.ts +4 -3
  352. package/src/style-resolution.test.ts +210 -0
  353. package/src/types/browser-native.ts +2 -2
  354. package/src/types/browser-nodes.ts +377 -135
  355. package/src/types/browser.ts +34 -55
  356. package/src/utils/LazyNativeEmitter.ts +20 -10
  357. package/src/utils/NativeUpdatedValue.ts +29 -13
  358. package/src/utils/getTrackIdentity.ts +20 -0
  359. package/src/utils/useNativeValueRefreshedBy.ts +38 -0
  360. package/src/web/NativeAudioBrowser.ts +37 -22
  361. package/src/web/TrackPlayer/QueueManager.test.ts +29 -0
  362. package/src/web/TrackPlayer/QueueManager.ts +14 -0
  363. package/src/web/browser/BrowserManager.ts +176 -95
  364. package/src/web/browser/FavoriteManager.test.ts +84 -0
  365. package/src/web/browser/FavoriteManager.ts +28 -23
  366. package/src/web/browser/assertBrowsePageShape.test.ts +1 -1
  367. package/src/web/browser/assertBrowsePageShape.ts +5 -3
  368. package/src/web/browser/classifyTrackNavigation.test.ts +10 -8
  369. package/src/web/browser/classifyTrackNavigation.ts +9 -9
  370. package/src/web/browser/parseSearchResponse.test.ts +8 -2
  371. package/src/web/browser/sections.test.ts +91 -0
  372. package/src/web/browser/sections.ts +72 -0
  373. package/src/web/player/NowPlayingManager.ts +4 -3
  374. package/src/web/util/BrowserPathHelper.test.ts +52 -0
  375. package/src/web/util/BrowserPathHelper.ts +61 -13
  376. package/website/guide/android-auto.md +114 -0
  377. package/website/guide/android-certificates.md +409 -0
  378. package/website/guide/artwork.md +255 -0
  379. package/website/guide/audio-output.md +135 -0
  380. package/website/guide/automotive.md +86 -0
  381. package/website/guide/basic-usage.md +151 -0
  382. package/website/guide/battery.md +115 -0
  383. package/website/guide/browser.md +581 -0
  384. package/website/guide/carplay.md +620 -0
  385. package/website/guide/configuration.md +173 -0
  386. package/website/guide/equalizer.md +231 -0
  387. package/website/guide/errors.md +310 -0
  388. package/website/guide/favorites.md +154 -0
  389. package/website/guide/gate.md +143 -0
  390. package/website/guide/getting-started.md +46 -0
  391. package/website/guide/hooks.md +238 -0
  392. package/website/guide/live-streams.md +125 -0
  393. package/website/guide/metadata.md +239 -0
  394. package/website/guide/migrating-from-track-player.md +244 -0
  395. package/website/guide/native-callback-fetch.md +127 -0
  396. package/website/guide/network.md +86 -0
  397. package/website/guide/now-playing.md +175 -0
  398. package/website/guide/playback.md +328 -0
  399. package/website/guide/queue.md +300 -0
  400. package/website/guide/remote-controls.md +256 -0
  401. package/website/guide/search.md +255 -0
  402. package/website/guide/sleep-timer.md +268 -0
  403. package/website/guide/track.md +246 -0
  404. package/ios/CarPlay/ImageRowItem+CarPlay.swift +0 -19
  405. package/nitrogen/generated/android/c++/JFavoriteConfig.hpp +0 -58
  406. package/nitrogen/generated/android/c++/JImageRowItem.hpp +0 -105
  407. package/nitrogen/generated/android/c++/JVariant_Boolean_FavoriteConfig.cpp +0 -26
  408. package/nitrogen/generated/android/c++/JVariant_Boolean_FavoriteConfig.hpp +0 -71
  409. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ImageRowItem.kt +0 -68
  410. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Variant_Boolean_FavoriteConfig.kt +0 -53
  411. package/nitrogen/generated/ios/swift/FavoriteConfig.swift +0 -29
  412. package/nitrogen/generated/ios/swift/FavoritesMatchMode.swift +0 -40
  413. package/nitrogen/generated/ios/swift/ImageRowItem.swift +0 -195
  414. package/nitrogen/generated/ios/swift/Variant_Bool_FavoriteConfig.swift +0 -18
  415. package/nitrogen/generated/shared/c++/FavoriteConfig.hpp +0 -84
  416. package/nitrogen/generated/shared/c++/ImageRowItem.hpp +0 -129
@@ -0,0 +1,135 @@
1
+ ---
2
+ description: 'Read where audio is currently playing (speaker, Bluetooth, AirPlay, the car), react when the route changes, and open the system output switcher.'
3
+ ---
4
+
5
+ # Audio Output
6
+
7
+ Read where audio is currently playing (speaker, Bluetooth, AirPlay, the car…),
8
+ react when it changes, and open the system output switcher so the listener can
9
+ move playback to another device. Both layers are **cross-platform**:
10
+
11
+ - **Reading the current output** — `getOutput()` / `useOutput()` /
12
+ `onOutputChanged`. iOS reports the active route while a session is active;
13
+ Android reports the active output route from `AudioManager` (the `type` is
14
+ coarse — e.g. wired headphones may report as `speaker`).
15
+ - **Opening the switcher** — `openOutputPicker()` / `supportsOutputSwitcher()`:
16
+ the system route picker on iOS, the system Output Switcher on Android 11+.
17
+
18
+ ::: tip Gate the switcher button on `supportsOutputSwitcher()`
19
+ Surface your output button only when `supportsOutputSwitcher()` is `true` — it's
20
+ `true` on iOS and Android 11+ (API 30), `false` on older Android and web.
21
+ Reading the current output works more broadly, but `getOutput()` can still be
22
+ `undefined` (before playback, or when unknown) — so guard for it.
23
+ :::
24
+
25
+ The UI snippets import `Text` / `Button` from `react-native`; everything else is
26
+ from `react-native-audio-browser`.
27
+
28
+ ## The current output
29
+
30
+ [`useOutput()`](/api/features/output/#useoutput) returns the active output and
31
+ re-renders whenever it changes (AirPods connect, headphones unplug, a Bluetooth
32
+ speaker is selected):
33
+
34
+ ```tsx
35
+ import { Text } from 'react-native'
36
+ import { useOutput } from 'react-native-audio-browser'
37
+
38
+ function OutputLabel() {
39
+ const output = useOutput()
40
+ if (!output) return null // not yet known
41
+ return <Text>Playing on {output.name}</Text>
42
+ }
43
+ ```
44
+
45
+ An [`Output`](/api/features/output/#output) is:
46
+
47
+ | Field | Type | Meaning |
48
+ | ---------- | ------------ | ------------------------------------------------------------------------------- |
49
+ | `name` | `string` | Human-readable device name, e.g. `"AirPods Pro"`, `"Kitchen speaker"`. |
50
+ | `type` | `OutputType` | The output kind (see below). |
51
+ | `external` | `boolean` | `false` only for the built-in speaker/receiver; `true` for everything external. |
52
+
53
+ `type` is one of `'speaker'`, `'receiver'` (the iOS earpiece), `'headphones'`,
54
+ `'bluetooth'`, `'airplay'`, `'car'`, `'hdmi'`, `'usb'`, `'cast'` (a remote
55
+ speaker / TV), or `'other'`. Both platforms map their native ports/routes into
56
+ this shared set — e.g. iOS's separate Bluetooth ports all collapse to
57
+ `'bluetooth'`.
58
+
59
+ ::: warning Android reports a coarser type
60
+ On Android the type comes from the system route and is coarser: wired headphones
61
+ often report as `'speaker'` (the built-in route), and really only `'bluetooth'`
62
+ is reliably distinguished from it (`'cast'` requires active route discovery,
63
+ which the reader doesn't run, so it won't appear here). The device **name** still
64
+ comes through.
65
+ :::
66
+
67
+ Outside React, read a snapshot with `getOutput()` or subscribe with
68
+ [`onOutputChanged`](/api/features/output/#onoutputchanged):
69
+
70
+ ```ts
71
+ import { getOutput, onOutputChanged } from 'react-native-audio-browser'
72
+
73
+ getOutput() // Output | undefined
74
+
75
+ const unsubscribe = onOutputChanged.addListener((output) => {
76
+ console.log('now playing on', output.name)
77
+ })
78
+
79
+ // later:
80
+ unsubscribe()
81
+ ```
82
+
83
+ ## Opening the output picker
84
+
85
+ [`openOutputPicker()`](/api/features/output/#openoutputpicker) presents the
86
+ system output switcher — the AirPlay / Bluetooth / speaker chooser on iOS, and
87
+ the Bluetooth / speaker / Cast switcher on Android (11+). Wire it to your own
88
+ output button, shown only when
89
+ [`supportsOutputSwitcher()`](/api/features/output/#supportsoutputswitcher) is
90
+ `true`:
91
+
92
+ ```tsx
93
+ import { Button } from 'react-native'
94
+ import {
95
+ openOutputPicker,
96
+ supportsOutputSwitcher
97
+ } from 'react-native-audio-browser'
98
+
99
+ function OutputButton() {
100
+ if (!supportsOutputSwitcher()) return null // older Android / web
101
+ return <Button title="Output" onPress={() => openOutputPicker()} />
102
+ }
103
+ ```
104
+
105
+ `openOutputPicker()` is safe to call unconditionally — it's a no-op where no
106
+ switcher exists — but gating the button on `supportsOutputSwitcher()` keeps you
107
+ from showing a control that would do nothing.
108
+
109
+ On Android the switcher is the system one (the picker from the media
110
+ notification); selecting a Bluetooth speaker there routes audio at the OS level.
111
+ The library can't force playback to a _specific_ Bluetooth device itself — route
112
+ selection is the system's job, which is what this hands off to. Sonos appears on
113
+ iOS (as an AirPlay target); on Android it isn't a system route, so it won't show.
114
+
115
+ ## You may not need this for unplug handling
116
+
117
+ When the current output **disappears** — headphones unplugged, a Bluetooth
118
+ speaker powered off — the player **pauses automatically** rather than blaring out
119
+ of the built-in speaker (the convention every media app follows). It's a
120
+ deliberate pause: the listener presses play again when ready. So you don't need
121
+ to watch `onOutputChanged` just to handle unplugging — reach for these APIs to
122
+ _display_ the output or to _offer_ a switcher.
123
+
124
+ ## API summary
125
+
126
+ | API | Platforms | Purpose |
127
+ | -------------------------- | ---------------- | -------------------------------------------------------------------------- |
128
+ | `openOutputPicker()` | iOS, Android 11+ | Present the system output switcher (Bluetooth / AirPlay / speaker / Cast). |
129
+ | `supportsOutputSwitcher()` | all | Whether a switcher can be shown — gate your output button on it. |
130
+ | `useOutput()` | iOS, Android | Reactive current output (`Output \| undefined`). |
131
+ | `getOutput()` | iOS, Android | One-off snapshot of the current output. |
132
+ | `onOutputChanged` | iOS, Android | Subscribe outside React; `addListener(cb)` returns an unsubscribe fn. |
133
+
134
+ The whole API is cross-platform; only the switcher needs Android 11+ (gate on
135
+ `supportsOutputSwitcher()`), and Android reports coarser output `type`s than iOS.
@@ -0,0 +1,86 @@
1
+ ---
2
+ description: 'How CarPlay, Android Auto, and Android Automotive all reuse the browse tree, queue, now-playing metadata, and search source you have already built.'
3
+ ---
4
+
5
+ # In the car
6
+
7
+ CarPlay, Android Auto, and Android Automotive all show your content on the car
8
+ screen and play through the same player as your app. You don't build a separate
9
+ "car app" — the car surfaces are driven by the **same cross-cutting pieces you've
10
+ already built**:
11
+
12
+ - your [browse tree](/guide/browser) becomes the car's browsable menus,
13
+ - your [now-playing metadata](/guide/now-playing) fills the car's now-playing
14
+ screen,
15
+ - the [player and queue](/guide/playback) are shared, so playback is continuous
16
+ whether the user started it in-app or in the car,
17
+ - your [`search` source](/guide/search) answers in-car voice commands
18
+ ("play jazz"),
19
+ - [favorites](/guide/favorites) surface a heart and a "play my favorites" intent.
20
+
21
+ Build those once and they light up every car surface. The per-platform pages
22
+ handle the platform-specific **setup**: **[Android Auto](/guide/android-auto)**
23
+ (also Android Automotive) and **[CarPlay](/guide/carplay)**.
24
+
25
+ ## Shared vs platform-specific
26
+
27
+ | Concern | Where it's handled |
28
+ | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
29
+ | Browse tree / menus | Shared — [Browser](/guide/browser) |
30
+ | Now-playing metadata & artwork | Shared — [Now Playing](/guide/now-playing) |
31
+ | Player, queue, playback | Shared — [Playback](/guide/playback) |
32
+ | Voice search ("play …") | Shared — your [`search`](/guide/search) source |
33
+ | Favorites heart & "play my favorites" | Shared — [Favorites](/guide/favorites) |
34
+ | App setup, entitlements, manifest | Per-platform — [Android Auto](/guide/android-auto) / [CarPlay](/guide/carplay) |
35
+ | Now-playing buttons | Per-platform — [Button layout](/guide/remote-controls#button-layout-android) (Android) / [CarPlay](/guide/carplay) (iOS) |
36
+
37
+ The takeaway: spend your effort on the shared content model; reach for a platform
38
+ page only for that platform's setup and buttons.
39
+
40
+ ## Detecting a car connection
41
+
42
+ To adapt your in-app UI while connected to a car (a "now playing in your car"
43
+ state, a simplified screen), use
44
+ [`useCarConnected()`](/api/features/carConnection/#usecarconnected). It's `true`
45
+ for a CarPlay connection on iOS, and an Android Auto **or Android Automotive**
46
+ connection on Android (`false` on web):
47
+
48
+ ```tsx
49
+ import { Text } from 'react-native'
50
+ import { useCarConnected } from 'react-native-audio-browser'
51
+
52
+ function CarBadge() {
53
+ const inCar = useCarConnected()
54
+ if (!inCar) return null
55
+ return <Text>Playing in your car</Text>
56
+ }
57
+ ```
58
+
59
+ Outside React, read a snapshot with
60
+ [`isCarConnected()`](/api/features/carConnection/#iscarconnected) or subscribe
61
+ with [`onCarConnectedChanged`](/api/features/carConnection/#oncarconnectedchanged)
62
+ (`addListener` returns an unsubscribe function):
63
+
64
+ ```ts
65
+ import {
66
+ isCarConnected,
67
+ onCarConnectedChanged
68
+ } from 'react-native-audio-browser'
69
+
70
+ isCarConnected() // boolean
71
+
72
+ const unsubscribe = onCarConnectedChanged.addListener((connected) => {
73
+ // ...
74
+ })
75
+ // later: unsubscribe()
76
+ ```
77
+
78
+ ## Next steps
79
+
80
+ 1. Set up the platform(s) you ship to —
81
+ **[Android Auto](/guide/android-auto)** (and Android Automotive) and/or
82
+ **[CarPlay](/guide/carplay)**.
83
+ 2. Make sure your [browse tree](/guide/browser) and
84
+ [now-playing](/guide/now-playing) are in good shape — that's what the car
85
+ renders.
86
+ 3. Wire your [`search` source](/guide/search) so voice commands work in the car.
@@ -0,0 +1,151 @@
1
+ ---
2
+ description: 'The browse tree in one page: browsable versus playable Tracks, setting up the player, declaring content, and playing it.'
3
+ ---
4
+
5
+ # Basic Usage
6
+
7
+ This guide covers the core idea — the **browse tree** — and the minimal code to set up the player, define some content, and play it. Installation is in [Getting Started](/guide/getting-started).
8
+
9
+ ## The browse tree
10
+
11
+ The library models all content as one navigable tree of **Tracks**. A single Track is **browsable**, **playable**, or both, depending on which fields you set:
12
+
13
+ - **Browsable** — has a `path`; navigating into it resolves its children.
14
+ - **Playable** — has a `src`; the player can stream it.
15
+
16
+ Three fields at a glance — each answers a different question about a Track:
17
+
18
+ | Field | Answers | Meaning |
19
+ | ------ | ------------------ | --------------------------------------------------------- |
20
+ | `path` | where does it go? | the browse-tree address navigating opens |
21
+ | `src` | what does it play? | the media identifier the player streams |
22
+ | `id` | which item is it? | identity across surfaces — falls back to `src` when unset |
23
+
24
+ ```mermaid
25
+ graph TD
26
+ Root[Root]
27
+ Root --> Favorites[Favorites]
28
+ Root --> Recent[Recently Played]
29
+ Root --> Browse[Browse]
30
+
31
+ Browse --> Jazz[Jazz]
32
+ Browse --> Rock[Rock]
33
+
34
+ Jazz --> J1[Smooth Floret FM]
35
+ Jazz --> J2[The Stalk 88.5]
36
+ Rock --> R90[Vintage]
37
+ Rock --> R1[Crunchy Greens]
38
+ Rock --> R2[Stem City Radio]
39
+ R90 --> R3[Funky Floret 101.3]
40
+ R90 --> R4[Wilted Greens FM]
41
+
42
+ classDef browsable fill:#e3f2fd,stroke:#1976d2
43
+ classDef playable fill:#e8f5e9,stroke:#388e3c
44
+
45
+ class Root,Favorites,Recent,Browse,Jazz,Rock,R90 browsable
46
+ class J1,J2,R1,R2,R3,R4 playable
47
+ ```
48
+
49
+ <div style="display: flex; gap: 1rem; margin-top: 0.5rem; font-size: 0.9em;">
50
+ <span><span style="display: inline-block; width: 12px; height: 12px; background: #e3f2fd; border: 1px solid #1976d2; margin-right: 4px;"></span> Browsable: opens to children</span>
51
+ <span><span style="display: inline-block; width: 12px; height: 12px; background: #e8f5e9; border: 1px solid #388e3c; margin-right: 4px;"></span> Playable: streams audio</span>
52
+ </div>
53
+
54
+ One tree powers both your in-app UI and the native browse views on CarPlay and Android Auto.
55
+
56
+ ## Set up the player
57
+
58
+ Call `setupPlayer()` once at startup to initialize the player:
59
+
60
+ ```ts
61
+ import { setupPlayer } from 'react-native-audio-browser'
62
+
63
+ await setupPlayer()
64
+ ```
65
+
66
+ ## Define a browse tree
67
+
68
+ Describe the tree with `configureBrowser`: **tabs** along the top, and **routes** that resolve each path to its children. The simplest source is static data declared inline:
69
+
70
+ ```ts
71
+ import { configureBrowser } from 'react-native-audio-browser'
72
+
73
+ configureBrowser({
74
+ tabs: [{ title: 'Browse', path: '/browse' }],
75
+ routes: {
76
+ '/browse': {
77
+ path: '/browse',
78
+ title: 'Browse',
79
+ children: [
80
+ {
81
+ title: 'Jazz',
82
+ // A path makes this browsable — tapping it opens that path.
83
+ path: '/browse/jazz'
84
+ },
85
+ {
86
+ title: 'Smooth Floret FM',
87
+ // A src makes this playable — tapping it streams the track.
88
+ src: 'https://example.com/floret.mp3'
89
+ }
90
+ ]
91
+ },
92
+ '/browse/jazz': {
93
+ path: '/browse/jazz',
94
+ title: 'Jazz',
95
+ children: [
96
+ {
97
+ title: 'The Stalk 88.5',
98
+ src: 'https://example.com/stalk.mp3'
99
+ }
100
+ ]
101
+ }
102
+ }
103
+ })
104
+ ```
105
+
106
+ A route value is a [`BrowserSource`](/api/types/browser/#browsersource): the static page object shown above, an **async callback** that returns one (`'/path': async ({ routeParams }) => ({ title, children })`), or an HTTP request config that fetches it from your API — handy for trees too large to declare upfront.
107
+
108
+ A page can also group its tracks into titled, styled **sections** (`sections: [{ title, style, children }, …]`) — a flat `children` list like the ones above is shorthand for a single untitled section. See [Browser → How a path resolves](/guide/browser#how-a-path-resolves).
109
+
110
+ ## Play a track
111
+
112
+ On CarPlay and Android Auto, tapping a playable Track plays it for you. To drive playback from your own UI, set a queue and call `play`:
113
+
114
+ ```ts
115
+ import { setQueue, play } from 'react-native-audio-browser'
116
+
117
+ setQueue([{ title: 'Smooth Floret FM', src: 'https://example.com/floret.mp3' }])
118
+ play()
119
+ ```
120
+
121
+ ## The queue
122
+
123
+ The player works through a **queue** of Tracks. The Track at the current position is the **active track** — it's what plays, and what external next/previous controls (car, headphones, lock screen) move between.
124
+
125
+ **Now Playing** is the metadata shown on the lock screen, notification, and car surfaces. By default it mirrors the active track; for live streams you can override it as the current song changes — see [Now Playing](/guide/now-playing).
126
+
127
+ ## Read state in your UI
128
+
129
+ Reactive hooks keep your in-app UI in sync with playback — they re-render automatically as it changes:
130
+
131
+ ```tsx
132
+ import {
133
+ togglePlayback,
134
+ usePlayingState,
135
+ useActiveTrack
136
+ } from 'react-native-audio-browser'
137
+
138
+ function PlayPauseButton() {
139
+ const { playing } = usePlayingState()
140
+ const track = useActiveTrack()
141
+
142
+ return (
143
+ <Button
144
+ title={playing ? `Pause ${track?.title ?? ''}` : 'Play'}
145
+ onPress={() => togglePlayback()}
146
+ />
147
+ )
148
+ }
149
+ ```
150
+
151
+ See the [API reference](/api/) for the full set of hooks (`useProgress`, `useQueue`, `useNowPlaying`, and more).
@@ -0,0 +1,115 @@
1
+ ---
2
+ description: 'Detect the Android 12+ battery restrictions that block the foreground service the player needs, and prompt the listener to fix their settings.'
3
+ ---
4
+
5
+ # Battery
6
+
7
+ On Android 12+, if the OS has put your app under battery restrictions, it
8
+ **blocks the foreground service** the player needs to start audio in the
9
+ background. So when a Bluetooth device or car head unit tries to resume playback
10
+ while your app is killed, nothing happens. This feature detects that block and
11
+ lets you prompt the user to fix their battery settings.
12
+
13
+ ::: warning Android only
14
+ This is an **Android-only** concern (Android 12+ foreground-service limits).
15
+ On iOS every getter/hook here is inert: `getBatteryWarningPending()` is always
16
+ `false`, `getBatteryOptimizationStatus()` is always `'unrestricted'`, the events
17
+ never fire, and `dismissBatteryWarning()` / `openBatterySettings()` are no-ops.
18
+ So you can render the banner below unconditionally — it simply never shows on iOS.
19
+ :::
20
+
21
+ The UI snippet imports `View` / `Text` / `Button` from `react-native`; everything
22
+ else is from `react-native-audio-browser`.
23
+
24
+ ## The warning banner
25
+
26
+ A warning becomes **pending** when a background resume is actually blocked. Show
27
+ a banner only while `pending` is true, offering to open settings or dismiss.
28
+ [`useBatteryWarning()`](/api/features/battery/#usebatterywarning) bundles
29
+ everything you need:
30
+
31
+ ```tsx
32
+ import { View, Text, Button } from 'react-native'
33
+ import { useBatteryWarning } from 'react-native-audio-browser'
34
+
35
+ function BatteryWarningBanner() {
36
+ const { pending, status, dismiss, openSettings } = useBatteryWarning()
37
+ if (!pending) return null
38
+
39
+ return (
40
+ <View>
41
+ <Text>Playback was blocked by battery settings ({status}).</Text>
42
+ <Button title="Fix" onPress={openSettings} />
43
+ <Button title="Dismiss" onPress={dismiss} />
44
+ </View>
45
+ )
46
+ }
47
+ ```
48
+
49
+ - `openSettings` ([`openBatterySettings`](/api/features/battery/#openbatterysettings))
50
+ opens this app's system battery settings. When the user returns having set the
51
+ app to unrestricted, the warning clears itself.
52
+ - `dismiss` ([`dismissBatteryWarning`](/api/features/battery/#dismissbatterywarning))
53
+ hides the warning without changing settings.
54
+
55
+ ## When the warning clears
56
+
57
+ `pending` goes back to `false` when any of these happens — you don't clear it
58
+ manually:
59
+
60
+ - the user calls `dismiss`, or
61
+ - the battery status becomes `'unrestricted'` (e.g. they fixed it in settings).
62
+
63
+ ## Battery optimization status
64
+
65
+ `status` is the device's current setting for your app:
66
+
67
+ | Status | Meaning |
68
+ | ---------------- | -------------------------------------------------------------------- |
69
+ | `'unrestricted'` | The user allowed the app to run freely in the background. |
70
+ | `'optimized'` | Default — the system may limit background work (Doze / App Standby). |
71
+ | `'restricted'` | Background work is severely limited; services are blocked. |
72
+
73
+ Background resume is reliable only when `'unrestricted'`, which is why the "Fix"
74
+ button sends users to settings to grant it.
75
+
76
+ ## Reading state directly
77
+
78
+ If you don't want the bundled hook, the pieces are available individually:
79
+
80
+ ```ts
81
+ import {
82
+ getBatteryWarningPending,
83
+ getBatteryOptimizationStatus,
84
+ onBatteryWarningPendingChanged,
85
+ onBatteryOptimizationStatusChanged
86
+ } from 'react-native-audio-browser'
87
+
88
+ getBatteryWarningPending() // boolean
89
+ getBatteryOptimizationStatus() // 'unrestricted' | 'optimized' | 'restricted'
90
+
91
+ const off = onBatteryWarningPendingChanged.addListener(({ pending }) => {})
92
+ const off2 = onBatteryOptimizationStatusChanged.addListener(({ status }) => {})
93
+
94
+ // each addListener returns an unsubscribe function:
95
+ off()
96
+ off2()
97
+ ```
98
+
99
+ The reactive hooks [`useBatteryWarningPending()`](/api/features/battery/#usebatterywarningpending)
100
+ and [`useBatteryOptimizationStatus()`](/api/features/battery/#usebatteryoptimizationstatus)
101
+ wrap the getter+event pairs; `useBatteryWarning()` simply combines both with the
102
+ two actions.
103
+
104
+ ## API summary
105
+
106
+ | API | Purpose |
107
+ | ----------------------------------------------------------------------- | ---------------------------------------------------------------------- |
108
+ | `useBatteryWarning()` | Everything for a banner: `{ pending, status, dismiss, openSettings }`. |
109
+ | `getBatteryWarningPending()` / `useBatteryWarningPending()` | Is a warning pending? (Android; `false` on iOS) |
110
+ | `getBatteryOptimizationStatus()` / `useBatteryOptimizationStatus()` | Current status (Android; `'unrestricted'` on iOS) |
111
+ | `onBatteryWarningPendingChanged` / `onBatteryOptimizationStatusChanged` | Subscribe outside React. |
112
+ | `openBatterySettings()` | Open the app's system battery settings (Android). |
113
+ | `dismissBatteryWarning()` | Dismiss the warning without changing settings (Android). |
114
+
115
+ All are **Android-only** — inert (`false` / `'unrestricted'` / no-op) on iOS.