From 980d5462f302daaf7ca7411f57801ade38c4a317 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 23 Jun 2023 10:38:36 +0200 Subject: [PATCH] Iterate on Room placeholder --- .../roomlist/impl/RoomListStateProvider.kt | 3 +- .../components/RoomSummaryPlaceholderRow.kt | 104 ++++++++++++++++++ .../impl/components/RoomSummaryRow.kt | 49 ++------- .../atomic/atoms/PlaceholderAtom.kt | 72 ++++++++++++ .../designsystem/theme/ColorAliases.kt | 4 +- 5 files changed, 191 insertions(+), 41 deletions(-) create mode 100644 features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomSummaryPlaceholderRow.kt create mode 100644 libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/atoms/PlaceholderAtom.kt diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListStateProvider.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListStateProvider.kt index d4406f0330..421e243504 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListStateProvider.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/RoomListStateProvider.kt @@ -82,6 +82,7 @@ internal fun aRoomListRoomSummaryList(): ImmutableList { id = "!roomId2:domain", roomId = RoomId("!roomId2:domain") ), - RoomListRoomSummaryPlaceholders.create("!roomId2:domain") + RoomListRoomSummaryPlaceholders.create("!roomId2:domain"), + RoomListRoomSummaryPlaceholders.create("!roomId3:domain"), ) } diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomSummaryPlaceholderRow.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomSummaryPlaceholderRow.kt new file mode 100644 index 0000000000..bab27b1a47 --- /dev/null +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomSummaryPlaceholderRow.kt @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2023 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.features.roomlist.impl.components + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import io.element.android.libraries.designsystem.atomic.atoms.PlaceholderAtom +import io.element.android.libraries.designsystem.components.avatar.AvatarSize +import io.element.android.libraries.designsystem.preview.ElementPreviewDark +import io.element.android.libraries.designsystem.preview.ElementPreviewLight +import io.element.android.libraries.designsystem.theme.ElementTheme +import io.element.android.libraries.designsystem.theme.roomListPlaceHolder + +/** + * https://www.figma.com/file/0MMNu7cTOzLOlWb7ctTkv3/Element-X?node-id=6547%3A147623 + */ +@Composable +internal fun RoomSummaryPlaceholderRow( + modifier: Modifier = Modifier, +) { + Row( + modifier = modifier + .fillMaxWidth() + .height(minHeight) + .padding(horizontal = 16.dp), + ) { + Box( + modifier = Modifier + .size(AvatarSize.RoomListItem.dp) + .align(Alignment.CenterVertically) + .background(color = ElementTheme.colors.roomListPlaceHolder(), shape = CircleShape) + ) + Column( + modifier = Modifier + .fillMaxWidth() + .padding(start = 20.dp, top = 19.dp, end = 4.dp) + ) { + Row( + modifier = Modifier + .fillMaxWidth() + .height(22.dp), + verticalAlignment = Alignment.CenterVertically + ) { + PlaceholderAtom(width = 40.dp, height = 7.dp) + Spacer(modifier = Modifier.width(7.dp)) + PlaceholderAtom(width = 45.dp, height = 7.dp) + Spacer(modifier = Modifier.weight(1f)) + PlaceholderAtom(width = 22.dp, height = 4.dp) + } + Row( + modifier = Modifier + .height(25.dp), + verticalAlignment = Alignment.CenterVertically + ) { + PlaceholderAtom(width = 70.dp, height = 6.dp) + Spacer(modifier = Modifier.width(6.dp)) + PlaceholderAtom(width = 70.dp, height = 6.dp) + } + } + } +} + +@Preview +@Composable +internal fun RoomSummaryPlaceholderRowLightPreview() = + ElementPreviewLight { ContentToPreview() } + +@Preview +@Composable +internal fun RoomSummaryPlaceholderRowDarkPreview() = + ElementPreviewDark { ContentToPreview() } + +@Composable +private fun ContentToPreview() { + RoomSummaryPlaceholderRow() +} diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomSummaryRow.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomSummaryRow.kt index e7601132e4..1e0102e1c9 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomSummaryRow.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomSummaryRow.kt @@ -27,7 +27,6 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.shape.CircleShape import androidx.compose.material.ripple.rememberRipple import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable @@ -49,7 +48,6 @@ import androidx.compose.ui.unit.Density import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import com.google.accompanist.placeholder.material.placeholder import io.element.android.features.roomlist.impl.model.RoomListRoomSummary import io.element.android.features.roomlist.impl.model.RoomListRoomSummaryProvider import io.element.android.libraries.core.extensions.orEmpty @@ -57,15 +55,13 @@ import io.element.android.libraries.designsystem.atomic.atoms.UnreadIndicatorAto import io.element.android.libraries.designsystem.components.avatar.Avatar import io.element.android.libraries.designsystem.preview.ElementPreviewDark import io.element.android.libraries.designsystem.preview.ElementPreviewLight -import io.element.android.libraries.theme.ElementTheme import io.element.android.libraries.designsystem.theme.components.Text -import io.element.android.libraries.designsystem.theme.roomListPlaceHolder import io.element.android.libraries.designsystem.theme.roomListRoomMessage import io.element.android.libraries.designsystem.theme.roomListRoomMessageDate import io.element.android.libraries.designsystem.theme.roomListRoomName import io.element.android.libraries.designsystem.theme.roomListUnreadIndicator -private val minHeight = 84.dp +internal val minHeight = 84.dp @OptIn(ExperimentalFoundationApi::class) @Composable @@ -75,16 +71,16 @@ internal fun RoomSummaryRow( onLongClick: (RoomListRoomSummary) -> Unit, modifier: Modifier = Modifier, ) { - val clickModifier = if (room.isPlaceholder) { - Modifier - } else { - Modifier.combinedClickable( - onClick = { onClick(room) }, - onLongClick = { onLongClick(room) }, - indication = rememberRipple(), - interactionSource = remember { MutableInteractionSource() } - ) + if (room.isPlaceholder) { + RoomSummaryPlaceholderRow(modifier) + return } + val clickModifier = Modifier.combinedClickable( + onClick = { onClick(room) }, + onLongClick = { onLongClick(room) }, + indication = rememberRipple(), + interactionSource = remember { MutableInteractionSource() } + ) Row( modifier = modifier @@ -100,11 +96,6 @@ internal fun RoomSummaryRow( .avatarData, modifier = Modifier .align(Alignment.CenterVertically) - .placeholder( - visible = room.isPlaceholder, - shape = CircleShape, - color = ElementTheme.colors.roomListPlaceHolder(), - ) ) Column( modifier = Modifier @@ -127,12 +118,7 @@ private fun RowScope.NameAndTimestampRow(room: RoomListRoomSummary) { Text( modifier = Modifier .weight(1f) - .padding(end = 16.dp) - .placeholder( - visible = room.isPlaceholder, - shape = TextPlaceholderShape, - color = ElementTheme.colors.roomListPlaceHolder(), - ), + .padding(end = 16.dp), fontSize = 16.sp, fontWeight = FontWeight.SemiBold, style = MaterialTheme.typography.bodyMedium, @@ -143,12 +129,6 @@ private fun RowScope.NameAndTimestampRow(room: RoomListRoomSummary) { ) // Timestamp Text( - modifier = Modifier - .placeholder( - visible = room.isPlaceholder, - shape = TextPlaceholderShape, - color = ElementTheme.colors.roomListPlaceHolder(), - ), fontSize = 12.sp, text = room.timestamp ?: "", color = MaterialTheme.roomListRoomMessageDate(), @@ -163,12 +143,7 @@ private fun RowScope.LastMessageAndIndicatorRow(room: RoomListRoomSummary) { Text( modifier = Modifier .weight(1f) - .padding(end = 28.dp) - .placeholder( - visible = room.isPlaceholder, - shape = TextPlaceholderShape, - color = ElementTheme.colors.roomListPlaceHolder(), - ), + .padding(end = 28.dp), text = attributedLastMessage, color = MaterialTheme.roomListRoomMessage(), fontSize = 14.sp, diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/atoms/PlaceholderAtom.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/atoms/PlaceholderAtom.kt new file mode 100644 index 0000000000..dd7684fa1b --- /dev/null +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/atoms/PlaceholderAtom.kt @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2023 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.atomic.atoms + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import io.element.android.libraries.designsystem.preview.ElementPreviewDark +import io.element.android.libraries.designsystem.preview.ElementPreviewLight +import io.element.android.libraries.designsystem.theme.ElementTheme +import io.element.android.libraries.designsystem.theme.roomListPlaceHolder + +@Composable +fun PlaceholderAtom( + width: Dp, + height: Dp, + modifier: Modifier = Modifier, + color: Color = ElementTheme.colors.roomListPlaceHolder(), +) { + Box( + modifier = modifier + .width(width) + .height(height) + .background( + color = color, + shape = RoundedCornerShape(size = height / 2) + ) + ) +} + +@Preview +@Composable +internal fun PlaceholderAtomLightPreview() = + ElementPreviewLight { ContentToPreview() } + +@Preview +@Composable +internal fun PlaceholderAtomDarkPreview() = + ElementPreviewDark { ContentToPreview() } + +@Composable +private fun ContentToPreview() { + // Use a Red background to see the shape + Box(modifier = Modifier.background(color = Color.Red)) { + PlaceholderAtom( + width = 80.dp, + height = 12.dp + ) + } +} diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/ColorAliases.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/ColorAliases.kt index 3ec7b587f7..0e9b5c27c7 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/ColorAliases.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/ColorAliases.kt @@ -24,8 +24,6 @@ import io.element.android.libraries.designsystem.preview.ElementPreviewDark import io.element.android.libraries.designsystem.preview.ElementPreviewLight import io.element.android.libraries.theme.ElementColors import io.element.android.libraries.theme.ElementTheme -import io.element.android.libraries.theme.SystemGrey4Dark -import io.element.android.libraries.theme.SystemGrey6Light import io.element.android.libraries.theme.previews.ColorListPreview import kotlinx.collections.immutable.persistentMapOf @@ -45,7 +43,7 @@ fun MaterialTheme.roomListRoomMessageDate() = colorScheme.secondary fun MaterialTheme.roomListUnreadIndicator() = colorScheme.primary @Composable -fun ElementColors.roomListPlaceHolder() = if (isLight) SystemGrey6Light else SystemGrey4Dark +fun ElementColors.roomListPlaceHolder() = if (isLight) Compound_Gray_300_Light else Compound_Gray_300_Dark @Preview @Composable