From 6ac66d08fdae46311f7d596245e80e0e15038285 Mon Sep 17 00:00:00 2001 From: ganfra Date: Mon, 11 Mar 2024 21:27:14 +0100 Subject: [PATCH] RoomListFilters : integrate with TopBar (and bloom) --- .../features/roomlist/impl/RoomListView.kt | 54 +---- .../impl/components/RoomListTopBar.kt | 226 ++++++++++-------- 2 files changed, 144 insertions(+), 136 deletions(-) diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListView.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListView.kt index f8cb6f137b..23a105f143 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListView.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListView.kt @@ -17,63 +17,36 @@ package io.element.android.features.roomlist.impl import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.statusBarsPadding -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.itemsIndexed -import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.rememberTopAppBarState import androidx.compose.runtime.Composable -import androidx.compose.runtime.derivedStateOf -import androidx.compose.runtime.getValue -import androidx.compose.runtime.remember -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.input.nestedscroll.NestedScrollConnection import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.PreviewParameter -import androidx.compose.ui.unit.Velocity -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.features.leaveroom.api.LeaveRoomView import io.element.android.features.networkmonitor.api.ui.ConnectivityIndicatorContainer -import io.element.android.features.roomlist.impl.components.ConfirmRecoveryKeyBanner -import io.element.android.features.roomlist.impl.components.RequestVerificationHeader import io.element.android.features.roomlist.impl.components.RoomListContentView import io.element.android.features.roomlist.impl.components.RoomListMenuAction import io.element.android.features.roomlist.impl.components.RoomListTopBar -import io.element.android.features.roomlist.impl.components.RoomSummaryRow -import io.element.android.features.roomlist.impl.filters.RoomListFiltersView -import io.element.android.features.roomlist.impl.migration.MigrationScreenView import io.element.android.features.roomlist.impl.model.RoomListRoomSummary import io.element.android.features.roomlist.impl.search.RoomListSearchView import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight -import io.element.android.libraries.designsystem.theme.components.Button import io.element.android.libraries.designsystem.theme.components.FloatingActionButton -import io.element.android.libraries.designsystem.theme.components.HorizontalDivider import io.element.android.libraries.designsystem.theme.components.Icon -import io.element.android.libraries.designsystem.theme.components.IconSource import io.element.android.libraries.designsystem.theme.components.Scaffold -import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.utils.snackbar.SnackbarHost import io.element.android.libraries.designsystem.utils.snackbar.rememberSnackbarHostState import io.element.android.libraries.matrix.api.core.RoomId -import io.element.android.libraries.ui.strings.CommonStrings @Composable fun RoomListView( @@ -161,21 +134,18 @@ private fun RoomListScaffold( Scaffold( modifier = modifier.nestedScroll(scrollBehavior.nestedScrollConnection), topBar = { - Column { - RoomListTopBar( - matrixUser = state.matrixUser, - showAvatarIndicator = state.showAvatarIndicator, - areSearchResultsDisplayed = state.searchState.isSearchActive, - onToggleSearch = { state.eventSink(RoomListEvents.ToggleSearchResults) }, - onMenuActionClicked = onMenuActionClicked, - onOpenSettings = onOpenSettings, - scrollBehavior = scrollBehavior, - displayMenuItems = !state.displayActions, - ) - if (state.displayFilters) { - RoomListFiltersView(state = state.filtersState) - } - } + RoomListTopBar( + matrixUser = state.matrixUser, + showAvatarIndicator = state.showAvatarIndicator, + areSearchResultsDisplayed = state.searchState.isSearchActive, + onToggleSearch = { state.eventSink(RoomListEvents.ToggleSearchResults) }, + onMenuActionClicked = onMenuActionClicked, + onOpenSettings = onOpenSettings, + scrollBehavior = scrollBehavior, + displayMenuItems = state.displayActions, + displayFilters = state.displayFilters, + filtersState = state.filtersState, + ) }, content = { padding -> RoomListContentView( diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomListTopBar.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomListTopBar.kt index 0d0a750a9f..50b4144225 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomListTopBar.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomListTopBar.kt @@ -17,6 +17,7 @@ package io.element.android.features.roomlist.impl.components import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding @@ -40,7 +41,6 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha import androidx.compose.ui.graphics.Color -import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.layout.onSizeChanged import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalInspectionMode @@ -52,8 +52,12 @@ import io.element.android.appconfig.RoomListConfig import io.element.android.compound.theme.ElementTheme import io.element.android.compound.tokens.generated.CompoundIcons import io.element.android.features.roomlist.impl.R +import io.element.android.features.roomlist.impl.filters.RoomListFiltersState +import io.element.android.features.roomlist.impl.filters.RoomListFiltersView +import io.element.android.features.roomlist.impl.filters.aRoomListFiltersState import io.element.android.libraries.designsystem.atomic.atoms.RedIndicatorAtom import io.element.android.libraries.designsystem.components.avatar.Avatar +import io.element.android.libraries.designsystem.components.avatar.AvatarData import io.element.android.libraries.designsystem.components.avatar.AvatarSize import io.element.android.libraries.designsystem.components.avatarBloom import io.element.android.libraries.designsystem.preview.ElementPreview @@ -91,6 +95,8 @@ fun RoomListTopBar( onOpenSettings: () -> Unit, scrollBehavior: TopAppBarScrollBehavior, displayMenuItems: Boolean, + displayFilters: Boolean, + filtersState: RoomListFiltersState, modifier: Modifier = Modifier, ) { DefaultRoomListTopBar( @@ -102,6 +108,8 @@ fun RoomListTopBar( onMenuActionClicked = onMenuActionClicked, scrollBehavior = scrollBehavior, displayMenuItems = displayMenuItems, + displayFilters = displayFilters, + filtersState = filtersState, modifier = modifier, ) } @@ -117,6 +125,8 @@ private fun DefaultRoomListTopBar( onSearchClicked: () -> Unit, onMenuActionClicked: (RoomListMenuAction) -> Unit, displayMenuItems: Boolean, + displayFilters: Boolean, + filtersState: RoomListFiltersState, modifier: Modifier = Modifier, ) { // We need this to manually clip the top app bar in preview mode @@ -153,12 +163,11 @@ private fun DefaultRoomListTopBar( titleLarge = collapsedTitleTextStyle ), ) { - MediumTopAppBar( + Column( modifier = Modifier .onSizeChanged { appBarHeight = it.height } - .nestedScroll(scrollBehavior.nestedScrollConnection) .avatarBloom( avatarData = avatarData, background = if (ElementTheme.isLightTheme) { @@ -178,113 +187,104 @@ private fun DefaultRoomListTopBar( DpSize.Unspecified }, bottomSoftEdgeColor = ElementTheme.materialColors.background, - bottomSoftEdgeAlpha = 1f - collapsedFraction, + bottomSoftEdgeAlpha = if (displayFilters) { + 1f + } else { + 1f - collapsedFraction + }, alpha = if (areSearchResultsDisplayed) 0f else 1f, ) .statusBarsPadding(), - colors = TopAppBarDefaults.mediumTopAppBarColors( - containerColor = Color.Transparent, - scrolledContainerColor = Color.Transparent, - ), - title = { - Text(text = stringResource(id = R.string.screen_roomlist_main_space_title)) - }, - navigationIcon = { - IconButton( - modifier = Modifier.testTag(TestTags.homeScreenSettings), - onClick = onOpenSettings - ) { - if (avatarData != null) { - Avatar( - avatarData = avatarData!!, - contentDescription = stringResource(CommonStrings.common_settings), - ) - } else { - // Placeholder avatar until the avatarData is available - Surface( - modifier = Modifier.size(AvatarSize.CurrentUserTopBar.dp), - shape = CircleShape, - color = ElementTheme.colors.iconSecondary, - content = {} - ) - } - if (showAvatarIndicator) { - RedIndicatorAtom( - modifier = Modifier - .padding(4.5.dp) - .align(Alignment.TopEnd) - ) - } - } - }, - actions = { - if (displayMenuItems) { - IconButton( - onClick = onSearchClicked, - ) { - Icon( - imageVector = CompoundIcons.Search(), - contentDescription = stringResource(CommonStrings.action_search), - ) - } - if (RoomListConfig.HAS_DROP_DOWN_MENU) { - var showMenu by remember { mutableStateOf(false) } + ) { + MediumTopAppBar( + colors = TopAppBarDefaults.mediumTopAppBarColors( + containerColor = Color.Transparent, + scrolledContainerColor = Color.Transparent, + ), + title = { + Text(text = stringResource(id = R.string.screen_roomlist_main_space_title)) + }, + navigationIcon = { + NavigationIcon( + avatarData = avatarData, + showAvatarIndicator = showAvatarIndicator, + onClick = onOpenSettings, + ) + }, + actions = { + if (displayMenuItems) { IconButton( - onClick = { showMenu = !showMenu } + onClick = onSearchClicked, ) { Icon( - imageVector = CompoundIcons.OverflowVertical(), - contentDescription = null, + imageVector = CompoundIcons.Search(), + contentDescription = stringResource(CommonStrings.action_search), ) } - DropdownMenu( - expanded = showMenu, - onDismissRequest = { showMenu = false } - ) { - if (RoomListConfig.SHOW_INVITE_MENU_ITEM) { - DropdownMenuItem( - onClick = { - showMenu = false - onMenuActionClicked(RoomListMenuAction.InviteFriends) - }, - text = { Text(stringResource(id = CommonStrings.action_invite)) }, - leadingIcon = { - Icon( - imageVector = CompoundIcons.ShareAndroid(), - tint = ElementTheme.materialColors.secondary, - contentDescription = null, - ) - } + if (RoomListConfig.HAS_DROP_DOWN_MENU) { + var showMenu by remember { mutableStateOf(false) } + IconButton( + onClick = { showMenu = !showMenu } + ) { + Icon( + imageVector = CompoundIcons.OverflowVertical(), + contentDescription = null, ) } - if (RoomListConfig.SHOW_REPORT_PROBLEM_MENU_ITEM) { - DropdownMenuItem( - onClick = { - showMenu = false - onMenuActionClicked(RoomListMenuAction.ReportBug) - }, - text = { Text(stringResource(id = CommonStrings.common_report_a_problem)) }, - leadingIcon = { - Icon( - imageVector = CompoundIcons.ChatProblem(), - tint = ElementTheme.materialColors.secondary, - contentDescription = null, - ) - } - ) + DropdownMenu( + expanded = showMenu, + onDismissRequest = { showMenu = false } + ) { + if (RoomListConfig.SHOW_INVITE_MENU_ITEM) { + DropdownMenuItem( + onClick = { + showMenu = false + onMenuActionClicked(RoomListMenuAction.InviteFriends) + }, + text = { Text(stringResource(id = CommonStrings.action_invite)) }, + leadingIcon = { + Icon( + imageVector = CompoundIcons.ShareAndroid(), + tint = ElementTheme.materialColors.secondary, + contentDescription = null, + ) + } + ) + } + if (RoomListConfig.SHOW_REPORT_PROBLEM_MENU_ITEM) { + DropdownMenuItem( + onClick = { + showMenu = false + onMenuActionClicked(RoomListMenuAction.ReportBug) + }, + text = { Text(stringResource(id = CommonStrings.common_report_a_problem)) }, + leadingIcon = { + Icon( + imageVector = CompoundIcons.ChatProblem(), + tint = ElementTheme.materialColors.secondary, + contentDescription = null, + ) + } + ) + } } } } - } - }, - scrollBehavior = scrollBehavior, - windowInsets = WindowInsets(0.dp), - ) + }, + scrollBehavior = scrollBehavior, + windowInsets = WindowInsets(0.dp), + ) + if (displayFilters) { + RoomListFiltersView( + state = filtersState, + modifier = Modifier.padding(bottom = 16.dp) + ) + } + } } HorizontalDivider( - modifier = - Modifier + modifier = Modifier .fillMaxWidth() .alpha(collapsedFraction) .align(Alignment.BottomCenter), @@ -293,6 +293,40 @@ private fun DefaultRoomListTopBar( } } +@Composable +private fun NavigationIcon( + avatarData: AvatarData?, + showAvatarIndicator: Boolean, + onClick: () -> Unit, +) { + IconButton( + modifier = Modifier.testTag(TestTags.homeScreenSettings), + onClick = onClick, + ) { + Box { + if (avatarData != null) { + Avatar( + avatarData = avatarData, + contentDescription = stringResource(CommonStrings.common_settings), + ) + } else { + // Placeholder avatar until the avatarData is available + Surface( + modifier = Modifier.size(AvatarSize.CurrentUserTopBar.dp), + shape = CircleShape, + color = ElementTheme.colors.iconSecondary, + content = {} + ) + } + if (showAvatarIndicator) { + RedIndicatorAtom( + modifier = Modifier.align(Alignment.TopEnd) + ) + } + } + } +} + @OptIn(ExperimentalMaterial3Api::class) @PreviewsDayNight @Composable @@ -305,6 +339,8 @@ internal fun DefaultRoomListTopBarPreview() = ElementPreview { onOpenSettings = {}, onSearchClicked = {}, displayMenuItems = true, + displayFilters = true, + filtersState = aRoomListFiltersState(), onMenuActionClicked = {}, ) } @@ -321,6 +357,8 @@ internal fun DefaultRoomListTopBarWithIndicatorPreview() = ElementPreview { onOpenSettings = {}, onSearchClicked = {}, displayMenuItems = true, + displayFilters = true, + filtersState = aRoomListFiltersState(), onMenuActionClicked = {}, ) }