package com.suno.android.ui.screens.create.text import androidx.compose.animation.core.Spring import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.spring import androidx.compose.foundation.background import androidx.compose.foundation.border import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxWidth 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.RoundedCornerShape import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.IconButtonDefaults 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.graphics.Color import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.layout.onSizeChanged import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.vectorResource import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.dp import com.suno.android.common_networking.remote.session.Model import com.suno.android.common_ui.components.menus.ModelSelectorDropdownMenu import com.suno.android.common_ui.extensions.xAsFormattedCount import com.suno.android.common_ui.theme.DarkTextPrimary import com.suno.android.common_ui.theme.ExtendedTheme import com.suno.android.common_ui.theme.HeaderLibraryOrange import com.suno.android.extensions.toModelSelectorDropdownStates import com.suno.android.ui.screens.orpheus.components.OrpheusActionButton import kotlin.math.roundToInt import com.suno.android.common_res.R as CommonResR import com.suno.android.common_ui.R as CommonUiR @Composable fun CreateTextTopBar( toggleState: Boolean, onCustomToggled: (Boolean) -> Unit, onModelNameSelected: (selectedModel: String) -> Unit, modifier: Modifier = Modifier, creditCount: Int? = null, activeModel: Model? = null, onCreditClick: () -> Unit = {}, availableModels: List = emptyList(), backgroundColor: Color = ExtendedTheme.colors.backgroundSecondary, isFromOrpheus: Boolean = false, onCreateClick: () -> Unit = {}, isCreateButtonEnabled: Boolean = true, onPlusClick: () -> Unit = {}, ) { Column( verticalArrangement = Arrangement.spacedBy(16.dp), modifier = modifier.background(backgroundColor), ) { Row( modifier = Modifier .fillMaxWidth() .padding(horizontal = 16.dp) .height(40.dp), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically, ) { if (isFromOrpheus) { OrpheusActionButton( onClick = onPlusClick, iconPainter = painterResource(id = CommonUiR.drawable.plus), contentDescription = stringResource(CommonResR.string.options), ) Column( verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally, ) { Text( text = stringResource(CommonResR.string.custom), style = ExtendedTheme.typography.cardTitle, color = ExtendedTheme.colors.textPrimary, ) creditCount?.let { Text( text = stringResource(CommonResR.string.available_credits, it.xAsFormattedCount()), style = ExtendedTheme.typography.smallSubtitle, color = ExtendedTheme.colors.textSecondary, ) } } OrpheusActionButton( onClick = onCreateClick, iconPainter = painterResource(id = CommonUiR.drawable.arrow_up), contentDescription = stringResource(CommonResR.string.create), colors = IconButtonDefaults.filledIconButtonColors( containerColor = HeaderLibraryOrange, contentColor = DarkTextPrimary, ), enabled = isCreateButtonEnabled, ) } else { CreditCountChip( creditCount = creditCount, onClick = onCreditClick, ) Box( modifier = Modifier.weight(1f), contentAlignment = Alignment.Center, ) { SimpleCustomModeToggle( options = listOf( stringResource(CommonResR.string.simple), stringResource(CommonResR.string.custom), ), selectedIndex = if (toggleState) 1 else 0, onSelectionChange = { onCustomToggled(it == 1) }, ) } ModelSelectorDropdownMenu( selectedItem = activeModel?.name ?: "v3.5", options = availableModels.toModelSelectorDropdownStates( selectedModelName = activeModel?.name, ), onOptionSelected = { onModelNameSelected(it.title) }, ) } } HorizontalDivider( color = ExtendedTheme.colors.backgroundTertiary, ) } } @Composable fun CreditCountChip( creditCount: Int?, onClick: () -> Unit, ) { Row( modifier = Modifier .height(40.dp) .border( width = 1.dp, color = ExtendedTheme.colors.backgroundQuarternary, shape = RoundedCornerShape(25.dp), ) .padding(horizontal = 12.dp) .clickable { onClick() }, verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(4.dp), ) { Icon( modifier = Modifier.size(16.dp), imageVector = ImageVector.vectorResource( id = CommonUiR.drawable.music, ), contentDescription = null, tint = ExtendedTheme.colors.textPrimary, ) Text( text = (creditCount ?: 0).xAsFormattedCount(), style = ExtendedTheme.typography.smallSubtitle, color = ExtendedTheme.colors.textPrimary, ) } } @Composable fun SimpleCustomModeToggle( options: List, selectedIndex: Int, onSelectionChange: (Int) -> Unit, modifier: Modifier = Modifier, textStyle: TextStyle = ExtendedTheme.typography.smallSubtitle, textColor: Color = ExtendedTheme.colors.textPrimary, selectedTextColor: Color = ExtendedTheme.colors.textPrimary, selectedTabColor: Color = ExtendedTheme.colors.backgroundTertiary, borderColor: Color = ExtendedTheme.colors.textPrimary.copy(alpha = 0.1f), ) { var componentWidth by remember { mutableStateOf(0.dp) } val density = LocalDensity.current val animatedOffset by animateFloatAsState( targetValue = selectedIndex.toFloat(), animationSpec = spring( dampingRatio = Spring.DampingRatioLowBouncy, stiffness = Spring.StiffnessHigh, ), ) Box( modifier = modifier .width(140.dp) .background( color = Color.Transparent, shape = RoundedCornerShape(25.dp), ) .border( width = 1.dp, color = borderColor, shape = RoundedCornerShape(25.dp), ) .padding(4.dp) .onSizeChanged { size -> componentWidth = with(density) { size.width.toDp() } }, ) { if (componentWidth > 0.dp) { val segmentWidth = componentWidth / options.size Box( modifier = Modifier .offset { IntOffset( x = (animatedOffset * with(density) { segmentWidth.toPx() }).roundToInt(), y = 0, ) } .width(segmentWidth) .fillMaxHeight() .background( color = selectedTabColor, shape = RoundedCornerShape(21.dp), ), ) } Row { options.forEachIndexed { index, option -> Box( modifier = Modifier .weight(1f) .fillMaxHeight() .clickable( indication = null, interactionSource = remember { MutableInteractionSource() }, ) { onSelectionChange(index) }, contentAlignment = Alignment.Center, ) { Text( modifier = Modifier.padding(horizontal = 4.dp), text = option, color = if (index == selectedIndex) selectedTextColor else textColor, fontWeight = if (index == selectedIndex) FontWeight.Medium else FontWeight.Normal, style = textStyle, ) } } } } }