Updated on 2026-08-14

This commit is contained in:
Tangem 2024-06-26 19:09:46 +04:00
parent e2403d5f5f
commit 1fbf2debcd
35 changed files with 169 additions and 156 deletions

View file

@ -13,7 +13,7 @@ import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.Dp
import coil.compose.SubcomposeAsyncImage
import coil.request.ImageRequest
import com.tangem.core.ui.components.currency.tokenicon.LoadingIcon
import com.tangem.core.ui.components.currency.icon.LoadingIcon
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.utils.ImageBackgroundContrastChecker
import kotlinx.coroutines.launch

View file

@ -1,4 +1,4 @@
package com.tangem.core.ui.components.currency.tokenicon
package com.tangem.core.ui.components.currency.icon
import androidx.annotation.DrawableRes
import androidx.compose.foundation.Image
@ -18,20 +18,20 @@ import com.tangem.core.ui.res.TangemTheme
@Composable
internal fun ContentIcon(
icon: TokenIconState,
icon: CurrencyIconState,
alpha: Float,
colorFilter: ColorFilter?,
modifier: Modifier = Modifier,
) {
when (icon) {
is TokenIconState.CoinIcon -> CoinIcon(
is CurrencyIconState.CoinIcon -> CoinIcon(
modifier = modifier,
url = icon.url,
fallbackResId = icon.fallbackResId,
alpha = alpha,
colorFilter = colorFilter,
)
is TokenIconState.TokenIcon -> TokenIcon(
is CurrencyIconState.TokenIcon -> TokenIcon(
modifier = modifier,
url = icon.url,
alpha = alpha,
@ -45,14 +45,14 @@ internal fun ContentIcon(
)
},
)
is TokenIconState.CustomTokenIcon -> CustomTokenIcon(
is CurrencyIconState.CustomTokenIcon -> CustomTokenIcon(
modifier = modifier,
tint = icon.tint,
background = icon.background,
alpha = alpha,
)
TokenIconState.Loading,
TokenIconState.Locked,
CurrencyIconState.Loading,
CurrencyIconState.Locked,
-> Unit
}
}

View file

@ -1,4 +1,4 @@
package com.tangem.core.ui.components.currency.tokenicon
package com.tangem.core.ui.components.currency.icon
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
@ -26,23 +26,23 @@ import com.tangem.core.ui.utils.NORMAL_ALPHA
* @param shouldDisplayNetwork specifies whether to display network badge
*/
@Composable
fun TokenIcon(state: TokenIconState, modifier: Modifier = Modifier, shouldDisplayNetwork: Boolean = true) {
fun CurrencyIcon(state: CurrencyIconState, modifier: Modifier = Modifier, shouldDisplayNetwork: Boolean = true) {
BaseContainer(modifier = modifier) {
val iconModifier = Modifier
.align(Alignment.Center)
.size(TangemTheme.dimens.size36)
when (state) {
is TokenIconState.Loading -> LoadingIcon(modifier = iconModifier)
is TokenIconState.Locked -> LockedIcon(modifier = iconModifier)
is TokenIconState.CoinIcon,
is TokenIconState.CustomTokenIcon,
is TokenIconState.TokenIcon,
is CurrencyIconState.Loading -> LoadingIcon(modifier = iconModifier)
is CurrencyIconState.Locked -> LockedIcon(modifier = iconModifier)
is CurrencyIconState.CoinIcon,
is CurrencyIconState.CustomTokenIcon,
is CurrencyIconState.TokenIcon,
-> {
ContentIconContainer(
icon = state,
modifier = iconModifier,
shouldDisplayNetwork = shouldDisplayNetwork,
shouldShowTopBadge = shouldDisplayNetwork,
)
}
}
@ -70,9 +70,9 @@ private fun LockedIcon(modifier: Modifier = Modifier) {
@Composable
private fun BoxScope.ContentIconContainer(
icon: TokenIconState,
icon: CurrencyIconState,
shouldShowTopBadge: Boolean,
modifier: Modifier = Modifier,
shouldDisplayNetwork: Boolean = true,
) {
val networkBadgeOffset = TangemTheme.dimens.spacing4
val (alpha, colorFilter) = remember(icon.isGrayscale) {
@ -90,19 +90,21 @@ private fun BoxScope.ContentIconContainer(
colorFilter = colorFilter,
)
if (icon.networkBadgeIconResId != null && shouldDisplayNetwork) {
NetworkBadge(
if (icon.topBadgeIconResId != null && shouldShowTopBadge) {
TopBadge(
modifier = Modifier
.offset(x = networkBadgeOffset, y = -networkBadgeOffset)
.align(Alignment.TopEnd),
iconResId = requireNotNull(icon.networkBadgeIconResId),
iconResId = requireNotNull(icon.topBadgeIconResId),
alpha = alpha,
colorFilter = colorFilter,
)
}
if (icon.showCustomBadge) {
CustomBadge(modifier = Modifier.align(Alignment.BottomEnd))
BottomBadge(
modifier = Modifier.align(Alignment.BottomEnd),
)
}
}

View file

@ -1,4 +1,4 @@
package com.tangem.core.ui.components.currency.tokenicon
package com.tangem.core.ui.components.currency.icon
import androidx.annotation.DrawableRes
import androidx.compose.runtime.Immutable
@ -10,11 +10,11 @@ import androidx.compose.ui.graphics.Color
* [REDACTED_TODO_COMMENT]
*/
@Immutable
sealed class TokenIconState {
sealed class CurrencyIconState {
abstract val isGrayscale: Boolean
abstract val showCustomBadge: Boolean
abstract val networkBadgeIconResId: Int?
abstract val topBadgeIconResId: Int?
/**
* Represents a coin icon.
@ -29,16 +29,16 @@ sealed class TokenIconState {
@DrawableRes val fallbackResId: Int,
override val isGrayscale: Boolean,
override val showCustomBadge: Boolean,
) : TokenIconState() {
) : CurrencyIconState() {
override val networkBadgeIconResId: Int? = null
override val topBadgeIconResId: Int? = null
}
/**
* Represents a token icon.
*
* @property url The URL where the token icon can be fetched from. May be `null` if not found.
* @property networkBadgeIconResId The drawable resource ID for the network badge.
* @property topBadgeIconResId The drawable resource ID for the network badge.
* @property isGrayscale Specifies whether to show the icon in grayscale.
* @property showCustomBadge Specifies whether to show the custom token badge.
* @property fallbackTint The color to be used for tinting the fallback icon.
@ -46,39 +46,39 @@ sealed class TokenIconState {
*/
data class TokenIcon(
val url: String?,
@DrawableRes override val networkBadgeIconResId: Int,
@DrawableRes override val topBadgeIconResId: Int,
override val isGrayscale: Boolean,
override val showCustomBadge: Boolean,
val fallbackTint: Color,
val fallbackBackground: Color,
) : TokenIconState()
) : CurrencyIconState()
/**
* Represents a custom token icon.
*
* @property tint The color to be used for tinting the icon.
* @property background The background color to be used for the icon.
* @property networkBadgeIconResId The drawable resource ID for the network badge.
* @property topBadgeIconResId The drawable resource ID for the network badge.
* @property isGrayscale Specifies whether to show the icon in grayscale.
* @property showCustomBadge Specifies whether to show the custom token badge.
*/
data class CustomTokenIcon(
val tint: Color,
val background: Color,
@DrawableRes override val networkBadgeIconResId: Int,
@DrawableRes override val topBadgeIconResId: Int,
override val isGrayscale: Boolean,
override val showCustomBadge: Boolean = true,
) : TokenIconState()
) : CurrencyIconState()
data object Loading : TokenIconState() {
data object Loading : CurrencyIconState() {
override val isGrayscale: Boolean = false
override val showCustomBadge: Boolean = false
override val networkBadgeIconResId: Int? = null
override val topBadgeIconResId: Int? = null
}
data object Locked : TokenIconState() {
data object Locked : CurrencyIconState() {
override val isGrayscale: Boolean = false
override val showCustomBadge: Boolean = false
override val networkBadgeIconResId: Int? = null
override val topBadgeIconResId: Int? = null
}
}

View file

@ -1,4 +1,4 @@
package com.tangem.core.ui.components.currency.tokenicon
package com.tangem.core.ui.components.currency.icon
import androidx.annotation.DrawableRes
import androidx.compose.foundation.Image
@ -14,7 +14,7 @@ import androidx.compose.ui.res.painterResource
import com.tangem.core.ui.res.TangemTheme
@Composable
internal fun NetworkBadge(
internal fun TopBadge(
@DrawableRes iconResId: Int,
alpha: Float,
colorFilter: ColorFilter?,
@ -41,7 +41,7 @@ internal fun NetworkBadge(
}
@Composable
internal fun CustomBadge(modifier: Modifier = Modifier) {
internal fun BottomBadge(modifier: Modifier = Modifier) {
Box(
modifier = modifier
.size(TangemTheme.dimens.size12)

View file

@ -1,6 +1,6 @@
package com.tangem.core.ui.components.currency.tokenicon.converter
package com.tangem.core.ui.components.currency.icon.converter
import com.tangem.core.ui.components.currency.tokenicon.TokenIconState
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
import com.tangem.core.ui.extensions.getTintForTokenIcon
import com.tangem.core.ui.extensions.networkIconResId
import com.tangem.core.ui.extensions.tryGetBackgroundForTokenIcon
@ -9,11 +9,11 @@ import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.utils.converter.Converter
/**
* Converts [CryptoCurrencyStatus] to [TokenIconState]
* Converts [CryptoCurrencyStatus] to [CurrencyIconState]
*/
class CryptoCurrencyToIconStateConverter : Converter<CryptoCurrencyStatus, TokenIconState> {
class CryptoCurrencyToIconStateConverter : Converter<CryptoCurrencyStatus, CurrencyIconState> {
override fun convert(value: CryptoCurrencyStatus): TokenIconState {
override fun convert(value: CryptoCurrencyStatus): CurrencyIconState {
return when (val currency = value.currency) {
is CryptoCurrency.Coin -> getIconStateForCoin(currency, value.value.isError)
is CryptoCurrency.Token -> getIconStateForToken(currency, value.value.isError)
@ -24,7 +24,7 @@ class CryptoCurrencyToIconStateConverter : Converter<CryptoCurrencyStatus, Token
value: CryptoCurrencyStatus,
forceGrayscale: Boolean,
showCustomTokenBadge: Boolean,
): TokenIconState {
): CurrencyIconState {
return when (val currency = value.currency) {
is CryptoCurrency.Coin -> getIconStateForCoin(
coin = currency,
@ -41,7 +41,7 @@ class CryptoCurrencyToIconStateConverter : Converter<CryptoCurrencyStatus, Token
}
}
fun convert(currency: CryptoCurrency): TokenIconState {
fun convert(currency: CryptoCurrency): CurrencyIconState {
return when (currency) {
is CryptoCurrency.Coin -> getIconStateForCoin(currency, isUnreachable = false)
is CryptoCurrency.Token -> getIconStateForToken(currency, isErrorStatus = false)
@ -53,8 +53,8 @@ class CryptoCurrencyToIconStateConverter : Converter<CryptoCurrencyStatus, Token
isUnreachable: Boolean,
showCustomBadge: Boolean = true,
forceGrayscale: Boolean = false,
): TokenIconState.CoinIcon {
return TokenIconState.CoinIcon(
): CurrencyIconState.CoinIcon {
return CurrencyIconState.CoinIcon(
url = coin.iconUrl,
fallbackResId = coin.networkIconResId,
isGrayscale = forceGrayscale || coin.network.isTestnet || isUnreachable,
@ -67,23 +67,23 @@ class CryptoCurrencyToIconStateConverter : Converter<CryptoCurrencyStatus, Token
isErrorStatus: Boolean,
showCustomBadge: Boolean = true,
forceGrayscale: Boolean = false,
): TokenIconState {
): CurrencyIconState {
val grayScale = forceGrayscale || token.network.isTestnet || isErrorStatus
val background = token.tryGetBackgroundForTokenIcon(grayScale)
val tint = getTintForTokenIcon(background)
return if (token.isCustom && token.iconUrl == null) {
TokenIconState.CustomTokenIcon(
CurrencyIconState.CustomTokenIcon(
tint = tint,
background = background,
networkBadgeIconResId = token.networkIconResId,
topBadgeIconResId = token.networkIconResId,
isGrayscale = grayScale,
showCustomBadge = showCustomBadge,
)
} else {
TokenIconState.TokenIcon(
CurrencyIconState.TokenIcon(
url = token.iconUrl,
networkBadgeIconResId = token.networkIconResId,
topBadgeIconResId = token.networkIconResId,
isGrayscale = grayScale,
fallbackTint = tint,
fallbackBackground = background,

View file

@ -12,13 +12,13 @@ import androidx.compose.ui.tooling.preview.Preview
import com.tangem.core.ui.R
import com.tangem.core.ui.components.atoms.text.EllipsisText
import com.tangem.core.ui.components.atoms.text.TextEllipsis
import com.tangem.core.ui.components.currency.tokenicon.TokenIcon
import com.tangem.core.ui.components.currency.tokenicon.TokenIconState
import com.tangem.core.ui.components.currency.icon.CurrencyIcon
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
import com.tangem.core.ui.components.inputrow.inner.DividerContainer
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
/**
* [Input Row Approx](https://www.figma.com/file/14ISV23YB1yVW1uNVwqrKv/Android?type=design&node-id=2207-810&mode=design&t=fM1ZU6zQF6g3CaTv-4)
@ -35,10 +35,10 @@ import com.tangem.core.ui.res.TangemTheme
@Suppress("LongParameterList")
@Composable
fun InputRowApprox(
leftIcon: TokenIconState,
leftIcon: CurrencyIconState,
leftTitle: TextReference,
leftSubtitle: TextReference,
rightIcon: TokenIconState,
rightIcon: CurrencyIconState,
rightTitle: TextReference,
rightSubtitle: TextReference,
modifier: Modifier = Modifier,
@ -86,7 +86,7 @@ fun InputRowApprox(
@Composable
private fun InputRowApproxItem(
iconState: TokenIconState,
iconState: CurrencyIconState,
title: TextReference,
subtitle: TextReference,
modifier: Modifier = Modifier,
@ -95,7 +95,7 @@ private fun InputRowApproxItem(
Row(
modifier = modifier,
) {
TokenIcon(
CurrencyIcon(
state = iconState,
modifier = Modifier
.size(TangemTheme.dimens.size36),
@ -131,11 +131,11 @@ private fun InputRowApproxPreview() {
TangemThemePreview {
Column {
InputRowApprox(
leftIcon = TokenIconState.Loading,
leftIcon = CurrencyIconState.Loading,
leftTitle = TextReference.Str("Left title USD"),
leftSubtitle = TextReference.Str("Left subtitle USD"),
leftTitleEllipsisOffset = 3,
rightIcon = TokenIconState.Loading,
rightIcon = CurrencyIconState.Loading,
rightTitle = TextReference.Str("Right title Right title Right title Right title Right title USD"),
rightSubtitle = TextReference.Str("Right subtitle Right subtitle Right subtitle USD"),
rightTitleEllipsisOffset = 3,
@ -143,11 +143,11 @@ private fun InputRowApproxPreview() {
.background(TangemTheme.colors.background.action),
)
InputRowApprox(
leftIcon = TokenIconState.Loading,
leftIcon = CurrencyIconState.Loading,
leftTitle = TextReference.Str("Left title Left title Left title Left title Left title USD"),
leftSubtitle = TextReference.Str("Left subtitle Left subtitle Left subtitle USD"),
leftTitleEllipsisOffset = 3,
rightIcon = TokenIconState.Loading,
rightIcon = CurrencyIconState.Loading,
rightTitle = TextReference.Str("Right title USD"),
rightSubtitle = TextReference.Str("Right subtitle USD"),
rightTitleEllipsisOffset = 3,

View file

@ -18,13 +18,13 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import com.tangem.core.ui.R
import com.tangem.core.ui.components.currency.icon.CurrencyIcon
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
import com.tangem.core.ui.components.inputrow.inner.DividerContainer
import com.tangem.core.ui.components.currency.tokenicon.TokenIcon
import com.tangem.core.ui.components.currency.tokenicon.TokenIconState
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
/**
* [Input Row Image](https://www.figma.com/file/14ISV23YB1yVW1uNVwqrKv/Android?type=design&node-id=2100-813&mode=design&t=IQ5lBJEkFGU4WSvi-4)
@ -32,7 +32,7 @@ import com.tangem.core.ui.res.TangemTheme
* @param title title reference
* @param subtitle subtitle reference
* @param caption caption reference
* @param tokenIconState token icon state [TokenIconState]
* @param tokenIconState token icon state [CurrencyIconState]
* @param modifier modifier
* @param titleColor title color
* @param subtitleColor subtitle color
@ -48,7 +48,7 @@ fun InputRowImage(
title: TextReference,
subtitle: TextReference,
caption: TextReference,
tokenIconState: TokenIconState,
tokenIconState: CurrencyIconState,
modifier: Modifier = Modifier,
titleColor: Color = TangemTheme.colors.text.secondary,
subtitleColor: Color = TangemTheme.colors.text.primary1,
@ -79,7 +79,7 @@ fun InputRowImage(
top = TangemTheme.dimens.spacing6,
),
) {
TokenIcon(
CurrencyIcon(
state = tokenIconState,
shouldDisplayNetwork = showNetworkIcon,
modifier = Modifier
@ -146,7 +146,7 @@ private data class InputRowImagePreviewData(
val title: TextReference,
val subtitle: TextReference,
val caption: TextReference,
val iconState: TokenIconState,
val iconState: CurrencyIconState,
val showDivider: Boolean,
val actionIconRes: Int?,
val showNetworkIcon: Boolean = false,
@ -160,7 +160,7 @@ private class InputRowImagePreviewDataProvider :
title = TextReference.Str("title"),
subtitle = TextReference.Str("subtitle"),
caption = TextReference.Str("caption"),
iconState = TokenIconState.Locked,
iconState = CurrencyIconState.Locked,
actionIconRes = null,
showDivider = false,
showNetworkIcon = false,
@ -169,7 +169,7 @@ private class InputRowImagePreviewDataProvider :
title = TextReference.Str("title"),
subtitle = TextReference.Str("subtitle"),
caption = TextReference.Str("caption"),
iconState = TokenIconState.Locked,
iconState = CurrencyIconState.Locked,
actionIconRes = R.drawable.ic_chevron_right_24,
showDivider = true,
showNetworkIcon = true,

View file

@ -8,7 +8,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import coil.compose.SubcomposeAsyncImage
import coil.request.ImageRequest
import com.tangem.core.ui.components.currency.tokenicon.LoadingIcon
import com.tangem.core.ui.components.currency.icon.LoadingIcon
import com.tangem.core.ui.res.TangemTheme
/**