diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/token/TokenItem.kt b/core/ui/src/main/java/com/tangem/core/ui/components/token/TokenItem.kt
index 8bdd28b235..027db6c7d6 100644
--- a/core/ui/src/main/java/com/tangem/core/ui/components/token/TokenItem.kt
+++ b/core/ui/src/main/java/com/tangem/core/ui/components/token/TokenItem.kt
@@ -37,12 +37,43 @@ private enum class LayoutId {
ICON, TITLE, FIAT_AMOUNT, CRYPTO_AMOUNT, CRYPTO_PRICE, NON_FIAT_CONTENT
}
+/**
+ * Token item for non reorderable list
+ *
+ * @param state token item state
+ * @param isBalanceHidden flag that shows/hides balance
+ * @param modifier modifier
+ *
+ * @see Figma Component
+ */
+@Composable
+fun TokenItem(state: TokenItemState, isBalanceHidden: Boolean, modifier: Modifier = Modifier) {
+ TokenItem(
+ state = state,
+ isBalanceHidden = isBalanceHidden,
+ modifier = modifier,
+ reorderableTokenListState = null,
+ )
+}
+
+/**
+ * Token item for reorderable list
+ *
+ * @param state token item state
+ * @param isBalanceHidden flag that shows/hides balance
+ * @param reorderableTokenListState reorderable token list state
+ * @param modifier modifier
+ *
+ * @see Figma Component
+ */
@Composable
fun TokenItem(
state: TokenItemState,
isBalanceHidden: Boolean,
+ reorderableTokenListState: ReorderableLazyListState?,
modifier: Modifier = Modifier,
- reorderableTokenListState: ReorderableLazyListState? = null,
) {
val betweenRowsMargin = TangemTheme.dimens.spacing2
@@ -76,7 +107,7 @@ fun TokenItem(
)
TokenPrice(
- state = state.cryptoPriceState,
+ state = state.subtitleState,
modifier = Modifier
.layoutId(layoutId = LayoutId.CRYPTO_PRICE)
.padding(end = TangemTheme.dimens.spacing8),
@@ -195,6 +226,10 @@ private fun CustomContainer(state: TokenItemState, modifier: Modifier = Modifier
is TokenItemState.Unreachable,
-> {
firstRowRemainingFreeSpace = layoutWidthWithoutPaddings - icon.width - nonFiatContent.width
+
+ if (state.subtitleState != null) {
+ secondRowRemainingFreeSpace = layoutWidthWithoutPaddings - icon.width - nonFiatContent.width
+ }
}
}
@@ -232,7 +267,13 @@ private fun CustomContainer(state: TokenItemState, modifier: Modifier = Modifier
y = when (state) {
is TokenItemState.NoAddress,
is TokenItemState.Unreachable,
- -> (layoutHeight - title.height).div(other = 2)
+ -> {
+ if (state.subtitleState == null) {
+ (layoutHeight - title.height).div(other = 2)
+ } else {
+ verticalPadding
+ }
+ }
else -> verticalPadding
},
)
@@ -411,7 +452,7 @@ private class TokenItemStateProvider : CollectionPreviewParameterProvider {
+ is TokenPriceState.CryptoPriceContent -> {
PriceBlock(
modifier = modifier,
price = state.price,
@@ -32,13 +37,12 @@ internal fun TokenPrice(state: TokenPriceChangeState?, modifier: Modifier = Modi
priceChangePercent = state.priceChangePercent,
)
}
- is TokenPriceChangeState.Unknown -> {
- PriceText(text = DASH_SIGN, modifier = modifier)
- }
- is TokenPriceChangeState.Loading -> {
+ is TokenPriceState.TextContent -> PriceText(text = state.value, modifier = modifier)
+ is TokenPriceState.Unknown -> PriceText(text = DASH_SIGN, modifier = modifier)
+ is TokenPriceState.Loading -> {
RectangleShimmer(modifier = modifier.placeholderSize(), radius = TangemTheme.dimens.radius4)
}
- is TokenPriceChangeState.Locked -> {
+ is TokenPriceState.Locked -> {
LockedRectangle(modifier = modifier.placeholderSize())
}
null -> Unit
@@ -122,4 +126,37 @@ private fun Modifier.placeholderSize(): Modifier = composed {
return@composed this
.padding(vertical = TangemTheme.dimens.spacing2)
.size(width = TangemTheme.dimens.size52, height = TangemTheme.dimens.size12)
-}
\ No newline at end of file
+}
+
+@Preview(showBackground = true)
+@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
+@Composable
+private fun Preview(@PreviewParameter(TokenPriceChangeStateProvider::class) state: TokenPriceState) {
+ TangemThemePreview {
+ TokenPrice(state = state)
+ }
+}
+
+private class TokenPriceChangeStateProvider : CollectionPreviewParameterProvider(
+ collection = listOf(
+ TokenPriceState.CryptoPriceContent(
+ price = "1.234",
+ priceChangePercent = "2.5%",
+ type = PriceChangeType.UP,
+ ),
+ TokenPriceState.CryptoPriceContent(
+ price = "1.234",
+ priceChangePercent = "2.5%",
+ type = PriceChangeType.DOWN,
+ ),
+ TokenPriceState.CryptoPriceContent(
+ price = "1.234",
+ priceChangePercent = "2.5%",
+ type = PriceChangeType.NEUTRAL,
+ ),
+ TokenPriceState.TextContent(value = "Subtitle"),
+ TokenPriceState.Unknown,
+ TokenPriceState.Loading,
+ TokenPriceState.Locked,
+ ),
+)
\ No newline at end of file
diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/token/state/TokenItemState.kt b/core/ui/src/main/java/com/tangem/core/ui/components/token/state/TokenItemState.kt
index 832b849235..9c014e8067 100644
--- a/core/ui/src/main/java/com/tangem/core/ui/components/token/state/TokenItemState.kt
+++ b/core/ui/src/main/java/com/tangem/core/ui/components/token/state/TokenItemState.kt
@@ -4,58 +4,78 @@ import androidx.compose.runtime.Immutable
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
import com.tangem.core.ui.components.marketprice.PriceChangeType
-/** Token item state */
+/** TokenItem component state */
@Immutable
sealed class TokenItemState {
+ /** Unique id */
abstract val id: String
+ /** Token icon state */
abstract val iconState: CurrencyIconState
+ /** Token title state (in one row with [fiatAmountState]) */
abstract val titleState: TitleState
+ /** Token subtitle state (under [titleState] and in one row with [cryptoAmountState]) */
+ 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?
- abstract val cryptoPriceState: CryptoPriceState?
-
- /** Loading token state */
+ /**
+ * Loading token state
+ *
+ * @property id unique id
+ * @property iconState token icon state
+ * @property titleState token title
+ * @property subtitleState token subtitle
+ */
data class Loading(
override val id: String,
override val iconState: CurrencyIconState,
override val titleState: TitleState.Content,
+ override val subtitleState: SubtitleState = SubtitleState.Loading,
) : TokenItemState() {
override val fiatAmountState: FiatAmountState = FiatAmountState.Loading
override val cryptoAmountState: CryptoAmountState = CryptoAmountState.Loading
- override val cryptoPriceState: CryptoPriceState = CryptoPriceState.Loading
}
- /** Locked token state */
+ /**
+ * Locked token state
+ *
+ * @property id unique id
+ */
data class Locked(override val id: String) : TokenItemState() {
override val iconState: CurrencyIconState = CurrencyIconState.Locked
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 cryptoPriceState: CryptoPriceState = CryptoPriceState.Locked
}
/**
* Content token state
*
- * @property id unique id
- * @property iconState token icon state
- * @property titleState token name
- * @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
+ * @property id unique id
+ * @property iconState token icon state
+ * @property titleState token title
+ * @property subtitleState token subtitle
+ * @property fiatAmountState token fiat amount
+ * @property cryptoAmountState 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
*/
data class Content(
override val id: String,
override val iconState: CurrencyIconState,
override val titleState: TitleState,
+ override val subtitleState: SubtitleState,
override val fiatAmountState: FiatAmountState,
override val cryptoAmountState: CryptoAmountState.Content,
- override val cryptoPriceState: CryptoPriceState,
val onItemClick: () -> Unit,
val onItemLongClick: () -> Unit,
) : TokenItemState()
@@ -63,9 +83,10 @@ sealed class TokenItemState {
/**
* Draggable token state
*
- * @property id unique id
- * @property iconState token icon state
- * @property titleState token name
+ * @property id unique id
+ * @property iconState token icon state
+ * @property titleState token title
+ * @property cryptoAmountState token crypto amount
*/
data class Draggable(
override val id: String,
@@ -73,48 +94,50 @@ sealed class TokenItemState {
override val titleState: TitleState,
override val cryptoAmountState: CryptoAmountState,
) : TokenItemState() {
+ override val subtitleState: SubtitleState? = null
override val fiatAmountState: FiatAmountState? = null
- override val cryptoPriceState: CryptoPriceState? = null
}
/**
* Unreachable token state
*
- * @property id token id
- * @property iconState token icon state
- * @property titleState token name
- * @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
+ * @property id unique id
+ * @property iconState token icon state
+ * @property titleState token title
+ * @property subtitleState token subtitle
+ * @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
*/
data class Unreachable(
override val id: String,
override val iconState: CurrencyIconState,
override val titleState: TitleState,
+ override val subtitleState: SubtitleState? = null,
val onItemClick: () -> Unit,
val onItemLongClick: () -> Unit,
) : TokenItemState() {
override val fiatAmountState: FiatAmountState? = null
override val cryptoAmountState: CryptoAmountState? = null
- override val cryptoPriceState: CryptoPriceState? = null
}
/**
* No derivation address state
*
- * @property id token id
- * @property iconState token icon state
- * @property titleState token name
- * @property onItemLongClick callback which will be called when an item is long clicked
+ * @property id unique id
+ * @property iconState token icon state
+ * @property titleState token title
+ * @property subtitleState token subtitle
+ * @property onItemLongClick callback which will be called when an item is long clicked
*/
data class NoAddress(
override val id: String,
override val iconState: CurrencyIconState,
override val titleState: TitleState,
+ override val subtitleState: SubtitleState? = null,
val onItemLongClick: () -> Unit,
) : TokenItemState() {
override val fiatAmountState: FiatAmountState? = null
override val cryptoAmountState: CryptoAmountState? = null
- override val cryptoPriceState: CryptoPriceState? = null
}
@Immutable
@@ -122,9 +145,27 @@ sealed class TokenItemState {
data class Content(val text: String, val hasPending: Boolean = false) : TitleState()
- object Loading : TitleState()
+ data object Loading : TitleState()
- object Locked : TitleState()
+ data object Locked : TitleState()
+ }
+
+ @Immutable
+ sealed class SubtitleState {
+
+ data class CryptoPriceContent(
+ val price: String,
+ val priceChangePercent: String,
+ val type: PriceChangeType,
+ ) : SubtitleState()
+
+ data class TextContent(val value: String) : SubtitleState()
+
+ data object Unknown : SubtitleState()
+
+ data object Loading : SubtitleState()
+
+ data object Locked : SubtitleState()
}
@Immutable
@@ -134,34 +175,19 @@ sealed class TokenItemState {
val hasStaked: Boolean = false,
) : FiatAmountState()
- object Loading : FiatAmountState()
+ data object Loading : FiatAmountState()
- object Locked : FiatAmountState()
+ data object Locked : FiatAmountState()
}
@Immutable
sealed class CryptoAmountState {
data class Content(val text: String) : CryptoAmountState()
- object Unreachable : CryptoAmountState()
+ data object Unreachable : CryptoAmountState()
- object Loading : CryptoAmountState()
+ data object Loading : CryptoAmountState()
- object Locked : CryptoAmountState()
- }
-
- sealed class CryptoPriceState {
-
- data class Content(
- val price: String,
- val priceChangePercent: String?,
- val type: PriceChangeType?,
- ) : CryptoPriceState()
-
- object Unknown : CryptoPriceState()
-
- object Loading : CryptoPriceState()
-
- object Locked : CryptoPriceState()
+ data object Locked : CryptoAmountState()
}
}
\ No newline at end of file
diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/preview/WalletScreenPreviewData.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/preview/WalletScreenPreviewData.kt
index 12dcfa641f..63585b4bbe 100644
--- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/preview/WalletScreenPreviewData.kt
+++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/common/preview/WalletScreenPreviewData.kt
@@ -20,7 +20,7 @@ internal object WalletScreenPreviewData {
titleState = TokenItemState.TitleState.Content(text = "Bitcoin"),
fiatAmountState = TokenItemState.FiatAmountState.Content(text = "12 368,14 \$"),
cryptoAmountState = TokenItemState.CryptoAmountState.Content(text = "0,35853044 BTC"),
- cryptoPriceState = TokenItemState.CryptoPriceState.Content(
+ subtitleState = TokenItemState.SubtitleState.CryptoPriceContent(
price = "34 496,75 \$",
priceChangePercent = "0,43 %",
type = PriceChangeType.DOWN,
@@ -46,7 +46,7 @@ internal object WalletScreenPreviewData {
titleState = TokenItemState.TitleState.Content(text = "Ethereum"),
fiatAmountState = TokenItemState.FiatAmountState.Content(text = "3 340,79 \$"),
cryptoAmountState = TokenItemState.CryptoAmountState.Content(text = "1,856660295 ETH"),
- cryptoPriceState = TokenItemState.CryptoPriceState.Content(
+ subtitleState = TokenItemState.SubtitleState.CryptoPriceContent(
price = "1 799,41 \$",
priceChangePercent = "5,16 %",
type = PriceChangeType.UP,
@@ -68,7 +68,7 @@ internal object WalletScreenPreviewData {
titleState = TokenItemState.TitleState.Content(text = "Shiba Inu"),
fiatAmountState = TokenItemState.FiatAmountState.Content(text = "48,64 \$"),
cryptoAmountState = TokenItemState.CryptoAmountState.Content(text = "6 200 220,00 SHIB"),
- cryptoPriceState = TokenItemState.CryptoPriceState.Content(
+ subtitleState = TokenItemState.SubtitleState.CryptoPriceContent(
price = "0.01 \$",
priceChangePercent = "1,34 %",
type = PriceChangeType.DOWN,
diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TokenItemStateConverter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TokenItemStateConverter.kt
index e47f61c804..e9752df81b 100644
--- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TokenItemStateConverter.kt
+++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TokenItemStateConverter.kt
@@ -59,7 +59,7 @@ internal class TokenItemStateConverter(
hasStaked = !getStakedBalance().isZero(),
),
cryptoAmountState = TokenItemState.CryptoAmountState.Content(text = getFormattedAmount()),
- cryptoPriceState = getCryptoPriceState(),
+ subtitleState = getCryptoPriceState(),
onItemClick = { clickIntents.onTokenItemClick(this) },
onItemLongClick = { clickIntents.onTokenItemLongClick(cryptoCurrencyStatus = this) },
)
@@ -97,12 +97,12 @@ internal class TokenItemStateConverter(
onItemLongClick = { clickIntents.onTokenItemLongClick(cryptoCurrencyStatus = this) },
)
- private fun CryptoCurrencyStatus.getCryptoPriceState(): TokenItemState.CryptoPriceState {
+ private fun CryptoCurrencyStatus.getCryptoPriceState(): TokenItemState.SubtitleState {
val fiatRate = value.fiatRate
val priceChange = value.priceChange
return if (fiatRate != null && priceChange != null) {
- TokenItemState.CryptoPriceState.Content(
+ TokenItemState.SubtitleState.CryptoPriceContent(
price = fiatRate.getFormattedCryptoPrice(),
priceChangePercent = BigDecimalFormatter.formatPercent(
percent = priceChange,
@@ -111,7 +111,7 @@ internal class TokenItemStateConverter(
type = priceChange.getPriceChangeType(),
)
} else {
- TokenItemState.CryptoPriceState.Unknown
+ TokenItemState.SubtitleState.Unknown
}
}