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

@ -69,7 +69,7 @@ class TokenItemStateConverter(
text = getFormattedFiatAmount(),
hasStaked = !getStakedBalance().isZero(),
),
cryptoAmountState = TokenItemState.CryptoAmountState.Content(text = getFormattedAmount()),
subtitle2State = TokenItemState.Subtitle2State.TextContent(text = getFormattedAmount()),
onItemClick = { onItemClick(this) },
onItemLongClick = onItemLongClick?.let {
{ it(this) }

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()
}
}

View file

@ -102,7 +102,8 @@ private class PortfolioTokenUMProvider : CollectionPreviewParameterProvider<Port
tokenUM.copy(
tokenItemState = tokenUM.tokenItemState.copy(
fiatAmountState = contentFiatAmount.copy(text = DASH_SIGN),
cryptoAmountState = tokenUM.tokenItemState.cryptoAmountState.copy(text = DASH_SIGN),
subtitle2State = (tokenUM.tokenItemState.subtitle2State as TokenItemState.Subtitle2State.TextContent)
.copy(text = DASH_SIGN),
),
),
tokenUM.copy(isBalanceHidden = true),

View file

@ -51,7 +51,7 @@ internal class PreviewMyPortfolioUMProvider : PreviewParameterProvider<MyPortfol
iconState = CurrencyIconState.Locked,
titleState = TokenItemState.TitleState.Content(text = "My wallet"),
fiatAmountState = TokenItemState.FiatAmountState.Content(text = "486,65 \$"),
cryptoAmountState = TokenItemState.CryptoAmountState.Content(text = "733,71097 MATIC"),
subtitle2State = TokenItemState.Subtitle2State.TextContent(text = "733,71097 MATIC"),
subtitleState = TokenItemState.SubtitleState.TextContent(value = "XRP Ledger token"),
onItemClick = {},
onItemLongClick = {},
@ -63,6 +63,6 @@ internal class PreviewMyPortfolioUMProvider : PreviewParameterProvider<MyPortfol
onQuickActionLongClick = {},
),
isBalanceHidden = false,
walletId = UserWalletId("walletId"),
walletId = UserWalletId(""),
)
}

View file

@ -77,7 +77,7 @@ internal object WalletPreviewData {
showCustomBadge = false,
),
titleState = TokenItemState.TitleState.Content(text = "Polygon"),
cryptoAmountState = TokenItemState.CryptoAmountState.Content(text = "3 172,14 $"),
subtitle2State = TokenItemState.Subtitle2State.TextContent(text = "3 172,14 $"),
)
}

View file

@ -20,7 +20,7 @@ internal object WalletScreenPreviewData {
iconState = CurrencyIconState.Locked,
titleState = TokenItemState.TitleState.Content(text = "Bitcoin"),
fiatAmountState = TokenItemState.FiatAmountState.Content(text = "12 368,14 \$"),
cryptoAmountState = TokenItemState.CryptoAmountState.Content(text = "0,35853044 BTC"),
subtitle2State = TokenItemState.Subtitle2State.TextContent(text = "0,35853044 BTC"),
subtitleState = TokenItemState.SubtitleState.CryptoPriceContent(
price = "34 496,75 \$",
priceChangePercent = "0,43 %",
@ -30,7 +30,7 @@ internal object WalletScreenPreviewData {
onItemLongClick = {},
)
private val contentTokensState = WalletTokensListState.ContentState.Content(
private val textContentTokensState = WalletTokensListState.ContentState.Content(
items = persistentListOf(
WalletTokensListState.TokensListItemState.NetworkGroupTitle(
id = 1,
@ -46,7 +46,7 @@ internal object WalletScreenPreviewData {
id = "2",
titleState = TokenItemState.TitleState.Content(text = "Ethereum"),
fiatAmountState = TokenItemState.FiatAmountState.Content(text = "3 340,79 \$"),
cryptoAmountState = TokenItemState.CryptoAmountState.Content(text = "1,856660295 ETH"),
subtitle2State = TokenItemState.Subtitle2State.TextContent(text = "1,856660295 ETH"),
subtitleState = TokenItemState.SubtitleState.CryptoPriceContent(
price = "1 799,41 \$",
priceChangePercent = "5,16 %",
@ -68,7 +68,7 @@ internal object WalletScreenPreviewData {
id = "4",
titleState = TokenItemState.TitleState.Content(text = "Shiba Inu"),
fiatAmountState = TokenItemState.FiatAmountState.Content(text = "48,64 \$"),
cryptoAmountState = TokenItemState.CryptoAmountState.Content(text = "6 200 220,00 SHIB"),
subtitle2State = TokenItemState.Subtitle2State.TextContent(text = "6 200 220,00 SHIB"),
subtitleState = TokenItemState.SubtitleState.CryptoPriceContent(
price = "0.01 \$",
priceChangePercent = "1,34 %",
@ -122,7 +122,7 @@ internal object WalletScreenPreviewData {
WalletNotification.Warning.SomeNetworksUnreachable,
),
bottomSheetConfig = null,
tokensListState = contentTokensState,
tokensListState = textContentTokensState,
)
}

View file

@ -47,10 +47,10 @@ internal class CryptoCurrencyToDraggableItemConverter(
id = getTokenItemId(currency.id),
iconState = iconStateConverter.convert(currencyStatus),
titleState = TokenItemState.TitleState.Content(text = currency.name),
cryptoAmountState = if (currencyStatus.value.isError) {
TokenItemState.CryptoAmountState.Unreachable
subtitle2State = if (currencyStatus.value.isError) {
TokenItemState.Subtitle2State.Unreachable
} else {
TokenItemState.CryptoAmountState.Content(text = getFormattedFiatAmount(currencyStatus, appCurrency))
TokenItemState.Subtitle2State.TextContent(text = getFormattedFiatAmount(currencyStatus, appCurrency))
},
)
}