Create dedicated package for visual list and add Figma link.
This commit is contained in:
+9
-9
@@ -31,12 +31,12 @@ import io.element.android.compound.tokens.generated.CompoundIcons
|
||||
import io.element.android.features.analytics.api.AnalyticsOptInEvents
|
||||
import io.element.android.libraries.designsystem.atomic.molecules.ButtonColumnMolecule
|
||||
import io.element.android.libraries.designsystem.atomic.molecules.IconTitleSubtitleMolecule
|
||||
import io.element.android.libraries.designsystem.atomic.organisms.InfoListItem
|
||||
import io.element.android.libraries.designsystem.atomic.organisms.InfoListOrganism
|
||||
import io.element.android.libraries.designsystem.atomic.pages.HeaderFooterPage
|
||||
import io.element.android.libraries.designsystem.background.OnboardingBackground
|
||||
import io.element.android.libraries.designsystem.components.BigIcon
|
||||
import io.element.android.libraries.designsystem.components.ClickableLinkText
|
||||
import io.element.android.libraries.designsystem.components.visuallist.VisualList
|
||||
import io.element.android.libraries.designsystem.components.visuallist.VisualListItemData
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||
import io.element.android.libraries.designsystem.text.buildAnnotatedStringWithStyledPart
|
||||
@@ -65,9 +65,9 @@ fun AnalyticsOptInView(
|
||||
BackHandler(onBack = ::onDeclineTerms)
|
||||
HeaderFooterPage(
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.systemBarsPadding()
|
||||
.imePadding(),
|
||||
.fillMaxSize()
|
||||
.systemBarsPadding()
|
||||
.imePadding(),
|
||||
background = { OnboardingBackground() },
|
||||
header = { AnalyticsOptInHeader(state, onClickTerms) },
|
||||
content = { AnalyticsOptInContent() },
|
||||
@@ -129,17 +129,17 @@ private fun AnalyticsOptInContent() {
|
||||
verticalBias = -0.4f
|
||||
)
|
||||
) {
|
||||
InfoListOrganism(
|
||||
VisualList(
|
||||
items = persistentListOf(
|
||||
InfoListItem(
|
||||
VisualListItemData(
|
||||
message = stringResource(id = R.string.screen_analytics_prompt_data_usage),
|
||||
iconVector = CompoundIcons.CheckCircle(),
|
||||
),
|
||||
InfoListItem(
|
||||
VisualListItemData(
|
||||
message = stringResource(id = R.string.screen_analytics_prompt_third_party_sharing),
|
||||
iconVector = CompoundIcons.CheckCircle(),
|
||||
),
|
||||
InfoListItem(
|
||||
VisualListItemData(
|
||||
message = stringResource(id = R.string.screen_analytics_prompt_settings),
|
||||
iconVector = CompoundIcons.CheckCircle(),
|
||||
),
|
||||
|
||||
+9
-9
@@ -36,10 +36,10 @@ import io.element.android.features.announcement.impl.AnnouncementState
|
||||
import io.element.android.features.announcement.impl.AnnouncementStateProvider
|
||||
import io.element.android.libraries.designsystem.atomic.molecules.ButtonColumnMolecule
|
||||
import io.element.android.libraries.designsystem.atomic.molecules.IconTitleSubtitleMolecule
|
||||
import io.element.android.libraries.designsystem.atomic.organisms.InfoListItem
|
||||
import io.element.android.libraries.designsystem.atomic.organisms.InfoListOrganism
|
||||
import io.element.android.libraries.designsystem.atomic.pages.HeaderFooterPage
|
||||
import io.element.android.libraries.designsystem.components.BigIcon
|
||||
import io.element.android.libraries.designsystem.components.visuallist.VisualList
|
||||
import io.element.android.libraries.designsystem.components.visuallist.VisualListItemData
|
||||
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
|
||||
@@ -134,7 +134,7 @@ private fun FullscreenAnnouncementContent(
|
||||
Column(
|
||||
modifier = modifier.fillMaxSize(),
|
||||
) {
|
||||
InfoListOrganism(
|
||||
VisualList(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
items = announcement.items(),
|
||||
textStyle = ElementTheme.typography.fontBodyLgMedium,
|
||||
@@ -186,25 +186,25 @@ private fun Announcement.Fullscreen.icon() = when (this) {
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Announcement.Fullscreen.items(): ImmutableList<InfoListItem> = when (this) {
|
||||
private fun Announcement.Fullscreen.items(): ImmutableList<VisualListItemData> = when (this) {
|
||||
Announcement.Fullscreen.Space -> persistentListOf(
|
||||
InfoListItem(
|
||||
VisualListItemData(
|
||||
message = "View spaces you\'ve created or joined",
|
||||
iconVector = CompoundIcons.VisibilityOn(),
|
||||
),
|
||||
InfoListItem(
|
||||
VisualListItemData(
|
||||
message = "Accept or decline invites to spaces",
|
||||
iconVector = CompoundIcons.Email(),
|
||||
),
|
||||
InfoListItem(
|
||||
VisualListItemData(
|
||||
message = "Discover any rooms you can join in your spaces",
|
||||
iconVector = CompoundIcons.Search(),
|
||||
),
|
||||
InfoListItem(
|
||||
VisualListItemData(
|
||||
message = "Join public spaces",
|
||||
iconVector = CompoundIcons.Explore(),
|
||||
),
|
||||
InfoListItem(
|
||||
VisualListItemData(
|
||||
message = "Leave any spaces you’ve joined",
|
||||
iconVector = CompoundIcons.Leave(),
|
||||
),
|
||||
|
||||
+7
-7
@@ -48,11 +48,11 @@ import io.element.android.compound.tokens.generated.CompoundIcons
|
||||
import io.element.android.features.deactivation.impl.R
|
||||
import io.element.android.features.logout.impl.ui.AccountDeactivationActionDialog
|
||||
import io.element.android.libraries.architecture.AsyncAction
|
||||
import io.element.android.libraries.designsystem.atomic.organisms.InfoListItem
|
||||
import io.element.android.libraries.designsystem.atomic.organisms.InfoListOrganism
|
||||
import io.element.android.libraries.designsystem.components.button.BackButton
|
||||
import io.element.android.libraries.designsystem.components.form.textFieldState
|
||||
import io.element.android.libraries.designsystem.components.list.SwitchListItem
|
||||
import io.element.android.libraries.designsystem.components.visuallist.VisualList
|
||||
import io.element.android.libraries.designsystem.components.visuallist.VisualListItemData
|
||||
import io.element.android.libraries.designsystem.modifiers.onTabOrEnterKeyFocusNext
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||
@@ -175,9 +175,9 @@ private fun Content(
|
||||
style = ElementTheme.typography.fontBodyMdRegular,
|
||||
color = ElementTheme.colors.textSecondary,
|
||||
)
|
||||
InfoListOrganism(
|
||||
VisualList(
|
||||
items = persistentListOf(
|
||||
InfoListItem(
|
||||
VisualListItemData(
|
||||
message = buildAnnotatedStringWithStyledPart(
|
||||
R.string.screen_deactivate_account_list_item_1,
|
||||
R.string.screen_deactivate_account_list_item_1_bold_part,
|
||||
@@ -194,7 +194,7 @@ private fun Content(
|
||||
)
|
||||
},
|
||||
),
|
||||
InfoListItem(
|
||||
VisualListItemData(
|
||||
message = stringResource(R.string.screen_deactivate_account_list_item_2),
|
||||
iconComposable = {
|
||||
Icon(
|
||||
@@ -205,7 +205,7 @@ private fun Content(
|
||||
)
|
||||
},
|
||||
),
|
||||
InfoListItem(
|
||||
VisualListItemData(
|
||||
message = stringResource(R.string.screen_deactivate_account_list_item_3),
|
||||
iconComposable = {
|
||||
Icon(
|
||||
@@ -216,7 +216,7 @@ private fun Content(
|
||||
)
|
||||
},
|
||||
),
|
||||
InfoListItem(
|
||||
VisualListItemData(
|
||||
message = stringResource(R.string.screen_deactivate_account_list_item_4),
|
||||
iconComposable = {
|
||||
Icon(
|
||||
|
||||
+6
-6
@@ -22,11 +22,11 @@ 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.securebackup.impl.R
|
||||
import io.element.android.libraries.designsystem.atomic.organisms.InfoListItem
|
||||
import io.element.android.libraries.designsystem.atomic.organisms.InfoListOrganism
|
||||
import io.element.android.libraries.designsystem.atomic.pages.FlowStepPage
|
||||
import io.element.android.libraries.designsystem.components.BigIcon
|
||||
import io.element.android.libraries.designsystem.components.dialogs.ConfirmationDialog
|
||||
import io.element.android.libraries.designsystem.components.visuallist.VisualList
|
||||
import io.element.android.libraries.designsystem.components.visuallist.VisualListItemData
|
||||
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
|
||||
@@ -79,10 +79,10 @@ private fun Content() {
|
||||
modifier = Modifier.padding(top = 8.dp, bottom = 40.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(24.dp),
|
||||
) {
|
||||
InfoListOrganism(
|
||||
VisualList(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
items = persistentListOf(
|
||||
InfoListItem(
|
||||
VisualListItemData(
|
||||
message = stringResource(R.string.screen_encryption_reset_bullet_1),
|
||||
iconComposable = {
|
||||
Icon(
|
||||
@@ -93,7 +93,7 @@ private fun Content() {
|
||||
)
|
||||
},
|
||||
),
|
||||
InfoListItem(
|
||||
VisualListItemData(
|
||||
message = stringResource(R.string.screen_encryption_reset_bullet_2),
|
||||
iconComposable = {
|
||||
Icon(
|
||||
@@ -104,7 +104,7 @@ private fun Content() {
|
||||
)
|
||||
},
|
||||
),
|
||||
InfoListItem(
|
||||
VisualListItemData(
|
||||
message = stringResource(R.string.screen_encryption_reset_bullet_3),
|
||||
iconComposable = {
|
||||
Icon(
|
||||
|
||||
+9
-9
@@ -25,10 +25,10 @@ import io.element.android.compound.theme.ElementTheme
|
||||
import io.element.android.compound.tokens.generated.CompoundIcons
|
||||
import io.element.android.libraries.designsystem.atomic.molecules.ButtonColumnMolecule
|
||||
import io.element.android.libraries.designsystem.atomic.molecules.IconTitleSubtitleMolecule
|
||||
import io.element.android.libraries.designsystem.atomic.organisms.InfoListItem
|
||||
import io.element.android.libraries.designsystem.atomic.organisms.InfoListOrganism
|
||||
import io.element.android.libraries.designsystem.atomic.pages.HeaderFooterPage
|
||||
import io.element.android.libraries.designsystem.components.BigIcon
|
||||
import io.element.android.libraries.designsystem.components.visuallist.VisualList
|
||||
import io.element.android.libraries.designsystem.components.visuallist.VisualListItemData
|
||||
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
|
||||
@@ -43,9 +43,9 @@ fun SignedOutView(
|
||||
BackHandler(onBack = { state.eventSink(SignedOutEvents.SignInAgain) })
|
||||
HeaderFooterPage(
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.systemBarsPadding()
|
||||
.imePadding(),
|
||||
.fillMaxSize()
|
||||
.systemBarsPadding()
|
||||
.imePadding(),
|
||||
header = { SignedOutHeader(state) },
|
||||
content = { SignedOutContent() },
|
||||
footer = {
|
||||
@@ -75,17 +75,17 @@ private fun SignedOutContent() {
|
||||
verticalBias = -0.4f
|
||||
)
|
||||
) {
|
||||
InfoListOrganism(
|
||||
VisualList(
|
||||
items = persistentListOf(
|
||||
InfoListItem(
|
||||
VisualListItemData(
|
||||
message = stringResource(id = R.string.screen_signed_out_reason_1),
|
||||
iconVector = CompoundIcons.Lock(),
|
||||
),
|
||||
InfoListItem(
|
||||
VisualListItemData(
|
||||
message = stringResource(id = R.string.screen_signed_out_reason_2),
|
||||
iconVector = CompoundIcons.Devices(),
|
||||
),
|
||||
InfoListItem(
|
||||
VisualListItemData(
|
||||
message = stringResource(id = R.string.screen_signed_out_reason_3),
|
||||
iconVector = CompoundIcons.Block(),
|
||||
),
|
||||
|
||||
+16
-24
@@ -6,9 +6,8 @@
|
||||
* 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
|
||||
@@ -17,14 +16,11 @@ 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,9 +28,12 @@ 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,
|
||||
@@ -49,12 +48,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 +95,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,
|
||||
)
|
||||
}
|
||||
+20
-17
@@ -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,
|
||||
+19
@@ -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 = {},
|
||||
)
|
||||
Reference in New Issue
Block a user