keyboard jumpy fix

This commit is contained in:
2026-03-03 21:56:13 +00:00
parent 9114b3189e
commit 0c6f0bc2c7
3 changed files with 80 additions and 14 deletions

View File

@@ -19,7 +19,8 @@
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop">
android:launchMode="singleTop"
android:windowSoftInputMode="adjustNothing">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

View File

@@ -13,6 +13,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
@@ -44,6 +45,8 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Path
@@ -289,7 +292,8 @@ fun MessageTimeline(
.padding(
top = contentPadding.calculateTopPadding(),
bottom = contentPadding.calculateBottomPadding(),
),
)
.imePadding(),
) {
if (selectedChannel != null) {
if (selectedThread != null) {
@@ -1372,18 +1376,78 @@ private fun MessageInput(
tint = MaterialTheme.colorScheme.onSurfaceVariant,
)
}
TextField(
value = text,
onValueChange = { text = it },
placeholder = { Text("Message #$channelName", color = MaterialTheme.colorScheme.onSurfaceVariant) },
modifier = Modifier.weight(1f).clip(RoundedCornerShape(8.dp)).heightIn(max = 160.dp),
maxLines = 8,
colors = TextFieldDefaults.colors(
unfocusedContainerColor = MaterialTheme.colorScheme.surfaceVariant,
focusedContainerColor = MaterialTheme.colorScheme.surfaceVariant,
unfocusedIndicatorColor = Color.Transparent,
focusedIndicatorColor = Color.Transparent,
),
val surfaceVariant = MaterialTheme.colorScheme.surfaceVariant
val onSurface = MaterialTheme.colorScheme.onSurface
val onSurfaceVariant = MaterialTheme.colorScheme.onSurfaceVariant
val textStyle = MaterialTheme.typography.bodyLarge
val density = LocalDensity.current
AndroidView(
factory = { ctx ->
object : android.widget.EditText(ctx) {
override fun requestRectangleOnScreen(rect: android.graphics.Rect?, immediate: Boolean): Boolean {
// Disable system scroll-into-view; Compose imePadding() handles it
return false
}
}.apply {
hint = "Message #$channelName"
setHintTextColor(onSurfaceVariant.toArgb())
setTextColor(onSurface.toArgb())
setTextSize(android.util.TypedValue.COMPLEX_UNIT_SP, textStyle.fontSize.value)
background = android.graphics.drawable.GradientDrawable().apply {
setColor(surfaceVariant.toArgb())
cornerRadius = with(density) { 8.dp.toPx() }
}
setPadding(
with(density) { 16.dp.toPx().toInt() },
with(density) { 12.dp.toPx().toInt() },
with(density) { 16.dp.toPx().toInt() },
with(density) { 12.dp.toPx().toInt() },
)
maxLines = 8
inputType = android.text.InputType.TYPE_CLASS_TEXT or
android.text.InputType.TYPE_TEXT_FLAG_MULTI_LINE or
android.text.InputType.TYPE_TEXT_FLAG_CAP_SENTENCES
isSingleLine = false
// Prevent EditText from fighting with Compose's imePadding()
imeOptions = android.view.inputmethod.EditorInfo.IME_FLAG_NO_EXTRACT_UI
addTextChangedListener(object : android.text.TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
override fun afterTextChanged(s: android.text.Editable?) {
text = s?.toString() ?: ""
}
})
androidx.core.view.ViewCompat.setOnReceiveContentListener(
this,
arrayOf("image/*"),
) { _, payload ->
val clip = payload.clip
var remaining = payload
for (i in 0 until clip.itemCount) {
val uri = clip.getItemAt(i).uri
if (uri != null) {
attachedUris = attachedUris + uri
}
}
// Return null to indicate all content was consumed
if (clip.itemCount > 0 && (0 until clip.itemCount).any { clip.getItemAt(it).uri != null }) null
else remaining
}
}
},
update = { editText ->
if (editText.text.toString() != text) {
editText.setText(text)
editText.setSelection(text.length)
}
editText.hint = "Message #$channelName"
},
modifier = Modifier
.weight(1f)
.heightIn(max = 160.dp),
)
if (emojiPacks.isNotEmpty()) {
IconButton(onClick = { showEmojiPackPicker = true }) {