react-native-audio-browser 0.2.0-next.10 → 0.2.0-next.12

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 (345) hide show
  1. package/README.md +4 -4
  2. package/android/build.gradle +6 -5
  3. package/android/gradle.properties +1 -1
  4. package/android/src/main/java/com/audiobrowser/AudioBrowser.kt +110 -25
  5. package/android/src/main/java/com/audiobrowser/browser/BrowserManager.kt +254 -188
  6. package/android/src/main/java/com/audiobrowser/browser/BrowserUrlResolution.kt +23 -3
  7. package/android/src/main/java/com/audiobrowser/browser/JsonModels.kt +77 -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 +49 -0
  10. package/android/src/main/java/com/audiobrowser/extension/ResolvedTrackExt.kt +9 -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/player/MediaSessionCallback.kt +120 -67
  14. package/android/src/main/java/com/audiobrowser/player/NowPlayingUpdater.kt +21 -24
  15. package/android/src/main/java/com/audiobrowser/player/PlaybackStateStore.kt +93 -73
  16. package/android/src/main/java/com/audiobrowser/player/Player.kt +48 -30
  17. package/android/src/main/java/com/audiobrowser/player/PlayerCapabilitiesExt.kt +2 -15
  18. package/android/src/main/java/com/audiobrowser/tls/AiaCertChaser.kt +46 -5
  19. package/android/src/main/java/com/audiobrowser/tls/AiaChasingExtendedTrustManager.kt +86 -27
  20. package/android/src/main/java/com/audiobrowser/tls/AiaChasingTrustManager.kt +58 -14
  21. package/android/src/main/java/com/audiobrowser/tls/AiaTls.kt +20 -6
  22. package/android/src/main/java/com/audiobrowser/tls/CachingCertificateFetcher.kt +249 -86
  23. package/android/src/main/java/com/audiobrowser/util/BrowserPathHelper.kt +44 -40
  24. package/android/src/main/java/com/audiobrowser/util/MediaExtrasBuilder.kt +28 -23
  25. package/android/src/main/java/com/audiobrowser/util/StyleWire.kt +35 -0
  26. package/android/src/main/java/com/audiobrowser/util/TrackFactory.kt +45 -53
  27. package/android/src/test/java/com/audiobrowser/TestFixtures.kt +69 -30
  28. package/android/src/test/java/com/audiobrowser/browser/BrowserManagerFavoritesTest.kt +153 -0
  29. package/android/src/test/java/com/audiobrowser/browser/BrowserManagerLayerResolutionTest.kt +6 -0
  30. package/android/src/test/java/com/audiobrowser/browser/BrowserManagerTest.kt +345 -8
  31. package/android/src/test/java/com/audiobrowser/browser/BrowserUrlResolutionTest.kt +38 -0
  32. package/android/src/test/java/com/audiobrowser/browser/JsonArtworkTest.kt +1 -1
  33. package/android/src/test/java/com/audiobrowser/browser/JsonStyleTest.kt +91 -0
  34. package/android/src/test/java/com/audiobrowser/browser/SectionScopeTest.kt +128 -53
  35. package/android/src/test/java/com/audiobrowser/browser/StyleResolverTest.kt +87 -0
  36. package/android/src/test/java/com/audiobrowser/extension/TappedTrackTest.kt +43 -0
  37. package/android/src/test/java/com/audiobrowser/extension/TrackIdentityTest.kt +41 -0
  38. package/android/src/test/java/com/audiobrowser/player/CapabilityControlsTest.kt +1 -2
  39. package/android/src/test/java/com/audiobrowser/player/NowPlayingUpdaterTest.kt +42 -2
  40. package/android/src/test/java/com/audiobrowser/player/PlaybackStateStoreTrackJsonTest.kt +55 -0
  41. package/android/src/test/java/com/audiobrowser/tls/AiaCertChaserTest.kt +152 -8
  42. package/android/src/test/java/com/audiobrowser/tls/AiaChasingTrustManagerTest.kt +218 -10
  43. package/android/src/test/java/com/audiobrowser/tls/CachingCertificateFetcherCallSiteTest.kt +322 -0
  44. package/android/src/test/java/com/audiobrowser/util/BrowserPathHelperTest.kt +41 -16
  45. package/android/src/test/java/com/audiobrowser/util/MediaExtrasBuilderTest.kt +161 -0
  46. package/android/src/test/java/com/audiobrowser/util/TrackFactoryMediaIdTest.kt +7 -7
  47. package/ios/Browser/BrowserConfig.swift +102 -5
  48. package/ios/Browser/BrowserManager+URLResolution.swift +18 -14
  49. package/ios/Browser/BrowserManager.swift +131 -143
  50. package/ios/Browser/BrowserPathHelper.swift +44 -44
  51. package/ios/Browser/JsonModels.swift +187 -106
  52. package/ios/Browser/SearchDrillIn.swift +6 -6
  53. package/ios/Browser/SectionPresentation.swift +34 -0
  54. package/ios/Browser/SectionScope.swift +58 -24
  55. package/ios/Browser/StyleResolver.swift +47 -0
  56. package/ios/Browser/TabBarEntries.swift +2 -2
  57. package/ios/Browser/TrackIdTemplate.swift +37 -0
  58. package/ios/CarPlay/CarPlayArtworkResolver.swift +8 -7
  59. package/ios/CarPlay/CarPlayController.swift +105 -67
  60. package/ios/CarPlay/CarPlayImageLoader.swift +38 -18
  61. package/ios/CarPlay/CarPlayListItemFactory.swift +217 -84
  62. package/ios/CarPlay/CarPlayNowPlayingManager.swift +15 -12
  63. package/ios/Extension/Capability+RemoteCommand.swift +1 -1
  64. package/ios/Extension/PlayerCapabilities+Favorite.swift +1 -15
  65. package/ios/Extension/ResolvedTrack+Copying.swift +11 -15
  66. package/ios/Extension/Section+Copying.swift +31 -0
  67. package/ios/Extension/Track+Copying.swift +6 -12
  68. package/ios/Extension/Track+Identity.swift +18 -0
  69. package/ios/HybridAudioBrowser.swift +113 -35
  70. package/ios/Model/NitroTypeStubs.swift +64 -23
  71. package/ios/Model/PlayerUpdateOptions.swift +7 -0
  72. package/ios/Player/NowPlayingUpdater.swift +1 -1
  73. package/ios/Player/PlaybackCoordinator.swift +2 -2
  74. package/ios/Player/RetryManager.swift +4 -3
  75. package/ios/Tests/BrowserPathHelperTests.swift +50 -20
  76. package/ios/Tests/CarPlayArtworkResolverTests.swift +24 -41
  77. package/ios/Tests/JsonModelsTests.swift +75 -1
  78. package/ios/Tests/PlaybackStateStoreTests.swift +4 -3
  79. package/ios/Tests/QueueManagerTests.swift +4 -4
  80. package/ios/Tests/ResolvedTrackCopyingTests.swift +37 -35
  81. package/ios/Tests/SearchDrillInTests.swift +16 -16
  82. package/ios/Tests/SectionPresentationTests.swift +61 -0
  83. package/ios/Tests/SectionScopeTests.swift +87 -55
  84. package/ios/Tests/StyleResolverTests.swift +67 -0
  85. package/ios/Tests/TabBarEntriesTests.swift +18 -18
  86. package/ios/Tests/TrackIdTemplateTests.swift +67 -0
  87. package/ios/Tests/TrackIdentityTests.swift +20 -0
  88. package/ios/Tests/TrackSelectorTests.swift +168 -33
  89. package/ios/TrackSelector.swift +45 -30
  90. package/ios/Util/ArtworkImageFetcher.swift +16 -1
  91. package/lib/commonjs/AudioBrowser.js +11 -0
  92. package/lib/commonjs/AudioBrowser.js.map +1 -1
  93. package/lib/commonjs/features/browser-config.js +11 -8
  94. package/lib/commonjs/features/browser-config.js.map +1 -1
  95. package/lib/commonjs/features/browser.js +2 -2
  96. package/lib/commonjs/features/favorites.js +13 -10
  97. package/lib/commonjs/features/favorites.js.map +1 -1
  98. package/lib/commonjs/features/playback/controls.js +4 -2
  99. package/lib/commonjs/features/playback/controls.js.map +1 -1
  100. package/lib/commonjs/features/playback/state.js +2 -3
  101. package/lib/commonjs/features/playback/state.js.map +1 -1
  102. package/lib/commonjs/features/player/options.js.map +1 -1
  103. package/lib/commonjs/features/player/setup.js +3 -1
  104. package/lib/commonjs/features/player/setup.js.map +1 -1
  105. package/lib/commonjs/features/player/validateOptions.js +2 -0
  106. package/lib/commonjs/features/player/validateOptions.js.map +1 -1
  107. package/lib/commonjs/features/queue/activeTrack.js +14 -3
  108. package/lib/commonjs/features/queue/activeTrack.js.map +1 -1
  109. package/lib/commonjs/features/queue/queue.js +11 -4
  110. package/lib/commonjs/features/queue/queue.js.map +1 -1
  111. package/lib/commonjs/utils/LazyNativeEmitter.js +21 -10
  112. package/lib/commonjs/utils/LazyNativeEmitter.js.map +1 -1
  113. package/lib/commonjs/utils/NativeUpdatedValue.js +31 -13
  114. package/lib/commonjs/utils/NativeUpdatedValue.js.map +1 -1
  115. package/lib/commonjs/utils/getTrackIdentity.js +24 -0
  116. package/lib/commonjs/utils/getTrackIdentity.js.map +1 -0
  117. package/lib/commonjs/utils/useNativeValueRefreshedBy.js +33 -0
  118. package/lib/commonjs/utils/useNativeValueRefreshedBy.js.map +1 -0
  119. package/lib/commonjs/web/NativeAudioBrowser.js +32 -24
  120. package/lib/commonjs/web/NativeAudioBrowser.js.map +1 -1
  121. package/lib/commonjs/web/browser/BrowserManager.js +144 -87
  122. package/lib/commonjs/web/browser/BrowserManager.js.map +1 -1
  123. package/lib/commonjs/web/browser/FavoriteManager.js +30 -21
  124. package/lib/commonjs/web/browser/FavoriteManager.js.map +1 -1
  125. package/lib/commonjs/web/browser/assertBrowsePageShape.js +2 -2
  126. package/lib/commonjs/web/browser/assertBrowsePageShape.js.map +1 -1
  127. package/lib/commonjs/web/browser/classifyTrackNavigation.js +9 -9
  128. package/lib/commonjs/web/browser/classifyTrackNavigation.js.map +1 -1
  129. package/lib/commonjs/web/browser/sections.js +89 -0
  130. package/lib/commonjs/web/browser/sections.js.map +1 -0
  131. package/lib/commonjs/web/player/NowPlayingManager.js +4 -3
  132. package/lib/commonjs/web/player/NowPlayingManager.js.map +1 -1
  133. package/lib/commonjs/web/util/BrowserPathHelper.js +56 -11
  134. package/lib/commonjs/web/util/BrowserPathHelper.js.map +1 -1
  135. package/lib/module/AudioBrowser.js +1 -0
  136. package/lib/module/AudioBrowser.js.map +1 -1
  137. package/lib/module/features/browser-config.js +11 -8
  138. package/lib/module/features/browser-config.js.map +1 -1
  139. package/lib/module/features/browser.js +2 -2
  140. package/lib/module/features/favorites.js +13 -10
  141. package/lib/module/features/favorites.js.map +1 -1
  142. package/lib/module/features/playback/controls.js +4 -2
  143. package/lib/module/features/playback/controls.js.map +1 -1
  144. package/lib/module/features/playback/state.js +2 -3
  145. package/lib/module/features/playback/state.js.map +1 -1
  146. package/lib/module/features/player/options.js.map +1 -1
  147. package/lib/module/features/player/setup.js +3 -1
  148. package/lib/module/features/player/setup.js.map +1 -1
  149. package/lib/module/features/player/validateOptions.js +2 -0
  150. package/lib/module/features/player/validateOptions.js.map +1 -1
  151. package/lib/module/features/queue/activeTrack.js +14 -3
  152. package/lib/module/features/queue/activeTrack.js.map +1 -1
  153. package/lib/module/features/queue/queue.js +11 -4
  154. package/lib/module/features/queue/queue.js.map +1 -1
  155. package/lib/module/utils/LazyNativeEmitter.js +21 -10
  156. package/lib/module/utils/LazyNativeEmitter.js.map +1 -1
  157. package/lib/module/utils/NativeUpdatedValue.js +31 -13
  158. package/lib/module/utils/NativeUpdatedValue.js.map +1 -1
  159. package/lib/module/utils/getTrackIdentity.js +20 -0
  160. package/lib/module/utils/getTrackIdentity.js.map +1 -0
  161. package/lib/module/utils/useNativeValueRefreshedBy.js +29 -0
  162. package/lib/module/utils/useNativeValueRefreshedBy.js.map +1 -0
  163. package/lib/module/web/NativeAudioBrowser.js +32 -24
  164. package/lib/module/web/NativeAudioBrowser.js.map +1 -1
  165. package/lib/module/web/browser/BrowserManager.js +144 -87
  166. package/lib/module/web/browser/BrowserManager.js.map +1 -1
  167. package/lib/module/web/browser/FavoriteManager.js +31 -21
  168. package/lib/module/web/browser/FavoriteManager.js.map +1 -1
  169. package/lib/module/web/browser/assertBrowsePageShape.js +2 -2
  170. package/lib/module/web/browser/assertBrowsePageShape.js.map +1 -1
  171. package/lib/module/web/browser/classifyTrackNavigation.js +9 -9
  172. package/lib/module/web/browser/classifyTrackNavigation.js.map +1 -1
  173. package/lib/module/web/browser/sections.js +83 -0
  174. package/lib/module/web/browser/sections.js.map +1 -0
  175. package/lib/module/web/player/NowPlayingManager.js +4 -3
  176. package/lib/module/web/player/NowPlayingManager.js.map +1 -1
  177. package/lib/module/web/util/BrowserPathHelper.js +56 -11
  178. package/lib/module/web/util/BrowserPathHelper.js.map +1 -1
  179. package/lib/typescript/src/AudioBrowser.d.ts +1 -0
  180. package/lib/typescript/src/AudioBrowser.d.ts.map +1 -1
  181. package/lib/typescript/src/features/browser-config.d.ts.map +1 -1
  182. package/lib/typescript/src/features/browser.d.ts +2 -2
  183. package/lib/typescript/src/features/favorites.d.ts +13 -10
  184. package/lib/typescript/src/features/favorites.d.ts.map +1 -1
  185. package/lib/typescript/src/features/playback/controls.d.ts +4 -2
  186. package/lib/typescript/src/features/playback/controls.d.ts.map +1 -1
  187. package/lib/typescript/src/features/playback/state.d.ts +2 -3
  188. package/lib/typescript/src/features/playback/state.d.ts.map +1 -1
  189. package/lib/typescript/src/features/playback/trackPlaybackTime.d.ts +1 -1
  190. package/lib/typescript/src/features/playback/trackPlaybackTime.d.ts.map +1 -1
  191. package/lib/typescript/src/features/player/options.d.ts +21 -19
  192. package/lib/typescript/src/features/player/options.d.ts.map +1 -1
  193. package/lib/typescript/src/features/player/setup.d.ts.map +1 -1
  194. package/lib/typescript/src/features/player/validateOptions.d.ts +1 -8
  195. package/lib/typescript/src/features/player/validateOptions.d.ts.map +1 -1
  196. package/lib/typescript/src/features/queue/activeTrack.d.ts +8 -1
  197. package/lib/typescript/src/features/queue/activeTrack.d.ts.map +1 -1
  198. package/lib/typescript/src/features/queue/queue.d.ts +5 -2
  199. package/lib/typescript/src/features/queue/queue.d.ts.map +1 -1
  200. package/lib/typescript/src/types/browser-native.d.ts +2 -2
  201. package/lib/typescript/src/types/browser-native.d.ts.map +1 -1
  202. package/lib/typescript/src/types/browser-nodes.d.ts +260 -127
  203. package/lib/typescript/src/types/browser-nodes.d.ts.map +1 -1
  204. package/lib/typescript/src/types/browser.d.ts +33 -53
  205. package/lib/typescript/src/types/browser.d.ts.map +1 -1
  206. package/lib/typescript/src/utils/LazyNativeEmitter.d.ts +16 -17
  207. package/lib/typescript/src/utils/LazyNativeEmitter.d.ts.map +1 -1
  208. package/lib/typescript/src/utils/NativeUpdatedValue.d.ts +24 -19
  209. package/lib/typescript/src/utils/NativeUpdatedValue.d.ts.map +1 -1
  210. package/lib/typescript/src/utils/getTrackIdentity.d.ts +18 -0
  211. package/lib/typescript/src/utils/getTrackIdentity.d.ts.map +1 -0
  212. package/lib/typescript/src/utils/useNativeValueRefreshedBy.d.ts +21 -0
  213. package/lib/typescript/src/utils/useNativeValueRefreshedBy.d.ts.map +1 -0
  214. package/nitrogen/generated/android/AudioBrowser+autolinking.cmake +0 -1
  215. package/nitrogen/generated/android/c++/{JFavoritesMatchMode.hpp → JArtworkRendering.hpp} +15 -15
  216. package/nitrogen/generated/android/c++/JArtworkRequestConfig.hpp +4 -3
  217. package/nitrogen/generated/android/c++/JBrowseResult.hpp +10 -4
  218. package/nitrogen/generated/android/c++/JCarPlayPlayingIndicatorLocation.hpp +58 -0
  219. package/nitrogen/generated/android/c++/JFavoriteChangedEvent.hpp +4 -3
  220. package/nitrogen/generated/android/c++/JFormatNowPlayingParams.hpp +4 -3
  221. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_RequestConfig___Track.hpp +4 -3
  222. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__optional_NowPlayingUpdate____FormatNowPlayingParams.hpp +4 -3
  223. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__optional_std__string____Track.hpp +4 -3
  224. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____Track.hpp +4 -3
  225. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_std__vector_Track______SearchParams.hpp +4 -2
  226. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_void_____TrackLoadEvent.hpp +4 -2
  227. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError__std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError_______BrowserSourceCallbackParam.hpp +10 -4
  228. package/nitrogen/generated/android/c++/JFunc_void_FavoriteChangedEvent.hpp +4 -3
  229. package/nitrogen/generated/android/c++/JFunc_void_Options.hpp +2 -5
  230. package/nitrogen/generated/android/c++/JFunc_void_PlaybackActiveTrackChangedEvent.hpp +4 -3
  231. package/nitrogen/generated/android/c++/JFunc_void_std__optional_ResolvedTrack_.hpp +9 -3
  232. package/nitrogen/generated/android/c++/JFunc_void_std__vector_Track_.hpp +4 -2
  233. package/nitrogen/generated/android/c++/JHybridAudioBrowserSpec.cpp +21 -14
  234. package/nitrogen/generated/android/c++/JIOSOptions.hpp +9 -3
  235. package/nitrogen/generated/android/c++/JMediaRequestConfig.hpp +4 -3
  236. package/nitrogen/generated/android/c++/JNativeBrowserConfiguration.hpp +16 -10
  237. package/nitrogen/generated/android/c++/JNativeRouteEntry.hpp +8 -2
  238. package/nitrogen/generated/android/c++/JNativeSetupPlayerOptions.hpp +6 -7
  239. package/nitrogen/generated/android/c++/JNativeUpdateOptions.hpp +2 -5
  240. package/nitrogen/generated/android/c++/JNitroIOSUpdateOptions.hpp +9 -3
  241. package/nitrogen/generated/android/c++/JOptions.hpp +2 -5
  242. package/nitrogen/generated/android/c++/JPlaybackActiveTrackChangedEvent.hpp +4 -3
  243. package/nitrogen/generated/android/c++/JPlayerCapabilities.hpp +5 -11
  244. package/nitrogen/generated/android/c++/JResolvedTrack.hpp +49 -51
  245. package/nitrogen/generated/android/c++/JSection.hpp +114 -0
  246. package/nitrogen/generated/android/c++/JSectionStyle.hpp +69 -0
  247. package/nitrogen/generated/android/c++/JStyleDisplay.hpp +58 -0
  248. package/nitrogen/generated/android/c++/JTrack.hpp +19 -48
  249. package/nitrogen/generated/android/c++/JTrackLoadEvent.hpp +4 -2
  250. package/nitrogen/generated/android/c++/JTrackStyle.hpp +25 -18
  251. package/nitrogen/generated/android/c++/JVariant_ResolvedTrack_BrowseError_Promise_BrowseResult_.hpp +10 -4
  252. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{FavoritesMatchMode.kt → ArtworkRendering.kt} +5 -5
  253. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/CarPlayPlayingIndicatorLocation.kt +23 -0
  254. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/IOSOptions.kt +6 -3
  255. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NativeBrowserConfiguration.kt +5 -5
  256. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NitroIOSUpdateOptions.kt +6 -3
  257. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlayerCapabilities.kt +2 -2
  258. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ResolvedTrack.kt +12 -18
  259. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Section.kt +50 -0
  260. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{FavoriteConfig.kt → SectionStyle.kt} +12 -6
  261. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/StyleDisplay.kt +23 -0
  262. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Track.kt +6 -15
  263. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/TrackStyle.kt +23 -5
  264. package/nitrogen/generated/ios/AudioBrowser-Swift-Cxx-Bridge.hpp +104 -82
  265. package/nitrogen/generated/ios/AudioBrowser-Swift-Cxx-Umbrella.hpp +16 -10
  266. package/nitrogen/generated/ios/c++/HybridAudioBrowserSpecSwift.hpp +16 -10
  267. package/nitrogen/generated/ios/swift/ArtworkRendering.swift +40 -0
  268. package/nitrogen/generated/ios/swift/CarPlayPlayingIndicatorLocation.swift +40 -0
  269. package/nitrogen/generated/ios/swift/IOSOptions.swift +7 -2
  270. package/nitrogen/generated/ios/swift/NativeBrowserConfiguration.swift +5 -5
  271. package/nitrogen/generated/ios/swift/NitroIOSUpdateOptions.swift +12 -1
  272. package/nitrogen/generated/ios/swift/PlayerCapabilities.swift +8 -27
  273. package/nitrogen/generated/ios/swift/ResolvedTrack.swift +54 -83
  274. package/nitrogen/generated/ios/swift/Section.swift +100 -0
  275. package/nitrogen/generated/ios/swift/SectionStyle.swift +64 -0
  276. package/nitrogen/generated/ios/swift/StyleDisplay.swift +40 -0
  277. package/nitrogen/generated/ios/swift/Track.swift +20 -73
  278. package/nitrogen/generated/ios/swift/TrackStyle.swift +28 -22
  279. package/nitrogen/generated/shared/c++/{FavoritesMatchMode.hpp → ArtworkRendering.hpp} +17 -17
  280. package/nitrogen/generated/shared/c++/CarPlayPlayingIndicatorLocation.hpp +76 -0
  281. package/nitrogen/generated/shared/c++/IOSOptions.hpp +9 -2
  282. package/nitrogen/generated/shared/c++/NativeBrowserConfiguration.hpp +6 -6
  283. package/nitrogen/generated/shared/c++/NitroIOSUpdateOptions.hpp +9 -2
  284. package/nitrogen/generated/shared/c++/PlayerCapabilities.hpp +6 -9
  285. package/nitrogen/generated/shared/c++/ResolvedTrack.hpp +30 -38
  286. package/nitrogen/generated/shared/c++/Section.hpp +106 -0
  287. package/nitrogen/generated/shared/c++/SectionStyle.hpp +96 -0
  288. package/nitrogen/generated/shared/c++/StyleDisplay.hpp +76 -0
  289. package/nitrogen/generated/shared/c++/Track.hpp +15 -31
  290. package/nitrogen/generated/shared/c++/TrackStyle.hpp +50 -34
  291. package/package.json +3 -2
  292. package/src/AudioBrowser.ts +1 -0
  293. package/src/features/browser-config.test.ts +21 -6
  294. package/src/features/browser-config.ts +11 -8
  295. package/src/features/browser.test.ts +1 -1
  296. package/src/features/browser.ts +2 -2
  297. package/src/features/favorites.ts +13 -10
  298. package/src/features/hook-wiring.test.ts +63 -15
  299. package/src/features/playback/controls.ts +4 -2
  300. package/src/features/playback/state.ts +2 -3
  301. package/src/features/playback/trackPlaybackTime.ts +1 -1
  302. package/src/features/player/options.ts +27 -19
  303. package/src/features/player/setup.test.ts +12 -3
  304. package/src/features/player/setup.ts +3 -1
  305. package/src/features/player/validateOptions.ts +2 -0
  306. package/src/features/queue/activeTrack.ts +14 -3
  307. package/src/features/queue/queue.ts +11 -4
  308. package/src/nitro-stub-drift.test.ts +277 -0
  309. package/src/public-surface.test.ts +40 -0
  310. package/src/specs/audio-browser.nitro.ts +4 -3
  311. package/src/style-resolution.test.ts +139 -0
  312. package/src/types/browser-native.ts +2 -2
  313. package/src/types/browser-nodes.ts +268 -136
  314. package/src/types/browser.ts +34 -55
  315. package/src/utils/LazyNativeEmitter.ts +20 -10
  316. package/src/utils/NativeUpdatedValue.ts +29 -13
  317. package/src/utils/getTrackIdentity.ts +20 -0
  318. package/src/utils/useNativeValueRefreshedBy.ts +38 -0
  319. package/src/web/NativeAudioBrowser.ts +37 -22
  320. package/src/web/browser/BrowserManager.ts +176 -95
  321. package/src/web/browser/FavoriteManager.test.ts +84 -0
  322. package/src/web/browser/FavoriteManager.ts +28 -23
  323. package/src/web/browser/assertBrowsePageShape.test.ts +1 -1
  324. package/src/web/browser/assertBrowsePageShape.ts +5 -3
  325. package/src/web/browser/classifyTrackNavigation.test.ts +10 -8
  326. package/src/web/browser/classifyTrackNavigation.ts +9 -9
  327. package/src/web/browser/parseSearchResponse.test.ts +8 -2
  328. package/src/web/browser/sections.test.ts +91 -0
  329. package/src/web/browser/sections.ts +72 -0
  330. package/src/web/player/NowPlayingManager.ts +4 -3
  331. package/src/web/util/BrowserPathHelper.test.ts +52 -0
  332. package/src/web/util/BrowserPathHelper.ts +61 -13
  333. package/ios/CarPlay/ImageRowItem+CarPlay.swift +0 -19
  334. package/nitrogen/generated/android/c++/JFavoriteConfig.hpp +0 -58
  335. package/nitrogen/generated/android/c++/JImageRowItem.hpp +0 -105
  336. package/nitrogen/generated/android/c++/JVariant_Boolean_FavoriteConfig.cpp +0 -26
  337. package/nitrogen/generated/android/c++/JVariant_Boolean_FavoriteConfig.hpp +0 -71
  338. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ImageRowItem.kt +0 -68
  339. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Variant_Boolean_FavoriteConfig.kt +0 -53
  340. package/nitrogen/generated/ios/swift/FavoriteConfig.swift +0 -29
  341. package/nitrogen/generated/ios/swift/FavoritesMatchMode.swift +0 -40
  342. package/nitrogen/generated/ios/swift/ImageRowItem.swift +0 -195
  343. package/nitrogen/generated/ios/swift/Variant_Bool_FavoriteConfig.swift +0 -18
  344. package/nitrogen/generated/shared/c++/FavoriteConfig.hpp +0 -84
  345. package/nitrogen/generated/shared/c++/ImageRowItem.hpp +0 -129
