react-native-audio-browser 0.1.1 → 0.2.0-next.10
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/AudioBrowser.podspec +1 -1
- package/README.md +184 -2
- package/android/build.gradle +17 -5
- package/android/gradle.properties +2 -2
- package/android/src/main/AndroidManifest.xml +18 -1
- package/android/src/main/java/com/audiobrowser/AudioBrowser.kt +473 -158
- package/android/src/main/java/com/audiobrowser/AudioBrowserLifecycleModule.kt +38 -0
- package/android/src/main/java/com/audiobrowser/AudioBrowserPackage.kt +18 -2
- package/android/src/main/java/com/audiobrowser/Callbacks.kt +4 -6
- package/android/src/main/java/com/audiobrowser/Service.kt +67 -18
- package/android/src/main/java/com/audiobrowser/ServiceBinding.kt +48 -0
- package/android/src/main/java/com/audiobrowser/browser/ArtworkResolutionRegistry.kt +37 -0
- package/android/src/main/java/com/audiobrowser/browser/BrowseArtworkRegistry.kt +34 -0
- package/android/src/main/java/com/audiobrowser/browser/BrowserManager.kt +442 -178
- package/android/src/main/java/com/audiobrowser/browser/BrowserUrlResolution.kt +299 -0
- package/android/src/main/java/com/audiobrowser/browser/JsonArtwork.kt +79 -0
- package/android/src/main/java/com/audiobrowser/browser/JsonModels.kt +41 -4
- package/android/src/main/java/com/audiobrowser/browser/SectionScope.kt +42 -0
- package/android/src/main/java/com/audiobrowser/browser/TrackLoadHandler.kt +4 -4
- package/android/src/main/java/com/audiobrowser/extension/ResolvedTrackExt.kt +35 -0
- package/android/src/main/java/com/audiobrowser/http/HttpClient.kt +20 -3
- package/android/src/main/java/com/audiobrowser/http/RequestConfigBuilder.kt +109 -97
- package/android/src/main/java/com/audiobrowser/model/PlaybackMetadata.kt +6 -10
- package/android/src/main/java/com/audiobrowser/model/PlayerSetupOptions.kt +40 -8
- package/android/src/main/java/com/audiobrowser/model/PlayerUpdateOptions.kt +40 -46
- package/android/src/main/java/com/audiobrowser/player/AutomaticBufferManager.kt +4 -1
- package/android/src/main/java/com/audiobrowser/player/CapabilityControls.kt +172 -0
- package/android/src/main/java/com/audiobrowser/player/DynamicLoadControl.kt +18 -1
- package/android/src/main/java/com/audiobrowser/player/EqualizerController.kt +153 -0
- package/android/src/main/java/com/audiobrowser/player/InterceptingPlayer.kt +141 -0
- package/android/src/main/java/com/audiobrowser/player/MediaFactory.kt +15 -3
- package/android/src/main/java/com/audiobrowser/player/MediaSessionCallback.kt +422 -134
- package/android/src/main/java/com/audiobrowser/player/MediaSessionCommandManager.kt +248 -404
- package/android/src/main/java/com/audiobrowser/player/NowPlayingUpdater.kt +347 -0
- package/android/src/main/java/com/audiobrowser/player/PlaybackErrorClassifier.kt +129 -0
- package/android/src/main/java/com/audiobrowser/player/PlaybackStateMachine.kt +85 -0
- package/android/src/main/java/com/audiobrowser/player/PlaybackStateStore.kt +25 -5
- package/android/src/main/java/com/audiobrowser/player/PlaybackTimer.kt +56 -0
- package/android/src/main/java/com/audiobrowser/player/Player.kt +475 -577
- package/android/src/main/java/com/audiobrowser/player/PlayerCapabilitiesExt.kt +20 -0
- package/android/src/main/java/com/audiobrowser/player/PlayerEngineFactory.kt +130 -0
- package/android/src/main/java/com/audiobrowser/player/PlayerListener.kt +190 -67
- package/android/src/main/java/com/audiobrowser/player/RetryLoadErrorHandlingPolicy.kt +118 -53
- package/android/src/main/java/com/audiobrowser/player/SleepTimer.kt +37 -3
- package/android/src/main/java/com/audiobrowser/player/SleepTimerManager.kt +80 -0
- package/android/src/main/java/com/audiobrowser/player/StuckRecoveryPolicy.kt +50 -0
- package/android/src/main/java/com/audiobrowser/player/TransformingDataSource.kt +85 -40
- package/android/src/main/java/com/audiobrowser/player/VolumeFader.kt +81 -0
- package/android/src/main/java/com/audiobrowser/tls/AiaCertChaser.kt +156 -0
- package/android/src/main/java/com/audiobrowser/tls/AiaChasingExtendedTrustManager.kt +109 -0
- package/android/src/main/java/com/audiobrowser/tls/AiaChasingTrustManager.kt +37 -0
- package/android/src/main/java/com/audiobrowser/tls/AiaTls.kt +55 -0
- package/android/src/main/java/com/audiobrowser/tls/CachingCertificateFetcher.kt +265 -0
- package/android/src/main/java/com/audiobrowser/util/ArtworkContentProvider.kt +161 -0
- package/android/src/main/java/com/audiobrowser/util/ArtworkUris.kt +28 -0
- package/android/src/main/java/com/audiobrowser/util/ArtworkVariant.kt +24 -0
- package/android/src/main/java/com/audiobrowser/util/BrowserPathHelper.kt +24 -0
- package/android/src/main/java/com/audiobrowser/util/CoilArtworkLoader.kt +49 -0
- package/android/src/main/java/com/audiobrowser/util/CoilArtworkLoaderHolder.kt +36 -0
- package/android/src/main/java/com/audiobrowser/util/CoilBitmapLoader.kt +23 -300
- package/android/src/main/java/com/audiobrowser/util/EqualizerManager.kt +13 -23
- package/android/src/main/java/com/audiobrowser/util/MediaExtrasBuilder.kt +2 -2
- package/android/src/main/java/com/audiobrowser/util/MetadataAdapter.kt +4 -3
- package/android/src/main/java/com/audiobrowser/util/OutputMonitor.kt +211 -0
- package/android/src/main/java/com/audiobrowser/util/OutputSwitcher.kt +58 -0
- package/android/src/main/java/com/audiobrowser/util/PlayingStateFactory.kt +2 -1
- package/android/src/main/java/com/audiobrowser/util/RatingFavorites.kt +14 -0
- package/android/src/main/java/com/audiobrowser/util/SvgArtworkRenderer.kt +6 -111
- package/android/src/main/java/com/audiobrowser/util/SystemVolumeMonitor.kt +22 -8
- package/android/src/main/java/com/audiobrowser/util/TrackFactory.kt +112 -80
- package/android/src/main/res/values/strings.xml +4 -0
- package/android/src/test/java/com/audiobrowser/ServiceBindingTest.kt +87 -0
- package/android/src/test/java/com/audiobrowser/TestFixtures.kt +165 -0
- package/android/src/test/java/com/audiobrowser/browser/ArtworkResolutionRegistryTest.kt +46 -0
- package/android/src/test/java/com/audiobrowser/browser/BrowseArtworkRegistryTest.kt +39 -0
- package/android/src/test/java/com/audiobrowser/browser/BrowserManagerBuildApiRequestTest.kt +114 -0
- package/android/src/test/java/com/audiobrowser/browser/BrowserManagerLayerResolutionTest.kt +141 -0
- package/android/src/test/java/com/audiobrowser/browser/BrowserManagerTest.kt +4 -0
- package/android/src/test/java/com/audiobrowser/browser/BrowserUrlResolutionTest.kt +177 -0
- package/android/src/test/java/com/audiobrowser/browser/JsonArtworkTest.kt +55 -0
- package/android/src/test/java/com/audiobrowser/browser/SectionScopeTest.kt +94 -0
- package/android/src/test/java/com/audiobrowser/browser/SimpleRouterTest.kt +1 -2
- package/android/src/test/java/com/audiobrowser/http/RequestConfigBuilderTest.kt +72 -0
- package/android/src/test/java/com/audiobrowser/player/CapabilityControlsTest.kt +203 -0
- package/android/src/test/java/com/audiobrowser/player/DynamicLoadControlTest.kt +56 -0
- package/android/src/test/java/com/audiobrowser/player/EqualizerControllerTest.kt +216 -0
- package/android/src/test/java/com/audiobrowser/player/MediaSessionSlotMappingTest.kt +45 -0
- package/android/src/test/java/com/audiobrowser/player/NowPlayingUpdaterTest.kt +442 -0
- package/android/src/test/java/com/audiobrowser/player/PlaybackErrorClassifierTest.kt +190 -0
- package/android/src/test/java/com/audiobrowser/player/PlaybackStateMachineTest.kt +198 -0
- package/android/src/test/java/com/audiobrowser/player/PlaybackTimerTest.kt +137 -0
- package/android/src/test/java/com/audiobrowser/player/PlayerEngineFactoryTest.kt +36 -0
- package/android/src/test/java/com/audiobrowser/player/RetryLoadErrorHandlingPolicyTest.kt +268 -0
- package/android/src/test/java/com/audiobrowser/player/SessionErrorMaskTest.kt +68 -0
- package/android/src/test/java/com/audiobrowser/player/StuckRecoveryPolicyTest.kt +40 -0
- package/android/src/test/java/com/audiobrowser/player/TransformingDataSourceTest.kt +193 -0
- package/android/src/test/java/com/audiobrowser/tls/AiaCertChaserTest.kt +153 -0
- package/android/src/test/java/com/audiobrowser/tls/AiaChasingTrustManagerTest.kt +186 -0
- package/android/src/test/java/com/audiobrowser/tls/CachingCertificateFetcherTest.kt +158 -0
- package/android/src/test/java/com/audiobrowser/tls/CertFixtures.kt +18 -0
- package/android/src/test/java/com/audiobrowser/util/ArtworkContentProviderTest.kt +163 -0
- package/android/src/test/java/com/audiobrowser/util/ArtworkUrisTest.kt +34 -0
- package/android/src/test/java/com/audiobrowser/util/BrowserPathHelperTest.kt +28 -0
- package/android/src/test/java/com/audiobrowser/util/CoilArtworkLoaderHolderTest.kt +53 -0
- package/android/src/test/java/com/audiobrowser/util/CoilArtworkLoaderTest.kt +58 -0
- package/android/src/test/java/com/audiobrowser/util/FakeImageLoader.kt +57 -0
- package/android/src/test/java/com/audiobrowser/util/PlayingStateFactoryTest.kt +40 -0
- package/android/src/test/java/com/audiobrowser/util/RatingFavoritesTest.kt +34 -0
- package/android/src/test/java/com/audiobrowser/util/TrackFactoryBrowseTest.kt +50 -0
- package/android/src/test/java/com/audiobrowser/util/TrackFactoryMediaIdTest.kt +63 -0
- package/android/src/test/java/com/audiobrowser/util/TrackFactoryRatingTest.kt +35 -0
- package/android/src/test/resources/certs/isrg-root-x1.pem +31 -0
- package/android/src/test/resources/certs/letsencrypt-r13.der +0 -0
- package/android/src/test/resources/certs/letsencrypt-r13.pem +29 -0
- package/android/src/test/resources/certs/stationplaylist-leaf.pem +34 -0
- package/ios/Browser/BrowserConfig.swift +41 -11
- package/ios/Browser/BrowserManager+URLResolution.swift +213 -93
- package/ios/Browser/BrowserManager.swift +303 -135
- package/ios/Browser/BrowserPathHelper.swift +32 -3
- package/ios/Browser/JsonModels.swift +287 -66
- package/ios/Browser/MediaResolveComposer.swift +114 -0
- package/ios/Browser/SearchDrillIn.swift +44 -0
- package/ios/Browser/SectionScope.swift +35 -0
- package/ios/Browser/TabBarEntries.swift +15 -0
- package/ios/CarPlay/CPInterfaceController+Safe.swift +126 -0
- package/ios/CarPlay/CarPlayArtworkResolver.swift +6 -6
- package/ios/CarPlay/CarPlayController.swift +739 -149
- package/ios/CarPlay/CarPlayImageLoader.swift +57 -8
- package/ios/CarPlay/CarPlayListItemFactory.swift +44 -35
- package/ios/CarPlay/CarPlayNowPlayingManager.swift +180 -36
- package/ios/CarPlay/ImageRowItem+CarPlay.swift +19 -0
- package/ios/CarPlay/RNABAudioBrowser.h +15 -10
- package/ios/CarPlay/RNABAudioBrowser.m +15 -14
- package/ios/CarPlay/RNABCarPlaySceneDelegate.m +2 -0
- package/ios/CarPlay/RNABMediaAddHandler.swift +75 -0
- package/ios/CarPlay/RNABMediaAffinityHandler.swift +69 -0
- package/ios/CarPlay/RNABMediaIntentHandler.swift +53 -43
- package/ios/Extension/Capability+RemoteCommand.swift +7 -9
- package/ios/Extension/ChapterMetadata+AVFoundation.swift +1 -1
- package/ios/Extension/NavigationError+Conversion.swift +8 -1
- package/ios/Extension/PlayerCapabilities+Favorite.swift +20 -0
- package/ios/Extension/RequestConfig+Copying.swift +31 -0
- package/ios/Extension/ResolvedTrack+Copying.swift +10 -4
- package/ios/Extension/TimedMetadata+AVFoundation.swift +1 -1
- package/ios/Extension/Track+AVPlayer.swift +4 -4
- package/ios/Extension/Track+Copying.swift +9 -3
- package/ios/Extension/TrackMetadata+AVFoundation.swift +1 -1
- package/ios/Extension/Variant+Artwork.swift +49 -0
- package/ios/HybridAudioBrowser.swift +805 -197
- package/ios/Model/NitroTypeStubs.swift +299 -224
- package/ios/Model/PlayerUpdateOptions.swift +23 -23
- package/ios/Model/RemoteCommand.swift +24 -6
- package/ios/Model/TrackPlayerError.swift +82 -18
- package/ios/NowPlayingInfo/NowPlayingInfoController.swift +99 -121
- package/ios/NowPlayingInfo/SilentAudioPrimer.swift +73 -0
- package/ios/Observer/PlayerItemNotificationObserver.swift +45 -5
- package/ios/Observer/PlayerItemPropertyObserver.swift +27 -4
- package/ios/Observer/PlayerTimeObserver.swift +3 -53
- package/ios/Option/SessionCategories.swift +34 -11
- package/ios/Player/AirPlayStallJudgement.swift +25 -0
- package/ios/Player/EndOfTrackJudgement.swift +32 -0
- package/ios/Player/LoadSeekCoordinator.swift +16 -1
- package/ios/Player/MediaIntentCriteria.swift +139 -0
- package/ios/Player/MediaLoader.swift +31 -11
- package/ios/Player/NowPlayingUpdater.swift +119 -26
- package/ios/Player/PersistedPlaybackState.swift +11 -0
- package/ios/Player/PlaybackCoordinator.swift +285 -51
- package/ios/Player/PlaybackCoordinatorCallbacks.swift +6 -1
- package/ios/Player/PlaybackEffectHandler.swift +19 -9
- package/ios/Player/PlaybackErrorHandler.swift +98 -14
- package/ios/Player/PlaybackStateMachine.swift +18 -13
- package/ios/Player/PlaybackStateStore.swift +27 -0
- package/ios/Player/PlaybackTimer.swift +61 -0
- package/ios/Player/PlayingStateManager.swift +3 -2
- package/ios/Player/QueueManager.swift +77 -64
- package/ios/Player/RetryManager.swift +175 -38
- package/ios/Player/ShuffleOrder.swift +10 -0
- package/ios/Player/SleepTimerHandling.swift +8 -0
- package/ios/Player/SleepTimerManager.swift +72 -11
- package/ios/Player/VolumeFader.swift +77 -0
- package/ios/RemoteCommand/RemoteCommandCallbacks.swift +47 -0
- package/ios/RemoteCommand/RemoteCommandController.swift +40 -21
- package/ios/Tests/AirPlayStallJudgementTests.swift +52 -0
- package/ios/Tests/BrowserPathHelperTests.swift +28 -0
- package/ios/Tests/CarPlayArtworkResolverTests.swift +39 -39
- package/ios/Tests/ChapterMetadataAVFoundationTests.swift +2 -2
- package/ios/Tests/EndOfTrackJudgementTests.swift +35 -0
- package/ios/Tests/JsonModelsTests.swift +58 -0
- package/ios/Tests/LRUCacheTests.swift +111 -0
- package/ios/Tests/LoadSeekCoordinatorTests.swift +40 -7
- package/ios/Tests/MediaIntentCriteriaTests.swift +170 -0
- package/ios/Tests/MediaLoaderAssetOptionsTests.swift +46 -0
- package/ios/Tests/MediaLoaderTests.swift +32 -20
- package/ios/Tests/MediaResolveTests.swift +126 -0
- package/ios/Tests/OnceValueTests.swift +79 -0
- package/ios/Tests/PlaybackCoordinatorTests.swift +787 -13
- package/ios/Tests/PlaybackErrorHandlerTests.swift +383 -47
- package/ios/Tests/PlaybackStateMachineTests.swift +33 -8
- package/ios/Tests/PlaybackStateStoreTests.swift +48 -0
- package/ios/Tests/PlaybackTimerTests.swift +55 -0
- package/ios/Tests/PlayerTimeObserverTests.swift +37 -0
- package/ios/Tests/PlayingStateManagerTests.swift +57 -0
- package/ios/Tests/QueueManagerTests.swift +195 -18
- package/ios/Tests/RemoteCommandControllerTests.swift +156 -0
- package/ios/Tests/RemoteCommandTests.swift +67 -0
- package/ios/Tests/ResolvedTrackCopyingTests.swift +15 -8
- package/ios/Tests/RetryManagerTests.swift +178 -0
- package/ios/Tests/SearchDrillInTests.swift +63 -0
- package/ios/Tests/SectionScopeTests.swift +82 -0
- package/ios/Tests/SleepTimerManagerTests.swift +107 -0
- package/ios/Tests/Support/ManualSleepTimerScheduler.swift +47 -0
- package/ios/Tests/Support/TestTypes.swift +61 -20
- package/ios/Tests/TabBarEntriesTests.swift +71 -0
- package/ios/Tests/TrackSelectorTests.swift +15 -15
- package/ios/TrackPlayer.swift +385 -58
- package/ios/TrackPlayerCallbacks.swift +5 -44
- package/ios/TrackSelector.swift +5 -5
- package/ios/Util/ArtworkImageFetcher.swift +4 -2
- package/ios/Util/LRUCache.swift +4 -1
- package/ios/Util/NetworkMonitor.swift +7 -3
- package/ios/Util/OnceValue.swift +34 -0
- package/lib/commonjs/AudioBrowser.js +0 -11
- package/lib/commonjs/AudioBrowser.js.map +1 -1
- package/lib/commonjs/CLAUDE.md +52 -0
- package/lib/commonjs/features/browser-config.js +227 -0
- package/lib/commonjs/features/browser-config.js.map +1 -0
- package/lib/commonjs/features/browser.js +60 -159
- package/lib/commonjs/features/browser.js.map +1 -1
- package/lib/commonjs/features/carConnection.js +42 -0
- package/lib/commonjs/features/carConnection.js.map +1 -0
- package/lib/commonjs/features/equalizer.js +1 -1
- package/lib/commonjs/features/errors.js +37 -5
- package/lib/commonjs/features/errors.js.map +1 -1
- package/lib/commonjs/features/favorites.js +1 -1
- package/lib/commonjs/features/gate.js +164 -0
- package/lib/commonjs/features/gate.js.map +1 -0
- package/lib/commonjs/features/index.js +22 -0
- package/lib/commonjs/features/index.js.map +1 -1
- package/lib/commonjs/features/metadata.js +20 -3
- package/lib/commonjs/features/metadata.js.map +1 -1
- package/lib/commonjs/features/network.js +1 -1
- package/lib/commonjs/features/nowPlaying.js +36 -1
- package/lib/commonjs/features/nowPlaying.js.map +1 -1
- package/lib/commonjs/features/output.js +37 -23
- package/lib/commonjs/features/output.js.map +1 -1
- package/lib/commonjs/features/playback/controls.js +9 -0
- package/lib/commonjs/features/playback/controls.js.map +1 -1
- package/lib/commonjs/features/playback/index.js +11 -0
- package/lib/commonjs/features/playback/index.js.map +1 -1
- package/lib/commonjs/features/playback/playWhenReady.js +1 -1
- package/lib/commonjs/features/playback/playing.js +1 -1
- package/lib/commonjs/features/playback/progress.js +29 -13
- package/lib/commonjs/features/playback/progress.js.map +1 -1
- package/lib/commonjs/features/playback/state.js +1 -1
- package/lib/commonjs/features/playback/trackPlaybackTime.js +86 -0
- package/lib/commonjs/features/playback/trackPlaybackTime.js.map +1 -0
- package/lib/commonjs/features/playback/volume.js +2 -2
- package/lib/commonjs/features/player/options.js +79 -29
- package/lib/commonjs/features/player/options.js.map +1 -1
- package/lib/commonjs/features/player/setup.js +256 -3
- package/lib/commonjs/features/player/setup.js.map +1 -1
- package/lib/commonjs/features/player/validateOptions.js +21 -0
- package/lib/commonjs/features/player/validateOptions.js.map +1 -0
- package/lib/commonjs/features/queue/activeTrack.js +1 -1
- package/lib/commonjs/features/queue/queue.js +12 -5
- package/lib/commonjs/features/queue/queue.js.map +1 -1
- package/lib/commonjs/features/queue/repeatMode.js +1 -1
- package/lib/commonjs/features/queue/shuffle.js +1 -1
- package/lib/commonjs/features/remoteControls.js +14 -104
- package/lib/commonjs/features/remoteControls.js.map +1 -1
- package/lib/commonjs/features/sleepTimer.js +22 -5
- package/lib/commonjs/features/sleepTimer.js.map +1 -1
- package/lib/commonjs/native.js +5 -0
- package/lib/commonjs/native.js.map +1 -1
- package/lib/commonjs/native.web.js +4 -1
- package/lib/commonjs/native.web.js.map +1 -1
- package/lib/commonjs/test-utils/reactNativeStub.js +65 -0
- package/lib/commonjs/test-utils/reactNativeStub.js.map +1 -0
- package/lib/commonjs/utils/LazyNativeEmitter.js +8 -8
- package/lib/commonjs/utils/LazyNativeEmitter.js.map +1 -1
- package/lib/commonjs/utils/NativeUpdatedValue.js +0 -3
- package/lib/commonjs/utils/NativeUpdatedValue.js.map +1 -1
- package/lib/commonjs/utils/artwork.js +31 -0
- package/lib/commonjs/utils/artwork.js.map +1 -0
- package/lib/commonjs/web/NativeAudioBrowser.js +302 -125
- package/lib/commonjs/web/NativeAudioBrowser.js.map +1 -1
- package/lib/commonjs/web/TrackPlayer/PlaybackStateMachine.js +71 -0
- package/lib/commonjs/web/TrackPlayer/PlaybackStateMachine.js.map +1 -0
- package/lib/commonjs/web/TrackPlayer/PlaybackTimer.js +34 -0
- package/lib/commonjs/web/TrackPlayer/PlaybackTimer.js.map +1 -0
- package/lib/commonjs/web/TrackPlayer/Player.js +90 -26
- package/lib/commonjs/web/TrackPlayer/Player.js.map +1 -1
- package/lib/commonjs/web/TrackPlayer/PlayingStateFactory.js +21 -0
- package/lib/commonjs/web/TrackPlayer/PlayingStateFactory.js.map +1 -0
- package/lib/commonjs/web/TrackPlayer/QueueManager.js +273 -0
- package/lib/commonjs/web/TrackPlayer/QueueManager.js.map +1 -0
- package/lib/commonjs/web/TrackPlayer/QueuePlayer.js +158 -0
- package/lib/commonjs/web/TrackPlayer/QueuePlayer.js.map +1 -0
- package/lib/commonjs/web/TrackPlayer/RepeatMode.js +1 -1
- package/lib/commonjs/web/TrackPlayer/RepeatMode.js.map +1 -1
- package/lib/commonjs/web/TrackPlayer/SleepTimer.js +34 -3
- package/lib/commonjs/web/TrackPlayer/SleepTimer.js.map +1 -1
- package/lib/commonjs/web/TrackPlayer/VolumeFader.js +75 -0
- package/lib/commonjs/web/TrackPlayer/VolumeFader.js.map +1 -0
- package/lib/commonjs/web/TrackPlayer/index.js +13 -5
- package/lib/commonjs/web/TrackPlayer/index.js.map +1 -1
- package/lib/commonjs/web/browser/BrowserManager.js +176 -50
- package/lib/commonjs/web/browser/BrowserManager.js.map +1 -1
- package/lib/commonjs/web/browser/NavigationErrorManager.js +3 -1
- package/lib/commonjs/web/browser/NavigationErrorManager.js.map +1 -1
- package/lib/commonjs/web/browser/SearchManager.js +11 -9
- package/lib/commonjs/web/browser/SearchManager.js.map +1 -1
- package/lib/commonjs/web/browser/assertBrowsePageShape.js +22 -0
- package/lib/commonjs/web/browser/assertBrowsePageShape.js.map +1 -0
- package/lib/commonjs/web/browser/classifyTrackNavigation.js +41 -0
- package/lib/commonjs/web/browser/classifyTrackNavigation.js.map +1 -0
- package/lib/commonjs/web/browser/parseSearchResponse.js +20 -0
- package/lib/commonjs/web/browser/parseSearchResponse.js.map +1 -0
- package/lib/commonjs/web/http/HttpClient.js +4 -23
- package/lib/commonjs/web/http/HttpClient.js.map +1 -1
- package/lib/commonjs/web/http/RequestConfigBuilder.js +107 -58
- package/lib/commonjs/web/http/RequestConfigBuilder.js.map +1 -1
- package/lib/commonjs/web/playbackErrorKind.js +57 -0
- package/lib/commonjs/web/playbackErrorKind.js.map +1 -0
- package/lib/commonjs/web/player/MediaSessionManager.js +121 -0
- package/lib/commonjs/web/player/MediaSessionManager.js.map +1 -0
- package/lib/commonjs/web/player/NowPlayingManager.js +6 -5
- package/lib/commonjs/web/player/NowPlayingManager.js.map +1 -1
- package/lib/commonjs/web/player/OptionsManager.js +9 -17
- package/lib/commonjs/web/player/OptionsManager.js.map +1 -1
- package/lib/commonjs/web/player/RemoteCommandController.js +96 -0
- package/lib/commonjs/web/player/RemoteCommandController.js.map +1 -0
- package/lib/module/AudioBrowser.js +1 -1
- package/lib/module/AudioBrowser.js.map +1 -1
- package/lib/module/CLAUDE.md +52 -0
- package/lib/module/features/browser-config.js +221 -0
- package/lib/module/features/browser-config.js.map +1 -0
- package/lib/module/features/browser.js +54 -157
- package/lib/module/features/browser.js.map +1 -1
- package/lib/module/features/carConnection.js +37 -0
- package/lib/module/features/carConnection.js.map +1 -0
- package/lib/module/features/equalizer.js +1 -1
- package/lib/module/features/errors.js +37 -5
- package/lib/module/features/errors.js.map +1 -1
- package/lib/module/features/favorites.js +1 -1
- package/lib/module/features/gate.js +159 -0
- package/lib/module/features/gate.js.map +1 -0
- package/lib/module/features/index.js +2 -0
- package/lib/module/features/index.js.map +1 -1
- package/lib/module/features/metadata.js +20 -3
- package/lib/module/features/metadata.js.map +1 -1
- package/lib/module/features/network.js +1 -1
- package/lib/module/features/nowPlaying.js +34 -1
- package/lib/module/features/nowPlaying.js.map +1 -1
- package/lib/module/features/output.js +32 -19
- package/lib/module/features/output.js.map +1 -1
- package/lib/module/features/playback/controls.js +8 -0
- package/lib/module/features/playback/controls.js.map +1 -1
- package/lib/module/features/playback/index.js +1 -0
- package/lib/module/features/playback/index.js.map +1 -1
- package/lib/module/features/playback/playWhenReady.js +1 -1
- package/lib/module/features/playback/playing.js +1 -1
- package/lib/module/features/playback/progress.js +29 -13
- package/lib/module/features/playback/progress.js.map +1 -1
- package/lib/module/features/playback/state.js +1 -1
- package/lib/module/features/playback/trackPlaybackTime.js +83 -0
- package/lib/module/features/playback/trackPlaybackTime.js.map +1 -0
- package/lib/module/features/playback/volume.js +2 -2
- package/lib/module/features/player/options.js +79 -29
- package/lib/module/features/player/options.js.map +1 -1
- package/lib/module/features/player/setup.js +256 -3
- package/lib/module/features/player/setup.js.map +1 -1
- package/lib/module/features/player/validateOptions.js +17 -0
- package/lib/module/features/player/validateOptions.js.map +1 -0
- package/lib/module/features/queue/activeTrack.js +1 -1
- package/lib/module/features/queue/queue.js +12 -5
- package/lib/module/features/queue/queue.js.map +1 -1
- package/lib/module/features/queue/repeatMode.js +1 -1
- package/lib/module/features/queue/shuffle.js +1 -1
- package/lib/module/features/remoteControls.js +13 -103
- package/lib/module/features/remoteControls.js.map +1 -1
- package/lib/module/features/sleepTimer.js +22 -5
- package/lib/module/features/sleepTimer.js.map +1 -1
- package/lib/module/native.js +5 -0
- package/lib/module/native.js.map +1 -1
- package/lib/module/native.web.js +4 -1
- package/lib/module/native.web.js.map +1 -1
- package/lib/module/test-utils/reactNativeStub.js +58 -0
- package/lib/module/test-utils/reactNativeStub.js.map +1 -0
- package/lib/module/utils/LazyNativeEmitter.js +8 -8
- package/lib/module/utils/LazyNativeEmitter.js.map +1 -1
- package/lib/module/utils/NativeUpdatedValue.js +0 -3
- package/lib/module/utils/NativeUpdatedValue.js.map +1 -1
- package/lib/module/utils/artwork.js +26 -0
- package/lib/module/utils/artwork.js.map +1 -0
- package/lib/module/web/NativeAudioBrowser.js +303 -126
- package/lib/module/web/NativeAudioBrowser.js.map +1 -1
- package/lib/module/web/TrackPlayer/PlaybackStateMachine.js +67 -0
- package/lib/module/web/TrackPlayer/PlaybackStateMachine.js.map +1 -0
- package/lib/module/web/TrackPlayer/PlaybackTimer.js +29 -0
- package/lib/module/web/TrackPlayer/PlaybackTimer.js.map +1 -0
- package/lib/module/web/TrackPlayer/Player.js +90 -26
- package/lib/module/web/TrackPlayer/Player.js.map +1 -1
- package/lib/module/web/TrackPlayer/PlayingStateFactory.js +17 -0
- package/lib/module/web/TrackPlayer/PlayingStateFactory.js.map +1 -0
- package/lib/module/web/TrackPlayer/QueueManager.js +269 -0
- package/lib/module/web/TrackPlayer/QueueManager.js.map +1 -0
- package/lib/module/web/TrackPlayer/QueuePlayer.js +154 -0
- package/lib/module/web/TrackPlayer/QueuePlayer.js.map +1 -0
- package/lib/module/web/TrackPlayer/RepeatMode.js +1 -1
- package/lib/module/web/TrackPlayer/RepeatMode.js.map +1 -1
- package/lib/module/web/TrackPlayer/SleepTimer.js +34 -3
- package/lib/module/web/TrackPlayer/SleepTimer.js.map +1 -1
- package/lib/module/web/TrackPlayer/VolumeFader.js +70 -0
- package/lib/module/web/TrackPlayer/VolumeFader.js.map +1 -0
- package/lib/module/web/TrackPlayer/index.js +2 -1
- package/lib/module/web/TrackPlayer/index.js.map +1 -1
- package/lib/module/web/browser/BrowserManager.js +176 -50
- package/lib/module/web/browser/BrowserManager.js.map +1 -1
- package/lib/module/web/browser/NavigationErrorManager.js +3 -1
- package/lib/module/web/browser/NavigationErrorManager.js.map +1 -1
- package/lib/module/web/browser/SearchManager.js +11 -9
- package/lib/module/web/browser/SearchManager.js.map +1 -1
- package/lib/module/web/browser/assertBrowsePageShape.js +18 -0
- package/lib/module/web/browser/assertBrowsePageShape.js.map +1 -0
- package/lib/module/web/browser/classifyTrackNavigation.js +38 -0
- package/lib/module/web/browser/classifyTrackNavigation.js.map +1 -0
- package/lib/module/web/browser/parseSearchResponse.js +16 -0
- package/lib/module/web/browser/parseSearchResponse.js.map +1 -0
- package/lib/module/web/http/HttpClient.js +4 -23
- package/lib/module/web/http/HttpClient.js.map +1 -1
- package/lib/module/web/http/RequestConfigBuilder.js +107 -58
- package/lib/module/web/http/RequestConfigBuilder.js.map +1 -1
- package/lib/module/web/playbackErrorKind.js +52 -0
- package/lib/module/web/playbackErrorKind.js.map +1 -0
- package/lib/module/web/player/MediaSessionManager.js +116 -0
- package/lib/module/web/player/MediaSessionManager.js.map +1 -0
- package/lib/module/web/player/NowPlayingManager.js +7 -5
- package/lib/module/web/player/NowPlayingManager.js.map +1 -1
- package/lib/module/web/player/OptionsManager.js +9 -17
- package/lib/module/web/player/OptionsManager.js.map +1 -1
- package/lib/module/web/player/RemoteCommandController.js +92 -0
- package/lib/module/web/player/RemoteCommandController.js.map +1 -0
- package/lib/typescript/src/AudioBrowser.d.ts +0 -1
- package/lib/typescript/src/AudioBrowser.d.ts.map +1 -1
- package/lib/typescript/src/features/browser-config.d.ts +12 -0
- package/lib/typescript/src/features/browser-config.d.ts.map +1 -0
- package/lib/typescript/src/features/browser.d.ts +40 -1
- package/lib/typescript/src/features/browser.d.ts.map +1 -1
- package/lib/typescript/src/features/carConnection.d.ts +20 -0
- package/lib/typescript/src/features/carConnection.d.ts.map +1 -0
- package/lib/typescript/src/features/equalizer.d.ts +1 -1
- package/lib/typescript/src/features/errors.d.ts +61 -6
- package/lib/typescript/src/features/errors.d.ts.map +1 -1
- package/lib/typescript/src/features/favorites.d.ts +1 -1
- package/lib/typescript/src/features/gate.d.ts +93 -0
- package/lib/typescript/src/features/gate.d.ts.map +1 -0
- package/lib/typescript/src/features/index.d.ts +2 -0
- package/lib/typescript/src/features/index.d.ts.map +1 -1
- package/lib/typescript/src/features/metadata.d.ts +26 -7
- package/lib/typescript/src/features/metadata.d.ts.map +1 -1
- package/lib/typescript/src/features/network.d.ts +1 -1
- package/lib/typescript/src/features/nowPlaying.d.ts +28 -1
- package/lib/typescript/src/features/nowPlaying.d.ts.map +1 -1
- package/lib/typescript/src/features/output.d.ts +28 -18
- package/lib/typescript/src/features/output.d.ts.map +1 -1
- package/lib/typescript/src/features/playback/controls.d.ts +5 -0
- package/lib/typescript/src/features/playback/controls.d.ts.map +1 -1
- package/lib/typescript/src/features/playback/index.d.ts +1 -0
- package/lib/typescript/src/features/playback/index.d.ts.map +1 -1
- package/lib/typescript/src/features/playback/playWhenReady.d.ts +1 -1
- package/lib/typescript/src/features/playback/playing.d.ts +1 -1
- package/lib/typescript/src/features/playback/progress.d.ts +4 -1
- package/lib/typescript/src/features/playback/progress.d.ts.map +1 -1
- package/lib/typescript/src/features/playback/state.d.ts +1 -1
- package/lib/typescript/src/features/playback/trackPlaybackTime.d.ts +34 -0
- package/lib/typescript/src/features/playback/trackPlaybackTime.d.ts.map +1 -0
- package/lib/typescript/src/features/playback/volume.d.ts +2 -2
- package/lib/typescript/src/features/player/options.d.ts +176 -127
- package/lib/typescript/src/features/player/options.d.ts.map +1 -1
- package/lib/typescript/src/features/player/setup.d.ts +216 -167
- package/lib/typescript/src/features/player/setup.d.ts.map +1 -1
- package/lib/typescript/src/features/player/validateOptions.d.ts +9 -0
- package/lib/typescript/src/features/player/validateOptions.d.ts.map +1 -0
- package/lib/typescript/src/features/queue/activeTrack.d.ts +1 -1
- package/lib/typescript/src/features/queue/queue.d.ts +11 -4
- package/lib/typescript/src/features/queue/queue.d.ts.map +1 -1
- package/lib/typescript/src/features/queue/repeatMode.d.ts +1 -1
- package/lib/typescript/src/features/queue/shuffle.d.ts +1 -1
- package/lib/typescript/src/features/remoteControls.d.ts +23 -35
- package/lib/typescript/src/features/remoteControls.d.ts.map +1 -1
- package/lib/typescript/src/features/sleepTimer.d.ts +19 -4
- package/lib/typescript/src/features/sleepTimer.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/native.d.ts +1 -2
- package/lib/typescript/src/native.d.ts.map +1 -1
- package/lib/typescript/src/specs/audio-browser.nitro.d.ts +17 -225
- package/lib/typescript/src/specs/audio-browser.nitro.d.ts.map +1 -1
- package/lib/typescript/src/test-utils/reactNativeStub.d.ts +36 -0
- package/lib/typescript/src/test-utils/reactNativeStub.d.ts.map +1 -0
- package/lib/typescript/src/types/browser-native.d.ts +9 -3
- package/lib/typescript/src/types/browser-native.d.ts.map +1 -1
- package/lib/typescript/src/types/browser-nodes.d.ts +145 -13
- package/lib/typescript/src/types/browser-nodes.d.ts.map +1 -1
- package/lib/typescript/src/types/browser.d.ts +349 -85
- package/lib/typescript/src/types/browser.d.ts.map +1 -1
- package/lib/typescript/src/utils/LazyNativeEmitter.d.ts +8 -6
- package/lib/typescript/src/utils/LazyNativeEmitter.d.ts.map +1 -1
- package/lib/typescript/src/utils/NativeUpdatedValue.d.ts +0 -2
- package/lib/typescript/src/utils/NativeUpdatedValue.d.ts.map +1 -1
- package/lib/typescript/src/utils/artwork.d.ts +19 -0
- package/lib/typescript/src/utils/artwork.d.ts.map +1 -0
- package/lib/typescript/src/utils/resolveAssetSource.d.ts.map +1 -1
- package/nitrogen/generated/android/AudioBrowser+autolinking.cmake +4 -2
- package/nitrogen/generated/android/AudioBrowserOnLoad.cpp +24 -10
- package/nitrogen/generated/android/c++/JAndroidAudioContentType.hpp +6 -6
- package/nitrogen/generated/android/c++/JAndroidOptions.hpp +10 -20
- package/nitrogen/generated/android/c++/JArtworkRequestConfig.hpp +33 -1
- package/nitrogen/generated/android/c++/JArtworkVariants.hpp +61 -0
- package/nitrogen/generated/android/c++/JBrowseResult.hpp +5 -0
- package/nitrogen/generated/android/c++/JCarPlayNowPlayingButton.hpp +3 -3
- package/nitrogen/generated/android/c++/JFavoriteChangedEvent.hpp +6 -0
- package/nitrogen/generated/android/c++/JFavoriteConfig.hpp +58 -0
- package/nitrogen/generated/android/c++/JFavoritesMatchMode.hpp +58 -0
- package/nitrogen/generated/android/c++/JFormatNowPlayingParams.hpp +100 -0
- package/nitrogen/generated/android/c++/JFormattedNavigationError.hpp +3 -2
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_RequestConfig___MediaTransformParams.hpp +112 -0
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_RequestConfig___RequestConfig_std__optional_std__unordered_map_std__string__std__string__.hpp +121 -0
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_RequestConfig___Track.hpp +123 -0
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__optional_NowPlayingUpdate____FormatNowPlayingParams.hpp +133 -0
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__optional_std__string____Track.hpp +121 -0
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_GateDecision_____NativeGateRequest.hpp +139 -0
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____Track.hpp +6 -0
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_TransformableRequestConfig____.hpp +134 -0
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_std__vector_Track______SearchParams.hpp +8 -0
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_void_____TrackLoadEvent.hpp +6 -0
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError__std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError_______BrowserSourceCallbackParam.hpp +131 -0
- package/nitrogen/generated/android/c++/JFunc_void_FavoriteChangedEvent.hpp +6 -0
- package/nitrogen/generated/android/c++/JFunc_void_GateEvent.hpp +79 -0
- package/nitrogen/generated/android/c++/JFunc_void_NowPlayingMetadata.hpp +0 -10
- package/nitrogen/generated/android/c++/JFunc_void_Options.hpp +14 -9
- package/nitrogen/generated/android/c++/JFunc_void_Output.hpp +80 -0
- package/nitrogen/generated/android/c++/JFunc_void_Playback.hpp +2 -0
- package/nitrogen/generated/android/c++/JFunc_void_PlaybackActiveTrackChangedEvent.hpp +6 -0
- package/nitrogen/generated/android/c++/JFunc_void_PlaybackErrorEvent.hpp +2 -0
- package/nitrogen/generated/android/c++/JFunc_void_bool.hpp +10 -10
- package/nitrogen/generated/android/c++/JFunc_void_std__optional_ResolvedTrack_.hpp +6 -0
- package/nitrogen/generated/android/c++/JFunc_void_std__vector_Track_.hpp +6 -0
- package/nitrogen/generated/android/c++/JGate.hpp +62 -0
- package/nitrogen/generated/android/c++/JGateDecision.hpp +64 -0
- package/nitrogen/generated/android/c++/{JThumbsRating.hpp → JGateEvent.hpp} +16 -15
- package/nitrogen/generated/android/c++/JGateReason.hpp +58 -0
- package/nitrogen/generated/android/c++/JHybridAudioBrowserSpec.cpp +247 -223
- package/nitrogen/generated/android/c++/JHybridAudioBrowserSpec.hpp +26 -23
- package/nitrogen/generated/android/c++/JIOSOptions.hpp +95 -0
- package/nitrogen/generated/android/c++/JImageRowItem.hpp +33 -3
- package/nitrogen/generated/android/c++/JMediaReference.hpp +58 -0
- package/nitrogen/generated/android/c++/JMediaRequestConfig.hpp +33 -1
- package/nitrogen/generated/android/c++/{JPartialAndroidSetupPlayerOptions.hpp → JNativeAndroidSetupOptions.hpp} +10 -10
- package/nitrogen/generated/android/c++/JNativeBrowserConfiguration.hpp +61 -28
- package/nitrogen/generated/android/c++/JNativeGateRequest.hpp +74 -0
- package/nitrogen/generated/android/c++/{JPartialIOSSetupPlayerOptions.hpp → JNativeIOSSetupOptions.hpp} +10 -10
- package/nitrogen/generated/android/c++/JNativeRouteEntry.hpp +20 -9
- package/nitrogen/generated/android/c++/JNativeSetupPlayerOptions.hpp +182 -0
- package/nitrogen/generated/android/c++/JNativeUpdateOptions.hpp +21 -24
- package/nitrogen/generated/android/c++/JNavigationErrorType.hpp +6 -0
- package/nitrogen/generated/android/c++/JNitroAndroidUpdateOptions.hpp +10 -20
- package/nitrogen/generated/android/c++/JNitroIOSUpdateOptions.hpp +96 -0
- package/nitrogen/generated/android/c++/JNowPlayingMetadata.hpp +3 -17
- package/nitrogen/generated/android/c++/JNowPlayingUpdate.hpp +7 -3
- package/nitrogen/generated/android/c++/JOptions.hpp +19 -14
- package/nitrogen/generated/android/c++/{JIosOutput.hpp → JOutput.hpp} +15 -15
- package/nitrogen/generated/android/c++/JOutputType.hpp +82 -0
- package/nitrogen/generated/android/c++/JPlayback.hpp +2 -0
- package/nitrogen/generated/android/c++/JPlaybackActiveTrackChangedEvent.hpp +6 -0
- package/nitrogen/generated/android/c++/JPlaybackError.hpp +18 -3
- package/nitrogen/generated/android/c++/JPlaybackErrorEvent.hpp +2 -0
- package/nitrogen/generated/android/c++/JPlaybackErrorKind.hpp +76 -0
- package/nitrogen/generated/android/c++/JPlaybackState.hpp +3 -3
- package/nitrogen/generated/android/c++/JPlayerCapabilities.hpp +11 -5
- package/nitrogen/generated/android/c++/{JNotificationButton.hpp → JRemoteButton.hpp} +20 -20
- package/nitrogen/generated/android/c++/JRemoteButtonLayout.hpp +86 -0
- package/nitrogen/generated/android/c++/JResolvedTrack.hpp +23 -5
- package/nitrogen/generated/android/c++/JRetryConfig.hpp +11 -7
- package/nitrogen/generated/android/c++/JSearchMode.hpp +27 -9
- package/nitrogen/generated/android/c++/JSearchParams.hpp +9 -3
- package/nitrogen/generated/android/c++/JStallReason.hpp +58 -0
- package/nitrogen/generated/android/c++/JTrack.hpp +23 -5
- package/nitrogen/generated/android/c++/JTrackLoadEvent.hpp +6 -0
- package/nitrogen/generated/android/c++/JTrackRequest.hpp +93 -0
- package/nitrogen/generated/android/c++/JTransformableRequestConfig.hpp +14 -1
- package/nitrogen/generated/android/c++/JVariant_Boolean_FavoriteConfig.cpp +26 -0
- package/nitrogen/generated/android/c++/JVariant_Boolean_FavoriteConfig.hpp +71 -0
- package/nitrogen/generated/android/c++/JVariant_NullType_RemoteButtonLayout.cpp +26 -0
- package/nitrogen/generated/android/c++/JVariant_NullType_RemoteButtonLayout.hpp +75 -0
- package/nitrogen/generated/android/c++/JVariant_ResolvedTrack_BrowseError_Promise_BrowseResult_.cpp +41 -0
- package/nitrogen/generated/android/c++/JVariant_ResolvedTrack_BrowseError_Promise_BrowseResult_.hpp +121 -0
- package/nitrogen/generated/android/c++/JVariant_String_ArtworkVariants.cpp +26 -0
- package/nitrogen/generated/android/c++/JVariant_String_ArtworkVariants.hpp +70 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/AndroidAudioContentType.kt +4 -4
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/AndroidOptions.kt +3 -9
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ArtworkRequestConfig.kt +10 -4
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ArtworkVariants.kt +41 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/CarPlayNowPlayingButton.kt +3 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{HeartRating.kt → FavoriteConfig.kt} +6 -6
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{RatingType.kt → FavoritesMatchMode.kt} +5 -10
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/FormatNowPlayingParams.kt +50 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/FormattedNavigationError.kt +2 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_RequestConfig___MediaTransformParams.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_RequestConfig___RequestConfig_std__optional_std__unordered_map_std__string__std__string__.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_RequestConfig___Track.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__optional_NowPlayingUpdate____FormatNowPlayingParams.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__optional_std__string____Track.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_GateDecision_____NativeGateRequest.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_TransformableRequestConfig____.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError______BrowserSourceCallbackParam.kt → Func_std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError__std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError_______BrowserSourceCallbackParam.kt} +12 -12
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{Func_void_RemoteSetRatingEvent.kt → Func_void_GateEvent.kt} +9 -9
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{Func_void_IosOutput.kt → Func_void_Output.kt} +9 -9
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_bool.kt +9 -9
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{ThumbsRating.kt → Gate.kt} +9 -6
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{PercentageRating.kt → GateDecision.kt} +9 -6
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{StarRating.kt → GateEvent.kt} +6 -6
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{NotificationButton.kt → GateReason.kt} +5 -8
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/HybridAudioBrowserSpec.kt +104 -110
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/IOSOptions.kt +44 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ImageRowItem.kt +24 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/MediaReference.kt +23 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/MediaRequestConfig.kt +10 -4
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{PartialAndroidSetupPlayerOptions.kt → NativeAndroidSetupOptions.kt} +5 -5
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NativeBrowserConfiguration.kt +18 -6
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{RemoteSetRatingEvent.kt → NativeGateRequest.kt} +12 -6
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{PartialIOSSetupPlayerOptions.kt → NativeIOSSetupOptions.kt} +5 -5
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NativeRouteEntry.kt +4 -4
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NativeSetupPlayerOptions.kt +66 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NativeUpdateOptions.kt +6 -6
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NavigationErrorType.kt +3 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NitroAndroidUpdateOptions.kt +3 -9
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NitroIOSUpdateOptions.kt +44 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NowPlayingMetadata.kt +3 -6
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NowPlayingUpdate.kt +6 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Options.kt +3 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{IosOutput.kt → Output.kt} +6 -6
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/OutputType.kt +31 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlaybackError.kt +12 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlaybackErrorKind.kt +29 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlaybackState.kt +6 -6
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlayerCapabilities.kt +2 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RemoteButton.kt +26 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RemoteButtonLayout.kt +44 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ResolvedTrack.kt +12 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RetryConfig.kt +7 -4
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/SearchMode.kt +12 -6
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/SearchParams.kt +6 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/StallReason.kt +23 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Track.kt +12 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/TrackRequest.kt +44 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/TransformableRequestConfig.kt +7 -4
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Variant_Boolean_FavoriteConfig.kt +53 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{Variant_NullType_NotificationButtonLayout.kt → Variant_NullType_RemoteButtonLayout.kt} +9 -9
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Variant_ResolvedTrack_BrowseError_Promise_BrowseResult_.kt +65 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Variant_String_ArtworkVariants.kt +53 -0
- package/nitrogen/generated/ios/AudioBrowser-Swift-Cxx-Bridge.cpp +139 -28
- package/nitrogen/generated/ios/AudioBrowser-Swift-Cxx-Bridge.hpp +1126 -490
- package/nitrogen/generated/ios/AudioBrowser-Swift-Cxx-Umbrella.hpp +66 -45
- package/nitrogen/generated/ios/c++/HybridAudioBrowserSpecSwift.hpp +178 -120
- package/nitrogen/generated/ios/swift/AndroidAudioContentType.swift +8 -8
- package/nitrogen/generated/ios/swift/AndroidOptions.swift +12 -22
- package/nitrogen/generated/ios/swift/ArtworkRequestConfig.swift +95 -1
- package/nitrogen/generated/ios/swift/ArtworkVariants.swift +34 -0
- package/nitrogen/generated/ios/swift/CarPlayNowPlayingButton.swift +4 -4
- package/nitrogen/generated/ios/swift/FavoriteConfig.swift +29 -0
- package/nitrogen/generated/ios/swift/FavoritesMatchMode.swift +40 -0
- package/nitrogen/generated/ios/swift/FormatNowPlayingParams.swift +67 -0
- package/nitrogen/generated/ios/swift/FormattedNavigationError.swift +17 -4
- package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_RequestConfig___MediaTransformParams.swift +54 -0
- package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_RequestConfig___RequestConfig_std__optional_std__unordered_map_std__string__std__string__.swift +69 -0
- package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_RequestConfig___Track.swift +54 -0
- package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__optional_NowPlayingUpdate____FormatNowPlayingParams.swift +60 -0
- package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__optional_std__string____Track.swift +60 -0
- package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_GateDecision_____NativeGateRequest.swift +61 -0
- package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_TransformableRequestConfig____.swift +61 -0
- package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError__std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError_______BrowserSourceCallbackParam.swift +77 -0
- package/nitrogen/generated/ios/swift/Func_void_GateDecision.swift +46 -0
- package/nitrogen/generated/ios/swift/{Func_void_RemoteSetRatingEvent.swift → Func_void_GateEvent.swift} +10 -10
- package/nitrogen/generated/ios/swift/{Func_void_IosOutput.swift → Func_void_Output.swift} +10 -10
- package/nitrogen/generated/ios/swift/Func_void_TransformableRequestConfig.swift +46 -0
- package/nitrogen/generated/ios/swift/Func_void_bool.swift +5 -5
- package/nitrogen/generated/ios/swift/Func_void_std__optional_NowPlayingUpdate_.swift +46 -0
- package/nitrogen/generated/ios/swift/Func_void_std__optional_std__string_.swift +53 -0
- package/nitrogen/generated/ios/swift/{Func_void_std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError___.swift → Func_void_std__shared_ptr_Promise_GateDecision__.swift} +17 -17
- package/nitrogen/generated/ios/swift/Func_void_std__shared_ptr_Promise_TransformableRequestConfig__.swift +66 -0
- package/nitrogen/generated/ios/swift/Func_void_std__variant_ResolvedTrack__BrowseError__std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError____.swift +81 -0
- package/nitrogen/generated/ios/swift/Gate.swift +47 -0
- package/nitrogen/generated/ios/swift/GateDecision.swift +40 -0
- package/nitrogen/generated/ios/swift/GateEvent.swift +29 -0
- package/nitrogen/generated/ios/swift/GateReason.swift +40 -0
- package/nitrogen/generated/ios/swift/HybridAudioBrowserSpec.swift +21 -15
- package/nitrogen/generated/ios/swift/HybridAudioBrowserSpec_cxx.swift +232 -199
- package/nitrogen/generated/ios/swift/IOSOptions.swift +51 -0
- package/nitrogen/generated/ios/swift/ImageRowItem.swift +121 -2
- package/nitrogen/generated/ios/swift/MediaReference.swift +40 -0
- package/nitrogen/generated/ios/swift/MediaRequestConfig.swift +107 -1
- package/nitrogen/generated/ios/swift/{PartialAndroidSetupPlayerOptions.swift → NativeAndroidSetupOptions.swift} +5 -5
- package/nitrogen/generated/ios/swift/NativeBrowserConfiguration.swift +161 -22
- package/nitrogen/generated/ios/swift/NativeGateRequest.swift +58 -0
- package/nitrogen/generated/ios/swift/{PartialIOSSetupPlayerOptions.swift → NativeIOSSetupOptions.swift} +5 -5
- package/nitrogen/generated/ios/swift/NativeRouteEntry.swift +19 -19
- package/nitrogen/generated/ios/swift/NativeSetupPlayerOptions.swift +206 -0
- package/nitrogen/generated/ios/swift/NativeUpdateOptions.swift +12 -25
- package/nitrogen/generated/ios/swift/NavigationErrorType.swift +8 -0
- package/nitrogen/generated/ios/swift/NitroAndroidUpdateOptions.swift +12 -41
- package/nitrogen/generated/ios/swift/NitroIOSUpdateOptions.swift +90 -0
- package/nitrogen/generated/ios/swift/NowPlayingMetadata.swift +1 -48
- package/nitrogen/generated/ios/swift/NowPlayingUpdate.swift +19 -1
- package/nitrogen/generated/ios/swift/Options.swift +10 -4
- package/nitrogen/generated/ios/swift/{IosOutput.swift → Output.swift} +7 -7
- package/nitrogen/generated/ios/swift/OutputType.swift +72 -0
- package/nitrogen/generated/ios/swift/PlaybackError.swift +43 -2
- package/nitrogen/generated/ios/swift/PlaybackErrorKind.swift +64 -0
- package/nitrogen/generated/ios/swift/PlaybackState.swift +4 -4
- package/nitrogen/generated/ios/swift/PlayerCapabilities.swift +27 -8
- package/nitrogen/generated/ios/swift/{NotificationButton.swift → RemoteButton.swift} +10 -10
- package/nitrogen/generated/ios/swift/RemoteButtonLayout.swift +57 -0
- package/nitrogen/generated/ios/swift/ResolvedTrack.swift +74 -8
- package/nitrogen/generated/ios/swift/RetryConfig.swift +35 -4
- package/nitrogen/generated/ios/swift/SearchMode.swift +36 -12
- package/nitrogen/generated/ios/swift/SearchParams.swift +7 -2
- package/nitrogen/generated/ios/swift/StallReason.swift +40 -0
- package/nitrogen/generated/ios/swift/Track.swift +74 -8
- package/nitrogen/generated/ios/swift/TrackRequest.swift +106 -0
- package/nitrogen/generated/ios/swift/TransformableRequestConfig.swift +60 -1
- package/nitrogen/generated/ios/swift/Variant_Bool_FavoriteConfig.swift +18 -0
- package/nitrogen/generated/ios/swift/{Variant_NullType_NotificationButtonLayout.swift → Variant_NullType_RemoteButtonLayout.swift} +3 -3
- package/nitrogen/generated/ios/swift/Variant_ResolvedTrack_BrowseError_Promise_BrowseResult_.swift +19 -0
- package/nitrogen/generated/ios/swift/Variant_String_ArtworkVariants.swift +18 -0
- package/nitrogen/generated/shared/c++/AndroidAudioContentType.hpp +10 -10
- package/nitrogen/generated/shared/c++/AndroidOptions.hpp +8 -19
- package/nitrogen/generated/shared/c++/ArtworkRequestConfig.hpp +10 -2
- package/nitrogen/generated/shared/c++/ArtworkVariants.hpp +87 -0
- package/nitrogen/generated/shared/c++/CarPlayNowPlayingButton.hpp +6 -6
- package/nitrogen/generated/shared/c++/EqualizerSettings.hpp +0 -2
- package/nitrogen/generated/shared/c++/{StarRating.hpp → FavoriteConfig.hpp} +18 -17
- package/nitrogen/generated/shared/c++/FavoritesMatchMode.hpp +76 -0
- package/nitrogen/generated/shared/c++/FormatNowPlayingParams.hpp +110 -0
- package/nitrogen/generated/shared/c++/FormattedNavigationError.hpp +6 -5
- package/nitrogen/generated/shared/c++/{PercentageRating.hpp → Gate.hpp} +21 -16
- package/nitrogen/generated/shared/c++/{HeartRating.hpp → GateDecision.hpp} +23 -17
- package/nitrogen/generated/shared/c++/{ThumbsRating.hpp → GateEvent.hpp} +18 -17
- package/nitrogen/generated/shared/c++/GateReason.hpp +76 -0
- package/nitrogen/generated/shared/c++/HybridAudioBrowserSpec.cpp +22 -19
- package/nitrogen/generated/shared/c++/HybridAudioBrowserSpec.hpp +45 -36
- package/nitrogen/generated/shared/c++/IOSOptions.hpp +91 -0
- package/nitrogen/generated/shared/c++/ImageRowItem.hpp +33 -2
- package/nitrogen/generated/shared/c++/MediaReference.hpp +76 -0
- package/nitrogen/generated/shared/c++/MediaRequestConfig.hpp +10 -2
- package/nitrogen/generated/shared/c++/{PartialAndroidSetupPlayerOptions.hpp → NativeAndroidSetupOptions.hpp} +11 -11
- package/nitrogen/generated/shared/c++/NativeBrowserConfiguration.hpp +31 -15
- package/nitrogen/generated/shared/c++/NativeGateRequest.hpp +97 -0
- package/nitrogen/generated/shared/c++/{PartialIOSSetupPlayerOptions.hpp → NativeIOSSetupOptions.hpp} +11 -11
- package/nitrogen/generated/shared/c++/NativeRouteEntry.hpp +5 -5
- package/nitrogen/generated/shared/c++/NativeSetupPlayerOptions.hpp +138 -0
- package/nitrogen/generated/shared/c++/NativeUpdateOptions.hpp +9 -7
- package/nitrogen/generated/shared/c++/NavigationErrorType.hpp +8 -0
- package/nitrogen/generated/shared/c++/NitroAndroidUpdateOptions.hpp +8 -19
- package/nitrogen/generated/shared/c++/NitroIOSUpdateOptions.hpp +92 -0
- package/nitrogen/generated/shared/c++/NowPlayingMetadata.hpp +3 -19
- package/nitrogen/generated/shared/c++/NowPlayingUpdate.hpp +6 -2
- package/nitrogen/generated/shared/c++/Options.hpp +8 -8
- package/nitrogen/generated/shared/c++/{IosOutput.hpp → Output.hpp} +18 -18
- package/nitrogen/generated/shared/c++/OutputType.hpp +108 -0
- package/nitrogen/generated/shared/c++/PlaybackError.hpp +18 -3
- package/nitrogen/generated/shared/c++/PlaybackErrorKind.hpp +100 -0
- package/nitrogen/generated/shared/c++/PlaybackState.hpp +9 -9
- package/nitrogen/generated/shared/c++/PlayerCapabilities.hpp +9 -6
- package/nitrogen/generated/shared/c++/{NotificationButton.hpp → RemoteButton.hpp} +25 -25
- package/nitrogen/generated/shared/c++/RemoteButtonLayout.hpp +94 -0
- package/nitrogen/generated/shared/c++/ResolvedTrack.hpp +24 -5
- package/nitrogen/generated/shared/c++/RetryConfig.hpp +10 -6
- package/nitrogen/generated/shared/c++/SearchMode.hpp +39 -15
- package/nitrogen/generated/shared/c++/SearchParams.hpp +9 -2
- package/nitrogen/generated/shared/c++/StallReason.hpp +76 -0
- package/nitrogen/generated/shared/c++/Track.hpp +24 -5
- package/nitrogen/generated/shared/c++/TrackRequest.hpp +93 -0
- package/nitrogen/generated/shared/c++/TransformableRequestConfig.hpp +6 -2
- package/package.json +20 -8
- package/src/AudioBrowser.ts +1 -1
- package/src/CLAUDE.md +52 -0
- package/src/codegen-no-config-variant.test.ts +70 -0
- package/src/features/battery.test.ts +79 -0
- package/src/features/browser-config.test.ts +110 -0
- package/src/features/browser-config.ts +293 -0
- package/src/features/browser.test.ts +19 -0
- package/src/features/browser.ts +59 -202
- package/src/features/carConnection.ts +36 -0
- package/src/features/equalizer.ts +1 -1
- package/src/features/errors.ts +71 -5
- package/src/features/favorites.ts +1 -1
- package/src/features/gate.test.ts +72 -0
- package/src/features/gate.ts +170 -0
- package/src/features/hook-wiring.test.ts +254 -0
- package/src/features/index.ts +2 -0
- package/src/features/metadata.ts +26 -15
- package/src/features/network.ts +1 -1
- package/src/features/nowPlaying.ts +37 -1
- package/src/features/output.ts +35 -22
- package/src/features/playback/controls.ts +8 -0
- package/src/features/playback/index.ts +1 -0
- package/src/features/playback/playWhenReady.ts +1 -1
- package/src/features/playback/playing.ts +1 -1
- package/src/features/playback/progress.test.ts +169 -0
- package/src/features/playback/progress.ts +32 -13
- package/src/features/playback/state.ts +1 -1
- package/src/features/playback/trackPlaybackTime.test.ts +76 -0
- package/src/features/playback/trackPlaybackTime.ts +101 -0
- package/src/features/playback/volume.ts +2 -2
- package/src/features/player/options.test.ts +38 -0
- package/src/features/player/options.ts +217 -110
- package/src/features/player/setup.test.ts +125 -0
- package/src/features/player/setup.ts +400 -175
- package/src/features/player/validateOptions.ts +19 -0
- package/src/features/queue/activeTrack.ts +1 -1
- package/src/features/queue/queue.test.ts +36 -0
- package/src/features/queue/queue.ts +17 -6
- package/src/features/queue/repeatMode.ts +1 -1
- package/src/features/queue/shuffle.ts +1 -1
- package/src/features/remoteControls.ts +13 -115
- package/src/features/sleepTimer.test.ts +172 -0
- package/src/features/sleepTimer.ts +32 -5
- package/src/native.ts +5 -0
- package/src/native.web.ts +4 -1
- package/src/public-surface.test.ts +107 -0
- package/src/specs/audio-browser.nitro.ts +132 -42
- package/src/test-utils/reactNativeStub.ts +60 -0
- package/src/types/browser-native.ts +19 -6
- package/src/types/browser-nodes.ts +160 -13
- package/src/types/browser.ts +377 -89
- package/src/utils/LazyNativeEmitter.ts +9 -8
- package/src/utils/NativeUpdatedValue.ts +0 -2
- package/src/utils/artwork.ts +30 -0
- package/src/utils/useDebug.test.ts +182 -0
- package/src/utils/useNativeUpdatedValue.test.ts +103 -0
- package/src/web/NativeAudioBrowser.playWhenReady.test.ts +301 -0
- package/src/web/NativeAudioBrowser.ts +366 -159
- package/src/web/TrackPlayer/PlaybackStateMachine.test.ts +139 -0
- package/src/web/TrackPlayer/PlaybackStateMachine.ts +82 -0
- package/src/web/TrackPlayer/PlaybackTimer.test.ts +67 -0
- package/src/web/TrackPlayer/PlaybackTimer.ts +33 -0
- package/src/web/TrackPlayer/Player.dispatch.test.ts +229 -0
- package/src/web/TrackPlayer/Player.load.test.ts +86 -0
- package/src/web/TrackPlayer/Player.ts +113 -39
- package/src/web/TrackPlayer/PlayingStateFactory.test.ts +51 -0
- package/src/web/TrackPlayer/PlayingStateFactory.ts +24 -0
- package/src/web/TrackPlayer/QueueManager.test.ts +289 -0
- package/src/web/TrackPlayer/QueueManager.ts +302 -0
- package/src/web/TrackPlayer/QueuePlayer.ts +188 -0
- package/src/web/TrackPlayer/RepeatMode.ts +1 -1
- package/src/web/TrackPlayer/SleepTimer.ts +38 -3
- package/src/web/TrackPlayer/VolumeFader.ts +74 -0
- package/src/web/TrackPlayer/index.ts +2 -1
- package/src/web/browser/BrowserManager.ts +231 -62
- package/src/web/browser/NavigationErrorManager.ts +3 -1
- package/src/web/browser/SearchManager.ts +11 -15
- package/src/web/browser/__tests__/layer-resolver.test.ts +69 -0
- package/src/web/browser/assertBrowsePageShape.test.ts +27 -0
- package/src/web/browser/assertBrowsePageShape.ts +27 -0
- package/src/web/browser/classifyTrackNavigation.test.ts +41 -0
- package/src/web/browser/classifyTrackNavigation.ts +35 -0
- package/src/web/browser/parseSearchResponse.test.ts +25 -0
- package/src/web/browser/parseSearchResponse.ts +15 -0
- package/src/web/http/HttpClient.ts +5 -35
- package/src/web/http/RequestConfigBuilder.test.ts +59 -0
- package/src/web/http/RequestConfigBuilder.ts +120 -63
- package/src/web/playbackErrorKind.test.ts +55 -0
- package/src/web/playbackErrorKind.ts +56 -0
- package/src/web/player/MediaSessionManager.test.ts +220 -0
- package/src/web/player/MediaSessionManager.ts +151 -0
- package/src/web/player/NowPlayingManager.test.ts +46 -0
- package/src/web/player/NowPlayingManager.ts +6 -5
- package/src/web/player/OptionsManager.ts +12 -18
- package/src/web/player/RemoteCommandController.test.ts +171 -0
- package/src/web/player/RemoteCommandController.ts +166 -0
- package/android/src/main/java/com/audiobrowser/player/PlaybackProgressUpdateManager.kt +0 -59
- package/android/src/main/java/com/audiobrowser/util/RatingFactory.kt +0 -72
- package/android/src/main/java/com/audiobrowser/util/ResolvedTrackFactory.kt +0 -36
- package/android/src/test/java/com/audiobrowser/player/PlaybackProgressUpdateManagerTest.kt +0 -146
- package/ios/CarPlay/Track+CarPlay.swift +0 -63
- package/ios/Model/MediaURL.swift +0 -67
- package/ios/NowPlayingInfo/NowPlayingInfoCenter.swift +0 -9
- package/ios/Player/PlaybackProgressUpdateManager.swift +0 -68
- package/ios/Tests/PlaybackProgressUpdateManagerTests.swift +0 -166
- package/lib/commonjs/features/rating.js +0 -2
- package/lib/commonjs/features/rating.js.map +0 -1
- package/lib/commonjs/types/player.js +0 -2
- package/lib/commonjs/types/player.js.map +0 -1
- package/lib/commonjs/web/SimpleRouter.test.js +0 -174
- package/lib/commonjs/web/SimpleRouter.test.js.map +0 -1
- package/lib/commonjs/web/TrackPlayer/PlaylistPlayer.js +0 -293
- package/lib/commonjs/web/TrackPlayer/PlaylistPlayer.js.map +0 -1
- package/lib/module/features/rating.js +0 -2
- package/lib/module/features/rating.js.map +0 -1
- package/lib/module/types/player.js +0 -2
- package/lib/module/types/player.js.map +0 -1
- package/lib/module/web/SimpleRouter.test.js +0 -174
- package/lib/module/web/SimpleRouter.test.js.map +0 -1
- package/lib/module/web/TrackPlayer/PlaylistPlayer.js +0 -288
- package/lib/module/web/TrackPlayer/PlaylistPlayer.js.map +0 -1
- package/lib/typescript/src/features/rating.d.ts +0 -14
- package/lib/typescript/src/features/rating.d.ts.map +0 -1
- package/lib/typescript/src/native.web.d.ts +0 -3
- package/lib/typescript/src/native.web.d.ts.map +0 -1
- package/lib/typescript/src/types/player.d.ts +0 -64
- package/lib/typescript/src/types/player.d.ts.map +0 -1
- package/lib/typescript/src/web/NativeAudioBrowser.d.ts +0 -188
- package/lib/typescript/src/web/NativeAudioBrowser.d.ts.map +0 -1
- package/lib/typescript/src/web/SimpleRouter.d.ts +0 -40
- package/lib/typescript/src/web/SimpleRouter.d.ts.map +0 -1
- package/lib/typescript/src/web/SimpleRouter.test.d.ts +0 -2
- package/lib/typescript/src/web/SimpleRouter.test.d.ts.map +0 -1
- package/lib/typescript/src/web/TrackPlayer/Event.d.ts +0 -11
- package/lib/typescript/src/web/TrackPlayer/Event.d.ts.map +0 -1
- package/lib/typescript/src/web/TrackPlayer/Player.d.ts +0 -59
- package/lib/typescript/src/web/TrackPlayer/Player.d.ts.map +0 -1
- package/lib/typescript/src/web/TrackPlayer/PlaylistPlayer.d.ts +0 -39
- package/lib/typescript/src/web/TrackPlayer/PlaylistPlayer.d.ts.map +0 -1
- package/lib/typescript/src/web/TrackPlayer/RepeatMode.d.ts +0 -6
- package/lib/typescript/src/web/TrackPlayer/RepeatMode.d.ts.map +0 -1
- package/lib/typescript/src/web/TrackPlayer/SetupNotCalledError.d.ts +0 -4
- package/lib/typescript/src/web/TrackPlayer/SetupNotCalledError.d.ts.map +0 -1
- package/lib/typescript/src/web/TrackPlayer/SleepTimer.d.ts +0 -34
- package/lib/typescript/src/web/TrackPlayer/SleepTimer.d.ts.map +0 -1
- package/lib/typescript/src/web/TrackPlayer/State.d.ts +0 -13
- package/lib/typescript/src/web/TrackPlayer/State.d.ts.map +0 -1
- package/lib/typescript/src/web/TrackPlayer/index.d.ts +0 -5
- package/lib/typescript/src/web/TrackPlayer/index.d.ts.map +0 -1
- package/lib/typescript/src/web/browser/BrowserManager.d.ts +0 -154
- package/lib/typescript/src/web/browser/BrowserManager.d.ts.map +0 -1
- package/lib/typescript/src/web/browser/FavoriteManager.d.ts +0 -42
- package/lib/typescript/src/web/browser/FavoriteManager.d.ts.map +0 -1
- package/lib/typescript/src/web/browser/NavigationErrorManager.d.ts +0 -40
- package/lib/typescript/src/web/browser/NavigationErrorManager.d.ts.map +0 -1
- package/lib/typescript/src/web/browser/SearchManager.d.ts +0 -22
- package/lib/typescript/src/web/browser/SearchManager.d.ts.map +0 -1
- package/lib/typescript/src/web/http/HttpClient.d.ts +0 -25
- package/lib/typescript/src/web/http/HttpClient.d.ts.map +0 -1
- package/lib/typescript/src/web/http/RequestConfigBuilder.d.ts +0 -98
- package/lib/typescript/src/web/http/RequestConfigBuilder.d.ts.map +0 -1
- package/lib/typescript/src/web/player/NowPlayingManager.d.ts +0 -34
- package/lib/typescript/src/web/player/NowPlayingManager.d.ts.map +0 -1
- package/lib/typescript/src/web/player/OptionsManager.d.ts +0 -32
- package/lib/typescript/src/web/player/OptionsManager.d.ts.map +0 -1
- package/lib/typescript/src/web/util/BrowserPathHelper.d.ts +0 -69
- package/lib/typescript/src/web/util/BrowserPathHelper.d.ts.map +0 -1
- package/lib/typescript/src/web/util/shuffle.d.ts +0 -8
- package/lib/typescript/src/web/util/shuffle.d.ts.map +0 -1
- package/nitrogen/generated/android/c++/JAndroidUpdateOptions.hpp +0 -86
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError______BrowserSourceCallbackParam.hpp +0 -147
- package/nitrogen/generated/android/c++/JFunc_void_IosOutput.hpp +0 -80
- package/nitrogen/generated/android/c++/JFunc_void_RemoteSetRatingEvent.hpp +0 -87
- package/nitrogen/generated/android/c++/JHeartRating.hpp +0 -57
- package/nitrogen/generated/android/c++/JIosOutputType.hpp +0 -85
- package/nitrogen/generated/android/c++/JNotificationButtonLayout.hpp +0 -94
- package/nitrogen/generated/android/c++/JPartialSetupPlayerOptions.hpp +0 -96
- package/nitrogen/generated/android/c++/JPercentageRating.hpp +0 -57
- package/nitrogen/generated/android/c++/JRatingType.hpp +0 -73
- package/nitrogen/generated/android/c++/JRemoteSetRatingEvent.hpp +0 -66
- package/nitrogen/generated/android/c++/JStarRating.hpp +0 -57
- package/nitrogen/generated/android/c++/JUpdateOptions.hpp +0 -105
- package/nitrogen/generated/android/c++/JVariant_HeartRating_ThumbsRating_StarRating_PercentageRating.cpp +0 -34
- package/nitrogen/generated/android/c++/JVariant_HeartRating_ThumbsRating_StarRating_PercentageRating.hpp +0 -105
- package/nitrogen/generated/android/c++/JVariant_NullType_NotificationButtonLayout.cpp +0 -26
- package/nitrogen/generated/android/c++/JVariant_NullType_NotificationButtonLayout.hpp +0 -75
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/AndroidUpdateOptions.kt +0 -50
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/IosOutputType.kt +0 -32
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NotificationButtonLayout.kt +0 -50
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PartialSetupPlayerOptions.kt +0 -47
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/UpdateOptions.kt +0 -53
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Variant_HeartRating_ThumbsRating_StarRating_PercentageRating.kt +0 -77
- package/nitrogen/generated/ios/swift/AndroidUpdateOptions.swift +0 -119
- package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError______BrowserSourceCallbackParam.swift +0 -68
- package/nitrogen/generated/ios/swift/HeartRating.swift +0 -29
- package/nitrogen/generated/ios/swift/IosOutputType.swift +0 -76
- package/nitrogen/generated/ios/swift/NotificationButtonLayout.swift +0 -92
- package/nitrogen/generated/ios/swift/PartialSetupPlayerOptions.swift +0 -101
- package/nitrogen/generated/ios/swift/PercentageRating.swift +0 -29
- package/nitrogen/generated/ios/swift/RatingType.swift +0 -60
- package/nitrogen/generated/ios/swift/RemoteSetRatingEvent.swift +0 -58
- package/nitrogen/generated/ios/swift/StarRating.swift +0 -29
- package/nitrogen/generated/ios/swift/ThumbsRating.swift +0 -29
- package/nitrogen/generated/ios/swift/UpdateOptions.swift +0 -143
- package/nitrogen/generated/ios/swift/Variant_HeartRating_ThumbsRating_StarRating_PercentageRating.swift +0 -20
- package/nitrogen/generated/shared/c++/AndroidUpdateOptions.hpp +0 -109
- package/nitrogen/generated/shared/c++/IosOutputType.hpp +0 -112
- package/nitrogen/generated/shared/c++/NotificationButtonLayout.hpp +0 -102
- package/nitrogen/generated/shared/c++/PartialSetupPlayerOptions.hpp +0 -104
- package/nitrogen/generated/shared/c++/RatingType.hpp +0 -96
- package/nitrogen/generated/shared/c++/RemoteSetRatingEvent.hpp +0 -94
- package/nitrogen/generated/shared/c++/UpdateOptions.hpp +0 -111
- package/src/features/rating.ts +0 -17
- package/src/types/player.ts +0 -69
- package/src/web/TrackPlayer/PlaylistPlayer.ts +0 -346
|
@@ -4,26 +4,50 @@ import android.os.Bundle
|
|
|
4
4
|
import androidx.media3.common.Player as MediaPlayer
|
|
5
5
|
import androidx.media3.session.CommandButton
|
|
6
6
|
import androidx.media3.session.MediaSession
|
|
7
|
-
import androidx.media3.session.R
|
|
8
7
|
import androidx.media3.session.SessionCommand
|
|
9
8
|
import androidx.media3.session.SessionCommands
|
|
10
|
-
import com.margelo.nitro.audiobrowser.NotificationButton
|
|
11
|
-
import com.margelo.nitro.audiobrowser.NotificationButtonLayout
|
|
12
9
|
import com.margelo.nitro.audiobrowser.PlayerCapabilities
|
|
10
|
+
import com.margelo.nitro.audiobrowser.RemoteButton
|
|
11
|
+
import com.margelo.nitro.audiobrowser.RemoteButtonLayout
|
|
13
12
|
import timber.log.Timber
|
|
14
13
|
|
|
14
|
+
/**
|
|
15
|
+
* A slot's Media3 preference list: the requested slot, then OVERFLOW as a fallback.
|
|
16
|
+
*
|
|
17
|
+
* `slots` is a preference order, not a coordinate — Media3 places a button in the first slot in the
|
|
18
|
+
* list "that exists, isn't already occupied and that allows this type of button". Naming OVERFLOW
|
|
19
|
+
* second means a button whose primary position is unavailable on some surface demotes instead of
|
|
20
|
+
* disappearing, because every flattening
|
|
21
|
+
* (`CommandButton.getCustomLayoutFromMediaButtonPreferences`, run by both `MediaSessionLegacyStub`
|
|
22
|
+
* for Android Auto and the Android 13+ controls, and `DefaultMediaNotificationProvider` for the
|
|
23
|
+
* notification) keeps a button only if it won BACK, won FORWARD, or *contains* OVERFLOW.
|
|
24
|
+
*/
|
|
25
|
+
internal fun media3SlotsFor(slot: ButtonSlot): IntArray =
|
|
26
|
+
when (slot) {
|
|
27
|
+
ButtonSlot.BACK -> intArrayOf(CommandButton.SLOT_BACK, CommandButton.SLOT_OVERFLOW)
|
|
28
|
+
ButtonSlot.FORWARD -> intArrayOf(CommandButton.SLOT_FORWARD, CommandButton.SLOT_OVERFLOW)
|
|
29
|
+
ButtonSlot.OVERFLOW -> intArrayOf(CommandButton.SLOT_OVERFLOW)
|
|
30
|
+
}
|
|
31
|
+
|
|
15
32
|
/**
|
|
16
33
|
* MediaSession manager that handles command configuration and execution.
|
|
17
34
|
*
|
|
18
35
|
* Responsibilities:
|
|
19
|
-
* - Maps player capabilities to MediaSession commands
|
|
36
|
+
* - Maps player capabilities to MediaSession commands
|
|
37
|
+
* - Builds the single, slot-annotated button layout published to every surface
|
|
20
38
|
* - Updates MediaSession configuration and applies changes immediately
|
|
21
39
|
* - Builds connection results for new MediaSession controllers
|
|
22
40
|
* - Handles execution of custom MediaSession commands (jump actions)
|
|
23
|
-
* - Maintains proper separation between global capabilities and notification-specific controls
|
|
24
41
|
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
42
|
+
* Capabilities decide what the player can do; the button layout decides where those buttons sit.
|
|
43
|
+
* Placement never revokes a capability — a control left out of the layout still works from a
|
|
44
|
+
* Bluetooth remote or headset.
|
|
45
|
+
*
|
|
46
|
+
* There is ONE layout, published session-wide via `setMediaButtonPreferences`. Media3 fans it out:
|
|
47
|
+
* `MediaNotificationManager` renders it as the MediaStyle notification (Android 12 and below), and
|
|
48
|
+
* `MediaSessionLegacyStub` converts it into the platform PlaybackState plus the slot-reservation
|
|
49
|
+
* extras that Android Auto and the Android 13+ system media controls read. Publishing
|
|
50
|
+
* per-controller instead would reach neither, since Android Auto connects as a legacy controller.
|
|
27
51
|
*/
|
|
28
52
|
class MediaSessionCommandManager {
|
|
29
53
|
|
|
@@ -31,59 +55,100 @@ class MediaSessionCommandManager {
|
|
|
31
55
|
private const val CUSTOM_ACTION_JUMP_BACKWARD = "JUMP_BACKWARD"
|
|
32
56
|
private const val CUSTOM_ACTION_JUMP_FORWARD = "JUMP_FORWARD"
|
|
33
57
|
const val CUSTOM_ACTION_FAVORITE = "FAVORITE"
|
|
34
|
-
}
|
|
35
58
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
59
|
+
/** Matches PlayerUpdateOptions.forwardJumpInterval/backwardJumpInterval */
|
|
60
|
+
private const val DEFAULT_JUMP_INTERVAL = 15.0
|
|
61
|
+
}
|
|
39
62
|
|
|
40
|
-
/**
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
63
|
+
/**
|
|
64
|
+
* Media3 ships numbered icons for 5, 10, 15 and 30 seconds; every other interval falls back to
|
|
65
|
+
* the unnumbered arrow.
|
|
66
|
+
*
|
|
67
|
+
* The match is exact, not rounded. A numbered icon is a claim about how far the button seeks, so
|
|
68
|
+
* a 14.6s interval must not draw "15" — it would promise a jump the player never makes. Better an
|
|
69
|
+
* honest arrow than a wrong number.
|
|
70
|
+
*
|
|
71
|
+
* The icon constant — not the drawable — is what a controller that renders its own UI reads, and
|
|
72
|
+
* it is carried through the legacy conversion Android Auto consumes. Building a button with only
|
|
73
|
+
* `setIconResId` leaves the constant at ICON_UNDEFINED, so the car has nothing to draw.
|
|
74
|
+
*/
|
|
75
|
+
private fun jumpForwardIcon(seconds: Double): Int =
|
|
76
|
+
when (seconds) {
|
|
77
|
+
5.0 -> CommandButton.ICON_SKIP_FORWARD_5
|
|
78
|
+
10.0 -> CommandButton.ICON_SKIP_FORWARD_10
|
|
79
|
+
15.0 -> CommandButton.ICON_SKIP_FORWARD_15
|
|
80
|
+
30.0 -> CommandButton.ICON_SKIP_FORWARD_30
|
|
81
|
+
else -> CommandButton.ICON_SKIP_FORWARD
|
|
82
|
+
}
|
|
44
83
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
84
|
+
private fun jumpBackwardIcon(seconds: Double): Int =
|
|
85
|
+
when (seconds) {
|
|
86
|
+
5.0 -> CommandButton.ICON_SKIP_BACK_5
|
|
87
|
+
10.0 -> CommandButton.ICON_SKIP_BACK_10
|
|
88
|
+
15.0 -> CommandButton.ICON_SKIP_BACK_15
|
|
89
|
+
30.0 -> CommandButton.ICON_SKIP_BACK_30
|
|
90
|
+
else -> CommandButton.ICON_SKIP_BACK
|
|
91
|
+
}
|
|
48
92
|
|
|
49
|
-
/**
|
|
50
|
-
|
|
93
|
+
/** Player commands available to every controller, derived from capabilities alone */
|
|
94
|
+
var playerCommands: MediaPlayer.Commands = MediaSession.ConnectionResult.DEFAULT_PLAYER_COMMANDS
|
|
51
95
|
private set
|
|
52
96
|
|
|
53
|
-
/**
|
|
54
|
-
lateinit var
|
|
97
|
+
/** Session commands available to every controller, derived from capabilities alone */
|
|
98
|
+
lateinit var sessionCommands: SessionCommands
|
|
55
99
|
private set
|
|
56
100
|
|
|
57
|
-
/**
|
|
58
|
-
lateinit var
|
|
101
|
+
/** The single slot-annotated button layout, published to every surface */
|
|
102
|
+
lateinit var buttonPreferences: List<CommandButton>
|
|
59
103
|
private set
|
|
60
104
|
|
|
61
105
|
/** Stored state for rebuilding layout */
|
|
62
|
-
private var currentCapabilities: PlayerCapabilities =
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
106
|
+
private var currentCapabilities: PlayerCapabilities =
|
|
107
|
+
PlayerCapabilities(
|
|
108
|
+
play = null,
|
|
109
|
+
pause = null,
|
|
110
|
+
stop = null,
|
|
111
|
+
seekTo = null,
|
|
112
|
+
skipToNext = null,
|
|
113
|
+
skipToPrevious = null,
|
|
114
|
+
jumpForward = null,
|
|
115
|
+
jumpBackward = null,
|
|
116
|
+
favorite = null,
|
|
117
|
+
shuffleMode = null,
|
|
118
|
+
repeatMode = null,
|
|
119
|
+
playbackRate = null,
|
|
120
|
+
)
|
|
121
|
+
private var currentRemoteButtonLayout: RemoteButtonLayout? = null
|
|
71
122
|
private var currentFavorited: Boolean? = null
|
|
123
|
+
private var currentForwardJumpInterval: Double = DEFAULT_JUMP_INTERVAL
|
|
124
|
+
private var currentBackwardJumpInterval: Double = DEFAULT_JUMP_INTERVAL
|
|
125
|
+
|
|
126
|
+
/** The Media3 player command behind each Capability (FAVORITE is a session command). */
|
|
127
|
+
private val capabilityPlayerCommands: Map<Capability, @MediaPlayer.Command Int> =
|
|
128
|
+
mapOf(
|
|
129
|
+
Capability.PLAY_PAUSE to MediaPlayer.COMMAND_PLAY_PAUSE,
|
|
130
|
+
Capability.STOP to MediaPlayer.COMMAND_STOP,
|
|
131
|
+
Capability.SEEK_TO to MediaPlayer.COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM,
|
|
132
|
+
Capability.SKIP_TO_NEXT to MediaPlayer.COMMAND_SEEK_TO_NEXT,
|
|
133
|
+
Capability.SKIP_TO_PREVIOUS to MediaPlayer.COMMAND_SEEK_TO_PREVIOUS,
|
|
134
|
+
Capability.JUMP_FORWARD to MediaPlayer.COMMAND_SEEK_FORWARD,
|
|
135
|
+
Capability.JUMP_BACKWARD to MediaPlayer.COMMAND_SEEK_BACK,
|
|
136
|
+
)
|
|
72
137
|
|
|
138
|
+
// Declared above `init` deliberately: `init` calls `buildPlayerCommands`, which reads
|
|
139
|
+
// `capabilityPlayerCommands`. Kotlin initializes properties in textual order, so this val must
|
|
140
|
+
// precede the init block or it would still be null when the constructor runs (NPE).
|
|
73
141
|
init {
|
|
74
142
|
// Initialize with defaults matching PlayerUpdateOptions (all capabilities enabled)
|
|
75
143
|
val defaultCapabilities = currentCapabilities
|
|
76
144
|
|
|
77
145
|
playerCommands = buildPlayerCommands(defaultCapabilities)
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
notificationSessionCommands = extSessionCommands
|
|
86
|
-
notificationCustomLayout = extCustomLayout
|
|
146
|
+
sessionCommands = buildSessionCommands(defaultCapabilities, searchAvailable = false)
|
|
147
|
+
buttonPreferences =
|
|
148
|
+
buildButtonPreferences(
|
|
149
|
+
deriveButtonSlots(defaultCapabilities, layout = null),
|
|
150
|
+
favorited = null,
|
|
151
|
+
)
|
|
87
152
|
}
|
|
88
153
|
|
|
89
154
|
/**
|
|
@@ -91,60 +156,74 @@ class MediaSessionCommandManager {
|
|
|
91
156
|
*
|
|
92
157
|
* @param mediaSession The MediaSession to configure
|
|
93
158
|
* @param capabilities Global capabilities that enable commands for ALL MediaSession controllers
|
|
94
|
-
* (Bluetooth, Android Auto, lock screen, notification, etc.). All capabilities are enabled
|
|
95
|
-
*
|
|
96
|
-
* @param
|
|
97
|
-
*
|
|
159
|
+
* (Bluetooth, Android Auto, lock screen, notification, etc.). All capabilities are enabled by
|
|
160
|
+
* default - only false values disable them.
|
|
161
|
+
* @param remoteButtonLayout Button layout, published to every surface — the notification, Android
|
|
162
|
+
* Auto, and the Android 13+ system media controls. When null the layout is derived from
|
|
163
|
+
* capabilities using smart defaults.
|
|
98
164
|
* @param searchAvailable Whether search functionality is configured and available
|
|
165
|
+
* @param forwardJumpInterval Seconds per forward jump; selects the button's icon constant
|
|
166
|
+
* @param backwardJumpInterval Seconds per backward jump; selects the button's icon constant
|
|
99
167
|
*
|
|
100
|
-
* Manager initializes with defaults: all
|
|
168
|
+
* Manager initializes with defaults: all capabilities enabled, default placement.
|
|
101
169
|
*/
|
|
102
170
|
fun updateMediaSession(
|
|
103
171
|
mediaSession: MediaSession,
|
|
104
172
|
capabilities: PlayerCapabilities,
|
|
105
|
-
|
|
173
|
+
remoteButtonLayout: RemoteButtonLayout?,
|
|
106
174
|
searchAvailable: Boolean,
|
|
107
|
-
|
|
175
|
+
forwardJumpInterval: Double = DEFAULT_JUMP_INTERVAL,
|
|
176
|
+
backwardJumpInterval: Double = DEFAULT_JUMP_INTERVAL,
|
|
108
177
|
) {
|
|
109
|
-
// Store state for future rebuilds
|
|
178
|
+
// Store state for future rebuilds. The favorite state is deliberately NOT reset here: options
|
|
179
|
+
// and favorites change independently, and rebuilding the layout as un-favorited would blank the
|
|
180
|
+
// heart on every updateOptions() call until the next track change happened to refresh it.
|
|
110
181
|
currentCapabilities = capabilities
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
182
|
+
currentRemoteButtonLayout = remoteButtonLayout
|
|
183
|
+
currentForwardJumpInterval = forwardJumpInterval
|
|
184
|
+
currentBackwardJumpInterval = backwardJumpInterval
|
|
114
185
|
|
|
115
|
-
//
|
|
186
|
+
// Commands gate on capabilities only — placement never revokes one, so a control left out of
|
|
187
|
+
// the layout still works from a Bluetooth remote or headset.
|
|
116
188
|
playerCommands = buildPlayerCommands(capabilities)
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
//
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
notificationCustomLayout = notifButtonPrefs
|
|
189
|
+
sessionCommands = buildSessionCommands(capabilities, searchAvailable)
|
|
190
|
+
buttonPreferences =
|
|
191
|
+
buildButtonPreferences(deriveButtonSlots(capabilities, remoteButtonLayout), currentFavorited)
|
|
192
|
+
|
|
193
|
+
// Push the rebuilt commands to already-connected controllers — buildConnectionResult only
|
|
194
|
+
// serves controllers that connect later, and an Android Auto session lives until the car shuts
|
|
195
|
+
// down. Granted before the layout broadcast so a newly-added button arrives with its command
|
|
196
|
+
// already available; Media3 disables buttons whose backing command is missing.
|
|
197
|
+
mediaSession.connectedControllers.forEach {
|
|
198
|
+
mediaSession.setAvailableCommands(it, sessionCommands, playerCommands)
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
publishButtonPreferences(mediaSession)
|
|
202
|
+
}
|
|
132
203
|
|
|
133
|
-
|
|
134
|
-
|
|
204
|
+
/**
|
|
205
|
+
* Publishes the layout. Media3 fans it out to the MediaStyle notification (Android 12 and below)
|
|
206
|
+
* and to the platform PlaybackState plus slot-reservation extras (Android Auto and the Android
|
|
207
|
+
* 13+ system media controls).
|
|
208
|
+
*
|
|
209
|
+
* Both calls are required. The session-wide call is the only one that reaches Android Auto, which
|
|
210
|
+
* connects as a legacy controller rather than a Media3 one. But it stops at
|
|
211
|
+
* `setPlatformMediaButtonPreferences`, which recomputes the legacy custom layout and only
|
|
212
|
+
* re-broadcasts when the reservation flags themselves change — it never refreshes the
|
|
213
|
+
* PlaybackState carrying the custom actions. Only the notification-controller overload calls
|
|
214
|
+
* `updateLegacySessionPlaybackState`, so without it a reordering that leaves the flags untouched
|
|
215
|
+
* sits invisible until some unrelated playback event republishes the state.
|
|
216
|
+
*/
|
|
217
|
+
private fun publishButtonPreferences(mediaSession: MediaSession) {
|
|
218
|
+
Timber.Forest.d(
|
|
219
|
+
"Publishing ${buttonPreferences.size} button preferences: " +
|
|
220
|
+
"${buttonPreferences.map { it.displayName }}"
|
|
221
|
+
)
|
|
222
|
+
mediaSession.setMediaButtonPreferences(buttonPreferences)
|
|
135
223
|
|
|
136
|
-
// Apply media button preferences to notification controller
|
|
137
224
|
mediaSession.mediaNotificationControllerInfo?.let { controllerInfo ->
|
|
138
|
-
mediaSession.setMediaButtonPreferences(controllerInfo,
|
|
139
|
-
mediaSession.setAvailableCommands(
|
|
140
|
-
controllerInfo,
|
|
141
|
-
notificationSessionCommands,
|
|
142
|
-
notificationPlayerCommands,
|
|
143
|
-
)
|
|
225
|
+
mediaSession.setMediaButtonPreferences(controllerInfo, buttonPreferences)
|
|
144
226
|
}
|
|
145
|
-
|
|
146
|
-
// Broadcast updated layout to all external controllers (Android Auto, etc.)
|
|
147
|
-
mediaSession.setCustomLayout(customLayout)
|
|
148
227
|
}
|
|
149
228
|
|
|
150
229
|
/**
|
|
@@ -162,29 +241,16 @@ class MediaSessionCommandManager {
|
|
|
162
241
|
|
|
163
242
|
currentFavorited = favorited
|
|
164
243
|
|
|
165
|
-
//
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
customLayout = extCustomLayout
|
|
170
|
-
Timber.Forest.d("Built external customLayout with ${customLayout.size} buttons")
|
|
171
|
-
|
|
172
|
-
// Rebuild notification button preferences with new favorite state
|
|
173
|
-
val (notifSessionCommands, notifButtonPrefs) =
|
|
174
|
-
buildNotificationButtonPreferences(
|
|
175
|
-
currentCapabilities,
|
|
176
|
-
currentNotificationButtons,
|
|
177
|
-
currentSearchAvailable,
|
|
244
|
+
// Only the heart's icon and label change, so the commands stay as they are.
|
|
245
|
+
buttonPreferences =
|
|
246
|
+
buildButtonPreferences(
|
|
247
|
+
deriveButtonSlots(currentCapabilities, currentRemoteButtonLayout),
|
|
178
248
|
favorited,
|
|
179
249
|
)
|
|
180
|
-
notificationSessionCommands = notifSessionCommands
|
|
181
|
-
notificationCustomLayout = notifButtonPrefs
|
|
182
250
|
|
|
183
|
-
//
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
mediaSession.setMediaButtonPreferences(controllerInfo, notificationCustomLayout)
|
|
187
|
-
}
|
|
251
|
+
// Republish so already-connected surfaces (Android Auto especially) flip the heart — without
|
|
252
|
+
// this it stays stale for the life of the connection.
|
|
253
|
+
publishButtonPreferences(mediaSession)
|
|
188
254
|
}
|
|
189
255
|
|
|
190
256
|
/**
|
|
@@ -195,7 +261,7 @@ class MediaSessionCommandManager {
|
|
|
195
261
|
*/
|
|
196
262
|
fun buildConnectionResult(session: MediaSession): MediaSession.ConnectionResult {
|
|
197
263
|
return MediaSession.ConnectionResult.AcceptedResultBuilder(session)
|
|
198
|
-
.
|
|
264
|
+
.setMediaButtonPreferences(buttonPreferences)
|
|
199
265
|
.setAvailableSessionCommands(sessionCommands)
|
|
200
266
|
.setAvailablePlayerCommands(playerCommands)
|
|
201
267
|
.build()
|
|
@@ -238,60 +304,31 @@ class MediaSessionCommandManager {
|
|
|
238
304
|
private fun buildPlayerCommands(capabilities: PlayerCapabilities): MediaPlayer.Commands {
|
|
239
305
|
val playerCommandsBuilder = MediaSession.ConnectionResult.DEFAULT_PLAYER_COMMANDS.buildUpon()
|
|
240
306
|
|
|
241
|
-
//
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
// This forces MediaSession to only use the "smart" commands we can control via capabilities
|
|
246
|
-
MediaPlayer.COMMAND_SEEK_TO_NEXT_MEDIA_ITEM,
|
|
247
|
-
MediaPlayer.COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM,
|
|
248
|
-
)
|
|
249
|
-
|
|
250
|
-
// Only disable jump commands if capabilities are explicitly disabled (false)
|
|
251
|
-
if (capabilities.jumpForward == false) {
|
|
252
|
-
disabledCommands.add(MediaPlayer.COMMAND_SEEK_FORWARD)
|
|
253
|
-
}
|
|
254
|
-
if (capabilities.jumpBackward == false) {
|
|
255
|
-
disabledCommands.add(MediaPlayer.COMMAND_SEEK_BACK)
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
// Check each capability and add commands to remove if explicitly disabled
|
|
259
|
-
// Both play and pause must be disabled to remove PLAY_PAUSE command
|
|
260
|
-
if (capabilities.play == false && capabilities.pause == false) {
|
|
261
|
-
disabledCommands.add(MediaPlayer.COMMAND_PLAY_PAUSE)
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
if (capabilities.stop == false) {
|
|
265
|
-
disabledCommands.add(MediaPlayer.COMMAND_STOP)
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
if (capabilities.seekTo == false) {
|
|
269
|
-
disabledCommands.add(MediaPlayer.COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM)
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
if (capabilities.skipToNext == false) {
|
|
273
|
-
disabledCommands.add(MediaPlayer.COMMAND_SEEK_TO_NEXT)
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
if (capabilities.skipToPrevious == false) {
|
|
277
|
-
disabledCommands.add(MediaPlayer.COMMAND_SEEK_TO_PREVIOUS)
|
|
278
|
-
}
|
|
307
|
+
// Always filter out direct media item commands to avoid dual-command confusion.
|
|
308
|
+
// This forces MediaSession to only use the "smart" commands we can control via capabilities.
|
|
309
|
+
playerCommandsBuilder.remove(MediaPlayer.COMMAND_SEEK_TO_NEXT_MEDIA_ITEM)
|
|
310
|
+
playerCommandsBuilder.remove(MediaPlayer.COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM)
|
|
279
311
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
312
|
+
capabilityPlayerCommands.forEach { (capability, command) ->
|
|
313
|
+
if (!capabilities.isEnabled(capability)) {
|
|
314
|
+
playerCommandsBuilder.remove(command)
|
|
315
|
+
Timber.Forest.d("Removed command: $command ($capability disabled)")
|
|
316
|
+
}
|
|
284
317
|
}
|
|
285
318
|
|
|
286
319
|
return playerCommandsBuilder.build()
|
|
287
320
|
}
|
|
288
321
|
|
|
289
|
-
|
|
322
|
+
/**
|
|
323
|
+
* Session commands for every controller. Registered for each capability-allowed custom button
|
|
324
|
+
* whether or not the layout places it — placement governs where a button appears, not whether its
|
|
325
|
+
* command exists. Media3 disables a button whose backing command is missing, so every button the
|
|
326
|
+
* layout can produce must have its command here.
|
|
327
|
+
*/
|
|
328
|
+
private fun buildSessionCommands(
|
|
290
329
|
capabilities: PlayerCapabilities,
|
|
291
330
|
searchAvailable: Boolean,
|
|
292
|
-
|
|
293
|
-
): Pair<SessionCommands, List<CommandButton>> {
|
|
294
|
-
val customLayoutButtons = mutableListOf<CommandButton>()
|
|
331
|
+
): SessionCommands {
|
|
295
332
|
val sessionCommandsBuilder =
|
|
296
333
|
MediaSession.ConnectionResult.DEFAULT_SESSION_AND_LIBRARY_COMMANDS.buildUpon()
|
|
297
334
|
|
|
@@ -302,277 +339,84 @@ class MediaSessionCommandManager {
|
|
|
302
339
|
Timber.Forest.d("Removed search commands - search not configured")
|
|
303
340
|
}
|
|
304
341
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
customLayoutButtons.add(
|
|
310
|
-
CommandButton.Builder()
|
|
311
|
-
.setDisplayName("Jump Backward")
|
|
312
|
-
.setSessionCommand(jumpBackCommand)
|
|
313
|
-
.setIconResId(R.drawable.media3_icon_skip_back)
|
|
314
|
-
.build()
|
|
315
|
-
)
|
|
316
|
-
sessionCommandsBuilder.add(jumpBackCommand)
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
if (capabilities.jumpForward != false) {
|
|
320
|
-
val jumpForwardCommand = SessionCommand(CUSTOM_ACTION_JUMP_FORWARD, Bundle())
|
|
321
|
-
customLayoutButtons.add(
|
|
322
|
-
CommandButton.Builder()
|
|
323
|
-
.setDisplayName("Jump Forward")
|
|
324
|
-
.setSessionCommand(jumpForwardCommand)
|
|
325
|
-
.setIconResId(R.drawable.media3_icon_skip_forward)
|
|
326
|
-
.build()
|
|
327
|
-
)
|
|
328
|
-
sessionCommandsBuilder.add(jumpForwardCommand)
|
|
329
|
-
}
|
|
342
|
+
RemoteButton.entries
|
|
343
|
+
.filter { capabilities.allows(it) }
|
|
344
|
+
.mapNotNull { customCommandFor(it) }
|
|
345
|
+
.forEach { sessionCommandsBuilder.add(it) }
|
|
330
346
|
|
|
331
|
-
|
|
332
|
-
if (capabilities.favorite != false) {
|
|
333
|
-
val heartIcon =
|
|
334
|
-
if (favorited == true) {
|
|
335
|
-
CommandButton.ICON_HEART_FILLED
|
|
336
|
-
} else {
|
|
337
|
-
CommandButton.ICON_HEART_UNFILLED
|
|
338
|
-
}
|
|
339
|
-
val displayName = if (favorited == true) "Remove from favorites" else "Add to favorites"
|
|
340
|
-
val favoriteCommand = SessionCommand(CUSTOM_ACTION_FAVORITE, Bundle())
|
|
341
|
-
|
|
342
|
-
customLayoutButtons.add(
|
|
343
|
-
CommandButton.Builder(heartIcon)
|
|
344
|
-
.setDisplayName(displayName)
|
|
345
|
-
.setSessionCommand(favoriteCommand)
|
|
346
|
-
.build()
|
|
347
|
-
)
|
|
348
|
-
sessionCommandsBuilder.add(favoriteCommand)
|
|
349
|
-
Timber.Forest.d("Added favorite button - favorited=$favorited")
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
return Pair(sessionCommandsBuilder.build(), customLayoutButtons)
|
|
347
|
+
return sessionCommandsBuilder.build()
|
|
353
348
|
}
|
|
354
349
|
|
|
355
350
|
/**
|
|
356
|
-
*
|
|
357
|
-
*
|
|
351
|
+
* The custom command behind a session-command-backed button, or null for the player-command ones
|
|
352
|
+
* (skip). Single source for both the command a button carries and the SessionCommands registry,
|
|
353
|
+
* so a published button can never be missing the command that makes it work — Media3 silently
|
|
354
|
+
* disables buttons whose backing command is unavailable.
|
|
358
355
|
*/
|
|
359
|
-
private fun
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
MediaSession.ConnectionResult.DEFAULT_SESSION_AND_LIBRARY_COMMANDS.buildUpon()
|
|
356
|
+
private fun customCommandFor(button: RemoteButton): SessionCommand? =
|
|
357
|
+
when (button) {
|
|
358
|
+
RemoteButton.JUMP_BACKWARD -> SessionCommand(CUSTOM_ACTION_JUMP_BACKWARD, Bundle())
|
|
359
|
+
RemoteButton.JUMP_FORWARD -> SessionCommand(CUSTOM_ACTION_JUMP_FORWARD, Bundle())
|
|
360
|
+
RemoteButton.FAVORITE -> SessionCommand(CUSTOM_ACTION_FAVORITE, Bundle())
|
|
361
|
+
RemoteButton.SKIP_TO_PREVIOUS,
|
|
362
|
+
RemoteButton.SKIP_TO_NEXT -> null
|
|
363
|
+
}
|
|
368
364
|
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
365
|
+
/**
|
|
366
|
+
* The Media3 player command behind a player-command-backed button; null for the custom ones. Both
|
|
367
|
+
* this and [customCommandFor] enumerate every button rather than using `else`, so adding one
|
|
368
|
+
* fails the build until it has been given an action on both sides.
|
|
369
|
+
*/
|
|
370
|
+
private fun playerCommandFor(button: RemoteButton): Int? =
|
|
371
|
+
when (button) {
|
|
372
|
+
RemoteButton.SKIP_TO_PREVIOUS -> MediaPlayer.COMMAND_SEEK_TO_PREVIOUS
|
|
373
|
+
RemoteButton.SKIP_TO_NEXT -> MediaPlayer.COMMAND_SEEK_TO_NEXT
|
|
374
|
+
RemoteButton.JUMP_BACKWARD,
|
|
375
|
+
RemoteButton.JUMP_FORWARD,
|
|
376
|
+
RemoteButton.FAVORITE -> null
|
|
373
377
|
}
|
|
374
378
|
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
.setDisplayName("Next")
|
|
392
|
-
.setPlayerCommand(MediaPlayer.COMMAND_SEEK_TO_NEXT)
|
|
393
|
-
.setSlots(slot)
|
|
394
|
-
.build()
|
|
395
|
-
} else null
|
|
396
|
-
}
|
|
397
|
-
NotificationButton.JUMP_BACKWARD -> {
|
|
398
|
-
if (capabilities.jumpBackward != false) {
|
|
399
|
-
val command = SessionCommand(CUSTOM_ACTION_JUMP_BACKWARD, Bundle())
|
|
400
|
-
sessionCommandsBuilder.add(command)
|
|
401
|
-
CommandButton.Builder()
|
|
402
|
-
.setDisplayName("Jump Backward")
|
|
403
|
-
.setSessionCommand(command)
|
|
404
|
-
.setIconResId(R.drawable.media3_icon_skip_back)
|
|
405
|
-
.setSlots(slot)
|
|
406
|
-
.build()
|
|
407
|
-
} else null
|
|
408
|
-
}
|
|
409
|
-
NotificationButton.JUMP_FORWARD -> {
|
|
410
|
-
if (capabilities.jumpForward != false) {
|
|
411
|
-
val command = SessionCommand(CUSTOM_ACTION_JUMP_FORWARD, Bundle())
|
|
412
|
-
sessionCommandsBuilder.add(command)
|
|
413
|
-
CommandButton.Builder()
|
|
414
|
-
.setDisplayName("Jump Forward")
|
|
415
|
-
.setSessionCommand(command)
|
|
416
|
-
.setIconResId(R.drawable.media3_icon_skip_forward)
|
|
417
|
-
.setSlots(slot)
|
|
418
|
-
.build()
|
|
419
|
-
} else null
|
|
420
|
-
}
|
|
421
|
-
NotificationButton.FAVORITE -> {
|
|
422
|
-
if (capabilities.favorite != false) {
|
|
423
|
-
val heartIcon =
|
|
379
|
+
/** The single definition of a control's icon and label, shared by every surface. */
|
|
380
|
+
private fun buttonFor(button: RemoteButton, favorited: Boolean?): CommandButton.Builder {
|
|
381
|
+
val builder =
|
|
382
|
+
when (button) {
|
|
383
|
+
RemoteButton.SKIP_TO_PREVIOUS ->
|
|
384
|
+
CommandButton.Builder(CommandButton.ICON_PREVIOUS).setDisplayName("Previous")
|
|
385
|
+
RemoteButton.SKIP_TO_NEXT ->
|
|
386
|
+
CommandButton.Builder(CommandButton.ICON_NEXT).setDisplayName("Next")
|
|
387
|
+
RemoteButton.JUMP_BACKWARD ->
|
|
388
|
+
CommandButton.Builder(jumpBackwardIcon(currentBackwardJumpInterval))
|
|
389
|
+
.setDisplayName("Jump Backward")
|
|
390
|
+
RemoteButton.JUMP_FORWARD ->
|
|
391
|
+
CommandButton.Builder(jumpForwardIcon(currentForwardJumpInterval))
|
|
392
|
+
.setDisplayName("Jump Forward")
|
|
393
|
+
RemoteButton.FAVORITE ->
|
|
394
|
+
CommandButton.Builder(
|
|
424
395
|
if (favorited == true) CommandButton.ICON_HEART_FILLED
|
|
425
396
|
else CommandButton.ICON_HEART_UNFILLED
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
sessionCommandsBuilder.add(command)
|
|
429
|
-
CommandButton.Builder(heartIcon)
|
|
430
|
-
.setDisplayName(displayName)
|
|
431
|
-
.setSessionCommand(command)
|
|
432
|
-
.setSlots(slot)
|
|
433
|
-
.build()
|
|
434
|
-
} else null
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
if (notificationButtons != null) {
|
|
440
|
-
// Use explicit slot configuration
|
|
441
|
-
notificationButtons.back?.let { btn ->
|
|
442
|
-
createButton(btn, CommandButton.SLOT_BACK)?.let { buttons.add(it) }
|
|
443
|
-
}
|
|
444
|
-
notificationButtons.forward?.let { btn ->
|
|
445
|
-
createButton(btn, CommandButton.SLOT_FORWARD)?.let { buttons.add(it) }
|
|
446
|
-
}
|
|
447
|
-
notificationButtons.backSecondary?.let { btn ->
|
|
448
|
-
createButton(btn, CommandButton.SLOT_BACK_SECONDARY)?.let { buttons.add(it) }
|
|
449
|
-
}
|
|
450
|
-
notificationButtons.forwardSecondary?.let { btn ->
|
|
451
|
-
createButton(btn, CommandButton.SLOT_FORWARD_SECONDARY)?.let { buttons.add(it) }
|
|
452
|
-
}
|
|
453
|
-
notificationButtons.overflow?.forEach { btn ->
|
|
454
|
-
createButton(btn, CommandButton.SLOT_OVERFLOW)?.let { buttons.add(it) }
|
|
455
|
-
}
|
|
456
|
-
} else {
|
|
457
|
-
// Derive from capabilities with default slot mapping
|
|
458
|
-
// All capabilities enabled by default - only false disables
|
|
459
|
-
val hasSkipPrevious = capabilities.skipToPrevious != false
|
|
460
|
-
val hasSkipNext = capabilities.skipToNext != false
|
|
461
|
-
|
|
462
|
-
// Back slot: skip-to-previous, or jump-backward if no skip
|
|
463
|
-
if (hasSkipPrevious) {
|
|
464
|
-
createButton(NotificationButton.SKIP_TO_PREVIOUS, CommandButton.SLOT_BACK)?.let {
|
|
465
|
-
buttons.add(it)
|
|
466
|
-
}
|
|
467
|
-
} else if (capabilities.jumpBackward != false) {
|
|
468
|
-
createButton(NotificationButton.JUMP_BACKWARD, CommandButton.SLOT_BACK)?.let {
|
|
469
|
-
buttons.add(it)
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
// Forward slot: skip-to-next, or jump-forward if no skip
|
|
474
|
-
if (hasSkipNext) {
|
|
475
|
-
createButton(NotificationButton.SKIP_TO_NEXT, CommandButton.SLOT_FORWARD)?.let {
|
|
476
|
-
buttons.add(it)
|
|
477
|
-
}
|
|
478
|
-
} else if (capabilities.jumpForward != false) {
|
|
479
|
-
createButton(NotificationButton.JUMP_FORWARD, CommandButton.SLOT_FORWARD)?.let {
|
|
480
|
-
buttons.add(it)
|
|
481
|
-
}
|
|
397
|
+
)
|
|
398
|
+
.setDisplayName(if (favorited == true) "Remove from favorites" else "Add to favorites")
|
|
482
399
|
}
|
|
483
400
|
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
buttons.add(it)
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
if (hasSkipNext && capabilities.jumpForward != false) {
|
|
491
|
-
createButton(NotificationButton.JUMP_FORWARD, CommandButton.SLOT_FORWARD_SECONDARY)?.let {
|
|
492
|
-
buttons.add(it)
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
// Overflow: favorite
|
|
497
|
-
if (capabilities.favorite != false) {
|
|
498
|
-
createButton(NotificationButton.FAVORITE, CommandButton.SLOT_OVERFLOW)?.let {
|
|
499
|
-
buttons.add(it)
|
|
500
|
-
}
|
|
501
|
-
}
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
Timber.Forest.d("Built notification button preferences: ${buttons.map { it.displayName }}")
|
|
505
|
-
return Pair(sessionCommandsBuilder.build(), buttons)
|
|
401
|
+
return customCommandFor(button)?.let { builder.setSessionCommand(it) }
|
|
402
|
+
?: playerCommandFor(button)?.let { builder.setPlayerCommand(it) }
|
|
403
|
+
?: builder
|
|
506
404
|
}
|
|
507
405
|
|
|
508
406
|
/**
|
|
509
|
-
*
|
|
510
|
-
*
|
|
407
|
+
* Assembles the CommandButtons for an already-derived slot layout (see [deriveButtonSlots] — the
|
|
408
|
+
* slots are pre-filtered by Capability).
|
|
409
|
+
*
|
|
410
|
+
* Each button gets its requested slot followed by OVERFLOW as a fallback. `slots` is an ordered
|
|
411
|
+
* preference list, and every surface caps how many buttons it renders — a head unit, the
|
|
412
|
+
* collapsed notification, the Android 13+ media controls all truncate differently. Without a
|
|
413
|
+
* fallback a button that loses its preferred slot disappears entirely instead of demoting.
|
|
511
414
|
*/
|
|
512
|
-
private fun
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
):
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
// Always remove direct media item commands to avoid dual-command confusion
|
|
519
|
-
builder.remove(MediaPlayer.COMMAND_SEEK_TO_NEXT_MEDIA_ITEM)
|
|
520
|
-
builder.remove(MediaPlayer.COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM)
|
|
521
|
-
|
|
522
|
-
// Determine which buttons will be shown
|
|
523
|
-
val showSkipPrevious: Boolean
|
|
524
|
-
val showSkipNext: Boolean
|
|
525
|
-
val showJumpBackward: Boolean
|
|
526
|
-
val showJumpForward: Boolean
|
|
527
|
-
|
|
528
|
-
if (notificationButtons != null) {
|
|
529
|
-
showSkipPrevious =
|
|
530
|
-
notificationButtons.back == NotificationButton.SKIP_TO_PREVIOUS ||
|
|
531
|
-
notificationButtons.backSecondary == NotificationButton.SKIP_TO_PREVIOUS
|
|
532
|
-
showSkipNext =
|
|
533
|
-
notificationButtons.forward == NotificationButton.SKIP_TO_NEXT ||
|
|
534
|
-
notificationButtons.forwardSecondary == NotificationButton.SKIP_TO_NEXT
|
|
535
|
-
showJumpBackward =
|
|
536
|
-
notificationButtons.back == NotificationButton.JUMP_BACKWARD ||
|
|
537
|
-
notificationButtons.backSecondary == NotificationButton.JUMP_BACKWARD
|
|
538
|
-
showJumpForward =
|
|
539
|
-
notificationButtons.forward == NotificationButton.JUMP_FORWARD ||
|
|
540
|
-
notificationButtons.forwardSecondary == NotificationButton.JUMP_FORWARD
|
|
541
|
-
} else {
|
|
542
|
-
// Default derivation from capabilities
|
|
543
|
-
// All capabilities enabled by default - only false disables
|
|
544
|
-
showSkipPrevious = capabilities.skipToPrevious != false
|
|
545
|
-
showSkipNext = capabilities.skipToNext != false
|
|
546
|
-
showJumpBackward = capabilities.jumpBackward != false
|
|
547
|
-
showJumpForward = capabilities.jumpForward != false
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
// Enable/disable commands based on what buttons are shown and capabilities
|
|
551
|
-
if (!showSkipPrevious || capabilities.skipToPrevious == false) {
|
|
552
|
-
builder.remove(MediaPlayer.COMMAND_SEEK_TO_PREVIOUS)
|
|
553
|
-
}
|
|
554
|
-
if (!showSkipNext || capabilities.skipToNext == false) {
|
|
555
|
-
builder.remove(MediaPlayer.COMMAND_SEEK_TO_NEXT)
|
|
556
|
-
}
|
|
557
|
-
if (!showJumpBackward || capabilities.jumpBackward == false) {
|
|
558
|
-
builder.remove(MediaPlayer.COMMAND_SEEK_BACK)
|
|
559
|
-
}
|
|
560
|
-
if (!showJumpForward || capabilities.jumpForward == false) {
|
|
561
|
-
builder.remove(MediaPlayer.COMMAND_SEEK_FORWARD)
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
// Other commands based on global capabilities
|
|
565
|
-
// Both play and pause must be disabled to remove PLAY_PAUSE
|
|
566
|
-
if (capabilities.play == false && capabilities.pause == false) {
|
|
567
|
-
builder.remove(MediaPlayer.COMMAND_PLAY_PAUSE)
|
|
568
|
-
}
|
|
569
|
-
if (capabilities.stop == false) {
|
|
570
|
-
builder.remove(MediaPlayer.COMMAND_STOP)
|
|
571
|
-
}
|
|
572
|
-
if (capabilities.seekTo == false) {
|
|
573
|
-
builder.remove(MediaPlayer.COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM)
|
|
415
|
+
private fun buildButtonPreferences(
|
|
416
|
+
slots: List<SlottedButton>,
|
|
417
|
+
favorited: Boolean?,
|
|
418
|
+
): List<CommandButton> =
|
|
419
|
+
slots.map { (button, slot) ->
|
|
420
|
+
buttonFor(button, favorited).setSlots(*media3SlotsFor(slot)).build()
|
|
574
421
|
}
|
|
575
|
-
|
|
576
|
-
return builder.build()
|
|
577
|
-
}
|
|
578
422
|
}
|