package com.radiola.ui.theme import androidx.compose.animation.core.Animatable import androidx.compose.animation.core.FastOutSlowInEasing import androidx.compose.animation.core.LinearEasing import androidx.compose.animation.core.RepeatMode import androidx.compose.animation.core.Spring import androidx.compose.animation.core.animateFloat import androidx.compose.animation.core.infiniteRepeatable import androidx.compose.animation.core.rememberInfiniteTransition import androidx.compose.animation.core.spring import androidx.compose.animation.core.tween import androidx.compose.foundation.Canvas import androidx.compose.foundation.gestures.detectTapGestures import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.interaction.collectIsPressedAsState import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.CornerRadius import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Size import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.unit.dp import kotlin.math.abs /** Стандартные длительности и кривые движения приложения. */ object Motion { const val Fast = 120 const val Medium = 220 const val Slow = 360 fun snappy() = spring( dampingRatio = Spring.DampingRatioMediumBouncy, stiffness = Spring.StiffnessMediumLow ) fun gentle() = tween(durationMillis = Medium, easing = FastOutSlowInEasing) } /** Лёгкое нажатие: плавное уменьшение масштаба, пока палец на элементе. */ @Composable fun Modifier.pressScale( pressedScale: Float = 0.94f, interactionSource: MutableInteractionSource = remember { MutableInteractionSource() } ): Modifier { val pressed by interactionSource.collectIsPressedAsState() val scale by androidx.compose.animation.core.animateFloatAsState( targetValue = if (pressed) pressedScale else 1f, animationSpec = tween(Motion.Fast, easing = FastOutSlowInEasing), label = "pressScale" ) return this.graphicsLayer { scaleX = scale scaleY = scale } } /** * Живой эквалайзер для прямого эфира — декоративный, без перемотки. * Полоски плавно «дышат» при воспроизведении. */ @Composable fun LiveEqualizer( modifier: Modifier = Modifier, barCount: Int = 36, color: Color = Accent, playing: Boolean = true ) { val transition = rememberInfiniteTransition(label = "eq") val phase by transition.animateFloat( initialValue = 0f, targetValue = (Math.PI * 2).toFloat(), animationSpec = infiniteRepeatable( animation = tween(1400, easing = LinearEasing), repeatMode = RepeatMode.Restart ), label = "eqPhase" ) Canvas(modifier = modifier) { val gap = 3.dp.toPx() val barWidth = (size.width - gap * (barCount - 1)) / barCount val maxH = size.height for (i in 0 until barCount) { val seed = (i * 0.7f) val wave = if (playing) { 0.45f + 0.55f * abs(kotlin.math.sin(phase + seed)) } else 0.25f val h = maxH * wave val x = i * (barWidth + gap) val y = (maxH - h) / 2f drawRoundRect( color = color, topLeft = Offset(x, y), size = Size(barWidth, h), cornerRadius = CornerRadius(barWidth / 2f, barWidth / 2f) ) } } }