package com.suno.android.common_ui.components.banner import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Icon import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.rotate import androidx.compose.ui.draw.shadow import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.painter.ColorPainter import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.vectorResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import coil3.compose.AsyncImage import com.suno.android.common_core_utils.model.Url import com.suno.android.common_ui.components.aura.auraBackground import com.suno.android.common_ui.components.loading.SunoSpinner import com.suno.android.common_ui.theme.ExtendedTheme import com.suno.android.common_ui.theme.SunoTheme import com.suno.android.common_res.R as CommonResR import com.suno.android.common_ui.R as CommonUIR private const val PREVIEW_ROTATION = 8f @Composable fun SongGenerationBanner( modifier: Modifier = Modifier, songGenerationReady: Boolean = false, generationPreviewUrls: List = emptyList(), onClick: () -> Unit, onPlayButtonClick: () -> Unit, onDismiss: (exitDirection: ExitDirection) -> Unit, ) { AuraBanner( modifier = modifier, onClick = onClick, onDismiss = onDismiss, ) { if (songGenerationReady) { // Ready state: preview images + text on left, play button on right Row( verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(4.dp), modifier = Modifier.align(Alignment.CenterStart), ) { if (generationPreviewUrls.isNotEmpty()) { PreviewImages(previewUrls = generationPreviewUrls) } Text( text = stringResource(CommonResR.string.songs_ready_tap_to_play), style = ExtendedTheme.typography.smallBody, color = Color.White, ) } BannerPlayButton( onClick = onPlayButtonClick, modifier = Modifier.align(Alignment.CenterEnd), ) } else { // Loading state: text on left, spinner on right Text( modifier = Modifier.align(Alignment.CenterStart), text = stringResource(CommonResR.string.generation_message_1), style = ExtendedTheme.typography.smallBody, color = Color.White, ) SunoSpinner( modifier = Modifier .size(32.dp) .align(Alignment.CenterEnd), ) } } } @Composable private fun PreviewImages( previewUrls: List, ) { Box( modifier = Modifier .height(48.dp) .width(60.dp) .padding(horizontal = 12.dp), contentAlignment = Alignment.CenterStart, ) { // Back image (rotated left) previewUrls.getOrNull(previewUrls.size - 2)?.let { url -> Box(modifier = Modifier.offset(x = (-5).dp)) { Box( modifier = Modifier .height(37.dp) .width(28.dp) .rotate(-PREVIEW_ROTATION) .shadow(elevation = 12.dp) .clip(shape = RoundedCornerShape(6.dp)), ) { AsyncImage( modifier = Modifier.fillMaxHeight(), model = url, placeholder = ColorPainter(Color.LightGray), contentDescription = null, contentScale = ContentScale.Crop, ) } } } // Front image (rotated right) previewUrls.lastOrNull()?.let { url -> Box(modifier = Modifier.offset(x = 5.dp)) { Box( modifier = Modifier .height(37.dp) .width(28.dp) .rotate(PREVIEW_ROTATION) .shadow(elevation = 12.dp) .clip(shape = RoundedCornerShape(6.dp)), ) { AsyncImage( modifier = Modifier.fillMaxHeight(), model = url, placeholder = ColorPainter(Color.LightGray), contentDescription = null, contentScale = ContentScale.Crop, ) } } } } } @Composable private fun BannerPlayButton( onClick: () -> Unit, modifier: Modifier = Modifier, ) { Box( modifier = modifier .size(48.dp) .clip(CircleShape) .auraBackground() .clickable(onClick = onClick), contentAlignment = Alignment.Center, ) { Icon( modifier = Modifier.size(24.dp), imageVector = ImageVector.vectorResource(CommonUIR.drawable.play), tint = Color.White, contentDescription = stringResource(CommonResR.string.play), ) } } @Preview @Composable private fun SongGenerationBanner_Generating_Preview() { SunoTheme { SongGenerationBanner( songGenerationReady = false, onClick = {}, onPlayButtonClick = {}, onDismiss = {}, ) } } @Preview @Composable private fun SongGenerationBanner_Ready_Preview() { SunoTheme { SongGenerationBanner( songGenerationReady = true, generationPreviewUrls = listOf( Url("https://picsum.photos/200/300"), Url("https://picsum.photos/200/300"), ), onClick = {}, onPlayButtonClick = {}, onDismiss = {}, ) } }