Merge pull request #7141 from element-hq/feature/bma/visualListItem

Iterate on visual list
This commit is contained in:
Benoit Marty
2026-07-03 09:35:31 +02:00
committed by GitHub
24 changed files with 117 additions and 111 deletions
@@ -6,25 +6,19 @@
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.libraries.designsystem.atomic.organisms
package io.element.android.libraries.designsystem.components.visuallist
import androidx.annotation.DrawableRes
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.size
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.LocalTextStyle
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import io.element.android.compound.theme.ElementTheme
import io.element.android.libraries.designsystem.atomic.molecules.InfoListItemMolecule
import io.element.android.libraries.designsystem.atomic.molecules.InfoListItemPosition
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
@@ -32,14 +26,17 @@ import io.element.android.libraries.designsystem.theme.components.Text
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
/**
* Ref: https://www.figma.com/design/G1xy0HDZKJf5TCRFmKb5d5/Compound-Android-Components?node-id=2001-140
*/
@Composable
fun InfoListOrganism(
items: ImmutableList<InfoListItem>,
fun VisualList(
items: ImmutableList<VisualListItemData>,
modifier: Modifier = Modifier,
backgroundColor: Color = ElementTheme.colors.bgSubtleSecondary,
iconTint: Color = LocalContentColor.current,
iconTint: Color = ElementTheme.colors.iconSecondary,
iconSize: Dp = 20.dp,
textStyle: TextStyle = LocalTextStyle.current,
textStyle: TextStyle = ElementTheme.typography.fontBodyMdMedium,
textColor: Color = ElementTheme.colors.textPrimary,
verticalArrangement: Arrangement.Vertical = Arrangement.spacedBy(4.dp),
) {
@@ -49,12 +46,12 @@ fun InfoListOrganism(
) {
for ((index, item) in items.withIndex()) {
val position = when {
items.size == 1 -> InfoListItemPosition.Single
index == 0 -> InfoListItemPosition.Top
index == items.size - 1 -> InfoListItemPosition.Bottom
else -> InfoListItemPosition.Middle
items.size == 1 -> VisualListItemPosition.Single
index == 0 -> VisualListItemPosition.Top
index == items.size - 1 -> VisualListItemPosition.Bottom
else -> VisualListItemPosition.Middle
}
InfoListItemMolecule(
VisualListItem(
message = {
if (item.message is AnnotatedString) {
Text(
@@ -96,22 +93,15 @@ fun InfoListOrganism(
}
}
data class InfoListItem(
val message: CharSequence,
@DrawableRes val iconId: Int? = null,
val iconVector: ImageVector? = null,
val iconComposable: @Composable () -> Unit = {},
)
@PreviewsDayNight
@Composable
internal fun InfoListOrganismPreview() = ElementPreview {
internal fun VisualListPreview() = ElementPreview {
val items = persistentListOf(
InfoListItem(message = "A top item"),
InfoListItem(message = "A middle item"),
InfoListItem(message = "A bottom item"),
VisualListItemData(message = "A top item"),
VisualListItemData(message = "A middle item"),
VisualListItemData(message = "A bottom item"),
)
InfoListOrganism(
VisualList(
items = items,
)
}
@@ -6,7 +6,7 @@
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.libraries.designsystem.atomic.molecules
package io.element.android.libraries.designsystem.components.visuallist
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
@@ -27,10 +27,13 @@ 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.Text
/**
* Ref: https://www.figma.com/design/G1xy0HDZKJf5TCRFmKb5d5/Compound-Android-Components?node-id=2001-159
*/
@Composable
fun InfoListItemMolecule(
fun VisualListItem(
message: @Composable () -> Unit,
position: InfoListItemPosition,
position: VisualListItemPosition,
backgroundColor: Color,
modifier: Modifier = Modifier,
icon: @Composable () -> Unit = {},
@@ -38,10 +41,10 @@ fun InfoListItemMolecule(
val radius = 14.dp
val backgroundShape = remember(position) {
when (position) {
InfoListItemPosition.Single -> RoundedCornerShape(radius)
InfoListItemPosition.Top -> RoundedCornerShape(topStart = radius, topEnd = radius)
InfoListItemPosition.Middle -> RoundedCornerShape(0.dp)
InfoListItemPosition.Bottom -> RoundedCornerShape(bottomStart = radius, bottomEnd = radius)
VisualListItemPosition.Single -> RoundedCornerShape(radius)
VisualListItemPosition.Top -> RoundedCornerShape(topStart = radius, topEnd = radius)
VisualListItemPosition.Middle -> RoundedCornerShape(0.dp)
VisualListItemPosition.Bottom -> RoundedCornerShape(bottomStart = radius, bottomEnd = radius)
}
}
Row(
@@ -61,42 +64,42 @@ fun InfoListItemMolecule(
@PreviewsDayNight
@Composable
internal fun InfoListItemMoleculePreview() {
internal fun VisualListItemPreview() {
ElementPreview {
val color = ElementTheme.colors.bgSubtleSecondary
Column(
modifier = Modifier.padding(10.dp),
verticalArrangement = Arrangement.spacedBy(8.dp),
) {
InfoListItemMolecule(
VisualListItem(
message = { Text("A single item") },
icon = { Icon(imageVector = CompoundIcons.InfoSolid(), contentDescription = null) },
position = InfoListItemPosition.Single,
position = VisualListItemPosition.Single,
backgroundColor = color,
)
InfoListItemMolecule(
VisualListItem(
message = { Text("A top item") },
icon = { Icon(imageVector = CompoundIcons.InfoSolid(), contentDescription = null) },
position = InfoListItemPosition.Top,
position = VisualListItemPosition.Top,
backgroundColor = color,
)
InfoListItemMolecule(
VisualListItem(
message = { Text("A middle item") },
icon = { Icon(imageVector = CompoundIcons.InfoSolid(), contentDescription = null) },
position = InfoListItemPosition.Middle,
position = VisualListItemPosition.Middle,
backgroundColor = color,
)
InfoListItemMolecule(
VisualListItem(
message = { Text("A bottom item") },
icon = { Icon(imageVector = CompoundIcons.InfoSolid(), contentDescription = null) },
position = InfoListItemPosition.Bottom,
position = VisualListItemPosition.Bottom,
backgroundColor = color,
)
}
}
}
enum class InfoListItemPosition {
enum class VisualListItemPosition {
Top,
Middle,
Bottom,
@@ -0,0 +1,19 @@
/*
* Copyright (c) 2026 Element Creations Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.libraries.designsystem.components.visuallist
import androidx.annotation.DrawableRes
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.vector.ImageVector
data class VisualListItemData(
val message: CharSequence,
@DrawableRes val iconId: Int? = null,
val iconVector: ImageVector? = null,
val iconComposable: @Composable () -> Unit = {},
)