Expandable player: kill sluggish morph (cheaper compositing + snappy spring) — vc=76
All checks were successful
build-apk / build-and-publish (push) Successful in 7m8s
gitleaks / scan (push) Successful in 42s

- The detail body's alpha fade was rendering the whole scroll subtree to
  an offscreen buffer every frame (CompositingStrategy.Auto goes offscreen
  when alpha<1). Switch to ModulateAlpha — the body's rows don't overlap,
  so the per-draw-op fade is correct and skips the buffer. Main fix.
- Replace the 300ms FastOutSlowIn tween (slow ramp at both ends) with a
  no-bounce StiffnessMedium spring — distance-adaptive, reads as snappy.
This commit is contained in:
Cobb 2026-06-20 13:41:46 -07:00
parent e357861fb1
commit f6006047ff
2 changed files with 27 additions and 6 deletions

View file

@ -9,6 +9,14 @@ const val STRAW_SDK_TARGET = 35
// Sulkta fork — Straw
//
// 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
// offscreen alpha pass on the whole scroll subtree was the main
// cause of the sluggish feel.
// * Morph animation is now a snappy no-bounce spring instead of a
// 300ms FastOutSlowIn tween (which ramped slowly at both ends).
//
// vc=75 / 0.1.0-CI — expandable player (full rearchitect):
// * The video page and the bottom minibar are now ONE container that
// morphs continuously between them, both directions. Replaces the
@ -74,6 +82,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 = 75
const val STRAW_VERSION_NAME = "0.1.0-CI"
const val STRAW_VERSION_CODE = 76
const val STRAW_VERSION_NAME = "0.1.0-CJ"
const val STRAW_APPLICATION_ID = "com.sulkta.straw"

View file

@ -34,8 +34,8 @@ import android.view.LayoutInflater
import android.widget.Toast
import androidx.annotation.OptIn
import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.FastOutSlowInEasing
import androidx.compose.animation.core.tween
import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.spring
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.gestures.Orientation
@ -82,6 +82,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.CompositingStrategy
import androidx.compose.ui.graphics.TransformOrigin
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.platform.LocalContext
@ -106,8 +107,14 @@ import com.sulkta.straw.feature.detail.VideoDetailViewModel
import com.sulkta.straw.util.LogDump
import kotlinx.coroutines.launch
private val ExpandSpec = tween<Float>(durationMillis = 300, easing = FastOutSlowInEasing)
private val CollapseSpec = tween<Float>(durationMillis = 260, easing = FastOutSlowInEasing)
// Snappy, no overshoot. A spring adapts its speed to the remaining
// distance, which reads as more responsive than a fixed-duration tween
// (the 300ms FastOutSlowIn tween felt sluggish — slow ramp at both ends).
private val ExpandSpec = spring<Float>(
dampingRatio = Spring.DampingRatioNoBouncy,
stiffness = Spring.StiffnessMedium,
)
private val CollapseSpec = ExpandSpec
/**
* Hosted in StrawActivity's root Box, above the browse screen. Visible
@ -269,6 +276,12 @@ fun ExpandablePlayer(
val playerBottomNow = lerp(collapsedTopPx, statusTopPx, fr) + expandedHpx * s
translationY = playerBottomNow - playerBottomExpandedPx
alpha = fr
// ModulateAlpha applies the fade per draw-op instead of
// rendering the whole (heavy) body to an offscreen buffer
// every frame — the body's rows don't overlap, so the
// blend is correct and it's far cheaper. This was the main
// source of the sluggish morph.
compositingStrategy = CompositingStrategy.ModulateAlpha
}
.background(MaterialTheme.colorScheme.background),
) {