@@ -1,18 +1,18 @@
1
1
  import Foundation
2
2
 
3
3
  /// A search result that may or may not be directly playable. `src` is the
4
- /// playable stream; `url` is a browsable container path. Abstracting these two
4
+ /// playable stream; `path` is a browsable container path. Abstracting these two
5
5
  /// fields keeps the drill-in decision free of the Nitro `Track` type so it can
6
6
  /// be unit-tested.
7
7
  protocol PlayableSearchItem {
8
8
  var src: String? { get }
9
- var url: String? { get }
9
+ var path: String? { get }
10
10
  }
11
11
 
12
12
  enum SearchDrillIn {
13
13
  /// Picks the playable items for a "play «X»" voice search.
14
14
  ///
15
- /// If the first result is browsable-only (a `url` container with no `src` — a
15
+ /// If the first result is browsable-only (a `path` container with no `src` — a
16
16
  /// place/genre page), drills into it via `resolveChildren` and uses its
17
17
  /// playable children, so we play the first station *inside* the page rather
18
18
  /// than skipping the page for a later inline station. Falls back to the flat
@@ -25,8 +25,8 @@ enum SearchDrillIn {
25
25
  guard !children.isEmpty else { return nil }
26
26
 
27
27
  let candidates: [Item]
28
- if let first = children.first, first.src == nil, let url = first.url {
29
- let drilled = try await resolveChildren(url).filter { $0.src != nil }
28
+ if let first = children.first, first.src == nil, let path = first.path {
29
+ let drilled = try await resolveChildren(path).filter { $0.src != nil }
30
30
  candidates = drilled.isEmpty ? children : drilled
31
31
  } else {
32
32
  candidates = children
@@ -37,7 +37,7 @@ enum SearchDrillIn {
37
37
  }
38
38
  }
39
39
 
40
- // The real Nitro `Track` already carries `src`/`url`; conform it for the app
40
+ // The real Nitro `Track` already carries `src`/`path`; conform it for the app
41
41
  // build. (The testable target builds without NitroModules and uses a stub item.)
42
42
  #if canImport(NitroModules)
43
43
  extension Track: PlayableSearchItem {}
@@ -0,0 +1,34 @@
1
+ #if canImport(NitroModules)
2
+ import NitroModules
3
+ #endif
4
+
5
+ /// The rendered form of a section — the single place where (resolved style,
6
+ /// platform capability) maps to what CarPlay draws. Degradation drops
7
+ /// decorations before layout (ADR 0011): a *wrapping* grid can only reach the
8
+ /// tile path where the platform has a wrapping tile container (CarPlay:
9
+ /// iOS 26+'s element API); without one it becomes a list, where every item
10
+ /// stays reachable instead of truncating at an unknowable width. A
11
+ /// single-line grid (`gridWrap: false`) renders everywhere — the legacy image
12
+ /// row IS the single-line presentation.
13
+ enum SectionPresentation: Equatable {
14
+ case list
15
+ case singleLineRow
16
+ case wrappingGrid
17
+
18
+ /// - Parameter supportsWrappingGrid: whether the platform has a wrapping
19
+ /// tile container. Injected (rather than read via `#available` here) so
20
+ /// the mapping is testable off-device.
21
+ init(for style: SectionStyle?, supportsWrappingGrid: Bool) {
22
+ guard style?.display == .grid else {
23
+ self = .list
24
+ return
25
+ }
26
+ if style?.gridWrap == false {
27
+ self = .singleLineRow
28
+ } else if supportsWrappingGrid {
29
+ self = .wrappingGrid
30
+ } else {
31
+ self = .list
32
+ }
33
+ }
34
+ }
@@ -1,35 +1,69 @@
1
1
  // Queue scope is the tapped section, not the whole page (ADR 0006): the
2
2
  // playback context a listener expects is the list they tapped in — a page
3
3
  // aggregating several sections must not leak next/previous across them.
4
+ // Sections are structural (ADR 0010), so scoping is a lookup, not a
5
+ // groupTitle-run derivation.
4
6
  enum SectionScope {
5
- enum Section {
6
- /// The tapped id lives inside an image row's items.
7
- case imageRow([ImageRowItem])
8
- /// The contiguous `groupTitle` run around the tapped child (items with
9
- /// no group title form runs of their own).
10
- case run([Track])
7
+ /// The section containing the tapped identity, plus the tapped child's
8
+ /// offset within it — non-nil only when the stamped flat index pinned the
9
+ /// exact copy.
10
+ struct Scoped {
11
+ let section: Section
12
+ let tappedOffset: Int?
11
13
  }
12
14
 
13
- /// The section of `children` containing the playable `trackId`, or nil
14
- /// when the id is not found.
15
- static func section(of children: [Track], containing trackId: String) -> Section? {
16
- for child in children {
17
- if let items = child.imageRow, items.contains(where: { $0.src == trackId }) {
18
- return .imageRow(items)
15
+ /// The section of `sections` containing the playable `trackId` (a track
16
+ /// identity: id when non-blank, else src), or nil when not found.
17
+ ///
18
+ /// `tappedIndex` — the flat page position stamped into the contextual URL
19
+ /// (children concatenated in section order) — is a tie-breaker, never an
20
+ /// identifier: when the child at that position still carries the tapped
21
+ /// identity, it pins which section (and which copy) was tapped; when it
22
+ /// doesn't (the list shifted), resolution falls back to the first section
23
+ /// containing the identity. A stale index can therefore never select a
24
+ /// different track — at worst a different copy of the same one.
25
+ static func scoped(
26
+ in sections: [Section],
27
+ containing trackId: String,
28
+ tappedIndex: Int? = nil,
29
+ ) -> Scoped? {
30
+ if let tappedIndex, tappedIndex >= 0 {
31
+ var start = 0
32
+ for section in sections {
33
+ let offset = tappedIndex - start
34
+ if offset < section.children.count {
35
+ if section.children[offset].identity == trackId {
36
+ return Scoped(section: section, tappedOffset: offset)
37
+ }
38
+ break
39
+ }
40
+ start += section.children.count
19
41
  }
20
42
  }
21
- guard let index = children.firstIndex(where: { $0.src == trackId }) else {
22
- return nil
23
- }
24
- let group = children[index].groupTitle
25
- var start = index
26
- while start > 0, children[start - 1].groupTitle == group {
27
- start -= 1
28
- }
29
- var end = index
30
- while end + 1 < children.count, children[end + 1].groupTitle == group {
31
- end += 1
43
+ for section in sections {
44
+ if section.children.contains(where: { $0.identity == trackId }) {
45
+ return Scoped(section: section, tappedOffset: nil)
46
+ }
32
47
  }
33
- return .run(Array(children[start ... end]))
48
+ return nil
49
+ }
50
+ }
51
+
52
+ // MARK: - Page shape helpers (ADR 0010)
53
+
54
+ extension ResolvedTrack {
55
+ /// The canonical sectioned shape: `sections` wins when present; plain
56
+ /// `children` is authoring sugar for one untitled section.
57
+ var normalizedSections: [Section]? {
58
+ if let sections { return sections }
59
+ guard let children else { return nil }
60
+ return [.untitled(children)]
61
+ }
62
+
63
+ /// The page's children concatenated in section order — the flattening
64
+ /// that defines contextual `__index` positions and the flat views (tabs,
65
+ /// search) of a sectioned page.
66
+ var flattenedChildren: [Track]? {
67
+ normalizedSections.map { $0.flatMap(\.children) }
34
68
  }
35
69
  }
@@ -0,0 +1,47 @@
1
+ #if canImport(NitroModules)
2
+ import NitroModules
3
+ #endif
4
+
5
+ /// The one place style declarations resolve to effective values (ADR 0011).
6
+ ///
7
+ /// Two mechanisms, deliberately distinct:
8
+ /// - **Inherited item properties** resolve `track ?? section ?? page`,
9
+ /// per property — a track's own declaration wins over the blocks that
10
+ /// contain it.
11
+ /// - **Container properties and the positional `display`** resolve by scope
12
+ /// override: `section ?? page` — the page declares for its whole scope, a
13
+ /// section overrides for its own children. `display` is never inherited
14
+ /// item-to-container: each holder describes its own children, and a
15
+ /// track's `display` is the promise for the page *it* opens, not its
16
+ /// rendering inside this section.
17
+ ///
18
+ /// Every key of `SectionStyle` must be read by `sectionStyle(section:page:)`
19
+ /// and every inherited key of `TrackStyle` by `trackStyle(track:section:)` —
20
+ /// Nitro flattens the spec's `extends`, so `src/style-resolution.test.ts`
21
+ /// enforces this completeness, not the type system.
22
+ enum StyleResolver {
23
+ /// Folds the page block into a section's block: every `SectionStyle` key
24
+ /// resolves `section ?? page`. The result is the section's effective
25
+ /// block; item resolution then only needs `track ?? section`.
26
+ static func sectionStyle(section: SectionStyle?, page: SectionStyle?) -> SectionStyle {
27
+ // Argument order is the generated init's (own properties before inherited
28
+ // ones — Nitro flattens `extends` own-props-first); the stub mirrors it.
29
+ SectionStyle(
30
+ gridWrap: section?.gridWrap ?? page?.gridWrap,
31
+ display: section?.display ?? page?.display,
32
+ artworkRendering: section?.artworkRendering ?? page?.artworkRendering,
33
+ )
34
+ }
35
+
36
+ /// Resolves a track's effective item properties against its (page-folded)
37
+ /// section block.
38
+ static func trackStyle(track: TrackStyle?, section: SectionStyle?) -> TrackStyle {
39
+ TrackStyle(
40
+ // Positional deny-list: `display` is never inherited onto an item —
41
+ // resolved nil, so no renderer can mistake the handle's page promise
42
+ // for this item's own layout.
43
+ display: nil,
44
+ artworkRendering: track?.artworkRendering ?? section?.artworkRendering,
45
+ )
46
+ }
47
+ }
@@ -1,6 +1,6 @@
1
1
  /// Compares the tab-list fields the CarPlay tab bar actually renders.
2
2
  enum TabBarEntries {
3
- /// Whether two tab lists produce identical tab-bar entries — title, url,
3
+ /// Whether two tab lists produce identical tab-bar entries — title, path,
4
4
  /// and the artwork inputs of `applyTabBarEntry`. Used to suppress
5
5
  /// `tabsChanged` when a tabs re-query (e.g. from `invalidateAllContent()`)
6
6
  /// resolves to the same entries, so an unchanged result never churns the
@@ -8,7 +8,7 @@ enum TabBarEntries {
8
8
  static func same(_ old: [Track]?, _ new: [Track]) -> Bool {
9
9
  guard let old, old.count == new.count else { return false }
10
10
  return zip(old, new).allSatisfy {
11
- $0.title == $1.title && $0.url == $1.url && $0.artwork == $1.artwork
11
+ $0.title == $1.title && $0.path == $1.path && $0.artwork == $1.artwork
12
12
  && $0.artworkSource?.uri == $1.artworkSource?.uri
13
13
  }
14
14
  }
@@ -0,0 +1,37 @@
1
+ import Foundation
2
+
3
+ /// `{id}` template-token substitution for request-config string values (path, query values,
4
+ /// header values), used by artwork URL resolution so a `nowPlayingArtwork` like
5
+ /// `{ path: "/artwork/{id}" }` resolves per track.
6
+ ///
7
+ /// A track without a non-blank id leaves the token LITERALLY in place — the request then
8
+ /// visibly 404s, which is intended (garbage in, garbage out with a self-describing error
9
+ /// trail; the caller logs a single warning when `containsToken` still matches after
10
+ /// substitution). Mirrors Android's `substituteTrackId` / `configContainsIdToken` in
11
+ /// `BrowserUrlResolution.kt` — keep the two in sync.
12
+ enum TrackIdTemplate {
13
+ static let token = "{id}"
14
+
15
+ /// Replaces the token when `id` is non-blank; otherwise returns the value unchanged
16
+ /// (token left literal).
17
+ static func substitute(_ value: String?, id: String?) -> String? {
18
+ guard let id, !id.isEmpty else { return value }
19
+ return value?.replacingOccurrences(of: token, with: id)
20
+ }
21
+
22
+ /// Dictionary-value variant of `substitute` (query / header values).
23
+ static func substitute(_ values: [String: String]?, id: String?) -> [String: String]? {
24
+ guard let id, !id.isEmpty else { return values }
25
+ return values?.mapValues { $0.replacingOccurrences(of: token, with: id) }
26
+ }
27
+
28
+ /// Whether the value still carries the token (an unfilled `{id}`).
29
+ static func containsToken(_ value: String?) -> Bool {
30
+ value?.contains(token) == true
31
+ }
32
+
33
+ /// Whether any dictionary value still carries the token.
34
+ static func containsToken(_ values: [String: String]?) -> Bool {
35
+ values?.values.contains { $0.contains(token) } == true
36
+ }
37
+ }
@@ -29,7 +29,8 @@ enum CarPlayArtworkResolver {
29
29
  /// - Parameters:
30
30
  /// - artwork: The track's `artwork` field (may be an SF Symbol string or URL)
31
31
  /// - artworkSourceUri: The track's `artworkSource?.uri` field
32
- /// - artworkCarPlayTinted: Whether to apply light/dark tinting
32
+ /// - stencil: Whether the artwork renders as a monochrome glyph tinted to
33
+ /// the surface appearance (`style.artworkRendering: 'stencil'`)
33
34
  /// - targetWidth: Target width in points
34
35
  /// - targetHeight: Target height in points
35
36
  /// - displayScale: The CarPlay display scale factor
@@ -37,7 +38,7 @@ enum CarPlayArtworkResolver {
37
38
  static func resolve(
38
39
  artwork: String?,
39
40
  artworkSourceUri: String?,
40
- artworkCarPlayTinted: Bool?,
41
+ stencil: Bool,
41
42
  targetWidth: Double,
42
43
  targetHeight: Double,
43
44
  displayScale: Double,
@@ -57,7 +58,7 @@ enum CarPlayArtworkResolver {
57
58
  return resolveDirectFallback(
58
59
  artwork: artwork,
59
60
  artworkSourceUri: artworkSourceUri,
60
- artworkCarPlayTinted: artworkCarPlayTinted,
61
+ stencil: stencil,
61
62
  targetWidth: targetWidth,
62
63
  targetHeight: targetHeight,
63
64
  )
@@ -66,7 +67,7 @@ enum CarPlayArtworkResolver {
66
67
  return .fetch(
67
68
  uri: resolved.uri,
68
69
  headers: resolved.headers,
69
- shouldTint: artworkCarPlayTinted ?? false,
70
+ shouldTint: stencil,
70
71
  isSvg: isSvg,
71
72
  )
72
73
  }
@@ -76,7 +77,7 @@ enum CarPlayArtworkResolver {
76
77
  return resolveDirectFallback(
77
78
  artwork: artwork,
78
79
  artworkSourceUri: artworkSourceUri,
79
- artworkCarPlayTinted: artworkCarPlayTinted,
80
+ stencil: stencil,
80
81
  targetWidth: targetWidth,
81
82
  targetHeight: targetHeight,
82
83
  )
@@ -85,7 +86,7 @@ enum CarPlayArtworkResolver {
85
86
  private static func resolveDirectFallback(
86
87
  artwork: String?,
87
88
  artworkSourceUri: String?,
88
- artworkCarPlayTinted: Bool?,
89
+ stencil: Bool,
89
90
  targetWidth: Double,
90
91
  targetHeight: Double,
91
92
  ) -> ArtworkLoadAction {
@@ -100,7 +101,7 @@ enum CarPlayArtworkResolver {
100
101
  return .fetch(
101
102
  uri: directUri,
102
103
  headers: nil,
103
- shouldTint: artworkCarPlayTinted ?? false,
104
+ shouldTint: stencil,
104
105
  isSvg: isSvg,
105
106
  )
106
107
  }