diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/di/RoomMemberModules.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/di/RoomMemberModules.kt index b17cb9ab6a..66fae2b50c 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/di/RoomMemberModules.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/di/RoomMemberModules.kt @@ -49,7 +49,7 @@ object RoomMemberProvidesModule { ): RoomMemberDetailsPresenter.Factory { return object : RoomMemberDetailsPresenter.Factory { override fun create(roomMember: RoomMember): RoomMemberDetailsPresenter { - return RoomMemberDetailsPresenter(matrixClient.sessionId, room, roomMember) + return RoomMemberDetailsPresenter(matrixClient, room, roomMember) } } } diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/details/RoomMemberDetailsPresenter.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/details/RoomMemberDetailsPresenter.kt index 8256453a08..33814c29f0 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/details/RoomMemberDetailsPresenter.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/members/details/RoomMemberDetailsPresenter.kt @@ -28,6 +28,7 @@ import dagger.assisted.Assisted import dagger.assisted.AssistedInject import io.element.android.features.roomdetails.impl.members.details.RoomMemberDetailsState.ConfirmationDialog import io.element.android.libraries.architecture.Presenter +import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.room.MatrixRoom @@ -36,7 +37,7 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch class RoomMemberDetailsPresenter @AssistedInject constructor( - private val currentUserSessionId: SessionId, + private val client: MatrixClient, private val room: MatrixRoom, @Assisted private val roomMember: RoomMember, ) : Presenter { @@ -91,16 +92,16 @@ class RoomMemberDetailsPresenter @AssistedInject constructor( avatarUrl = userAvatar, isBlocked = isBlocked.value, displayConfirmationDialog = confirmationDialog, - isCurrentUser = roomMember.userId == currentUserSessionId, + isCurrentUser = roomMember.userId == client.sessionId, eventSink = ::handleEvents ) } private fun CoroutineScope.blockUser(userId: UserId, isBlockedState: MutableState) = launch { - room.ignoreUser(userId).onSuccess { isBlockedState.value = true } + client.ignoreUser(userId).onSuccess { isBlockedState.value = true } } private fun CoroutineScope.unblockUser(userId: UserId, isBlockedState: MutableState) = launch { - room.unignoreUser(userId).onSuccess { isBlockedState.value = false } + client.unignoreUser(userId).onSuccess { isBlockedState.value = false } } } diff --git a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/RoomDetailsPresenterTests.kt b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/RoomDetailsPresenterTests.kt index 949cf269d4..2409172f04 100644 --- a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/RoomDetailsPresenterTests.kt +++ b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/RoomDetailsPresenterTests.kt @@ -27,6 +27,7 @@ import io.element.android.features.roomdetails.impl.RoomDetailsType import io.element.android.features.roomdetails.impl.members.details.RoomMemberDetailsPresenter import io.element.android.libraries.architecture.Async 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.UserId import io.element.android.libraries.matrix.api.room.MatrixRoom import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState @@ -39,6 +40,7 @@ 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_USER_ID import io.element.android.libraries.matrix.test.A_USER_ID_2 +import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.test.room.FakeMatrixRoom import io.element.android.tests.testutils.testCoroutineDispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -57,7 +59,7 @@ class RoomDetailsPresenterTests { private fun aRoomDetailsPresenter(room: MatrixRoom): RoomDetailsPresenter { val roomMemberDetailsPresenterFactory = object : RoomMemberDetailsPresenter.Factory { override fun create(roomMember: RoomMember): RoomMemberDetailsPresenter { - return RoomMemberDetailsPresenter(A_SESSION_ID, room, roomMember) + return RoomMemberDetailsPresenter(aMatrixClient(), room, roomMember) } } return RoomDetailsPresenter(room, roomMembershipObserver, testCoroutineDispatchers, roomMemberDetailsPresenterFactory) @@ -240,6 +242,10 @@ class RoomDetailsPresenterTests { } } +fun aMatrixClient( + sessionId: SessionId = A_SESSION_ID, +) = FakeMatrixClient() + fun aMatrixRoom( roomId: RoomId = A_ROOM_ID, name: String? = A_ROOM_NAME, diff --git a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/members/details/RoomMemberDetailsPresenterTests.kt b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/members/details/RoomMemberDetailsPresenterTests.kt index a98ec1f971..3731c910fc 100644 --- a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/members/details/RoomMemberDetailsPresenterTests.kt +++ b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/members/details/RoomMemberDetailsPresenterTests.kt @@ -20,12 +20,12 @@ import app.cash.molecule.RecompositionClock import app.cash.molecule.moleculeFlow import app.cash.turbine.test import com.google.common.truth.Truth +import io.element.android.features.roomdetails.aMatrixClient import io.element.android.features.roomdetails.aMatrixRoom import io.element.android.features.roomdetails.aRoomMember import io.element.android.features.roomdetails.impl.members.details.RoomMemberDetailsEvents import io.element.android.features.roomdetails.impl.members.details.RoomMemberDetailsPresenter import io.element.android.features.roomdetails.impl.members.details.RoomMemberDetailsState -import io.element.android.libraries.matrix.test.A_SESSION_ID import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runTest import org.junit.Test @@ -33,6 +33,8 @@ import org.junit.Test @ExperimentalCoroutinesApi class RoomMemberDetailsPresenterTests { + private val matrixClient = aMatrixClient() + @Test fun `present - returns the room member's data, then updates it if needed`() = runTest { val room = aMatrixRoom().apply { @@ -40,7 +42,7 @@ class RoomMemberDetailsPresenterTests { givenUserAvatarUrlResult(Result.success("A custom avatar")) } val roomMember = aRoomMember(displayName = "Alice") - val presenter = RoomMemberDetailsPresenter(A_SESSION_ID, room, roomMember) + val presenter = RoomMemberDetailsPresenter(matrixClient, room, roomMember) moleculeFlow(RecompositionClock.Immediate) { presenter.present() }.test { @@ -63,7 +65,7 @@ class RoomMemberDetailsPresenterTests { givenUserAvatarUrlResult(Result.failure(Throwable())) } val roomMember = aRoomMember(displayName = "Alice") - val presenter = RoomMemberDetailsPresenter(A_SESSION_ID, room, roomMember) + val presenter = RoomMemberDetailsPresenter(matrixClient, room, roomMember) moleculeFlow(RecompositionClock.Immediate) { presenter.present() }.test { @@ -82,7 +84,7 @@ class RoomMemberDetailsPresenterTests { givenUserAvatarUrlResult(Result.success(null)) } val roomMember = aRoomMember(displayName = "Alice") - val presenter = RoomMemberDetailsPresenter(A_SESSION_ID, room, roomMember) + val presenter = RoomMemberDetailsPresenter(matrixClient, room, roomMember) moleculeFlow(RecompositionClock.Immediate) { presenter.present() }.test { @@ -98,7 +100,7 @@ class RoomMemberDetailsPresenterTests { fun `present - BlockUser needing confirmation displays confirmation dialog`() = runTest { val room = aMatrixRoom() val roomMember = aRoomMember() - val presenter = RoomMemberDetailsPresenter(A_SESSION_ID, room, roomMember) + val presenter = RoomMemberDetailsPresenter(matrixClient, room, roomMember) moleculeFlow(RecompositionClock.Immediate) { presenter.present() }.test { @@ -119,7 +121,7 @@ class RoomMemberDetailsPresenterTests { fun `present - BlockUser and UnblockUser without confirmation change the 'blocked' state`() = runTest { val room = aMatrixRoom() val roomMember = aRoomMember() - val presenter = RoomMemberDetailsPresenter(A_SESSION_ID, room, roomMember) + val presenter = RoomMemberDetailsPresenter(matrixClient, room, roomMember) moleculeFlow(RecompositionClock.Immediate) { presenter.present() }.test { @@ -136,7 +138,7 @@ class RoomMemberDetailsPresenterTests { fun `present - UnblockUser needing confirmation displays confirmation dialog`() = runTest { val room = aMatrixRoom() val roomMember = aRoomMember() - val presenter = RoomMemberDetailsPresenter(A_SESSION_ID, room, roomMember) + val presenter = RoomMemberDetailsPresenter(matrixClient, room, roomMember) moleculeFlow(RecompositionClock.Immediate) { presenter.present() }.test { diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/MatrixClient.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/MatrixClient.kt index eab4060d85..7bc9ba0797 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/MatrixClient.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/MatrixClient.kt @@ -35,6 +35,8 @@ interface MatrixClient : Closeable { val invitesDataSource: RoomSummaryDataSource fun getRoom(roomId: RoomId): MatrixRoom? fun findDM(userId: UserId): MatrixRoom? + suspend fun ignoreUser(userId: UserId): Result + suspend fun unignoreUser(userId: UserId): Result suspend fun createRoom(createRoomParams: CreateRoomParameters): Result suspend fun createDM(userId: UserId): Result fun startSync() diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoom.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoom.kt index 87afee55da..41cd874098 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoom.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/MatrixRoom.kt @@ -68,10 +68,6 @@ interface MatrixRoom : Closeable { suspend fun redactEvent(eventId: EventId, reason: String? = null): Result - suspend fun ignoreUser(userId: UserId): Result - - suspend fun unignoreUser(userId: UserId): Result - suspend fun leave(): Result suspend fun acceptInvitation(): Result diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt index 2a7e7c0826..b710a5cf6d 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/RustMatrixClient.kt @@ -212,6 +212,18 @@ class RustMatrixClient constructor( return roomId?.let { getRoom(it) } } + override suspend fun ignoreUser(userId: UserId): Result = withContext(dispatchers.io) { + runCatching { + client.ignoreUser(userId.value) + } + } + + override suspend fun unignoreUser(userId: UserId): Result = withContext(dispatchers.io) { + runCatching { + client.unignoreUser(userId.value) + } + } + override suspend fun createRoom(createRoomParams: CreateRoomParameters): Result = withContext(dispatchers.io) { runCatching { val rustParams = RustCreateRoomParameters( diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustMatrixRoom.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustMatrixRoom.kt index 95094cfdc6..1e75867215 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustMatrixRoom.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RustMatrixRoom.kt @@ -38,6 +38,7 @@ import org.matrix.rustcomponents.sdk.SlidingSyncRoom import org.matrix.rustcomponents.sdk.UpdateSummary import org.matrix.rustcomponents.sdk.genTransactionId import org.matrix.rustcomponents.sdk.messageEventContentFromMarkdown +import org.matrix.rustcomponents.sdk.use import org.matrix.rustcomponents.sdk.RoomMember as RustRoomMember class RustMatrixRoom( @@ -200,19 +201,10 @@ class RustMatrixRoom( } } - override suspend fun ignoreUser(userId: UserId): Result { - return runCatching { - getRustMember(userId)?.ignore() ?: error("No member with userId $userId exists in room $roomId") - } - } - - override suspend fun unignoreUser(userId: UserId): Result { - return runCatching { - getRustMember(userId)?.unignore() ?: error("No member with userId $userId exists in room $roomId") - } - } - - private fun getRustMember(userId: UserId): RustRoomMember? { - return innerRoom.members().find { it.userId() == userId.value } + private fun findRoomMember(userId: UserId, action: (RustRoomMember).() -> Unit) { + return innerRoom.members() + .find { it.userId() == userId.value } + ?.use(action) + ?: error("No member with userId $userId exists in room $roomId") } } diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt index d33bd5c939..c547ac8237 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt @@ -47,6 +47,8 @@ class FakeMatrixClient( private val notificationService: FakeNotificationService = FakeNotificationService(), ) : MatrixClient { + private var ignoreUserResult: Result = Result.success(Unit) + private var unignoreUserResult: Result = Result.success(Unit) private var createRoomResult: Result = Result.success(A_ROOM_ID) private var createDmResult: Result = Result.success(A_ROOM_ID) private var createDmFailure: Throwable? = null @@ -62,6 +64,14 @@ class FakeMatrixClient( return findDmResult } + override suspend fun ignoreUser(userId: UserId): Result { + return ignoreUserResult + } + + override suspend fun unignoreUser(userId: UserId): Result { + return unignoreUserResult + } + override suspend fun createRoom(createRoomParams: CreateRoomParameters): Result { delay(100) return createRoomResult @@ -130,6 +140,14 @@ class FakeMatrixClient( createDmResult = result } + fun givenIgnoreUserResult(result: Result) { + ignoreUserResult = result + } + + fun givenUnignoreUserResult(result: Result) { + unignoreUserResult = result + } + fun givenCreateDmError(failure: Throwable?) { createDmFailure = failure } diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt index c0f4a7ee20..28d6525739 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt @@ -117,10 +117,6 @@ class FakeMatrixRoom( return Result.success(Unit) } - override suspend fun ignoreUser(userId: UserId): Result = ignoreResult - - override suspend fun unignoreUser(userId: UserId): Result = unignoreResult - override suspend fun leave(): Result = leaveRoomError?.let { Result.failure(it) } ?: Result.success(Unit) override suspend fun acceptInvitation(): Result { isInviteAccepted = true