Improve live location bottomsheet interaction with map

This commit is contained in:
ganfra 2026-04-15 13:46:31 +02:00
parent e85b532d6a
commit f5683f9c8b
2 changed files with 37 additions and 28 deletions

View file

@ -10,12 +10,14 @@ package io.element.android.features.location.impl.common.ui
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope import androidx.compose.foundation.layout.BoxScope
import androidx.compose.foundation.layout.BoxWithConstraints import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.WindowInsetsSides import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.navigationBars import androidx.compose.foundation.layout.navigationBars
import androidx.compose.foundation.layout.only import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.safeDrawing import androidx.compose.foundation.layout.safeDrawing
@ -43,6 +45,7 @@ import androidx.compose.ui.unit.max
import io.element.android.features.location.api.internal.rememberTileStyleUrl import io.element.android.features.location.api.internal.rememberTileStyleUrl
import io.element.android.features.location.impl.common.MapDefaults import io.element.android.features.location.impl.common.MapDefaults
import io.element.android.libraries.core.data.tryOrNull import io.element.android.libraries.core.data.tryOrNull
import io.element.android.libraries.designsystem.text.toDp
import io.element.android.libraries.designsystem.theme.components.BottomSheetScaffold import io.element.android.libraries.designsystem.theme.components.BottomSheetScaffold
import org.maplibre.compose.camera.CameraState import org.maplibre.compose.camera.CameraState
import org.maplibre.compose.camera.rememberCameraState import org.maplibre.compose.camera.rememberCameraState
@ -112,8 +115,11 @@ fun MapBottomSheetScaffold(
modifier = Modifier, modifier = Modifier,
sheetPeekHeight = sheetPeekHeight, sheetPeekHeight = sheetPeekHeight,
sheetContent = { sheetContent = {
sheetContent(sheetPadding) val maxContentHeight = (layoutHeightPx * 0.5f).roundToInt().toDp()
Spacer(modifier = Modifier.windowInsetsBottomHeight(WindowInsets.navigationBars)) Column(modifier = Modifier.heightIn(max = maxContentHeight)) {
sheetContent(sheetPadding)
Spacer(modifier = Modifier.windowInsetsBottomHeight(WindowInsets.navigationBars))
}
}, },
scaffoldState = scaffoldState, scaffoldState = scaffoldState,
sheetDragHandle = sheetDragHandle, sheetDragHandle = sheetDragHandle,

View file

@ -15,6 +15,8 @@ import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.BottomSheetDefaults import androidx.compose.material3.BottomSheetDefaults
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.SheetValue import androidx.compose.material3.SheetValue
@ -90,15 +92,13 @@ fun ShowLocationView(
val userLocationState = rememberUserLocationState(state.hasLocationPermission) val userLocationState = rememberUserLocationState(state.hasLocationPermission)
val scaffoldState = rememberBottomSheetScaffoldState( val scaffoldState = rememberBottomSheetScaffoldState(
bottomSheetState = rememberStandardBottomSheetState( bottomSheetState = rememberStandardBottomSheetState(SheetValue.Expanded)
initialValue =
if (state.isSheetDraggable) {
SheetValue.Expanded
} else {
SheetValue.Expanded
}
)
) )
LaunchedEffect(state.isSheetDraggable) {
if (!state.isSheetDraggable) {
scaffoldState.bottomSheetState.expand()
}
}
MapBottomSheetScaffold( MapBottomSheetScaffold(
sheetDragHandle = if (state.isSheetDraggable) { sheetDragHandle = if (state.isSheetDraggable) {
{ BottomSheetDefaults.DragHandle() } { BottomSheetDefaults.DragHandle() }
@ -122,18 +122,19 @@ fun ShowLocationView(
sheetContent = { sheetPaddings -> sheetContent = { sheetPaddings ->
val coroutineScope = rememberCoroutineScope() val coroutineScope = rememberCoroutineScope()
if (!state.isSheetDraggable) { if (!state.isSheetDraggable) {
// If sheet is draggable the DragHandle has already some padding
Spacer(Modifier.height(20.dp)) Spacer(Modifier.height(20.dp))
} }
if (state.locationShares.isEmpty()) { if (state.locationShares.isEmpty()) {
Spacer(Modifier.height(16.dp))
Text( Text(
text = "Nobody is sharing their location", text = "Nobody is sharing their location",
style = ElementTheme.typography.fontBodyLgMedium, style = ElementTheme.typography.fontBodyLgMedium,
color = ElementTheme.colors.textPrimary, color = ElementTheme.colors.textPrimary,
modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp), modifier = Modifier
.fillMaxWidth()
.padding(all = 16.dp),
textAlign = TextAlign.Center, textAlign = TextAlign.Center,
) )
Spacer(Modifier.height(16.dp))
} else { } else {
Text( Text(
text = stringResource(CommonStrings.screen_static_location_sheet_title), text = stringResource(CommonStrings.screen_static_location_sheet_title),
@ -141,22 +142,24 @@ fun ShowLocationView(
color = ElementTheme.colors.textPrimary, color = ElementTheme.colors.textPrimary,
modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp), modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp),
) )
state.locationShares.forEach { locationShare -> LazyColumn {
LocationShareRow( items(state.locationShares) { locationShare ->
item = locationShare, LocationShareRow(
onShareClick = { state.eventSink(ShowLocationEvent.Share(locationShare.location)) }, item = locationShare,
modifier = Modifier.clickable { onShareClick = { state.eventSink(ShowLocationEvent.Share(locationShare.location)) },
state.eventSink(ShowLocationEvent.TrackMyLocation(false)) modifier = Modifier.clickable {
val position = CameraPosition( state.eventSink(ShowLocationEvent.TrackMyLocation(false))
padding = sheetPaddings, val position = CameraPosition(
target = Position(locationShare.location.lon, locationShare.location.lat), padding = sheetPaddings,
zoom = MapDefaults.DEFAULT_ZOOM target = Position(locationShare.location.lon, locationShare.location.lat),
) zoom = MapDefaults.DEFAULT_ZOOM
coroutineScope.launch { )
cameraState.animateTo(finalPosition = position) coroutineScope.launch {
cameraState.animateTo(finalPosition = position)
}
} }
} )
) }
} }
} }
}, },