diff --git a/buildSrc/src/main/kotlin/ProjectConfig.kt b/buildSrc/src/main/kotlin/ProjectConfig.kt index 225a8c548..e4f73c6c8 100644 --- a/buildSrc/src/main/kotlin/ProjectConfig.kt +++ b/buildSrc/src/main/kotlin/ProjectConfig.kt @@ -55,6 +55,6 @@ const val NEWPIPE_APPLICATION_ID_NEW = "net.newpipe.app" // vc=19 / 0.1.0-AE — rust pipeline cutover. Extraction via // strawcore-core (Sulkta-Coop/strawcore) via the UniFFI wrapper; no // NewPipeExtractor in the runtime path. -const val STRAW_VERSION_CODE = 56 -const val STRAW_VERSION_NAME = "0.1.0-BP" +const val STRAW_VERSION_CODE = 57 +const val STRAW_VERSION_NAME = "0.1.0-BQ" const val STRAW_APPLICATION_ID = "com.sulkta.straw" diff --git a/strawApp/src/main/kotlin/com/sulkta/straw/feature/detail/VideoDetailScreen.kt b/strawApp/src/main/kotlin/com/sulkta/straw/feature/detail/VideoDetailScreen.kt index e10c841f9..447c7f79e 100644 --- a/strawApp/src/main/kotlin/com/sulkta/straw/feature/detail/VideoDetailScreen.kt +++ b/strawApp/src/main/kotlin/com/sulkta/straw/feature/detail/VideoDetailScreen.kt @@ -776,6 +776,14 @@ private fun InlinePlayer( onDispose { c?.removeListener(listener) } } + // Track whether the shared controller has actually swapped over to + // THIS video's stream. Until it does (the brief window between + // streamInfo resolving and setPlayingFrom + setMediaItem landing), + // binding PlayerView to the controller would render the PREVIOUS + // video's frame under the new detail page — exactly the "new page, + // old video" bug. + val nowPlaying by NowPlaying.current.collectAsStateWithLifecycle() + val controllerOnThisVideo = nowPlaying?.streamUrl == streamUrl Box(modifier = modifier, contentAlignment = Alignment.Center) { when { controller == null || state.loading -> CircularProgressIndicator(color = Color.White) @@ -794,6 +802,22 @@ private fun InlinePlayer( color = Color.White, modifier = Modifier.padding(16.dp), ) + // Stream resolved for THIS URL but the controller hasn't + // actually swapped media items yet — show the thumbnail + // with a spinner. Without this, the PlayerView below would + // bind to the controller and render the OUTGOING video's + // last frame while the new detail page chrome shows the + // new title/description. Bug reported 2026-05-26. + !controllerOnThisVideo -> { + if (!thumbnail.isNullOrBlank()) { + AsyncImage( + model = thumbnail, + contentDescription = null, + modifier = Modifier.fillMaxSize(), + ) + } + CircularProgressIndicator(color = Color.White) + } else -> { AndroidView( factory = { ctx ->