Fix not being able to decline an invite from the room list (#3466)
* Add `InvitedRoom` to wrap Rust SDK Rooms in 'invited' membership state. At the moment, this is a wrapper that allows us to call `Room.leave()` without having to initialise the room's timeline (which is impossible). * Add `MatrixRoom.getInvitedRoom(roomId)` to get one of these rooms. Also, `RustRoomFactory` now has a `createInvitedRoom` method for this. * Adapt `AcceptDeclineInvitePresenter` to use the new APIs.
This commit is contained in:
parent
764692b90b
commit
7238af7f7f
9 changed files with 122 additions and 15 deletions
|
|
@ -112,8 +112,8 @@ class AcceptDeclineInvitePresenter @Inject constructor(
|
|||
|
||||
private fun CoroutineScope.declineInvite(roomId: RoomId, declinedAction: MutableState<AsyncAction<RoomId>>) = launch {
|
||||
suspend {
|
||||
client.getRoom(roomId)?.use {
|
||||
it.leave().getOrThrow()
|
||||
client.getInvitedRoom(roomId)?.use {
|
||||
it.declineInvite().getOrThrow()
|
||||
notificationCleaner.clearMembershipNotificationForRoom(client.sessionId, roomId)
|
||||
}
|
||||
roomId
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import io.element.android.libraries.matrix.test.A_ROOM_ID
|
|||
import io.element.android.libraries.matrix.test.A_ROOM_NAME
|
||||
import io.element.android.libraries.matrix.test.A_SESSION_ID
|
||||
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
||||
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
|
||||
import io.element.android.libraries.matrix.test.room.FakeInvitedRoom
|
||||
import io.element.android.libraries.matrix.test.room.join.FakeJoinRoom
|
||||
import io.element.android.libraries.push.api.notifications.NotificationCleaner
|
||||
import io.element.android.libraries.push.test.notifications.FakeNotificationCleaner
|
||||
|
|
@ -83,12 +83,7 @@ class AcceptDeclineInvitePresenterTest {
|
|||
Result.failure<Unit>(RuntimeException("Failed to leave room"))
|
||||
}
|
||||
val client = FakeMatrixClient().apply {
|
||||
givenGetRoomResult(
|
||||
roomId = A_ROOM_ID,
|
||||
result = FakeMatrixRoom(
|
||||
leaveRoomLambda = declineInviteFailure
|
||||
)
|
||||
)
|
||||
getInvitedRoomResults[A_ROOM_ID] = FakeInvitedRoom(declineInviteResult = declineInviteFailure)
|
||||
}
|
||||
val presenter = createAcceptDeclineInvitePresenter(client = client)
|
||||
presenter.test {
|
||||
|
|
@ -133,12 +128,7 @@ class AcceptDeclineInvitePresenterTest {
|
|||
Result.success(Unit)
|
||||
}
|
||||
val client = FakeMatrixClient().apply {
|
||||
givenGetRoomResult(
|
||||
roomId = A_ROOM_ID,
|
||||
result = FakeMatrixRoom(
|
||||
leaveRoomLambda = declineInviteSuccess
|
||||
)
|
||||
)
|
||||
getInvitedRoomResults[A_ROOM_ID] = FakeInvitedRoom(declineInviteResult = declineInviteSuccess)
|
||||
}
|
||||
val presenter = createAcceptDeclineInvitePresenter(
|
||||
client = client,
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import io.element.android.libraries.matrix.api.notification.NotificationService
|
|||
import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService
|
||||
import io.element.android.libraries.matrix.api.oidc.AccountManagementAction
|
||||
import io.element.android.libraries.matrix.api.pusher.PushersService
|
||||
import io.element.android.libraries.matrix.api.room.InvitedRoom
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoomInfo
|
||||
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
|
||||
|
|
@ -49,6 +50,7 @@ interface MatrixClient : Closeable {
|
|||
val sessionCoroutineScope: CoroutineScope
|
||||
val ignoredUsersFlow: StateFlow<ImmutableList<UserId>>
|
||||
suspend fun getRoom(roomId: RoomId): MatrixRoom?
|
||||
suspend fun getInvitedRoom(roomId: RoomId): InvitedRoom?
|
||||
suspend fun findDM(userId: UserId): RoomId?
|
||||
suspend fun ignoreUser(userId: UserId): Result<Unit>
|
||||
suspend fun unignoreUser(userId: UserId): Result<Unit>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* Copyright 2024 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Please see LICENSE in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.api.room
|
||||
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
|
||||
/** A reference to a room the current user has been invited to, with the ability to decline the invite. */
|
||||
interface InvitedRoom : AutoCloseable {
|
||||
val sessionId: SessionId
|
||||
val roomId: RoomId
|
||||
|
||||
/** Decline the invite to this room. */
|
||||
suspend fun declineInvite(): Result<Unit>
|
||||
}
|
||||
|
|
@ -29,6 +29,7 @@ import io.element.android.libraries.matrix.api.notificationsettings.Notification
|
|||
import io.element.android.libraries.matrix.api.oidc.AccountManagementAction
|
||||
import io.element.android.libraries.matrix.api.pusher.PushersService
|
||||
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
|
||||
import io.element.android.libraries.matrix.api.room.InvitedRoom
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoomInfo
|
||||
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
|
||||
|
|
@ -245,6 +246,10 @@ class RustMatrixClient(
|
|||
return roomFactory.create(roomId)
|
||||
}
|
||||
|
||||
override suspend fun getInvitedRoom(roomId: RoomId): InvitedRoom? {
|
||||
return roomFactory.createInvitedRoom(roomId)
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for the room to be available in the room list, with a membership for the current user of [CurrentUserMembership.JOINED].
|
||||
* @param roomIdOrAlias the room id or alias to wait for
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright 2024 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Please see LICENSE in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.impl.room
|
||||
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
import io.element.android.libraries.matrix.api.room.InvitedRoom
|
||||
import org.matrix.rustcomponents.sdk.Room
|
||||
|
||||
class RustInvitedRoom(
|
||||
override val sessionId: SessionId,
|
||||
private val invitedRoom: Room,
|
||||
) : InvitedRoom {
|
||||
override val roomId = RoomId(invitedRoom.id())
|
||||
|
||||
override suspend fun declineInvite(): Result<Unit> = runCatching {
|
||||
invitedRoom.leave()
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
invitedRoom.destroy()
|
||||
}
|
||||
}
|
||||
|
|
@ -14,6 +14,7 @@ import io.element.android.libraries.matrix.api.core.DeviceId
|
|||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService
|
||||
import io.element.android.libraries.matrix.api.room.InvitedRoom
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.roomlist.RoomListService
|
||||
import io.element.android.libraries.matrix.api.roomlist.awaitLoaded
|
||||
|
|
@ -27,6 +28,7 @@ import kotlinx.coroutines.sync.Mutex
|
|||
import kotlinx.coroutines.sync.withLock
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.matrix.rustcomponents.sdk.FilterTimelineEventType
|
||||
import org.matrix.rustcomponents.sdk.Membership
|
||||
import org.matrix.rustcomponents.sdk.Room
|
||||
import org.matrix.rustcomponents.sdk.RoomListException
|
||||
import org.matrix.rustcomponents.sdk.RoomListItem
|
||||
|
|
@ -123,6 +125,33 @@ class RustRoomFactory(
|
|||
}
|
||||
}
|
||||
|
||||
suspend fun createInvitedRoom(roomId: RoomId): InvitedRoom? = withContext(dispatcher) {
|
||||
if (isDestroyed) {
|
||||
Timber.d("Room factory is destroyed, returning null for $roomId")
|
||||
return@withContext null
|
||||
}
|
||||
val roomListItem = innerRoomListService.roomOrNull(roomId.value)
|
||||
if (roomListItem == null) {
|
||||
Timber.d("Room not found for $roomId")
|
||||
return@withContext null
|
||||
}
|
||||
if (roomListItem.membership() != Membership.INVITED) {
|
||||
Timber.d("Room $roomId is not in invited state")
|
||||
return@withContext null
|
||||
}
|
||||
val invitedRoom = try {
|
||||
roomListItem.invitedRoom()
|
||||
} catch (e: RoomListException) {
|
||||
Timber.e(e, "Failed to get invited room for $roomId")
|
||||
return@withContext null
|
||||
}
|
||||
|
||||
RustInvitedRoom(
|
||||
sessionId = sessionId,
|
||||
invitedRoom = invitedRoom,
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun getRoomReferences(roomId: RoomId): RustRoomReferences? {
|
||||
cache[roomId]?.let {
|
||||
Timber.d("Room found in cache for $roomId")
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import io.element.android.libraries.matrix.api.notification.NotificationService
|
|||
import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService
|
||||
import io.element.android.libraries.matrix.api.oidc.AccountManagementAction
|
||||
import io.element.android.libraries.matrix.api.pusher.PushersService
|
||||
import io.element.android.libraries.matrix.api.room.InvitedRoom
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoomInfo
|
||||
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
|
||||
|
|
@ -99,6 +100,7 @@ class FakeMatrixClient(
|
|||
private var createDmResult: Result<RoomId> = Result.success(A_ROOM_ID)
|
||||
private var findDmResult: RoomId? = A_ROOM_ID
|
||||
private val getRoomResults = mutableMapOf<RoomId, MatrixRoom>()
|
||||
val getInvitedRoomResults = mutableMapOf<RoomId, InvitedRoom>()
|
||||
private val searchUserResults = mutableMapOf<String, Result<MatrixSearchUserResults>>()
|
||||
private val getProfileResults = mutableMapOf<UserId, Result<MatrixUser>>()
|
||||
private var uploadMediaResult: Result<String> = Result.success(AN_AVATAR_URL)
|
||||
|
|
@ -125,6 +127,10 @@ class FakeMatrixClient(
|
|||
return getRoomResults[roomId]
|
||||
}
|
||||
|
||||
override suspend fun getInvitedRoom(roomId: RoomId): InvitedRoom? {
|
||||
return getInvitedRoomResults[roomId]
|
||||
}
|
||||
|
||||
override suspend fun findDM(userId: UserId): RoomId? {
|
||||
return findDmResult
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright 2024 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* Please see LICENSE in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.test.room
|
||||
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
import io.element.android.libraries.matrix.api.room.InvitedRoom
|
||||
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
||||
import io.element.android.libraries.matrix.test.A_SESSION_ID
|
||||
import io.element.android.tests.testutils.lambda.lambdaError
|
||||
|
||||
class FakeInvitedRoom(
|
||||
override val sessionId: SessionId = A_SESSION_ID,
|
||||
override val roomId: RoomId = A_ROOM_ID,
|
||||
private val declineInviteResult: () -> Result<Unit> = { lambdaError() }
|
||||
) : InvitedRoom {
|
||||
override suspend fun declineInvite(): Result<Unit> {
|
||||
return declineInviteResult()
|
||||
}
|
||||
|
||||
override fun close() = Unit
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue