Expandable player: static poster during collapse/morph, live player only when expanded — vc=77
The remaining sluggishness was scaling a live-playing TextureView through the morph's graphicsLayer every frame. Now the minibar + the whole collapse/expand morph render the video's static poster (AsyncImage); the live PlayerView only mounts once settled fully expanded. Audio is unaffected — it's owned by the foreground service, never stops.
This commit is contained in:
parent
f6006047ff
commit
4b73616083
2 changed files with 45 additions and 28 deletions
|
|
@ -9,6 +9,13 @@ const val STRAW_SDK_TARGET = 35
|
|||
|
||||
// Sulkta fork — Straw
|
||||
//
|
||||
// vc=77 / 0.1.0-CK — morph perf: static poster during collapse/morph:
|
||||
// * The minibar + the whole collapse/expand morph now render the video's
|
||||
// static poster, not the live TextureView. Scaling a live-playing
|
||||
// TextureView through the morph's graphicsLayer every frame was the
|
||||
// remaining sluggishness; the live PlayerView only mounts once settled
|
||||
// fully expanded. Audio is unaffected (it's in the foreground service).
|
||||
//
|
||||
// vc=76 / 0.1.0-CJ — expandable-player smoothness pass:
|
||||
// * The detail body no longer renders to an offscreen buffer every
|
||||
// frame during the morph (CompositingStrategy.ModulateAlpha) — that
|
||||
|
|
@ -82,6 +89,6 @@ const val STRAW_SDK_TARGET = 35
|
|||
// 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 = 76
|
||||
const val STRAW_VERSION_NAME = "0.1.0-CJ"
|
||||
const val STRAW_VERSION_CODE = 77
|
||||
const val STRAW_VERSION_NAME = "0.1.0-CK"
|
||||
const val STRAW_APPLICATION_ID = "com.sulkta.straw"
|
||||
|
|
|
|||
|
|
@ -385,7 +385,7 @@ fun ExpandablePlayer(
|
|||
InlinePlayerSurface(
|
||||
streamUrl = cur.streamUrl,
|
||||
title = cur.title,
|
||||
controlsEnabled = fullyExpanded,
|
||||
expanded = fullyExpanded,
|
||||
onFullscreen = { onFullscreen(cur.streamUrl, cur.title) },
|
||||
)
|
||||
}
|
||||
|
|
@ -413,17 +413,18 @@ private fun BarIconButton(
|
|||
* The single TextureView-backed PlayerView, plus the resolve→play wiring
|
||||
* that used to live in VideoDetailScreen's InlinePlayer. Renders a
|
||||
* thumbnail + spinner until the shared controller has actually swapped to
|
||||
* this video, then the live surface. [controlsEnabled] gates the Media3
|
||||
* controller overlay (off while collapsed so taps fall through to the
|
||||
* expand gesture). Honors the Auto-start-playback setting: when off, a
|
||||
* Play overlay waits for a tap before priming the stream.
|
||||
* this video. [expanded] = fully expanded + settled: only then do we mount
|
||||
* the live PlayerView (+ controls). While collapsed or mid-morph we show a
|
||||
* static poster instead, so the morph never scales a live TextureView frame
|
||||
* by frame (the sluggishness). Honors Auto-start-playback: when off, a Play
|
||||
* overlay waits for a tap before priming the stream.
|
||||
*/
|
||||
@OptIn(UnstableApi::class)
|
||||
@Composable
|
||||
private fun InlinePlayerSurface(
|
||||
streamUrl: String,
|
||||
title: String,
|
||||
controlsEnabled: Boolean,
|
||||
expanded: Boolean,
|
||||
onFullscreen: () -> Unit,
|
||||
) {
|
||||
val controller = LocalStrawController.current
|
||||
|
|
@ -533,40 +534,49 @@ private fun InlinePlayerSurface(
|
|||
}
|
||||
CircularProgressIndicator(color = Color.White)
|
||||
}
|
||||
!expanded -> {
|
||||
// Collapsed or mid-morph: show the static poster, NOT the live
|
||||
// TextureView. Scaling a live-playing TextureView through the
|
||||
// morph's graphicsLayer every frame was the remaining cost —
|
||||
// only mount the real player once we've settled fully expanded.
|
||||
// Audio keeps playing via the service the whole time.
|
||||
val poster = nowPlaying?.thumbnail ?: thumbnail
|
||||
if (!poster.isNullOrBlank()) {
|
||||
AsyncImage(
|
||||
model = poster,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
AndroidView(
|
||||
factory = { ctx ->
|
||||
// Inflate from XML for a TEXTURE_VIEW surface — a
|
||||
// SurfaceView won't follow the graphicsLayer scale,
|
||||
// which is exactly the morph here.
|
||||
// SurfaceView won't follow the graphicsLayer scale.
|
||||
(LayoutInflater.from(ctx)
|
||||
.inflate(R.layout.inline_player_view, null) as PlayerView)
|
||||
.apply {
|
||||
player = controller
|
||||
useController = controlsEnabled
|
||||
useController = true
|
||||
keepScreenOn = true
|
||||
}
|
||||
},
|
||||
update = {
|
||||
it.player = controller
|
||||
it.useController = controlsEnabled
|
||||
},
|
||||
update = { it.player = controller },
|
||||
onRelease = { it.player = null },
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
if (controlsEnabled) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.align(Alignment.TopEnd)
|
||||
.padding(8.dp)
|
||||
.size(36.dp)
|
||||
.clip(RoundedCornerShape(6.dp))
|
||||
.background(OverlayChromeColor)
|
||||
.clickable(onClick = onFullscreen),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Text("⛶", color = Color.White)
|
||||
}
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.align(Alignment.TopEnd)
|
||||
.padding(8.dp)
|
||||
.size(36.dp)
|
||||
.clip(RoundedCornerShape(6.dp))
|
||||
.background(OverlayChromeColor)
|
||||
.clickable(onClick = onFullscreen),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Text("⛶", color = Color.White)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue