Updated on 2026-08-14

This commit is contained in:
Tangem 2024-10-01 11:20:02 +04:00
parent bfc17662fa
commit 2f200e3194
11 changed files with 182 additions and 36 deletions

View file

@ -0,0 +1,86 @@
package com.tangem.core.ui.components.audits
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
/**
* Audit label component
*
* @param state state
* @param modifier modifier
*
* @see <a href="https://www.figma.com/design/14ISV23YB1yVW1uNVwqrKv/Android?node-id=3401-3635&t=kjnj9RhYUOwbO1hn-4">Figma</a>
*
[REDACTED_AUTHOR]
*/
@Composable
fun AuditLabel(state: AuditLabelUM, modifier: Modifier = Modifier) {
AuditLabelInternal(
textReference = state.text,
textColor = getColorByType(state.type),
backgroundColor = getColorByType(state.type).copy(alpha = 0.1f),
modifier = modifier,
)
}
@Composable
private fun AuditLabelInternal(
textReference: TextReference,
textColor: Color,
backgroundColor: Color,
modifier: Modifier = Modifier,
) {
Box(
modifier = modifier.background(
color = backgroundColor,
shape = TangemTheme.shapes.roundedCornersSmall2,
),
) {
Text(
text = textReference.resolveReference(),
style = TangemTheme.typography.caption1,
color = textColor,
modifier = Modifier.padding(horizontal = TangemTheme.dimens.spacing4),
)
}
}
@ReadOnlyComposable
@Composable
private fun getColorByType(type: AuditLabelUM.Type): Color {
return when (type) {
AuditLabelUM.Type.Prohibition -> TangemTheme.colors.text.warning
AuditLabelUM.Type.Warning -> TangemTheme.colors.text.attention
AuditLabelUM.Type.Permit -> TangemTheme.colors.text.accent
}
}
@Preview
@Composable
private fun Preview_AuditLabel(@PreviewParameter(AuditLabelUMProvider::class) state: AuditLabelUM) {
TangemThemePreview {
AuditLabel(state = state)
}
}
private class AuditLabelUMProvider : CollectionPreviewParameterProvider<AuditLabelUM>(
collection = AuditLabelUM.Type.entries.map { type ->
AuditLabelUM(
text = TextReference.Str(value = type.name),
type = type,
)
},
)

View file

@ -0,0 +1,26 @@
package com.tangem.core.ui.components.audits
import com.tangem.core.ui.extensions.TextReference
/**
* Audit label component UI model
*
* @property text text reference
* @property type type of label
*
[REDACTED_AUTHOR]
*/
data class AuditLabelUM(val text: TextReference, val type: Type) {
enum class Type {
/** Red. Like, "risky" */
Prohibition,
/** Yellow. Like, "caution" */
Warning,
/** Blue. Like, "trusted" */
Permit,
}
}

View file

