From 16fbd409070c5e508b73575ec73ba99c655d803f Mon Sep 17 00:00:00 2001 From: Sweetbread Date: Thu, 23 Apr 2026 20:35:29 +0300 Subject: [PATCH] fix: close message field after closing a keyboard, change design --- .../risdeveau/pixeldragon/ui/layout/Room.kt | 74 +++++++++++++++---- 1 file changed, 60 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/ru/risdeveau/pixeldragon/ui/layout/Room.kt b/app/src/main/java/ru/risdeveau/pixeldragon/ui/layout/Room.kt index 44ad2ca..afdb6ef 100755 --- a/app/src/main/java/ru/risdeveau/pixeldragon/ui/layout/Room.kt +++ b/app/src/main/java/ru/risdeveau/pixeldragon/ui/layout/Room.kt @@ -24,17 +24,21 @@ import android.webkit.WebSettings import android.webkit.WebView import android.webkit.WebViewClient import android.widget.TextView +import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.BoxWithConstraints import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ExperimentalLayoutApi import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.isImeVisible import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size @@ -61,12 +65,15 @@ import androidx.compose.runtime.rememberUpdatedState import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.composed import androidx.compose.ui.draw.alpha import androidx.compose.ui.draw.clipToBounds +import androidx.compose.ui.focus.onFocusEvent import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.IntOffset @@ -94,7 +101,6 @@ import de.connect2x.trixnity.core.model.events.m.room.RoomMessageEventContent import de.connect2x.trixnity.core.model.events.m.room.TopicEventContent import io.github.rabehx.iconsax.Iconsax import io.github.rabehx.iconsax.filled.Send2 -import io.github.rabehx.iconsax.outline.Send2 import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -125,6 +131,7 @@ private const val TIMELINE_BOTTOM_AUTOSCROLL_THRESHOLD = 3 private const val MAX_INITIAL_UNREAD_SEARCH_LIMIT = 500 private val TIMELINE_AVATAR_SIZE = 32.dp private val MESSAGE_FIELD_TOP_PADDING = 8.dp +private val MESSAGE_FIELD_SIZE = 48.dp private val simpleHtmlTags = setOf( "a", "b", "blockquote", "br", "code", "del", "div", "em", "h1", "h2", @@ -363,29 +370,43 @@ fun Room(modifier: Modifier = Modifier, rid: String) { } } - Row(Modifier.fillMaxWidth()) { + Row(Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) { OutlinedTextField( modifier = Modifier + .clearFocusOnKeyboardDismiss() .padding(MESSAGE_FIELD_TOP_PADDING) + .height(MESSAGE_FIELD_SIZE) .weight(1f), + shape = CircleShape, value = message, onValueChange = { message = it }, ) - IconButton( - enabled = message.isNotBlank(), - content = { Icon(if (message.isBlank()) Iconsax.Outline.Send2 else Iconsax.Filled.Send2, contentDescription = "Send") }, - onClick = { - val payload = message.trim() - if (payload.isBlank()) return@IconButton - CoroutineScope(Dispatchers.IO).launch { - client!!.room.sendMessage(RoomId(rid)) { - text(payload) + AnimatedVisibility(message.isNotBlank()) { + IconButton( + modifier = Modifier + .size(MESSAGE_FIELD_SIZE) + .background(MaterialTheme.colorScheme.primary, CircleShape), + enabled = message.isNotBlank(), + content = { + Icon(Iconsax.Filled.Send2, + contentDescription = "Send", + tint = MaterialTheme.colorScheme.inversePrimary + ) + }, + onClick = { + val payload = message.trim() + if (payload.isBlank()) return@IconButton + + CoroutineScope(Dispatchers.IO).launch { + client!!.room.sendMessage(RoomId(rid)) { + text(payload) + } } + message = "" } - message = "" - } - ) + ) + } } } } @@ -1727,3 +1748,28 @@ private fun wrapHtml( private fun colorToCss(color: Color): String { return String.format("#%06X", 0xFFFFFF and color.toArgb()) } + +@OptIn(ExperimentalLayoutApi::class) +fun Modifier.clearFocusOnKeyboardDismiss(): Modifier = composed { + var isFocused by remember { mutableStateOf(false) } + var keyboardAppearedSinceLastFocused by remember { mutableStateOf(false) } + if (isFocused) { + val imeIsVisible = WindowInsets.isImeVisible + val focusManager = LocalFocusManager.current + LaunchedEffect(imeIsVisible) { + if (imeIsVisible) { + keyboardAppearedSinceLastFocused = true + } else if (keyboardAppearedSinceLastFocused) { + focusManager.clearFocus() + } + } + } + onFocusEvent { + if (isFocused != it.isFocused) { + isFocused = it.isFocused + if (isFocused) { + keyboardAppearedSinceLastFocused = false + } + } + } +}