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.
- package/README.md +4 -4
- package/android/build.gradle +6 -5
- package/android/gradle.properties +1 -1
- package/android/src/main/java/com/audiobrowser/AudioBrowser.kt +110 -25
- package/android/src/main/java/com/audiobrowser/browser/BrowserManager.kt +254 -188
- package/android/src/main/java/com/audiobrowser/browser/BrowserUrlResolution.kt +23 -3
- package/android/src/main/java/com/audiobrowser/browser/JsonModels.kt +77 -58
- package/android/src/main/java/com/audiobrowser/browser/SectionScope.kt +68 -26
- package/android/src/main/java/com/audiobrowser/browser/StyleResolver.kt +49 -0
- package/android/src/main/java/com/audiobrowser/extension/ResolvedTrackExt.kt +9 -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/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 +93 -73
- package/android/src/main/java/com/audiobrowser/player/Player.kt +48 -30
- package/android/src/main/java/com/audiobrowser/player/PlayerCapabilitiesExt.kt +2 -15
- package/android/src/main/java/com/audiobrowser/tls/AiaCertChaser.kt +46 -5
- package/android/src/main/java/com/audiobrowser/tls/AiaChasingExtendedTrustManager.kt +86 -27
- package/android/src/main/java/com/audiobrowser/tls/AiaChasingTrustManager.kt +58 -14
- package/android/src/main/java/com/audiobrowser/tls/AiaTls.kt +20 -6
- package/android/src/main/java/com/audiobrowser/tls/CachingCertificateFetcher.kt +249 -86
- 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 +35 -0
- package/android/src/main/java/com/audiobrowser/util/TrackFactory.kt +45 -53
- package/android/src/test/java/com/audiobrowser/TestFixtures.kt +69 -30
- package/android/src/test/java/com/audiobrowser/browser/BrowserManagerFavoritesTest.kt +153 -0
- package/android/src/test/java/com/audiobrowser/browser/BrowserManagerLayerResolutionTest.kt +6 -0
- package/android/src/test/java/com/audiobrowser/browser/BrowserManagerTest.kt +345 -8
- package/android/src/test/java/com/audiobrowser/browser/BrowserUrlResolutionTest.kt +38 -0
- package/android/src/test/java/com/audiobrowser/browser/JsonArtworkTest.kt +1 -1
- package/android/src/test/java/com/audiobrowser/browser/JsonStyleTest.kt +91 -0
- package/android/src/test/java/com/audiobrowser/browser/SectionScopeTest.kt +128 -53
- package/android/src/test/java/com/audiobrowser/browser/StyleResolverTest.kt +87 -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/tls/AiaCertChaserTest.kt +152 -8
- package/android/src/test/java/com/audiobrowser/tls/AiaChasingTrustManagerTest.kt +218 -10
- package/android/src/test/java/com/audiobrowser/tls/CachingCertificateFetcherCallSiteTest.kt +322 -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 +131 -143
- package/ios/Browser/BrowserPathHelper.swift +44 -44
- package/ios/Browser/JsonModels.swift +187 -106
- package/ios/Browser/SearchDrillIn.swift +6 -6
- package/ios/Browser/SectionPresentation.swift +34 -0
- package/ios/Browser/SectionScope.swift +58 -24
- package/ios/Browser/StyleResolver.swift +47 -0
- package/ios/Browser/TabBarEntries.swift +2 -2
- package/ios/Browser/TrackIdTemplate.swift +37 -0
- package/ios/CarPlay/CarPlayArtworkResolver.swift +8 -7
- package/ios/CarPlay/CarPlayController.swift +105 -67
- package/ios/CarPlay/CarPlayImageLoader.swift +38 -18
- package/ios/CarPlay/CarPlayListItemFactory.swift +217 -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/HybridAudioBrowser.swift +113 -35
- package/ios/Model/NitroTypeStubs.swift +64 -23
- package/ios/Model/PlayerUpdateOptions.swift +7 -0
- package/ios/Player/NowPlayingUpdater.swift +1 -1
- package/ios/Player/PlaybackCoordinator.swift +2 -2
- package/ios/Player/RetryManager.swift +4 -3
- package/ios/Tests/BrowserPathHelperTests.swift +50 -20
- package/ios/Tests/CarPlayArtworkResolverTests.swift +24 -41
- package/ios/Tests/JsonModelsTests.swift +75 -1
- package/ios/Tests/PlaybackStateStoreTests.swift +4 -3
- package/ios/Tests/QueueManagerTests.swift +4 -4
- package/ios/Tests/ResolvedTrackCopyingTests.swift +37 -35
- package/ios/Tests/SearchDrillInTests.swift +16 -16
- package/ios/Tests/SectionPresentationTests.swift +61 -0
- package/ios/Tests/SectionScopeTests.swift +87 -55
- package/ios/Tests/StyleResolverTests.swift +67 -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/TrackSelector.swift +45 -30
- package/ios/Util/ArtworkImageFetcher.swift +16 -1
- 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/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/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/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/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/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 +260 -127
- 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 +4 -3
- package/nitrogen/generated/android/c++/JBrowseResult.hpp +10 -4
- package/nitrogen/generated/android/c++/JCarPlayPlayingIndicatorLocation.hpp +58 -0
- package/nitrogen/generated/android/c++/JFavoriteChangedEvent.hpp +4 -3
- package/nitrogen/generated/android/c++/JFormatNowPlayingParams.hpp +4 -3
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_RequestConfig___Track.hpp +4 -3
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__optional_NowPlayingUpdate____FormatNowPlayingParams.hpp +4 -3
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__optional_std__string____Track.hpp +4 -3
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____Track.hpp +4 -3
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_std__vector_Track______SearchParams.hpp +4 -2
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_void_____TrackLoadEvent.hpp +4 -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 +10 -4
- package/nitrogen/generated/android/c++/JFunc_void_FavoriteChangedEvent.hpp +4 -3
- package/nitrogen/generated/android/c++/JFunc_void_Options.hpp +2 -5
- package/nitrogen/generated/android/c++/JFunc_void_PlaybackActiveTrackChangedEvent.hpp +4 -3
- package/nitrogen/generated/android/c++/JFunc_void_std__optional_ResolvedTrack_.hpp +9 -3
- package/nitrogen/generated/android/c++/JFunc_void_std__vector_Track_.hpp +4 -2
- package/nitrogen/generated/android/c++/JHybridAudioBrowserSpec.cpp +21 -14
- package/nitrogen/generated/android/c++/JIOSOptions.hpp +9 -3
- package/nitrogen/generated/android/c++/JMediaRequestConfig.hpp +4 -3
- package/nitrogen/generated/android/c++/JNativeBrowserConfiguration.hpp +16 -10
- package/nitrogen/generated/android/c++/JNativeRouteEntry.hpp +8 -2
- package/nitrogen/generated/android/c++/JNativeSetupPlayerOptions.hpp +6 -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 +4 -3
- package/nitrogen/generated/android/c++/JPlayerCapabilities.hpp +5 -11
- package/nitrogen/generated/android/c++/JResolvedTrack.hpp +49 -51
- package/nitrogen/generated/android/c++/JSection.hpp +114 -0
- package/nitrogen/generated/android/c++/JSectionStyle.hpp +69 -0
- package/nitrogen/generated/android/c++/JStyleDisplay.hpp +58 -0
- package/nitrogen/generated/android/c++/JTrack.hpp +19 -48
- package/nitrogen/generated/android/c++/JTrackLoadEvent.hpp +4 -2
- package/nitrogen/generated/android/c++/JTrackStyle.hpp +25 -18
- package/nitrogen/generated/android/c++/JVariant_ResolvedTrack_BrowseError_Promise_BrowseResult_.hpp +10 -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/IOSOptions.kt +6 -3
- 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/Section.kt +50 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{FavoriteConfig.kt → SectionStyle.kt} +12 -6
- 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 +23 -5
- package/nitrogen/generated/ios/AudioBrowser-Swift-Cxx-Bridge.hpp +104 -82
- package/nitrogen/generated/ios/AudioBrowser-Swift-Cxx-Umbrella.hpp +16 -10
- package/nitrogen/generated/ios/c++/HybridAudioBrowserSpecSwift.hpp +16 -10
- package/nitrogen/generated/ios/swift/ArtworkRendering.swift +40 -0
- package/nitrogen/generated/ios/swift/CarPlayPlayingIndicatorLocation.swift +40 -0
- package/nitrogen/generated/ios/swift/IOSOptions.swift +7 -2
- 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 +64 -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 +28 -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++/IOSOptions.hpp +9 -2
- 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 +96 -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 +50 -34
- package/package.json +3 -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/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 +277 -0
- package/src/public-surface.test.ts +40 -0
- package/src/specs/audio-browser.nitro.ts +4 -3
- package/src/style-resolution.test.ts +139 -0
- package/src/types/browser-native.ts +2 -2
- package/src/types/browser-nodes.ts +268 -136
- 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/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/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
|
@@ -1,94 +1,169 @@
|
|
|
1
1
|
package com.audiobrowser.browser
|
|
2
2
|
|
|
3
|
-
import com.audiobrowser.TestFixtures.
|
|
3
|
+
import com.audiobrowser.TestFixtures.resolvedTrack
|
|
4
|
+
import com.audiobrowser.TestFixtures.section
|
|
4
5
|
import com.audiobrowser.TestFixtures.track
|
|
6
|
+
import com.margelo.nitro.audiobrowser.SectionStyle
|
|
7
|
+
import com.margelo.nitro.audiobrowser.StyleDisplay
|
|
5
8
|
import org.junit.Assert.assertEquals
|
|
6
9
|
import org.junit.Assert.assertNull
|
|
7
10
|
import org.junit.Test
|
|
8
11
|
|
|
9
12
|
class SectionScopeTest {
|
|
10
13
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
track(
|
|
20
|
-
)
|
|
14
|
+
// Two sections sharing an identity — the duplicate-heavy shape the flat model
|
|
15
|
+
// had to disambiguate by precedence; sections + the stamped flat index make
|
|
16
|
+
// it exact.
|
|
17
|
+
private val sections =
|
|
18
|
+
listOf(
|
|
19
|
+
section(title = "First", children = arrayOf(track(src = "dup"), track(src = "x"))),
|
|
20
|
+
section(
|
|
21
|
+
title = "Second",
|
|
22
|
+
children = arrayOf(track(src = "y"), track(src = "dup"), track(src = "z")),
|
|
23
|
+
),
|
|
24
|
+
)
|
|
21
25
|
|
|
22
|
-
|
|
23
|
-
|
|
26
|
+
@Test
|
|
27
|
+
fun `falls back to the first section containing the identity`() {
|
|
28
|
+
val scoped = SectionScope.scoped(sections, "dup")!!
|
|
29
|
+
assertEquals(listOf("dup", "x"), scoped.section.children.map { it.src })
|
|
30
|
+
assertNull(scoped.tappedOffset)
|
|
31
|
+
}
|
|
24
32
|
|
|
25
|
-
|
|
26
|
-
|
|
33
|
+
@Test
|
|
34
|
+
fun `flat index pins the tapped section`() {
|
|
35
|
+
// Flat index 3 = second section, offset 1.
|
|
36
|
+
val scoped = SectionScope.scoped(sections, "dup", tappedIndex = 3)!!
|
|
37
|
+
assertEquals(listOf("y", "dup", "z"), scoped.section.children.map { it.src })
|
|
38
|
+
assertEquals(1, scoped.tappedOffset)
|
|
27
39
|
}
|
|
28
40
|
|
|
29
41
|
@Test
|
|
30
|
-
fun `
|
|
31
|
-
val
|
|
42
|
+
fun `flat index pins the exact copy within a section`() {
|
|
43
|
+
val playlist =
|
|
32
44
|
listOf(
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
track(src = "d", groupTitle = "Second"),
|
|
45
|
+
section(
|
|
46
|
+
children = arrayOf(track(src = "a"), track(src = "b"), track(src = "a"), track(src = "c"))
|
|
47
|
+
)
|
|
37
48
|
)
|
|
49
|
+
val scoped = SectionScope.scoped(playlist, "a", tappedIndex = 2)!!
|
|
50
|
+
assertEquals(2, scoped.tappedOffset)
|
|
51
|
+
}
|
|
38
52
|
|
|
39
|
-
|
|
40
|
-
|
|
53
|
+
@Test
|
|
54
|
+
fun `stale index falls back to the first identity match`() {
|
|
55
|
+
// The child at the stamped index no longer carries the tapped identity
|
|
56
|
+
// (the list shifted) — resolution ignores the index and pins nothing.
|
|
57
|
+
val scoped = SectionScope.scoped(sections, "dup", tappedIndex = 1)!!
|
|
58
|
+
assertEquals(listOf("dup", "x"), scoped.section.children.map { it.src })
|
|
59
|
+
assertNull(scoped.tappedOffset)
|
|
41
60
|
}
|
|
42
61
|
|
|
43
62
|
@Test
|
|
44
|
-
fun `
|
|
63
|
+
fun `out-of-range index is ignored`() {
|
|
64
|
+
val scoped = SectionScope.scoped(sections, "dup", tappedIndex = 99)!!
|
|
65
|
+
assertEquals(listOf("dup", "x"), scoped.section.children.map { it.src })
|
|
66
|
+
assertNull(scoped.tappedOffset)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
@Test
|
|
70
|
+
fun `vanished identity returns null`() {
|
|
71
|
+
assertNull(SectionScope.scoped(sections, "gone"))
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
@Test
|
|
75
|
+
fun `locates a track by its id when it has one`() {
|
|
76
|
+
// Identity rule (ADR 0008): the id wins over the src, so a __trackId stamped
|
|
77
|
+
// from an id-bearing track must resolve — and its src must not.
|
|
45
78
|
val children =
|
|
46
|
-
|
|
47
|
-
track(
|
|
48
|
-
track(
|
|
49
|
-
track(src = "b", groupTitle = "Same"),
|
|
79
|
+
arrayOf(
|
|
80
|
+
track(id = "stable-a", src = "https://s/a.mp3"),
|
|
81
|
+
track(id = "stable-b", src = "https://s/b.mp3"),
|
|
50
82
|
)
|
|
83
|
+
val scoped = SectionScope.scoped(listOf(section(children = children)), "stable-b")!!
|
|
84
|
+
assertEquals(listOf("stable-a", "stable-b"), scoped.section.children.map { it.id })
|
|
51
85
|
|
|
52
|
-
|
|
53
|
-
|
|
86
|
+
// The src is shadowed by the id — it is not the track's identity.
|
|
87
|
+
assertNull(SectionScope.scoped(listOf(section(children = children)), "https://s/b.mp3"))
|
|
54
88
|
}
|
|
55
89
|
|
|
90
|
+
// MARK: page shape helpers
|
|
91
|
+
|
|
56
92
|
@Test
|
|
57
|
-
fun `
|
|
58
|
-
val
|
|
59
|
-
val
|
|
60
|
-
|
|
93
|
+
fun `children sugar normalizes to one untitled section`() {
|
|
94
|
+
val page = resolvedTrack(children = arrayOf(track(src = "a"), track(src = "b")))
|
|
95
|
+
val sections = page.normalizedSections!!
|
|
96
|
+
assertEquals(1, sections.size)
|
|
97
|
+
assertNull(sections[0].title)
|
|
98
|
+
assertEquals(listOf("a", "b"), sections[0].children.map { it.src })
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
@Test
|
|
102
|
+
fun `sections win over children`() {
|
|
103
|
+
val page =
|
|
104
|
+
resolvedTrack(
|
|
105
|
+
sections = arrayOf(section(title = "S", children = arrayOf(track(src = "a")))),
|
|
106
|
+
children = arrayOf(track(src = "zzz")),
|
|
107
|
+
)
|
|
108
|
+
val sections = page.normalizedSections!!
|
|
109
|
+
assertEquals(1, sections.size)
|
|
110
|
+
assertEquals("S", sections[0].title)
|
|
111
|
+
}
|
|
61
112
|
|
|
62
|
-
|
|
63
|
-
|
|
113
|
+
@Test
|
|
114
|
+
fun `flattened children concatenate in section order`() {
|
|
115
|
+
val page =
|
|
116
|
+
resolvedTrack(
|
|
117
|
+
sections =
|
|
118
|
+
arrayOf(
|
|
119
|
+
section(title = "A", children = arrayOf(track(src = "a1"), track(src = "a2"))),
|
|
120
|
+
section(children = arrayOf(track(src = "b1"))),
|
|
121
|
+
)
|
|
122
|
+
)
|
|
123
|
+
assertEquals(listOf("a1", "a2", "b1"), page.flattenedChildren!!.map { it.src })
|
|
64
124
|
}
|
|
65
125
|
|
|
66
126
|
@Test
|
|
67
|
-
fun `
|
|
68
|
-
assertNull(
|
|
127
|
+
fun `childless page has no sections`() {
|
|
128
|
+
assertNull(resolvedTrack().normalizedSections)
|
|
69
129
|
}
|
|
70
130
|
|
|
71
|
-
//
|
|
72
|
-
|
|
131
|
+
// --- styleResolvedSections: the page->section fold (ADR 0011) ---
|
|
132
|
+
|
|
73
133
|
@Test
|
|
74
|
-
fun `
|
|
75
|
-
|
|
76
|
-
|
|
134
|
+
fun `an unstyled section reaches the surface with the page's block folded in`() {
|
|
135
|
+
// The end-to-end wire for ResolvedTrack.style: without this fold, the
|
|
136
|
+
// page tier is a dead field — every existing unit test would stay green
|
|
137
|
+
// while a whole tier of ADR 0011 went dark in production.
|
|
138
|
+
val page =
|
|
139
|
+
resolvedTrack(
|
|
140
|
+
style =
|
|
141
|
+
SectionStyle(display = StyleDisplay.GRID, artworkRendering = null, gridWrap = false),
|
|
142
|
+
sections = arrayOf(section(children = arrayOf(track(src = "a")))),
|
|
143
|
+
)
|
|
77
144
|
|
|
78
|
-
val
|
|
79
|
-
assertEquals(
|
|
145
|
+
val folded = page.styleResolvedSections()!!.single()
|
|
146
|
+
assertEquals(StyleDisplay.GRID, folded.style?.display)
|
|
147
|
+
assertEquals(false, folded.style?.gridWrap)
|
|
148
|
+
// The extras leg of this wire — folded section → per-item grid hint — is
|
|
149
|
+
// asserted in MediaExtrasBuilderTest (it needs Robolectric for Bundle).
|
|
80
150
|
}
|
|
81
151
|
|
|
82
152
|
@Test
|
|
83
|
-
fun `
|
|
84
|
-
val
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
153
|
+
fun `a section's own block overrides the page's in the fold`() {
|
|
154
|
+
val page =
|
|
155
|
+
resolvedTrack(
|
|
156
|
+
style = SectionStyle(display = StyleDisplay.GRID, artworkRendering = null, gridWrap = null),
|
|
157
|
+
sections =
|
|
158
|
+
arrayOf(
|
|
159
|
+
section(
|
|
160
|
+
style =
|
|
161
|
+
SectionStyle(display = StyleDisplay.LIST, artworkRendering = null, gridWrap = null),
|
|
162
|
+
children = arrayOf(track(src = "a")),
|
|
163
|
+
)
|
|
164
|
+
),
|
|
89
165
|
)
|
|
90
166
|
|
|
91
|
-
|
|
92
|
-
assertEquals(listOf("dup"), section.tracks.map { it.src })
|
|
167
|
+
assertEquals(StyleDisplay.LIST, page.styleResolvedSections()!!.single().style?.display)
|
|
93
168
|
}
|
|
94
169
|
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
package com.audiobrowser.browser
|
|
2
|
+
|
|
3
|
+
import com.margelo.nitro.audiobrowser.ArtworkRendering
|
|
4
|
+
import com.margelo.nitro.audiobrowser.SectionStyle
|
|
5
|
+
import com.margelo.nitro.audiobrowser.StyleDisplay
|
|
6
|
+
import com.margelo.nitro.audiobrowser.TrackStyle
|
|
7
|
+
import org.junit.Assert.assertEquals
|
|
8
|
+
import org.junit.Assert.assertNull
|
|
9
|
+
import org.junit.Test
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Resolution semantics (ADR 0011): container properties and `display` resolve by scope override
|
|
13
|
+
* (`section ?? page`), inherited item properties resolve `track ?? section ?? page` — and `display`
|
|
14
|
+
* never inherits onto an item.
|
|
15
|
+
*/
|
|
16
|
+
class StyleResolverTest {
|
|
17
|
+
|
|
18
|
+
@Test
|
|
19
|
+
fun `section overrides the page per property`() {
|
|
20
|
+
val resolved =
|
|
21
|
+
StyleResolver.sectionStyle(
|
|
22
|
+
section =
|
|
23
|
+
SectionStyle(display = StyleDisplay.LIST, artworkRendering = null, gridWrap = null),
|
|
24
|
+
page =
|
|
25
|
+
SectionStyle(
|
|
26
|
+
display = StyleDisplay.GRID,
|
|
27
|
+
artworkRendering = ArtworkRendering.STENCIL,
|
|
28
|
+
gridWrap = false,
|
|
29
|
+
),
|
|
30
|
+
)
|
|
31
|
+
// Declared on the section: wins. Undeclared: the page's scope-wide value.
|
|
32
|
+
assertEquals(StyleDisplay.LIST, resolved.display)
|
|
33
|
+
assertEquals(ArtworkRendering.STENCIL, resolved.artworkRendering)
|
|
34
|
+
assertEquals(false, resolved.gridWrap)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
@Test
|
|
38
|
+
fun `a styleless section takes the page block`() {
|
|
39
|
+
val resolved =
|
|
40
|
+
StyleResolver.sectionStyle(
|
|
41
|
+
section = null,
|
|
42
|
+
page = SectionStyle(display = StyleDisplay.GRID, artworkRendering = null, gridWrap = true),
|
|
43
|
+
)
|
|
44
|
+
assertEquals(StyleDisplay.GRID, resolved.display)
|
|
45
|
+
assertEquals(true, resolved.gridWrap)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
@Test
|
|
49
|
+
fun `track overrides the section per property`() {
|
|
50
|
+
val resolved =
|
|
51
|
+
StyleResolver.trackStyle(
|
|
52
|
+
track = TrackStyle(display = null, artworkRendering = ArtworkRendering.ORIGINAL),
|
|
53
|
+
section =
|
|
54
|
+
SectionStyle(
|
|
55
|
+
display = StyleDisplay.GRID,
|
|
56
|
+
artworkRendering = ArtworkRendering.STENCIL,
|
|
57
|
+
gridWrap = null,
|
|
58
|
+
),
|
|
59
|
+
)
|
|
60
|
+
assertEquals(ArtworkRendering.ORIGINAL, resolved.artworkRendering)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
@Test
|
|
64
|
+
fun `a styleless track inherits the section value`() {
|
|
65
|
+
val resolved =
|
|
66
|
+
StyleResolver.trackStyle(
|
|
67
|
+
track = null,
|
|
68
|
+
section =
|
|
69
|
+
SectionStyle(display = null, artworkRendering = ArtworkRendering.STENCIL, gridWrap = null),
|
|
70
|
+
)
|
|
71
|
+
assertEquals(ArtworkRendering.STENCIL, resolved.artworkRendering)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
@Test
|
|
75
|
+
fun `display never inherits onto an item`() {
|
|
76
|
+
// The track's own display is the page promise for the page IT opens; the
|
|
77
|
+
// section's describes its children's layout. Neither may surface as the
|
|
78
|
+
// item's resolved display.
|
|
79
|
+
val resolved =
|
|
80
|
+
StyleResolver.trackStyle(
|
|
81
|
+
track = TrackStyle(display = StyleDisplay.GRID, artworkRendering = null),
|
|
82
|
+
section =
|
|
83
|
+
SectionStyle(display = StyleDisplay.GRID, artworkRendering = null, gridWrap = null),
|
|
84
|
+
)
|
|
85
|
+
assertNull(resolved.display)
|
|
86
|
+
}
|
|
87
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
package com.audiobrowser.extension
|
|
2
|
+
|
|
3
|
+
import com.audiobrowser.TestFixtures.track
|
|
4
|
+
import com.audiobrowser.util.BrowserPathHelper
|
|
5
|
+
import org.junit.Assert.assertEquals
|
|
6
|
+
import org.junit.Test
|
|
7
|
+
import org.junit.runner.RunWith
|
|
8
|
+
import org.robolectric.RobolectricTestRunner
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* The skip-in-place queue match (ADR 0009): exact contextual-path equality pins the tapped copy;
|
|
12
|
+
* the identity match remains for index-less paths; an index-stamped path with no exact match
|
|
13
|
+
* misses, so the caller re-expands. Robolectric for `android.net.Uri` (contextual-path parsing).
|
|
14
|
+
*/
|
|
15
|
+
@RunWith(RobolectricTestRunner::class)
|
|
16
|
+
class TappedTrackTest {
|
|
17
|
+
|
|
18
|
+
private fun stamped(id: String, index: Int) = BrowserPathHelper.build("/page", id, index)
|
|
19
|
+
|
|
20
|
+
private val queue =
|
|
21
|
+
arrayOf(
|
|
22
|
+
track(src = "a").copy(path = stamped("a", 0)),
|
|
23
|
+
track(src = "b").copy(path = stamped("b", 1)),
|
|
24
|
+
track(src = "a").copy(path = stamped("a", 2)),
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
@Test
|
|
28
|
+
fun `exact path match pins the tapped copy of a duplicate identity`() {
|
|
29
|
+
assertEquals(2, queue.indexOfTappedTrack(stamped("a", 2), "a"))
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
@Test
|
|
33
|
+
fun `index-less path falls back to the identity match`() {
|
|
34
|
+
assertEquals(0, queue.indexOfTappedTrack(BrowserPathHelper.build("/page", "a"), "a"))
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
@Test
|
|
38
|
+
fun `index-stamped path with no exact match misses instead of identity-skipping`() {
|
|
39
|
+
// A tap in another section whose identity also sits in this queue: the
|
|
40
|
+
// caller must re-expand (re-scoping to the tapped section), not skip.
|
|
41
|
+
assertEquals(-1, queue.indexOfTappedTrack(stamped("a", 7), "a"))
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
package com.audiobrowser.extension
|
|
2
|
+
|
|
3
|
+
import com.audiobrowser.TestFixtures.track
|
|
4
|
+
import org.junit.Assert.assertEquals
|
|
5
|
+
import org.junit.Assert.assertNull
|
|
6
|
+
import org.junit.Test
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* THE identity rule (ADR 0008): a track's identity is its `id` when non-blank, else its `src`.
|
|
10
|
+
* Everything that compares tracks — favorites, section scoping, skip-in-place, `__trackId` — goes
|
|
11
|
+
* through this extension.
|
|
12
|
+
*/
|
|
13
|
+
class TrackIdentityTest {
|
|
14
|
+
|
|
15
|
+
@Test
|
|
16
|
+
fun `id wins over src`() {
|
|
17
|
+
assertEquals("stable-id", track(id = "stable-id", src = "https://s/a.mp3").identity)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
@Test
|
|
21
|
+
fun `blank id falls back to src`() {
|
|
22
|
+
assertEquals("https://s/a.mp3", track(id = "", src = "https://s/a.mp3").identity)
|
|
23
|
+
assertEquals("https://s/a.mp3", track(id = " ", src = "https://s/a.mp3").identity)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
@Test
|
|
27
|
+
fun `missing id falls back to src`() {
|
|
28
|
+
assertEquals("https://s/a.mp3", track(id = null, src = "https://s/a.mp3").identity)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
@Test
|
|
32
|
+
fun `id alone is an identity`() {
|
|
33
|
+
assertEquals("stable-id", track(id = "stable-id", src = null).identity)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
@Test
|
|
37
|
+
fun `neither id nor src means no identity`() {
|
|
38
|
+
assertNull(track(id = null, src = null).identity)
|
|
39
|
+
assertNull(track(id = "", src = null).identity)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -3,7 +3,6 @@ package com.audiobrowser.player
|
|
|
3
3
|
import com.margelo.nitro.audiobrowser.PlayerCapabilities
|
|
4
4
|
import com.margelo.nitro.audiobrowser.RemoteButton
|
|
5
5
|
import com.margelo.nitro.audiobrowser.RemoteButtonLayout
|
|
6
|
-
import com.margelo.nitro.audiobrowser.Variant_Boolean_FavoriteConfig
|
|
7
6
|
import org.junit.Assert.assertEquals
|
|
8
7
|
import org.junit.Assert.assertFalse
|
|
9
8
|
import org.junit.Assert.assertTrue
|
|
@@ -36,7 +35,7 @@ class CapabilityControlsTest {
|
|
|
36
35
|
skipToPrevious = skipToPrevious,
|
|
37
36
|
jumpForward = jumpForward,
|
|
38
37
|
jumpBackward = jumpBackward,
|
|
39
|
-
favorite = favorite
|
|
38
|
+
favorite = favorite,
|
|
40
39
|
shuffleMode = null,
|
|
41
40
|
repeatMode = null,
|
|
42
41
|
playbackRate = null,
|
|
@@ -377,7 +377,7 @@ class NowPlayingUpdaterTest {
|
|
|
377
377
|
}
|
|
378
378
|
|
|
379
379
|
@Test
|
|
380
|
-
fun `artwork re-resolves for a new track
|
|
380
|
+
fun `artwork re-resolves for a new track identity including id-less tracks`() = runTest {
|
|
381
381
|
val surface =
|
|
382
382
|
FakeSurface().apply {
|
|
383
383
|
currentTrack = track("A", id = "a")
|
|
@@ -393,10 +393,31 @@ class NowPlayingUpdaterTest {
|
|
|
393
393
|
runCurrent()
|
|
394
394
|
assertEquals(2, surface.artworkResolveCount)
|
|
395
395
|
|
|
396
|
+
// The config runs for id-less tracks too — no blanket skip.
|
|
396
397
|
surface.currentTrack = track("C", id = null, src = "https://s/c.mp3")
|
|
397
398
|
updater.render()
|
|
398
399
|
runCurrent()
|
|
399
|
-
assertEquals(
|
|
400
|
+
assertEquals(3, surface.artworkResolveCount)
|
|
401
|
+
assertEquals(0 to "https://img/a.png", surface.artworkStamps.last())
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
@Test
|
|
405
|
+
fun `artwork for an id-less track resolves once keyed on src identity`() = runTest {
|
|
406
|
+
val surface =
|
|
407
|
+
FakeSurface().apply {
|
|
408
|
+
currentTrack = track("C", id = null, src = "https://s/c.mp3")
|
|
409
|
+
hasNowPlayingArtworkConfig = true
|
|
410
|
+
artworkResult = "https://img/c.png"
|
|
411
|
+
}
|
|
412
|
+
val updater = NowPlayingUpdater(surface, backgroundScope)
|
|
413
|
+
|
|
414
|
+
updater.render()
|
|
415
|
+
runCurrent()
|
|
416
|
+
updater.updateNowPlaying(update(title = "Song")) // re-render, same track
|
|
417
|
+
runCurrent()
|
|
418
|
+
|
|
419
|
+
assertEquals(1, surface.artworkResolveCount)
|
|
420
|
+
assertEquals(listOf(0 to "https://img/c.png"), surface.artworkStamps)
|
|
400
421
|
}
|
|
401
422
|
|
|
402
423
|
@Test
|
|
@@ -439,4 +460,23 @@ class NowPlayingUpdaterTest {
|
|
|
439
460
|
|
|
440
461
|
assertTrue(surface.artworkStamps.isEmpty())
|
|
441
462
|
}
|
|
463
|
+
|
|
464
|
+
@Test
|
|
465
|
+
fun `a stale artwork result for an id-less track is not stamped after a track change`() =
|
|
466
|
+
runTest {
|
|
467
|
+
val surface =
|
|
468
|
+
FakeSurface().apply {
|
|
469
|
+
currentTrack = track("A", id = null, src = "https://s/a.mp3")
|
|
470
|
+
hasNowPlayingArtworkConfig = true
|
|
471
|
+
artworkResult = "https://img/a.png"
|
|
472
|
+
}
|
|
473
|
+
val updater = NowPlayingUpdater(surface, backgroundScope)
|
|
474
|
+
|
|
475
|
+
updater.render() // schedules the artwork resolve
|
|
476
|
+
// Skip to another id-less track before it lands: identity (src) keying must catch it.
|
|
477
|
+
surface.currentTrack = track("B", id = null, src = "https://s/b.mp3")
|
|
478
|
+
runCurrent()
|
|
479
|
+
|
|
480
|
+
assertTrue(surface.artworkStamps.isEmpty())
|
|
481
|
+
}
|
|
442
482
|
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
package com.audiobrowser.player
|
|
2
|
+
|
|
3
|
+
import com.audiobrowser.TestFixtures
|
|
4
|
+
import com.margelo.nitro.audiobrowser.ArtworkRendering
|
|
5
|
+
import com.margelo.nitro.audiobrowser.StyleDisplay
|
|
6
|
+
import com.margelo.nitro.audiobrowser.TrackStyle
|
|
7
|
+
import org.junit.Assert.assertEquals
|
|
8
|
+
import org.junit.Assert.assertNull
|
|
9
|
+
import org.junit.Test
|
|
10
|
+
import org.junit.runner.RunWith
|
|
11
|
+
import org.robolectric.RobolectricTestRunner
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The bespoke org.json persistence of the resumption track. ADR 0011: the style block and
|
|
15
|
+
* `disabled` survive process death (a restored queue keeps its visible fidelity), and a snapshot
|
|
16
|
+
* written before the block model — `style` as an enum-name string — restores without a declaration
|
|
17
|
+
* rather than failing.
|
|
18
|
+
*/
|
|
19
|
+
@RunWith(RobolectricTestRunner::class)
|
|
20
|
+
class PlaybackStateStoreTrackJsonTest {
|
|
21
|
+
|
|
22
|
+
@Test
|
|
23
|
+
fun `style and disabled survive the round-trip`() {
|
|
24
|
+
val track =
|
|
25
|
+
TestFixtures.track(title = "Night Mix", src = "https://s/a.mp3", disabled = true)
|
|
26
|
+
.copy(
|
|
27
|
+
style =
|
|
28
|
+
TrackStyle(display = StyleDisplay.GRID, artworkRendering = ArtworkRendering.STENCIL)
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
val restored = PlaybackStateStore.trackFromJson(PlaybackStateStore.trackToJson(track))
|
|
32
|
+
|
|
33
|
+
assertEquals(StyleDisplay.GRID, restored?.style?.display)
|
|
34
|
+
assertEquals(ArtworkRendering.STENCIL, restored?.style?.artworkRendering)
|
|
35
|
+
assertEquals(true, restored?.disabled)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
@Test
|
|
39
|
+
fun `a track without style round-trips without one`() {
|
|
40
|
+
val track = TestFixtures.track(title = "Plain", src = "https://s/a.mp3")
|
|
41
|
+
|
|
42
|
+
val restored = PlaybackStateStore.trackFromJson(PlaybackStateStore.trackToJson(track))
|
|
43
|
+
|
|
44
|
+
assertNull(restored?.style)
|
|
45
|
+
assertNull(restored?.disabled)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
@Test
|
|
49
|
+
fun `a pre-block snapshot with a string style restores without a declaration`() {
|
|
50
|
+
val restored = PlaybackStateStore.trackFromJson("""{"title":"X","src":"s","style":"LIST"}""")
|
|
51
|
+
|
|
52
|
+
assertEquals("X", restored?.title)
|
|
53
|
+
assertNull(restored?.style)
|
|
54
|
+
}
|
|
55
|
+
}
|