Expose liveLocationSharing methods from sdk

This commit is contained in:
ganfra
2026-02-18 14:59:49 +01:00
parent 18e5b47106
commit 5b68664350
5 changed files with 124 additions and 0 deletions

View File

@@ -17,6 +17,7 @@ import io.element.android.libraries.matrix.api.encryption.identity.IdentityState
import io.element.android.libraries.matrix.api.room.history.RoomHistoryVisibility 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.join.JoinRule
import io.element.android.libraries.matrix.api.room.knock.KnockRequest 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.RoomPowerLevelsValues
import io.element.android.libraries.matrix.api.room.powerlevels.UserRoleChange import io.element.android.libraries.matrix.api.room.powerlevels.UserRoleChange
import io.element.android.libraries.matrix.api.roomdirectory.RoomVisibility import io.element.android.libraries.matrix.api.roomdirectory.RoomVisibility
@@ -182,4 +183,30 @@ interface JoinedRoom : BaseRoom {
* Subscribe to a [Flow] of [SendQueueUpdate] related to this room. * Subscribe to a [Flow] of [SendQueueUpdate] related to this room.
*/ */
fun subscribeToSendQueueUpdates(): Flow<SendQueueUpdate> fun subscribeToSendQueueUpdates(): Flow<SendQueueUpdate>
/**
* Subscribe to live location shares in this room.
* @return Flow of list of active live location shares.
*/
fun subscribeToLiveLocationShares(): Flow<List<LiveLocationShare>>
/**
* Start sharing live location in this room.
* @param durationMillis How long to share location (in milliseconds).
* @return Result indicating success or failure.
*/
suspend fun startLiveLocationShare(durationMillis: Long): Result<Unit>
/**
* Stop sharing live location in this room.
* @return Result indicating success or failure.
*/
suspend fun stopLiveLocationShare(): Result<Unit>
/**
* Send a live location update while a live location share is active.
* @param geoUri The geo URI (e.g., "geo:51.5074,-0.1278").
* @return Result indicating success or failure.
*/
suspend fun sendLiveLocation(geoUri: String): Result<Unit>
} }

View File

@@ -0,0 +1,24 @@
/*
* 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.api.room.location
import io.element.android.libraries.matrix.api.core.UserId
/**
* Represents a live location share from a user in a room.
*/
data class LiveLocationShare(
/** The user who is sharing their location. */
val userId: UserId,
/** The last known geo URI (e.g., "geo:51.5074,-0.1278"). */
val lastGeoUri: String,
/** The timestamp of the last location update. */
val lastTimestamp: Long,
/** Whether the live location share is still active. */
val isLive: Boolean,
)

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.history.RoomHistoryVisibility
import io.element.android.libraries.matrix.api.room.join.JoinRule 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.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.RoomPowerLevelsValues
import io.element.android.libraries.matrix.api.room.powerlevels.UserRoleChange import io.element.android.libraries.matrix.api.room.powerlevels.UserRoleChange
import io.element.android.libraries.matrix.api.room.roomNotificationSettings 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.history.map
import io.element.android.libraries.matrix.impl.room.join.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.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.room.member.RoomMemberListFetcher
import io.element.android.libraries.matrix.impl.roomdirectory.map import io.element.android.libraries.matrix.impl.roomdirectory.map
import io.element.android.libraries.matrix.impl.timeline.RustTimeline 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.DateDividerMode
import org.matrix.rustcomponents.sdk.IdentityStatusChangeListener import org.matrix.rustcomponents.sdk.IdentityStatusChangeListener
import org.matrix.rustcomponents.sdk.KnockRequestsListener import org.matrix.rustcomponents.sdk.KnockRequestsListener
import org.matrix.rustcomponents.sdk.LiveLocationShareListener
import org.matrix.rustcomponents.sdk.RoomMessageEventMessageType import org.matrix.rustcomponents.sdk.RoomMessageEventMessageType
import org.matrix.rustcomponents.sdk.RoomSendQueueUpdate import org.matrix.rustcomponents.sdk.RoomSendQueueUpdate
import org.matrix.rustcomponents.sdk.SendQueueListener 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 close() = destroy()
override fun destroy() { override fun destroy() {

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

@@ -27,6 +27,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.history.RoomHistoryVisibility
import io.element.android.libraries.matrix.api.room.join.JoinRule 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.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.RoomPowerLevelsValues
import io.element.android.libraries.matrix.api.room.powerlevels.UserRoleChange import io.element.android.libraries.matrix.api.room.powerlevels.UserRoleChange
import io.element.android.libraries.matrix.api.roomdirectory.RoomVisibility import io.element.android.libraries.matrix.api.roomdirectory.RoomVisibility
@@ -84,6 +85,10 @@ class FakeJoinedRoom(
private val enableEncryptionResult: () -> Result<Unit> = { lambdaError() }, private val enableEncryptionResult: () -> Result<Unit> = { lambdaError() },
private val updateJoinRuleResult: (JoinRule) -> Result<Unit> = { lambdaError() }, private val updateJoinRuleResult: (JoinRule) -> Result<Unit> = { lambdaError() },
private val setSendQueueEnabledResult: (Boolean) -> Unit = { _: Boolean -> }, private val setSendQueueEnabledResult: (Boolean) -> Unit = { _: Boolean -> },
private val liveLocationSharesFlow: Flow<List<LiveLocationShare>> = MutableStateFlow(emptyList()),
private val startLiveLocationShareResult: (Long) -> Result<Unit> = { lambdaError() },
private val stopLiveLocationShareResult: () -> Result<Unit> = { lambdaError() },
private val sendLiveLocationResult: (String) -> Result<Unit> = { lambdaError() },
) : JoinedRoom, BaseRoom by baseRoom { ) : JoinedRoom, BaseRoom by baseRoom {
private val sendQueueUpdates = MutableSharedFlow<SendQueueUpdate>(extraBufferCapacity = 10) private val sendQueueUpdates = MutableSharedFlow<SendQueueUpdate>(extraBufferCapacity = 10)
@@ -227,6 +232,22 @@ class FakeJoinedRoom(
return sendQueueUpdates return sendQueueUpdates
} }
override fun subscribeToLiveLocationShares(): Flow<List<LiveLocationShare>> {
return liveLocationSharesFlow
}
override suspend fun startLiveLocationShare(durationMillis: Long): Result<Unit> = simulateLongTask {
startLiveLocationShareResult(durationMillis)
}
override suspend fun stopLiveLocationShare(): Result<Unit> = simulateLongTask {
stopLiveLocationShareResult()
}
override suspend fun sendLiveLocation(geoUri: String): Result<Unit> = simulateLongTask {
sendLiveLocationResult(geoUri)
}
private suspend fun simulateSendMediaProgress(progressCallback: ProgressCallback?) { private suspend fun simulateSendMediaProgress(progressCallback: ProgressCallback?) {
progressCallbackValues.forEach { (current, total) -> progressCallbackValues.forEach { (current, total) ->
progressCallback?.onProgress(current, total) progressCallback?.onProgress(current, total)