RoomListFilters: extract logic of selection/deselection and tweak a bit the animations.

This commit is contained in:
ganfra 2024-03-05 11:29:58 +01:00
parent dc5f93ef2f
commit 2da9bc198a
11 changed files with 211 additions and 96 deletions

View file

@ -20,12 +20,12 @@ import io.element.android.features.roomlist.impl.R
/** /**
* Enum class representing the different filters that can be applied to the room list. * Enum class representing the different filters that can be applied to the room list.
* Order is important. * Order is important, it'll be used as initial order in the UI.
*/ */
enum class RoomListFilter(val stringResource: Int) { enum class RoomListFilter(val stringResource: Int) {
Rooms(R.string.screen_roomlist_filter_rooms),
People(R.string.screen_roomlist_filter_people),
Unread(R.string.screen_roomlist_filter_unreads), Unread(R.string.screen_roomlist_filter_unreads),
People(R.string.screen_roomlist_filter_people),
Rooms(R.string.screen_roomlist_filter_rooms),
Favourites(R.string.screen_roomlist_filter_favourites); Favourites(R.string.screen_roomlist_filter_favourites);
val oppositeFilter: RoomListFilter? val oppositeFilter: RoomListFilter?

View file

@ -17,6 +17,6 @@
package io.element.android.features.roomlist.impl.filters package io.element.android.features.roomlist.impl.filters
sealed interface RoomListFiltersEvents { sealed interface RoomListFiltersEvents {
data object ClearSelectedFilters : RoomListFiltersEvents
data class ToggleFilter(val filter: RoomListFilter) : RoomListFiltersEvents data class ToggleFilter(val filter: RoomListFilter) : RoomListFiltersEvents
data object ClearSelectedFilters : RoomListFiltersEvents
} }

View file

@ -20,9 +20,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import io.element.android.features.roomlist.impl.filters.selection.FilterSelectionStrategy
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.featureflag.api.FeatureFlagService import io.element.android.libraries.featureflag.api.FeatureFlagService
import io.element.android.libraries.featureflag.api.FeatureFlags import io.element.android.libraries.featureflag.api.FeatureFlags
@ -34,50 +32,39 @@ import io.element.android.libraries.matrix.api.roomlist.RoomListFilter as Matrix
class RoomListFiltersPresenter @Inject constructor( class RoomListFiltersPresenter @Inject constructor(
private val roomListService: RoomListService, private val roomListService: RoomListService,
private val featureFlagService: FeatureFlagService, private val featureFlagService: FeatureFlagService,
private val filterSelectionStrategy: FilterSelectionStrategy,
) : Presenter<RoomListFiltersState> { ) : Presenter<RoomListFiltersState> {
@Composable @Composable
override fun present(): RoomListFiltersState { override fun present(): RoomListFiltersState {
val isFeatureEnabled by featureFlagService.isFeatureEnabledFlow(FeatureFlags.RoomListFilters).collectAsState(false)
var unselectedFilters: Set<RoomListFilter> by rememberSaveable {
mutableStateOf(RoomListFilter.entries.toSet())
}
var selectedFilters: Set<RoomListFilter> by rememberSaveable {
mutableStateOf(emptySet())
}
fun updateFilters(newSelectedFilters: Set<RoomListFilter>) { val isFeatureEnabled by featureFlagService.isFeatureEnabledFlow(FeatureFlags.RoomListFilters).collectAsState(false)
selectedFilters = newSelectedFilters val filters by filterSelectionStrategy.filterSelectionStates.collectAsState()
unselectedFilters = RoomListFilter.entries.toSet() -
selectedFilters -
selectedFilters.mapNotNull { it.oppositeFilter }.toSet()
}
fun handleEvents(event: RoomListFiltersEvents) { fun handleEvents(event: RoomListFiltersEvents) {
when (event) { when (event) {
is RoomListFiltersEvents.ToggleFilter -> {
val newSelectedFilters = if (selectedFilters.contains(event.filter)) {
selectedFilters - event.filter
} else {
selectedFilters + event.filter
}
updateFilters(newSelectedFilters)
}
RoomListFiltersEvents.ClearSelectedFilters -> { RoomListFiltersEvents.ClearSelectedFilters -> {
updateFilters(newSelectedFilters = emptySet()) filterSelectionStrategy.clear()
}
is RoomListFiltersEvents.ToggleFilter -> {
filterSelectionStrategy.toggle(event.filter)
} }
} }
} }
LaunchedEffect(isFeatureEnabled) { LaunchedEffect(isFeatureEnabled) {
if (!isFeatureEnabled) { if (!isFeatureEnabled) {
updateFilters(emptySet()) filterSelectionStrategy.clear()
} }
} }
LaunchedEffect(selectedFilters) { LaunchedEffect(filters) {
val allRoomsFilter = MatrixRoomListFilter.All( val allRoomsFilter = MatrixRoomListFilter.All(
selectedFilters.map { roomListFilter -> filters
when (roomListFilter) { .filter { it.isSelected }
.map { roomListFilter ->
when (roomListFilter.filter) {
RoomListFilter.Rooms -> MatrixRoomListFilter.Category.Group RoomListFilter.Rooms -> MatrixRoomListFilter.Category.Group
RoomListFilter.People -> MatrixRoomListFilter.Category.People RoomListFilter.People -> MatrixRoomListFilter.Category.People
RoomListFilter.Unread -> MatrixRoomListFilter.Unread RoomListFilter.Unread -> MatrixRoomListFilter.Unread
@ -88,9 +75,9 @@ class RoomListFiltersPresenter @Inject constructor(
roomListService.allRooms.updateFilter(allRoomsFilter) roomListService.allRooms.updateFilter(allRoomsFilter)
} }
return RoomListFiltersState( return RoomListFiltersState(
unselectedFilters = unselectedFilters.toPersistentList(), filterSelectionStates = filters.toPersistentList(),
selectedFilters = selectedFilters.toPersistentList(),
isFeatureEnabled = isFeatureEnabled, isFeatureEnabled = isFeatureEnabled,
eventSink = ::handleEvents eventSink = ::handleEvents
) )

View file

@ -16,13 +16,13 @@
package io.element.android.features.roomlist.impl.filters package io.element.android.features.roomlist.impl.filters
import io.element.android.features.roomlist.impl.filters.selection.FilterSelectionState
import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableList
data class RoomListFiltersState( data class RoomListFiltersState(
val unselectedFilters: ImmutableList<RoomListFilter>, val filterSelectionStates: ImmutableList<FilterSelectionState>,
val selectedFilters: ImmutableList<RoomListFilter>,
val isFeatureEnabled: Boolean, val isFeatureEnabled: Boolean,
val eventSink: (RoomListFiltersEvents) -> Unit, val eventSink: (RoomListFiltersEvents) -> Unit,
) { ) {
val hasAnyFilterSelected = selectedFilters.isNotEmpty() val hasAnyFilterSelected = filterSelectionStates.any { it.isSelected }
} }

View file

@ -17,8 +17,7 @@
package io.element.android.features.roomlist.impl.filters package io.element.android.features.roomlist.impl.filters
import androidx.compose.ui.tooling.preview.PreviewParameterProvider import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import kotlinx.collections.immutable.ImmutableList import io.element.android.features.roomlist.impl.filters.selection.FilterSelectionState
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList import kotlinx.collections.immutable.toImmutableList
class RoomListFiltersStateProvider : PreviewParameterProvider<RoomListFiltersState> { class RoomListFiltersStateProvider : PreviewParameterProvider<RoomListFiltersState> {
@ -26,20 +25,17 @@ class RoomListFiltersStateProvider : PreviewParameterProvider<RoomListFiltersSta
get() = sequenceOf( get() = sequenceOf(
aRoomListFiltersState(), aRoomListFiltersState(),
aRoomListFiltersState( aRoomListFiltersState(
selectedFilters = persistentListOf(RoomListFilter.Rooms, RoomListFilter.Favourites), filterSelectionStates = RoomListFilter.entries.map { FilterSelectionState(it, isSelected = true) }
unselectedFilters = persistentListOf(RoomListFilter.Unread),
), ),
) )
} }
fun aRoomListFiltersState( fun aRoomListFiltersState(
unselectedFilters: ImmutableList<RoomListFilter> = RoomListFilter.entries.toImmutableList(), filterSelectionStates: List<FilterSelectionState> = RoomListFilter.entries.map { FilterSelectionState(it, isSelected = false) },
selectedFilters: ImmutableList<RoomListFilter> = persistentListOf(),
isFeatureEnabled: Boolean = true, isFeatureEnabled: Boolean = true,
eventSink: (RoomListFiltersEvents) -> Unit = {}, eventSink: (RoomListFiltersEvents) -> Unit = {},
) = RoomListFiltersState( ) = RoomListFiltersState(
unselectedFilters = unselectedFilters, filterSelectionStates = filterSelectionStates.toImmutableList(),
selectedFilters = selectedFilters,
isFeatureEnabled = isFeatureEnabled, isFeatureEnabled = isFeatureEnabled,
eventSink = eventSink, eventSink = eventSink,
) )

View file

@ -17,6 +17,7 @@
package io.element.android.features.roomlist.impl.filters package io.element.android.features.roomlist.impl.filters
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.tween
import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
@ -25,7 +26,6 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.lazy.rememberLazyListState
@ -34,6 +34,7 @@ import androidx.compose.material3.FilterChip
import androidx.compose.material3.FilterChipDefaults import androidx.compose.material3.FilterChipDefaults
import androidx.compose.material3.minimumInteractiveComponentSize import androidx.compose.material3.minimumInteractiveComponentSize
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
@ -51,18 +52,19 @@ import io.element.android.libraries.designsystem.theme.components.IconButton
import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.testtags.TestTags import io.element.android.libraries.testtags.TestTags
import io.element.android.libraries.testtags.testTag import io.element.android.libraries.testtags.testTag
import kotlinx.collections.immutable.ImmutableList
@OptIn(ExperimentalFoundationApi::class)
@Composable @Composable
fun RoomListFiltersView( fun RoomListFiltersView(
state: RoomListFiltersState, state: RoomListFiltersState,
modifier: Modifier = Modifier modifier: Modifier = Modifier
) { ) {
fun onClearFiltersClicked() { fun onClearFiltersClicked() {
state.eventSink(RoomListFiltersEvents.ClearSelectedFilters) state.eventSink(RoomListFiltersEvents.ClearSelectedFilters)
} }
fun onFilterClicked(filter: RoomListFilter) { fun onToggleFilter(filter: RoomListFilter) {
state.eventSink(RoomListFiltersEvents.ToggleFilter(filter)) state.eventSink(RoomListFiltersEvents.ToggleFilter(filter))
} }
@ -71,12 +73,14 @@ fun RoomListFiltersView(
modifier = modifier.padding(start = startPadding, end = 16.dp), modifier = modifier.padding(start = startPadding, end = 16.dp),
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
) { ) {
AnimatedVisibility(visible = state.hasAnyFilterSelected) { AnimatedVisibility(visible = state.hasAnyFilterSelected) {
RoomListClearFiltersButton( RoomListClearFiltersButton(
modifier = Modifier.testTag(TestTags.homeScreenClearFilters), modifier = Modifier.testTag(TestTags.homeScreenClearFilters),
onClick = ::onClearFiltersClicked onClick = ::onClearFiltersClicked
) )
} }
val lazyListState = rememberLazyListState() val lazyListState = rememberLazyListState()
val fadingEdgesBrush = horizontalFadingEdgesBrush( val fadingEdgesBrush = horizontalFadingEdgesBrush(
showLeft = lazyListState.canScrollBackward, showLeft = lazyListState.canScrollBackward,
@ -89,26 +93,25 @@ fun RoomListFiltersView(
state = lazyListState, state = lazyListState,
horizontalArrangement = Arrangement.spacedBy(8.dp) horizontalArrangement = Arrangement.spacedBy(8.dp)
) { ) {
roomListFilters(state.selectedFilters, selected = true, onClick = ::onFilterClicked) items(
roomListFilters(state.unselectedFilters, selected = false, onClick = ::onFilterClicked) items = state.filterSelectionStates,
key = { it.filter.ordinal }
) { filterWithSelection ->
RoomListFilterView(
modifier = Modifier.animateItemPlacement(
animationSpec = tween(200),
),
roomListFilter = filterWithSelection.filter,
selected = filterWithSelection.isSelected,
onClick = ::onToggleFilter,
)
}
}
LaunchedEffect(state.filterSelectionStates) {
if (lazyListState.canScrollBackward) {
lazyListState.animateScrollToItem(0)
}
} }
}
}
@OptIn(ExperimentalFoundationApi::class)
private fun LazyListScope.roomListFilters(
filters: ImmutableList<RoomListFilter>,
selected: Boolean,
onClick: (RoomListFilter) -> Unit,
) {
items(
items = filters,
) { filter ->
RoomListFilterView(
roomListFilter = filter,
selected = selected,
onClick = onClick,
)
} }
} }

View file

@ -0,0 +1,67 @@
/*
* 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.selection
import com.squareup.anvil.annotations.ContributesBinding
import io.element.android.features.roomlist.impl.filters.RoomListFilter
import io.element.android.libraries.di.SessionScope
import kotlinx.coroutines.flow.MutableStateFlow
import javax.inject.Inject
@ContributesBinding(SessionScope::class)
class DefaultFilterSelectionStrategy @Inject constructor() : FilterSelectionStrategy {
private val selectedFilters = LinkedHashSet<RoomListFilter>()
override val filterSelectionStates = MutableStateFlow(buildFilters())
override fun select(filter: RoomListFilter) {
selectedFilters.add(filter)
filterSelectionStates.value = buildFilters()
}
override fun deselect(filter: RoomListFilter) {
selectedFilters.remove(filter)
filterSelectionStates.value = buildFilters()
}
override fun isSelected(filter: RoomListFilter): Boolean {
return selectedFilters.contains(filter)
}
override fun clear() {
selectedFilters.clear()
filterSelectionStates.value = buildFilters()
}
private fun buildFilters(): Set<FilterSelectionState> {
val selectedFilterStates = selectedFilters.map {
FilterSelectionState(
filter = it,
isSelected = true
)
}
val unselectedFilters = RoomListFilter.entries - selectedFilters - selectedFilters.mapNotNull { it.oppositeFilter }.toSet()
val unselectedFilterStates = unselectedFilters.map {
FilterSelectionState(
filter = it,
isSelected = false
)
}
return (selectedFilterStates + unselectedFilterStates).toSet()
}
}

View file

@ -0,0 +1,24 @@
/*
* 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.selection
import io.element.android.features.roomlist.impl.filters.RoomListFilter
data class FilterSelectionState(
val filter: RoomListFilter,
val isSelected: Boolean,
)

View file

@ -0,0 +1,38 @@
/*
* 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.selection
import io.element.android.features.roomlist.impl.filters.RoomListFilter
import kotlinx.coroutines.flow.StateFlow
interface FilterSelectionStrategy {
val filterSelectionStates: StateFlow<Set<FilterSelectionState>>
fun select(filter: RoomListFilter)
fun deselect(filter: RoomListFilter)
fun isSelected(filter: RoomListFilter): Boolean
fun clear()
fun toggle(filter: RoomListFilter) {
if (isSelected(filter)) {
deselect(filter)
} else {
select(filter)
}
}
}

View file

@ -20,6 +20,8 @@ import app.cash.molecule.RecompositionMode
import app.cash.molecule.moleculeFlow import app.cash.molecule.moleculeFlow
import app.cash.turbine.test import app.cash.turbine.test
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import io.element.android.features.roomlist.impl.filters.selection.DefaultFilterSelectionStrategy
import io.element.android.features.roomlist.impl.filters.selection.FilterSelectionState
import io.element.android.libraries.featureflag.api.FeatureFlagService import io.element.android.libraries.featureflag.api.FeatureFlagService
import io.element.android.libraries.featureflag.test.FakeFeatureFlagService import io.element.android.libraries.featureflag.test.FakeFeatureFlagService
import io.element.android.libraries.matrix.api.roomlist.RoomListService import io.element.android.libraries.matrix.api.roomlist.RoomListService
@ -37,13 +39,12 @@ class RoomListFiltersPresenterTests {
presenter.present() presenter.present()
}.test { }.test {
awaitItem().let { state -> awaitItem().let { state ->
assertThat(state.selectedFilters).isEmpty()
assertThat(state.hasAnyFilterSelected).isFalse() assertThat(state.hasAnyFilterSelected).isFalse()
assertThat(state.unselectedFilters).containsExactly( assertThat(state.filterSelectionStates).containsExactly(
RoomListFilter.Rooms, filterSelectionState(RoomListFilter.Unread, false),
RoomListFilter.People, filterSelectionState(RoomListFilter.People, false),
RoomListFilter.Unread, filterSelectionState(RoomListFilter.Rooms, false),
RoomListFilter.Favourites, filterSelectionState(RoomListFilter.Favourites, false),
) )
} }
cancelAndIgnoreRemainingEvents() cancelAndIgnoreRemainingEvents()
@ -58,32 +59,29 @@ class RoomListFiltersPresenterTests {
presenter.present() presenter.present()
}.test { }.test {
awaitItem().eventSink.invoke(RoomListFiltersEvents.ToggleFilter(RoomListFilter.Rooms)) awaitItem().eventSink.invoke(RoomListFiltersEvents.ToggleFilter(RoomListFilter.Rooms))
awaitLastSequentialItem().let { state -> awaitLastSequentialItem().let { state ->
assertThat(state.selectedFilters).containsExactly(RoomListFilter.Rooms)
assertThat(state.hasAnyFilterSelected).isTrue() assertThat(state.hasAnyFilterSelected).isTrue()
assertThat(state.unselectedFilters).containsExactly( assertThat(state.filterSelectionStates).containsExactly(
RoomListFilter.Unread, filterSelectionState(RoomListFilter.Rooms, true),
RoomListFilter.Favourites, filterSelectionState(RoomListFilter.Unread, false),
) filterSelectionState(RoomListFilter.Favourites, false),
).inOrder()
val roomListCurrentFilter = roomListService.allRooms.currentFilter.value as MatrixRoomListFilter.All val roomListCurrentFilter = roomListService.allRooms.currentFilter.value as MatrixRoomListFilter.All
assertThat(roomListCurrentFilter.filters).containsExactly( assertThat(roomListCurrentFilter.filters).containsExactly(
MatrixRoomListFilter.Category.Group, MatrixRoomListFilter.Category.Group,
) )
state.eventSink.invoke(RoomListFiltersEvents.ToggleFilter(RoomListFilter.Rooms)) state.eventSink.invoke(RoomListFiltersEvents.ToggleFilter(RoomListFilter.Rooms))
} }
awaitLastSequentialItem().let { state -> awaitLastSequentialItem().let { state ->
assertThat(state.selectedFilters).isEmpty()
assertThat(state.hasAnyFilterSelected).isFalse() assertThat(state.hasAnyFilterSelected).isFalse()
assertThat(state.unselectedFilters).containsExactly( assertThat(state.filterSelectionStates).containsExactly(
RoomListFilter.Rooms, filterSelectionState(RoomListFilter.Unread, false),
RoomListFilter.People, filterSelectionState(RoomListFilter.People, false),
RoomListFilter.Unread, filterSelectionState(RoomListFilter.Rooms, false),
RoomListFilter.Favourites, filterSelectionState(RoomListFilter.Favourites, false),
) ).inOrder()
val roomListCurrentFilter = roomListService.allRooms.currentFilter.value as MatrixRoomListFilter.All val roomListCurrentFilter = roomListService.allRooms.currentFilter.value as MatrixRoomListFilter.All
assertThat(roomListCurrentFilter.filters).isEmpty() assertThat(roomListCurrentFilter.filters).isEmpty()
} }
@ -99,24 +97,28 @@ class RoomListFiltersPresenterTests {
}.test { }.test {
awaitItem().eventSink.invoke(RoomListFiltersEvents.ToggleFilter(RoomListFilter.Rooms)) awaitItem().eventSink.invoke(RoomListFiltersEvents.ToggleFilter(RoomListFilter.Rooms))
awaitLastSequentialItem().let { state -> awaitLastSequentialItem().let { state ->
assertThat(state.selectedFilters).isNotEmpty()
assertThat(state.hasAnyFilterSelected).isTrue() assertThat(state.hasAnyFilterSelected).isTrue()
state.eventSink.invoke(RoomListFiltersEvents.ClearSelectedFilters) state.eventSink.invoke(RoomListFiltersEvents.ClearSelectedFilters)
} }
awaitLastSequentialItem().let { state -> awaitLastSequentialItem().let { state ->
assertThat(state.selectedFilters).isEmpty()
assertThat(state.hasAnyFilterSelected).isFalse() assertThat(state.hasAnyFilterSelected).isFalse()
} }
} }
} }
} }
fun createRoomListFiltersPresenter( private fun filterSelectionState(filter: RoomListFilter, selected: Boolean) = FilterSelectionState(
filter = filter,
isSelected = selected,
)
private fun createRoomListFiltersPresenter(
roomListService: RoomListService = FakeRoomListService(), roomListService: RoomListService = FakeRoomListService(),
featureFlagService: FeatureFlagService = FakeFeatureFlagService(), featureFlagService: FeatureFlagService = FakeFeatureFlagService(),
): RoomListFiltersPresenter { ): RoomListFiltersPresenter {
return RoomListFiltersPresenter( return RoomListFiltersPresenter(
roomListService = roomListService, roomListService = roomListService,
featureFlagService = featureFlagService, featureFlagService = featureFlagService,
filterSelectionStrategy = DefaultFilterSelectionStrategy(),
) )
} }

View file

@ -20,12 +20,11 @@ import androidx.activity.ComponentActivity
import androidx.compose.ui.test.junit4.createAndroidComposeRule import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
import io.element.android.features.roomlist.impl.R import io.element.android.features.roomlist.impl.R
import io.element.android.features.roomlist.impl.filters.selection.FilterSelectionState
import io.element.android.libraries.testtags.TestTags import io.element.android.libraries.testtags.TestTags
import io.element.android.tests.testutils.EventsRecorder import io.element.android.tests.testutils.EventsRecorder
import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.clickOn
import io.element.android.tests.testutils.pressTag import io.element.android.tests.testutils.pressTag
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
@ -56,8 +55,7 @@ class RoomListFiltersViewTests {
rule.setContent { rule.setContent {
RoomListFiltersView( RoomListFiltersView(
state = aRoomListFiltersState( state = aRoomListFiltersState(
unselectedFilters = persistentListOf(), filterSelectionStates = RoomListFilter.entries.map { FilterSelectionState(it, isSelected = true) },
selectedFilters = RoomListFilter.entries.toImmutableList(),
eventSink = eventsRecorder eventSink = eventsRecorder
), ),
) )