diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeView.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeView.kt index e6056e6636..9c0791230a 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeView.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeView.kt @@ -228,6 +228,7 @@ private fun HomeScaffold( RoomListContentView( contentState = roomListState.contentState, filtersState = roomListState.filtersState, + spaceFiltersState = roomListState.spaceFiltersState, lazyListState = roomsLazyListState, hideInvitesAvatars = roomListState.hideInvitesAvatars, eventSink = roomListState.eventSink, diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/components/RoomListContentView.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/components/RoomListContentView.kt index f3628fce9d..a03399baf7 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/components/RoomListContentView.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/components/RoomListContentView.kt @@ -45,6 +45,8 @@ import io.element.android.features.home.impl.roomlist.RoomListContentState import io.element.android.features.home.impl.roomlist.RoomListContentStateProvider import io.element.android.features.home.impl.roomlist.RoomListEvent import io.element.android.features.home.impl.roomlist.SecurityBannerState +import io.element.android.features.home.impl.spacefilters.SpaceFiltersState +import io.element.android.features.home.impl.spacefilters.anUnselectedSpaceFiltersState import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.components.Button @@ -59,6 +61,7 @@ import kotlinx.collections.immutable.ImmutableList fun RoomListContentView( contentState: RoomListContentState, filtersState: RoomListFiltersState, + spaceFiltersState: SpaceFiltersState, lazyListState: LazyListState, hideInvitesAvatars: Boolean, eventSink: (RoomListEvent) -> Unit, @@ -93,6 +96,7 @@ fun RoomListContentView( state = contentState, hideInvitesAvatars = hideInvitesAvatars, filtersState = filtersState, + spaceFiltersState = spaceFiltersState, eventSink = eventSink, onSetUpRecoveryClick = onSetUpRecoveryClick, onConfirmRecoveryKeyClick = onConfirmRecoveryKeyClick, @@ -172,6 +176,7 @@ private fun RoomsView( state: RoomListContentState.Rooms, hideInvitesAvatars: Boolean, filtersState: RoomListFiltersState, + spaceFiltersState: SpaceFiltersState, eventSink: (RoomListEvent) -> Unit, onSetUpRecoveryClick: () -> Unit, onConfirmRecoveryKeyClick: () -> Unit, @@ -180,9 +185,12 @@ private fun RoomsView( lazyListState: LazyListState, modifier: Modifier = Modifier, ) { - if (state.summaries.isEmpty() && filtersState.hasAnyFilterSelected) { + val isSpaceFilterSelected = spaceFiltersState is SpaceFiltersState.Selected + val hasAnyFilterSelected = filtersState.hasAnyFilterSelected || isSpaceFilterSelected + if (state.summaries.isEmpty() && hasAnyFilterSelected) { EmptyViewForFilterStates( selectedFilters = filtersState.selectedFilters(), + isSpaceFilterSelected = isSpaceFilterSelected, modifier = modifier.fillMaxSize() ) } else { @@ -278,9 +286,10 @@ private fun RoomsViewList( @Composable private fun EmptyViewForFilterStates( selectedFilters: ImmutableList, + isSpaceFilterSelected: Boolean, modifier: Modifier = Modifier, ) { - val emptyStateResources = RoomListFiltersEmptyStateResources.fromSelectedFilters(selectedFilters) ?: return + val emptyStateResources = RoomListFiltersEmptyStateResources.fromSelectedFilters(selectedFilters, isSpaceFilterSelected) ?: return EmptyScaffold( title = emptyStateResources.title, subtitle = emptyStateResources.subtitle, @@ -331,6 +340,7 @@ internal fun RoomListContentViewPreview(@PreviewParameter(RoomListContentStatePr ) } ), + spaceFiltersState = anUnselectedSpaceFiltersState(), hideInvitesAvatars = false, eventSink = {}, onSetUpRecoveryClick = {}, diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/filters/RoomListFiltersEmptyStateResources.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/filters/RoomListFiltersEmptyStateResources.kt index 7381ac308e..084c3c9c0c 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/filters/RoomListFiltersEmptyStateResources.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/filters/RoomListFiltersEmptyStateResources.kt @@ -24,8 +24,12 @@ data class RoomListFiltersEmptyStateResources( /** * Create a [RoomListFiltersEmptyStateResources] from a list of selected filters. */ - fun fromSelectedFilters(selectedFilters: List): RoomListFiltersEmptyStateResources? { + fun fromSelectedFilters(selectedFilters: List, isSpaceFilterSelected: Boolean): RoomListFiltersEmptyStateResources? { return when { + isSpaceFilterSelected -> RoomListFiltersEmptyStateResources( + title = R.string.screen_roomlist_filter_mixed_empty_state_title, + subtitle = R.string.screen_roomlist_filter_mixed_empty_state_subtitle + ) selectedFilters.isEmpty() -> null selectedFilters.size == 1 -> { when (selectedFilters.first()) { diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/filters/RoomListFiltersEvent.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/filters/RoomListFiltersEvent.kt index a34e91e089..d4383f2091 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/filters/RoomListFiltersEvent.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/filters/RoomListFiltersEvent.kt @@ -11,4 +11,5 @@ package io.element.android.features.home.impl.filters sealed interface RoomListFiltersEvent { data class ToggleFilter(val filter: RoomListFilter) : RoomListFiltersEvent data object ClearSelectedFilters : RoomListFiltersEvent + data class SetHiddenFilter(val filters: Set): RoomListFiltersEvent } diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/filters/RoomListFiltersPresenter.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/filters/RoomListFiltersPresenter.kt index e73660219c..08d6fe4ef0 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/filters/RoomListFiltersPresenter.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/filters/RoomListFiltersPresenter.kt @@ -30,6 +30,9 @@ class RoomListFiltersPresenter( is RoomListFiltersEvent.ToggleFilter -> { filterSelectionStrategy.toggle(event.filter) } + is RoomListFiltersEvent.SetHiddenFilter -> { + filterSelectionStrategy.setHiddenFilters(event.filters) + } } } diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/filters/selection/DefaultFilterSelectionStrategy.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/filters/selection/DefaultFilterSelectionStrategy.kt index 877e934727..707a1c83e3 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/filters/selection/DefaultFilterSelectionStrategy.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/filters/selection/DefaultFilterSelectionStrategy.kt @@ -15,17 +15,29 @@ import kotlinx.coroutines.flow.MutableStateFlow @ContributesBinding(SessionScope::class) class DefaultFilterSelectionStrategy : FilterSelectionStrategy { - private val selectedFilters = LinkedHashSet() + private val _selectedFilters = LinkedHashSet() + private val hiddenFilters = LinkedHashSet() + private val selectedFilters + get() = _selectedFilters - hiddenFilters + + private val availableFilters + get() = RoomListFilter.entries.toSet() - hiddenFilters override val filterSelectionStates = MutableStateFlow(buildFilters()) + override fun setHiddenFilters(filters: Set) { + hiddenFilters.clear() + hiddenFilters.addAll(filters) + filterSelectionStates.value = buildFilters() + } + override fun select(filter: RoomListFilter) { - selectedFilters.add(filter) + _selectedFilters.add(filter) filterSelectionStates.value = buildFilters() } override fun deselect(filter: RoomListFilter) { - selectedFilters.remove(filter) + _selectedFilters.remove(filter) filterSelectionStates.value = buildFilters() } @@ -34,7 +46,7 @@ class DefaultFilterSelectionStrategy : FilterSelectionStrategy { } override fun clear() { - selectedFilters.clear() + _selectedFilters.clear() filterSelectionStates.value = buildFilters() } @@ -45,7 +57,7 @@ class DefaultFilterSelectionStrategy : FilterSelectionStrategy { isSelected = true ) } - val unselectedFilters = RoomListFilter.entries - selectedFilters - selectedFilters.flatMap { it.incompatibleFilters }.toSet() + val unselectedFilters = availableFilters - selectedFilters - selectedFilters.flatMap { it.incompatibleFilters }.toSet() val unselectedFilterStates = unselectedFilters.map { FilterSelectionState( filter = it, diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/filters/selection/FilterSelectionStrategy.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/filters/selection/FilterSelectionStrategy.kt index f0877b5e0d..036c786f61 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/filters/selection/FilterSelectionStrategy.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/filters/selection/FilterSelectionStrategy.kt @@ -14,6 +14,7 @@ import kotlinx.coroutines.flow.StateFlow interface FilterSelectionStrategy { val filterSelectionStates: StateFlow> + fun setHiddenFilters(filters: Set) fun select(filter: RoomListFilter) fun deselect(filter: RoomListFilter) fun isSelected(filter: RoomListFilter): Boolean diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListPresenter.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListPresenter.kt index f52e8dafc2..1a16f2f865 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListPresenter.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListPresenter.kt @@ -28,6 +28,9 @@ import im.vector.app.features.analytics.plan.Interaction import io.element.android.features.announcement.api.Announcement import io.element.android.features.announcement.api.AnnouncementService import io.element.android.features.home.impl.datasource.RoomListDataSource +import io.element.android.features.home.impl.filters.RoomListFilter.People +import io.element.android.features.home.impl.filters.RoomListFilter.Rooms +import io.element.android.features.home.impl.filters.RoomListFiltersEvent import io.element.android.features.home.impl.filters.RoomListFiltersState import io.element.android.features.home.impl.filters.into import io.element.android.features.home.impl.search.RoomListSearchEvent @@ -156,13 +159,16 @@ class RoomListPresenter( } } - LaunchedEffect(filtersState.filterSelectionStates, spaceFiltersState.selectedFilter()) { - val selectedFilters = filtersState.filterSelectionStates.mapNotNull { filterState -> - if (!filterState.isSelected) { - return@mapNotNull null - } - filterState.filter.into() + LaunchedEffect(spaceFiltersState.selectedFilter()) { + val hiddenFilters = if (spaceFiltersState is SpaceFiltersState.Selected) { + setOf(People, Rooms) + } else { + emptySet() } + filtersState.eventSink(RoomListFiltersEvent.SetHiddenFilter(hiddenFilters)) + } + LaunchedEffect(filtersState.filterSelectionStates, spaceFiltersState.selectedFilter()) { + val selectedFilters = filtersState.selectedFilters().map { filter -> filter.into() } val selectedSpaceFilter = when (spaceFiltersState) { is SpaceFiltersState.Selected -> RoomListFilter.Identifiers(spaceFiltersState.selectedFilter.descendants) else -> null diff --git a/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/filters/RoomListFiltersEmptyStateResourcesTest.kt b/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/filters/RoomListFiltersEmptyStateResourcesTest.kt index 250f43ee8f..1762d0d6bf 100644 --- a/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/filters/RoomListFiltersEmptyStateResourcesTest.kt +++ b/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/filters/RoomListFiltersEmptyStateResourcesTest.kt @@ -16,14 +16,14 @@ class RoomListFiltersEmptyStateResourcesTest { @Test fun `fromSelectedFilters should return null when selectedFilters is empty`() { val selectedFilters = emptyList() - val result = RoomListFiltersEmptyStateResources.fromSelectedFilters(selectedFilters) + val result = RoomListFiltersEmptyStateResources.fromSelectedFilters(selectedFilters, isSpaceFilterSelected = false) assertThat(result).isNull() } @Test fun `fromSelectedFilters should return exact RoomListFiltersEmptyStateResources when selectedFilters has only unread filter`() { val selectedFilters = listOf(RoomListFilter.Unread) - val result = RoomListFiltersEmptyStateResources.fromSelectedFilters(selectedFilters) + val result = RoomListFiltersEmptyStateResources.fromSelectedFilters(selectedFilters, isSpaceFilterSelected = false) assertThat(result).isNotNull() assertThat(result?.title).isEqualTo(R.string.screen_roomlist_filter_unreads_empty_state_title) assertThat(result?.subtitle).isEqualTo(R.string.screen_roomlist_filter_mixed_empty_state_subtitle) @@ -32,7 +32,7 @@ class RoomListFiltersEmptyStateResourcesTest { @Test fun `fromSelectedFilters should return exact RoomListFiltersEmptyStateResources when selectedFilters has only people filter`() { val selectedFilters = listOf(RoomListFilter.People) - val result = RoomListFiltersEmptyStateResources.fromSelectedFilters(selectedFilters) + val result = RoomListFiltersEmptyStateResources.fromSelectedFilters(selectedFilters, isSpaceFilterSelected = false) assertThat(result).isNotNull() assertThat(result?.title).isEqualTo(R.string.screen_roomlist_filter_people_empty_state_title) assertThat(result?.subtitle).isEqualTo(R.string.screen_roomlist_filter_mixed_empty_state_subtitle) @@ -41,7 +41,7 @@ class RoomListFiltersEmptyStateResourcesTest { @Test fun `fromSelectedFilters should return exact RoomListFiltersEmptyStateResources when selectedFilters has only rooms filter`() { val selectedFilters = listOf(RoomListFilter.Rooms) - val result = RoomListFiltersEmptyStateResources.fromSelectedFilters(selectedFilters) + val result = RoomListFiltersEmptyStateResources.fromSelectedFilters(selectedFilters, isSpaceFilterSelected = false) assertThat(result).isNotNull() assertThat(result?.title).isEqualTo(R.string.screen_roomlist_filter_rooms_empty_state_title) assertThat(result?.subtitle).isEqualTo(R.string.screen_roomlist_filter_mixed_empty_state_subtitle) @@ -50,7 +50,7 @@ class RoomListFiltersEmptyStateResourcesTest { @Test fun `fromSelectedFilters should return exact RoomListFiltersEmptyStateResources when selectedFilters has only favourites filter`() { val selectedFilters = listOf(RoomListFilter.Favourites) - val result = RoomListFiltersEmptyStateResources.fromSelectedFilters(selectedFilters) + val result = RoomListFiltersEmptyStateResources.fromSelectedFilters(selectedFilters, isSpaceFilterSelected = false) assertThat(result).isNotNull() assertThat(result?.title).isEqualTo(R.string.screen_roomlist_filter_favourites_empty_state_title) assertThat(result?.subtitle).isEqualTo(R.string.screen_roomlist_filter_favourites_empty_state_subtitle) @@ -59,7 +59,7 @@ class RoomListFiltersEmptyStateResourcesTest { @Test fun `fromSelectedFilters should return exact RoomListFiltersEmptyStateResources when selectedFilters has only invites filter`() { val selectedFilters = listOf(RoomListFilter.Invites) - val result = RoomListFiltersEmptyStateResources.fromSelectedFilters(selectedFilters) + val result = RoomListFiltersEmptyStateResources.fromSelectedFilters(selectedFilters, isSpaceFilterSelected = false) assertThat(result).isNotNull() assertThat(result?.title).isEqualTo(R.string.screen_roomlist_filter_invites_empty_state_title) assertThat(result?.subtitle).isEqualTo(R.string.screen_roomlist_filter_mixed_empty_state_subtitle) @@ -68,7 +68,15 @@ class RoomListFiltersEmptyStateResourcesTest { @Test fun `fromSelectedFilters should return exact RoomListFiltersEmptyStateResources when selectedFilters has multiple filters`() { val selectedFilters = listOf(RoomListFilter.Unread, RoomListFilter.People, RoomListFilter.Rooms, RoomListFilter.Favourites) - val result = RoomListFiltersEmptyStateResources.fromSelectedFilters(selectedFilters) + val result = RoomListFiltersEmptyStateResources.fromSelectedFilters(selectedFilters, isSpaceFilterSelected = false) + assertThat(result).isNotNull() + assertThat(result?.title).isEqualTo(R.string.screen_roomlist_filter_mixed_empty_state_title) + assertThat(result?.subtitle).isEqualTo(R.string.screen_roomlist_filter_mixed_empty_state_subtitle) + } + + @Test + fun `fromSelectedFilters should return exact RoomListFiltersEmptyStateResources when isSpaceFilterSelected is true`() { + val result = RoomListFiltersEmptyStateResources.fromSelectedFilters(emptyList(), isSpaceFilterSelected = true) assertThat(result).isNotNull() assertThat(result?.title).isEqualTo(R.string.screen_roomlist_filter_mixed_empty_state_title) assertThat(result?.subtitle).isEqualTo(R.string.screen_roomlist_filter_mixed_empty_state_subtitle)