Merge pull request #5835 from element-hq/feature/bma/limitComposerHeight

Limit composer height dynamically
This commit is contained in:
Benoit Marty 2025-12-04 09:49:19 +01:00 committed by GitHub
commit 9e71e2283b
3 changed files with 16 additions and 36 deletions

View file

@ -29,10 +29,15 @@ import androidx.compose.foundation.layout.systemBarsPadding
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.shadow import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.RectangleShape import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.platform.LocalView import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.Role import androidx.compose.ui.semantics.Role
@ -82,6 +87,7 @@ import io.element.android.libraries.designsystem.components.rememberExpandableBo
import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.text.toAnnotatedString import io.element.android.libraries.designsystem.text.toAnnotatedString
import io.element.android.libraries.designsystem.text.toDp
import io.element.android.libraries.designsystem.theme.components.BottomSheetDragHandle import io.element.android.libraries.designsystem.theme.components.BottomSheetDragHandle
import io.element.android.libraries.designsystem.theme.components.Scaffold import io.element.android.libraries.designsystem.theme.components.Scaffold
import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.theme.components.Text
@ -129,6 +135,8 @@ fun MessagesView(
val snackbarHostState = rememberSnackbarHostState(snackbarMessage = state.snackbarMessage) val snackbarHostState = rememberSnackbarHostState(snackbarMessage = state.snackbarMessage)
var maxComposerHeightPx by remember { mutableIntStateOf(120) }
// This is needed because the composer is inside an AndroidView that can't be affected by the FocusManager in Compose // This is needed because the composer is inside an AndroidView that can't be affected by the FocusManager in Compose
val localView = LocalView.current val localView = LocalView.current
@ -179,7 +187,13 @@ fun MessagesView(
modifier = modifier modifier = modifier
.fillMaxSize() .fillMaxSize()
.imePadding() .imePadding()
.systemBarsPadding(), .systemBarsPadding()
.onSizeChanged { size ->
// Let the composer takes at max half of the available height.
// The value will be different if the soft keyboard is displayed
// or not.
maxComposerHeightPx = (size.height * 0.5f).toInt()
},
content = { content = {
Scaffold( Scaffold(
contentWindowInsets = WindowInsets.statusBars, contentWindowInsets = WindowInsets.statusBars,
@ -313,7 +327,7 @@ fun MessagesView(
} else { } else {
RectangleShape RectangleShape
}, },
maxBottomSheetContentHeight = 360.dp, maxBottomSheetContentHeight = maxComposerHeightPx.toDp(),
) )
ActionListView( ActionListView(

View file

@ -77,28 +77,9 @@ fun ExpandableBottomSheetLayout(
var calculatedMaxBottomContentHeightPx by remember(maxBottomContentHeightPx) { mutableIntStateOf(maxBottomContentHeightPx) } var calculatedMaxBottomContentHeightPx by remember(maxBottomContentHeightPx) { mutableIntStateOf(maxBottomContentHeightPx) }
val animatable = remember { Animatable(0f) } val animatable = remember { Animatable(0f) }
fun calculatePercentage(currentPos: Int, minPos: Int, maxPos: Int): Float {
val currentProgress = currentPos - minPos
if (currentProgress < 0) {
Timber.e("Invalid current progress: $currentProgress, minPos: $minPos, maxPos: $maxPos")
return 0f
}
val total = (maxPos - minPos).toFloat()
if (total <= 0) {
Timber.e("Invalid total space: $total, minPos: $minPos, maxPos: $maxPos")
return 0f
}
return currentProgress / total
}
LaunchedEffect(animatable.value) { LaunchedEffect(animatable.value) {
if (animatable.isRunning && animatable.value != animatable.targetValue) { if (animatable.isRunning && animatable.value != animatable.targetValue) {
currentBottomContentHeightPx = animatable.value.roundToInt() currentBottomContentHeightPx = animatable.value.roundToInt()
state.internalDraggingPercentage = calculatePercentage(
currentPos = currentBottomContentHeightPx,
minPos = minBottomContentHeightPx,
maxPos = calculatedMaxBottomContentHeightPx,
)
} }
} }
@ -122,11 +103,6 @@ fun ExpandableBottomSheetLayout(
minBottomContentHeightPx -> ExpandableBottomSheetLayoutState.Position.COLLAPSED minBottomContentHeightPx -> ExpandableBottomSheetLayoutState.Position.COLLAPSED
else -> ExpandableBottomSheetLayoutState.Position.DRAGGING else -> ExpandableBottomSheetLayoutState.Position.DRAGGING
} }
state.internalDraggingPercentage = calculatePercentage(
currentPos = newHeight,
minPos = minBottomContentHeightPx,
maxPos = calculatedMaxBottomContentHeightPx,
)
currentBottomContentHeightPx = newHeight currentBottomContentHeightPx = newHeight
}, },
onDragEnd = { onDragEnd = {

View file

@ -11,7 +11,6 @@ package io.element.android.libraries.designsystem.components
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable import androidx.compose.runtime.Stable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
@ -32,21 +31,12 @@ fun rememberExpandableBottomSheetLayoutState(): ExpandableBottomSheetLayoutState
@Stable @Stable
class ExpandableBottomSheetLayoutState { class ExpandableBottomSheetLayoutState {
internal var internalPosition: Position by mutableStateOf(Position.COLLAPSED) internal var internalPosition: Position by mutableStateOf(Position.COLLAPSED)
internal var internalDraggingPercentage: Float by mutableFloatStateOf(
if (internalPosition == Position.EXPANDED) 1f else 0f
)
/** /**
* The current position of the bottom sheet layout. * The current position of the bottom sheet layout.
*/ */
val position get() = internalPosition val position get() = internalPosition
/**
* The percentage of the bottom sheet layout that is currently being dragged.
* This value ranges from `0f` for [Position.COLLAPSED] to `1f` for [Position.EXPANDED].
*/
val draggingPercentage = internalDraggingPercentage
/** /**
* The position of the bottom sheet layout. * The position of the bottom sheet layout.
*/ */