Browse Source

RoomListFilters: try to improve ui with animation and fading edges

jme/room_list_filters_embedded
ganfra 7 months ago
parent
commit
7471e12bc5
  1. 1
      features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListPresenter.kt
  2. 2
      features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/filters/RoomListFilter.kt
  3. 2
      features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/filters/RoomListFiltersPresenter.kt
  4. 1
      features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/filters/RoomListFiltersStateProvider.kt
  5. 65
      features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/filters/RoomListFiltersView.kt
  6. 1
      features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTests.kt
  7. 1
      features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/filters/RoomListFiltersPresenterTests.kt
  8. 57
      libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/modifiers/FadingEdge.kt

1
features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListPresenter.kt

@ -36,7 +36,6 @@ import io.element.android.features.networkmonitor.api.NetworkStatus @@ -36,7 +36,6 @@ import io.element.android.features.networkmonitor.api.NetworkStatus
import io.element.android.features.preferences.api.store.SessionPreferencesStore
import io.element.android.features.roomlist.impl.datasource.InviteStateDataSource
import io.element.android.features.roomlist.impl.datasource.RoomListDataSource
import io.element.android.features.roomlist.impl.filters.RoomListFiltersPresenter
import io.element.android.features.roomlist.impl.filters.RoomListFiltersState
import io.element.android.features.roomlist.impl.migration.MigrationScreenPresenter
import io.element.android.features.roomlist.impl.search.RoomListSearchEvents

2
features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/filters/RoomListFilter.kt

@ -22,7 +22,7 @@ import io.element.android.features.roomlist.impl.R @@ -22,7 +22,7 @@ import io.element.android.features.roomlist.impl.R
* Enum class representing the different filters that can be applied to the room list.
* Order is important.
*/
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),

2
features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/filters/RoomListFiltersPresenter.kt

