knock : use PendingRoom instead of InvitedRoom

This commit is contained in:
ganfra 2024-10-18 20:58:19 +02:00
parent 12d26bb3b7
commit 1c72135148
9 changed files with 46 additions and 43 deletions

View file

@ -94,8 +94,8 @@ class AcceptDeclineInvitePresenter @Inject constructor(
private fun CoroutineScope.declineInvite(roomId: RoomId, declinedAction: MutableState<AsyncAction<RoomId>>) = launch { private fun CoroutineScope.declineInvite(roomId: RoomId, declinedAction: MutableState<AsyncAction<RoomId>>) = launch {
suspend { suspend {
client.getInvitedRoom(roomId)?.use { client.getPendingRoom(roomId)?.use {
it.declineInvite().getOrThrow() it.leave().getOrThrow()
notificationCleaner.clearMembershipNotificationForRoom(client.sessionId, roomId) notificationCleaner.clearMembershipNotificationForRoom(client.sessionId, roomId)
} }
roomId roomId

View file

@ -22,7 +22,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_ROOM_NAME
import io.element.android.libraries.matrix.test.A_SESSION_ID 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.FakeMatrixClient
import io.element.android.libraries.matrix.test.room.FakeInvitedRoom import io.element.android.libraries.matrix.test.room.FakePendingRoom
import io.element.android.libraries.matrix.test.room.join.FakeJoinRoom 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.api.notifications.NotificationCleaner
import io.element.android.libraries.push.test.notifications.FakeNotificationCleaner import io.element.android.libraries.push.test.notifications.FakeNotificationCleaner
@ -78,7 +78,7 @@ class AcceptDeclineInvitePresenterTest {
Result.failure<Unit>(RuntimeException("Failed to leave room")) Result.failure<Unit>(RuntimeException("Failed to leave room"))
} }
val client = FakeMatrixClient().apply { val client = FakeMatrixClient().apply {
getInvitedRoomResults[A_ROOM_ID] = FakeInvitedRoom(declineInviteResult = declineInviteFailure) getPendingRoomResults[A_ROOM_ID] = FakePendingRoom(declineInviteResult = declineInviteFailure)
} }
val presenter = createAcceptDeclineInvitePresenter(client = client) val presenter = createAcceptDeclineInvitePresenter(client = client)
presenter.test { presenter.test {
@ -121,7 +121,7 @@ class AcceptDeclineInvitePresenterTest {
Result.success(Unit) Result.success(Unit)
} }
val client = FakeMatrixClient().apply { val client = FakeMatrixClient().apply {
getInvitedRoomResults[A_ROOM_ID] = FakeInvitedRoom(declineInviteResult = declineInviteSuccess) getPendingRoomResults[A_ROOM_ID] = FakePendingRoom(declineInviteResult = declineInviteSuccess)
} }
val presenter = createAcceptDeclineInvitePresenter( val presenter = createAcceptDeclineInvitePresenter(
client = client, client = client,

View file

@ -21,7 +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.notificationsettings.NotificationSettingsService
import io.element.android.libraries.matrix.api.oidc.AccountManagementAction 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.pusher.PushersService
import io.element.android.libraries.matrix.api.room.InvitedRoom import io.element.android.libraries.matrix.api.room.PendingRoom
import io.element.android.libraries.matrix.api.room.MatrixRoom 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.MatrixRoomInfo
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
@ -52,7 +52,7 @@ interface MatrixClient : Closeable {
val sessionCoroutineScope: CoroutineScope val sessionCoroutineScope: CoroutineScope
val ignoredUsersFlow: StateFlow<ImmutableList<UserId>> val ignoredUsersFlow: StateFlow<ImmutableList<UserId>>
suspend fun getRoom(roomId: RoomId): MatrixRoom? suspend fun getRoom(roomId: RoomId): MatrixRoom?
suspend fun getInvitedRoom(roomId: RoomId): InvitedRoom? suspend fun getPendingRoom(roomId: RoomId): PendingRoom?
suspend fun findDM(userId: UserId): RoomId? suspend fun findDM(userId: UserId): RoomId?
suspend fun ignoreUser(userId: UserId): Result<Unit> suspend fun ignoreUser(userId: UserId): Result<Unit>
suspend fun unignoreUser(userId: UserId): Result<Unit> suspend fun unignoreUser(userId: UserId): Result<Unit>

View file

@ -10,11 +10,11 @@ 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.RoomId
import io.element.android.libraries.matrix.api.core.SessionId 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. */ /** A reference to a room the current user has knocked to or has been invited to, with the ability to leave the room. */
interface InvitedRoom : AutoCloseable { interface PendingRoom : AutoCloseable {
val sessionId: SessionId val sessionId: SessionId
val roomId: RoomId val roomId: RoomId
/** Decline the invite to this room. */ /** Leave the room ie.decline invite or cancel knock. */
suspend fun declineInvite(): Result<Unit> suspend fun leave(): Result<Unit>
} }

View file

@ -30,7 +30,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.oidc.AccountManagementAction
import io.element.android.libraries.matrix.api.pusher.PushersService 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.CurrentUserMembership
import io.element.android.libraries.matrix.api.room.InvitedRoom import io.element.android.libraries.matrix.api.room.PendingRoom
import io.element.android.libraries.matrix.api.room.MatrixRoom import io.element.android.libraries.matrix.api.room.MatrixRoom
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
import io.element.android.libraries.matrix.api.room.alias.ResolvedRoomAlias import io.element.android.libraries.matrix.api.room.alias.ResolvedRoomAlias
@ -251,19 +251,21 @@ class RustMatrixClient(
return roomFactory.create(roomId) return roomFactory.create(roomId)
} }
override suspend fun getInvitedRoom(roomId: RoomId): InvitedRoom? { override suspend fun getPendingRoom(roomId: RoomId): PendingRoom? {
return roomFactory.createInvitedRoom(roomId) return roomFactory.createPendingRoom(roomId)
} }
/** /**
* Wait for the room to be available in the room list, with a membership for the current user of [CurrentUserMembership.JOINED]. * Wait for the room to be available in the room list with the correct membership for the current user.
* @param roomIdOrAlias the room id or alias to wait for * @param roomIdOrAlias the room id or alias to wait for
* @param timeout the timeout to wait for the room to be available * @param timeout the timeout to wait for the room to be available
* @param currentUserMembership the membership to wait for
* @throws TimeoutCancellationException if the room is not available after the timeout * @throws TimeoutCancellationException if the room is not available after the timeout
*/ */
private suspend fun awaitJoinedRoom( private suspend fun awaitRoom(
roomIdOrAlias: RoomIdOrAlias, roomIdOrAlias: RoomIdOrAlias,
timeout: Duration timeout: Duration,
currentUserMembership: CurrentUserMembership,
): RoomSummary { ): RoomSummary {
return withTimeout(timeout) { return withTimeout(timeout) {
getRoomSummaryFlow(roomIdOrAlias) getRoomSummaryFlow(roomIdOrAlias)

View file

@ -9,20 +9,20 @@ 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.RoomId
import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.matrix.api.core.SessionId
import io.element.android.libraries.matrix.api.room.InvitedRoom import io.element.android.libraries.matrix.api.room.PendingRoom
import org.matrix.rustcomponents.sdk.Room import org.matrix.rustcomponents.sdk.Room
class RustInvitedRoom( class RustPendingRoom(
override val sessionId: SessionId, override val sessionId: SessionId,
private val invitedRoom: Room, private val inner: Room,
) : InvitedRoom { ) : PendingRoom {
override val roomId = RoomId(invitedRoom.id()) override val roomId = RoomId(inner.id())
override suspend fun declineInvite(): Result<Unit> = runCatching { override suspend fun leave(): Result<Unit> = runCatching {
invitedRoom.leave() inner.leave()
} }
override fun close() { override fun close() {
invitedRoom.destroy() inner.destroy()
} }
} }

View file

@ -14,8 +14,8 @@ 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.RoomId
import io.element.android.libraries.matrix.api.core.SessionId 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.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.room.MatrixRoom
import io.element.android.libraries.matrix.api.room.PendingRoom
import io.element.android.libraries.matrix.api.roomlist.RoomListService import io.element.android.libraries.matrix.api.roomlist.RoomListService
import io.element.android.libraries.matrix.api.roomlist.awaitLoaded import io.element.android.libraries.matrix.api.roomlist.awaitLoaded
import io.element.android.libraries.matrix.impl.roomlist.fullRoomWithTimeline import io.element.android.libraries.matrix.impl.roomlist.fullRoomWithTimeline
@ -35,6 +35,7 @@ import timber.log.Timber
import org.matrix.rustcomponents.sdk.RoomListService as InnerRoomListService import org.matrix.rustcomponents.sdk.RoomListService as InnerRoomListService
private const val CACHE_SIZE = 16 private const val CACHE_SIZE = 16
private val PENDING_MEMBERSHIPS = setOf(Membership.INVITED, Membership.KNOCKED)
class RustRoomFactory( class RustRoomFactory(
private val sessionId: SessionId, private val sessionId: SessionId,
@ -49,6 +50,7 @@ class RustRoomFactory(
private val roomSyncSubscriber: RoomSyncSubscriber, private val roomSyncSubscriber: RoomSyncSubscriber,
private val timelineEventTypeFilterFactory: TimelineEventTypeFilterFactory, private val timelineEventTypeFilterFactory: TimelineEventTypeFilterFactory,
) { ) {
@OptIn(ExperimentalCoroutinesApi::class) @OptIn(ExperimentalCoroutinesApi::class)
private val dispatcher = dispatchers.io.limitedParallelism(1) private val dispatcher = dispatchers.io.limitedParallelism(1)
private val mutex = Mutex() private val mutex = Mutex()
@ -120,7 +122,7 @@ class RustRoomFactory(
} }
} }
suspend fun createInvitedRoom(roomId: RoomId): InvitedRoom? = withContext(dispatcher) { suspend fun createPendingRoom(roomId: RoomId): PendingRoom? = withContext(dispatcher) {
if (isDestroyed) { if (isDestroyed) {
Timber.d("Room factory is destroyed, returning null for $roomId") Timber.d("Room factory is destroyed, returning null for $roomId")
return@withContext null return@withContext null
@ -130,20 +132,19 @@ class RustRoomFactory(
Timber.d("Room not found for $roomId") Timber.d("Room not found for $roomId")
return@withContext null return@withContext null
} }
if (roomListItem.membership() != Membership.INVITED) { if (roomListItem.membership() !in PENDING_MEMBERSHIPS) {
Timber.d("Room $roomId is not in invited state") Timber.d("Room $roomId is not in pending state")
return@withContext null return@withContext null
} }
val invitedRoom = try { val innerRoom = try {
roomListItem.invitedRoom() roomListItem.roomWithoutTimeline()
} catch (e: RoomListException) { } catch (e: RoomListException) {
Timber.e(e, "Failed to get invited room for $roomId") Timber.e(e, "Failed to get pending room for $roomId")
return@withContext null return@withContext null
} }
RustPendingRoom(
RustInvitedRoom(
sessionId = sessionId, sessionId = sessionId,
invitedRoom = invitedRoom, inner = innerRoom,
) )
} }

View file

@ -22,7 +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.notificationsettings.NotificationSettingsService
import io.element.android.libraries.matrix.api.oidc.AccountManagementAction 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.pusher.PushersService
import io.element.android.libraries.matrix.api.room.InvitedRoom import io.element.android.libraries.matrix.api.room.PendingRoom
import io.element.android.libraries.matrix.api.room.MatrixRoom import io.element.android.libraries.matrix.api.room.MatrixRoom
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
import io.element.android.libraries.matrix.api.room.alias.ResolvedRoomAlias import io.element.android.libraries.matrix.api.room.alias.ResolvedRoomAlias
@ -101,7 +101,7 @@ class FakeMatrixClient(
private var createDmResult: Result<RoomId> = Result.success(A_ROOM_ID) private var createDmResult: Result<RoomId> = Result.success(A_ROOM_ID)
private var findDmResult: RoomId? = A_ROOM_ID private var findDmResult: RoomId? = A_ROOM_ID
private val getRoomResults = mutableMapOf<RoomId, MatrixRoom>() private val getRoomResults = mutableMapOf<RoomId, MatrixRoom>()
val getInvitedRoomResults = mutableMapOf<RoomId, InvitedRoom>() val getPendingRoomResults = mutableMapOf<RoomId, PendingRoom>()
private val searchUserResults = mutableMapOf<String, Result<MatrixSearchUserResults>>() private val searchUserResults = mutableMapOf<String, Result<MatrixSearchUserResults>>()
private val getProfileResults = mutableMapOf<UserId, Result<MatrixUser>>() private val getProfileResults = mutableMapOf<UserId, Result<MatrixUser>>()
private var uploadMediaResult: Result<String> = Result.success(AN_AVATAR_URL) private var uploadMediaResult: Result<String> = Result.success(AN_AVATAR_URL)
@ -128,8 +128,8 @@ class FakeMatrixClient(
return getRoomResults[roomId] return getRoomResults[roomId]
} }
override suspend fun getInvitedRoom(roomId: RoomId): InvitedRoom? { override suspend fun getPendingRoom(roomId: RoomId): PendingRoom? {
return getInvitedRoomResults[roomId] return getPendingRoomResults[roomId]
} }
override suspend fun findDM(userId: UserId): RoomId? { override suspend fun findDM(userId: UserId): RoomId? {

View file

@ -9,18 +9,18 @@ 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.RoomId
import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.matrix.api.core.SessionId
import io.element.android.libraries.matrix.api.room.InvitedRoom import io.element.android.libraries.matrix.api.room.PendingRoom
import io.element.android.libraries.matrix.test.A_ROOM_ID import io.element.android.libraries.matrix.test.A_ROOM_ID
import io.element.android.libraries.matrix.test.A_SESSION_ID import io.element.android.libraries.matrix.test.A_SESSION_ID
import io.element.android.tests.testutils.lambda.lambdaError import io.element.android.tests.testutils.lambda.lambdaError
import io.element.android.tests.testutils.simulateLongTask import io.element.android.tests.testutils.simulateLongTask
class FakeInvitedRoom( class FakePendingRoom(
override val sessionId: SessionId = A_SESSION_ID, override val sessionId: SessionId = A_SESSION_ID,
override val roomId: RoomId = A_ROOM_ID, override val roomId: RoomId = A_ROOM_ID,
private val declineInviteResult: () -> Result<Unit> = { lambdaError() } private val declineInviteResult: () -> Result<Unit> = { lambdaError() }
) : InvitedRoom { ) : PendingRoom {
override suspend fun declineInvite(): Result<Unit> = simulateLongTask { override suspend fun leave(): Result<Unit> = simulateLongTask {
declineInviteResult() declineInviteResult()
} }