input field: more breathing room, mic/send toggle
Reduced outer padding (12dp→8dp) for wider feel, increased inner padding (8dp→10dp) and min height (36dp→42dp) for more air. Placeholder text slightly smaller (15sp) and more subtle (0.6α). Text line-height increased to 24sp. Single action button: shows Mic icon when input is empty, morphs to Send button when text is entered — like WhatsApp/iMessage. Removed separate Call button that took space without function. Aligned action buttons to bottom for multi-line input.
This commit is contained in:
parent
fb90577884
commit
2d57afff61
1 changed files with 18 additions and 18 deletions
|
|
@ -89,6 +89,7 @@ import androidx.compose.material.icons.rounded.VideoFile
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.material.icons.rounded.Bolt
|
import androidx.compose.material.icons.rounded.Bolt
|
||||||
|
import androidx.compose.material.icons.rounded.Mic
|
||||||
import androidx.compose.material.icons.rounded.ExpandMore
|
import androidx.compose.material.icons.rounded.ExpandMore
|
||||||
import androidx.compose.material.icons.rounded.Psychology
|
import androidx.compose.material.icons.rounded.Psychology
|
||||||
import androidx.compose.material.icons.rounded.Tune
|
import androidx.compose.material.icons.rounded.Tune
|
||||||
|
|
@ -463,10 +464,13 @@ fun ChatInput(
|
||||||
val cs = MaterialTheme.colorScheme
|
val cs = MaterialTheme.colorScheme
|
||||||
val isDark = isSystemInDarkTheme()
|
val isDark = isSystemInDarkTheme()
|
||||||
|
|
||||||
|
val hasContent = value.isNotBlank() || pendingFiles.any { it.uploaded != null }
|
||||||
|
val canSend = enabled && hasContent && pendingFiles.none { it.uploading }
|
||||||
|
|
||||||
GlassSurface(
|
GlassSurface(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(horizontal = 12.dp),
|
.padding(horizontal = 8.dp),
|
||||||
shape = KaizenShapes.xl,
|
shape = KaizenShapes.xl,
|
||||||
tintAlpha = GlassTiers.input(isDark),
|
tintAlpha = GlassTiers.input(isDark),
|
||||||
shadowStack = KaizenShadows.level2,
|
shadowStack = KaizenShadows.level2,
|
||||||
|
|
@ -475,39 +479,35 @@ fun ChatInput(
|
||||||
Column {
|
Column {
|
||||||
if (pendingFiles.isNotEmpty()) {
|
if (pendingFiles.isNotEmpty()) {
|
||||||
Row(
|
Row(
|
||||||
Modifier.fillMaxWidth().horizontalScroll(rememberScrollState()).padding(start = 12.dp, end = 12.dp, top = 8.dp),
|
Modifier.fillMaxWidth().horizontalScroll(rememberScrollState()).padding(start = 14.dp, end = 14.dp, top = 10.dp),
|
||||||
horizontalArrangement = Arrangement.spacedBy(6.dp),
|
horizontalArrangement = Arrangement.spacedBy(6.dp),
|
||||||
) {
|
) {
|
||||||
pendingFiles.forEach { pf -> PendingFileChip(pf, onRemove = { onRemoveFile(pf.id) }) }
|
pendingFiles.forEach { pf -> PendingFileChip(pf, onRemove = { onRemoveFile(pf.id) }) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Row(Modifier.padding(horizontal = 8.dp, vertical = 8.dp), verticalAlignment = Alignment.CenterVertically) {
|
Row(Modifier.padding(start = 6.dp, end = 8.dp, top = 10.dp, bottom = 10.dp), verticalAlignment = Alignment.Bottom) {
|
||||||
Box(Modifier.size(40.dp).clip(KaizenShapes.circle).clickable(onClick = onAddClick), contentAlignment = Alignment.Center) {
|
Box(Modifier.size(42.dp).clip(KaizenShapes.circle).clickable(onClick = onAddClick), contentAlignment = Alignment.Center) {
|
||||||
Icon(Icons.Rounded.Add, stringResource(R.string.chat_attachment), tint = cs.onSurfaceVariant, modifier = Modifier.size(22.dp))
|
Icon(Icons.Rounded.Add, stringResource(R.string.chat_attachment), tint = cs.onSurfaceVariant, modifier = Modifier.size(22.dp))
|
||||||
}
|
}
|
||||||
Box(Modifier.weight(1f).heightIn(min = 36.dp).padding(horizontal = 4.dp), contentAlignment = Alignment.CenterStart) {
|
Box(Modifier.weight(1f).heightIn(min = 42.dp).padding(horizontal = 6.dp), contentAlignment = Alignment.CenterStart) {
|
||||||
if (value.isEmpty()) Text(stringResource(R.string.chat_input_placeholder), color = cs.onSurfaceVariant, fontSize = 16.sp)
|
if (value.isEmpty()) Text(stringResource(R.string.chat_input_placeholder), color = cs.onSurfaceVariant.copy(alpha = 0.6f), fontSize = 15.sp)
|
||||||
val accent = LocalKaizenAccent.current
|
val accent = LocalKaizenAccent.current
|
||||||
BasicTextField(
|
BasicTextField(
|
||||||
value = value, onValueChange = onValueChange,
|
value = value, onValueChange = onValueChange,
|
||||||
textStyle = TextStyle(color = cs.onBackground, fontSize = 16.sp, lineHeight = 22.sp),
|
textStyle = TextStyle(color = cs.onBackground, fontSize = 16.sp, lineHeight = 24.sp),
|
||||||
cursorBrush = SolidColor(accent.primary), maxLines = 6, modifier = Modifier.fillMaxWidth(),
|
cursorBrush = SolidColor(accent.primary), maxLines = 6, modifier = Modifier.fillMaxWidth(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
GhostIconButton(Icons.Rounded.Call, stringResource(R.string.chat_call))
|
|
||||||
Spacer(Modifier.width(4.dp))
|
Spacer(Modifier.width(4.dp))
|
||||||
val canSend = enabled && (value.isNotBlank() || pendingFiles.any { it.uploaded != null }) && pendingFiles.none { it.uploading }
|
if (hasContent) {
|
||||||
SendButton(enabled = canSend, onClick = onSend)
|
SendButton(enabled = canSend, onClick = onSend)
|
||||||
|
} else {
|
||||||
|
Box(Modifier.size(44.dp).clip(KaizenShapes.circle), contentAlignment = Alignment.Center) {
|
||||||
|
Icon(Icons.Rounded.Mic, stringResource(R.string.chat_call), tint = cs.onSurfaceVariant, modifier = Modifier.size(22.dp))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun GhostIconButton(icon: ImageVector, contentDescription: String) {
|
|
||||||
val cs = MaterialTheme.colorScheme
|
|
||||||
Box(Modifier.size(40.dp).clip(KaizenShapes.circle), contentAlignment = Alignment.Center) {
|
|
||||||
Icon(icon, contentDescription, tint = cs.onSurfaceVariant, modifier = Modifier.size(22.dp))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue