diff --git a/app/src/main/java/com/rada/ui/player/PlayerScreen.kt b/app/src/main/java/com/rada/ui/player/PlayerScreen.kt index ea0ff8f..9db2807 100644 --- a/app/src/main/java/com/rada/ui/player/PlayerScreen.kt +++ b/app/src/main/java/com/rada/ui/player/PlayerScreen.kt @@ -84,6 +84,7 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf +import androidx.compose.ui.layout.onSizeChanged import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue @@ -440,41 +441,49 @@ private fun WaveGraphic(modifier: Modifier = Modifier) { val gradientColors = listOf(LocalTokens.current.accentFill, GradientMid, GradientEnd) val accentGlow = LocalTokens.current.accentFill - Canvas(modifier = modifier) { + // Build each wave path + its gradient ONCE per size/palette, not per draw + // pass: this canvas sits on the hub, and rebuilding ~1k lineTo segments + // per layer was the heavy frame behind the hub-transition jank (99th-p + // ~200ms). 4px steps are indistinguishable at this frequency and cut + // segment count by 4x. + var canvasSize by remember { mutableStateOf(androidx.compose.ui.unit.IntSize.Zero) } + val layers = remember(canvasSize, gradientColors) { + val w = canvasSize.width.toFloat() + val h = canvasSize.height.toFloat() + if (w <= 0f || h <= 0f) emptyList() + else (0..2).map { layer -> + val amplitude = (30f - layer * 8f) * (w / 400f) + val frequency = 0.008f + layer * 0.002f + val phaseShift = layer * 0.5f + val path = Path().apply { + moveTo(0f, h / 2 + amplitude * kotlin.math.sin(phaseShift.toDouble()).toFloat()) + var x = 0f + while (x <= w) { + val y = h / 2 + amplitude * kotlin.math.sin( + (x * frequency * Math.PI * 2).toDouble() + phaseShift + ).toFloat() + lineTo(x, y) + x += 4f + } + } + val strokeBrush = Brush.horizontalGradient( + colors = gradientColors.map { it.copy(alpha = 0.6f - layer * 0.15f) }, + startX = 0f, + endX = w, + ) + Triple(path, strokeBrush, (3f - layer * 0.5f) * (w / 400f)) + } + } + + Canvas( + modifier = modifier.onSizeChanged { canvasSize = it }, + ) { val width = size.width val height = size.height val centerY = height / 2 - // Draw multiple wave layers - for (layer in 0..2) { - val path = Path() - val amplitude = (30f - layer * 8f) * (width / 400f) - val frequency = 0.008f + layer * 0.002f - val phaseShift = layer * 0.5f - - path.moveTo(0f, centerY) - - for (x in 0..width.toInt()) { - val xFloat = x.toFloat() - val y = centerY + amplitude * kotlin.math.sin( - (xFloat * frequency * Math.PI * 2).toDouble() + phaseShift - ).toFloat() - if (x == 0) { - path.moveTo(xFloat, y) - } else { - path.lineTo(xFloat, y) - } - } - - drawPath( - path = path, - brush = Brush.horizontalGradient( - colors = gradientColors.map { it.copy(alpha = 0.6f - layer * 0.15f) }, - startX = 0f, - endX = width, - ), - style = Stroke(width = (3f - layer * 0.5f) * (width / 400f)), - ) + for ((path, strokeBrush, strokeWidth) in layers) { + drawPath(path = path, brush = strokeBrush, style = Stroke(width = strokeWidth)) } // Ambient glow behind the waves — wide, faint, no visible disc edge.