package com.suno.android.common_ui.components.menus import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.tween import androidx.compose.foundation.border 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.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Icon import androidx.compose.material3.Text import androidx.compose.runtime.Composable 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.draw.clip import androidx.compose.ui.draw.rotate import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.res.vectorResource import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.rememberTextMeasurer import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.PreviewLightDark import androidx.compose.ui.unit.dp import com.suno.android.common_ui.R import com.suno.android.common_ui.theme.ExtendedTheme import com.suno.android.common_ui.theme.SunoTheme import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf @Composable fun ModelSelectorDropdownMenu( modifier: Modifier = Modifier, selectedItem: String, options: ImmutableList, onOptionSelected: (ModelSelectorDropdownState) -> Unit, ) { var expanded by remember { mutableStateOf(false) } val textStyle = ExtendedTheme.typography.smallSubtitle.copy( textAlign = TextAlign.Center, ) val textMeasurer = rememberTextMeasurer() val maxWidth = options.map { it.title }.maxOfOrNull { text -> val textLayoutResult = textMeasurer.measure( text = AnnotatedString(text), style = textStyle, ) textLayoutResult.size.width }?.coerceAtMost(70) ?: 70 Box(contentAlignment = Alignment.Center) { Row( modifier = modifier .height(40.dp) .border( width = 1.dp, color = ExtendedTheme.colors.textPrimary.copy(alpha = 0.1f), shape = RoundedCornerShape(25.dp), ) .clip(shape = RoundedCornerShape(25.dp)) .clickable { expanded = expanded.not() } .padding(horizontal = 12.dp) .width(maxWidth.dp), horizontalArrangement = Arrangement.spacedBy(4.dp), verticalAlignment = Alignment.CenterVertically, ) { Text( modifier = Modifier.weight(1f), text = selectedItem, style = textStyle, color = ExtendedTheme.colors.textPrimary, ) val iconRotation by animateFloatAsState( targetValue = if (expanded) 180f else 0f, animationSpec = tween(durationMillis = 300), ) Icon( modifier = Modifier .rotate(iconRotation) .size(16.dp), imageVector = ImageVector.vectorResource( id = R.drawable.chevron_down, ), contentDescription = "Close", tint = ExtendedTheme.colors.textPrimary, ) } ModelDropdownMenu( expanded = expanded, onDismissRequest = { expanded = false }, options = options, onOptionSelected = { selectedOption -> onOptionSelected(selectedOption) expanded = false }, ) } } @PreviewLightDark @Composable private fun BasicMenu_Preview() { SunoTheme { ModelSelectorDropdownMenu( selectedItem = "v4.5", options = persistentListOf( ModelSelectorDropdownState( title = "v4.5", showProBadge = true, songsLeft = null, description = "This is sparta!!!", isSelected = true, ), ), onOptionSelected = {}, ) } }