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 ed5f3b1ea1..f901502b79 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 @@ -37,6 +37,7 @@ import io.element.android.features.preferences.api.store.SessionPreferencesStore 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.filters.RoomListFiltersPresenter +import io.element.android.features.roomlist.impl.filters.RoomListFiltersState import io.element.android.features.roomlist.impl.migration.MigrationScreenPresenter import io.element.android.features.roomlist.impl.search.RoomListSearchEvents import io.element.android.features.roomlist.impl.search.RoomListSearchState @@ -78,7 +79,7 @@ class RoomListPresenter @Inject constructor( private val roomListDataSource: RoomListDataSource, private val featureFlagService: FeatureFlagService, private val indicatorService: IndicatorService, - private val filtersPresenter: RoomListFiltersPresenter, + private val filtersPresenter: Presenter, private val searchPresenter: Presenter, private val migrationScreenPresenter: MigrationScreenPresenter, private val sessionPreferencesStore: SessionPreferencesStore, diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/di/RoomListModule.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/di/RoomListModule.kt index 369da2fc75..b66401695e 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/di/RoomListModule.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/di/RoomListModule.kt @@ -19,6 +19,8 @@ package io.element.android.features.roomlist.impl.di import com.squareup.anvil.annotations.ContributesTo import dagger.Binds import dagger.Module +import io.element.android.features.roomlist.impl.filters.RoomListFiltersPresenter +import io.element.android.features.roomlist.impl.filters.RoomListFiltersState import io.element.android.features.roomlist.impl.search.RoomListSearchPresenter import io.element.android.features.roomlist.impl.search.RoomListSearchState import io.element.android.libraries.architecture.Presenter @@ -29,4 +31,7 @@ import io.element.android.libraries.di.SessionScope interface RoomListModule { @Binds fun bindSearchPresenter(presenter: RoomListSearchPresenter): Presenter + + @Binds + fun bindFiltersPresenter(presenter: RoomListFiltersPresenter): Presenter } 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 d8c8e3923a..e8d812c1b9 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 @@ -31,6 +31,8 @@ import io.element.android.features.roomlist.impl.datasource.InviteStateDataSourc 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.filters.RoomListFiltersPresenter +import io.element.android.features.roomlist.impl.filters.RoomListFiltersState +import io.element.android.features.roomlist.impl.filters.aRoomListFiltersState import io.element.android.features.roomlist.impl.migration.InMemoryMigrationScreenStore import io.element.android.features.roomlist.impl.migration.MigrationScreenPresenter import io.element.android.features.roomlist.impl.model.createRoomListRoomSummary @@ -581,7 +583,7 @@ class RoomListPresenterTests { matrixClient = client, migrationScreenStore = InMemoryMigrationScreenStore(), ), - filtersPresenter: RoomListFiltersPresenter = RoomListFiltersPresenter(), + filtersPresenter: Presenter = Presenter { aRoomListFiltersState() }, searchPresenter: Presenter = Presenter { aRoomListSearchState() }, ) = RoomListPresenter( client = client, diff --git a/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/filters/RoomListFiltersPresenterTests.kt b/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/filters/RoomListFiltersPresenterTests.kt new file mode 100644 index 0000000000..b9a9f82922 --- /dev/null +++ b/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/filters/RoomListFiltersPresenterTests.kt @@ -0,0 +1,121 @@ +/* + * 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.roomlist.impl.filters + +import app.cash.molecule.RecompositionMode +import app.cash.molecule.moleculeFlow +import app.cash.turbine.test +import com.google.common.truth.Truth.assertThat +import io.element.android.libraries.matrix.api.roomlist.RoomListService +import io.element.android.libraries.matrix.test.roomlist.FakeRoomListService +import io.element.android.tests.testutils.awaitLastSequentialItem +import kotlinx.coroutines.test.runTest +import org.junit.Test +import io.element.android.libraries.matrix.api.roomlist.RoomListFilter as MatrixRoomListFilter + +class RoomListFiltersPresenterTests { + + @Test + fun `present - initial state`() = runTest { + val presenter = createRoomListFiltersPresenter() + moleculeFlow(RecompositionMode.Immediate) { + presenter.present() + }.test { + awaitItem().let { state -> + assertThat(state.selectedFilters).isEmpty() + assertThat(state.showClearFilterButton).isFalse() + assertThat(state.unselectedFilters).containsExactly( + RoomListFilter.Rooms, + RoomListFilter.People, + RoomListFilter.Unread, + RoomListFilter.Favourites, + ) + } + } + } + + @Test + fun `present - toggle rooms filter`() = runTest { + val roomListService = FakeRoomListService() + val presenter = createRoomListFiltersPresenter(roomListService) + moleculeFlow(RecompositionMode.Immediate) { + presenter.present() + }.test { + awaitItem().eventSink.invoke(RoomListFiltersEvents.ToggleFilter(RoomListFilter.Rooms)) + + awaitLastSequentialItem().let { state -> + + assertThat(state.selectedFilters).containsExactly(RoomListFilter.Rooms) + assertThat(state.showClearFilterButton).isTrue() + assertThat(state.unselectedFilters).containsExactly( + RoomListFilter.Unread, + RoomListFilter.Favourites, + ) + val roomListCurrentFilter = roomListService.allRooms.currentFilter.value as MatrixRoomListFilter.All + assertThat(roomListCurrentFilter.filters).containsExactly( + MatrixRoomListFilter.NonLeft, + MatrixRoomListFilter.Category.Group, + ) + + state.eventSink.invoke(RoomListFiltersEvents.ToggleFilter(RoomListFilter.Rooms)) + } + + awaitLastSequentialItem().let { state -> + assertThat(state.selectedFilters).isEmpty() + assertThat(state.showClearFilterButton).isFalse() + assertThat(state.unselectedFilters).containsExactly( + RoomListFilter.Rooms, + RoomListFilter.People, + RoomListFilter.Unread, + RoomListFilter.Favourites, + ) + val roomListCurrentFilter = roomListService.allRooms.currentFilter.value as MatrixRoomListFilter.All + assertThat(roomListCurrentFilter.filters).containsExactly( + MatrixRoomListFilter.NonLeft, + ) + } + } + } + + @Test + fun `present - clear filters event`() = runTest { + val roomListService = FakeRoomListService() + val presenter = createRoomListFiltersPresenter(roomListService) + moleculeFlow(RecompositionMode.Immediate) { + presenter.present() + }.test { + awaitItem().eventSink.invoke(RoomListFiltersEvents.ToggleFilter(RoomListFilter.Rooms)) + awaitLastSequentialItem().let { state -> + assertThat(state.selectedFilters).isNotEmpty() + assertThat(state.showClearFilterButton).isTrue() + state.eventSink.invoke(RoomListFiltersEvents.ClearSelectedFilters) + } + awaitLastSequentialItem().let { state -> + assertThat(state.selectedFilters).isEmpty() + assertThat(state.showClearFilterButton).isFalse() + } + } + } +} + +fun createRoomListFiltersPresenter( + roomListService: RoomListService = FakeRoomListService(), +): RoomListFiltersPresenter { + return RoomListFiltersPresenter( + roomListService = roomListService, + ) +}