change(design) : introduce Announcement component
This commit is contained in:
parent
f31e648e35
commit
dff29fa270
1 changed files with 208 additions and 0 deletions
|
|
@ -0,0 +1,208 @@
|
|||
/*
|
||||
* Copyright 2025 New Vector 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
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement.spacedBy
|
||||
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.width
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.stringResource
|
||||
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.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.ButtonSize
|
||||
import io.element.android.libraries.designsystem.theme.components.Icon
|
||||
import io.element.android.libraries.designsystem.theme.components.Surface
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
|
||||
@Composable
|
||||
fun Announcement(
|
||||
title: String,
|
||||
description: String?,
|
||||
type: AnnouncementType,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
when (type) {
|
||||
is AnnouncementType.Informative -> InformativeAnnouncement(
|
||||
title = title,
|
||||
description = description,
|
||||
isError = type.isError,
|
||||
modifier = modifier,
|
||||
)
|
||||
is AnnouncementType.Actionable -> ActionableAnnouncement(
|
||||
title = title,
|
||||
description = description,
|
||||
actionText = type.actionText,
|
||||
onActionClick = type.onActionClick,
|
||||
onDismissClick = type.onDismissClick,
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Immutable
|
||||
sealed interface AnnouncementType {
|
||||
data class Informative(val isError: Boolean = false) : AnnouncementType
|
||||
data class Actionable(
|
||||
val actionText: String,
|
||||
val onActionClick: () -> Unit,
|
||||
val onDismissClick: (() -> Unit)?,
|
||||
) : AnnouncementType
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ActionableAnnouncement(
|
||||
title: String,
|
||||
description: String?,
|
||||
actionText: String,
|
||||
onActionClick: () -> Unit,
|
||||
onDismissClick: (() -> Unit)?,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
AnnouncementSurface(modifier) {
|
||||
Column {
|
||||
TitleAndDescription(
|
||||
title = title,
|
||||
description = description,
|
||||
trailingContent = onDismissClick?.let {
|
||||
{
|
||||
Icon(
|
||||
modifier = Modifier.clickable(onClick = onDismissClick),
|
||||
imageVector = CompoundIcons.Close(),
|
||||
contentDescription = stringResource(CommonStrings.action_close)
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
Spacer(Modifier.height(16.dp))
|
||||
Button(
|
||||
text = actionText,
|
||||
size = ButtonSize.Medium,
|
||||
onClick = onActionClick,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun InformativeAnnouncement(
|
||||
title: String,
|
||||
description: String?,
|
||||
isError: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
AnnouncementSurface(modifier = modifier) {
|
||||
Row {
|
||||
Icon(
|
||||
imageVector = if (isError) CompoundIcons.Error() else CompoundIcons.Info(),
|
||||
tint = if (isError) ElementTheme.colors.iconCriticalPrimary else ElementTheme.colors.iconPrimary,
|
||||
contentDescription = null,
|
||||
)
|
||||
Spacer(Modifier.width(12.dp))
|
||||
TitleAndDescription(
|
||||
title = title,
|
||||
description = description,
|
||||
titleColor = if (isError) ElementTheme.colors.textCriticalPrimary else ElementTheme.colors.textPrimary,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TitleAndDescription(
|
||||
title: String,
|
||||
description: String?,
|
||||
modifier: Modifier = Modifier,
|
||||
titleColor: Color = ElementTheme.colors.textPrimary,
|
||||
descriptionColor: Color = ElementTheme.colors.textSecondary,
|
||||
trailingContent: (@Composable () -> Unit)? = null,
|
||||
) {
|
||||
Column(modifier = modifier) {
|
||||
Row {
|
||||
Text(
|
||||
text = title,
|
||||
style = ElementTheme.typography.fontBodyLgMedium,
|
||||
color = titleColor,
|
||||
modifier = Modifier.weight(1f),
|
||||
)
|
||||
if (trailingContent != null) {
|
||||
Spacer(Modifier.width(12.dp))
|
||||
trailingContent()
|
||||
}
|
||||
}
|
||||
if (description != null) {
|
||||
Spacer(Modifier.height(4.dp))
|
||||
Text(
|
||||
text = description,
|
||||
style = ElementTheme.typography.fontBodyMdRegular,
|
||||
color = descriptionColor,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun AnnouncementSurface(
|
||||
modifier: Modifier = Modifier,
|
||||
content: @Composable () -> Unit,
|
||||
) {
|
||||
Surface(
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
shape = RoundedCornerShape(size = 12.dp),
|
||||
color = ElementTheme.colors.bgSubtleSecondary
|
||||
) {
|
||||
Box(modifier = Modifier.padding(16.dp)) {
|
||||
content()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@PreviewsDayNight
|
||||
@Composable
|
||||
internal fun AnnouncementPreview() = ElementPreview {
|
||||
Column(
|
||||
verticalArrangement = spacedBy(16.dp),
|
||||
modifier = Modifier.padding(16.dp)
|
||||
) {
|
||||
Announcement(
|
||||
title = "Headline",
|
||||
description = "Text description goes here.",
|
||||
type = AnnouncementType.Informative(isError = false),
|
||||
)
|
||||
Announcement(
|
||||
title = "Headline",
|
||||
description = "Text description goes here.",
|
||||
type = AnnouncementType.Informative(isError = true),
|
||||
)
|
||||
Announcement(
|
||||
title = "Headline",
|
||||
description = "Text description goes here.",
|
||||
type = AnnouncementType.Actionable(
|
||||
actionText = "Label",
|
||||
onActionClick = {},
|
||||
onDismissClick = {},
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue