From eb97bce6c68b0713ab29fa569061bdf0760bffb4 Mon Sep 17 00:00:00 2001 From: Joe Groocock Date: Tue, 7 May 2024 01:10:03 +0100 Subject: [PATCH 1/3] Ensure selected/deselected filters stay on top This looks a little more "sane", and more closely matches what iOS does with it's filter chips. This has to manually track which filters were "just-deselected" and move those even higher up the z stack to ensure they appear above even when sliding right. This is because the order is determined by the position left-to-right of the _final_ destination of the chip. In this case we want anything that's either currently selected, or was selected and is still fading out to appear on top. Signed-off-by: Joe Groocock --- changelog.d/2809.bugfix | 1 + .../impl/filters/RoomListFiltersView.kt | 21 +++++++++++++++---- 2 files changed, 18 insertions(+), 4 deletions(-) create mode 100644 changelog.d/2809.bugfix diff --git a/changelog.d/2809.bugfix b/changelog.d/2809.bugfix new file mode 100644 index 0000000000..70e3079686 --- /dev/null +++ b/changelog.d/2809.bugfix @@ -0,0 +1 @@ +Render selected/deselected room list filters on top diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/filters/RoomListFiltersView.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/filters/RoomListFiltersView.kt index fcdc260c6e..be7448c4a0 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/filters/RoomListFiltersView.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/filters/RoomListFiltersView.kt @@ -32,12 +32,15 @@ import androidx.compose.material3.FilterChip import androidx.compose.material3.FilterChipDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp +import androidx.compose.ui.zIndex import io.element.android.compound.theme.ElementTheme import io.element.android.compound.tokens.generated.CompoundIcons import io.element.android.libraries.designsystem.preview.ElementPreview @@ -62,6 +65,7 @@ fun RoomListFiltersView( } val lazyListState = rememberLazyListState() + val previousFilters = remember { mutableStateOf(listOf()) } LazyRow( contentPadding = PaddingValues(start = 8.dp, end = 16.dp), modifier = modifier.fillMaxWidth(), @@ -75,17 +79,26 @@ fun RoomListFiltersView( modifier = Modifier .padding(start = 8.dp) .testTag(TestTags.homeScreenClearFilters), - onClick = ::onClearFiltersClicked + onClick = { + previousFilters.value = state.selectedFilters() + onClearFiltersClicked() + } ) } } - for (filterWithSelection in state.filterSelectionStates) { + state.filterSelectionStates.forEachIndexed { i, filterWithSelection -> item(filterWithSelection.filter) { + val zIndex = (if (previousFilters.value.contains(filterWithSelection.filter)) state.filterSelectionStates.size else 0) - i.toFloat() RoomListFilterView( - modifier = Modifier.animateItemPlacement(), + modifier = Modifier + .animateItemPlacement() + .zIndex(zIndex), roomListFilter = filterWithSelection.filter, selected = filterWithSelection.isSelected, - onClick = ::onToggleFilter, + onClick = { + previousFilters.value = state.selectedFilters() + onToggleFilter(it) + }, ) } } From 7aa9d856b853c64ccc6e6cbbd8efe3c0229188cd Mon Sep 17 00:00:00 2001 From: Joe Groocock Date: Wed, 8 May 2024 09:54:48 +0100 Subject: [PATCH 2/3] Animate room filter colours This is much closer to how iOS looks, and is much nicer on the eyes. Signed-off-by: Joe Groocock --- .../impl/filters/RoomListFiltersView.kt | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/filters/RoomListFiltersView.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/filters/RoomListFiltersView.kt index be7448c4a0..2ebad2646e 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/filters/RoomListFiltersView.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/filters/RoomListFiltersView.kt @@ -16,6 +16,9 @@ package io.element.android.features.roomlist.impl.filters +import androidx.compose.animation.animateColorAsState +import androidx.compose.animation.core.Spring +import androidx.compose.animation.core.spring import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.background import androidx.compose.foundation.clickable @@ -139,16 +142,27 @@ private fun RoomListFilterView( onClick: (RoomListFilter) -> Unit, modifier: Modifier = Modifier ) { + val background = animateColorAsState( + targetValue = if (selected) ElementTheme.colors.bgActionPrimaryRest else ElementTheme.colors.bgCanvasDefault, + animationSpec = spring(stiffness = Spring.StiffnessMediumLow), + label = "chip background colour", + ) + val textColour = animateColorAsState( + targetValue = if (selected) ElementTheme.colors.textOnSolidPrimary else ElementTheme.colors.textPrimary, + animationSpec = spring(stiffness = Spring.StiffnessMediumLow), + label = "chip text colour", + ) + FilterChip( selected = selected, onClick = { onClick(roomListFilter) }, modifier = modifier.height(36.dp), shape = CircleShape, colors = FilterChipDefaults.filterChipColors( - containerColor = ElementTheme.colors.bgCanvasDefault, - selectedContainerColor = ElementTheme.colors.bgActionPrimaryRest, - labelColor = ElementTheme.colors.textPrimary, - selectedLabelColor = ElementTheme.colors.textOnSolidPrimary, + containerColor = background.value, + selectedContainerColor = background.value, + labelColor = textColour.value, + selectedLabelColor = textColour.value ), label = { Text(text = stringResource(id = roomListFilter.stringResource)) From b852578ffc0139304c04aaca7794900a4acbc4b1 Mon Sep 17 00:00:00 2001 From: Joe Groocock Date: Tue, 21 May 2024 22:17:18 +0000 Subject: [PATCH 3/3] Animate room list filters when clearing They animate cleanly back to their original locations now, and correctly overlap each other when doing so. The only thing that is mildly jarring is the reappearing chips, but there's no way to animate appearance in the current version of jetpack compose, so that'll have to be fixed later. Signed-off-by: Joe Groocock --- .../features/roomlist/impl/filters/RoomListFiltersView.kt | 8 -------- 1 file changed, 8 deletions(-) diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/filters/RoomListFiltersView.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/filters/RoomListFiltersView.kt index 2ebad2646e..7a1cb2039a 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/filters/RoomListFiltersView.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/filters/RoomListFiltersView.kt @@ -34,7 +34,6 @@ import androidx.compose.foundation.shape.CircleShape import androidx.compose.material3.FilterChip import androidx.compose.material3.FilterChipDefaults import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment @@ -106,13 +105,6 @@ fun RoomListFiltersView( } } } - LaunchedEffect(state.filterSelectionStates) { - // Checking for canScrollBackward is necessary for the itemPlacementAnimation to work correctly. - // We don't want the itemPlacementAnimation to be triggered when clearing the filters. - if (!state.hasAnyFilterSelected || lazyListState.canScrollBackward) { - lazyListState.animateScrollToItem(0) - } - } } @Composable