Updated on 2026-08-14

This commit is contained in:
Tangem 2025-10-14 19:51:58 +05:00
parent 86dc859a67
commit 006669ae0d
26 changed files with 281 additions and 87 deletions

View file

@ -0,0 +1,60 @@
package com.tangem.common.ui.account
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.dp
import com.tangem.core.ui.components.account.AccountIconSize
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.test.SendScreenTestTags
/**
* A composable function that displays an account label (icon + name) with an optional prefix.
*
* Depending on the type of [accountTitleUM], it either shows a prefix text followed by
* an account label (with name and icon) or just a title text.
*
* @param accountTitleUM The data model containing information about the account title.
* @param modifier Optional [Modifier] for styling.
* @param textStyle The [TextStyle] to apply to the text elements. Defaults to subtitle2 style from TangemTheme.
*/
@Composable
fun AccountTitle(
accountTitleUM: AccountTitleUM,
modifier: Modifier = Modifier,
textStyle: TextStyle = TangemTheme.typography.subtitle2,
) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(4.dp),
modifier = modifier,
) {
when (accountTitleUM) {
is AccountTitleUM.Account -> {
Text(
text = accountTitleUM.prefixText.resolveReference(),
style = textStyle,
color = TangemTheme.colors.text.tertiary,
)
AccountLabel(
name = accountTitleUM.name,
icon = accountTitleUM.icon,
iconSize = AccountIconSize.ExtraSmall,
nameStyle = textStyle,
)
}
is AccountTitleUM.Text -> Text(
text = accountTitleUM.title.resolveReference(),
style = textStyle,
color = TangemTheme.colors.text.tertiary,
modifier = Modifier.testTag(SendScreenTestTags.AMOUNT_CONTAINER_TITLE),
)
}
}
}

View file

@ -0,0 +1,24 @@
package com.tangem.common.ui.account
import androidx.compose.runtime.Immutable
import com.tangem.core.ui.extensions.TextReference
/**
* A sealed interface representing the title of an account, which can be either a simple text
* or a more complex account representation with a prefix, name, and icon.
*/
@Immutable
sealed interface AccountTitleUM {
/** Represents a simple text title. */
data class Text(
val title: TextReference,
) : AccountTitleUM
/** Represents an account with a prefix, name, and icon. */
data class Account(
val prefixText: TextReference,
val name: TextReference,
val icon: CryptoPortfolioIconUM,
) : AccountTitleUM
}

View file

@ -0,0 +1,27 @@
package com.tangem.common.ui.amountScreen.converters
import com.tangem.common.ui.account.AccountTitleUM
import com.tangem.common.ui.account.toUM
import com.tangem.core.ui.extensions.TextReference
import com.tangem.domain.models.account.Account
import com.tangem.utils.converter.Converter
class AmountAccountConverter(
private val prefixText: TextReference,
private val isAccountsMode: Boolean,
private val walletTitle: TextReference,
) : Converter<Account.CryptoPortfolio?, AccountTitleUM> {
override fun convert(value: Account.CryptoPortfolio?): AccountTitleUM {
return if (value != null && isAccountsMode) {
AccountTitleUM.Account(
name = value.accountName.toUM().value,
icon = value.icon.toUM(),
prefixText = prefixText,
)
} else {
AccountTitleUM.Text(
title = walletTitle,
)
}
}
}

View file

@ -1,5 +1,6 @@
package com.tangem.common.ui.amountScreen.converters
import com.tangem.common.ui.account.AccountTitleUM
import com.tangem.common.ui.amountScreen.AmountScreenClickIntents
import com.tangem.common.ui.amountScreen.converters.field.AmountFieldConverter
import com.tangem.common.ui.amountScreen.models.AmountParameters
@ -36,6 +37,7 @@ class AmountStateConverter(
private val maxEnterAmount: EnterAmountBoundary,
private val iconStateConverter: CryptoCurrencyToIconStateConverter,
private val isBalanceHidden: Boolean,
private val accountTitleUM: AccountTitleUM,
) : Converter<AmountParameters, AmountState> {
private val amountFieldConverter by lazy(LazyThreadSafetyMode.NONE) {
@ -55,7 +57,7 @@ class AmountStateConverter(
}
return AmountState.Data(
title = value.title,
accountTitleUM = accountTitleUM,
availableBalanceCrypto = stringReference(crypto).orMaskWithStars(isBalanceHidden),
availableBalanceFiat = if (isBalanceHidden) {
TextReference.EMPTY

View file

@ -1,6 +1,7 @@
package com.tangem.common.ui.amountScreen.models
import androidx.compose.runtime.Stable
import com.tangem.common.ui.account.AccountTitleUM
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
import com.tangem.core.ui.extensions.TextReference
import com.tangem.domain.appcurrency.model.AppCurrency
@ -14,7 +15,7 @@ sealed class AmountState {
/**
* @param isPrimaryButtonEnabled indicates if next state button enabled
* @param title title
* @param accountTitleUM info about current account or wallet
* @param availableBalanceCrypto user crypto currency balance in crypto
* @param availableBalanceFiat user crypto currency balance in fiat
* @param tokenIconState crypto currency icon state
@ -26,7 +27,7 @@ sealed class AmountState {
*/
data class Data(
override val isPrimaryButtonEnabled: Boolean,
val title: TextReference,
val accountTitleUM: AccountTitleUM,
val availableBalanceCrypto: TextReference,
val availableBalanceFiat: TextReference,
val tokenName: TextReference,

View file

@ -2,12 +2,18 @@ package com.tangem.common.ui.amountScreen.preview
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import com.tangem.common.ui.R
import com.tangem.common.ui.account.AccountNameUM
import com.tangem.common.ui.account.AccountTitleUM
import com.tangem.common.ui.account.toUM
import com.tangem.common.ui.amountScreen.models.AmountFieldModel
import com.tangem.common.ui.amountScreen.models.AmountState
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.models.account.CryptoPortfolioIcon
import com.tangem.domain.tokens.model.Amount
import com.tangem.domain.tokens.model.AmountType
import com.tangem.utils.StringsSigns
@ -19,7 +25,7 @@ object AmountStatePreviewData {
val amountState = AmountState.Data(
isPrimaryButtonEnabled = false,
title = stringReference("Family Wallet"),
accountTitleUM = AccountTitleUM.Text(stringReference("Family Wallet")),
availableBalanceCrypto = stringReference("2 130,81231238 USDT"),
availableBalanceFiat = stringReference("1 232 129,12 \$"),
tokenIconState = CurrencyIconState.Loading,
@ -78,6 +84,17 @@ object AmountStatePreviewData {
),
),
)
val amountStateV2Accounts = amountState.copy(
accountTitleUM = AccountTitleUM.Account(
name = AccountNameUM.DefaultMain.value,
icon = CryptoPortfolioIcon.ofDefaultCustomAccount().toUM(),
prefixText = resourceReference(R.string.common_from),
),
availableBalanceCrypto = stringReference("2 130,81231238 USDT"),
availableBalanceFiat = stringReference(" ${StringsSigns.DOT} 1 232 129,12 $"),
)
val amountErrorState = amountWithValueState.copy(
amountTextField = amountWithValueState.amountTextField.copy(
isError = true,

View file

@ -16,12 +16,12 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import androidx.compose.ui.unit.dp
import com.tangem.common.ui.account.AccountTitle
import com.tangem.common.ui.amountScreen.models.AmountState
import com.tangem.common.ui.amountScreen.preview.AmountStatePreviewData
import com.tangem.core.ui.components.ResizableText
import com.tangem.core.ui.components.SpacerH
import com.tangem.core.ui.components.currency.icon.CurrencyIcon
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.format.bigdecimal.crypto
import com.tangem.core.ui.format.bigdecimal.fiat
import com.tangem.core.ui.format.bigdecimal.format
@ -60,11 +60,7 @@ fun AmountBlock(amountState: AmountState, isClickDisabled: Boolean, isEditingDis
.clickable(enabled = !isClickDisabled && !isEditingDisabled, onClick = onClick)
.padding(TangemTheme.dimens.spacing16),
) {
Text(
text = amountState.title.resolveReference(),
style = TangemTheme.typography.subtitle2,
color = TangemTheme.colors.text.tertiary,
)
AccountTitle(accountTitleUM = amountState.accountTitleUM)
SpacerH(20.dp)
CurrencyIcon(
state = amountState.tokenIconState,

View file

@ -14,6 +14,8 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import androidx.compose.ui.unit.dp
import com.tangem.common.ui.account.AccountTitle
import com.tangem.common.ui.account.AccountTitleUM
import com.tangem.common.ui.amountScreen.models.AmountState
import com.tangem.common.ui.amountScreen.preview.AmountStatePreviewData
import com.tangem.core.ui.components.ResizableText
@ -65,7 +67,7 @@ fun AmountBlockV2(
val currencyTitle = amount.cryptoAmount.currencySymbol
AmountBlockV2(
title = amountState.title,
accountTitleUM = amountState.accountTitleUM,
balance = amountState.availableBalanceCrypto,
currencyTitle = currencyTitle,
currencyIconState = amountState.tokenIconState,
@ -82,7 +84,7 @@ fun AmountBlockV2(
@Suppress("LongParameterList", "LongMethod")
@Composable
private fun AmountBlockV2(
title: TextReference,
accountTitleUM: AccountTitleUM,
balance: TextReference,
currencyTitle: String,
currencyIconState: CurrencyIconState,
@ -107,11 +109,7 @@ private fun AmountBlockV2(
.padding(TangemTheme.dimens.spacing16),
) {
Row {
Text(
text = title.resolveReference(),
style = TangemTheme.typography.subtitle2,
color = TangemTheme.colors.text.tertiary,
)
AccountTitle(accountTitleUM)
SpacerWMax()
Text(
text = balance.resolveReference(),
@ -188,6 +186,7 @@ private class AmountBlockV2PreviewProvider : PreviewParameterProvider<AmountStat
override val values: Sequence<AmountState>
get() = sequenceOf(
AmountStatePreviewData.amountState,
AmountStatePreviewData.amountStateV2Accounts,
)
}
// endregion

View file

@ -18,6 +18,7 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.unit.dp
import com.tangem.common.ui.R
import com.tangem.common.ui.account.AccountTitle
import com.tangem.common.ui.amountScreen.models.AmountState
import com.tangem.core.ui.components.TextShimmer
import com.tangem.core.ui.components.atoms.text.EllipsisText
@ -58,12 +59,7 @@ internal fun LazyListScope.amountFieldV2(
modifier = Modifier.width(60.dp),
)
} else {
Text(
text = amountState.title.resolveReference(),
style = TangemTheme.typography.subtitle2,
color = TangemTheme.colors.text.tertiary,
modifier = Modifier.testTag(SendScreenTestTags.AMOUNT_CONTAINER_TITLE),
)
AccountTitle(amountState.accountTitleUM)
}
AmountFieldV2(
amountUM = amountState,
@ -137,9 +133,8 @@ private fun AmountInfoMain(amountUM: AmountState, modifier: Modifier = Modifier)
) {
when (currentAmount) {
is AmountState.Data -> {
val amountUM = amountUM as AmountState.Data
Text(
text = amountUM.tokenName.resolveReference(),
text = currentAmount.tokenName.resolveReference(),
style = TangemTheme.typography.subtitle2,
color = TangemTheme.colors.text.primary1,
maxLines = 1,
@ -147,22 +142,22 @@ private fun AmountInfoMain(amountUM: AmountState, modifier: Modifier = Modifier)
)
Row {
EllipsisText(
text = amountUM.availableBalanceCrypto.resolveReference(),
text = currentAmount.availableBalanceCrypto.resolveReference(),
style = TangemTheme.typography.caption2,
color = TangemTheme.colors.text.tertiary,
ellipsis = TextEllipsis.OffsetEnd(
amountUM.amountTextField.cryptoAmount.currencySymbol.length,
currentAmount.amountTextField.cryptoAmount.currencySymbol.length,
),
modifier = Modifier
.weight(1f, fill = false)
.testTag(SendScreenTestTags.PRIMARY_AMOUNT),
)
EllipsisText(
text = amountUM.availableBalanceFiat.resolveReference(),
text = currentAmount.availableBalanceFiat.resolveReference(),
style = TangemTheme.typography.caption2,
color = TangemTheme.colors.text.tertiary,
ellipsis = TextEllipsis.OffsetEnd(
amountUM.amountTextField.fiatAmount.currencySymbol.length,
currentAmount.amountTextField.fiatAmount.currencySymbol.length,
),
modifier = Modifier.testTag(SendScreenTestTags.SECONDARY_AMOUNT),
)