From d6f95fd47d8a32192484883aa5c3a34141ce9b42 Mon Sep 17 00:00:00 2001 From: ganfra Date: Fri, 3 Jan 2025 15:30:11 +0100 Subject: [PATCH 1/3] design : introduce CounterAtom and ListItemContent.Counter --- .../designsystem/atomic/atoms/CounterAtom.kt | 83 +++++++++++++++++++ .../components/list/ListItemContent.kt | 7 ++ 2 files changed, 90 insertions(+) create mode 100644 libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/atoms/CounterAtom.kt diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/atoms/CounterAtom.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/atoms/CounterAtom.kt new file mode 100644 index 0000000000..c84906bbad --- /dev/null +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/atoms/CounterAtom.kt @@ -0,0 +1,83 @@ +/* + * Copyright 2025 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only + * Please see LICENSE in the repository root for full details. + */ + +package io.element.android.libraries.designsystem.atomic.atoms + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement.spacedBy +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.size +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.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.rememberTextMeasurer +import androidx.compose.ui.unit.dp +import io.element.android.compound.theme.ElementTheme +import io.element.android.libraries.designsystem.preview.ElementPreview +import io.element.android.libraries.designsystem.preview.PreviewsDayNight +import io.element.android.libraries.designsystem.text.toDp +import io.element.android.libraries.designsystem.theme.components.Text + +private const val MAX_COUNT = 99 +private const val MAX_COUNT_STRING = "+$MAX_COUNT" + +/** + * A counter atom that displays a number in a circle. + * Figma link : https://www.figma.com/design/G1xy0HDZKJf5TCRFmKb5d5/Compound-Android-Components?node-id=2805-2649&m=dev + * + * @param count The number to display. If the number is greater than [MAX_COUNT], the counter will display [MAX_COUNT_STRING]. + * If the number is less than 1, the counter will not be displayed. + * @param modifier The modifier to apply to this layout. + */ +@Composable +fun CounterAtom( + count: Int, + modifier: Modifier = Modifier, +) { + if (count < 1) return + val countAsText = when (count) { + in 0..MAX_COUNT -> count.toString() + else -> MAX_COUNT_STRING + } + val textStyle = ElementTheme.typography.fontBodyMdMedium + val textMeasurer = rememberTextMeasurer() + // Measure the maximum count string size + val textLayoutResult = textMeasurer.measure( + text = MAX_COUNT_STRING, + style = textStyle + ) + val textSize = textLayoutResult.size + val squareSize = maxOf(textSize.width, textSize.height) + Box( + modifier = modifier + .size(squareSize.toDp() + 1.dp) + .clip(CircleShape) + .background(ElementTheme.colors.iconSuccessPrimary) + ) { + Text( + modifier = Modifier.align(Alignment.Center), + text = countAsText, + style = textStyle, + color = Color.White, + ) + } +} + +@PreviewsDayNight +@Composable +internal fun CounterAtomPreview() = ElementPreview { + Column(verticalArrangement = spacedBy(2.dp)) { + CounterAtom(count = 0) + CounterAtom(count = 4) + CounterAtom(count = 99) + CounterAtom(count = 100) + } +} diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/list/ListItemContent.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/list/ListItemContent.kt index 67d464a946..d2fb1259fc 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/list/ListItemContent.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/list/ListItemContent.kt @@ -17,6 +17,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.dp +import io.element.android.libraries.designsystem.atomic.atoms.CounterAtom import io.element.android.libraries.designsystem.atomic.atoms.RedIndicatorAtom import io.element.android.libraries.designsystem.theme.components.IconSource import io.element.android.libraries.designsystem.theme.components.ListItem @@ -91,6 +92,9 @@ sealed interface ListItemContent { /** Displays a badge. */ data object Badge : ListItemContent + /** Displays a counter. */ + data class Counter(val count: Int) : ListItemContent + @Composable fun View() { when (this) { @@ -125,6 +129,9 @@ sealed interface ListItemContent { ) { RedIndicatorAtom() } + is Counter -> { + CounterAtom(count = count) + } is Custom -> content() } } From a7383b9ef7761e41d26f9fdec4e892298ea656e6 Mon Sep 17 00:00:00 2001 From: ganfra Date: Fri, 3 Jan 2025 15:30:52 +0100 Subject: [PATCH 2/3] feature(knock) : use ListItemContent.Counter according to design --- .../features/roomdetails/impl/RoomDetailsStateProvider.kt | 2 ++ .../android/features/roomdetails/impl/RoomDetailsView.kt | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsStateProvider.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsStateProvider.kt index b3a4c0e7ee..eaa9d816ac 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsStateProvider.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsStateProvider.kt @@ -48,6 +48,8 @@ open class RoomDetailsStateProvider : PreviewParameterProvider aRoomDetailsState(isPublic = false), aRoomDetailsState(heroes = aMatrixUserList()), aRoomDetailsState(pinnedMessagesCount = 3), + aRoomDetailsState(knockRequestsCount = null, canShowKnockRequests = true), + aRoomDetailsState(knockRequestsCount = 4, canShowKnockRequests = true), // Add other state here ) } diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsView.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsView.kt index 5e65ce9336..a7f7089861 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsView.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsView.kt @@ -251,7 +251,7 @@ private fun KnockRequestsItem(knockRequestsCount: Int?, onKnockRequestsClick: () trailingContent = if (knockRequestsCount == null || knockRequestsCount == 0) { null } else { - ListItemContent.Text(knockRequestsCount.toString()) + ListItemContent.Counter(knockRequestsCount) }, onClick = onKnockRequestsClick, ) From f80fa13d0ec9d096772dd20caef977004396fefb Mon Sep 17 00:00:00 2001 From: ElementBot Date: Fri, 3 Jan 2025 14:42:17 +0000 Subject: [PATCH 3/3] Update screenshots --- .../images/features.roomdetails.impl_RoomDetailsDark_14_en.png | 3 +++ .../images/features.roomdetails.impl_RoomDetailsDark_15_en.png | 3 +++ .../images/features.roomdetails.impl_RoomDetails_14_en.png | 3 +++ .../images/features.roomdetails.impl_RoomDetails_15_en.png | 3 +++ ...ibraries.designsystem.atomic.atoms_CounterAtom_Day_0_en.png | 3 +++ ...raries.designsystem.atomic.atoms_CounterAtom_Night_0_en.png | 3 +++ 6 files changed, 18 insertions(+) create mode 100644 tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_14_en.png create mode 100644 tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_15_en.png create mode 100644 tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_14_en.png create mode 100644 tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_15_en.png create mode 100644 tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.atoms_CounterAtom_Day_0_en.png create mode 100644 tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.atoms_CounterAtom_Night_0_en.png diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_14_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_14_en.png new file mode 100644 index 0000000000..4d87c5c693 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_14_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d3ecde943af214c1c2012edf6f7fa4db2e1f8b81e912fc44e3452aced3dcac3f +size 41454 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_15_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_15_en.png new file mode 100644 index 0000000000..52e11b9fc1 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetailsDark_15_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d215f0c099c5bdf410c777392f6089a8441aea42a57a2b188a1f701c7519d502 +size 42036 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_14_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_14_en.png new file mode 100644 index 0000000000..7e231863e9 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_14_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e457078f488ce08554849e214ab45404217627e2d253f21d8a2cbd08009bf75b +size 42405 diff --git a/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_15_en.png b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_15_en.png new file mode 100644 index 0000000000..21d423d243 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.roomdetails.impl_RoomDetails_15_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4086a1ea9bc4cca80ceeb8f41f52d11551a0f1e702f3b72b65dbe244edaff867 +size 43019 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.atoms_CounterAtom_Day_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.atoms_CounterAtom_Day_0_en.png new file mode 100644 index 0000000000..f12cb438d2 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.atoms_CounterAtom_Day_0_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7a2a171ac0edac9cb734d418b7baf68dd294d9feb93f005cf445420a7538a8ed +size 7687 diff --git a/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.atoms_CounterAtom_Night_0_en.png b/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.atoms_CounterAtom_Night_0_en.png new file mode 100644 index 0000000000..cd66fcf3c8 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/libraries.designsystem.atomic.atoms_CounterAtom_Night_0_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:56508c5827cfda4c672f924e3e9280659b729b772455c65dbae76ba7815e18dd +size 7502