up version

This commit is contained in:
2026-07-29 19:49:43 +03:00
parent 4bd8e0a2bc
commit 98976cb3f5
3 changed files with 58 additions and 29 deletions
@@ -41,6 +41,11 @@ 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.input.key.Key
import androidx.compose.ui.input.key.KeyEventType
import androidx.compose.ui.input.key.key
import androidx.compose.ui.input.key.onKeyEvent
import androidx.compose.ui.input.key.type
import androidx.compose.ui.text.LinkAnnotation
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.TextLinkStyles
@@ -127,7 +132,8 @@ private fun ChatContent(
) {
val listState = rememberLazyListState()
var textInput by remember { mutableStateOf("") }
val requester = remember { FocusRequester() }
val textFieldFocusRequester = remember { FocusRequester() }
val listFocusRequester = remember { FocusRequester() }
LaunchedEffect(state.messages.size) {
if (state.messages.isNotEmpty()) {
@@ -141,6 +147,7 @@ private fun ChatContent(
LazyColumn(
state = listState,
modifier = Modifier.applyBlurSource(blurState)
.focusRequester(listFocusRequester)
.weight(1f)
.fillMaxWidth(),
contentPadding = contentPadding,
@@ -170,7 +177,7 @@ private fun ChatContent(
OutlinedTextField(
value = textInput,
onValueChange = { textInput = it },
modifier = Modifier.focusRequester(requester).fillMaxWidth(),
modifier = Modifier.focusRequester(textFieldFocusRequester).resetFocusOnUpEvent(listFocusRequester).fillMaxWidth(),
shape = RoundedCornerShape(24.dp),
placeholder = { Text(stringResource(Res.string.chat_input_placeholder)) },
enabled = !state.isSending,
@@ -184,7 +191,7 @@ private fun ChatContent(
}
LaunchedEffect(null) {
withFrameNanos {}
requester.requestFocus()
textFieldFocusRequester.requestFocus()
}
}
@@ -199,39 +206,51 @@ private fun MessageBubble(
val containerColor = if (isUser) MaterialTheme.colorScheme.primaryContainer else MaterialTheme.colorScheme.surfaceVariant
val contentColor = if (isUser) MaterialTheme.colorScheme.onPrimaryContainer else MaterialTheme.colorScheme.onSurfaceVariant
val tokens = remember(message.content) { onParseMessage(message.content) }
val annotatedString = buildAnnotatedString {
tokens.forEach { token ->
when (token) {
is TextToken.Plain -> { append(token.text) }
is TextToken.Link -> {
val linkAnnotation = LinkAnnotation.Clickable(
tag = "LINK",
styles = TextLinkStyles(
style = SpanStyle(
color = MaterialTheme.colorScheme.primary,
fontWeight = FontWeight.Bold,
textDecoration = TextDecoration.Underline
)
),
linkInteractionListener = {
onClickLink(token.text)
}
)
withLink(linkAnnotation) { append(token.text) }
val primaryColor = MaterialTheme.colorScheme.primary
val focusBackgroundColor = MaterialTheme.colorScheme.primary.copy(alpha = 0.15f)
val annotatedString = remember(tokens, primaryColor, focusBackgroundColor) {
buildAnnotatedString {
tokens.forEach { token ->
when (token) {
is TextToken.Plain -> append(token.text)
is TextToken.Link -> {
val linkAnnotation = LinkAnnotation.Clickable(
tag = "LINK",
styles = TextLinkStyles(
style = SpanStyle(
color = primaryColor,
fontWeight = FontWeight.Bold,
textDecoration = TextDecoration.Underline
),
focusedStyle = SpanStyle(
background = focusBackgroundColor,
color = primaryColor
)
),
linkInteractionListener = { onClickLink(token.text) }
)
withLink(linkAnnotation) { append(token.text) }
}
}
}
}
}
Box(modifier = Modifier.fillMaxWidth(), contentAlignment = alignment) {
Box(
modifier = Modifier.fillMaxWidth(),
contentAlignment = alignment
) {
Card(
colors = CardDefaults.cardColors(containerColor = containerColor, contentColor = contentColor),
colors = CardDefaults.cardColors(
containerColor = containerColor,
contentColor = contentColor
),
modifier = Modifier.widthIn(max = 280.dp)
) {
Column(modifier = Modifier.padding(12.dp)) {
SelectionContainer {
Text(
text = annotatedString,
style = MaterialTheme.typography.bodyLarge.copy(color = contentColor)
style = MaterialTheme.typography.bodyLarge
)
}
}
@@ -239,3 +258,14 @@ private fun MessageBubble(
}
}
private fun Modifier.resetFocusOnUpEvent(focusRequester: FocusRequester): Modifier {
return onKeyEvent {
if (it.type == KeyEventType.KeyUp) {
if (it.key == Key.DirectionUp) {
focusRequester.requestFocus()
}
}
true
}
}