package com.suno.android.common_ui.components.bottom_sheet import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.defaultMinSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.statusBars import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material3.ModalBottomSheet import androidx.compose.material3.SheetState import androidx.compose.material3.Text import androidx.compose.material3.TextField import androidx.compose.material3.TextFieldDefaults import androidx.compose.material3.rememberModalBottomSheetState 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.focus.FocusRequester import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.TextRange import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.suno.android.common_ui.R import com.suno.android.common_ui.components.buttons.SunoMediumButton import com.suno.android.common_ui.components.omni.CircleIconButton import com.suno.android.common_ui.components.preview.SunoPreview import com.suno.android.common_ui.theme.ExtendedTheme import com.suno.android.common_res.R as CommonResR @Composable fun TextEditingBottomSheet( sheetState: SheetState = rememberModalBottomSheetState(true), headerName: String, confirmButtonName: String, value: String, onConfirm: (String) -> Unit = {}, onDismiss: () -> Unit = {}, onEnter: () -> Unit = {}, maxLines: Int = 1, ) { val focusRequester = remember { FocusRequester() } ModalBottomSheet( onDismissRequest = onDismiss, sheetState = sheetState, dragHandle = null, ) { val statusBarHeightDp = with(LocalDensity.current) { WindowInsets.statusBars.getTop(LocalDensity.current).toDp() } Column( modifier = Modifier .background(ExtendedTheme.colors.backgroundPrimary) .fillMaxWidth() .defaultMinSize(minHeight = 128.dp) .heightIn( max = (LocalConfiguration.current.screenHeightDp - statusBarHeightDp.value).dp, ), ) { // Header Box( modifier = Modifier .fillMaxWidth() .padding(top = 16.dp) .height(64.dp), ) { Text( modifier = Modifier.align(Alignment.Center), text = headerName, style = ExtendedTheme.typography.introCopy, maxLines = maxLines, ) CircleIconButton( modifier = Modifier .align(Alignment.CenterEnd) .padding(16.dp), vectorDrawableResId = R.drawable.close, contentDescription = stringResource(CommonResR.string.close), onClick = onDismiss, ) } Column( modifier = Modifier .fillMaxWidth() .padding(horizontal = 16.dp), ) { var textState by remember { mutableStateOf( TextFieldValue( text = value, selection = TextRange(value.length), ), ) } val focusManager = LocalFocusManager.current TextField( modifier = Modifier .fillMaxWidth() .padding(top = 16.dp) .height(96.dp) .focusRequester(focusRequester), value = textState, onValueChange = { textState = it }, keyboardOptions = KeyboardOptions.Default.copy( autoCorrectEnabled = true, keyboardType = KeyboardType.Text, imeAction = ImeAction.Done, ), keyboardActions = KeyboardActions( onDone = { focusManager.clearFocus() onEnter() }, ), textStyle = ExtendedTheme.typography.largeBody.copy( textAlign = TextAlign.Center, fontSize = 32.sp, color = ExtendedTheme.colors.textBrand, ), colors = TextFieldDefaults.colors( unfocusedContainerColor = Color.Transparent, focusedContainerColor = Color.Transparent, unfocusedIndicatorColor = Color.Transparent, focusedIndicatorColor = Color.Transparent, focusedTextColor = ExtendedTheme.colors.textSecondary, unfocusedTextColor = ExtendedTheme.colors.textSecondary, cursorColor = ExtendedTheme.colors.sunoPink, ), maxLines = 1, ) Spacer(modifier = Modifier.height(16.dp)) SunoMediumButton( text = confirmButtonName, onClick = { onConfirm(textState.text) }, modifier = Modifier .fillMaxWidth() .padding(8.dp) .navigationBarsPadding(), enabled = textState.text.isNotBlank(), ) Spacer(modifier = Modifier.height(16.dp)) } } } LaunchedEffect(Unit) { focusRequester.requestFocus() } } @Preview(showSystemUi = true) @Composable private fun TextEditingBottomSheet_Preview() { SunoPreview { TextEditingBottomSheet( headerName = "Title", confirmButtonName = "Confirm", value = "Untitled", ) } }