From 905c8eb8a7892a6c6d3c76d0e4a2741d24769c5b Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 18 Apr 2026 03:06:19 +0000 Subject: [PATCH] fix(video): show blurhash instead of fake waveform while loading VideoView already renders the blurhash underneath VideoViewInner, but the player still showed FakeWaveformAnimation over it during loading. Two issues combined: Tracks.isAudio() returned true for an empty track list (the state before the player has resolved any tracks), and AudioPlayingAnimation had no way to know the media was a video. If a blurhash is available we know this is a video, so propagate that hint down and skip the audio waveform entirely. Also guard isAudio() so an empty track list is no longer treated as audio. --- .../service/playback/composable/RenderVideoPlayer.kt | 2 ++ .../amethyst/service/playback/composable/VideoView.kt | 2 ++ .../amethyst/service/playback/composable/VideoViewInner.kt | 2 ++ .../playback/composable/wavefront/AudioPlayingAnimation.kt | 5 ++++- .../amethyst/ui/components/ZoomableContentDialog.kt | 2 ++ 5 files changed, 12 insertions(+), 1 deletion(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/RenderVideoPlayer.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/RenderVideoPlayer.kt index b51e5727ea..723899fd8e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/RenderVideoPlayer.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/RenderVideoPlayer.kt @@ -87,6 +87,7 @@ fun RenderVideoPlayer( videoModifier: Modifier, onDialog: (() -> Unit)? = null, controllerVisible: MutableState = remember { mutableStateOf(false) }, + hasBlurhash: Boolean = false, accountViewModel: AccountViewModel, ) { val containerSize = remember { mutableStateOf(IntSize.Zero) } @@ -123,6 +124,7 @@ fun RenderVideoPlayer( controllerState, mediaItem.src.waveformData, Modifier.fillMaxSize().align(Alignment.Center), + hasBlurhash = hasBlurhash, ) if (showControls) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/VideoView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/VideoView.kt index 20ddfc2337..efb7cef5e3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/VideoView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/VideoView.kt @@ -137,6 +137,7 @@ fun VideoView( nostrUriCallback = nostrUriCallback, automaticallyStartPlayback = automaticallyStartPlayback.value, onZoom = onDialog, + hasBlurhash = false, accountViewModel = accountViewModel, showControls = showControls, ) @@ -183,6 +184,7 @@ fun VideoView( nostrUriCallback = nostrUriCallback, automaticallyStartPlayback = automaticallyStartPlayback.value, onZoom = onDialog, + hasBlurhash = true, accountViewModel = accountViewModel, showControls = showControls, ) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/VideoViewInner.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/VideoViewInner.kt index f9e2ddb595..99f0a55562 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/VideoViewInner.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/VideoViewInner.kt @@ -49,6 +49,7 @@ fun VideoViewInner( automaticallyStartPlayback: Boolean, controllerVisible: MutableState = mutableStateOf(false), onZoom: (() -> Unit)? = null, + hasBlurhash: Boolean = false, accountViewModel: AccountViewModel, ) { // keeps a copy of the value to avoid recompositions here when the DEFAULT value changes @@ -82,6 +83,7 @@ fun VideoViewInner( videoModifier = videoModifier, controllerVisible = controllerVisible, onDialog = onZoom, + hasBlurhash = hasBlurhash, accountViewModel = accountViewModel, ) } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/wavefront/AudioPlayingAnimation.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/wavefront/AudioPlayingAnimation.kt index 0336e55194..28afe97b33 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/wavefront/AudioPlayingAnimation.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/playback/composable/wavefront/AudioPlayingAnimation.kt @@ -33,14 +33,17 @@ import androidx.media3.common.Tracks import com.vitorpamplona.amethyst.service.playback.composable.MediaControllerState import com.vitorpamplona.amethyst.service.playback.composable.WaveformData -fun Tracks.isAudio() = groups.none { it.type == C.TRACK_TYPE_VIDEO } +fun Tracks.isAudio() = groups.isNotEmpty() && groups.none { it.type == C.TRACK_TYPE_VIDEO } @Composable fun AudioPlayingAnimation( controllerState: MediaControllerState, waveform: WaveformData?, modifier: Modifier = Modifier, + hasBlurhash: Boolean = false, ) { + if (hasBlurhash) return + var isAudio by remember { mutableStateOf(controllerState.controller.currentTracks.isAudio()) } DisposableEffect(controllerState.controller) { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentDialog.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentDialog.kt index 1f3cd7faf9..c6331c9f0c 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentDialog.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableContentDialog.kt @@ -568,6 +568,7 @@ private fun RenderImageOrVideo( nostrUriCallback = content.uri, automaticallyStartPlayback = true, controllerVisible = controllerVisible, + hasBlurhash = content.blurhash != null, accountViewModel = accountViewModel, ) } @@ -626,6 +627,7 @@ private fun RenderImageOrVideo( nostrUriCallback = content.uri, automaticallyStartPlayback = true, controllerVisible = controllerVisible, + hasBlurhash = content.blurhash != null, accountViewModel = accountViewModel, ) }