Merge pull request #6342 from element-hq/feature/fga/live_location_sharing_setup

Setup live location sharing feature
This commit is contained in:
ganfra 2026-03-24 15:46:45 +01:00 committed by GitHub
commit 92920b862b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
197 changed files with 3767 additions and 2803 deletions

View file

@ -30,6 +30,7 @@ import io.element.android.libraries.matrix.api.room.SendQueueUpdate
import io.element.android.libraries.matrix.api.room.history.RoomHistoryVisibility
import io.element.android.libraries.matrix.api.room.join.JoinRule
import io.element.android.libraries.matrix.api.room.knock.KnockRequest
import io.element.android.libraries.matrix.api.room.location.LiveLocationShare
import io.element.android.libraries.matrix.api.room.powerlevels.RoomPowerLevelsValues
import io.element.android.libraries.matrix.api.room.powerlevels.UserRoleChange
import io.element.android.libraries.matrix.api.room.roomNotificationSettings
@ -42,6 +43,7 @@ import io.element.android.libraries.matrix.impl.mapper.map
import io.element.android.libraries.matrix.impl.room.history.map
import io.element.android.libraries.matrix.impl.room.join.map
import io.element.android.libraries.matrix.impl.room.knock.RustKnockRequest
import io.element.android.libraries.matrix.impl.room.location.map
import io.element.android.libraries.matrix.impl.room.member.RoomMemberListFetcher
import io.element.android.libraries.matrix.impl.roomdirectory.map
import io.element.android.libraries.matrix.impl.timeline.RustTimeline
@ -66,6 +68,7 @@ import kotlinx.coroutines.withContext
import org.matrix.rustcomponents.sdk.DateDividerMode
import org.matrix.rustcomponents.sdk.IdentityStatusChangeListener
import org.matrix.rustcomponents.sdk.KnockRequestsListener
import org.matrix.rustcomponents.sdk.LiveLocationShareListener
import org.matrix.rustcomponents.sdk.RoomMessageEventMessageType
import org.matrix.rustcomponents.sdk.RoomSendQueueUpdate
import org.matrix.rustcomponents.sdk.SendQueueListener
@ -500,6 +503,34 @@ class JoinedRustRoom(
}
}
override fun subscribeToLiveLocationShares(): Flow<List<LiveLocationShare>> {
return mxCallbackFlow {
innerRoom.subscribeToLiveLocationShares(object : LiveLocationShareListener {
override fun call(liveLocationShares: List<org.matrix.rustcomponents.sdk.LiveLocationShare>) {
trySend(liveLocationShares.map { it.map() })
}
})
}
}
override suspend fun startLiveLocationShare(durationMillis: Long): Result<Unit> = withContext(roomDispatcher) {
runCatchingExceptions {
innerRoom.startLiveLocationShare(durationMillis.toULong())
}
}
override suspend fun stopLiveLocationShare(): Result<Unit> = withContext(roomDispatcher) {
runCatchingExceptions {
innerRoom.stopLiveLocationShare()
}
}
override suspend fun sendLiveLocation(geoUri: String): Result<Unit> = withContext(roomDispatcher) {
runCatchingExceptions {
innerRoom.sendLiveLocation(geoUri)
}
}
override fun close() = destroy()
override fun destroy() {

View file

@ -9,8 +9,16 @@
package io.element.android.libraries.matrix.impl.room.location
import io.element.android.libraries.matrix.api.room.location.AssetType
import org.matrix.rustcomponents.sdk.AssetType as RustAssetType
fun AssetType.toInner(): org.matrix.rustcomponents.sdk.AssetType = when (this) {
AssetType.SENDER -> org.matrix.rustcomponents.sdk.AssetType.SENDER
AssetType.PIN -> org.matrix.rustcomponents.sdk.AssetType.PIN
fun AssetType.into(): RustAssetType = when (this) {
AssetType.SENDER -> RustAssetType.SENDER
AssetType.PIN -> RustAssetType.PIN
AssetType.UNKNOWN -> RustAssetType.UNKNOWN
}
fun RustAssetType.into(): AssetType = when (this) {
RustAssetType.SENDER -> AssetType.SENDER
RustAssetType.PIN -> AssetType.PIN
RustAssetType.UNKNOWN -> AssetType.UNKNOWN
}

View file

@ -0,0 +1,21 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.libraries.matrix.impl.room.location
import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.room.location.LiveLocationShare
import org.matrix.rustcomponents.sdk.LiveLocationShare as RustLiveLocationShare
fun RustLiveLocationShare.map(): LiveLocationShare {
return LiveLocationShare(
userId = UserId(userId),
lastGeoUri = lastLocation.location.geoUri,
lastTimestamp = lastLocation.ts.toLong(),
isLive = isLive,
)
}

View file

@ -32,7 +32,7 @@ import io.element.android.libraries.matrix.impl.media.MediaUploadHandlerImpl
import io.element.android.libraries.matrix.impl.media.map
import io.element.android.libraries.matrix.impl.poll.toInner
import io.element.android.libraries.matrix.impl.room.RoomContentForwarder
import io.element.android.libraries.matrix.impl.room.location.toInner
import io.element.android.libraries.matrix.impl.room.location.into
import io.element.android.libraries.matrix.impl.timeline.item.event.EventTimelineItemMapper
import io.element.android.libraries.matrix.impl.timeline.item.event.TimelineEventContentMapper
import io.element.android.libraries.matrix.impl.timeline.item.virtual.VirtualTimelineItemMapper
@ -478,7 +478,7 @@ class RustTimeline(
geoUri = geoUri,
description = description,
zoomLevel = zoomLevel?.toUByte(),
assetType = assetType?.toInner(),
assetType = assetType?.into(),
repliedToEventId = inReplyToEventId?.value,
)
}

View file

@ -24,6 +24,7 @@ import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageTy
import io.element.android.libraries.matrix.api.timeline.item.event.VideoMessageType
import io.element.android.libraries.matrix.api.timeline.item.event.VoiceMessageType
import io.element.android.libraries.matrix.impl.media.map
import io.element.android.libraries.matrix.impl.room.location.into
import io.element.android.libraries.matrix.impl.timeline.reply.InReplyToMapper
import org.matrix.rustcomponents.sdk.InReplyToDetails
import org.matrix.rustcomponents.sdk.MessageType
@ -112,7 +113,12 @@ class EventMessageMapper {
)
}
is RustMessageType.Location -> {
LocationMessageType(type.content.body, type.content.geoUri, type.content.description)
LocationMessageType(
body = type.content.body,
geoUri = type.content.geoUri,
description = type.content.description,
assetType = type.content.asset.into()
)
}
is MessageType.Other -> {
OtherMessageType(type.msgtype, type.body)

View file

@ -15,7 +15,7 @@ import org.junit.Test
class AssetTypeKtTest {
@Test
fun toInner() {
assertThat(AssetType.SENDER.toInner()).isEqualTo(org.matrix.rustcomponents.sdk.AssetType.SENDER)
assertThat(AssetType.PIN.toInner()).isEqualTo(org.matrix.rustcomponents.sdk.AssetType.PIN)
assertThat(AssetType.SENDER.into()).isEqualTo(org.matrix.rustcomponents.sdk.AssetType.SENDER)
assertThat(AssetType.PIN.into()).isEqualTo(org.matrix.rustcomponents.sdk.AssetType.PIN)
}
}