Updated on 2026-08-14

This commit is contained in:
Tangem 2024-07-26 11:14:52 +03:00
parent 2cd0164d1d
commit 5016ee56ea
10 changed files with 1798 additions and 1560 deletions

View file

@ -0,0 +1,125 @@
package com.tangem.core.ui.components.notifications
import android.content.res.Configuration
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.text.ClickableText
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.colorspace.ColorSpaces
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.tooling.preview.Preview
import com.tangem.core.ui.R
import com.tangem.core.ui.components.SpacerW
import com.tangem.core.ui.components.currency.tokenicon.TokenIcon
import com.tangem.core.ui.components.currency.tokenicon.TokenIconState
import com.tangem.core.ui.extensions.*
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
/**
* Currency notification component from Design system.
*
* @param config component config
* @param modifier modifier
* @param containerColor container color
*
* @see <a href = "https://www.figma.com/design/14ISV23YB1yVW1uNVwqrKv/Android?node-id=3251-3466&t=eZb7ZPoNE8pQw45Y-4"
* >Figma component</a>
*/
@Composable
fun CurrencyNotification(
config: CurrencyNotificationConfig,
modifier: Modifier = Modifier,
containerColor: Color? = null,
) {
NotificationBaseContainer(
buttonsState = config.buttonsState,
onClick = null,
onCloseClick = null,
modifier = modifier,
containerColor = containerColor,
) {
MainContent(
tokenIconState = config.tokenIconState,
title = config.title,
subtitle = config.subtitle,
)
}
}
@Composable
private fun MainContent(
tokenIconState: TokenIconState,
title: TextReference,
subtitle: CurrencyNotificationConfig.AnnotatedSubtitle,
) {
Row {
TokenIcon(
state = tokenIconState,
modifier = Modifier.align(alignment = Alignment.CenterVertically),
)
SpacerW(width = TangemTheme.dimens.spacing6)
TextsBlock(title = title, subtitle = subtitle)
}
}
@Composable
private fun TextsBlock(title: TextReference, subtitle: CurrencyNotificationConfig.AnnotatedSubtitle) {
Column(verticalArrangement = Arrangement.spacedBy(space = TangemTheme.dimens.spacing2)) {
Text(
text = title.resolveReference(),
color = TangemTheme.colors.text.primary1,
style = TangemTheme.typography.button,
)
val subtitleValue = subtitle.valueProvider()
ClickableText(
text = subtitleValue,
onClick = { subtitle.onClick(subtitleValue, it) },
style = TangemTheme.typography.caption2,
)
}
}
@Preview
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
private fun Preview_Notification() {
TangemThemePreview {
CurrencyNotification(
config = CurrencyNotificationConfig(
title = resourceReference(
R.string.express_exchange_notification_refund_title,
wrappedList("USDT", "Polygon"),
),
subtitle = CurrencyNotificationConfig.AnnotatedSubtitle(
valueProvider = {
buildAnnotatedString {
append("Your transaction amount was refunded in USDT to your wallet due to OKX")
}
},
onClick = { _, _ -> },
),
tokenIconState = TokenIconState.TokenIcon(
url = "https://s3.eu-central-1.amazonaws.com/tangem.api/coins/large/usd-coin.png",
networkBadgeIconResId = R.drawable.ic_polygon_22,
isGrayscale = false,
showCustomBadge = false,
fallbackTint = Color(1.0f, 1.0f, 1.0f, 1.0f, ColorSpaces.Srgb),
fallbackBackground = Color(0.23529412f, 0.28627452f, 0.6117647f, 1.0f, ColorSpaces.Srgb),
),
buttonsState = NotificationConfig.ButtonsState.SecondaryButtonConfig(
text = stringReference("Go to token"),
onClick = {},
),
),
)
}
}

View file

