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.
- package/README.md +14 -4
- package/android/build.gradle +20 -1
- package/android/src/main/java/com/audiobrowser/AudioBrowser.kt +115 -26
- package/android/src/main/java/com/audiobrowser/browser/BrowserManager.kt +262 -188
- package/android/src/main/java/com/audiobrowser/browser/BrowserUrlResolution.kt +23 -3
- package/android/src/main/java/com/audiobrowser/browser/InertStyleDiagnostic.kt +267 -0
- package/android/src/main/java/com/audiobrowser/browser/JsonModels.kt +95 -58
- package/android/src/main/java/com/audiobrowser/browser/SectionScope.kt +68 -26
- package/android/src/main/java/com/audiobrowser/browser/StyleResolver.kt +60 -0
- package/android/src/main/java/com/audiobrowser/extension/ResolvedTrackExt.kt +19 -7
- package/android/src/main/java/com/audiobrowser/extension/TappedTrack.kt +20 -0
- package/android/src/main/java/com/audiobrowser/extension/TrackIdentity.kt +15 -0
- package/android/src/main/java/com/audiobrowser/model/PlayerUpdateOptions.kt +1 -1
- package/android/src/main/java/com/audiobrowser/player/MediaSessionCallback.kt +120 -67
- package/android/src/main/java/com/audiobrowser/player/NowPlayingUpdater.kt +21 -24
- package/android/src/main/java/com/audiobrowser/player/PlaybackStateStore.kt +109 -74
- package/android/src/main/java/com/audiobrowser/player/Player.kt +51 -30
- package/android/src/main/java/com/audiobrowser/player/PlayerCapabilitiesExt.kt +2 -15
- package/android/src/main/java/com/audiobrowser/player/ShuffleOrderLedBy.kt +30 -0
- package/android/src/main/java/com/audiobrowser/util/BrowserPathHelper.kt +44 -40
- package/android/src/main/java/com/audiobrowser/util/MediaExtrasBuilder.kt +28 -23
- package/android/src/main/java/com/audiobrowser/util/StyleWire.kt +108 -0
- package/android/src/main/java/com/audiobrowser/util/TrackFactory.kt +52 -53
- package/android/src/test/java/com/audiobrowser/TestFixtures.kt +74 -41
- package/android/src/test/java/com/audiobrowser/browser/BrowserManagerFavoritesTest.kt +153 -0
- package/android/src/test/java/com/audiobrowser/browser/BrowserManagerTest.kt +229 -50
- package/android/src/test/java/com/audiobrowser/browser/BrowserUrlResolutionTest.kt +38 -0
- package/android/src/test/java/com/audiobrowser/browser/InertStyleDiagnosticTest.kt +277 -0
- package/android/src/test/java/com/audiobrowser/browser/JsonArtworkTest.kt +1 -1
- package/android/src/test/java/com/audiobrowser/browser/JsonStyleTest.kt +147 -0
- package/android/src/test/java/com/audiobrowser/browser/SectionScopeTest.kt +128 -53
- package/android/src/test/java/com/audiobrowser/browser/StyleResolverTest.kt +154 -0
- package/android/src/test/java/com/audiobrowser/extension/TappedTrackTest.kt +43 -0
- package/android/src/test/java/com/audiobrowser/extension/TrackIdentityTest.kt +41 -0
- package/android/src/test/java/com/audiobrowser/player/CapabilityControlsTest.kt +1 -2
- package/android/src/test/java/com/audiobrowser/player/NowPlayingUpdaterTest.kt +42 -2
- package/android/src/test/java/com/audiobrowser/player/PlaybackStateStoreTrackJsonTest.kt +55 -0
- package/android/src/test/java/com/audiobrowser/player/ShuffleOrderLedByTest.kt +79 -0
- package/android/src/test/java/com/audiobrowser/util/BrowserPathHelperTest.kt +41 -16
- package/android/src/test/java/com/audiobrowser/util/MediaExtrasBuilderTest.kt +161 -0
- package/android/src/test/java/com/audiobrowser/util/TrackFactoryMediaIdTest.kt +7 -7
- package/ios/Browser/BrowserConfig.swift +102 -5
- package/ios/Browser/BrowserManager+URLResolution.swift +18 -14
- package/ios/Browser/BrowserManager.swift +229 -180
- package/ios/Browser/BrowserPathHelper.swift +44 -44
- package/ios/Browser/InertStyleDiagnostic.swift +279 -0
- package/ios/Browser/JsonModels.swift +258 -106
- package/ios/Browser/SearchDrillIn.swift +6 -6
- package/ios/Browser/SectionPresentation.swift +64 -0
- package/ios/Browser/SectionScope.swift +58 -24
- package/ios/Browser/StyleResolver.swift +58 -0
- package/ios/Browser/TabBarEntries.swift +9 -3
- package/ios/Browser/TrackIdTemplate.swift +37 -0
- package/ios/CarPlay/CarPlayArtworkResolver.swift +8 -7
- package/ios/CarPlay/CarPlayController.swift +227 -85
- package/ios/CarPlay/CarPlayImageLoader.swift +38 -18
- package/ios/CarPlay/CarPlayListItemFactory.swift +289 -84
- package/ios/CarPlay/CarPlayNowPlayingManager.swift +15 -12
- package/ios/Extension/Capability+RemoteCommand.swift +1 -1
- package/ios/Extension/PlayerCapabilities+Favorite.swift +1 -15
- package/ios/Extension/ResolvedTrack+Copying.swift +11 -15
- package/ios/Extension/Section+Copying.swift +31 -0
- package/ios/Extension/Track+Copying.swift +6 -12
- package/ios/Extension/Track+Identity.swift +18 -0
- package/ios/Extension/UIApplication+ActiveScene.swift +27 -0
- package/ios/Http/HttpClient.swift +8 -2
- package/ios/HybridAudioBrowser.swift +166 -45
- package/ios/Model/NitroTypeStubs.swift +106 -21
- package/ios/Model/PlayerUpdateOptions.swift +7 -0
- package/ios/Player/MediaIntentCriteria.swift +13 -5
- package/ios/Player/MediaLoader.swift +33 -9
- package/ios/Player/NowPlayingUpdater.swift +54 -6
- package/ios/Player/PlaybackCoordinator.swift +13 -6
- package/ios/Player/PlaybackTimer.swift +8 -2
- package/ios/Player/QueueManager.swift +36 -10
- package/ios/Player/RetryManager.swift +4 -3
- package/ios/Player/ShuffleOrder.swift +23 -0
- package/ios/Player/SleepTimerHandling.swift +13 -0
- package/ios/RemoteCommand/RemoteCommandController.swift +53 -18
- package/ios/Tests/BrowserPathHelperTests.swift +50 -20
- package/ios/Tests/CarPlayArtworkResolverTests.swift +24 -41
- package/ios/Tests/InertStyleDiagnosticTests.swift +200 -0
- package/ios/Tests/JsonModelsTests.swift +150 -1
- package/ios/Tests/PlaybackStateStoreTests.swift +4 -3
- package/ios/Tests/QueueManagerTests.swift +72 -6
- package/ios/Tests/RemoteCommandControllerTests.swift +16 -0
- package/ios/Tests/ResolvedTrackCopyingTests.swift +37 -35
- package/ios/Tests/SearchDrillInTests.swift +16 -16
- package/ios/Tests/SectionPresentationTests.swift +90 -0
- package/ios/Tests/SectionScopeTests.swift +87 -55
- package/ios/Tests/StyleResolverTests.swift +127 -0
- package/ios/Tests/Support/TestTypes.swift +7 -0
- package/ios/Tests/TabBarEntriesTests.swift +18 -18
- package/ios/Tests/TrackIdTemplateTests.swift +67 -0
- package/ios/Tests/TrackIdentityTests.swift +20 -0
- package/ios/Tests/TrackSelectorTests.swift +168 -33
- package/ios/TrackPlayer.swift +57 -34
- package/ios/TrackSelector.swift +45 -30
- package/ios/Util/ArtworkImageFetcher.swift +16 -1
- package/ios/Util/NetworkMonitor.swift +43 -26
- package/ios/Util/SFSymbolRenderer.swift +24 -2
- package/ios/Util/SVGProcessor.swift +9 -2
- package/lib/commonjs/AudioBrowser.js +11 -0
- package/lib/commonjs/AudioBrowser.js.map +1 -1
- package/lib/commonjs/features/browser-config.js +11 -8
- package/lib/commonjs/features/browser-config.js.map +1 -1
- package/lib/commonjs/features/browser.js +2 -2
- package/lib/commonjs/features/favorites.js +13 -10
- package/lib/commonjs/features/favorites.js.map +1 -1
- package/lib/commonjs/features/playback/controls.js +4 -2
- package/lib/commonjs/features/playback/controls.js.map +1 -1
- package/lib/commonjs/features/playback/progress.js +2 -1
- package/lib/commonjs/features/playback/progress.js.map +1 -1
- package/lib/commonjs/features/playback/rate.js +8 -1
- package/lib/commonjs/features/playback/rate.js.map +1 -1
- package/lib/commonjs/features/playback/state.js +2 -3
- package/lib/commonjs/features/playback/state.js.map +1 -1
- package/lib/commonjs/features/player/options.js.map +1 -1
- package/lib/commonjs/features/player/setup.js +3 -1
- package/lib/commonjs/features/player/setup.js.map +1 -1
- package/lib/commonjs/features/player/validateOptions.js +2 -0
- package/lib/commonjs/features/player/validateOptions.js.map +1 -1
- package/lib/commonjs/features/queue/activeTrack.js +14 -3
- package/lib/commonjs/features/queue/activeTrack.js.map +1 -1
- package/lib/commonjs/features/queue/queue.js +11 -4
- package/lib/commonjs/features/queue/queue.js.map +1 -1
- package/lib/commonjs/utils/LazyNativeEmitter.js +21 -10
- package/lib/commonjs/utils/LazyNativeEmitter.js.map +1 -1
- package/lib/commonjs/utils/NativeUpdatedValue.js +31 -13
- package/lib/commonjs/utils/NativeUpdatedValue.js.map +1 -1
- package/lib/commonjs/utils/getTrackIdentity.js +24 -0
- package/lib/commonjs/utils/getTrackIdentity.js.map +1 -0
- package/lib/commonjs/utils/useNativeValueRefreshedBy.js +33 -0
- package/lib/commonjs/utils/useNativeValueRefreshedBy.js.map +1 -0
- package/lib/commonjs/web/NativeAudioBrowser.js +32 -24
- package/lib/commonjs/web/NativeAudioBrowser.js.map +1 -1
- package/lib/commonjs/web/TrackPlayer/QueueManager.js +14 -0
- package/lib/commonjs/web/TrackPlayer/QueueManager.js.map +1 -1
- package/lib/commonjs/web/browser/BrowserManager.js +144 -87
- package/lib/commonjs/web/browser/BrowserManager.js.map +1 -1
- package/lib/commonjs/web/browser/FavoriteManager.js +30 -21
- package/lib/commonjs/web/browser/FavoriteManager.js.map +1 -1
- package/lib/commonjs/web/browser/assertBrowsePageShape.js +2 -2
- package/lib/commonjs/web/browser/assertBrowsePageShape.js.map +1 -1
- package/lib/commonjs/web/browser/classifyTrackNavigation.js +9 -9
- package/lib/commonjs/web/browser/classifyTrackNavigation.js.map +1 -1
- package/lib/commonjs/web/browser/sections.js +89 -0
- package/lib/commonjs/web/browser/sections.js.map +1 -0
- package/lib/commonjs/web/player/NowPlayingManager.js +4 -3
- package/lib/commonjs/web/player/NowPlayingManager.js.map +1 -1
- package/lib/commonjs/web/util/BrowserPathHelper.js +56 -11
- package/lib/commonjs/web/util/BrowserPathHelper.js.map +1 -1
- package/lib/module/AudioBrowser.js +1 -0
- package/lib/module/AudioBrowser.js.map +1 -1
- package/lib/module/features/browser-config.js +11 -8
- package/lib/module/features/browser-config.js.map +1 -1
- package/lib/module/features/browser.js +2 -2
- package/lib/module/features/favorites.js +13 -10
- package/lib/module/features/favorites.js.map +1 -1
- package/lib/module/features/playback/controls.js +4 -2
- package/lib/module/features/playback/controls.js.map +1 -1
- package/lib/module/features/playback/progress.js +2 -1
- package/lib/module/features/playback/progress.js.map +1 -1
- package/lib/module/features/playback/rate.js +8 -1
- package/lib/module/features/playback/rate.js.map +1 -1
- package/lib/module/features/playback/state.js +2 -3
- package/lib/module/features/playback/state.js.map +1 -1
- package/lib/module/features/player/options.js.map +1 -1
- package/lib/module/features/player/setup.js +3 -1
- package/lib/module/features/player/setup.js.map +1 -1
- package/lib/module/features/player/validateOptions.js +2 -0
- package/lib/module/features/player/validateOptions.js.map +1 -1
- package/lib/module/features/queue/activeTrack.js +14 -3
- package/lib/module/features/queue/activeTrack.js.map +1 -1
- package/lib/module/features/queue/queue.js +11 -4
- package/lib/module/features/queue/queue.js.map +1 -1
- package/lib/module/utils/LazyNativeEmitter.js +21 -10
- package/lib/module/utils/LazyNativeEmitter.js.map +1 -1
- package/lib/module/utils/NativeUpdatedValue.js +31 -13
- package/lib/module/utils/NativeUpdatedValue.js.map +1 -1
- package/lib/module/utils/getTrackIdentity.js +20 -0
- package/lib/module/utils/getTrackIdentity.js.map +1 -0
- package/lib/module/utils/useNativeValueRefreshedBy.js +29 -0
- package/lib/module/utils/useNativeValueRefreshedBy.js.map +1 -0
- package/lib/module/web/NativeAudioBrowser.js +32 -24
- package/lib/module/web/NativeAudioBrowser.js.map +1 -1
- package/lib/module/web/TrackPlayer/QueueManager.js +14 -0
- package/lib/module/web/TrackPlayer/QueueManager.js.map +1 -1
- package/lib/module/web/browser/BrowserManager.js +144 -87
- package/lib/module/web/browser/BrowserManager.js.map +1 -1
- package/lib/module/web/browser/FavoriteManager.js +31 -21
- package/lib/module/web/browser/FavoriteManager.js.map +1 -1
- package/lib/module/web/browser/assertBrowsePageShape.js +2 -2
- package/lib/module/web/browser/assertBrowsePageShape.js.map +1 -1
- package/lib/module/web/browser/classifyTrackNavigation.js +9 -9
- package/lib/module/web/browser/classifyTrackNavigation.js.map +1 -1
- package/lib/module/web/browser/sections.js +83 -0
- package/lib/module/web/browser/sections.js.map +1 -0
- package/lib/module/web/player/NowPlayingManager.js +4 -3
- package/lib/module/web/player/NowPlayingManager.js.map +1 -1
- package/lib/module/web/util/BrowserPathHelper.js +56 -11
- package/lib/module/web/util/BrowserPathHelper.js.map +1 -1
- package/lib/typescript/src/AudioBrowser.d.ts +1 -0
- package/lib/typescript/src/AudioBrowser.d.ts.map +1 -1
- package/lib/typescript/src/features/browser-config.d.ts.map +1 -1
- package/lib/typescript/src/features/browser.d.ts +2 -2
- package/lib/typescript/src/features/favorites.d.ts +13 -10
- package/lib/typescript/src/features/favorites.d.ts.map +1 -1
- package/lib/typescript/src/features/playback/controls.d.ts +4 -2
- package/lib/typescript/src/features/playback/controls.d.ts.map +1 -1
- package/lib/typescript/src/features/playback/progress.d.ts.map +1 -1
- package/lib/typescript/src/features/playback/rate.d.ts +8 -1
- package/lib/typescript/src/features/playback/rate.d.ts.map +1 -1
- package/lib/typescript/src/features/playback/state.d.ts +2 -3
- package/lib/typescript/src/features/playback/state.d.ts.map +1 -1
- package/lib/typescript/src/features/playback/trackPlaybackTime.d.ts +1 -1
- package/lib/typescript/src/features/playback/trackPlaybackTime.d.ts.map +1 -1
- package/lib/typescript/src/features/player/options.d.ts +21 -19
- package/lib/typescript/src/features/player/options.d.ts.map +1 -1
- package/lib/typescript/src/features/player/setup.d.ts.map +1 -1
- package/lib/typescript/src/features/player/validateOptions.d.ts +1 -8
- package/lib/typescript/src/features/player/validateOptions.d.ts.map +1 -1
- package/lib/typescript/src/features/queue/activeTrack.d.ts +8 -1
- package/lib/typescript/src/features/queue/activeTrack.d.ts.map +1 -1
- package/lib/typescript/src/features/queue/queue.d.ts +5 -2
- package/lib/typescript/src/features/queue/queue.d.ts.map +1 -1
- package/lib/typescript/src/types/browser-native.d.ts +2 -2
- package/lib/typescript/src/types/browser-native.d.ts.map +1 -1
- package/lib/typescript/src/types/browser-nodes.d.ts +361 -126
- package/lib/typescript/src/types/browser-nodes.d.ts.map +1 -1
- package/lib/typescript/src/types/browser.d.ts +33 -53
- package/lib/typescript/src/types/browser.d.ts.map +1 -1
- package/lib/typescript/src/utils/LazyNativeEmitter.d.ts +16 -17
- package/lib/typescript/src/utils/LazyNativeEmitter.d.ts.map +1 -1
- package/lib/typescript/src/utils/NativeUpdatedValue.d.ts +24 -19
- package/lib/typescript/src/utils/NativeUpdatedValue.d.ts.map +1 -1
- package/lib/typescript/src/utils/getTrackIdentity.d.ts +18 -0
- package/lib/typescript/src/utils/getTrackIdentity.d.ts.map +1 -0
- package/lib/typescript/src/utils/useNativeValueRefreshedBy.d.ts +21 -0
- package/lib/typescript/src/utils/useNativeValueRefreshedBy.d.ts.map +1 -0
- package/nitrogen/generated/android/AudioBrowser+autolinking.cmake +0 -1
- package/nitrogen/generated/android/c++/{JFavoritesMatchMode.hpp → JArtworkRendering.hpp} +15 -15
- package/nitrogen/generated/android/c++/JArtworkRequestConfig.hpp +8 -3
- package/nitrogen/generated/android/c++/JBrowseResult.hpp +16 -4
- package/nitrogen/generated/android/c++/JCarPlayPlayingIndicatorLocation.hpp +58 -0
- package/nitrogen/generated/android/c++/JCardImage.hpp +58 -0
- package/nitrogen/generated/android/c++/JFavoriteChangedEvent.hpp +8 -3
- package/nitrogen/generated/android/c++/JFormatNowPlayingParams.hpp +8 -3
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_RequestConfig___Track.hpp +8 -3
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__optional_NowPlayingUpdate____FormatNowPlayingParams.hpp +8 -3
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__optional_std__string____Track.hpp +8 -3
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____Track.hpp +8 -3
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_std__vector_Track______SearchParams.hpp +8 -2
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_void_____TrackLoadEvent.hpp +8 -2
- 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
- package/nitrogen/generated/android/c++/JFunc_void_FavoriteChangedEvent.hpp +8 -3
- package/nitrogen/generated/android/c++/JFunc_void_Options.hpp +2 -5
- package/nitrogen/generated/android/c++/JFunc_void_PlaybackActiveTrackChangedEvent.hpp +8 -3
- package/nitrogen/generated/android/c++/JFunc_void_std__optional_ResolvedTrack_.hpp +15 -3
- package/nitrogen/generated/android/c++/JFunc_void_std__vector_Track_.hpp +8 -2
- package/nitrogen/generated/android/c++/JGridTile.hpp +61 -0
- package/nitrogen/generated/android/c++/JHybridAudioBrowserSpec.cpp +33 -14
- package/nitrogen/generated/android/c++/JIOSOptions.hpp +9 -3
- package/nitrogen/generated/android/c++/JImageShape.hpp +58 -0
- package/nitrogen/generated/android/c++/JMediaRequestConfig.hpp +8 -3
- package/nitrogen/generated/android/c++/JNativeBrowserConfiguration.hpp +22 -10
- package/nitrogen/generated/android/c++/JNativeRouteEntry.hpp +14 -2
- package/nitrogen/generated/android/c++/JNativeSetupPlayerOptions.hpp +10 -7
- package/nitrogen/generated/android/c++/JNativeUpdateOptions.hpp +2 -5
- package/nitrogen/generated/android/c++/JNitroIOSUpdateOptions.hpp +9 -3
- package/nitrogen/generated/android/c++/JOptions.hpp +2 -5
- package/nitrogen/generated/android/c++/JPlaybackActiveTrackChangedEvent.hpp +8 -3
- package/nitrogen/generated/android/c++/JPlayerCapabilities.hpp +5 -11
- package/nitrogen/generated/android/c++/JResolvedTrack.hpp +55 -51
- package/nitrogen/generated/android/c++/JSection.hpp +120 -0
- package/nitrogen/generated/android/c++/JSectionStyle.hpp +96 -0
- package/nitrogen/generated/android/c++/JStyleDisplay.hpp +58 -0
- package/nitrogen/generated/android/c++/JTrack.hpp +23 -48
- package/nitrogen/generated/android/c++/JTrackLoadEvent.hpp +8 -2
- package/nitrogen/generated/android/c++/JTrackStyle.hpp +46 -18
- package/nitrogen/generated/android/c++/JVariant_ResolvedTrack_BrowseError_Promise_BrowseResult_.hpp +16 -4
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{FavoritesMatchMode.kt → ArtworkRendering.kt} +5 -5
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/CarPlayPlayingIndicatorLocation.kt +23 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/CardImage.kt +23 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/GridTile.kt +24 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/IOSOptions.kt +6 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ImageShape.kt +23 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NativeBrowserConfiguration.kt +5 -5
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NitroIOSUpdateOptions.kt +6 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlayerCapabilities.kt +2 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ResolvedTrack.kt +12 -18
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{FavoriteConfig.kt → Section.kt} +18 -6
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/SectionStyle.kt +59 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/StyleDisplay.kt +23 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Track.kt +6 -15
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/TrackStyle.kt +35 -5
- package/nitrogen/generated/ios/AudioBrowser-Swift-Cxx-Bridge.hpp +158 -82
- package/nitrogen/generated/ios/AudioBrowser-Swift-Cxx-Umbrella.hpp +25 -10
- package/nitrogen/generated/ios/c++/HybridAudioBrowserSpecSwift.hpp +25 -10
- package/nitrogen/generated/ios/swift/ArtworkRendering.swift +40 -0
- package/nitrogen/generated/ios/swift/CarPlayPlayingIndicatorLocation.swift +40 -0
- package/nitrogen/generated/ios/swift/CardImage.swift +40 -0
- package/nitrogen/generated/ios/swift/GridTile.swift +44 -0
- package/nitrogen/generated/ios/swift/IOSOptions.swift +7 -2
- package/nitrogen/generated/ios/swift/ImageShape.swift +40 -0
- package/nitrogen/generated/ios/swift/NativeBrowserConfiguration.swift +5 -5
- package/nitrogen/generated/ios/swift/NitroIOSUpdateOptions.swift +12 -1
- package/nitrogen/generated/ios/swift/PlayerCapabilities.swift +8 -27
- package/nitrogen/generated/ios/swift/ResolvedTrack.swift +54 -83
- package/nitrogen/generated/ios/swift/Section.swift +100 -0
- package/nitrogen/generated/ios/swift/SectionStyle.swift +133 -0
- package/nitrogen/generated/ios/swift/StyleDisplay.swift +40 -0
- package/nitrogen/generated/ios/swift/Track.swift +20 -73
- package/nitrogen/generated/ios/swift/TrackStyle.swift +86 -22
- package/nitrogen/generated/shared/c++/{FavoritesMatchMode.hpp → ArtworkRendering.hpp} +17 -17
- package/nitrogen/generated/shared/c++/CarPlayPlayingIndicatorLocation.hpp +76 -0
- package/nitrogen/generated/shared/c++/CardImage.hpp +76 -0
- package/nitrogen/generated/shared/c++/GridTile.hpp +80 -0
- package/nitrogen/generated/shared/c++/IOSOptions.hpp +9 -2
- package/nitrogen/generated/shared/c++/ImageShape.hpp +76 -0
- package/nitrogen/generated/shared/c++/NativeBrowserConfiguration.hpp +6 -6
- package/nitrogen/generated/shared/c++/NitroIOSUpdateOptions.hpp +9 -2
- package/nitrogen/generated/shared/c++/PlayerCapabilities.hpp +6 -9
- package/nitrogen/generated/shared/c++/ResolvedTrack.hpp +30 -38
- package/nitrogen/generated/shared/c++/Section.hpp +106 -0
- package/nitrogen/generated/shared/c++/SectionStyle.hpp +126 -0
- package/nitrogen/generated/shared/c++/StyleDisplay.hpp +76 -0
- package/nitrogen/generated/shared/c++/Track.hpp +15 -31
- package/nitrogen/generated/shared/c++/TrackStyle.hpp +73 -34
- package/package.json +7 -2
- package/src/AudioBrowser.ts +1 -0
- package/src/features/browser-config.test.ts +21 -6
- package/src/features/browser-config.ts +11 -8
- package/src/features/browser.test.ts +1 -1
- package/src/features/browser.ts +2 -2
- package/src/features/favorites.ts +13 -10
- package/src/features/hook-wiring.test.ts +63 -15
- package/src/features/playback/controls.ts +4 -2
- package/src/features/playback/progress.ts +2 -1
- package/src/features/playback/rate.ts +8 -1
- package/src/features/playback/state.ts +2 -3
- package/src/features/playback/trackPlaybackTime.ts +1 -1
- package/src/features/player/options.ts +27 -19
- package/src/features/player/setup.test.ts +12 -3
- package/src/features/player/setup.ts +3 -1
- package/src/features/player/validateOptions.ts +2 -0
- package/src/features/queue/activeTrack.ts +14 -3
- package/src/features/queue/queue.ts +11 -4
- package/src/nitro-stub-drift.test.ts +40 -0
- package/src/public-surface.test.ts +40 -0
- package/src/specs/audio-browser.nitro.ts +4 -3
- package/src/style-resolution.test.ts +210 -0
- package/src/types/browser-native.ts +2 -2
- package/src/types/browser-nodes.ts +377 -135
- package/src/types/browser.ts +34 -55
- package/src/utils/LazyNativeEmitter.ts +20 -10
- package/src/utils/NativeUpdatedValue.ts +29 -13
- package/src/utils/getTrackIdentity.ts +20 -0
- package/src/utils/useNativeValueRefreshedBy.ts +38 -0
- package/src/web/NativeAudioBrowser.ts +37 -22
- package/src/web/TrackPlayer/QueueManager.test.ts +29 -0
- package/src/web/TrackPlayer/QueueManager.ts +14 -0
- package/src/web/browser/BrowserManager.ts +176 -95
- package/src/web/browser/FavoriteManager.test.ts +84 -0
- package/src/web/browser/FavoriteManager.ts +28 -23
- package/src/web/browser/assertBrowsePageShape.test.ts +1 -1
- package/src/web/browser/assertBrowsePageShape.ts +5 -3
- package/src/web/browser/classifyTrackNavigation.test.ts +10 -8
- package/src/web/browser/classifyTrackNavigation.ts +9 -9
- package/src/web/browser/parseSearchResponse.test.ts +8 -2
- package/src/web/browser/sections.test.ts +91 -0
- package/src/web/browser/sections.ts +72 -0
- package/src/web/player/NowPlayingManager.ts +4 -3
- package/src/web/util/BrowserPathHelper.test.ts +52 -0
- package/src/web/util/BrowserPathHelper.ts +61 -13
- package/website/guide/android-auto.md +114 -0
- package/website/guide/android-certificates.md +409 -0
- package/website/guide/artwork.md +255 -0
- package/website/guide/audio-output.md +135 -0
- package/website/guide/automotive.md +86 -0
- package/website/guide/basic-usage.md +151 -0
- package/website/guide/battery.md +115 -0
- package/website/guide/browser.md +581 -0
- package/website/guide/carplay.md +620 -0
- package/website/guide/configuration.md +173 -0
- package/website/guide/equalizer.md +231 -0
- package/website/guide/errors.md +310 -0
- package/website/guide/favorites.md +154 -0
- package/website/guide/gate.md +143 -0
- package/website/guide/getting-started.md +46 -0
- package/website/guide/hooks.md +238 -0
- package/website/guide/live-streams.md +125 -0
- package/website/guide/metadata.md +239 -0
- package/website/guide/migrating-from-track-player.md +244 -0
- package/website/guide/native-callback-fetch.md +127 -0
- package/website/guide/network.md +86 -0
- package/website/guide/now-playing.md +175 -0
- package/website/guide/playback.md +328 -0
- package/website/guide/queue.md +300 -0
- package/website/guide/remote-controls.md +256 -0
- package/website/guide/search.md +255 -0
- package/website/guide/sleep-timer.md +268 -0
- package/website/guide/track.md +246 -0
- package/ios/CarPlay/ImageRowItem+CarPlay.swift +0 -19
- package/nitrogen/generated/android/c++/JFavoriteConfig.hpp +0 -58
- package/nitrogen/generated/android/c++/JImageRowItem.hpp +0 -105
- package/nitrogen/generated/android/c++/JVariant_Boolean_FavoriteConfig.cpp +0 -26
- package/nitrogen/generated/android/c++/JVariant_Boolean_FavoriteConfig.hpp +0 -71
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ImageRowItem.kt +0 -68
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Variant_Boolean_FavoriteConfig.kt +0 -53
- package/nitrogen/generated/ios/swift/FavoriteConfig.swift +0 -29
- package/nitrogen/generated/ios/swift/FavoritesMatchMode.swift +0 -40
- package/nitrogen/generated/ios/swift/ImageRowItem.swift +0 -195
- package/nitrogen/generated/ios/swift/Variant_Bool_FavoriteConfig.swift +0 -18
- package/nitrogen/generated/shared/c++/FavoriteConfig.hpp +0 -84
- package/nitrogen/generated/shared/c++/ImageRowItem.hpp +0 -129
|
@@ -35,9 +35,7 @@ namespace margelo::nitro::audiobrowser { struct ImageSource; }
|
|
|
35
35
|
// Forward declaration of `TrackRequest` to properly resolve imports.
|
|
36
36
|
namespace margelo::nitro::audiobrowser { struct TrackRequest; }
|
|
37
37
|
// Forward declaration of `TrackStyle` to properly resolve imports.
|
|
38
|
-
namespace margelo::nitro::audiobrowser {
|
|
39
|
-
// Forward declaration of `ImageRowItem` to properly resolve imports.
|
|
40
|
-
namespace margelo::nitro::audiobrowser { struct ImageRowItem; }
|
|
38
|
+
namespace margelo::nitro::audiobrowser { struct TrackStyle; }
|
|
41
39
|
|
|
42
40
|
#include <string>
|
|
43
41
|
#include <optional>
|
|
@@ -46,8 +44,6 @@ namespace margelo::nitro::audiobrowser { struct ImageRowItem; }
|
|
|
46
44
|
#include "ImageSource.hpp"
|
|
47
45
|
#include "TrackRequest.hpp"
|
|
48
46
|
#include "TrackStyle.hpp"
|
|
49
|
-
#include "ImageRowItem.hpp"
|
|
50
|
-
#include <vector>
|
|
51
47
|
|
|
52
48
|
namespace margelo::nitro::audiobrowser {
|
|
53
49
|
|
|
@@ -57,30 +53,27 @@ namespace margelo::nitro::audiobrowser {
|
|
|
57
53
|
struct Track final {
|
|
58
54
|
public:
|
|
59
55
|
std::optional<std::string> id SWIFT_PRIVATE;
|
|
60
|
-
std::optional<std::string>
|
|
56
|
+
std::optional<std::string> path SWIFT_PRIVATE;
|
|
61
57
|
std::optional<std::string> src SWIFT_PRIVATE;
|
|
62
58
|
std::optional<std::variant<std::string, ArtworkVariants>> artwork SWIFT_PRIVATE;
|
|
63
59
|
std::optional<ImageSource> artworkSource SWIFT_PRIVATE;
|
|
64
60
|
std::optional<TrackRequest> request SWIFT_PRIVATE;
|
|
65
|
-
std::optional<bool> artworkCarPlayTinted SWIFT_PRIVATE;
|
|
66
61
|
std::string title SWIFT_PRIVATE;
|
|
67
62
|
std::optional<std::string> subtitle SWIFT_PRIVATE;
|
|
68
63
|
std::optional<std::string> artist SWIFT_PRIVATE;
|
|
69
|
-
std::optional<std::string>
|
|
64
|
+
std::optional<std::string> albumPath SWIFT_PRIVATE;
|
|
70
65
|
std::optional<std::string> album SWIFT_PRIVATE;
|
|
71
66
|
std::optional<std::string> description SWIFT_PRIVATE;
|
|
72
67
|
std::optional<std::string> genre SWIFT_PRIVATE;
|
|
73
68
|
std::optional<double> duration SWIFT_PRIVATE;
|
|
74
69
|
std::optional<TrackStyle> style SWIFT_PRIVATE;
|
|
75
|
-
std::optional<
|
|
70
|
+
std::optional<bool> disabled SWIFT_PRIVATE;
|
|
76
71
|
std::optional<bool> favorited SWIFT_PRIVATE;
|
|
77
|
-
std::optional<std::string> groupTitle SWIFT_PRIVATE;
|
|
78
72
|
std::optional<bool> live SWIFT_PRIVATE;
|
|
79
|
-
std::optional<std::vector<ImageRowItem>> imageRow SWIFT_PRIVATE;
|
|
80
73
|
|
|
81
74
|
public:
|
|
82
75
|
Track() = default;
|
|
83
|
-
explicit Track(std::optional<std::string> id, std::optional<std::string>
|
|
76
|
+
explicit Track(std::optional<std::string> id, std::optional<std::string> path, std::optional<std::string> src, std::optional<std::variant<std::string, ArtworkVariants>> artwork, std::optional<ImageSource> artworkSource, std::optional<TrackRequest> request, std::string title, std::optional<std::string> subtitle, std::optional<std::string> artist, std::optional<std::string> albumPath, std::optional<std::string> album, std::optional<std::string> description, std::optional<std::string> genre, std::optional<double> duration, std::optional<TrackStyle> style, std::optional<bool> disabled, std::optional<bool> favorited, std::optional<bool> live): id(id), path(path), src(src), artwork(artwork), artworkSource(artworkSource), request(request), title(title), subtitle(subtitle), artist(artist), albumPath(albumPath), album(album), description(description), genre(genre), duration(duration), style(style), disabled(disabled), favorited(favorited), live(live) {}
|
|
84
77
|
|
|
85
78
|
public:
|
|
86
79
|
friend bool operator==(const Track& lhs, const Track& rhs) = default;
|
|
@@ -97,51 +90,45 @@ namespace margelo::nitro {
|
|
|
97
90
|
jsi::Object obj = arg.asObject(runtime);
|
|
98
91
|
return margelo::nitro::audiobrowser::Track(
|
|
99
92
|
JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "id"))),
|
|
100
|
-
JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "
|
|
93
|
+
JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "path"))),
|
|
101
94
|
JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "src"))),
|
|
102
95
|
JSIConverter<std::optional<std::variant<std::string, margelo::nitro::audiobrowser::ArtworkVariants>>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "artwork"))),
|
|
103
96
|
JSIConverter<std::optional<margelo::nitro::audiobrowser::ImageSource>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "artworkSource"))),
|
|
104
97
|
JSIConverter<std::optional<margelo::nitro::audiobrowser::TrackRequest>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "request"))),
|
|
105
|
-
JSIConverter<std::optional<bool>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "artworkCarPlayTinted"))),
|
|
106
98
|
JSIConverter<std::string>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "title"))),
|
|
107
99
|
JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "subtitle"))),
|
|
108
100
|
JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "artist"))),
|
|
109
|
-
JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "
|
|
101
|
+
JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "albumPath"))),
|
|
110
102
|
JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "album"))),
|
|
111
103
|
JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "description"))),
|
|
112
104
|
JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "genre"))),
|
|
113
105
|
JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "duration"))),
|
|
114
106
|
JSIConverter<std::optional<margelo::nitro::audiobrowser::TrackStyle>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "style"))),
|
|
115
|
-
JSIConverter<std::optional<
|
|
107
|
+
JSIConverter<std::optional<bool>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "disabled"))),
|
|
116
108
|
JSIConverter<std::optional<bool>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "favorited"))),
|
|
117
|
-
JSIConverter<std::optional<
|
|
118
|
-
JSIConverter<std::optional<bool>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "live"))),
|
|
119
|
-
JSIConverter<std::optional<std::vector<margelo::nitro::audiobrowser::ImageRowItem>>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "imageRow")))
|
|
109
|
+
JSIConverter<std::optional<bool>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "live")))
|
|
120
110
|
);
|
|
121
111
|
}
|
|
122
112
|
static inline jsi::Value toJSI(jsi::Runtime& runtime, const margelo::nitro::audiobrowser::Track& arg) {
|
|
123
113
|
jsi::Object obj(runtime);
|
|
124
114
|
obj.setProperty(runtime, PropNameIDCache::get(runtime, "id"), JSIConverter<std::optional<std::string>>::toJSI(runtime, arg.id));
|
|
125
|
-
obj.setProperty(runtime, PropNameIDCache::get(runtime, "
|
|
115
|
+
obj.setProperty(runtime, PropNameIDCache::get(runtime, "path"), JSIConverter<std::optional<std::string>>::toJSI(runtime, arg.path));
|
|
126
116
|
obj.setProperty(runtime, PropNameIDCache::get(runtime, "src"), JSIConverter<std::optional<std::string>>::toJSI(runtime, arg.src));
|
|
127
117
|
obj.setProperty(runtime, PropNameIDCache::get(runtime, "artwork"), JSIConverter<std::optional<std::variant<std::string, margelo::nitro::audiobrowser::ArtworkVariants>>>::toJSI(runtime, arg.artwork));
|
|
128
118
|
obj.setProperty(runtime, PropNameIDCache::get(runtime, "artworkSource"), JSIConverter<std::optional<margelo::nitro::audiobrowser::ImageSource>>::toJSI(runtime, arg.artworkSource));
|
|
129
119
|
obj.setProperty(runtime, PropNameIDCache::get(runtime, "request"), JSIConverter<std::optional<margelo::nitro::audiobrowser::TrackRequest>>::toJSI(runtime, arg.request));
|
|
130
|
-
obj.setProperty(runtime, PropNameIDCache::get(runtime, "artworkCarPlayTinted"), JSIConverter<std::optional<bool>>::toJSI(runtime, arg.artworkCarPlayTinted));
|
|
131
120
|
obj.setProperty(runtime, PropNameIDCache::get(runtime, "title"), JSIConverter<std::string>::toJSI(runtime, arg.title));
|
|
132
121
|
obj.setProperty(runtime, PropNameIDCache::get(runtime, "subtitle"), JSIConverter<std::optional<std::string>>::toJSI(runtime, arg.subtitle));
|
|
133
122
|
obj.setProperty(runtime, PropNameIDCache::get(runtime, "artist"), JSIConverter<std::optional<std::string>>::toJSI(runtime, arg.artist));
|
|
134
|
-
obj.setProperty(runtime, PropNameIDCache::get(runtime, "
|
|
123
|
+
obj.setProperty(runtime, PropNameIDCache::get(runtime, "albumPath"), JSIConverter<std::optional<std::string>>::toJSI(runtime, arg.albumPath));
|
|
135
124
|
obj.setProperty(runtime, PropNameIDCache::get(runtime, "album"), JSIConverter<std::optional<std::string>>::toJSI(runtime, arg.album));
|
|
136
125
|
obj.setProperty(runtime, PropNameIDCache::get(runtime, "description"), JSIConverter<std::optional<std::string>>::toJSI(runtime, arg.description));
|
|
137
126
|
obj.setProperty(runtime, PropNameIDCache::get(runtime, "genre"), JSIConverter<std::optional<std::string>>::toJSI(runtime, arg.genre));
|
|
138
127
|
obj.setProperty(runtime, PropNameIDCache::get(runtime, "duration"), JSIConverter<std::optional<double>>::toJSI(runtime, arg.duration));
|
|
139
128
|
obj.setProperty(runtime, PropNameIDCache::get(runtime, "style"), JSIConverter<std::optional<margelo::nitro::audiobrowser::TrackStyle>>::toJSI(runtime, arg.style));
|
|
140
|
-
obj.setProperty(runtime, PropNameIDCache::get(runtime, "
|
|
129
|
+
obj.setProperty(runtime, PropNameIDCache::get(runtime, "disabled"), JSIConverter<std::optional<bool>>::toJSI(runtime, arg.disabled));
|
|
141
130
|
obj.setProperty(runtime, PropNameIDCache::get(runtime, "favorited"), JSIConverter<std::optional<bool>>::toJSI(runtime, arg.favorited));
|
|
142
|
-
obj.setProperty(runtime, PropNameIDCache::get(runtime, "groupTitle"), JSIConverter<std::optional<std::string>>::toJSI(runtime, arg.groupTitle));
|
|
143
131
|
obj.setProperty(runtime, PropNameIDCache::get(runtime, "live"), JSIConverter<std::optional<bool>>::toJSI(runtime, arg.live));
|
|
144
|
-
obj.setProperty(runtime, PropNameIDCache::get(runtime, "imageRow"), JSIConverter<std::optional<std::vector<margelo::nitro::audiobrowser::ImageRowItem>>>::toJSI(runtime, arg.imageRow));
|
|
145
132
|
return obj;
|
|
146
133
|
}
|
|
147
134
|
static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) {
|
|
@@ -153,26 +140,23 @@ namespace margelo::nitro {
|
|
|
153
140
|
return false;
|
|
154
141
|
}
|
|
155
142
|
if (!JSIConverter<std::optional<std::string>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "id")))) return false;
|
|
156
|
-
if (!JSIConverter<std::optional<std::string>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "
|
|
143
|
+
if (!JSIConverter<std::optional<std::string>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "path")))) return false;
|
|
157
144
|
if (!JSIConverter<std::optional<std::string>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "src")))) return false;
|
|
158
145
|
if (!JSIConverter<std::optional<std::variant<std::string, margelo::nitro::audiobrowser::ArtworkVariants>>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "artwork")))) return false;
|
|
159
146
|
if (!JSIConverter<std::optional<margelo::nitro::audiobrowser::ImageSource>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "artworkSource")))) return false;
|
|
160
147
|
if (!JSIConverter<std::optional<margelo::nitro::audiobrowser::TrackRequest>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "request")))) return false;
|
|
161
|
-
if (!JSIConverter<std::optional<bool>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "artworkCarPlayTinted")))) return false;
|
|
162
148
|
if (!JSIConverter<std::string>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "title")))) return false;
|
|
163
149
|
if (!JSIConverter<std::optional<std::string>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "subtitle")))) return false;
|
|
164
150
|
if (!JSIConverter<std::optional<std::string>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "artist")))) return false;
|
|
165
|
-
if (!JSIConverter<std::optional<std::string>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "
|
|
151
|
+
if (!JSIConverter<std::optional<std::string>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "albumPath")))) return false;
|
|
166
152
|
if (!JSIConverter<std::optional<std::string>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "album")))) return false;
|
|
167
153
|
if (!JSIConverter<std::optional<std::string>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "description")))) return false;
|
|
168
154
|
if (!JSIConverter<std::optional<std::string>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "genre")))) return false;
|
|
169
155
|
if (!JSIConverter<std::optional<double>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "duration")))) return false;
|
|
170
156
|
if (!JSIConverter<std::optional<margelo::nitro::audiobrowser::TrackStyle>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "style")))) return false;
|
|
171
|
-
if (!JSIConverter<std::optional<
|
|
157
|
+
if (!JSIConverter<std::optional<bool>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "disabled")))) return false;
|
|
172
158
|
if (!JSIConverter<std::optional<bool>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "favorited")))) return false;
|
|
173
|
-
if (!JSIConverter<std::optional<std::string>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "groupTitle")))) return false;
|
|
174
159
|
if (!JSIConverter<std::optional<bool>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "live")))) return false;
|
|
175
|
-
if (!JSIConverter<std::optional<std::vector<margelo::nitro::audiobrowser::ImageRowItem>>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "imageRow")))) return false;
|
|
176
160
|
return true;
|
|
177
161
|
}
|
|
178
162
|
};
|
|
@@ -7,11 +7,6 @@
|
|
|
7
7
|
|
|
8
8
|
#pragma once
|
|
9
9
|
|
|
10
|
-
#if __has_include(<NitroModules/NitroHash.hpp>)
|
|
11
|
-
#include <NitroModules/NitroHash.hpp>
|
|
12
|
-
#else
|
|
13
|
-
#error NitroModules cannot be found! Are you sure you installed NitroModules properly?
|
|
14
|
-
#endif
|
|
15
10
|
#if __has_include(<NitroModules/JSIConverter.hpp>)
|
|
16
11
|
#include <NitroModules/JSIConverter.hpp>
|
|
17
12
|
#else
|
|
@@ -22,54 +17,98 @@
|
|
|
22
17
|
#else
|
|
23
18
|
#error NitroModules cannot be found! Are you sure you installed NitroModules properly?
|
|
24
19
|
#endif
|
|
20
|
+
#if __has_include(<NitroModules/JSIHelpers.hpp>)
|
|
21
|
+
#include <NitroModules/JSIHelpers.hpp>
|
|
22
|
+
#else
|
|
23
|
+
#error NitroModules cannot be found! Are you sure you installed NitroModules properly?
|
|
24
|
+
#endif
|
|
25
|
+
#if __has_include(<NitroModules/PropNameIDCache.hpp>)
|
|
26
|
+
#include <NitroModules/PropNameIDCache.hpp>
|
|
27
|
+
#else
|
|
28
|
+
#error NitroModules cannot be found! Are you sure you installed NitroModules properly?
|
|
29
|
+
#endif
|
|
30
|
+
|
|
31
|
+
// Forward declaration of `StyleDisplay` to properly resolve imports.
|
|
32
|
+
namespace margelo::nitro::audiobrowser { enum class StyleDisplay; }
|
|
33
|
+
// Forward declaration of `ArtworkRendering` to properly resolve imports.
|
|
34
|
+
namespace margelo::nitro::audiobrowser { enum class ArtworkRendering; }
|
|
35
|
+
// Forward declaration of `ImageShape` to properly resolve imports.
|
|
36
|
+
namespace margelo::nitro::audiobrowser { enum class ImageShape; }
|
|
37
|
+
// Forward declaration of `CardImage` to properly resolve imports.
|
|
38
|
+
namespace margelo::nitro::audiobrowser { enum class CardImage; }
|
|
39
|
+
|
|
40
|
+
#include "StyleDisplay.hpp"
|
|
41
|
+
#include <optional>
|
|
42
|
+
#include "ArtworkRendering.hpp"
|
|
43
|
+
#include "ImageShape.hpp"
|
|
44
|
+
#include <string>
|
|
45
|
+
#include "CardImage.hpp"
|
|
25
46
|
|
|
26
47
|
namespace margelo::nitro::audiobrowser {
|
|
27
48
|
|
|
28
49
|
/**
|
|
29
|
-
*
|
|
50
|
+
* A struct which can be represented as a JavaScript object (TrackStyle).
|
|
30
51
|
*/
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
52
|
+
struct TrackStyle final {
|
|
53
|
+
public:
|
|
54
|
+
std::optional<StyleDisplay> display SWIFT_PRIVATE;
|
|
55
|
+
std::optional<ArtworkRendering> artworkRendering SWIFT_PRIVATE;
|
|
56
|
+
std::optional<ImageShape> imageShape SWIFT_PRIVATE;
|
|
57
|
+
std::optional<std::string> accessorySymbol SWIFT_PRIVATE;
|
|
58
|
+
std::optional<std::string> cardTint SWIFT_PRIVATE;
|
|
59
|
+
std::optional<CardImage> cardImage SWIFT_PRIVATE;
|
|
60
|
+
|
|
61
|
+
public:
|
|
62
|
+
TrackStyle() = default;
|
|
63
|
+
explicit TrackStyle(std::optional<StyleDisplay> display, std::optional<ArtworkRendering> artworkRendering, std::optional<ImageShape> imageShape, std::optional<std::string> accessorySymbol, std::optional<std::string> cardTint, std::optional<CardImage> cardImage): display(display), artworkRendering(artworkRendering), imageShape(imageShape), accessorySymbol(accessorySymbol), cardTint(cardTint), cardImage(cardImage) {}
|
|
64
|
+
|
|
65
|
+
public:
|
|
66
|
+
friend bool operator==(const TrackStyle& lhs, const TrackStyle& rhs) = default;
|
|
67
|
+
};
|
|
35
68
|
|
|
36
69
|
} // namespace margelo::nitro::audiobrowser
|
|
37
70
|
|
|
38
71
|
namespace margelo::nitro {
|
|
39
72
|
|
|
40
|
-
// C++ TrackStyle <> JS TrackStyle (
|
|
73
|
+
// C++ TrackStyle <> JS TrackStyle (object)
|
|
41
74
|
template <>
|
|
42
75
|
struct JSIConverter<margelo::nitro::audiobrowser::TrackStyle> final {
|
|
43
76
|
static inline margelo::nitro::audiobrowser::TrackStyle fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
77
|
+
jsi::Object obj = arg.asObject(runtime);
|
|
78
|
+
return margelo::nitro::audiobrowser::TrackStyle(
|
|
79
|
+
JSIConverter<std::optional<margelo::nitro::audiobrowser::StyleDisplay>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "display"))),
|
|
80
|
+
JSIConverter<std::optional<margelo::nitro::audiobrowser::ArtworkRendering>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "artworkRendering"))),
|
|
81
|
+
JSIConverter<std::optional<margelo::nitro::audiobrowser::ImageShape>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "imageShape"))),
|
|
82
|
+
JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "accessorySymbol"))),
|
|
83
|
+
JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "cardTint"))),
|
|
84
|
+
JSIConverter<std::optional<margelo::nitro::audiobrowser::CardImage>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "cardImage")))
|
|
85
|
+
);
|
|
51
86
|
}
|
|
52
|
-
static inline jsi::Value toJSI(jsi::Runtime& runtime, margelo::nitro::audiobrowser::TrackStyle arg) {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
87
|
+
static inline jsi::Value toJSI(jsi::Runtime& runtime, const margelo::nitro::audiobrowser::TrackStyle& arg) {
|
|
88
|
+
jsi::Object obj(runtime);
|
|
89
|
+
obj.setProperty(runtime, PropNameIDCache::get(runtime, "display"), JSIConverter<std::optional<margelo::nitro::audiobrowser::StyleDisplay>>::toJSI(runtime, arg.display));
|
|
90
|
+
obj.setProperty(runtime, PropNameIDCache::get(runtime, "artworkRendering"), JSIConverter<std::optional<margelo::nitro::audiobrowser::ArtworkRendering>>::toJSI(runtime, arg.artworkRendering));
|
|
91
|
+
obj.setProperty(runtime, PropNameIDCache::get(runtime, "imageShape"), JSIConverter<std::optional<margelo::nitro::audiobrowser::ImageShape>>::toJSI(runtime, arg.imageShape));
|
|
92
|
+
obj.setProperty(runtime, PropNameIDCache::get(runtime, "accessorySymbol"), JSIConverter<std::optional<std::string>>::toJSI(runtime, arg.accessorySymbol));
|
|
93
|
+
obj.setProperty(runtime, PropNameIDCache::get(runtime, "cardTint"), JSIConverter<std::optional<std::string>>::toJSI(runtime, arg.cardTint));
|
|
94
|
+
obj.setProperty(runtime, PropNameIDCache::get(runtime, "cardImage"), JSIConverter<std::optional<margelo::nitro::audiobrowser::CardImage>>::toJSI(runtime, arg.cardImage));
|
|
95
|
+
return obj;
|
|
60
96
|
}
|
|
61
97
|
static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) {
|
|
62
|
-
if (!value.
|
|
98
|
+
if (!value.isObject()) {
|
|
63
99
|
return false;
|
|
64
100
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
case hashString("grid"):
|
|
69
|
-
return true;
|
|
70
|
-
default:
|
|
71
|
-
return false;
|
|
101
|
+
jsi::Object obj = value.getObject(runtime);
|
|
102
|
+
if (!nitro::isPlainObject(runtime, obj)) {
|
|
103
|
+
return false;
|
|
72
104
|
}
|
|
105
|
+
if (!JSIConverter<std::optional<margelo::nitro::audiobrowser::StyleDisplay>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "display")))) return false;
|
|
106
|
+
if (!JSIConverter<std::optional<margelo::nitro::audiobrowser::ArtworkRendering>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "artworkRendering")))) return false;
|
|
107
|
+
if (!JSIConverter<std::optional<margelo::nitro::audiobrowser::ImageShape>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "imageShape")))) return false;
|
|
108
|
+
if (!JSIConverter<std::optional<std::string>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "accessorySymbol")))) return false;
|
|
109
|
+
if (!JSIConverter<std::optional<std::string>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "cardTint")))) return false;
|
|
110
|
+
if (!JSIConverter<std::optional<margelo::nitro::audiobrowser::CardImage>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "cardImage")))) return false;
|
|
111
|
+
return true;
|
|
73
112
|
}
|
|
74
113
|
};
|
|
75
114
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-audio-browser",
|
|
3
|
-
"version": "0.2.0-next.
|
|
3
|
+
"version": "0.2.0-next.13",
|
|
4
4
|
"description": "react-native-audio-browser is a react native package built with Nitro",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react-native",
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
"ios/**/*.mm",
|
|
32
32
|
"ios/**/*.cpp",
|
|
33
33
|
"ios/**/*.swift",
|
|
34
|
+
"website/guide",
|
|
34
35
|
"*.podspec",
|
|
35
36
|
"README.md"
|
|
36
37
|
],
|
|
@@ -46,23 +47,27 @@
|
|
|
46
47
|
"scripts": {
|
|
47
48
|
"android:format": "yarn workspace example-native android:format",
|
|
48
49
|
"android:format:check": "yarn workspace example-native android:format:check",
|
|
50
|
+
"android:gradle-stop": "yarn workspace example-native android:gradle-stop",
|
|
49
51
|
"android:ide": "yarn workspace example-native android:ide",
|
|
50
52
|
"android:logs": "react-native log-android",
|
|
51
53
|
"android:test": "yarn workspace example-native android:test",
|
|
54
|
+
"android:types": "yarn workspace example-native android:types",
|
|
52
55
|
"build": "yarn prepare",
|
|
53
56
|
"clean": "del-cli android/build example/android/build example/android/app/build example/ios/build lib",
|
|
54
57
|
"codegen": "node codegen/index.js --logLevel=\"debug\" && node post-script.cjs && node codegen/strip-struct-equality.cjs && yarn build",
|
|
55
58
|
"prepare": "bob build && yarn hooks:install",
|
|
56
59
|
"hooks:install": "git config core.hooksPath .githooks || exit 0",
|
|
57
60
|
"example": "yarn workspace example-native",
|
|
61
|
+
"ci:android": "yarn android:format:check && yarn android:types && yarn android:test",
|
|
58
62
|
"ci:format": "oxfmt --check --ignore-path .gitignore --ignore-path .oxfmtignore .",
|
|
59
63
|
"ci:format:ios": "swiftformat --lint ios",
|
|
64
|
+
"ci:ios": "yarn ci:format:ios && yarn ios:test",
|
|
60
65
|
"ci:lint": "oxlint --type-aware src",
|
|
61
66
|
"format": "oxfmt --write --ignore-path .gitignore --ignore-path .oxfmtignore .",
|
|
62
67
|
"ios:format": "swiftformat ios",
|
|
63
68
|
"ios:ide": "yarn workspace example-native ios:ide",
|
|
64
69
|
"ios:rebuild": "yarn workspace example-native ios:rebuild",
|
|
65
|
-
"ios:test": "swift test",
|
|
70
|
+
"ios:test": "swift test --disable-sandbox",
|
|
66
71
|
"lint": "oxlint --fix",
|
|
67
72
|
"release": "semantic-release",
|
|
68
73
|
"test": "vitest run",
|
package/src/AudioBrowser.ts
CHANGED
|
@@ -18,7 +18,7 @@ describe('toNativeConfig route classification', () => {
|
|
|
18
18
|
|
|
19
19
|
it('keeps a static page with a string artwork out of the RouteConfig branch', () => {
|
|
20
20
|
const page = {
|
|
21
|
-
|
|
21
|
+
path: '/x',
|
|
22
22
|
title: 'X',
|
|
23
23
|
artwork: 'https://img.example.com/x.png',
|
|
24
24
|
children: []
|
|
@@ -28,6 +28,21 @@ describe('toNativeConfig route classification', () => {
|
|
|
28
28
|
expect(entry?.artwork).toBeUndefined()
|
|
29
29
|
})
|
|
30
30
|
|
|
31
|
+
it('classifies a static page as static despite its top-level `path` key', () => {
|
|
32
|
+
// `path` is also a RequestConfig field; the page's required `title` must
|
|
33
|
+
// win the classification (a config with a `path` alone is not a page).
|
|
34
|
+
const page = { path: '/x', title: 'X', children: [] }
|
|
35
|
+
const entry = entryFor({ '/x': page }, '/x')
|
|
36
|
+
expect(entry?.browseStatic).toEqual(page)
|
|
37
|
+
expect(entry?.browseConfig).toBeUndefined()
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
it('classifies a path-only request config as a request config', () => {
|
|
41
|
+
const entry = entryFor({ '/x': { path: '/remapped' } }, '/x')
|
|
42
|
+
expect(entry?.browseConfig).toEqual({ path: '/remapped' })
|
|
43
|
+
expect(entry?.browseStatic).toBeUndefined()
|
|
44
|
+
})
|
|
45
|
+
|
|
31
46
|
it('classifies a method-only request config as a request config', () => {
|
|
32
47
|
const entry = entryFor({ '/x': { method: 'POST' } }, '/x')
|
|
33
48
|
expect(entry?.browseConfig).toEqual({ method: 'POST' })
|
|
@@ -66,13 +81,13 @@ describe('validateBrowserConfiguration', () => {
|
|
|
66
81
|
it('is silent for a valid configuration', () => {
|
|
67
82
|
validateBrowserConfiguration({
|
|
68
83
|
routes: {
|
|
69
|
-
'/favorites': async () => ({
|
|
84
|
+
'/favorites': async () => ({ path: '/favorites', title: 'Favorites' }),
|
|
70
85
|
'/albums/{id}': { baseUrl: 'https://api.example.com' },
|
|
71
86
|
'*': { baseUrl: 'https://api.example.com' }
|
|
72
87
|
},
|
|
73
88
|
tabs: [
|
|
74
|
-
{ title: 'Home',
|
|
75
|
-
{ title: 'Search',
|
|
89
|
+
{ title: 'Home', path: '/' },
|
|
90
|
+
{ title: 'Search', path: '/search' }
|
|
76
91
|
]
|
|
77
92
|
})
|
|
78
93
|
expect(warnings).toEqual([])
|
|
@@ -96,14 +111,14 @@ describe('validateBrowserConfiguration', () => {
|
|
|
96
111
|
|
|
97
112
|
it('does not flag a valid static page as unclassifiable', () => {
|
|
98
113
|
validateBrowserConfiguration({
|
|
99
|
-
routes: { '/x': {
|
|
114
|
+
routes: { '/x': { path: '/x', title: 'X', children: [] } }
|
|
100
115
|
})
|
|
101
116
|
expect(warnings).toEqual([])
|
|
102
117
|
})
|
|
103
118
|
|
|
104
119
|
it('warns on more than 4 static tabs', () => {
|
|
105
120
|
validateBrowserConfiguration({
|
|
106
|
-
tabs: [1, 2, 3, 4, 5].map((n) => ({ title: `Tab ${n}`,
|
|
121
|
+
tabs: [1, 2, 3, 4, 5].map((n) => ({ title: `Tab ${n}`, path: `/${n}` }))
|
|
107
122
|
})
|
|
108
123
|
expect(warnings.some((w) => w.includes('at most 4'))).toBe(true)
|
|
109
124
|
})
|
|
@@ -38,9 +38,12 @@ function isTransformableRequestConfig(
|
|
|
38
38
|
source: unknown
|
|
39
39
|
): source is TransformableRequestConfig {
|
|
40
40
|
if (!isObjectValue(source)) return false
|
|
41
|
-
//
|
|
42
|
-
//
|
|
43
|
-
//
|
|
41
|
+
// A static ResolvedTrack page also carries a top-level `path`, so `path`
|
|
42
|
+
// alone cannot mark a request config. A page is recognised by its required
|
|
43
|
+
// `title` — no RequestConfig field is named `title`.
|
|
44
|
+
if ('title' in source) return false
|
|
45
|
+
// Any RequestConfig key marks a request config. (A static ResolvedTrack's
|
|
46
|
+
// per-track request override is nested under `request`, not top-level.)
|
|
44
47
|
return (
|
|
45
48
|
'baseUrl' in source ||
|
|
46
49
|
'path' in source ||
|
|
@@ -120,7 +123,7 @@ function searchSourceToRouteEntry(source: SearchSource): NativeRouteEntry {
|
|
|
120
123
|
*/
|
|
121
124
|
function wrapTracksAsResolvedTrack(tracks: Track[]): ResolvedTrack {
|
|
122
125
|
return {
|
|
123
|
-
|
|
126
|
+
path: TABS_ROUTE_PATH,
|
|
124
127
|
title: 'Tabs',
|
|
125
128
|
children: tracks
|
|
126
129
|
}
|
|
@@ -245,14 +248,14 @@ export function validateBrowserConfiguration(
|
|
|
245
248
|
!isRouteConfig(source) &&
|
|
246
249
|
!isTransformableRequestConfig(source)
|
|
247
250
|
) {
|
|
248
|
-
// Falls through to the static-page branch; a page needs
|
|
251
|
+
// Falls through to the static-page branch; a page needs path + title.
|
|
249
252
|
const page = source as Partial<ResolvedTrack>
|
|
250
|
-
if (typeof page.
|
|
253
|
+
if (typeof page.path !== 'string' || typeof page.title !== 'string') {
|
|
251
254
|
warn(
|
|
252
255
|
`route "${path}" matched no source shape — expected a callback, ` +
|
|
253
256
|
`a request config ({ baseUrl, path, headers, ... }), a ` +
|
|
254
257
|
`RouteConfig ({ browse, media, artwork }), or a static page ` +
|
|
255
|
-
`({
|
|
258
|
+
`({ path, title, children? }). It will be served as static ` +
|
|
256
259
|
`content and likely render a blank screen.`
|
|
257
260
|
)
|
|
258
261
|
}
|
|
@@ -287,7 +290,7 @@ export function toNativeConfig(
|
|
|
287
290
|
handleTrackLoad: config.handleTrackLoad,
|
|
288
291
|
androidControllerOfflineError: config.androidControllerOfflineError,
|
|
289
292
|
carPlayLoadingTitle: config.carPlayLoadingTitle,
|
|
290
|
-
|
|
293
|
+
resolveAlbumPath: config.resolveAlbumPath,
|
|
291
294
|
formatNavigationError: config.formatNavigationError
|
|
292
295
|
}
|
|
293
296
|
}
|
|
@@ -12,7 +12,7 @@ describe('getBrowserConfiguration', () => {
|
|
|
12
12
|
})
|
|
13
13
|
|
|
14
14
|
it('returns the last configuration in its public shape', () => {
|
|
15
|
-
const config = { tabs: [{ title: 'Home',
|
|
15
|
+
const config = { tabs: [{ title: 'Home', path: '/' }] }
|
|
16
16
|
configureBrowser(config)
|
|
17
17
|
expect(getBrowserConfiguration()).toBe(config)
|
|
18
18
|
})
|
package/src/features/browser.ts
CHANGED
|
@@ -43,8 +43,8 @@ let currentConfiguration: BrowserConfiguration | undefined
|
|
|
43
43
|
* }
|
|
44
44
|
* },
|
|
45
45
|
* tabs: [
|
|
46
|
-
* { title: 'Home',
|
|
47
|
-
* { title: 'Search',
|
|
46
|
+
* { title: 'Home', path: '/' },
|
|
47
|
+
* { title: 'Search', path: '/search' }
|
|
48
48
|
* ]
|
|
49
49
|
* })
|
|
50
50
|
* ```
|
|
@@ -37,26 +37,29 @@ export function toggleActiveTrackFavorited(): void {
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
/**
|
|
40
|
-
* Sets the list of favorited track
|
|
40
|
+
* Sets the list of favorited track identifiers.
|
|
41
41
|
*
|
|
42
42
|
* This syncs your app's favorites with the native favorites cache, enabling
|
|
43
43
|
* the heart button in media controllers (notification, Android Auto, CarPlay)
|
|
44
44
|
* to show the correct state.
|
|
45
45
|
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
46
|
+
* Each identifier is matched **exactly** against a track's *identity* — its
|
|
47
|
+
* `id` when set, falling back to `src`. Store favorites as the same stable
|
|
48
|
+
* identifier you put in `Track.id` (or as the full `src` for id-less tracks).
|
|
49
49
|
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
50
|
+
* A track whose response already carries `favorited` keeps that value on
|
|
51
|
+
* display surfaces — a caller-set flag wins over cache hydration. The cache
|
|
52
|
+
* itself is written only by this call and by heart toggles
|
|
53
|
+
* (`setActiveTrackFavorited()` / media-controller taps), so you only need to
|
|
54
|
+
* call this on app launch — and again whenever the collection changes outside
|
|
55
|
+
* the player (a sync from another device, say).
|
|
53
56
|
*
|
|
54
|
-
* @param favorites - Array of favorited track `src`
|
|
57
|
+
* @param favorites - Array of favorited track identities (`id`, or `src` for id-less tracks)
|
|
55
58
|
*
|
|
56
59
|
* @example
|
|
57
60
|
* ```ts
|
|
58
|
-
* const
|
|
59
|
-
* setFavorites(
|
|
61
|
+
* const favoriteIds = await loadFavoritesFromStorage()
|
|
62
|
+
* setFavorites(favoriteIds)
|
|
60
63
|
* ```
|
|
61
64
|
*/
|
|
62
65
|
export function setFavorites(favorites: string[]): void {
|
|
@@ -4,10 +4,12 @@ import { renderHook, act, cleanup } from '@testing-library/react'
|
|
|
4
4
|
import { describe, it, expect, afterEach, vi } from 'vitest'
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* The
|
|
7
|
+
* The hooks that are a single delegation to `useNativeUpdatedValue`. Their
|
|
8
8
|
* behaviour is covered once in `utils/useNativeUpdatedValue.test.ts`; what is
|
|
9
9
|
* per-hook and untestable there is the wiring — which native callback slot the
|
|
10
10
|
* emitter claims, and which `eventKey` is pulled out of the payload.
|
|
11
|
+
* (`useActiveTrack` and `useQueue` are getter-refreshed instead — they update
|
|
12
|
+
* on transitions AND favorite toggles — and are covered in their own block.)
|
|
11
13
|
*
|
|
12
14
|
* Both are easy to get wrong and silent when wrong: the hook simply never
|
|
13
15
|
* updates, or yields the whole event where a field was meant. Five slots
|
|
@@ -159,13 +161,6 @@ const wirings: Wiring[] = [
|
|
|
159
161
|
event: true,
|
|
160
162
|
expected: true
|
|
161
163
|
},
|
|
162
|
-
{
|
|
163
|
-
name: 'useQueue',
|
|
164
|
-
hook: useQueue,
|
|
165
|
-
slot: 'onPlaybackQueueChanged',
|
|
166
|
-
event: [{ src: 'a' }],
|
|
167
|
-
expected: [{ src: 'a' }]
|
|
168
|
-
},
|
|
169
164
|
{
|
|
170
165
|
name: 'useFormattedNavigationError',
|
|
171
166
|
hook: useFormattedNavigationError,
|
|
@@ -210,13 +205,6 @@ const wirings: Wiring[] = [
|
|
|
210
205
|
event: { repeatMode: 'queue' },
|
|
211
206
|
expected: 'queue'
|
|
212
207
|
},
|
|
213
|
-
{
|
|
214
|
-
name: 'useActiveTrack',
|
|
215
|
-
hook: useActiveTrack,
|
|
216
|
-
slot: 'onPlaybackActiveTrackChanged',
|
|
217
|
-
event: { track: { src: 'a' } },
|
|
218
|
-
expected: { src: 'a' }
|
|
219
|
-
},
|
|
220
208
|
{
|
|
221
209
|
name: 'useBatteryWarningPending',
|
|
222
210
|
hook: useBatteryWarningPending,
|
|
@@ -252,3 +240,63 @@ describe('hook wiring table', () => {
|
|
|
252
240
|
expect(new Set(wirings.map((w) => w.slot)).size).toBe(wirings.length)
|
|
253
241
|
})
|
|
254
242
|
})
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* `useActiveTrack` and `useQueue` are getter-refreshed: a favorite toggle
|
|
246
|
+
* mutates the active track in place WITHOUT a transition event —
|
|
247
|
+
* transitions and mutations are separate events — so
|
|
248
|
+
* these hooks re-read their native getter on the transition slot AND on
|
|
249
|
+
* `onFavoriteChanged`.
|
|
250
|
+
*/
|
|
251
|
+
const { nativeBrowser } = await import('../native')
|
|
252
|
+
|
|
253
|
+
describe.each([
|
|
254
|
+
{
|
|
255
|
+
name: 'useActiveTrack',
|
|
256
|
+
hook: useActiveTrack,
|
|
257
|
+
getter: 'getActiveTrack',
|
|
258
|
+
transitionSlot: 'onPlaybackActiveTrackChanged',
|
|
259
|
+
initial: { src: 'a', favorited: false },
|
|
260
|
+
mutated: { src: 'a', favorited: true }
|
|
261
|
+
},
|
|
262
|
+
{
|
|
263
|
+
name: 'useQueue',
|
|
264
|
+
hook: useQueue,
|
|
265
|
+
getter: 'getQueue',
|
|
266
|
+
transitionSlot: 'onPlaybackQueueChanged',
|
|
267
|
+
initial: [{ src: 'a', favorited: false }],
|
|
268
|
+
mutated: [{ src: 'a', favorited: true }]
|
|
269
|
+
}
|
|
270
|
+
])(
|
|
271
|
+
'$name (getter-refreshed)',
|
|
272
|
+
({ hook, getter, transitionSlot, initial, mutated }) => {
|
|
273
|
+
it(`re-reads ${getter} on ${transitionSlot} and onFavoriteChanged`, () => {
|
|
274
|
+
expect(slots.has(transitionSlot)).toBe(true)
|
|
275
|
+
expect(slots.has('onFavoriteChanged')).toBe(true)
|
|
276
|
+
|
|
277
|
+
const getterMock = (
|
|
278
|
+
nativeBrowser as unknown as Record<string, ReturnType<typeof vi.fn>>
|
|
279
|
+
)[getter]!
|
|
280
|
+
|
|
281
|
+
getterMock.mockReturnValue(initial)
|
|
282
|
+
const { result } = renderHook(() => hook())
|
|
283
|
+
expect(result.current).toEqual(initial)
|
|
284
|
+
|
|
285
|
+
// A transition re-reads the getter (the event payload is not consumed).
|
|
286
|
+
getterMock.mockReturnValue(mutated)
|
|
287
|
+
act(() => slots.get(transitionSlot)!({}))
|
|
288
|
+
expect(result.current).toEqual(mutated)
|
|
289
|
+
|
|
290
|
+
// A favorite toggle mutates in place — no transition event fires, but
|
|
291
|
+
// the hook must still refresh.
|
|
292
|
+
getterMock.mockReturnValue(initial)
|
|
293
|
+
act(() =>
|
|
294
|
+
slots.get('onFavoriteChanged')!({
|
|
295
|
+
track: { src: 'a' },
|
|
296
|
+
favorited: false
|
|
297
|
+
})
|
|
298
|
+
)
|
|
299
|
+
expect(result.current).toEqual(initial)
|
|
300
|
+
})
|
|
301
|
+
}
|
|
302
|
+
)
|