From d9017a098cfbc9a3fd848bb5b0c1a4f91f83e3b3 Mon Sep 17 00:00:00 2001 From: ganfra Date: Fri, 2 Feb 2024 14:54:28 +0100 Subject: [PATCH] Favorite : rework and add tests --- features/roomactions/api/build.gradle.kts | 27 +++ .../api/SetRoomIsFavoriteAction.kt | 42 +++++ features/roomactions/impl/build.gradle.kts | 50 ++++++ .../impl/DefaultSetRoomIsFavoriteAction.kt | 56 ++++++ .../DefaultSetRoomIsFavoriteActionTests.kt | 59 ++++++ features/roomactions/test/build.gradle.kts | 28 +++ .../test/FakeSetRoomIsFavoriteAction.kt | 39 ++++ features/roomdetails/impl/build.gradle.kts | 2 + .../roomdetails/impl/RoomDetailsPresenter.kt | 8 +- .../roomdetails/RoomDetailsPresenterTests.kt | 170 ++++++++---------- features/roomlist/impl/build.gradle.kts | 2 + .../roomlist/impl/RoomListContextMenu.kt | 2 +- .../features/roomlist/impl/RoomListEvents.kt | 2 +- .../roomlist/impl/RoomListPresenter.kt | 44 ++--- .../roomlist/impl/RoomListPresenterTests.kt | 51 +++++- .../libraries/matrix/api/room/MatrixRoom.kt | 3 + .../matrix/api/room/tags/RoomNotableTags.kt | 6 +- .../matrix/impl/room/RustMatrixRoom.kt | 3 +- .../roomlist/RoomSummaryDetailsFactory.kt | 1 - .../item/event/EventTimelineItemMapper.kt | 2 +- .../matrix/test/room/FakeMatrixRoom.kt | 1 - 21 files changed, 454 insertions(+), 144 deletions(-) create mode 100644 features/roomactions/api/build.gradle.kts create mode 100644 features/roomactions/api/src/main/kotlin/io/element/android/features/roomactions/api/SetRoomIsFavoriteAction.kt create mode 100644 features/roomactions/impl/build.gradle.kts create mode 100644 features/roomactions/impl/src/main/kotlin/io/element/android/features/roomactions/impl/DefaultSetRoomIsFavoriteAction.kt create mode 100644 features/roomactions/impl/src/test/kotlin/io/element/android/features/roomactions/impl/DefaultSetRoomIsFavoriteActionTests.kt create mode 100644 features/roomactions/test/build.gradle.kts create mode 100644 features/roomactions/test/src/main/kotlin/io/element/android/features/roomactions/test/FakeSetRoomIsFavoriteAction.kt diff --git a/features/roomactions/api/build.gradle.kts b/features/roomactions/api/build.gradle.kts new file mode 100644 index 0000000000..6bfccef3e5 --- /dev/null +++ b/features/roomactions/api/build.gradle.kts @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2024 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +plugins { + id("io.element.android-library") +} + +android { + namespace = "io.element.android.features.roomactions.api" +} + +dependencies { + implementation(projects.libraries.matrix.api) +} diff --git a/features/roomactions/api/src/main/kotlin/io/element/android/features/roomactions/api/SetRoomIsFavoriteAction.kt b/features/roomactions/api/src/main/kotlin/io/element/android/features/roomactions/api/SetRoomIsFavoriteAction.kt new file mode 100644 index 0000000000..04f8bc8223 --- /dev/null +++ b/features/roomactions/api/src/main/kotlin/io/element/android/features/roomactions/api/SetRoomIsFavoriteAction.kt @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2024 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.features.roomactions.api + +import io.element.android.libraries.matrix.api.core.RoomId +import io.element.android.libraries.matrix.api.room.MatrixRoom + +/** + * Set the favorite status of a room. + * This will update the notable tags of the room. + */ +interface SetRoomIsFavoriteAction { + sealed interface Result { + data object Success : Result + data object RoomNotFound : Result + data class Exception(val inner: java.lang.Exception) : Result + } + + /** + * Set the favorite status of a room by its id, it'll try to load the room from the session. + */ + suspend operator fun invoke(roomId: RoomId, isFavorite: Boolean): Result + + /** + * Set the favorite status of a room using the provided instance. + */ + suspend operator fun invoke(room: MatrixRoom, isFavorite: Boolean): Result +} diff --git a/features/roomactions/impl/build.gradle.kts b/features/roomactions/impl/build.gradle.kts new file mode 100644 index 0000000000..61f666da08 --- /dev/null +++ b/features/roomactions/impl/build.gradle.kts @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2024 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// TODO: Remove once https://youtrack.jetbrains.com/issue/KTIJ-19369 is fixed +@Suppress("DSL_SCOPE_VIOLATION") +plugins { + id("io.element.android-compose-library") + alias(libs.plugins.anvil) + alias(libs.plugins.ksp) + id("kotlin-parcelize") +} + +android { + namespace = "io.element.android.features.roomactions.impl" +} + +anvil { + generateDaggerFactories.set(true) +} + +dependencies { + implementation(projects.anvilannotations) + anvil(projects.anvilcodegen) + api(projects.features.roomactions.api) + implementation(projects.libraries.core) + implementation(projects.libraries.architecture) + implementation(projects.libraries.matrix.api) + + testImplementation(libs.test.junit) + testImplementation(libs.coroutines.test) + testImplementation(libs.molecule.runtime) + testImplementation(libs.test.truth) + testImplementation(libs.test.turbine) + testImplementation(projects.libraries.matrix.test) + + ksp(libs.showkase.processor) +} diff --git a/features/roomactions/impl/src/main/kotlin/io/element/android/features/roomactions/impl/DefaultSetRoomIsFavoriteAction.kt b/features/roomactions/impl/src/main/kotlin/io/element/android/features/roomactions/impl/DefaultSetRoomIsFavoriteAction.kt new file mode 100644 index 0000000000..947c56ebcb --- /dev/null +++ b/features/roomactions/impl/src/main/kotlin/io/element/android/features/roomactions/impl/DefaultSetRoomIsFavoriteAction.kt @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2024 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.features.roomactions.impl + +import com.squareup.anvil.annotations.ContributesBinding +import io.element.android.features.roomactions.api.SetRoomIsFavoriteAction +import io.element.android.libraries.di.SessionScope +import io.element.android.libraries.matrix.api.MatrixClient +import io.element.android.libraries.matrix.api.core.RoomId +import io.element.android.libraries.matrix.api.room.MatrixRoom +import kotlinx.coroutines.flow.first +import javax.inject.Inject +import kotlin.coroutines.cancellation.CancellationException + +@ContributesBinding(SessionScope::class) +class DefaultSetRoomIsFavoriteAction @Inject constructor(private val client: MatrixClient) : SetRoomIsFavoriteAction { + override suspend operator fun invoke(roomId: RoomId, isFavorite: Boolean): SetRoomIsFavoriteAction.Result { + return client.getRoom(roomId).use { room -> + room?.setIsFavorite(isFavorite) ?: SetRoomIsFavoriteAction.Result.RoomNotFound + } + } + + override suspend fun invoke(room: MatrixRoom, isFavorite: Boolean): SetRoomIsFavoriteAction.Result { + return room.setIsFavorite(isFavorite) + } + + private suspend fun MatrixRoom.setIsFavorite(isFavorite: Boolean): SetRoomIsFavoriteAction.Result { + val notableTags = notableTagsFlow.first().copy(isFavorite = isFavorite) + return updateNotableTags(notableTags).fold( + onSuccess = { + SetRoomIsFavoriteAction.Result.Success + }, + onFailure = { throwable -> + if (throwable is Exception && throwable !is CancellationException) { + SetRoomIsFavoriteAction.Result.Exception(throwable) + } else { + throw throwable + } + } + ) + } +} diff --git a/features/roomactions/impl/src/test/kotlin/io/element/android/features/roomactions/impl/DefaultSetRoomIsFavoriteActionTests.kt b/features/roomactions/impl/src/test/kotlin/io/element/android/features/roomactions/impl/DefaultSetRoomIsFavoriteActionTests.kt new file mode 100644 index 0000000000..93c7518cd7 --- /dev/null +++ b/features/roomactions/impl/src/test/kotlin/io/element/android/features/roomactions/impl/DefaultSetRoomIsFavoriteActionTests.kt @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2024 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.features.roomactions.impl + +import io.element.android.features.roomactions.api.SetRoomIsFavoriteAction +import io.element.android.libraries.matrix.test.FakeMatrixClient +import io.element.android.libraries.matrix.test.room.FakeMatrixRoom +import kotlinx.coroutines.test.runTest +import org.junit.Test + +class DefaultSetRoomIsFavoriteActionTests { + private val room = FakeMatrixRoom() + + @Test + fun `given a room id and a client without rooms, when action is invoked, then it returns Result_RoomNotFound`() = runTest { + val action = DefaultSetRoomIsFavoriteAction(FakeMatrixClient()) + val result = action(room.roomId, true) + assert(result is SetRoomIsFavoriteAction.Result.RoomNotFound) + } + + @Test + fun `given a room, when action is invoked, then it returns Result_Success`() = runTest { + val action = DefaultSetRoomIsFavoriteAction(FakeMatrixClient()) + val result = action(room, true) + assert(result is SetRoomIsFavoriteAction.Result.Success) + } + + @Test + fun `given a room id and a client with a room, when action is invoked, then it returns Result_Success`() = runTest { + val client = FakeMatrixClient().apply { + givenGetRoomResult(room.roomId, room) + } + val action = DefaultSetRoomIsFavoriteAction(client) + val result = action(room.roomId, true) + assert(result is SetRoomIsFavoriteAction.Result.Success) + } + + @Test + fun `given a room, when action is invoked and fail, then it returns Result_Exception`() = runTest { + val action = DefaultSetRoomIsFavoriteAction(FakeMatrixClient()) + room.givenUpdateNotableTagsResult(Result.failure(Exception())) + val result = action(room, true) + assert(result is SetRoomIsFavoriteAction.Result.Exception) + } +} diff --git a/features/roomactions/test/build.gradle.kts b/features/roomactions/test/build.gradle.kts new file mode 100644 index 0000000000..d43603e54a --- /dev/null +++ b/features/roomactions/test/build.gradle.kts @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +plugins { + id("io.element.android-library") +} + +android { + namespace = "io.element.android.features.roomactions.test" +} + +dependencies { + implementation(projects.features.roomactions.api) + implementation(projects.libraries.matrix.api) + implementation(libs.coroutines.core) +} diff --git a/features/roomactions/test/src/main/kotlin/io/element/android/features/roomactions/test/FakeSetRoomIsFavoriteAction.kt b/features/roomactions/test/src/main/kotlin/io/element/android/features/roomactions/test/FakeSetRoomIsFavoriteAction.kt new file mode 100644 index 0000000000..c892079f7b --- /dev/null +++ b/features/roomactions/test/src/main/kotlin/io/element/android/features/roomactions/test/FakeSetRoomIsFavoriteAction.kt @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2024 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.features.roomactions.test + +import io.element.android.features.roomactions.api.SetRoomIsFavoriteAction +import io.element.android.libraries.matrix.api.core.RoomId +import io.element.android.libraries.matrix.api.room.MatrixRoom + +class FakeSetRoomIsFavoriteAction : SetRoomIsFavoriteAction { + private var counter = 0 + + fun assertCalled(number: Int) { + assert(counter == number) { "Expected $number calls, got $counter" } + } + + override suspend fun invoke(roomId: RoomId, isFavorite: Boolean): SetRoomIsFavoriteAction.Result { + counter++ + return SetRoomIsFavoriteAction.Result.Success + } + + override suspend fun invoke(room: MatrixRoom, isFavorite: Boolean): SetRoomIsFavoriteAction.Result { + counter++ + return SetRoomIsFavoriteAction.Result.Success + } +} diff --git a/features/roomdetails/impl/build.gradle.kts b/features/roomdetails/impl/build.gradle.kts index 0f1a139f40..d76ebbc9d8 100644 --- a/features/roomdetails/impl/build.gradle.kts +++ b/features/roomdetails/impl/build.gradle.kts @@ -54,6 +54,7 @@ dependencies { implementation(projects.features.createroom.api) implementation(projects.services.analytics.api) implementation(projects.features.poll.api) + implementation(projects.features.roomactions.api) testImplementation(libs.test.junit) testImplementation(libs.coroutines.test) @@ -70,6 +71,7 @@ dependencies { testImplementation(projects.tests.testutils) testImplementation(projects.features.leaveroom.test) testImplementation(projects.features.createroom.test) + testImplementation(projects.features.roomactions.test) ksp(libs.showkase.processor) } diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenter.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenter.kt index 4b6e33b288..ca17050181 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenter.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsPresenter.kt @@ -29,6 +29,7 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.lifecycle.Lifecycle import io.element.android.features.leaveroom.api.LeaveRoomEvent import io.element.android.features.leaveroom.api.LeaveRoomPresenter +import io.element.android.features.roomactions.api.SetRoomIsFavoriteAction import io.element.android.features.roomdetails.impl.members.details.RoomMemberDetailsPresenter import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.core.coroutine.CoroutineDispatchers @@ -44,7 +45,6 @@ import io.element.android.libraries.matrix.api.room.StateEventType import io.element.android.libraries.matrix.api.room.powerlevels.canInvite import io.element.android.libraries.matrix.api.room.powerlevels.canSendState import io.element.android.libraries.matrix.api.room.roomNotificationSettings -import io.element.android.libraries.matrix.api.room.tags.RoomNotableTags import io.element.android.libraries.matrix.ui.room.getDirectRoomMember import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.launchIn @@ -61,6 +61,7 @@ class RoomDetailsPresenter @Inject constructor( private val roomMembersDetailsPresenterFactory: RoomMemberDetailsPresenter.Factory, private val leaveRoomPresenter: LeaveRoomPresenter, private val dispatchers: CoroutineDispatchers, + private val setRoomIsFavorite: SetRoomIsFavoriteAction, ) : Presenter { @Composable override fun present(): RoomDetailsState { @@ -126,9 +127,8 @@ class RoomDetailsPresenter @Inject constructor( } } is RoomDetailsEvent.SetIsFavorite -> { - scope.launch(dispatchers.io) { - val tags = RoomNotableTags(isFavorite = event.isFavorite) - room.updateNotableTags(tags) + scope.launch { + setRoomIsFavorite(room, event.isFavorite) } } } 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 299a8120a5..0e0b392782 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 @@ -19,14 +19,18 @@ package io.element.android.features.roomdetails import androidx.lifecycle.Lifecycle import app.cash.molecule.RecompositionMode import app.cash.molecule.moleculeFlow +import app.cash.turbine.TurbineTestContext import app.cash.turbine.test import com.google.common.truth.Truth.assertThat import io.element.android.features.createroom.test.FakeStartDMAction import io.element.android.features.leaveroom.api.LeaveRoomEvent import io.element.android.features.leaveroom.api.LeaveRoomPresenter import io.element.android.features.leaveroom.fake.FakeLeaveRoomPresenter +import io.element.android.features.roomactions.api.SetRoomIsFavoriteAction +import io.element.android.features.roomactions.test.FakeSetRoomIsFavoriteAction import io.element.android.features.roomdetails.impl.RoomDetailsEvent import io.element.android.features.roomdetails.impl.RoomDetailsPresenter +import io.element.android.features.roomdetails.impl.RoomDetailsState import io.element.android.features.roomdetails.impl.RoomDetailsType import io.element.android.features.roomdetails.impl.RoomTopicState import io.element.android.features.roomdetails.impl.members.aRoomMember @@ -40,6 +44,7 @@ import io.element.android.libraries.matrix.api.room.MatrixRoom import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState import io.element.android.libraries.matrix.api.room.RoomNotificationMode import io.element.android.libraries.matrix.api.room.StateEventType +import io.element.android.libraries.matrix.api.room.tags.RoomNotableTags 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 @@ -71,10 +76,11 @@ class RoomDetailsPresenterTests { } private fun TestScope.createRoomDetailsPresenter( - room: MatrixRoom, + room: MatrixRoom = aMatrixRoom(), leaveRoomPresenter: LeaveRoomPresenter = FakeLeaveRoomPresenter(), dispatchers: CoroutineDispatchers = testCoroutineDispatchers(), - notificationSettingsService: FakeNotificationSettingsService = FakeNotificationSettingsService() + notificationSettingsService: FakeNotificationSettingsService = FakeNotificationSettingsService(), + setRoomIsFavoriteAction: SetRoomIsFavoriteAction = FakeSetRoomIsFavoriteAction(), ): RoomDetailsPresenter { val matrixClient = FakeMatrixClient(notificationSettingsService = notificationSettingsService) val roomMemberDetailsPresenterFactory = object : RoomMemberDetailsPresenter.Factory { @@ -86,25 +92,30 @@ class RoomDetailsPresenterTests { mapOf(FeatureFlags.NotificationSettings.key to true) ) return RoomDetailsPresenter( - matrixClient, - room, - featureFlagService, - matrixClient.notificationSettingsService(), - roomMemberDetailsPresenterFactory, - leaveRoomPresenter, - dispatchers + client = matrixClient, + room = room, + featureFlagService = featureFlagService, + notificationSettingsService = matrixClient.notificationSettingsService(), + roomMembersDetailsPresenterFactory = roomMemberDetailsPresenterFactory, + leaveRoomPresenter = leaveRoomPresenter, + dispatchers = dispatchers, + setRoomIsFavorite = setRoomIsFavoriteAction, ) } + private suspend fun RoomDetailsPresenter.test(validate: suspend TurbineTestContext.() -> Unit) { + moleculeFlow(RecompositionMode.Immediate) { + withFakeLifecycleOwner(fakeLifecycleOwner) { + present() + } + }.test(validate = validate) + } + @Test fun `present - initial state is created from room if roomInfo is null`() = runTest { val room = aMatrixRoom() val presenter = createRoomDetailsPresenter(room) - moleculeFlow(RecompositionMode.Immediate) { - withFakeLifecycleOwner(fakeLifecycleOwner) { - presenter.present() - } - }.test { + presenter.test { val initialState = awaitItem() assertThat(initialState.roomId).isEqualTo(room.roomId.value) assertThat(initialState.roomName).isEqualTo(room.name) @@ -124,11 +135,7 @@ class RoomDetailsPresenterTests { givenRoomInfo(roomInfo) } val presenter = createRoomDetailsPresenter(room) - moleculeFlow(RecompositionMode.Immediate) { - withFakeLifecycleOwner(fakeLifecycleOwner) { - presenter.present() - } - }.test { + presenter.test { skipItems(1) val updatedState = awaitItem() assertThat(updatedState.roomName).isEqualTo(roomInfo.name) @@ -143,11 +150,7 @@ class RoomDetailsPresenterTests { fun `present - initial state with no room name`() = runTest { val room = aMatrixRoom(name = null) val presenter = createRoomDetailsPresenter(room) - moleculeFlow(RecompositionMode.Immediate) { - withFakeLifecycleOwner(fakeLifecycleOwner) { - presenter.present() - } - }.test { + presenter.test { val initialState = awaitItem() assertThat(initialState.roomName).isEqualTo(room.displayName) @@ -167,11 +170,7 @@ class RoomDetailsPresenterTests { givenRoomMembersState(MatrixRoomMembersState.Ready(roomMembers)) } val presenter = createRoomDetailsPresenter(room) - moleculeFlow(RecompositionMode.Immediate) { - withFakeLifecycleOwner(fakeLifecycleOwner) { - presenter.present() - } - }.test { + presenter.test { val initialState = awaitItem() assertThat(initialState.roomType).isEqualTo(RoomDetailsType.Dm(otherRoomMember)) @@ -185,11 +184,7 @@ class RoomDetailsPresenterTests { givenCanInviteResult(Result.success(true)) } val presenter = createRoomDetailsPresenter(room, dispatchers = testCoroutineDispatchers()) - moleculeFlow(RecompositionMode.Immediate) { - withFakeLifecycleOwner(fakeLifecycleOwner) { - presenter.present() - } - }.test { + presenter.test { // Initially false assertThat(awaitItem().canInvite).isFalse() // Then the asynchronous check completes and it becomes true @@ -205,11 +200,7 @@ class RoomDetailsPresenterTests { givenCanInviteResult(Result.success(false)) } val presenter = createRoomDetailsPresenter(room) - moleculeFlow(RecompositionMode.Immediate) { - withFakeLifecycleOwner(fakeLifecycleOwner) { - presenter.present() - } - }.test { + presenter.test { assertThat(awaitItem().canInvite).isFalse() cancelAndIgnoreRemainingEvents() @@ -222,11 +213,7 @@ class RoomDetailsPresenterTests { givenCanInviteResult(Result.failure(Throwable("Whoops"))) } val presenter = createRoomDetailsPresenter(room) - moleculeFlow(RecompositionMode.Immediate) { - withFakeLifecycleOwner(fakeLifecycleOwner) { - presenter.present() - } - }.test { + presenter.test { assertThat(awaitItem().canInvite).isFalse() cancelAndIgnoreRemainingEvents() @@ -242,11 +229,7 @@ class RoomDetailsPresenterTests { givenCanInviteResult(Result.success(false)) } val presenter = createRoomDetailsPresenter(room) - moleculeFlow(RecompositionMode.Immediate) { - withFakeLifecycleOwner(fakeLifecycleOwner) { - presenter.present() - } - }.test { + presenter.test { // Initially false assertThat(awaitItem().canEdit).isFalse() // Then the asynchronous check completes and it becomes true @@ -273,11 +256,7 @@ class RoomDetailsPresenterTests { givenCanInviteResult(Result.success(false)) } val presenter = createRoomDetailsPresenter(room) - moleculeFlow(RecompositionMode.Immediate) { - withFakeLifecycleOwner(fakeLifecycleOwner) { - presenter.present() - } - }.test { + presenter.test { // Initially false assertThat(awaitItem().canEdit).isFalse() // Then the asynchronous check completes, but editing is still disallowed because it's a DM @@ -305,11 +284,7 @@ class RoomDetailsPresenterTests { givenCanSendStateResult(StateEventType.ROOM_TOPIC, Result.success(true)) } val presenter = createRoomDetailsPresenter(room) - moleculeFlow(RecompositionMode.Immediate) { - withFakeLifecycleOwner(fakeLifecycleOwner) { - presenter.present() - } - }.test { + presenter.test { skipItems(1) // There's no topic, so we hide the entire UI for DMs @@ -328,11 +303,7 @@ class RoomDetailsPresenterTests { givenCanInviteResult(Result.success(false)) } val presenter = createRoomDetailsPresenter(room) - moleculeFlow(RecompositionMode.Immediate) { - withFakeLifecycleOwner(fakeLifecycleOwner) { - presenter.present() - } - }.test { + presenter.test { // Initially false assertThat(awaitItem().canEdit).isFalse() // Then the asynchronous check completes and it becomes true @@ -351,11 +322,7 @@ class RoomDetailsPresenterTests { givenCanInviteResult(Result.success(false)) } val presenter = createRoomDetailsPresenter(room) - moleculeFlow(RecompositionMode.Immediate) { - withFakeLifecycleOwner(fakeLifecycleOwner) { - presenter.present() - } - }.test { + presenter.test { // Initially false, and no further events assertThat(awaitItem().canEdit).isFalse() @@ -371,11 +338,7 @@ class RoomDetailsPresenterTests { } val presenter = createRoomDetailsPresenter(room) - moleculeFlow(RecompositionMode.Immediate) { - withFakeLifecycleOwner(fakeLifecycleOwner) { - presenter.present() - } - }.test { + presenter.test { // The initial state is "hidden" and no further state changes happen assertThat(awaitItem().roomTopic).isEqualTo(RoomTopicState.Hidden) @@ -392,11 +355,7 @@ class RoomDetailsPresenterTests { } val presenter = createRoomDetailsPresenter(room) - moleculeFlow(RecompositionMode.Immediate) { - withFakeLifecycleOwner(fakeLifecycleOwner) { - presenter.present() - } - }.test { + presenter.test { // Ignore the initial state skipItems(1) @@ -416,11 +375,7 @@ class RoomDetailsPresenterTests { leaveRoomPresenter = leaveRoomPresenter, dispatchers = testCoroutineDispatchers() ) - moleculeFlow(RecompositionMode.Immediate) { - withFakeLifecycleOwner(fakeLifecycleOwner) { - presenter.present() - } - }.test { + presenter.test { awaitItem().eventSink(RoomDetailsEvent.LeaveRoom) assertThat(leaveRoomPresenter.events).contains(LeaveRoomEvent.ShowConfirmation(room.roomId)) @@ -439,11 +394,7 @@ class RoomDetailsPresenterTests { leaveRoomPresenter = leaveRoomPresenter, notificationSettingsService = notificationSettingsService, ) - moleculeFlow(RecompositionMode.Immediate) { - withFakeLifecycleOwner(fakeLifecycleOwner) { - presenter.present() - } - }.test { + presenter.test { notificationSettingsService.setRoomNotificationMode(room.roomId, RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY) val updatedState = consumeItemsUntilPredicate { it.roomNotificationSettings?.mode == RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY @@ -458,11 +409,7 @@ class RoomDetailsPresenterTests { val notificationSettingsService = FakeNotificationSettingsService(initialRoomMode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY) val room = aMatrixRoom(notificationSettingsService = notificationSettingsService) val presenter = createRoomDetailsPresenter(room = room, notificationSettingsService = notificationSettingsService) - moleculeFlow(RecompositionMode.Immediate) { - withFakeLifecycleOwner(fakeLifecycleOwner) { - presenter.present() - } - }.test { + presenter.test { awaitItem().eventSink(RoomDetailsEvent.MuteNotification) val updatedState = consumeItemsUntilPredicate(timeout = 250.milliseconds) { it.roomNotificationSettings?.mode == RoomNotificationMode.MUTE @@ -480,11 +427,7 @@ class RoomDetailsPresenterTests { ) val room = aMatrixRoom(notificationSettingsService = notificationSettingsService) val presenter = createRoomDetailsPresenter(room = room, notificationSettingsService = notificationSettingsService) - moleculeFlow(RecompositionMode.Immediate) { - withFakeLifecycleOwner(fakeLifecycleOwner) { - presenter.present() - } - }.test { + presenter.test { awaitItem().eventSink(RoomDetailsEvent.UnmuteNotification) val updatedState = consumeItemsUntilPredicate { it.roomNotificationSettings?.mode == RoomNotificationMode.ALL_MESSAGES @@ -493,6 +436,35 @@ class RoomDetailsPresenterTests { cancelAndIgnoreRemainingEvents() } } + + @Test + fun `present - when set is favorite event is emitted, then the action is called`() = runTest { + val setRoomIsFavoriteAction = FakeSetRoomIsFavoriteAction() + val presenter = createRoomDetailsPresenter(setRoomIsFavoriteAction = setRoomIsFavoriteAction) + presenter.test { + val initialState = awaitItem() + initialState.eventSink(RoomDetailsEvent.SetIsFavorite(true)) + setRoomIsFavoriteAction.assertCalled(1) + cancelAndIgnoreRemainingEvents() + } + } + + @Test + fun `present - changes in notable tags updates is favorite flag`() = runTest { + val room = aMatrixRoom() + val presenter = createRoomDetailsPresenter(room = room) + presenter.test { + room.updateNotableTags(RoomNotableTags(true)) + consumeItemsUntilPredicate { it.isFavorite }.last().let { state -> + assertThat(state.isFavorite).isTrue() + } + room.updateNotableTags(RoomNotableTags(false)) + consumeItemsUntilPredicate { !it.isFavorite }.last().let { state -> + assertThat(state.isFavorite).isFalse() + } + cancelAndIgnoreRemainingEvents() + } + } } fun aMatrixRoom( diff --git a/features/roomlist/impl/build.gradle.kts b/features/roomlist/impl/build.gradle.kts index 4e415fd2a2..fdb0e7a3e2 100644 --- a/features/roomlist/impl/build.gradle.kts +++ b/features/roomlist/impl/build.gradle.kts @@ -56,6 +56,7 @@ dependencies { implementation(projects.features.networkmonitor.api) implementation(projects.features.leaveroom.api) implementation(projects.services.analytics.api) + implementation(projects.features.roomactions.api) api(projects.features.roomlist.api) ksp(libs.showkase.processor) @@ -75,4 +76,5 @@ dependencies { testImplementation(projects.features.networkmonitor.test) testImplementation(projects.tests.testutils) testImplementation(projects.features.leaveroom.test) + testImplementation(projects.features.roomactions.test) } diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListContextMenu.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListContextMenu.kt index f5ce9897b4..dc448a412c 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListContextMenu.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListContextMenu.kt @@ -60,7 +60,7 @@ fun RoomListContextMenu( eventSink(RoomListEvents.LeaveRoom(contextMenu.roomId)) }, onFavoriteChanged = { isFavorite -> - eventSink(RoomListEvents.MarkRoomAsFavorite(contextMenu.roomId, isFavorite)) + eventSink(RoomListEvents.SetRoomIsFavorite(contextMenu.roomId, isFavorite)) }, ) } diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListEvents.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListEvents.kt index b804db5315..b707de4055 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListEvents.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListEvents.kt @@ -28,5 +28,5 @@ sealed interface RoomListEvents { data class ShowContextMenu(val roomListRoomSummary: RoomListRoomSummary) : RoomListEvents data object HideContextMenu : RoomListEvents data class LeaveRoom(val roomId: RoomId) : RoomListEvents - data class MarkRoomAsFavorite(val roomId: RoomId, val isFavorite: Boolean) : RoomListEvents + data class SetRoomIsFavorite(val roomId: RoomId, val isFavorite: Boolean) : RoomListEvents } diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListPresenter.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListPresenter.kt index 595f75c2fa..5b8c7a37ab 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListPresenter.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListPresenter.kt @@ -31,6 +31,7 @@ import io.element.android.features.leaveroom.api.LeaveRoomEvent import io.element.android.features.leaveroom.api.LeaveRoomPresenter import io.element.android.features.networkmonitor.api.NetworkMonitor import io.element.android.features.networkmonitor.api.NetworkStatus +import io.element.android.features.roomactions.api.SetRoomIsFavoriteAction import io.element.android.features.roomlist.impl.datasource.InviteStateDataSource import io.element.android.features.roomlist.impl.datasource.RoomListDataSource import io.element.android.libraries.architecture.AsyncData @@ -45,17 +46,14 @@ import io.element.android.libraries.indicator.api.IndicatorService import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.encryption.EncryptionService import io.element.android.libraries.matrix.api.encryption.RecoveryState -import io.element.android.libraries.matrix.api.room.tags.RoomNotableTags import io.element.android.libraries.matrix.api.user.MatrixUser import io.element.android.libraries.matrix.api.user.getCurrentUser import io.element.android.libraries.matrix.api.verification.SessionVerificationService import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Job +import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.distinctUntilChanged -import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch -import timber.log.Timber import javax.inject.Inject private const val EXTENDED_RANGE_SIZE = 40 @@ -71,6 +69,7 @@ class RoomListPresenter @Inject constructor( private val encryptionService: EncryptionService, private val featureFlagService: FeatureFlagService, private val indicatorService: IndicatorService, + private val setRoomIsFavorite: SetRoomIsFavoriteAction, ) : Presenter { @Composable override fun present(): RoomListState { @@ -134,7 +133,7 @@ class RoomListPresenter @Inject constructor( contextMenu.value = RoomListState.ContextMenu.Hidden } is RoomListEvents.LeaveRoom -> leaveRoomState.eventSink(LeaveRoomEvent.ShowConfirmation(event.roomId)) - is RoomListEvents.MarkRoomAsFavorite -> coroutineScope.markRoomAsFavorite(event) + is RoomListEvents.SetRoomIsFavorite -> coroutineScope.setRoomIsFavorite(event) } } @@ -170,28 +169,23 @@ class RoomListPresenter @Inject constructor( isFavorite = AsyncData.Loading(), ) contextMenuState.value = initialState - val room = client.getRoom(event.roomListRoomSummary.roomId) - if (room != null) { - room.notableTagsFlow - .distinctUntilChanged() - .onEach { tags -> - val newState = initialState.copy(isFavorite = AsyncData.Success(tags.isFavorite)) - contextMenuState.value = newState - } - .launchIn(this) - } else { - contextMenuState.value = initialState.copy(isFavorite = AsyncData.Failure(IllegalStateException("Room not found"))) + client.getRoom(event.roomListRoomSummary.roomId).use { room -> + if (room != null) { + room.notableTagsFlow + .distinctUntilChanged() + .onEach { tags -> + val newState = initialState.copy(isFavorite = AsyncData.Success(tags.isFavorite)) + contextMenuState.value = newState + } + .collect() + } else { + contextMenuState.value = initialState.copy(isFavorite = AsyncData.Failure(IllegalStateException("Room not found"))) + } } } - private fun CoroutineScope.markRoomAsFavorite(event: RoomListEvents.MarkRoomAsFavorite) = launch { - val room = client.getRoom(event.roomId) - if (room != null) { - val notableTags = RoomNotableTags(isFavorite = event.isFavorite); - room.updateNotableTags(notableTags) - }else { - Timber.w("Room ${event.roomId} not found, can't mark as favorite"); - } + private fun CoroutineScope.setRoomIsFavorite(event: RoomListEvents.SetRoomIsFavorite) = launch { + setRoomIsFavorite(event.roomId, event.isFavorite) } private fun updateVisibleRange(range: IntRange) { @@ -204,5 +198,3 @@ class RoomListPresenter @Inject constructor( client.roomListService.updateAllRoomsVisibleRange(extendedRange) } } - - diff --git a/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTests.kt b/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTests.kt index 839fa04cf7..b3da58220f 100644 --- a/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTests.kt +++ b/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTests.kt @@ -25,11 +25,14 @@ import io.element.android.features.leaveroom.api.LeaveRoomPresenter import io.element.android.features.leaveroom.fake.FakeLeaveRoomPresenter import io.element.android.features.networkmonitor.api.NetworkMonitor import io.element.android.features.networkmonitor.test.FakeNetworkMonitor +import io.element.android.features.roomactions.api.SetRoomIsFavoriteAction +import io.element.android.features.roomactions.test.FakeSetRoomIsFavoriteAction import io.element.android.features.roomlist.impl.datasource.FakeInviteDataSource import io.element.android.features.roomlist.impl.datasource.InviteStateDataSource import io.element.android.features.roomlist.impl.datasource.RoomListDataSource import io.element.android.features.roomlist.impl.datasource.RoomListRoomSummaryFactory import io.element.android.features.roomlist.impl.model.RoomListRoomSummary +import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.dateformatter.api.LastMessageTimestampFormatter import io.element.android.libraries.dateformatter.test.FakeLastMessageTimestampFormatter import io.element.android.libraries.designsystem.components.avatar.AvatarData @@ -44,6 +47,7 @@ import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.encryption.BackupState import io.element.android.libraries.matrix.api.encryption.EncryptionService import io.element.android.libraries.matrix.api.room.RoomNotificationMode +import io.element.android.libraries.matrix.api.room.tags.RoomNotableTags import io.element.android.libraries.matrix.api.verification.SessionVerificationService import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatus import io.element.android.libraries.matrix.test.AN_AVATAR_URL @@ -55,6 +59,7 @@ import io.element.android.libraries.matrix.test.A_USER_NAME import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.test.encryption.FakeEncryptionService import io.element.android.libraries.matrix.test.notificationsettings.FakeNotificationSettingsService +import io.element.android.libraries.matrix.test.room.FakeMatrixRoom import io.element.android.libraries.matrix.test.room.aRoomSummaryFilled import io.element.android.libraries.matrix.test.roomlist.FakeRoomListService import io.element.android.libraries.matrix.test.verification.FakeSessionVerificationService @@ -309,19 +314,29 @@ class RoomListPresenterTests { @Test fun `present - show context menu`() = runTest { val scope = CoroutineScope(coroutineContext + SupervisorJob()) - val presenter = createRoomListPresenter(coroutineScope = scope) + val room = FakeMatrixRoom() + val client = FakeMatrixClient().apply { + givenGetRoomResult(A_ROOM_ID, room) + } + val presenter = createRoomListPresenter(client = client, coroutineScope = scope) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { skipItems(1) - val initialState = awaitItem() val summary = aRoomListRoomSummary initialState.eventSink(RoomListEvents.ShowContextMenu(summary)) - val shownState = awaitItem() - assertThat(shownState.contextMenu) - .isEqualTo(RoomListState.ContextMenu.Shown(summary.roomId, summary.name, false)) + awaitItem().also { state -> + assertThat(state.contextMenu) + .isEqualTo(RoomListState.ContextMenu.Shown(summary.roomId, summary.name, false, AsyncData.Success(false))) + } + + room.updateNotableTags(RoomNotableTags(isFavorite = true)) + awaitItem().also { state -> + assertThat(state.contextMenu) + .isEqualTo(RoomListState.ContextMenu.Shown(summary.roomId, summary.name, false, AsyncData.Success(true))) + } scope.cancel() } } @@ -329,7 +344,11 @@ class RoomListPresenterTests { @Test fun `present - hide context menu`() = runTest { val scope = CoroutineScope(coroutineContext + SupervisorJob()) - val presenter = createRoomListPresenter(coroutineScope = scope) + val room = FakeMatrixRoom() + val client = FakeMatrixClient().apply { + givenGetRoomResult(A_ROOM_ID, room) + } + val presenter = createRoomListPresenter(client = client, coroutineScope = scope) moleculeFlow(RecompositionMode.Immediate) { presenter.present() }.test { @@ -341,7 +360,7 @@ class RoomListPresenterTests { val shownState = awaitItem() assertThat(shownState.contextMenu) - .isEqualTo(RoomListState.ContextMenu.Shown(summary.roomId, summary.name, false)) + .isEqualTo(RoomListState.ContextMenu.Shown(summary.roomId, summary.name, false, AsyncData.Success(false))) shownState.eventSink(RoomListEvents.HideContextMenu) val hiddenState = awaitItem() @@ -394,6 +413,22 @@ class RoomListPresenterTests { } } + @Test + fun `present - when set is favorite event is emitted, then the action is called`() = runTest { + val scope = CoroutineScope(coroutineContext + SupervisorJob()) + val setRoomIsFavoriteAction = FakeSetRoomIsFavoriteAction() + val presenter = createRoomListPresenter(setRoomIsFavoriteAction = setRoomIsFavoriteAction, coroutineScope = scope) + moleculeFlow(RecompositionMode.Immediate) { + presenter.present() + }.test { + val initialState = awaitItem() + initialState.eventSink(RoomListEvents.SetRoomIsFavorite(A_ROOM_ID, true)) + setRoomIsFavoriteAction.assertCalled(1) + cancelAndIgnoreRemainingEvents() + scope.cancel() + } + } + private fun TestScope.createRoomListPresenter( client: MatrixClient = FakeMatrixClient(), sessionVerificationService: SessionVerificationService = FakeSessionVerificationService(), @@ -407,6 +442,7 @@ class RoomListPresenterTests { roomLastMessageFormatter: RoomLastMessageFormatter = FakeRoomLastMessageFormatter(), encryptionService: EncryptionService = FakeEncryptionService(), coroutineScope: CoroutineScope, + setRoomIsFavoriteAction: SetRoomIsFavoriteAction = FakeSetRoomIsFavoriteAction(), ) = RoomListPresenter( client = client, sessionVerificationService = sessionVerificationService, @@ -431,6 +467,7 @@ class RoomListPresenterTests { encryptionService = encryptionService, featureFlagService = FakeFeatureFlagService(mapOf(FeatureFlags.SecureStorage.key to true)), ), + setRoomIsFavorite = setRoomIsFavoriteAction, ) } 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 630f87a0fb..7c40d37155 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 @@ -58,6 +58,9 @@ interface MatrixRoom : Closeable { val roomInfoFlow: Flow + /** + * The current notable tags as a Flow. + */ val notableTagsFlow: Flow /** diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/tags/RoomNotableTags.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/tags/RoomNotableTags.kt index 25a19b5697..aabd6fc4f0 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/tags/RoomNotableTags.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/room/tags/RoomNotableTags.kt @@ -16,6 +16,10 @@ package io.element.android.libraries.matrix.api.room.tags +/** + * Represents the notable tags of a room. + * @param isFavorite true if the room is marked as favorite. + */ data class RoomNotableTags( - val isFavorite: Boolean, + val isFavorite: Boolean = false, ) 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 9c0cd11e3f..d9bd6bfa96 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 @@ -82,8 +82,8 @@ import org.matrix.rustcomponents.sdk.use import timber.log.Timber import java.io.File import org.matrix.rustcomponents.sdk.Room as InnerRoom -import uniffi.matrix_sdk_base.RoomNotableTags as RustRoomNotableTags import org.matrix.rustcomponents.sdk.Timeline as InnerTimeline +import uniffi.matrix_sdk_base.RoomNotableTags as RustRoomNotableTags @OptIn(ExperimentalCoroutinesApi::class) class RustMatrixRoom( @@ -118,7 +118,6 @@ class RustMatrixRoom( override val notableTagsFlow: Flow = mxCallbackFlow { innerRoom.subscribeToNotableTags(object : RoomNotableTagsListener { override fun call(notableTags: RustRoomNotableTags) { - Timber.d("On notable tags update: $notableTags") channel.trySend(notableTags.map()) } }) diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryDetailsFactory.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryDetailsFactory.kt index 4934b0058b..1b3e900f17 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryDetailsFactory.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomSummaryDetailsFactory.kt @@ -25,7 +25,6 @@ import org.matrix.rustcomponents.sdk.RoomInfo import org.matrix.rustcomponents.sdk.use class RoomSummaryDetailsFactory(private val roomMessageFactory: RoomMessageFactory = RoomMessageFactory()) { - fun create(roomInfo: RoomInfo): RoomSummaryDetails { val latestRoomMessage = roomInfo.latestEvent?.use { roomMessageFactory.create(it) diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/EventTimelineItemMapper.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/EventTimelineItemMapper.kt index 20cd781dcb..ed56d4a8d0 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/EventTimelineItemMapper.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/EventTimelineItemMapper.kt @@ -28,7 +28,6 @@ import io.element.android.libraries.matrix.api.timeline.item.event.ReactionSende import io.element.android.libraries.matrix.api.timeline.item.event.Receipt import io.element.android.libraries.matrix.api.timeline.item.event.TimelineItemEventOrigin import kotlinx.collections.immutable.ImmutableList -import uniffi.matrix_sdk_ui.EventItemOrigin as RustEventItemOrigin import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList import org.matrix.rustcomponents.sdk.Reaction @@ -37,6 +36,7 @@ import org.matrix.rustcomponents.sdk.EventTimelineItem as RustEventTimelineItem import org.matrix.rustcomponents.sdk.EventTimelineItemDebugInfo as RustEventTimelineItemDebugInfo import org.matrix.rustcomponents.sdk.ProfileDetails as RustProfileDetails import org.matrix.rustcomponents.sdk.Receipt as RustReceipt +import uniffi.matrix_sdk_ui.EventItemOrigin as RustEventItemOrigin class EventTimelineItemMapper(private val contentMapper: TimelineEventContentMapper = TimelineEventContentMapper()) { fun map(eventTimelineItem: RustEventTimelineItem): EventTimelineItem = eventTimelineItem.use { 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 72508440ea..c5d1f88a81 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 @@ -627,7 +627,6 @@ fun aRoomInfo( isPublic: Boolean = true, isSpace: Boolean = false, isTombstoned: Boolean = false, - isFavorite: Boolean = false, canonicalAlias: String? = null, alternativeAliases: List = emptyList(), currentUserMembership: CurrentUserMembership = CurrentUserMembership.JOINED,