@ -0,0 +1,35 @@
package com.tangem.core.ui.components.notifications
import androidx.compose.runtime.Composable
import androidx.compose.ui.text.AnnotatedString
import com.tangem.core.ui.components.currency.tokenicon.TokenIconState
import com.tangem.core.ui.extensions.TextReference
/**
* Currency notification component state
*
* @property title title
* @property subtitle subtitle
* @property buttonsState buttons state
* @property tokenIconState token icon state
*
[REDACTED_AUTHOR]
*/
data class CurrencyNotificationConfig(
val title: TextReference,
val subtitle: AnnotatedSubtitle,
val tokenIconState: TokenIconState,
val buttonsState: NotificationConfig.ButtonsState,
) {
/**
* Subtitle as [AnnotatedString]
*
* @property valueProvider composable function that provides [AnnotatedString]
* @property onClick lambda be invoked when text in specified position is clicked
*/
data class AnnotatedSubtitle(
val valueProvider: @Composable () -> AnnotatedString,
val onClick: (value: AnnotatedString, position: Int) -> Unit,
)
}

View file

@ -30,17 +30,19 @@ import com.tangem.core.ui.components.*
import com.tangem.core.ui.components.buttons.common.TangemButtonSize
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.core.ui.components.notifications.NotificationConfig.ButtonsState as NotificationButtonsState
/**
* Notification component from Design system.
* Use this for Notification with title, subtitle, clickable or not.
*
* @param config component config
* @param modifier modifier
* @param iconTint icon tint
* @param config component config
* @param modifier modifier
* @param containerColor container color
* @param iconTint icon tint
* @param isEnabled flag that defines if component is clickable
*
* @see <a href = "https://www.figma.com/file/14ISV23YB1yVW1uNVwqrKv/Android?node-id=1045-807&t=6CVvYDJe0sB7wBKE-0"
* >Figma component</a>
@ -53,44 +55,33 @@ fun Notification(
iconTint: Color? = null,
isEnabled: Boolean = true,
) {
BaseContainer(
NotificationBaseContainer(
buttonsState = config.buttonsState,
onClick = config.onClick,
onCloseClick = config.onCloseClick,
modifier = modifier,
containerColor = containerColor,
isEnabled = isEnabled,
) {
Column(
modifier = Modifier.padding(all = TangemTheme.dimens.spacing12),
verticalArrangement = Arrangement.spacedBy(space = TangemTheme.dimens.spacing12),
) {
MainContent(
iconResId = config.iconResId,
iconTint = iconTint,
title = config.title,
subtitle = config.subtitle,
isClickableComponent = isEnabled && config.onClick != null,
)
Buttons(state = config.buttonsState, isEnabled = isEnabled)
}
CloseableIconButton(
onClick = config.onCloseClick,
modifier = Modifier.align(alignment = Alignment.TopEnd),
isEnabled = isEnabled,
MainContent(
iconResId = config.iconResId,
iconTint = iconTint,
title = config.title,
subtitle = config.subtitle,
isClickableComponent = isEnabled && config.onClick != null,
)
}
}
@Composable
private fun BaseContainer(
internal fun NotificationBaseContainer(
buttonsState: NotificationConfig.ButtonsState?,
onClick: (() -> Unit)?,
onCloseClick: (() -> Unit)?,
modifier: Modifier = Modifier,
isEnabled: Boolean = true,
containerColor: Color? = null,
content: @Composable BoxScope.() -> Unit,
content: @Composable ColumnScope.() -> Unit,
) {
val tempContainerColor by rememberUpdatedState(
newValue = if (buttonsState != null || onClick != null) {
@ -109,7 +100,22 @@ private fun BaseContainer(
shape = TangemTheme.shapes.roundedCornersXMedium,
color = containerColor ?: tempContainerColor,
) {
Box(content = content)
Box {
Column(
modifier = Modifier.padding(all = TangemTheme.dimens.spacing12),
verticalArrangement = Arrangement.spacedBy(space = TangemTheme.dimens.spacing12),
) {
content()
Buttons(state = buttonsState, isEnabled = isEnabled)
}
CloseableIconButton(
onClick = onCloseClick,
modifier = Modifier.align(alignment = Alignment.TopEnd),
isEnabled = isEnabled,
)
}
}
}