Skip to content

Commit eff693c

Browse files
Fix for message composer losing focus in Compose 1.8.0 (#4853)
Co-authored-by: ElementBot <[email protected]>
1 parent 2eda54d commit eff693c

File tree

12 files changed

+46
-25
lines changed

12 files changed

+46
-25
lines changed

features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/ExpandableBottomSheetScaffold.kt

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@
1010
package io.element.android.features.messages.impl
1111

1212
import androidx.compose.foundation.layout.PaddingValues
13+
import androidx.compose.foundation.layout.WindowInsets
1314
import androidx.compose.foundation.layout.fillMaxHeight
15+
import androidx.compose.foundation.layout.ime
16+
import androidx.compose.foundation.layout.windowInsetsPadding
1417
import androidx.compose.material3.ExperimentalMaterial3Api
1518
import androidx.compose.material3.SheetValue
1619
import androidx.compose.material3.rememberBottomSheetScaffoldState
@@ -112,7 +115,7 @@ internal fun ExpandableBottomSheetScaffold(
112115
}
113116

114117
SubcomposeLayout(
115-
modifier = modifier,
118+
modifier = modifier.windowInsetsPadding(WindowInsets.ime),
116119
measurePolicy = { constraints: Constraints ->
117120
val sheetContentSub = subcompose(Slot.SheetContent(sheetContentKey)) { sheetContent(true) }.map {
118121
it.measure(Constraints(maxWidth = constraints.maxWidth))
@@ -123,7 +126,7 @@ internal fun ExpandableBottomSheetScaffold(
123126
val dragHandleHeight = dragHandleSub?.height?.toDp() ?: 0.dp
124127

125128
val maxHeight = constraints.maxHeight.toDp()
126-
val contentHeight = sheetContentSub.height.toDp() + dragHandleHeight
129+
val contentHeight = sheetContentSub.measuredHeight.toDp() + dragHandleHeight
127130

128131
contentOverflows = contentHeight > maxHeight
129132

@@ -140,7 +143,7 @@ internal fun ExpandableBottomSheetScaffold(
140143
measurePolicy = { measurables, constraints ->
141144
val constraintHeight = constraints.maxHeight
142145
val offset = tryOrNull { scaffoldState.bottomSheetState.requireOffset() } ?: 0f
143-
val height = Integer.max(0, constraintHeight - offset.roundToInt())
146+
val height = Integer.max(peekHeight.roundToPx(), constraintHeight - offset.roundToInt())
144147
val top = measurables[0].measure(
145148
constraints.copy(
146149
minHeight = height,

libraries/androidutils/src/main/kotlin/io/element/android/libraries/androidutils/ui/View.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ fun View.showKeyboard(andRequestFocus: Boolean = false) {
2727
imm?.showSoftInput(this, InputMethodManager.SHOW_IMPLICIT)
2828
}
2929

30+
fun View.isKeyboardVisible(): Boolean {
31+
val imm = context?.getSystemService<InputMethodManager>()
32+
return imm?.isAcceptingText == true
33+
}
34+
3035
suspend fun View.awaitWindowFocus() = suspendCancellableCoroutine { continuation ->
3136
if (hasWindowFocus()) {
3237
continuation.resume(Unit)

libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/SoftKeyboardEffect.kt

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,16 @@
77

88
package io.element.android.libraries.textcomposer
99

10+
import android.os.Build
11+
import android.view.WindowInsets
1012
import androidx.compose.runtime.Composable
1113
import androidx.compose.runtime.LaunchedEffect
1214
import androidx.compose.runtime.getValue
1315
import androidx.compose.runtime.rememberUpdatedState
1416
import androidx.compose.ui.platform.LocalView
1517
import androidx.compose.ui.viewinterop.AndroidView
1618
import io.element.android.libraries.androidutils.ui.awaitWindowFocus
19+
import io.element.android.libraries.androidutils.ui.isKeyboardVisible
1720
import io.element.android.libraries.androidutils.ui.showKeyboard
1821

1922
/**
@@ -40,11 +43,17 @@ internal fun <T> SoftKeyboardEffect(
4043
// Await window focus in case returning from a dialog
4144
view.awaitWindowFocus()
4245

43-
// Show the keyboard, temporarily using the root view for focus
44-
view.showKeyboard(andRequestFocus = true)
46+
if (!view.isKeyboardVisible()) {
47+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
48+
view.windowInsetsController?.show(WindowInsets.Type.ime())
49+
} else {
50+
// Show the keyboard, temporarily using the root view for focus
51+
view.showKeyboard(andRequestFocus = true)
52+
}
4553

46-
// Refocus to the correct view
47-
latestOnRequestFocus()
54+
// Refocus to the correct view
55+
latestOnRequestFocus()
56+
}
4857
}
4958
}
5059
}

libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/TextComposer.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,14 @@ import androidx.compose.foundation.layout.Column
1818
import androidx.compose.foundation.layout.IntrinsicSize
1919
import androidx.compose.foundation.layout.Row
2020
import androidx.compose.foundation.layout.Spacer
21+
import androidx.compose.foundation.layout.WindowInsets
2122
import androidx.compose.foundation.layout.fillMaxSize
2223
import androidx.compose.foundation.layout.fillMaxWidth
2324
import androidx.compose.foundation.layout.height
2425
import androidx.compose.foundation.layout.padding
2526
import androidx.compose.foundation.layout.requiredHeightIn
2627
import androidx.compose.foundation.layout.size
28+
import androidx.compose.foundation.layout.systemBars
2729
import androidx.compose.foundation.layout.width
2830
import androidx.compose.runtime.Composable
2931
import androidx.compose.runtime.LaunchedEffect
@@ -35,6 +37,7 @@ import androidx.compose.runtime.setValue
3537
import androidx.compose.ui.Alignment
3638
import androidx.compose.ui.Modifier
3739
import androidx.compose.ui.draw.clip
40+
import androidx.compose.ui.platform.LocalDensity
3841
import androidx.compose.ui.res.stringResource
3942
import androidx.compose.ui.text.style.TextOverflow
4043
import androidx.compose.ui.tooling.preview.Preview
@@ -432,8 +435,9 @@ private fun TextFormattingLayout(
432435
sendButton: @Composable () -> Unit,
433436
modifier: Modifier = Modifier
434437
) {
438+
val bottomPadding = with(LocalDensity.current) { WindowInsets.systemBars.getBottom(this).toDp() + 8.dp }
435439
Column(
436-
modifier = modifier.padding(vertical = 4.dp),
440+
modifier = modifier.padding(vertical = 4.dp).padding(bottom = bottomPadding),
437441
verticalArrangement = Arrangement.spacedBy(4.dp),
438442
) {
439443
if (isRoomEncrypted == false) {

libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/markdown/MarkdownEditText.kt

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
package io.element.android.libraries.textcomposer.components.markdown
99

1010
import android.content.Context
11-
import android.view.View
1211
import androidx.appcompat.widget.AppCompatEditText
1312

1413
internal class MarkdownEditText(
@@ -37,8 +36,4 @@ internal class MarkdownEditText(
3736
onSelectionChangeListener?.invoke(selStart, selEnd)
3837
}
3938
}
40-
41-
override fun focusSearch(direction: Int): View? {
42-
return null
43-
}
4439
}

libraries/textcomposer/impl/src/main/kotlin/io/element/android/libraries/textcomposer/components/markdown/MarkdownTextInput.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,11 @@ fun MarkdownTextInput(
118118
)
119119
}
120120
state.requestFocusAction = { this.requestFocus() }
121+
} else {
122+
isEnabled = false
123+
isFocusable = false
124+
isFocusableInTouchMode = false
125+
isClickable = false
121126
}
122127
}
123128
},
Lines changed: 2 additions & 2 deletions
Loading
Lines changed: 2 additions & 2 deletions
Loading
Lines changed: 2 additions & 2 deletions
Loading
Lines changed: 2 additions & 2 deletions
Loading

0 commit comments

Comments
 (0)