@ -17,11 +17,13 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
import androidx.compose.ui.unit.Constraints
import com.tangem.core.ui.R
import com.tangem.core.ui.components.audits.AuditLabelUM
import com.tangem.core.ui.components.currency.icon.CurrencyIcon
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
import com.tangem.core.ui.components.marketprice.PriceChangeType
import com.tangem.core.ui.components.token.internal.*
import com.tangem.core.ui.components.token.state.TokenItemState
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.rememberHapticFeedback
import com.tangem.core.ui.res.TangemColorPalette
import com.tangem.core.ui.res.TangemTheme
@ -122,7 +124,7 @@ fun TokenItem(
)
TokenCryptoAmount(
state = state.cryptoAmountState,
state = state.subtitle2State,
isBalanceHidden = isBalanceHidden,
modifier = Modifier.layoutId(layoutId = LayoutId.CRYPTO_AMOUNT),
)
@ -461,7 +463,7 @@ private class TokenItemStateProvider : CollectionPreviewParameterProvider<TokenI
text = "3213123123321312312312312312 $",
hasStaked = true,
),
cryptoAmountState = TokenItemState.CryptoAmountState.Content(text = "5,4123123213123123123123123123 MATIC"),
subtitle2State = TokenItemState.Subtitle2State.TextContent(text = "5,4123123213123123123123123123 MATIC"),
subtitleState = TokenItemState.SubtitleState.CryptoPriceContent(
price = "312 USD",
priceChangePercent = "42.0%",
@ -500,14 +502,33 @@ private class TokenItemStateProvider : CollectionPreviewParameterProvider<TokenI
id = UUID.randomUUID().toString(),
iconState = tokenIconState,
titleState = TokenItemState.TitleState.Content(text = "Polygon"),
cryptoAmountState = TokenItemState.CryptoAmountState.Content(text = "3 172,14 $"),
subtitle2State = TokenItemState.Subtitle2State.TextContent(text = "3 172,14 $"),
),
TokenItemState.Content(
id = UUID.randomUUID().toString(),
iconState = tokenIconState,
titleState = TokenItemState.TitleState.Content(text = "Polygon"),
fiatAmountState = TokenItemState.FiatAmountState.Content(text = "321 $", hasStaked = false),
cryptoAmountState = TokenItemState.CryptoAmountState.Content(text = "5,412 MATIC"),
subtitle2State = TokenItemState.Subtitle2State.TextContent(text = "5,412 MATIC"),
subtitleState = TokenItemState.SubtitleState.CryptoPriceContent(
price = "312 USD",
priceChangePercent = "2.0%",
type = PriceChangeType.UP,
),
onItemClick = {},
onItemLongClick = {},
),
TokenItemState.Content(
id = UUID.randomUUID().toString(),
iconState = tokenIconState,
titleState = TokenItemState.TitleState.Content(text = "Polygon"),
fiatAmountState = TokenItemState.FiatAmountState.Content(text = "321 $", hasStaked = false),
subtitle2State = TokenItemState.Subtitle2State.LabelContent(
auditLabelUM = AuditLabelUM(
text = TextReference.Str(value = "Trusted"),
type = AuditLabelUM.Type.Permit,
),
),
subtitleState = TokenItemState.SubtitleState.CryptoPriceContent(
price = "312 USD",
priceChangePercent = "2.0%",
@ -573,7 +594,7 @@ private class TokenItemStateProvider : CollectionPreviewParameterProvider<TokenI
iconState = coinIconState,
titleState = TokenItemState.TitleState.Content(text = "Polygon", hasPending = true),
fiatAmountState = TokenItemState.FiatAmountState.Content(text = "321 $", hasStaked = true),
cryptoAmountState = TokenItemState.CryptoAmountState.Content(text = "5,412 MATIC"),
subtitle2State = TokenItemState.Subtitle2State.TextContent(text = "5,412 MATIC"),
subtitleState = TokenItemState.SubtitleState.Unknown,
onItemClick = {},
onItemLongClick = {},

View file

@ -10,9 +10,11 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import com.tangem.core.ui.R
import com.tangem.core.ui.components.RectangleShimmer
import com.tangem.core.ui.components.audits.AuditLabel
import com.tangem.core.ui.components.token.state.TokenItemState
import com.tangem.core.ui.extensions.orMaskWithStars
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.components.token.state.TokenItemState.CryptoAmountState as TokenCryptoAmountState
import com.tangem.core.ui.components.token.state.TokenItemState.Subtitle2State as TokenCryptoAmountState
@Composable
internal fun TokenCryptoAmount(
@ -21,12 +23,15 @@ internal fun TokenCryptoAmount(
modifier: Modifier = Modifier,
) {
when (state) {
is TokenCryptoAmountState.Content -> {
is TokenCryptoAmountState.TextContent -> {
CryptoAmountText(
amount = state.text.orMaskWithStars(isBalanceHidden),
modifier = modifier,
)
}
is TokenItemState.Subtitle2State.LabelContent -> {
AuditLabel(state = state.auditLabelUM, modifier = modifier)
}
is TokenCryptoAmountState.Unreachable -> {
CryptoAmountText(amount = stringResource(id = R.string.common_unreachable), modifier = modifier)
}

View file

@ -1,6 +1,7 @@
package com.tangem.core.ui.components.token.state
import androidx.compose.runtime.Immutable
import com.tangem.core.ui.components.audits.AuditLabelUM
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
import com.tangem.core.ui.components.marketprice.PriceChangeType
@ -17,14 +18,17 @@ sealed class TokenItemState {
/** Token title state (in one row with [fiatAmountState]) */
abstract val titleState: TitleState
/** Token subtitle state (under [titleState] and in one row with [cryptoAmountState]) */
/** Token subtitle state (under [titleState] and in one row with [subtitle2State]) */
abstract val subtitleState: SubtitleState?
/** Token fiat amount state (in one row with [titleState]) */
abstract val fiatAmountState: FiatAmountState?
/** Token crypto amount state (under [fiatAmountState] and in one row with [subtitleState]) */
abstract val cryptoAmountState: CryptoAmountState?
/**
* Second subtitle state (under [fiatAmountState] and in one row with [subtitleState]).
* Example, token crypto amount.
*/
abstract val subtitle2State: Subtitle2State?
/** Callback which will be called when an item is clicked */
abstract val onItemClick: (() -> Unit)?
@ -47,7 +51,7 @@ sealed class TokenItemState {
override val subtitleState: SubtitleState = SubtitleState.Loading,
) : TokenItemState() {
override val fiatAmountState: FiatAmountState = FiatAmountState.Loading
override val cryptoAmountState: CryptoAmountState = CryptoAmountState.Loading
override val subtitle2State: Subtitle2State = Subtitle2State.Loading
override val onItemClick: (() -> Unit)? = null
override val onItemLongClick: (() -> Unit)? = null
}
@ -62,7 +66,7 @@ sealed class TokenItemState {
override val titleState: TitleState = TitleState.Locked
override val subtitleState: SubtitleState = SubtitleState.Locked
override val fiatAmountState: FiatAmountState = FiatAmountState.Locked
override val cryptoAmountState: CryptoAmountState = CryptoAmountState.Locked
override val subtitle2State: Subtitle2State = Subtitle2State.Locked
override val onItemClick: (() -> Unit)? = null
override val onItemLongClick: (() -> Unit)? = null
}
@ -75,7 +79,7 @@ sealed class TokenItemState {
* @property titleState token title
* @property subtitleState token subtitle
* @property fiatAmountState token fiat amount
* @property cryptoAmountState token crypto amount
* @property subtitle2State token crypto amount
* @property onItemClick callback which will be called when an item is clicked
* @property onItemLongClick callback which will be called when an item is long clicked
*/
@ -85,7 +89,7 @@ sealed class TokenItemState {
override val titleState: TitleState,
override val subtitleState: SubtitleState,
override val fiatAmountState: FiatAmountState,
override val cryptoAmountState: CryptoAmountState.Content,
override val subtitle2State: Subtitle2State,
override val onItemClick: (() -> Unit)?,
override val onItemLongClick: (() -> Unit)?,
) : TokenItemState()
@ -96,13 +100,13 @@ sealed class TokenItemState {
* @property id unique id
* @property iconState token icon state
* @property titleState token title
* @property cryptoAmountState token crypto amount
* @property subtitle2State token crypto amount
*/
data class Draggable(
override val id: String,
override val iconState: CurrencyIconState,
override val titleState: TitleState,
override val cryptoAmountState: CryptoAmountState,
override val subtitle2State: Subtitle2State,
) : TokenItemState() {
override val subtitleState: SubtitleState? = null
override val fiatAmountState: FiatAmountState? = null
@ -129,7 +133,7 @@ sealed class TokenItemState {
override val onItemLongClick: (() -> Unit)?,
) : TokenItemState() {
override val fiatAmountState: FiatAmountState? = null
override val cryptoAmountState: CryptoAmountState? = null
override val subtitle2State: Subtitle2State? = null
}
/**
@ -149,7 +153,7 @@ sealed class TokenItemState {
override val onItemLongClick: (() -> Unit)?,
) : TokenItemState() {
override val fiatAmountState: FiatAmountState? = null
override val cryptoAmountState: CryptoAmountState? = null
override val subtitle2State: Subtitle2State? = null
override val onItemClick: (() -> Unit)? = null
}
@ -194,13 +198,16 @@ sealed class TokenItemState {
}
@Immutable
sealed class CryptoAmountState {
data class Content(val text: String) : CryptoAmountState()
sealed class Subtitle2State {
data object Unreachable : CryptoAmountState()
data class TextContent(val text: String) : Subtitle2State()
data object Loading : CryptoAmountState()
data class LabelContent(val auditLabelUM: AuditLabelUM) : Subtitle2State()
data object Locked : CryptoAmountState()
data object Unreachable : Subtitle2State()
data object Loading : Subtitle2State()
data object Locked : Subtitle2State()
}
}