diff --git a/changelog.d/3083.bugfix b/changelog.d/3083.bugfix new file mode 100644 index 0000000000..e3dfaf1da0 --- /dev/null +++ b/changelog.d/3083.bugfix @@ -0,0 +1 @@ +Improve room filters behavior 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 545884c875..884c13b0f9 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 @@ -22,6 +22,7 @@ import androidx.compose.animation.core.spring import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.background import androidx.compose.foundation.clickable +import androidx.compose.foundation.gestures.animateScrollBy import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.PaddingValues @@ -34,8 +35,12 @@ 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.getValue +import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip @@ -66,7 +71,31 @@ fun RoomListFiltersView( state.eventSink(RoomListFiltersEvents.ToggleFilter(filter)) } + var scrollToStart by remember { mutableIntStateOf(0) } val lazyListState = rememberLazyListState() + LaunchedEffect(scrollToStart) { + // Scroll until the first item start to be displayed + // Since all items have different size, there is no way to compute the amount of + // pixel to scroll to go directly to the start of the row. + // But IRL it should only happen for one item. + while (lazyListState.firstVisibleItemIndex > 0) { + lazyListState.animateScrollBy( + value = -(lazyListState.firstVisibleItemScrollOffset + 1f), + animationSpec = spring( + stiffness = Spring.StiffnessMediumLow, + ) + ) + } + // Then scroll to the start of the list, a bit faster, to fully reveal the first + // item, which can be the close button to reset filter, or the first item + // if the user has scroll a bit before clicking on the close button. + lazyListState.animateScrollBy( + value = -lazyListState.firstVisibleItemScrollOffset.toFloat(), + animationSpec = spring( + stiffness = Spring.StiffnessMedium, + ) + ) + } val previousFilters = remember { mutableStateOf(listOf()) } LazyRow( contentPadding = PaddingValues(start = 8.dp, end = 16.dp), @@ -84,6 +113,9 @@ fun RoomListFiltersView( onClick = { previousFilters.value = state.selectedFilters() onClearFiltersClick() + // When clearing filter, we want to ensure that the list + // of filters is scrolled to the start. + scrollToStart++ } ) } @@ -100,6 +132,10 @@ fun RoomListFiltersView( onClick = { previousFilters.value = state.selectedFilters() onToggleFilter(it) + // When selecting a filter, we want to scroll to the start of the list + if (filterWithSelection.isSelected.not()) { + scrollToStart++ + } }, ) }