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
+2 -2
View File
@@ -12,8 +12,8 @@ android {
applicationId = namespace applicationId = namespace
minSdk = libs.versions.proj.min.get().toInt() minSdk = libs.versions.proj.min.get().toInt()
targetSdk = libs.versions.proj.target.get().toInt() targetSdk = libs.versions.proj.target.get().toInt()
versionCode = 44 versionCode = 45
versionName = "1.24" versionName = "1.24.1"
} }
} }
@@ -41,6 +41,11 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.FocusRequester
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.LinkAnnotation
import androidx.compose.ui.text.SpanStyle import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.TextLinkStyles import androidx.compose.ui.text.TextLinkStyles
@@ -127,7 +132,8 @@ private fun ChatContent(
) { ) {
val listState = rememberLazyListState() val listState = rememberLazyListState()
var textInput by remember { mutableStateOf("") } var textInput by remember { mutableStateOf("") }
val requester = remember { FocusRequester() } val textFieldFocusRequester = remember { FocusRequester() }
val listFocusRequester = remember { FocusRequester() }
LaunchedEffect(state.messages.size) { LaunchedEffect(state.messages.size) {
if (state.messages.isNotEmpty()) { if (state.messages.isNotEmpty()) {
@@ -141,6 +147,7 @@ private fun ChatContent(
LazyColumn( LazyColumn(
state = listState, state = listState,
modifier = Modifier.applyBlurSource(blurState) modifier = Modifier.applyBlurSource(blurState)
.focusRequester(listFocusRequester)
.weight(1f) .weight(1f)
.fillMaxWidth(), .fillMaxWidth(),
contentPadding = contentPadding, contentPadding = contentPadding,
@@ -170,7 +177,7 @@ private fun ChatContent(
OutlinedTextField( OutlinedTextField(
value = textInput, value = textInput,
onValueChange = { textInput = it }, onValueChange = { textInput = it },
modifier = Modifier.focusRequester(requester).fillMaxWidth(), modifier = Modifier.focusRequester(textFieldFocusRequester).resetFocusOnUpEvent(listFocusRequester).fillMaxWidth(),
shape = RoundedCornerShape(24.dp), shape = RoundedCornerShape(24.dp),
placeholder = { Text(stringResource(Res.string.chat_input_placeholder)) }, placeholder = { Text(stringResource(Res.string.chat_input_placeholder)) },
enabled = !state.isSending, enabled = !state.isSending,
@@ -184,7 +191,7 @@ private fun ChatContent(
} }
LaunchedEffect(null) { LaunchedEffect(null) {
withFrameNanos {} withFrameNanos {}
requester.requestFocus() textFieldFocusRequester.requestFocus()
} }
} }
@@ -199,39 +206,51 @@ private fun MessageBubble(
val containerColor = if (isUser) MaterialTheme.colorScheme.primaryContainer else MaterialTheme.colorScheme.surfaceVariant val containerColor = if (isUser) MaterialTheme.colorScheme.primaryContainer else MaterialTheme.colorScheme.surfaceVariant
val contentColor = if (isUser) MaterialTheme.colorScheme.onPrimaryContainer else MaterialTheme.colorScheme.onSurfaceVariant val contentColor = if (isUser) MaterialTheme.colorScheme.onPrimaryContainer else MaterialTheme.colorScheme.onSurfaceVariant
val tokens = remember(message.content) { onParseMessage(message.content) } val tokens = remember(message.content) { onParseMessage(message.content) }
val annotatedString = buildAnnotatedString { val primaryColor = MaterialTheme.colorScheme.primary
tokens.forEach { token -> val focusBackgroundColor = MaterialTheme.colorScheme.primary.copy(alpha = 0.15f)
when (token) { val annotatedString = remember(tokens, primaryColor, focusBackgroundColor) {
is TextToken.Plain -> { append(token.text) } buildAnnotatedString {
is TextToken.Link -> { tokens.forEach { token ->
val linkAnnotation = LinkAnnotation.Clickable( when (token) {
tag = "LINK", is TextToken.Plain -> append(token.text)
styles = TextLinkStyles( is TextToken.Link -> {
style = SpanStyle( val linkAnnotation = LinkAnnotation.Clickable(
color = MaterialTheme.colorScheme.primary, tag = "LINK",
fontWeight = FontWeight.Bold, styles = TextLinkStyles(
textDecoration = TextDecoration.Underline style = SpanStyle(
) color = primaryColor,
), fontWeight = FontWeight.Bold,
linkInteractionListener = { textDecoration = TextDecoration.Underline
onClickLink(token.text) ),
} focusedStyle = SpanStyle(
) background = focusBackgroundColor,
withLink(linkAnnotation) { append(token.text) } color = primaryColor
)
),
linkInteractionListener = { onClickLink(token.text) }
)
withLink(linkAnnotation) { append(token.text) }
}
} }
} }
} }
} }
Box(modifier = Modifier.fillMaxWidth(), contentAlignment = alignment) { Box(
modifier = Modifier.fillMaxWidth(),
contentAlignment = alignment
) {
Card( Card(
colors = CardDefaults.cardColors(containerColor = containerColor, contentColor = contentColor), colors = CardDefaults.cardColors(
containerColor = containerColor,
contentColor = contentColor
),
modifier = Modifier.widthIn(max = 280.dp) modifier = Modifier.widthIn(max = 280.dp)
) { ) {
Column(modifier = Modifier.padding(12.dp)) { Column(modifier = Modifier.padding(12.dp)) {
SelectionContainer { SelectionContainer {
Text( Text(
text = annotatedString, 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
}
}
@@ -10,7 +10,6 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.navigationBars import androidx.compose.foundation.layout.navigationBars
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.safeDrawing
import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.material3.ColorScheme import androidx.compose.material3.ColorScheme
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
@@ -106,7 +105,7 @@ fun <T : Route> AppScaffold(
modifier modifier
}, snackbarHost = { }, snackbarHost = {
snackbarState?.let { SnackbarHost(it) } snackbarState?.let { SnackbarHost(it) }
}, contentWindowInsets = WindowInsets.safeDrawing }
) )
} }
} }