package com.radiola.ui.components import androidx.compose.animation.core.Animatable import androidx.compose.animation.core.FastOutSlowInEasing import androidx.compose.animation.core.tween import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.layout.ContentScale import coil.compose.AsyncImage /** * Обложка с эффектом 3D-переворота при смене изображения — как будто * перелистывается страница альбома / пластинка. Старая обложка «улетает» * передней стороной (0–90°), новая «прилетает» задней (90–180°). */ @Composable fun FlipCover( model: String?, contentDescription: String?, modifier: Modifier = Modifier, fallback: @Composable () -> Unit, ) { var current by remember { mutableStateOf(model) } var previous by remember { mutableStateOf(model) } val rotation = remember { Animatable(0f) } LaunchedEffect(model) { if (model != current) { previous = current current = model rotation.snapTo(0f) rotation.animateTo(180f, animationSpec = tween(620, easing = FastOutSlowInEasing)) // Оседаем: новая обложка становится «лицом», угол 0 — без рывка. previous = current rotation.snapTo(0f) } } val angle = rotation.value val showFront = angle <= 90f val faceModel = if (showFront) previous else current Box( modifier = modifier.graphicsLayer { rotationY = angle cameraDistance = 16f * density }, contentAlignment = Alignment.Center, ) { // Заднюю грань контр-вращаем, чтобы изображение не было зеркальным. Box( modifier = Modifier .fillMaxSize() .graphicsLayer { rotationY = if (showFront) 0f else 180f }, contentAlignment = Alignment.Center, ) { if (!faceModel.isNullOrBlank()) { AsyncImage( model = faceModel, contentDescription = contentDescription, modifier = Modifier.fillMaxSize(), contentScale = ContentScale.Crop, ) } else { fallback() } } } }