@ -35,7 +35,6 @@ class RoomListFiltersPresenter @Inject constructor( @@ -35,7 +35,6 @@ class RoomListFiltersPresenter @Inject constructor(
private val roomListService: RoomListService,
private val featureFlagService: FeatureFlagService,
) : Presenter<RoomListFiltersState> {
@Composable
override fun present(): RoomListFiltersState {
val isFeatureEnabled by featureFlagService.isFeatureEnabledFlow(FeatureFlags.RoomListFilters).collectAsState(false)
@ -91,4 +90,3 @@ class RoomListFiltersPresenter @Inject constructor( @@ -91,4 +90,3 @@ class RoomListFiltersPresenter @Inject constructor(
)
}
}

1
features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/filters/RoomListFiltersStateProvider.kt

@ -22,7 +22,6 @@ import kotlinx.collections.immutable.persistentListOf @@ -22,7 +22,6 @@ import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
class RoomListFiltersStateProvider : PreviewParameterProvider<RoomListFiltersState> {
override val values: Sequence<RoomListFiltersState>
get() = sequenceOf(
aRoomListFiltersState(),

65
features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/filters/RoomListFiltersView.kt

@ -17,13 +17,17 @@ @@ -17,13 +17,17 @@
package io.element.android.features.roomlist.impl.filters
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.FilterChip
import androidx.compose.material3.FilterChipDefaults
@ -36,11 +40,14 @@ import androidx.compose.ui.tooling.preview.PreviewParameter @@ -36,11 +40,14 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
import io.element.android.compound.theme.ElementTheme
import io.element.android.compound.tokens.generated.CompoundIcons
import io.element.android.libraries.designsystem.modifiers.fadingEdge
import io.element.android.libraries.designsystem.modifiers.horizontalFadingEdgesBrush
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.theme.components.Icon
import io.element.android.libraries.designsystem.theme.components.IconButton
import io.element.android.libraries.designsystem.theme.components.Text
import kotlinx.collections.immutable.ImmutableList
import timber.log.Timber
@Composable
@ -61,34 +68,50 @@ fun RoomListFiltersView( @@ -61,34 +68,50 @@ fun RoomListFiltersView(
state.eventSink(RoomListFiltersEvents.ToggleFilter(filter))
}
val horizontalPadding = if (state.showClearFilterButton) 4.dp else 16.dp
val scrollState = rememberScrollState()
val startPadding = if (state.showClearFilterButton) 4.dp else 16.dp
Row(
modifier = modifier
.padding(horizontal = horizontalPadding)
.horizontalScroll(scrollState),
horizontalArrangement = Arrangement.spacedBy(8.dp),
modifier = modifier.padding(start = startPadding, end = 16.dp),
) {
AnimatedVisibility(visible = state.showClearFilterButton) {
RoomListClearFiltersButton(onClick = ::onClearFiltersClicked)
}
for (filter in state.selectedFilters) {
RoomListFilterView(
roomListFilter = filter,
selected = true,
onClick = ::onFilterClicked,
)
}
for (filter in state.unselectedFilters) {
RoomListFilterView(
roomListFilter = filter,
selected = false,
onClick = ::onFilterClicked,
)
val lazyListState = rememberLazyListState()
val fadingEdgesBrush = horizontalFadingEdgesBrush(
showLeft = lazyListState.canScrollBackward,
showRight = lazyListState.canScrollForward
)
LazyRow(
modifier = Modifier
.fillMaxWidth()
.fadingEdge(fadingEdgesBrush),
state = lazyListState,
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
roomListFilters(state.selectedFilters, selected = true, onClick = ::onFilterClicked)
roomListFilters(state.unselectedFilters, selected = false, onClick = ::onFilterClicked)
}
}
}
@OptIn(ExperimentalFoundationApi::class)
private fun LazyListScope.roomListFilters(
filters: ImmutableList<RoomListFilter>,
selected: Boolean,
onClick: (RoomListFilter) -> Unit,
) {
items(
items = filters,
key = { it.ordinal },
) { filter ->
RoomListFilterView(
modifier = Modifier.animateItemPlacement(),
roomListFilter = filter,
selected = selected,
onClick = onClick,
)
}
}
@Composable
private fun RoomListClearFiltersButton(
onClick: () -> Unit,

1
features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTests.kt

@ -30,7 +30,6 @@ import io.element.android.features.roomlist.impl.datasource.FakeInviteDataSource @@ -30,7 +30,6 @@ import io.element.android.features.roomlist.impl.datasource.FakeInviteDataSource
import io.element.android.features.roomlist.impl.datasource.InviteStateDataSource
import io.element.android.features.roomlist.impl.datasource.RoomListDataSource
import io.element.android.features.roomlist.impl.datasource.RoomListRoomSummaryFactory
import io.element.android.features.roomlist.impl.filters.RoomListFiltersPresenter
import io.element.android.features.roomlist.impl.filters.RoomListFiltersState
import io.element.android.features.roomlist.impl.filters.aRoomListFiltersState
import io.element.android.features.roomlist.impl.migration.InMemoryMigrationScreenStore

1
features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/filters/RoomListFiltersPresenterTests.kt

@ -30,7 +30,6 @@ import org.junit.Test @@ -30,7 +30,6 @@ import org.junit.Test
import io.element.android.libraries.matrix.api.roomlist.RoomListFilter as MatrixRoomListFilter
class RoomListFiltersPresenterTests {
@Test
fun `present - initial state`() = runTest {
val presenter = createRoomListFiltersPresenter()

57
libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/modifiers/FadingEdge.kt

@ -0,0 +1,57 @@ @@ -0,0 +1,57 @@
/*
* 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.libraries.designsystem.modifiers
import androidx.compose.animation.animateColorAsState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawWithContent
import androidx.compose.ui.graphics.BlendMode
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.CompositingStrategy
import androidx.compose.ui.graphics.graphicsLayer
@Composable
fun horizontalFadingEdgesBrush(
showLeft: Boolean,
showRight: Boolean,
percent: Float = 0.1f,
): Brush {
val leftColor by animateColorAsState(
targetValue = if (showLeft) Color.Transparent else Color.White,
label = "AnimateLeftColor",
)
val rightColor by animateColorAsState(
targetValue = if (showRight) Color.Transparent else Color.White,
label = "AnimateRightColor",
)
return Brush.horizontalGradient(
0f to leftColor,
percent to Color.White,
1f - percent to Color.White,
1f to rightColor
)
}
fun Modifier.fadingEdge(brush: Brush) = this
.graphicsLayer(compositingStrategy = CompositingStrategy.Offscreen)
.drawWithContent {
drawContent()
drawRect(brush = brush, blendMode = BlendMode.DstIn)
}
Loading…
Cancel
Save