Model SpaceFilters ui states

This commit is contained in:
ganfra
2026-02-02 16:15:54 +01:00
parent 908616e8e8
commit e2e49ba384
4 changed files with 161 additions and 12 deletions

View File

@@ -7,4 +7,22 @@
package io.element.android.features.home.impl.spacefilters
sealed interface SpaceFiltersEvent
import io.element.android.libraries.matrix.api.spaces.SpaceServiceFilter
sealed interface SpaceFiltersEvent {
// Only valid in Unselected state
sealed interface Unselected : SpaceFiltersEvent {
data object ShowFilters : Unselected
}
// Only valid in Selecting state
sealed interface Selecting : SpaceFiltersEvent {
data object Cancel : Selecting
data class SelectFilter(val spaceFilter: SpaceServiceFilter) : Selecting
}
// Only valid in Selected state
sealed interface Selected : SpaceFiltersEvent {
data object ClearSelection : Selected
}
}

View File

@@ -8,15 +8,87 @@
package io.element.android.features.home.impl.spacefilters
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import dev.zacsweers.metro.Inject
import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.featureflag.api.FeatureFlagService
import io.element.android.libraries.featureflag.api.FeatureFlags
import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.spaces.SpaceServiceFilter
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.flow.map
@Inject
class SpaceFiltersPresenter : Presenter<SpaceFiltersState> {
class SpaceFiltersPresenter(
private val featureFlagService: FeatureFlagService,
private val matrixClient: MatrixClient,
) : Presenter<SpaceFiltersState> {
@Composable
override fun present(): SpaceFiltersState {
return SpaceFiltersState(
eventSink = {},
)
val isFeatureEnabled by featureFlagService
.isFeatureEnabledFlow(FeatureFlags.RoomListSpaceFilters)
.collectAsState(initial = false)
if (!isFeatureEnabled) {
return SpaceFiltersState.Disabled
}
val availableFilters by remember {
matrixClient.spaceService.spaceFiltersFlow.map { it.toImmutableList() }
}.collectAsState(initial = persistentListOf())
var selectionMode by remember { mutableStateOf<SelectionMode>(SelectionMode.Unselected) }
fun handleUnselectedEvent(event: SpaceFiltersEvent.Unselected) {
when (event) {
SpaceFiltersEvent.Unselected.ShowFilters -> {
selectionMode = SelectionMode.Selecting
}
}
}
fun handleSelectingEvent(event: SpaceFiltersEvent.Selecting) {
when (event) {
SpaceFiltersEvent.Selecting.Cancel -> {
selectionMode = SelectionMode.Unselected
}
is SpaceFiltersEvent.Selecting.SelectFilter -> {
selectionMode = SelectionMode.Selected(event.spaceFilter)
}
}
}
fun handleSelectedEvent(event: SpaceFiltersEvent.Selected) {
when (event) {
SpaceFiltersEvent.Selected.ClearSelection -> {
selectionMode = SelectionMode.Unselected
}
}
}
return when (val mode = selectionMode) {
SelectionMode.Unselected -> SpaceFiltersState.Unselected(
eventSink = ::handleUnselectedEvent,
)
SelectionMode.Selecting -> SpaceFiltersState.Selecting(
availableFilters = availableFilters,
eventSink = ::handleSelectingEvent,
)
is SelectionMode.Selected -> SpaceFiltersState.Selected(
selectedFilter = mode.filter,
eventSink = ::handleSelectedEvent,
)
}
}
}
private sealed interface SelectionMode {
data object Unselected : SelectionMode
data object Selecting : SelectionMode
data class Selected(val filter: SpaceServiceFilter) : SelectionMode
}

View File

@@ -7,6 +7,23 @@
package io.element.android.features.home.impl.spacefilters
data class SpaceFiltersState(
val eventSink: (SpaceFiltersEvent) -> Unit,
)
import io.element.android.libraries.matrix.api.spaces.SpaceServiceFilter
import kotlinx.collections.immutable.ImmutableList
sealed interface SpaceFiltersState {
data object Disabled : SpaceFiltersState
data class Unselected(
val eventSink: (SpaceFiltersEvent.Unselected) -> Unit,
) : SpaceFiltersState
data class Selecting(
val availableFilters: ImmutableList<SpaceServiceFilter>,
val eventSink: (SpaceFiltersEvent.Selecting) -> Unit,
) : SpaceFiltersState
data class Selected(
val selectedFilter: SpaceServiceFilter,
val eventSink: (SpaceFiltersEvent.Selected) -> Unit,
) : SpaceFiltersState
}

View File

@@ -8,14 +8,56 @@
package io.element.android.features.home.impl.spacefilters
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.spaces.SpaceServiceFilter
import io.element.android.libraries.previewutils.room.aSpaceRoom
import kotlinx.collections.immutable.persistentListOf
class SpaceFiltersStateProvider : PreviewParameterProvider<SpaceFiltersState> {
override val values: Sequence<SpaceFiltersState>
get() = sequenceOf(aSpaceFiltersState())
get() = sequenceOf(
aDisabledSpaceFiltersState(),
anUnselectedSpaceFiltersState(),
aSelectingSpaceFiltersState(),
aSelectedSpaceFiltersState(),
)
}
fun aSpaceFiltersState(
eventSink: (SpaceFiltersEvent) -> Unit = {},
) = SpaceFiltersState(
fun aDisabledSpaceFiltersState() = SpaceFiltersState.Disabled
fun anUnselectedSpaceFiltersState(
eventSink: (SpaceFiltersEvent.Unselected) -> Unit = {},
) = SpaceFiltersState.Unselected(
eventSink = eventSink,
)
fun aSelectingSpaceFiltersState(
availableFilters: List<SpaceServiceFilter> = listOf(
aSpaceServiceFilter(displayName = "Work"),
aSpaceServiceFilter(displayName = "Personal", roomId = RoomId("!personal:example.com")),
aSpaceServiceFilter(displayName = "Gaming", roomId = RoomId("!gaming:example.com")),
),
eventSink: (SpaceFiltersEvent.Selecting) -> Unit = {},
) = SpaceFiltersState.Selecting(
availableFilters = persistentListOf(*availableFilters.toTypedArray()),
eventSink = eventSink,
)
fun aSelectedSpaceFiltersState(
selectedFilter: SpaceServiceFilter = aSpaceServiceFilter(displayName = "Work"),
eventSink: (SpaceFiltersEvent.Selected) -> Unit = {},
) = SpaceFiltersState.Selected(
selectedFilter = selectedFilter,
eventSink = eventSink,
)
fun aSpaceServiceFilter(
displayName: String = "Space",
roomId: RoomId = RoomId("!space:example.com"),
level: Int = 0,
descendants: List<RoomId> = emptyList(),
) = SpaceServiceFilter(
spaceRoom = aSpaceRoom(displayName = displayName, roomId = roomId),
level = level,
descendants = descendants,
)