Updated on 2026-08-14

This commit is contained in:
Tangem 2025-08-21 12:43:59 +03:00
commit fe2cfac54d
1140 changed files with 23493 additions and 8579 deletions

View file

@ -4,11 +4,13 @@ import android.os.Bundle
import com.tangem.common.routing.AppRoute.ManageTokens.Source
import com.tangem.common.routing.bundle.RouteBundleParams
import com.tangem.common.routing.bundle.bundle
import com.tangem.common.routing.entity.InitScreenLaunchMode
import com.tangem.common.routing.entity.SerializableIntent
import com.tangem.core.decompose.navigation.Route
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.feedback.models.CardInfo
import com.tangem.domain.markets.TokenMarketParams
import com.tangem.domain.models.account.Account
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.models.wallet.UserWalletId
@ -23,10 +25,16 @@ sealed class AppRoute(val path: String) : Route {
data object Initial : AppRoute(path = "/initial")
@Serializable
data object Home : AppRoute(path = "/home")
data class Home(
val launchMode: InitScreenLaunchMode = InitScreenLaunchMode.Standard,
) : AppRoute(path = "/home")
@Serializable
data class Welcome(
@Deprecated("No longer used, will be removed in future releases")
val launchMode: InitScreenLaunchMode = InitScreenLaunchMode.Standard,
// we still have this param to be handled by WalletConnectLinkIntentHandler in WelcomeMiddleware
@Deprecated("No longer used, will be removed in future releases")
val intent: SerializableIntent? = null,
) : AppRoute(path = "/welcome"), RouteBundleParams {
@ -129,6 +137,8 @@ sealed class AppRoute(val path: String) : Route {
val initialCurrency: CryptoCurrency,
val selectedCurrency: CryptoCurrency?,
val source: Source,
val showSendViaSwapNotification: Boolean,
val analyticsCategoryName: String,
) : AppRoute(path = "/$source/choose_managed_tokens/$userWalletId/${initialCurrency.id.value}") {
enum class Source {
SendViaSwap,
@ -304,6 +314,21 @@ sealed class AppRoute(val path: String) : Route {
@Serializable
object AddExistingWallet : AppRoute(path = "/add_existing_wallet")
@Serializable
data class WalletActivation(
val userWalletId: UserWalletId,
) : AppRoute(path = "/wallet_activation/${userWalletId.stringValue}")
@Serializable
data class CreateWalletBackup(
val userWalletId: UserWalletId,
) : AppRoute(path = "/create_wallet_backup/${userWalletId.stringValue}")
@Serializable
data class UpdateAccessCode(
val userWalletId: UserWalletId,
) : AppRoute(path = "/update_access_code/${userWalletId.stringValue}")
@Serializable
data class SendEntryPoint(
val userWalletId: UserWalletId,
@ -317,4 +342,27 @@ sealed class AppRoute(val path: String) : Route {
val userWalletId: UserWalletId,
val currency: CryptoCurrency,
) : AppRoute(path = "/send_with_swap/${userWalletId.stringValue}/${currency.symbol}")
@Serializable
data class CreateAccount(
val userWalletId: UserWalletId,
) : AppRoute(path = "/create_account/${userWalletId.stringValue}")
@Serializable
data class EditAccount(
val account: Account,
) : AppRoute(path = "/edit_account/${account.accountId.value}")
@Serializable
data class AccountDetails(
val account: Account,
) : AppRoute(path = "/account_details/${account.accountId.value}")
@Serializable
data class ArchivedAccountList(
val userWalletId: UserWalletId,
) : AppRoute(path = "/archived_account/${userWalletId.stringValue}")
@Serializable
data object TangemPayDetails : AppRoute(path = "/tangem_pay_details")
}

View file

@ -0,0 +1,13 @@
package com.tangem.common.routing.entity
import kotlinx.serialization.Serializable
@Serializable
sealed class InitScreenLaunchMode {
@Serializable
data object Standard : InitScreenLaunchMode()
@Serializable
data object WithCardScan : InitScreenLaunchMode()
}

View file

@ -14,6 +14,7 @@ data class SerializableIntent(
val packageValue: String?,
val component: String?,
val flags: Int,
// CAUTION: works wrong with SerializableBundle constructor(bundle: Bundle), need to be removed
val extras: SerializableBundle?,
) {

View file

@ -5,7 +5,7 @@ import com.tangem.datasource.api.stakekit.models.response.model.BalanceDTO
import com.tangem.datasource.api.stakekit.models.response.model.NetworkTypeDTO
import com.tangem.datasource.api.stakekit.models.response.model.TokenDTO
import com.tangem.datasource.api.stakekit.models.response.model.YieldBalanceWrapperDTO
import com.tangem.domain.staking.model.StakingID
import com.tangem.domain.models.staking.StakingID
import java.math.BigDecimal
/**

View file

@ -4,7 +4,7 @@ import com.tangem.datasource.api.stakekit.models.response.model.AddressArgumentD
import com.tangem.datasource.api.stakekit.models.response.model.NetworkTypeDTO
import com.tangem.datasource.api.stakekit.models.response.model.TokenDTO
import com.tangem.datasource.api.stakekit.models.response.model.YieldDTO
import com.tangem.domain.staking.model.StakingID
import com.tangem.domain.models.staking.StakingID
import java.math.BigDecimal
/**

View file

@ -8,8 +8,8 @@ import com.tangem.blockchainsdk.utils.toNetworkId
import com.tangem.common.test.domain.card.MockScanResponseFactory
import com.tangem.common.test.domain.wallet.MockUserWalletFactory
import com.tangem.data.common.currency.CryptoCurrencyFactory
import com.tangem.domain.card.DerivationStyleProvider
import com.tangem.domain.card.common.util.derivationStyleProvider
import com.tangem.domain.wallets.derivations.DerivationStyleProvider
import com.tangem.domain.wallets.derivations.derivationStyleProvider
import com.tangem.domain.card.configs.GenericCardConfig
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.network.Network
@ -25,6 +25,7 @@ class MockCryptoCurrencyFactory(private val userWallet: UserWallet.Cold = defaul
val cardano by lazy { createCoin(blockchain = Blockchain.Cardano) }
val chia by lazy { createCoin(Blockchain.Chia) }
val ethereum by lazy { createCoin(Blockchain.Ethereum) }
val stellar by lazy { createCoin(Blockchain.Stellar) }
val chiaAndEthereum by lazy {
listOf(
@ -64,6 +65,10 @@ class MockCryptoCurrencyFactory(private val userWallet: UserWallet.Cold = defaul
hasFiatFeeRate = blockchain.feePaidCurrency() !is FeePaidCurrency.FeeResource,
canHandleTokens = false,
transactionExtrasType = Network.TransactionExtrasType.NONE,
nameResolvingType = when (blockchain) {
Blockchain.Ethereum, Blockchain.EthereumTestnet -> Network.NameResolvingType.ENS
else -> Network.NameResolvingType.NONE
},
)
return factory.createCoin(network = network)
@ -94,6 +99,7 @@ class MockCryptoCurrencyFactory(private val userWallet: UserWallet.Cold = defaul
hasFiatFeeRate = true,
canHandleTokens = true,
transactionExtrasType = Network.TransactionExtrasType.NONE,
nameResolvingType = Network.NameResolvingType.NONE,
),
name = "NEVER-MIND",
symbol = "NEVER-MIND",

View file

@ -9,7 +9,24 @@ fun <B> assertEither(actual: Either<Throwable, B>, expected: Either<Throwable, B
.onLeft {
val expectedError = expected.leftOrNull() ?: error("Actual is Either.Left: $it")
Truth.assertThat(it::class.java).isEqualTo(expectedError::class.java)
Truth.assertThat(it).isInstanceOf(expectedError::class.java)
Truth.assertThat(it).hasMessageThat().isEqualTo(expectedError.message)
}
}
fun assertEitherRight(actual: Either<Throwable, Unit>) {
actual
.onRight { Truth.assertThat(actual).isEqualTo(Either.Right(Unit)) }
.onLeft {
error("Actual is Either.Left: $it")
}
}
fun <B> assertEitherLeft(actual: Either<Throwable, B>, expected: Throwable) {
actual
.onRight { error("Actual is Either.Right: $it") }
.onLeft {
Truth.assertThat(it::class.java).isEqualTo(expected::class.java)
Truth.assertThat(it).hasMessageThat().isEqualTo(expected.message)
}
}

View file

@ -12,7 +12,6 @@ dependencies {
/** Compose */
implementation(deps.compose.material3)
implementation(deps.compose.material)
implementation(deps.compose.foundation)
implementation(deps.compose.ui)
implementation(deps.compose.ui.tooling)

View file

@ -4,7 +4,7 @@ import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import com.tangem.common.ui.amountScreen.models.AmountState
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.utils.isNullOrZero
import com.tangem.utils.transformer.Transformer

View file

@ -14,7 +14,7 @@ import com.tangem.core.ui.extensions.wrappedList
import com.tangem.core.ui.format.bigdecimal.crypto
import com.tangem.core.ui.format.bigdecimal.format
import com.tangem.core.ui.utils.parseBigDecimal
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.utils.isNullOrZero
import com.tangem.utils.transformer.Transformer
import java.math.BigDecimal

View file

@ -15,7 +15,7 @@ import com.tangem.core.ui.format.bigdecimal.crypto
import com.tangem.core.ui.format.bigdecimal.format
import com.tangem.core.ui.utils.parseBigDecimal
import com.tangem.core.ui.utils.parseToBigDecimal
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.utils.isNullOrZero
import com.tangem.utils.transformer.Transformer
import java.math.BigDecimal

View file

@ -9,6 +9,7 @@ import com.tangem.common.ui.amountScreen.models.AmountSegmentedButtonsConfig
import com.tangem.common.ui.amountScreen.models.AmountState
import com.tangem.common.ui.amountScreen.models.EnterAmountBoundary
import com.tangem.core.ui.components.currency.icon.converter.CryptoCurrencyToIconStateConverter
import com.tangem.core.ui.extensions.combinedReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.extensions.wrappedList
@ -16,8 +17,9 @@ import com.tangem.core.ui.format.bigdecimal.crypto
import com.tangem.core.ui.format.bigdecimal.fiat
import com.tangem.core.ui.format.bigdecimal.format
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.utils.Provider
import com.tangem.utils.StringsSigns.DOT
import com.tangem.utils.converter.Converter
import com.tangem.utils.isNullOrZero
import kotlinx.collections.immutable.persistentListOf
@ -58,6 +60,7 @@ class AmountStateConverter(
return AmountState.Data(
title = value.title,
availableBalance = resourceReference(R.string.common_crypto_fiat_format, wrappedList(crypto, fiat)),
availableBalanceShort = stringReference(crypto),
tokenName = stringReference(status.currency.name),
tokenIconState = iconStateConverter.convert(status),
amountTextField = amountFieldConverter.convert(value.value),
@ -120,10 +123,15 @@ class AmountStateConverterV2(
return AmountState.Data(
title = value.title,
availableBalance = if (isRedesignEnabled) {
resourceReference(R.string.common_balance, wrappedList(crypto))
combinedReference(
stringReference(crypto),
stringReference(" $DOT "),
stringReference(fiat),
)
} else {
resourceReference(R.string.common_crypto_fiat_format, wrappedList(crypto, fiat))
},
availableBalanceShort = stringReference(crypto),
tokenName = stringReference(cryptoCurrencyStatus.currency.name),
tokenIconState = iconStateConverter.convert(cryptoCurrencyStatus.currency),
amountTextField = amountFieldConverter.convert(value.value),

View file

@ -1,7 +1,7 @@
package com.tangem.common.ui.amountScreen.converters
import com.tangem.common.ui.amountScreen.models.EnterAmountBoundary
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.utils.converter.Converter
/**

View file

@ -3,13 +3,16 @@ package com.tangem.common.ui.amountScreen.converters.field
import com.tangem.common.ui.R
import com.tangem.common.ui.amountScreen.models.AmountState
import com.tangem.common.ui.amountScreen.models.EnterAmountBoundary
import com.tangem.core.ui.extensions.combinedReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.extensions.wrappedList
import com.tangem.core.ui.format.bigdecimal.crypto
import com.tangem.core.ui.format.bigdecimal.fiat
import com.tangem.core.ui.format.bigdecimal.format
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.utils.StringsSigns.DOT
import com.tangem.utils.transformer.Transformer
/**
@ -34,13 +37,18 @@ class AmountBoundaryUpdateTransformer(
val crypto = maxEnterAmount.amount.format { crypto(cryptoCurrencyStatus.currency) }
val availableBalance = if (isRedesignEnabled) {
resourceReference(R.string.common_balance, wrappedList(crypto))
combinedReference(
stringReference(crypto),
stringReference(" $DOT "),
stringReference(fiat),
)
} else {
resourceReference(R.string.common_crypto_fiat_format, wrappedList(crypto, fiat))
}
return prevState.copy(
availableBalance = availableBalance,
availableBalanceShort = stringReference(crypto),
)
}
}

View file

@ -16,7 +16,7 @@ import com.tangem.core.ui.extensions.wrappedList
import com.tangem.core.ui.format.bigdecimal.crypto
import com.tangem.core.ui.format.bigdecimal.format
import com.tangem.core.ui.utils.parseToBigDecimal
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.utils.isNullOrZero
import com.tangem.utils.transformer.Transformer
import java.math.BigDecimal

View file

@ -9,9 +9,9 @@ import com.tangem.common.ui.amountScreen.models.AmountFieldModel
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.utils.parseBigDecimal
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.tokens.model.Amount
import com.tangem.domain.tokens.model.AmountType
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.tokens.model.convertToAmount
import com.tangem.utils.Provider
import com.tangem.utils.converter.Converter

View file

@ -12,7 +12,7 @@ import com.tangem.core.ui.extensions.wrappedList
import com.tangem.core.ui.format.bigdecimal.crypto
import com.tangem.core.ui.format.bigdecimal.format
import com.tangem.core.ui.utils.parseBigDecimal
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.utils.extensions.isZero
import com.tangem.utils.transformer.Transformer
import java.math.BigDecimal

View file

@ -17,7 +17,8 @@ sealed class AmountState {
/**
* @param isPrimaryButtonEnabled indicates if next state button enabled
* @param title title
* @param availableBalance user crypto currency balance
* @param availableBalance user crypto currency balance with fiat balance
* @param availableBalanceShort user crypto currency balance without fiat balance
* @param tokenIconState crypto currency icon state
* @param segmentedButtonConfig currency switcher config
* @param selectedButton selected currency index
@ -33,6 +34,7 @@ sealed class AmountState {
override val isRedesignEnabled: Boolean,
val title: TextReference,
val availableBalance: TextReference,
val availableBalanceShort: TextReference,
val tokenName: TextReference,
val tokenIconState: CurrencyIconState,
val segmentedButtonConfig: PersistentList<AmountSegmentedButtonsConfig>,

View file

@ -24,7 +24,8 @@ object AmountStatePreviewData {
val amountState = AmountState.Data(
isPrimaryButtonEnabled = false,
title = stringReference("Family Wallet"),
availableBalance = stringReference("2 130,88 USDT (2 129,92 \$)"),
availableBalance = stringReference("2 130,88 USDT • 2 129,92 \$)"),
availableBalanceShort = stringReference("2 130,88 USDT"),
tokenIconState = CurrencyIconState.Loading,
segmentedButtonConfig = persistentListOf(
AmountSegmentedButtonsConfig(

View file

@ -11,6 +11,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
@ -25,6 +26,7 @@ import com.tangem.core.ui.format.bigdecimal.fiat
import com.tangem.core.ui.format.bigdecimal.format
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.core.ui.test.StakingSendDetailsScreenTestTags
import java.math.BigDecimal
@Composable
@ -63,7 +65,8 @@ fun AmountBlock(amountState: AmountState, isClickDisabled: Boolean, isEditingDis
maxLines = 1,
modifier = Modifier
.fillMaxWidth()
.padding(top = TangemTheme.dimens.spacing24),
.padding(top = TangemTheme.dimens.spacing24)
.testTag(StakingSendDetailsScreenTestTags.PRIMARY_AMOUNT),
)
Text(
text = secondAmount,
@ -72,7 +75,8 @@ fun AmountBlock(amountState: AmountState, isClickDisabled: Boolean, isEditingDis
textAlign = TextAlign.Center,
modifier = Modifier
.fillMaxWidth()
.padding(top = TangemTheme.dimens.spacing8),
.padding(top = TangemTheme.dimens.spacing8)
.testTag(StakingSendDetailsScreenTestTags.SECONDARY_AMOUNT),
)
}
}

View file

@ -15,6 +15,7 @@ import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import androidx.compose.ui.unit.dp
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.SpacerWMax
import com.tangem.core.ui.components.currency.icon.CurrencyIcon
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
@ -24,6 +25,7 @@ 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
import com.tangem.core.ui.format.bigdecimal.uncapped
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
@ -43,7 +45,7 @@ fun AmountBlockV2(
crypto(
symbol = "",
decimals = amount.cryptoAmount.decimals,
)
).uncapped()
}.orEmpty()
val fiatAmount = amount.fiatAmount.value.format {
@ -62,7 +64,7 @@ fun AmountBlockV2(
AmountBlockV2(
title = amountState.title,
balance = amountState.availableBalance,
balance = amountState.availableBalanceShort,
currencyTitle = currencyTitle,
currencyIconState = amountState.tokenIconState,
firstAmount = firstAmount,
@ -102,7 +104,7 @@ private fun AmountBlockV2(
Row {
Text(
text = title.resolveReference(),
style = TangemTheme.typography.body2,
style = TangemTheme.typography.subtitle2,
color = TangemTheme.colors.text.tertiary,
)
SpacerWMax()
@ -121,18 +123,20 @@ private fun AmountBlockV2(
verticalArrangement = Arrangement.spacedBy(4.dp),
modifier = Modifier.padding(top = 8.dp),
) {
Text(
ResizableText(
text = firstAmount,
style = TangemTheme.typography.h2,
color = TangemTheme.colors.text.primary1,
maxLines = 1,
)
Row(
horizontalArrangement = Arrangement.spacedBy(4.dp),
) {
Text(
ResizableText(
text = secondAmount,
style = TangemTheme.typography.body2,
color = TangemTheme.colors.text.tertiary,
maxLines = 1,
)
extraContent()
}

View file

@ -12,6 +12,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.platform.testTag
import com.tangem.common.ui.R
import com.tangem.common.ui.amountScreen.AmountScreenClickIntents
import com.tangem.common.ui.amountScreen.models.AmountSegmentedButtonsConfig
@ -22,6 +23,7 @@ import com.tangem.core.ui.components.currency.icon.CurrencyIcon
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.test.StakingSendScreenTestTags
import kotlinx.collections.immutable.PersistentList
private const val AMOUNT_BUTTONS_KEY = "amountButtonsKey"
@ -77,7 +79,8 @@ internal fun LazyListScope.buttons(
.padding(
vertical = TangemTheme.dimens.spacing10,
horizontal = TangemTheme.dimens.spacing34,
),
)
.testTag(StakingSendScreenTestTags.MAX_BUTTON),
)
}
}
@ -90,7 +93,8 @@ private fun AmountCurrencyButton(button: AmountSegmentedButtonsConfig, isSegment
.fillMaxSize()
.padding(
horizontal = TangemTheme.dimens.spacing10,
),
)
.testTag(StakingSendScreenTestTags.CURRENCY_BUTTON),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically,
) {
@ -102,13 +106,13 @@ private fun AmountCurrencyButton(button: AmountSegmentedButtonsConfig, isSegment
url = button.iconUrl,
size = TangemTheme.dimens.size18,
isGrayscale = !isSegmentedButtonsEnabled,
modifier = iconModifier,
modifier = iconModifier.testTag(StakingSendScreenTestTags.FIAT_ICON),
)
} else if (button.iconState != null) {
CurrencyIcon(
state = button.iconState,
shouldDisplayNetwork = false,
modifier = iconModifier,
modifier = iconModifier.testTag(StakingSendScreenTestTags.CURRENCY_ICON),
)
}
Text(

View file

@ -17,6 +17,7 @@ import androidx.compose.ui.Alignment.Companion.TopCenter
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextDirection
import com.tangem.common.ui.amountScreen.models.AmountFieldModel
@ -28,6 +29,7 @@ import com.tangem.core.ui.format.bigdecimal.crypto
import com.tangem.core.ui.format.bigdecimal.fiat
import com.tangem.core.ui.format.bigdecimal.format
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.test.StakingSendScreenTestTags
import com.tangem.core.ui.utils.rememberDecimalFormat
import kotlinx.coroutines.delay
@ -116,7 +118,8 @@ private fun AmountSecondary(amountField: AmountFieldModel, appCurrencyCode: Stri
textAlign = TextAlign.Center,
modifier = Modifier
.align(TopCenter)
.padding(bottom = TangemTheme.dimens.spacing32),
.padding(bottom = TangemTheme.dimens.spacing32)
.testTag(StakingSendScreenTestTags.SECONDARY_AMOUNT),
)
AmountFieldError(
isError = amountField.isError,

View file

@ -15,6 +15,7 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import com.tangem.common.ui.R
@ -29,6 +30,7 @@ import com.tangem.core.ui.extensions.orMaskWithStars
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.test.StakingSendScreenTestTags
private const val AMOUNT_FIELD_KEY = "amountFieldKey"
@ -52,7 +54,8 @@ internal fun LazyListScope.amountField(
style = TangemTheme.typography.subtitle2,
color = TangemTheme.colors.text.tertiary,
modifier = Modifier
.padding(top = TangemTheme.dimens.spacing14),
.padding(top = TangemTheme.dimens.spacing14)
.testTag(StakingSendScreenTestTags.AMOUNT_CONTAINER_TITLE),
)
val balance = amountState.availableBalance.orMaskWithStars(isBalanceHidden).resolveReference()
@ -66,7 +69,8 @@ internal fun LazyListScope.amountField(
color = TangemTheme.colors.text.tertiary,
textAlign = TextAlign.Center,
modifier = Modifier
.padding(top = TangemTheme.dimens.spacing2),
.padding(top = TangemTheme.dimens.spacing2)
.testTag(StakingSendScreenTestTags.AMOUNT_CONTAINER_TEXT),
)
}
CurrencyIcon(
@ -113,7 +117,7 @@ internal fun LazyListScope.amountFieldV2(
} else {
Text(
text = amountState.title.resolveReference(),
style = TangemTheme.typography.caption2,
style = TangemTheme.typography.subtitle2,
color = TangemTheme.colors.text.tertiary,
)
}
@ -164,7 +168,7 @@ private fun AmountInfo(amountUM: AmountState, onMaxAmountClick: () -> Unit, modi
modifier = Modifier
.padding(end = 16.dp)
.clip(RoundedCornerShape(16.dp))
.background(TangemTheme.colors.background.secondary)
.background(TangemTheme.colors.button.secondary)
.clickable(
interactionSource = remember { MutableInteractionSource() },
indication = ripple(),

View file

@ -127,7 +127,7 @@ private fun AmountSecondary(amountUM: AmountState, onCurrencyChange: (Boolean) -
modifier = Modifier
.fillMaxWidth()
.animateContentSize()
.padding(top = 8.dp),
.padding(top = 4.dp),
) {
if (amountUM is AmountState.Empty) {
TextShimmer(
@ -141,6 +141,7 @@ private fun AmountSecondary(amountUM: AmountState, onCurrencyChange: (Boolean) -
AmountFieldCurrencyInfo(
amountUM = amountUM,
onCurrencyChange = onCurrencyChange,
)
AmountFieldError(
isError = amountUM.amountTextField.isError,
@ -148,7 +149,7 @@ private fun AmountSecondary(amountUM: AmountState, onCurrencyChange: (Boolean) -
error = amountUM.amountTextField.error,
modifier = Modifier
.align(BottomCenter)
.padding(top = 20.dp),
.padding(top = 24.dp),
)
}
}
@ -161,12 +162,13 @@ private fun BoxScope.AmountFieldCurrencyInfo(amountUM: AmountState.Data, onCurre
horizontalArrangement = Arrangement.spacedBy(4.dp),
modifier = Modifier
.align(TopCenter)
.padding(bottom = 20.dp)
.padding(bottom = 16.dp)
.clickable(
interactionSource = remember { MutableInteractionSource() },
indication = null,
onClick = { onCurrencyChange(!amountUM.amountTextField.isFiatValue) },
),
)
.padding(4.dp),
) {
val iconRotateState by animateFloatAsState(
targetValue = if (amountUM.amountTextField.isFiatValue) ROTATED_DEGREE else INITIAL_DEGREE,
@ -324,6 +326,7 @@ private class AmountFieldV2PreviewProvider : PreviewParameterProvider<AmountStat
get() = sequenceOf(
AmountStatePreviewData.emptyState,
AmountStatePreviewData.amountState,
AmountStatePreviewData.amountErrorState,
)
}
// endregion

View file

@ -2,9 +2,11 @@ package com.tangem.common.ui.amountScreen.utils
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.utils.BigDecimalFormatter
import com.tangem.core.ui.utils.BigDecimalFormatter.EMPTY_BALANCE_SIGN
import com.tangem.core.ui.format.bigdecimal.approximateAmount
import com.tangem.core.ui.format.bigdecimal.fiat
import com.tangem.core.ui.format.bigdecimal.format
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.utils.StringsSigns.DASH_SIGN
import java.math.BigDecimal
fun getFiatReference(value: BigDecimal?, rate: BigDecimal?, appCurrency: AppCurrency): TextReference? {
@ -19,12 +21,19 @@ fun getFiatString(
appCurrency: AppCurrency,
approximate: Boolean = false,
): String {
if (value == null || rate == null) return EMPTY_BALANCE_SIGN
if (value == null || rate == null) return DASH_SIGN
val feeValue = value.multiply(rate)
return BigDecimalFormatter.formatFiatAmount(
fiatAmount = feeValue,
fiatCurrencyCode = appCurrency.code,
fiatCurrencySymbol = appCurrency.symbol,
withApproximateSign = approximate,
)
return feeValue.format {
if (approximate) {
fiat(
fiatCurrencyCode = appCurrency.code,
fiatCurrencySymbol = appCurrency.symbol,
).approximateAmount()
} else {
fiat(
fiatCurrencyCode = appCurrency.code,
fiatCurrencySymbol = appCurrency.symbol,
)
}
}
}

View file

@ -43,9 +43,9 @@ fun GiveTxPermissionBottomSheet(config: TangemBottomSheetConfig) {
config = config,
containerColor = TangemTheme.colors.background.secondary,
titleText = resourceReference(R.string.give_permission_title),
titleAction = TopAppBarButtonUM(
titleAction = TopAppBarButtonUM.Icon(
iconRes = R.drawable.ic_information_24,
onIconClicked = { isPermissionAlertShow = true },
onClicked = { isPermissionAlertShow = true },
),
content = { content: GiveTxPermissionBottomSheetConfig ->
GiveTxPermissionBottomSheetContent(content = content)

View file

@ -49,10 +49,10 @@ fun SendingText(footerText: TextReference, modifier: Modifier = Modifier) {
text = footerText.resolveAnnotatedReference(),
textAlign = TextAlign.Center,
style = TangemTheme.typography.caption2,
color = TangemTheme.colors.text.primary1,
color = TangemTheme.colors.text.tertiary,
modifier = Modifier
.fillMaxWidth()
.padding(12.dp),
.padding(16.dp),
)
}
}

View file

@ -15,6 +15,9 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.graphics.vector.rememberVectorPainter
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
@ -22,18 +25,18 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import com.tangem.common.ui.navigationButtons.preview.NavigationButtonsPreview
import com.tangem.core.ui.components.Keyboard
import com.tangem.core.ui.components.SecondaryButtonIconStart
import com.tangem.core.ui.components.buttons.common.TangemButton
import com.tangem.core.ui.components.buttons.common.TangemButtonIconPosition
import com.tangem.core.ui.components.buttons.common.TangemButtonsDefaults
import com.tangem.core.ui.components.buttons.common.contentColor
import com.tangem.core.ui.components.keyboardAsState
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.isNullOrEmpty
import com.tangem.core.ui.extensions.rememberHapticFeedback
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import kotlinx.collections.immutable.ImmutableList
import com.tangem.core.ui.utils.singleEvent
import com.tangem.core.ui.test.StakingSendScreenTestTags
@Composable
fun NavigationButtonsBlock(
@ -47,7 +50,7 @@ fun NavigationButtonsBlock(
modifier = modifier.fillMaxWidth(),
) {
InfoText(footerText)
ExtraButtons(state?.extraButtons, state?.txUrl)
DoneButtons(state?.extraButtons)
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing12),
@ -58,9 +61,33 @@ fun NavigationButtonsBlock(
}
}
@Composable
fun NavigationButtonsBlockV2(
navigationUM: NavigationUM,
modifier: Modifier = Modifier,
footerText: TextReference? = null,
) {
val navigationUM = navigationUM as? NavigationUM.Content
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = modifier.fillMaxWidth(),
) {
InfoText(footerText)
DoneButtons(navigationUM?.secondaryPairButtonsUM)
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing12),
) {
PreviousButton(navigationUM?.prevButton)
NavigationPrimaryButton(navigationUM?.primaryButton, modifier = Modifier.weight(1f))
}
}
}
@Composable
fun NavigationPrimaryButton(primaryButton: NavigationButton?, modifier: Modifier = Modifier) {
val wrappedButton by rememberNavigationButton(primaryButton)
val hapticFeedback = LocalHapticFeedback.current
AnimatedContent(
targetState = wrappedButton,
transitionSpec = { navigationButtonsTransition() },
@ -83,7 +110,12 @@ fun NavigationPrimaryButton(primaryButton: NavigationButton?, modifier: Modifier
TangemButton(
text = button.textReference.resolveReference(),
enabled = button.isEnabled,
onClick = button.onClick,
onClick = {
if (button.isHapticClick) {
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
}
button.onClick()
},
showProgress = button.showProgress,
colors = color,
textStyle = TangemTheme.typography.subtitle1,
@ -116,40 +148,47 @@ private fun PreviousButton(prevButton: NavigationButton?) {
.clip(RoundedCornerShape(TangemTheme.dimens.radius16))
.background(TangemTheme.colors.button.secondary)
.clickable(onClick = button.onClick)
.padding(TangemTheme.dimens.spacing12),
.padding(TangemTheme.dimens.spacing12)
.testTag(StakingSendScreenTestTags.PREVIOUS_BUTTON),
)
}
}
}
@Composable
private fun ExtraButtons(extraButtons: ImmutableList<NavigationButton>?, txUrl: String?) {
fun DoneButtons(pairButtons: Pair<NavigationButton, NavigationButton>?, modifier: Modifier = Modifier) {
AnimatedVisibility(
visible = !txUrl.isNullOrBlank() && extraButtons != null,
visible = pairButtons != null,
enter = slideInVertically(initialOffsetY = { it / 2 }).plus(fadeIn()),
exit = slideOutVertically(targetOffsetY = { it / 2 }).plus(fadeOut()),
label = "Animate show sent state buttons",
modifier = Modifier.fillMaxWidth(),
modifier = modifier.fillMaxWidth(),
) {
val buttons = remember(this) { requireNotNull(extraButtons) }
val (leftButton, rightButton) = remember(this) { requireNotNull(pairButtons) }
Row(
horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing12),
modifier = Modifier.padding(bottom = TangemTheme.dimens.spacing12),
) {
buttons.forEach { button ->
val icon = button.iconRes?.let { TangemButtonIconPosition.Start(iconResId = it) }
?: TangemButtonIconPosition.None
TangemButton(
text = button.textReference.resolveReference(),
icon = icon,
textStyle = TangemTheme.typography.subtitle1,
onClick = rememberHapticFeedback(state = button, onAction = button.onClick),
modifier = Modifier.weight(1f),
enabled = button.isEnabled,
showProgress = false,
colors = TangemButtonsDefaults.secondaryButtonColors,
)
}
SecondaryButtonIconStart(
text = leftButton.textReference.resolveReference(),
iconResId = requireNotNull(leftButton.iconRes),
onClick = {
singleEvent {
leftButton.onClick()
}
},
modifier = Modifier.weight(1f),
)
SecondaryButtonIconStart(
text = rightButton.textReference.resolveReference(),
iconResId = requireNotNull(rightButton.iconRes),
onClick = {
singleEvent {
rightButton.onClick()
}
},
modifier = Modifier.weight(1f),
)
}
}
}

View file

@ -2,7 +2,6 @@ package com.tangem.common.ui.navigationButtons
import androidx.annotation.DrawableRes
import com.tangem.core.ui.extensions.TextReference
import kotlinx.collections.immutable.ImmutableList
sealed class NavigationButtonsState {
data object Empty : NavigationButtonsState()
@ -10,7 +9,7 @@ sealed class NavigationButtonsState {
data class Data(
val primaryButton: NavigationButton?,
val prevButton: NavigationButton?,
val extraButtons: ImmutableList<NavigationButton>,
val extraButtons: Pair<NavigationButton, NavigationButton>?,
val txUrl: String? = null,
val onTextClick: (String) -> Unit,
) : NavigationButtonsState()

View file

@ -5,29 +5,25 @@ import com.tangem.common.ui.navigationButtons.NavigationButton
import com.tangem.common.ui.navigationButtons.NavigationButtonsState
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resourceReference
import kotlinx.collections.immutable.persistentListOf
internal object NavigationButtonsPreview {
private val extraButtons = persistentListOf(
NavigationButton(
textReference = resourceReference(R.string.common_explore),
iconRes = R.drawable.ic_tangem_24,
isSecondary = true,
isIconVisible = true,
showProgress = false,
isEnabled = true,
onClick = {},
),
NavigationButton(
textReference = resourceReference(R.string.common_share),
iconRes = R.drawable.ic_tangem_24,
isSecondary = true,
isIconVisible = true,
showProgress = false,
isEnabled = true,
onClick = {},
),
private val extraButtons = NavigationButton(
textReference = resourceReference(R.string.common_explore),
iconRes = R.drawable.ic_tangem_24,
isSecondary = true,
isIconVisible = true,
showProgress = false,
isEnabled = true,
onClick = {},
) to NavigationButton(
textReference = resourceReference(R.string.common_share),
iconRes = R.drawable.ic_tangem_24,
isSecondary = true,
isIconVisible = true,
showProgress = false,
isEnabled = true,
onClick = {},
)
private val prev = NavigationButton(

View file

@ -0,0 +1,11 @@
package com.tangem.common.ui.notifications
/**
* NotificationId represents unique identifiers for notifications in the app.
*
* These ids can be used with [ShouldShowNotificationUseCase] and [SetShouldShowNotificationUseCase]
* to check or update the visibility state of notifications.
*/
enum class NotificationId(val key: String) {
SendViaSwapTokenSelectorNotification("SendViaSwapTokenSelectorNotificationKey"),
}

View file

@ -373,5 +373,15 @@ sealed class NotificationUM(val config: NotificationConfig) {
formatArgs = wrappedList(rentInfo.exemptionAmount),
),
)
data class RentExemptionDestination(
private val rentExemptionAmount: BigDecimal,
) : Error(
title = TextReference.Res(R.string.send_notification_invalid_amount_title),
subtitle = TextReference.Res(
id = R.string.send_notification_invalid_amount_rent_destination,
formatArgs = wrappedList(rentExemptionAmount),
),
)
}
}

View file

@ -11,7 +11,7 @@ import com.tangem.core.ui.format.bigdecimal.uncapped
import com.tangem.core.ui.utils.parseBigDecimal
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.tokens.model.warnings.CryptoCurrencyCheck
import com.tangem.domain.tokens.model.warnings.CryptoCurrencyWarning
import com.tangem.domain.transaction.error.GetFeeError
@ -354,7 +354,11 @@ object NotificationsFactory {
onReduceClick = onReduceClick,
)
is BlockchainSdkError.DestinationTagRequired -> addRequireDestinationTagErrorNotification()
null -> minAdaValue?.let {
is BlockchainSdkError.Solana.DestinationRentExemption -> addRentExemptionDestinationNotification(
rentExemptionAmount = validationError.rentAmount,
)
null,
-> minAdaValue?.let {
add(
NotificationUM.Cardano.MinAdaValueCharged(
tokenName = cryptoCurrency.name,
@ -439,6 +443,14 @@ object NotificationsFactory {
add(NotificationUM.Solana.RentInfo(rentWarning))
}
fun MutableList<NotificationUM>.addRentExemptionDestinationNotification(rentExemptionAmount: BigDecimal) {
add(
NotificationUM.Solana.RentExemptionDestination(
rentExemptionAmount = rentExemptionAmount,
),
)
}
fun MutableList<NotificationUM>.addHighFeeWarningNotification(
enteredAmountValue: BigDecimal,
cryptoCurrencyStatus: CryptoCurrencyStatus,

View file

@ -10,6 +10,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
@ -29,6 +30,7 @@ import com.tangem.core.ui.res.LocalWindowSize
import com.tangem.core.ui.res.TangemColorPalette
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.core.ui.test.SwapStoriesScreenTestTags
import kotlinx.collections.immutable.persistentListOf
private val SubtitleColor = Color(0xFFB0B0B0)
@ -46,7 +48,8 @@ fun SwapStoriesScreen(config: SwapStoriesUM) {
Box(
modifier = Modifier
.fillMaxSize()
.background(TangemColorPalette.Black),
.background(TangemColorPalette.Black)
.testTag(SwapStoriesScreenTestTags.SCREEN_CONTAINER),
) {
SubcomposeAsyncImage(
modifier = Modifier.fillMaxSize(),

View file

@ -13,9 +13,9 @@ import com.tangem.core.ui.format.bigdecimal.format
import com.tangem.core.ui.format.bigdecimal.percent
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.models.StatusSource
import com.tangem.domain.staking.model.stakekit.YieldBalance
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.models.staking.YieldBalance
import com.tangem.domain.staking.utils.getTotalWithRewardsStakingBalance
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.utils.StringsSigns.DASH_SIGN
import com.tangem.utils.converter.Converter
import com.tangem.utils.extensions.isZero

View file

@ -3,7 +3,9 @@ package com.tangem.common.ui.userwallet
import android.content.res.Configuration
import androidx.compose.animation.AnimatedContent
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.CardColors
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
@ -22,6 +24,7 @@ import androidx.compose.ui.text.style.TextOverflow
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 coil.compose.SubcomposeAsyncImage
import coil.request.ImageRequest
import com.tangem.common.ui.R
@ -30,6 +33,9 @@ import com.tangem.core.ui.components.RectangleShimmer
import com.tangem.core.ui.components.TextShimmer
import com.tangem.core.ui.components.block.BlockCard
import com.tangem.core.ui.components.block.TangemBlockCardColors
import com.tangem.core.ui.components.label.Label
import com.tangem.core.ui.components.label.entity.LabelStyle
import com.tangem.core.ui.components.label.entity.LabelUM
import com.tangem.core.ui.components.text.applyBladeBrush
import com.tangem.core.ui.extensions.*
import com.tangem.core.ui.res.TangemTheme
@ -67,8 +73,10 @@ fun UserWalletItem(
balance = state.balance,
)
state.label?.let { Label(it) }
when (state.endIcon) {
UserWalletItemUM.EndIcon.None -> {}
UserWalletItemUM.EndIcon.None -> Unit
UserWalletItemUM.EndIcon.Arrow -> {
Icon(
imageVector = ImageVector.vectorResource(R.drawable.ic_chevron_right_24),
@ -179,6 +187,19 @@ fun CardImage(imageState: UserWalletItemUM.ImageState, modifier: Modifier = Modi
radius = TangemTheme.dimens.size2,
)
}
is UserWalletItemUM.ImageState.MobileWallet -> {
Image(
modifier = Modifier
.size(36.dp)
.background(
color = TangemTheme.colors.field.focused,
shape = RoundedCornerShape(10.dp),
)
.padding(6.dp),
imageVector = ImageVector.vectorResource(R.drawable.ic_mobile_wallet_icon_24),
contentDescription = null,
)
}
is UserWalletItemUM.ImageState.Image -> {
val verifiedArtwork = imageState.artwork.verifiedArtwork
if (verifiedArtwork != null) {
@ -257,6 +278,18 @@ private fun Preview_UserWalletItem(
private class UserWalletItemUMPreviewProvider : PreviewParameterProvider<UserWalletItemUM> {
override val values: Sequence<UserWalletItemUM>
get() = sequenceOf(
UserWalletItemUM(
id = UserWalletId("user_wallet_0".encodeToByteArray()),
name = stringReference("Mobile Wallet"),
information = getInformation(cardCount = 1),
balance = UserWalletItemUM.Balance.Locked,
label = LabelUM(
text = resourceReference(R.string.hw_backup_no_backup),
style = LabelStyle.WARNING,
),
isEnabled = true,
onClick = {},
),
UserWalletItemUM(
id = UserWalletId("user_wallet_1".encodeToByteArray()),
name = stringReference("My Wallet"),
@ -347,6 +380,18 @@ private class UserWalletItemUMPreviewProvider : PreviewParameterProvider<UserWal
isEnabled = true,
onClick = {},
),
UserWalletItemUM(
id = UserWalletId("user_wallet_3".encodeToByteArray()),
name = stringReference("Multi Card"),
information = UserWalletItemUM.Information.Failed,
balance = UserWalletItemUM.Balance.Loaded(
value = "1.2345 BTC",
isFlickering = false,
),
imageState = UserWalletItemUM.ImageState.MobileWallet,
isEnabled = true,
onClick = {},
),
)
private fun getInformation(cardCount: Int): UserWalletItemUM.Information.Loaded {

View file

@ -2,7 +2,10 @@ package com.tangem.common.ui.userwallet.converter
import com.tangem.common.ui.R
import com.tangem.common.ui.userwallet.state.UserWalletItemUM
import com.tangem.core.ui.components.label.entity.LabelUM
import com.tangem.core.ui.components.label.entity.LabelStyle
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.extensions.wrappedList
import com.tangem.core.ui.format.bigdecimal.fiat
@ -32,6 +35,7 @@ class UserWalletItemUMConverter(
private val appCurrency: AppCurrency? = null,
private val balance: TotalFiatBalance? = null,
private val isBalanceHidden: Boolean = false,
private val authMode: Boolean = false,
private val endIcon: UserWalletItemUM.EndIcon = UserWalletItemUM.EndIcon.None,
private val artwork: ArtworkModel? = null,
) : Converter<UserWallet, UserWalletItemUM> {
@ -45,16 +49,38 @@ class UserWalletItemUMConverter(
name = stringReference(name),
information = getInfo(userWallet = this),
balance = getBalanceInfo(userWallet = this),
isEnabled = !isLocked,
isEnabled = isEnabled(userWallet = this),
endIcon = endIcon,
onClick = { onClick(value.walletId) },
imageState = artwork?.let {
UserWalletItemUM.ImageState.Image(artworkUMConverter.convert(it))
} ?: UserWalletItemUM.ImageState.Loading,
imageState = getImageState(userWallet = value),
label = getLabelOrNull(userWallet = this),
)
}
}
private fun isEnabled(userWallet: UserWallet): Boolean {
return authMode || userWallet.isLocked.not()
}
private fun getLabelOrNull(userWallet: UserWallet): LabelUM? {
return if (authMode.not() && userWallet is UserWallet.Hot && !userWallet.backedUp) {
LabelUM(
text = resourceReference(R.string.hw_backup_no_backup),
style = LabelStyle.WARNING,
)
} else {
null
}
}
private fun getImageState(userWallet: UserWallet): UserWalletItemUM.ImageState {
return when {
userWallet is UserWallet.Hot -> UserWalletItemUM.ImageState.MobileWallet
artwork != null -> UserWalletItemUM.ImageState.Image(artworkUMConverter.convert(artwork))
else -> UserWalletItemUM.ImageState.Loading
}
}
private fun getInfo(userWallet: UserWallet): UserWalletItemUM.Information.Loaded {
val text = when (userWallet) {
is UserWallet.Cold -> {

View file

@ -1,6 +1,7 @@
package com.tangem.common.ui.userwallet.state
import com.tangem.core.ui.components.artwork.ArtworkUM
import com.tangem.core.ui.components.label.entity.LabelUM
import com.tangem.core.ui.extensions.TextReference
import com.tangem.domain.models.wallet.UserWalletId
import javax.annotation.concurrent.Immutable
@ -15,6 +16,7 @@ data class UserWalletItemUM(
val isEnabled: Boolean,
val endIcon: EndIcon = EndIcon.None,
val onClick: () -> Unit,
val label: LabelUM? = null,
) {
enum class EndIcon {
None,
@ -54,6 +56,8 @@ data class UserWalletItemUM(
data object Loading : ImageState()
data object MobileWallet : ImageState()
data class Image(
val artwork: ArtworkUM,
) : ImageState()