Add focused location tracking when opening the map

This commit is contained in:
ganfra 2026-04-10 21:11:30 +02:00
parent 0e9af5f42a
commit 537063d899
6 changed files with 28 additions and 16 deletions

View file

@ -24,5 +24,7 @@ sealed interface ShowLocationMode : Parcelable {
) : ShowLocationMode
@Parcelize
data object Live : ShowLocationMode
data class Live(
val senderId: UserId
) : ShowLocationMode
}

View file

@ -131,8 +131,8 @@ class ShowLocationPresenter(
)
}
}
ShowLocationMode.Live -> {
val liveShares by produceState(persistentListOf()) {
is ShowLocationMode.Live -> {
produceState(persistentListOf()) {
val liveLocationSharesFlow = joinedRoom.subscribeToLiveLocationShares()
val membersStateFlow = joinedRoom.membersStateFlow.mapState { it.joinedRoomMembers() }
combine(liveLocationSharesFlow, membersStateFlow) { liveShares, members ->
@ -158,14 +158,19 @@ class ShowLocationPresenter(
)
}.toPersistentList()
}.collect { value = it }
}
liveShares
}.value
}
}
val focusedLocation = when (mode) {
is ShowLocationMode.Static -> locationShares.firstOrNull()
is ShowLocationMode.Live -> locationShares.firstOrNull { it.userId == mode.senderId }
}
return ShowLocationState(
dialogState = dialogState,
locationShares = locationShares,
focusedLocation = focusedLocation,
hasLocationPermission = permissionsState.isAnyGranted,
isTrackMyLocation = isTrackMyLocation,
isLive = mode is ShowLocationMode.Live,

View file

@ -9,7 +9,6 @@
package io.element.android.features.location.impl.show
import io.element.android.features.location.api.Location
import io.element.android.features.location.api.ShowLocationMode
import io.element.android.features.location.impl.common.ui.LocationConstraintsDialogState
import io.element.android.features.location.impl.common.ui.LocationMarkerData
import io.element.android.libraries.designsystem.components.PinVariant
@ -22,6 +21,7 @@ data class ShowLocationState(
val isLive: Boolean,
val dialogState: LocationConstraintsDialogState,
val locationShares: ImmutableList<LocationShareItem>,
val focusedLocation: LocationShareItem?,
val hasLocationPermission: Boolean,
val isTrackMyLocation: Boolean,
val appName: String,

View file

@ -50,6 +50,7 @@ fun aShowLocationState(
isLive: Boolean = false,
constraintsDialogState: LocationConstraintsDialogState = LocationConstraintsDialogState.None,
locationShares: List<LocationShareItem> = listOf(aLocationShareItem(isLive = isLive)),
focusedLocation: LocationShareItem? = locationShares.firstOrNull(),
hasLocationPermission: Boolean = false,
isTrackMyLocation: Boolean = false,
appName: String = APP_NAME,
@ -58,6 +59,7 @@ fun aShowLocationState(
return ShowLocationState(
dialogState = constraintsDialogState,
locationShares = locationShares.toImmutableList(),
focusedLocation = focusedLocation,
hasLocationPermission = hasLocationPermission,
isTrackMyLocation = isTrackMyLocation,
appName = appName,

View file

@ -22,8 +22,11 @@ import androidx.compose.material3.rememberBottomSheetScaffoldState
import androidx.compose.material3.rememberStandardBottomSheetState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
@ -67,25 +70,25 @@ fun ShowLocationView(
onDismiss = { state.eventSink(ShowLocationEvent.DismissDialog) },
)
val initialPosition = remember {
if (state.locationShares.isEmpty()) {
MapDefaults.defaultCameraPosition
} else {
val firstLocation = state.locationShares.first().location
CameraPosition(
target = Position(latitude = firstLocation.lat, longitude = firstLocation.lon),
val cameraState = rememberCameraState(firstPosition = MapDefaults.defaultCameraPosition)
var hasAnimatedToFocusedLocation by remember { mutableStateOf(false) }
LaunchedEffect(state.focusedLocation) {
if (state.focusedLocation != null && !hasAnimatedToFocusedLocation) {
hasAnimatedToFocusedLocation = true
val position = CameraPosition(
target = Position(latitude = state.focusedLocation.location.lat, longitude = state.focusedLocation.location.lon),
zoom = MapDefaults.DEFAULT_ZOOM
)
cameraState.position = position
}
}
val cameraState = rememberCameraState(firstPosition = initialPosition)
val userLocationState = rememberUserLocationState(state.hasLocationPermission)
LaunchedEffect(cameraState.isCameraMoving) {
if (cameraState.moveReason == CameraMoveReason.GESTURE) {
state.eventSink(ShowLocationEvent.TrackMyLocation(false))
}
}
val userLocationState = rememberUserLocationState(state.hasLocationPermission)
val scaffoldState = rememberBottomSheetScaffoldState(
bottomSheetState = rememberStandardBottomSheetState(
initialValue =

View file

@ -571,7 +571,7 @@ class MessagesFlowNode(
}
is TimelineItemLocationContent -> {
val mode = when(event.content.mode){
is TimelineItemLocationContent.Mode.Live -> ShowLocationMode.Live
is TimelineItemLocationContent.Mode.Live -> ShowLocationMode.Live(event.senderId)
is TimelineItemLocationContent.Mode.Static -> ShowLocationMode.Static(
location = event.content.mode.location,
senderName = event.safeSenderName,