package soy.iko.opencode.ui.chat import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.PlaylistPlay import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.ModalBottomSheet import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.Role import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.role import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.foundation.layout.Box import soy.iko.opencode.data.model.Command import soy.iko.opencode.R /** Bottom sheet that lists slash-commands; selecting one invokes it. */ @OptIn(ExperimentalMaterial3Api::class) @Composable fun CommandPickerSheet( commands: List, loading: Boolean, error: Boolean, onSelect: (Command) -> Unit, onRetry: () -> Unit, onDismiss: () -> Unit, ) { ModalBottomSheet(onDismissRequest = onDismiss) { Text( stringResource(R.string.commands), style = MaterialTheme.typography.titleMedium, modifier = Modifier.padding(start = 24.dp, end = 24.dp, bottom = 8.dp), ) if (loading) { val loadingLabel = stringResource(R.string.loading) Box( modifier = Modifier.fillMaxWidth().padding(vertical = 24.dp), contentAlignment = Alignment.Center, ) { CircularProgressIndicator(Modifier.semantics { contentDescription = loadingLabel }) } } else if (error && commands.isEmpty()) { Text( stringResource(R.string.load_failed), style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.error, modifier = Modifier .fillMaxWidth() .clickable(role = Role.Button) { onRetry() } .padding(horizontal = 24.dp, vertical = 16.dp), ) } else if (commands.isEmpty()) { Text( stringResource(R.string.no_commands), style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant, modifier = Modifier.padding(horizontal = 24.dp, vertical = 16.dp), ) } else { LazyColumn(modifier = Modifier.fillMaxWidth().heightIn(max = 420.dp)) { items(commands, key = { it.name }) { cmd -> Column( modifier = Modifier .fillMaxWidth() .clickable(role = Role.Button) { onSelect(cmd); onDismiss() } .padding(horizontal = 24.dp, vertical = 12.dp), ) { androidx.compose.foundation.layout.Row( verticalAlignment = androidx.compose.ui.Alignment.CenterVertically, ) { Icon(Icons.AutoMirrored.Filled.PlaylistPlay, contentDescription = null) Text( "/${cmd.name}", style = MaterialTheme.typography.bodyLarge, modifier = Modifier.padding(start = 8.dp), ) } Text( cmd.displayDescription, style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant, maxLines = 2, overflow = TextOverflow.Ellipsis, modifier = Modifier.padding(start = 28.dp, top = 2.dp), ) } } } } } }