Updated on 2026-08-14

This commit is contained in:
Tangem 2025-12-12 15:11:58 +05:00
parent eb73a64054
commit 00d55ff5a6
39 changed files with 195 additions and 272 deletions

View file

@ -24,7 +24,6 @@
<ID>NoNameShadowing:TextAnimatedCounter.kt$char</ID> <ID>NoNameShadowing:TextAnimatedCounter.kt$char</ID>
<ID>PropertyUsedBeforeDeclaration:InputManager.kt$InputManager$_query</ID> <ID>PropertyUsedBeforeDeclaration:InputManager.kt$InputManager$_query</ID>
<ID>ReusedModifierInstance:EllipsisText.kt$Text( text = layoutText, color = color, style = style, fontStyle = fontStyle, textDecoration = textDecoration, textAlign = textAlign, softWrap = softWrap, maxLines = 1, onTextLayout = { textLayoutResultState.value = it }, modifier = modifier, )</ID> <ID>ReusedModifierInstance:EllipsisText.kt$Text( text = layoutText, color = color, style = style, fontStyle = fontStyle, textDecoration = textDecoration, textAlign = textAlign, softWrap = softWrap, maxLines = 1, onTextLayout = { textLayoutResultState.value = it }, modifier = modifier, )</ID>
<ID>ReusedModifierInstance:Label.kt$Row( verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(4.dp), modifier = modifier .padding(horizontal = 4.dp) .clip(TangemTheme.shapes.roundedCorners8) .background(color = backgroundColor) .then( if (state.onClick != null) { Modifier.clickable( interactionSource = remember { MutableInteractionSource() }, indication = ripple(), onClick = state.onClick, ) } else { Modifier }, ) .padding(horizontal = 8.dp, vertical = 4.dp), ) { Text( modifier = Modifier.weight(1.0f, fill = false), text = text.resolveReference(), style = TangemTheme.typography.caption1, color = textColor, ) AnimatedVisibility(state.icon != null) { val wrappedIcon = remember(this) { requireNotNull(state.icon) } Icon( imageVector = ImageVector.vectorResource(wrappedIcon), tint = iconColor, contentDescription = null, modifier = Modifier .size(16.dp) .clickable( interactionSource = remember { MutableInteractionSource() }, indication = ripple(bounded = false), onClick = { state.onIconClick?.invoke() }, ), ) } }</ID>
<ID>ReusedModifierInstance:TangemRadioButton.kt$AnimatedVisibility( visible = isSelected, label = "Radio button animation", modifier = modifier .size(TangemTheme.dimens.size24), ) { Icon( painter = painterResource(id = R.drawable.ic_check_circle_24), contentDescription = null, tint = TangemTheme.colors.control.checked, ) }</ID> <ID>ReusedModifierInstance:TangemRadioButton.kt$AnimatedVisibility( visible = isSelected, label = "Radio button animation", modifier = modifier .size(TangemTheme.dimens.size24), ) { Icon( painter = painterResource(id = R.drawable.ic_check_circle_24), contentDescription = null, tint = TangemTheme.colors.control.checked, ) }</ID>
<ID>ReusedModifierInstance:TokenPrice.kt$Icon( modifier = modifier, painter = painterResource( id = when (animatedType) { PriceChangeType.UP -&gt; R.drawable.ic_arrow_up_8 PriceChangeType.DOWN -&gt; R.drawable.ic_arrow_down_8 PriceChangeType.NEUTRAL -&gt; R.drawable.ic_elipse_8 }, ), tint = when (animatedType) { PriceChangeType.UP -&gt; TangemTheme.colors.icon.accent PriceChangeType.DOWN -&gt; TangemTheme.colors.icon.warning PriceChangeType.NEUTRAL -&gt; TangemTheme.colors.icon.inactive }, contentDescription = null, )</ID> <ID>ReusedModifierInstance:TokenPrice.kt$Icon( modifier = modifier, painter = painterResource( id = when (animatedType) { PriceChangeType.UP -&gt; R.drawable.ic_arrow_up_8 PriceChangeType.DOWN -&gt; R.drawable.ic_arrow_down_8 PriceChangeType.NEUTRAL -&gt; R.drawable.ic_elipse_8 }, ), tint = when (animatedType) { PriceChangeType.UP -&gt; TangemTheme.colors.icon.accent PriceChangeType.DOWN -&gt; TangemTheme.colors.icon.warning PriceChangeType.NEUTRAL -&gt; TangemTheme.colors.icon.inactive }, contentDescription = null, )</ID>
<ID>UnnecessaryEventHandlerParameter:PinTextField.kt$onValueChange: (String) -&gt; Unit</ID> <ID>UnnecessaryEventHandlerParameter:PinTextField.kt$onValueChange: (String) -&gt; Unit</ID>

View file

@ -1,19 +0,0 @@
<?xml version="1.0" ?>
<SmellBaseline>
<ManuallySuppressedIssues/>
<CurrentIssues>
<ID>MaxChainedCallsOnSameLine:DefaultSwapRepositoryV2.kt$DefaultSwapRepositoryV2$fromCryptoCurrencyStatus.value.networkAddress?.defaultAddress?.value.orEmpty()</ID>
<ID>MultilineLambdaItParameter:DefaultSwapRepositoryV2.kt$DefaultSwapRepositoryV2${ Timber.w(it, "Unable to get pairs") throw it }</ID>
<ID>MultilineLambdaItParameter:DefaultSwapRepositoryV2.kt$DefaultSwapRepositoryV2${ it.currency.getContractAddress() == pair.from.contractAddress &amp;&amp; it.currency.network.backendId == pair.from.network }</ID>
<ID>MultilineLambdaItParameter:DefaultSwapRepositoryV2.kt$DefaultSwapRepositoryV2${ it.currency.getContractAddress() == pair.to.contractAddress &amp;&amp; it.currency.network.backendId == pair.to.network }</ID>
<ID>MultilineLambdaItParameter:DefaultSwapRepositoryV2.kt$DefaultSwapRepositoryV2${ it.getContractAddress() == pair.from.contractAddress &amp;&amp; it.network.backendId == pair.from.network }</ID>
<ID>MultilineLambdaItParameter:DefaultSwapRepositoryV2.kt$DefaultSwapRepositoryV2${ it.getContractAddress() == pair.to.contractAddress &amp;&amp; it.network.backendId == pair.to.network }</ID>
<ID>MultilineLambdaItParameter:DefaultSwapTransactionRepository.kt$DefaultSwapTransactionRepository${ it.checkId( checkUserWalletId = userWalletId, fromCurrencyId = fromCryptoCurrency.id, toCurrencyId = toCryptoCurrency.id, ) }</ID>
<ID>MultilineLambdaItParameter:DefaultSwapTransactionRepository.kt$DefaultSwapTransactionRepository${ it.userWalletId == userWallet.walletId.stringValue &amp;&amp; ( it.toCryptoCurrencyId == cryptoCurrencyId.value || it.fromCryptoCurrencyId == cryptoCurrencyId.value ) }</ID>
<ID>MultilineLambdaItParameter:DefaultSwapTransactionRepository.kt$DefaultSwapTransactionRepository${ listConverter.convertBack( value = it, multiAccountList = multiAccountList, userWallet = userWallet, txStatuses = txStatuses, ) }</ID>
<ID>MultilineLambdaItParameter:DefaultSwapTransactionRepository.kt$DefaultSwapTransactionRepository${ storeTransactionState( txId = transaction.txId, status = it, accountWithCurrency = fromAccount?.accountId to fromCryptoCurrency, ) }</ID>
<ID>MultilineLambdaItParameter:SwapDataConverter.kt$SwapDataConverter${ if (it == "0") { BigDecimal.ZERO } else { requireNotNull(it.toBigDecimalOrNull()) { "wrong amount format, use only digits" } } }</ID>
<ID>NoNameShadowing:DefaultSwapRepositoryV2.kt$DefaultSwapRepositoryV2$mappedProviders</ID>
<ID>NoNameShadowing:DefaultSwapTransactionRepository.kt$DefaultSwapTransactionRepository${ it.txId == txId }</ID>
</CurrentIssues>
</SmellBaseline>

View file

@ -79,23 +79,23 @@ internal class DefaultSwapRepositoryV2 @Inject constructor(
userWallet = userWallet, userWallet = userWallet,
filterProviderTypes = filterProviderTypes, filterProviderTypes = filterProviderTypes,
) )
val mappedProviders = providers.associateBy(ExpressProvider::providerId) val expressProviders = providers.associateBy(ExpressProvider::providerId)
allPairs.map { pair -> allPairs.map { pair ->
async { async {
val statusFrom = cryptoCurrencyStatusList val statusFrom = cryptoCurrencyStatusList
.firstOrNull { .firstOrNull { currencyStatus ->
it.currency.getContractAddress() == pair.from.contractAddress && currencyStatus.currency.getContractAddress() == pair.from.contractAddress &&
it.currency.network.backendId == pair.from.network currencyStatus.currency.network.backendId == pair.from.network
} }
val statusTo = cryptoCurrencyStatusList val statusTo = cryptoCurrencyStatusList
.firstOrNull { .firstOrNull { currencyStatus ->
it.currency.getContractAddress() == pair.to.contractAddress && currencyStatus.currency.getContractAddress() == pair.to.contractAddress &&
it.currency.network.backendId == pair.to.network currencyStatus.currency.network.backendId == pair.to.network
} }
val mappedProviders = pair.providers.mapNotNull { val mappedProviders = pair.providers.mapNotNull {
mappedProviders[it.providerId] expressProviders[it.providerId]
}.filterYieldSupplyProvider(statusFrom) }.filterYieldSupplyProvider(statusFrom)
if (statusFrom != null && statusTo != null && mappedProviders.isNotEmpty()) { if (statusFrom != null && statusTo != null && mappedProviders.isNotEmpty()) {
@ -135,16 +135,16 @@ internal class DefaultSwapRepositoryV2 @Inject constructor(
async { async {
val statusFromDeferred = async { val statusFromDeferred = async {
cryptoCurrencyList cryptoCurrencyList
.firstOrNull { .firstOrNull { currency ->
it.getContractAddress() == pair.from.contractAddress && currency.getContractAddress() == pair.from.contractAddress &&
it.network.backendId == pair.from.network currency.network.backendId == pair.from.network
} }
} }
val statusToDeferred = async { val statusToDeferred = async {
cryptoCurrencyList cryptoCurrencyList
.firstOrNull { .firstOrNull { currency ->
it.getContractAddress() == pair.to.contractAddress && currency.getContractAddress() == pair.to.contractAddress &&
it.network.backendId == pair.to.network currency.network.backendId == pair.to.network
} }
} }
@ -213,27 +213,27 @@ internal class DefaultSwapRepositoryV2 @Inject constructor(
expressOperationType: ExpressOperationType, expressOperationType: ExpressOperationType,
): SwapDataModel = withContext(coroutineDispatcher.io) { ): SwapDataModel = withContext(coroutineDispatcher.io) {
val requestId = UUID.randomUUID().toString() val requestId = UUID.randomUUID().toString()
val fromCryptoCurrency = fromCryptoCurrencyStatus.currency val (fromCurrency, fromStatus) = fromCryptoCurrencyStatus
val refundData = when (expressProvider.type) { val refundData = when (expressProvider.type) {
ExpressProviderType.CEX, ExpressProviderType.CEX,
ExpressProviderType.DEX_BRIDGE, ExpressProviderType.DEX_BRIDGE,
ExpressProviderType.DEX, ExpressProviderType.DEX,
-> SwapRefundData( -> SwapRefundData(
refundAddress = fromCryptoCurrencyStatus.value.networkAddress?.defaultAddress?.value, refundAddress = fromStatus.networkAddress?.defaultAddress?.value,
refundExtraId = null, // currently always null refundExtraId = null, // currently always null
) )
else -> null else -> null
} }
val response = tangemExpressApi.getExchangeData( val response = tangemExpressApi.getExchangeData(
fromContractAddress = fromCryptoCurrency.getContractAddress(), fromContractAddress = fromCurrency.getContractAddress(),
toContractAddress = toCryptoCurrency.getContractAddress(), toContractAddress = toCryptoCurrency.getContractAddress(),
fromNetwork = fromCryptoCurrency.network.backendId, fromNetwork = fromCurrency.network.backendId,
toNetwork = toCryptoCurrency.network.backendId, toNetwork = toCryptoCurrency.network.backendId,
fromAddress = fromCryptoCurrencyStatus.value.networkAddress?.defaultAddress?.value.orEmpty(), fromAddress = fromStatus.networkAddress?.defaultAddress?.value.orEmpty(),
toAddress = toAddress, toAddress = toAddress,
fromDecimals = fromCryptoCurrency.decimals, fromDecimals = fromCurrency.decimals,
toDecimals = toCryptoCurrency.decimals, toDecimals = toCryptoCurrency.decimals,
fromAmount = fromAmount, fromAmount = fromAmount,
providerId = expressProvider.providerId, providerId = expressProvider.providerId,
@ -277,6 +277,7 @@ internal class DefaultSwapRepositoryV2 @Inject constructor(
txHash: String, txHash: String,
txExtraId: String?, txExtraId: String?,
) { ) {
val (currency, status) = fromCryptoCurrencyStatus
withContext(coroutineDispatcher.io) { withContext(coroutineDispatcher.io) {
tangemExpressApi.exchangeSent( tangemExpressApi.exchangeSent(
userWalletId = userWallet.walletId.stringValue, userWalletId = userWallet.walletId.stringValue,
@ -286,8 +287,8 @@ internal class DefaultSwapRepositoryV2 @Inject constructor(
), ),
body = ExchangeSentRequestBody( body = ExchangeSentRequestBody(
txId = txId, txId = txId,
fromNetwork = fromCryptoCurrencyStatus.currency.network.backendId, fromNetwork = currency.network.backendId,
fromAddress = fromCryptoCurrencyStatus.value.networkAddress?.defaultAddress?.value.orEmpty(), fromAddress = status.networkAddress?.defaultAddress?.value.orEmpty(),
payinAddress = toAddress, payinAddress = toAddress,
payinExtraId = txExtraId, payinExtraId = txExtraId,
txHash = txHash, txHash = txHash,
@ -364,9 +365,9 @@ internal class DefaultSwapRepositoryV2 @Inject constructor(
), ),
).getOrThrow() ).getOrThrow()
}, },
onError = { onError = { error ->
Timber.w(it, "Unable to get pairs") Timber.w(error, "Unable to get pairs")
throw it throw error
}, },
) )
} }

View file

@ -64,10 +64,10 @@ internal class DefaultSwapTransactionRepository(
toAccount: Account.CryptoPortfolio?, toAccount: Account.CryptoPortfolio?,
transaction: SwapTransactionModel, transaction: SwapTransactionModel,
) { ) {
transaction.status?.let { transaction.status?.let { swapTxList ->
storeTransactionState( storeTransactionState(
txId = transaction.txId, txId = transaction.txId,
status = it, status = swapTxList,
accountWithCurrency = fromAccount?.accountId to fromCryptoCurrency, accountWithCurrency = fromAccount?.accountId to fromCryptoCurrency,
) )
} }
@ -76,8 +76,8 @@ internal class DefaultSwapTransactionRepository(
key = PreferencesKeys.SWAP_TRANSACTIONS_KEY, key = PreferencesKeys.SWAP_TRANSACTIONS_KEY,
) )
val tokenTransactions = savedTransactions val tokenTransactions = savedTransactions
?.firstOrNull { ?.firstOrNull { swapTxList ->
it.checkId( swapTxList.checkId(
checkUserWalletId = userWalletId, checkUserWalletId = userWalletId,
fromCurrencyId = fromCryptoCurrency.id, fromCurrencyId = fromCryptoCurrency.id,
toCurrencyId = toCryptoCurrency.id, toCurrencyId = toCryptoCurrency.id,
@ -129,17 +129,17 @@ internal class DefaultSwapTransactionRepository(
}, },
) { savedTransactions, txStatuses, multiAccountList -> ) { savedTransactions, txStatuses, multiAccountList ->
val currencyTxs = savedTransactions val currencyTxs = savedTransactions
?.filter { ?.filter { swapTxList ->
it.userWalletId == userWallet.walletId.stringValue && swapTxList.userWalletId == userWallet.walletId.stringValue &&
( (
it.toCryptoCurrencyId == cryptoCurrencyId.value || swapTxList.toCryptoCurrencyId == cryptoCurrencyId.value ||
it.fromCryptoCurrencyId == cryptoCurrencyId.value swapTxList.fromCryptoCurrencyId == cryptoCurrencyId.value
) )
} }
currencyTxs?.mapNotNull { currencyTxs?.mapNotNull { swapTxList ->
listConverter.convertBack( listConverter.convertBack(
value = it, value = swapTxList,
multiAccountList = multiAccountList, multiAccountList = multiAccountList,
userWallet = userWallet, userWallet = userWallet,
txStatuses = txStatuses, txStatuses = txStatuses,
@ -155,8 +155,8 @@ internal class DefaultSwapTransactionRepository(
) )
val tokenTransactions = savedList val tokenTransactions = savedList
?.asSequence() ?.asSequence()
?.map { ?.map { swapTxList ->
it.copy(transactions = it.transactions.filterNot { it.txId == txId }) swapTxList.copy(transactions = swapTxList.transactions.filterNot { swapTx -> swapTx.txId == txId })
}?.filterNot { it.transactions.isEmpty() } }?.filterNot { it.transactions.isEmpty() }
?.toList() ?.toList()
@ -257,8 +257,8 @@ internal class DefaultSwapTransactionRepository(
toAccount = toAccount, toAccount = toAccount,
tokenTransactions = transactions, tokenTransactions = transactions,
), ),
predicate = { predicate = { swapTxList ->
it.checkId( swapTxList.checkId(
checkUserWalletId = userWalletId, checkUserWalletId = userWalletId,
fromCurrencyId = fromCryptoCurrency.id, fromCurrencyId = fromCryptoCurrency.id,
toCurrencyId = toCryptoCurrency.id, toCurrencyId = toCryptoCurrency.id,

View file

@ -31,11 +31,11 @@ internal class SwapDataConverter : Converter<ExchangeDataResponseWithTxDetails,
) )
return if (transactionDto.txType == TxType.SWAP) { return if (transactionDto.txType == TxType.SWAP) {
val otherNativeFeeWei = transactionDto.otherNativeFee?.let { val otherNativeFeeWei = transactionDto.otherNativeFee?.let { otherFee ->
if (it == "0") { if (otherFee == "0") {
BigDecimal.ZERO BigDecimal.ZERO
} else { } else {
requireNotNull(it.toBigDecimalOrNull()) { "wrong amount format, use only digits" } requireNotNull(otherFee.toBigDecimalOrNull()) { "wrong amount format, use only digits" }
} }
} }
SwapDataTransactionModel.DEX( SwapDataTransactionModel.DEX(

View file

@ -1,7 +1,7 @@
========================================== ==========================================
Detekt Baseline Updater & Issue Counter Detekt Baseline Updater & Issue Counter
========================================== ==========================================
Date: 2025-12-08 12:25:24 Date: 2025-12-12 13:10:21
Step 1: Running detekt to check for new issues... Step 1: Running detekt to check for new issues...
@ -17,13 +17,13 @@ Counting issues in baseline files...
========================================== ==========================================
Summary: Summary:
Total Issues: 1311 Total Issues: 1247
Modules with Issues: 48 Modules with Issues: 46
Average Issues per Module: 27 Average Issues per Module: 27
Progress: Progress:
Fixed: 491 out of 1802 (27%) Fixed: 555 out of 1802 (30%)
Remaining: 1311 Remaining: 1247
========================================== ==========================================
All Modules with Issues (sorted by count) All Modules with Issues (sorted by count)
@ -31,21 +31,20 @@ All Modules with Issues (sorted by count)
Module Issues Module Issues
──────────────────────────────────────────────────────────────── ────────────────────────────────────────────────────────────────
features/markets/impl 148 features/markets/impl 147
features/wallet/impl 145 features/wallet/impl 144
features/onboarding-v2/impl 130 features/onboarding-v2/impl 128
features/swap/impl 67 features/swap/impl 67
data/wallet-connect 54 data/wallet-connect 54
features/hot-wallet/impl 51 features/hot-wallet/impl 51
features/walletconnect/impl 47 features/walletconnect/impl 47
features/tokendetails/impl 46
features/staking/impl 46 features/staking/impl 46
features/manage-tokens/impl 45 features/tokendetails/impl 45
features/swap-v2/impl 40 features/manage-tokens/impl 44
domain/wallets 37 domain/wallets 37
features/nft/impl 34 features/nft/impl 34
features/tester/impl 30 features/tester/impl 28
core/ui 27 core/ui 26
features/swap/domain 25 features/swap/domain 25
domain/tokens 25 domain/tokens 25
common/ui 24 common/ui 24
@ -55,20 +54,19 @@ data/visa 21
data/nft 19 data/nft 19
features/swap/data 15 features/swap/data 15
data/wallets 13 data/wallets 13
data/swap 13
features/token-recieve/impl 11 features/token-recieve/impl 11
features/qr-scanning/impl 11 features/qr-scanning/impl 11
data/onramp 11 data/onramp 11
core/datasource 11 core/datasource 11
data/markets 10 data/markets 10
features/details/impl 9 features/details/impl 9
domain/staking 9
domain/account/status 9 domain/account/status 9
data/yield-supply 9 data/yield-supply 9
data/networks 9 data/networks 9
features/referral/impl 8
domain/transaction 8 domain/transaction 8
domain/staking 8
libs/tangem-sdk-api 7 libs/tangem-sdk-api 7
features/referral/impl 7
data/txhistory 7 data/txhistory 7
features/welcome/impl 6 features/welcome/impl 6
libs/visa 5 libs/visa 5

View file

@ -2,7 +2,6 @@
<SmellBaseline> <SmellBaseline>
<ManuallySuppressedIssues/> <ManuallySuppressedIssues/>
<CurrentIssues> <CurrentIssues>
<ID>CanBeNonNullable:StakingAnalyticsEvent.kt$StakingAnalyticsEvent$value: Any?</ID>
<ID>MultilineLambdaItParameter:FetchStakingYieldBalanceUseCase.kt$FetchStakingYieldBalanceUseCase${ when (it) { is StakingIdFactory.Error.UnableToGetAddress -&gt; raise(StakingError.DomainError("$it")) StakingIdFactory.Error.UnsupportedCurrency -&gt; Unit.right() } return@either }</ID> <ID>MultilineLambdaItParameter:FetchStakingYieldBalanceUseCase.kt$FetchStakingYieldBalanceUseCase${ when (it) { is StakingIdFactory.Error.UnableToGetAddress -&gt; raise(StakingError.DomainError("$it")) StakingIdFactory.Error.UnsupportedCurrency -&gt; Unit.right() } return@either }</ID>
<ID>MultilineLambdaItParameter:InvalidatePendingTransactionsUseCase.kt$InvalidatePendingTransactionsUseCase${ !it.isPending &amp;&amp; action.amount &lt; it.amount &amp;&amp; it.type == BalanceType.STAKED &amp;&amp; it.validatorAddress == action.validatorAddress }</ID> <ID>MultilineLambdaItParameter:InvalidatePendingTransactionsUseCase.kt$InvalidatePendingTransactionsUseCase${ !it.isPending &amp;&amp; action.amount &lt; it.amount &amp;&amp; it.type == BalanceType.STAKED &amp;&amp; it.validatorAddress == action.validatorAddress }</ID>
<ID>NamedArguments:GetConstructedStakingTransactionUseCase.kt$GetConstructedStakingTransactionUseCase$constructTransaction(networkId, fee, amount, transactionId)</ID> <ID>NamedArguments:GetConstructedStakingTransactionUseCase.kt$GetConstructedStakingTransactionUseCase$constructTransaction(networkId, fee, amount, transactionId)</ID>

View file

@ -15,7 +15,6 @@
<ID>MultilineLambdaItParameter:ChooseManagedTokenContent.kt${ add( CurrencyItemUM.Basic( id = ManagedCryptoCurrency.ID( value = "ID+$it", ), name = "Bitcoin", symbol = "BTC", icon = CurrencyIconState.Loading, networks = CurrencyItemUM.Basic.NetworksUM.Collapsed, onExpandClick = {}, ), ) }</ID> <ID>MultilineLambdaItParameter:ChooseManagedTokenContent.kt${ add( CurrencyItemUM.Basic( id = ManagedCryptoCurrency.ID( value = "ID+$it", ), name = "Bitcoin", symbol = "BTC", icon = CurrencyIconState.Loading, networks = CurrencyItemUM.Basic.NetworksUM.Collapsed, onExpandClick = {}, ), ) }</ID>
<ID>MultilineLambdaItParameter:ChooseManagedTokensModel.kt$ChooseManagedTokensModel${ it.copy( notificationUM = null, ) }</ID> <ID>MultilineLambdaItParameter:ChooseManagedTokensModel.kt$ChooseManagedTokensModel${ it.copy( notificationUM = null, ) }</ID>
<ID>MultilineLambdaItParameter:CurrencyItemMapper.kt${ it.toCurrencyNetworkModel( isSelected = it.network in addedIn, isEditable = false, onSelectedStateChange = { _, _ -&gt; }, onLongTap = { _ -&gt; }, ) }</ID> <ID>MultilineLambdaItParameter:CurrencyItemMapper.kt${ it.toCurrencyNetworkModel( isSelected = it.network in addedIn, isEditable = false, onSelectedStateChange = { _, _ -&gt; }, onLongTap = { _ -&gt; }, ) }</ID>
<ID>MultilineLambdaItParameter:CurrencyNetworksMapper.kt${ it.toCurrencyNetworkModel( isSelected = it.network in addedIn, isEditable = isItemsEditable, onSelectedStateChange = onSelectedStateChange, onLongTap = onLongTap, ) }</ID>
<ID>MultilineLambdaItParameter:CustomCurrencyFormOperations.kt${ it[Field.CONTRACT_ADDRESS] = it.getValue(Field.CONTRACT_ADDRESS).copy( error = when (exception) { CustomTokenFormValidationException.ContractAddress.Invalid -&gt; { resourceReference(R.string.custom_token_creation_error_invalid_contract_address) } }, ) }</ID> <ID>MultilineLambdaItParameter:CustomCurrencyFormOperations.kt${ it[Field.CONTRACT_ADDRESS] = it.getValue(Field.CONTRACT_ADDRESS).copy( error = when (exception) { CustomTokenFormValidationException.ContractAddress.Invalid -&gt; { resourceReference(R.string.custom_token_creation_error_invalid_contract_address) } }, ) }</ID>
<ID>MultilineLambdaItParameter:CustomCurrencyFormOperations.kt${ it[Field.DECIMALS] = it.getValue(Field.DECIMALS).copy( error = when (exception) { is CustomTokenFormValidationException.Decimals.Empty -&gt; { null // Should not display this error } is CustomTokenFormValidationException.Decimals.Invalid -&gt; { resourceReference( R.string.custom_token_creation_error_wrong_decimals, wrappedList(ValidateTokenFormUseCase.MAX_DECIMALS), ) } }, ) }</ID> <ID>MultilineLambdaItParameter:CustomCurrencyFormOperations.kt${ it[Field.DECIMALS] = it.getValue(Field.DECIMALS).copy( error = when (exception) { is CustomTokenFormValidationException.Decimals.Empty -&gt; { null // Should not display this error } is CustomTokenFormValidationException.Decimals.Invalid -&gt; { resourceReference( R.string.custom_token_creation_error_wrong_decimals, wrappedList(ValidateTokenFormUseCase.MAX_DECIMALS), ) } }, ) }</ID>
<ID>MultilineLambdaItParameter:CustomTokenFormContent.kt$PreviewCustomTokenFormComponentProvider${ it[Field.CONTRACT_ADDRESS] = it[Field.CONTRACT_ADDRESS]!!.copy( label = stringReference("Contract address"), value = "0x1234567890", error = stringReference("Contract address is invalid"), placeholder = stringReference("0x1234567890"), ) }</ID> <ID>MultilineLambdaItParameter:CustomTokenFormContent.kt$PreviewCustomTokenFormComponentProvider${ it[Field.CONTRACT_ADDRESS] = it[Field.CONTRACT_ADDRESS]!!.copy( label = stringReference("Contract address"), value = "0x1234567890", error = stringReference("Contract address is invalid"), placeholder = stringReference("0x1234567890"), ) }</ID>

View file

@ -57,7 +57,6 @@
<ID>MultilineLambdaItParameter:MarketsListBatchFlowManager.kt$MarketsListBatchFlowManager${ when (val status = it.status) { is PaginationStatus.Paginating -&gt; { if (status.lastResult is BatchFetchResult.Success) { it.data.size == 1 } else { null } } is PaginationStatus.EndOfPagination -&gt; { it.data.size == 1 } else -&gt; null } }</ID> <ID>MultilineLambdaItParameter:MarketsListBatchFlowManager.kt$MarketsListBatchFlowManager${ when (val status = it.status) { is PaginationStatus.Paginating -&gt; { if (status.lastResult is BatchFetchResult.Success) { it.data.size == 1 } else { null } } is PaginationStatus.EndOfPagination -&gt; { it.data.size == 1 } else -&gt; null } }</ID>
<ID>MultilineLambdaItParameter:MarketsListItem.kt${ if (Random.nextBoolean()) { it.first.inc() to PriceChangeType.UP } else { it.first.dec() to PriceChangeType.DOWN } }</ID> <ID>MultilineLambdaItParameter:MarketsListItem.kt${ if (Random.nextBoolean()) { it.first.inc() to PriceChangeType.UP } else { it.first.dec() to PriceChangeType.DOWN } }</ID>
<ID>MultilineLambdaItParameter:MarketsListLazyColumn.kt${ (it.key as? String)?.split(TOKEN_LAZY_LIST_ID_SEPARATOR)?.first() ?.let { rawId -&gt; CryptoCurrency.RawID(rawId) } }</ID> <ID>MultilineLambdaItParameter:MarketsListLazyColumn.kt${ (it.key as? String)?.split(TOKEN_LAZY_LIST_ID_SEPARATOR)?.first() ?.let { rawId -&gt; CryptoCurrency.RawID(rawId) } }</ID>
<ID>MultilineLambdaItParameter:MarketsListModel.kt$MarketsListModel${ if (it == BottomSheetState.EXPANDED) { analyticsEventHandler.send(MarketsListAnalyticsEvent.BottomSheetOpened) } }</ID>
<ID>MultilineLambdaItParameter:MarketsListModel.kt$MarketsListModel${ if (it) { analyticsEventHandler.send(MarketsListAnalyticsEvent.TokenSearched(tokenFound = false)) } }</ID> <ID>MultilineLambdaItParameter:MarketsListModel.kt$MarketsListModel${ if (it) { analyticsEventHandler.send(MarketsListAnalyticsEvent.TokenSearched(tokenFound = false)) } }</ID>
<ID>MultilineLambdaItParameter:MarketsListModel.kt$MarketsListModel${ if (it.isNotEmpty()) { activeListManager.getBatchKeysByItemIds(visibleItemIds.value) } else { null } }</ID> <ID>MultilineLambdaItParameter:MarketsListModel.kt$MarketsListModel${ if (it.isNotEmpty()) { activeListManager.getBatchKeysByItemIds(visibleItemIds.value) } else { null } }</ID>
<ID>MultilineLambdaItParameter:MarketsListModel.kt$MarketsListModel${ if (it.list !is ListUM.Content) { visibleItemIds.value = emptyList() } }</ID> <ID>MultilineLambdaItParameter:MarketsListModel.kt$MarketsListModel${ if (it.list !is ListUM.Content) { visibleItemIds.value = emptyList() } }</ID>

View file

@ -98,7 +98,6 @@
<ID>MultilineLambdaItParameter:OnboardingVisaModel.kt$OnboardingVisaModel${ val derivedKey = it.derivedKeys[VisaUtilities.visaDefaultDerivationPath] ?: return@any false VisaWalletPublicKeyUtility.validateExtendedPublicKey( targetAddress = targetAddress, extendedPublicKey = derivedKey, ).onLeft { return@any VisaWalletPublicKeyUtility.findKeyWithoutDerivation( targetAddress = targetAddress, card = wallet.scanResponse.card, ).isRight() }.isRight() }</ID> <ID>MultilineLambdaItParameter:OnboardingVisaModel.kt$OnboardingVisaModel${ val derivedKey = it.derivedKeys[VisaUtilities.visaDefaultDerivationPath] ?: return@any false VisaWalletPublicKeyUtility.validateExtendedPublicKey( targetAddress = targetAddress, extendedPublicKey = derivedKey, ).onLeft { return@any VisaWalletPublicKeyUtility.findKeyWithoutDerivation( targetAddress = targetAddress, card = wallet.scanResponse.card, ).isRight() }.isRight() }</ID>
<ID>MultilineLambdaItParameter:OnboardingVisaOtherWalletModel.kt$OnboardingVisaOtherWalletModel${ if (it is VisaActivationRemoteState.AwaitingPinCode) { onDone.emit(it.activationOrderInfo) return@launch } }</ID> <ID>MultilineLambdaItParameter:OnboardingVisaOtherWalletModel.kt$OnboardingVisaOtherWalletModel${ if (it is VisaActivationRemoteState.AwaitingPinCode) { onDone.emit(it.activationOrderInfo) return@launch } }</ID>
<ID>MultilineLambdaItParameter:OnboardingVisaOtherWalletModel.kt$OnboardingVisaOtherWalletModel${ uiMessageSender.showErrorDialog(it) analyticsEventHandler.send(VisaAnalyticsEvent.ErrorOnboarding(it)) delay(timeMillis = 60_000) }</ID> <ID>MultilineLambdaItParameter:OnboardingVisaOtherWalletModel.kt$OnboardingVisaOtherWalletModel${ uiMessageSender.showErrorDialog(it) analyticsEventHandler.send(VisaAnalyticsEvent.ErrorOnboarding(it)) delay(timeMillis = 60_000) }</ID>
<ID>MultilineLambdaItParameter:OnboardingVisaPinCodeModel.kt$OnboardingVisaPinCodeModel${ it.copy( pinCode = pin, submitButtonEnabled = PinCodeValidation.validate(pin), error = if (isError) { analyticsEventHandler.send(OnboardingVisaAnalyticsEvent.ErrorPinValidation) resourceReference(R.string.visa_onboarding_pin_validation_error_message) } else { null }, ) }</ID>
<ID>MultilineLambdaItParameter:OnboardingVisaWelcomeModel.kt$OnboardingVisaWelcomeModel${ onError(it) return@launch }</ID> <ID>MultilineLambdaItParameter:OnboardingVisaWelcomeModel.kt$OnboardingVisaWelcomeModel${ onError(it) return@launch }</ID>
<ID>MultilineLambdaItParameter:SeedPhraseCheckUiStateBuilder.kt$SeedPhraseCheckUiStateBuilder${ checkWordField( word = it.word.text, shownIndex = it.index, ) }</ID> <ID>MultilineLambdaItParameter:SeedPhraseCheckUiStateBuilder.kt$SeedPhraseCheckUiStateBuilder${ checkWordField( word = it.word.text, shownIndex = it.index, ) }</ID>
<ID>MultilineLambdaItParameter:TwinWalletArtwork.kt${ animationState = it val maxTime = maxOf( transition1.totalDurationNanos, transition2.totalDurationNanos, ) delay(TimeUnit.NANOSECONDS.toMillis(maxTime)) }</ID> <ID>MultilineLambdaItParameter:TwinWalletArtwork.kt${ animationState = it val maxTime = maxOf( transition1.totalDurationNanos, transition2.totalDurationNanos, ) delay(TimeUnit.NANOSECONDS.toMillis(maxTime)) }</ID>
@ -126,7 +125,6 @@
<ID>UseEmptyCounterpart:OnboardingEvent.kt$OnboardingEvent$mapOf()</ID> <ID>UseEmptyCounterpart:OnboardingEvent.kt$OnboardingEvent$mapOf()</ID>
<ID>UseEmptyCounterpart:OnboardingEvent.kt$OnboardingEvent.Backup$mapOf()</ID> <ID>UseEmptyCounterpart:OnboardingEvent.kt$OnboardingEvent.Backup$mapOf()</ID>
<ID>UseEmptyCounterpart:OnboardingEvent.kt$OnboardingEvent.CreateWallet$mapOf()</ID> <ID>UseEmptyCounterpart:OnboardingEvent.kt$OnboardingEvent.CreateWallet$mapOf()</ID>
<ID>UseEmptyCounterpart:OnboardingEvent.kt$OnboardingEvent.Topup$mapOf()</ID>
<ID>UseEmptyCounterpart:OnboardingEvent.kt$OnboardingEvent.Twins$mapOf()</ID> <ID>UseEmptyCounterpart:OnboardingEvent.kt$OnboardingEvent.Twins$mapOf()</ID>
<ID>UseEmptyCounterpart:OnboardingVisaAnalyticsEvent.kt$OnboardingVisaAnalyticsEvent$mapOf()</ID> <ID>UseEmptyCounterpart:OnboardingVisaAnalyticsEvent.kt$OnboardingVisaAnalyticsEvent$mapOf()</ID>
<ID>UseEmptyCounterpart:VisaAnalyticsEvent.kt$VisaAnalyticsEvent$mapOf()</ID> <ID>UseEmptyCounterpart:VisaAnalyticsEvent.kt$VisaAnalyticsEvent$mapOf()</ID>

View file

@ -3,7 +3,6 @@
<ManuallySuppressedIssues/> <ManuallySuppressedIssues/>
<CurrentIssues> <CurrentIssues>
<ID>MultilineLambdaItParameter:AgreementText.kt${ val clickableSpanStyle = requireNotNull(agreementText.spanStyles.getOrNull(1)) if (it in clickableSpanStyle.start..clickableSpanStyle.end) { onClick() } }</ID> <ID>MultilineLambdaItParameter:AgreementText.kt${ val clickableSpanStyle = requireNotNull(agreementText.spanStyles.getOrNull(1)) if (it in clickableSpanStyle.start..clickableSpanStyle.end) { onClick() } }</ID>
<ID>MultilineLambdaItParameter:ReferralModel.kt$ReferralModel${ analyticsEventHandler.send(ReferralEvents.ParticipateSuccessful) referralData.value = it }</ID>
<ID>MultilineLambdaItParameter:ReferralScreen.kt${ // TODO: use StateEvent if (stateHolder.errorSnackbar != null) { TangemSnackbar(data = it, actionOnNewLine = true) } else { CopiedTextSnackbar(it) } }</ID> <ID>MultilineLambdaItParameter:ReferralScreen.kt${ // TODO: use StateEvent if (stateHolder.errorSnackbar != null) { TangemSnackbar(data = it, actionOnNewLine = true) } else { CopiedTextSnackbar(it) } }</ID>
<ID>MultilineLambdaItParameter:ReferralScreen.kt${ ReferralContent( stateHolder = stateHolder, snackbarHostState = snackbarHostState, onAgreementClick = stateHolder.analytics.onAgreementClicked, modifier = Modifier.padding(it), ) }</ID> <ID>MultilineLambdaItParameter:ReferralScreen.kt${ ReferralContent( stateHolder = stateHolder, snackbarHostState = snackbarHostState, onAgreementClick = stateHolder.analytics.onAgreementClicked, modifier = Modifier.padding(it), ) }</ID>
<ID>NamedArguments:ReferralScreen.kt$Text( formatAwardConditionsString( quantity = award, network = networkName, address = if (!address.isNullOrBlank()) " $address" else "", ), color = TangemTheme.colors.text.tertiary, style = TangemTheme.typography.body2, modifier = Modifier.testTag(ReferralProgramScreenTestTags.INFO_FOR_YOU_TEXT), )</ID> <ID>NamedArguments:ReferralScreen.kt$Text( formatAwardConditionsString( quantity = award, network = networkName, address = if (!address.isNullOrBlank()) " $address" else "", ), color = TangemTheme.colors.text.tertiary, style = TangemTheme.typography.body2, modifier = Modifier.testTag(ReferralProgramScreenTestTags.INFO_FOR_YOU_TEXT), )</ID>

View file

@ -1,46 +0,0 @@
<?xml version="1.0" ?>
<SmellBaseline>
<ManuallySuppressedIssues/>
<CurrentIssues>
<ID>BooleanPropertyNaming:ConfirmUM.kt$ConfirmUM.Content$val showTapHelp: Boolean</ID>
<ID>BooleanPropertyNaming:SwapAmountModel.kt$SwapAmountModel$private var showBestRateAnimation: Boolean = false</ID>
<ID>BooleanPropertyNaming:SwapAmountModel.kt$SwapAmountModel$val showSendViaSwapNotification = shouldShowNotificationUseCase( NotificationId.SendViaSwapTokenSelectorNotification.key, )</ID>
<ID>BooleanPropertyNaming:SwapAmountPrimaryReadyStateTransformer.kt$SwapAmountPrimaryReadyStateTransformer$private val showBestRateAnimation: Boolean</ID>
<ID>BooleanPropertyNaming:SwapAmountSecondaryReadyStateTransformer.kt$SwapAmountSecondaryReadyStateTransformer$private val showBestRateAnimation: Boolean</ID>
<ID>BooleanPropertyNaming:SwapAmountSelectQuoteTransformer.kt$SwapAmountSelectQuoteTransformer$private val needApplyFCARestrictions: Boolean</ID>
<ID>BooleanPropertyNaming:SwapAmountSetQuotesTransformer.kt$SwapAmountSetQuotesTransformer$private val needApplyFcaRestrictions: Boolean</ID>
<ID>BooleanPropertyNaming:SwapAmountUM.kt$SwapAmountUM.Content$val showBestRateAnimation: Boolean</ID>
<ID>BooleanPropertyNaming:SwapAmountUM.kt$SwapAmountUM.Content$val showFCAWarning: Boolean</ID>
<ID>BooleanPropertyNaming:SwapChooseProviderModel.kt$SwapChooseProviderModel$private val needApplyFCARestrictions = params.userCountry.needApplyFCARestrictions()</ID>
<ID>BooleanPropertyNaming:SwapProviderListItemConverter.kt$SwapProviderListItemConverter$private val needApplyFCARestrictions: Boolean</ID>
<ID>BooleanPropertyNaming:SwapProviderStateConverter.kt$SwapProviderStateConverter$private val needApplyFCARestrictions: Boolean</ID>
<ID>CouldBeSequence:SwapAmountModel.kt$SwapAmountModel$filter { it.currencyStatus.currency.id == toCryptoCurrency.id }</ID>
<ID>MaxChainedCallsOnSameLine:SwapAlertFactory.kt$SwapAlertFactory$confirmData?.fee?.amount?.value?.toString().orEmpty()</ID>
<ID>MultilineLambdaItParameter:SendWithSwapConfirmModel.kt$SendWithSwapConfirmModel${ it.copy( confirmUM = SendWithSwapConfirmInitialStateTransformer( isShowTapHelp = isShowTapHelp, ).transform(uiState.value.confirmUM), ) }</ID>
<ID>MultilineLambdaItParameter:SendWithSwapConfirmModel.kt$SendWithSwapConfirmModel${ val confirmUM = it.confirmUM as? ConfirmUM.Content it.copy(confirmUM = confirmUM?.copy(showTapHelp = showTapHelp) ?: it.confirmUM) }</ID>
<ID>MultilineLambdaItParameter:SendWithSwapConfirmModel.kt$SendWithSwapConfirmModel${ val feeUM = it.feeSelectorUM as? FeeSelectorUM.Content it.copy( confirmUM = (it.confirmUM as? ConfirmUM.Content)?.copy( isPrimaryButtonEnabled = !hasError &amp;&amp; feeUM != null, ) ?: it.confirmUM, ) }</ID>
<ID>MultilineLambdaItParameter:SendWithSwapConfirmationNotificationsTransformer.kt$SendWithSwapConfirmationNotificationsTransformer${ ConfirmUM.Content.LegalUM( title = resourceReference(R.string.common_privacy_policy), link = it, ) }</ID>
<ID>MultilineLambdaItParameter:SendWithSwapConfirmationNotificationsTransformer.kt$SendWithSwapConfirmationNotificationsTransformer${ ConfirmUM.Content.LegalUM( title = resourceReference(R.string.common_terms_of_use), link = it, ) }</ID>
<ID>MultilineLambdaItParameter:SendWithSwapModel.kt$SendWithSwapModel${ Timber.w(it.toString()) swapAlertFactory.getGenericErrorState( expressError = ExpressError.UnknownError, onFailedTxEmailClick = { modelScope.launch { swapAlertFactory.onFailedTxEmailClick( userWallet = userWallet, cryptoCurrency = params.currency, errorMessage = it.toString(), ) } }, popBack = ::onBackClick, ) }</ID>
<ID>MultilineLambdaItParameter:SendWithSwapModel.kt$SendWithSwapModel${ it.copy( destinationUM = DestinationUM.Empty(), feeSelectorUM = FeeSelectorUM.Loading, confirmUM = ConfirmUM.Empty, navigationUM = NavigationUM.Empty, ) }</ID>
<ID>MultilineLambdaItParameter:SwapAmountSetQuotesTransformer.kt$SwapAmountSetQuotesTransformer${ it is SwapQuoteUM.Content || it is SwapQuoteUM.Allowance || (it as? SwapQuoteUM.Error)?.expressError is ExpressError.AmountError }</ID>
<ID>MultilineLambdaItParameter:SwapChooseProviderModel.kt$SwapChooseProviderModel${ it is SwapQuoteUM.Content || it is SwapQuoteUM.Allowance || (it as? SwapQuoteUM.Error)?.expressError is ExpressError.AmountError }</ID>
<ID>MultilineLambdaItParameter:SwapChooseTokenNetworkModel.kt$SwapChooseTokenNetworkModel${ Timber.e("Failed to get user wallet: $it") swapChooseTokenAlertFactory.getGenericErrorState(params.onDismiss) return }</ID>
<ID>MultilineLambdaItParameter:SwapChooseTokenNetworkModel.kt$SwapChooseTokenNetworkModel${ Timber.e(it.toString()) uiState.update( SwapChooseErrorStateTransformer( tokenName = params.token.name, onDismiss = params.onDismiss, ), ) return@launch }</ID>
<ID>MultilineLambdaItParameter:SwapTransactionSender.kt$SwapTransactionSender${ Timber.e(it, "Failed to create swap CEX tx data") onSendError(SendTransactionError.UnknownError(Exception(it))) return }</ID>
<ID>MultilineLambdaItParameter:SwapTransactionSender.kt$SwapTransactionSender${ onExpressError(it); return }</ID>
<ID>NamedArguments:SwapTransactionSender.kt$SwapTransactionSender$getSwapDataUseCase( userWallet = userWallet, fromCryptoCurrencyStatus = fromStatus, fromAmount = fromAmount.toStringWithRightOffset(fromStatus.currency.decimals), toCryptoCurrency = toStatus.currency, toAddress = destination, expressProvider = provider, rateType = rateType, expressOperationType, )</ID>
<ID>NoNameShadowing:SendWithSwapContent.kt$navigationUM</ID>
<ID>NoNameShadowing:SwapAmountContent.kt$amountFieldUM</ID>
<ID>NullableToStringCall:SendWithSwapConfirmModel.kt$SendWithSwapConfirmModel$error.toString()</ID>
<ID>NullableToStringCall:SwapAmountModel.kt$SwapAmountModel$$primaryStatus</ID>
<ID>NullableToStringCall:SwapAmountModel.kt$SwapAmountModel$$secondaryStatus</ID>
<ID>PropertyUsedBeforeDeclaration:SendWithSwapConfirmModel.kt$SendWithSwapConfirmModel$amountUM</ID>
<ID>UnnecessaryEventHandlerParameter:SwapAmountContent.kt$onExpandEditField: (SwapAmountType) -&gt; Unit</ID>
<ID>UseEmptyCounterpart:SendWithSwapAnalyticEvents.kt$SendWithSwapAnalyticEvents$mapOf()</ID>
<ID>UseEmptyCounterpart:SendWithSwapSuccessContent.kt$listOf()</ID>
<ID>UseEmptyCounterpart:SwapAmountAnalyticEvents.kt$SwapAmountAnalyticEvents$mapOf()</ID>
<ID>VarCouldBeVal:SwapAmountModel.kt$SwapAmountModel$private var primaryCryptoCurrency: CryptoCurrency = params.primaryCryptoCurrencyStatusFlow.value.currency</ID>
<ID>VarCouldBeVal:SwapAmountModel.kt$SwapAmountModel$private var userWallet = params.userWallet</ID>
</CurrentIssues>
</SmellBaseline>

View file

@ -6,7 +6,7 @@ import com.tangem.core.analytics.models.AnalyticsParam.Key.PROVIDER
internal sealed class SwapAmountAnalyticEvents( internal sealed class SwapAmountAnalyticEvents(
category: String, category: String,
event: String, event: String,
params: Map<String, String> = mapOf(), params: Map<String, String> = emptyMap(),
) : AnalyticsEvent(category = category, event = event, params = params) { ) : AnalyticsEvent(category = category, event = event, params = params) {
data class ProviderSelectorClicked( data class ProviderSelectorClicked(

View file

@ -48,11 +48,11 @@ internal sealed class SwapAmountUM {
val swapCurrencies: SwapCurrencies, val swapCurrencies: SwapCurrencies,
val swapQuotes: ImmutableList<SwapQuoteUM>, val swapQuotes: ImmutableList<SwapQuoteUM>,
val selectedQuote: SwapQuoteUM, val selectedQuote: SwapQuoteUM,
val showFCAWarning: Boolean, val isShowFCAWarning: Boolean,
// extra data // extra data
val appCurrency: AppCurrency?, val appCurrency: AppCurrency?,
val showBestRateAnimation: Boolean, val isShowBestRateAnimation: Boolean,
) : SwapAmountUM() ) : SwapAmountUM()
} }

View file

@ -26,11 +26,8 @@ import com.tangem.domain.notifications.ShouldShowNotificationUseCase
import com.tangem.domain.settings.usercountry.GetUserCountryUseCase import com.tangem.domain.settings.usercountry.GetUserCountryUseCase
import com.tangem.domain.settings.usercountry.models.UserCountry import com.tangem.domain.settings.usercountry.models.UserCountry
import com.tangem.domain.settings.usercountry.models.needApplyFCARestrictions import com.tangem.domain.settings.usercountry.models.needApplyFCARestrictions
import com.tangem.domain.swap.models.SwapCurrencies import com.tangem.domain.swap.models.*
import com.tangem.domain.swap.models.SwapDirection
import com.tangem.domain.swap.models.SwapDirection.Companion.withSwapDirection import com.tangem.domain.swap.models.SwapDirection.Companion.withSwapDirection
import com.tangem.domain.swap.models.SwapQuoteModel
import com.tangem.domain.swap.models.getGroupWithDirection
import com.tangem.domain.swap.usecase.GetSwapQuoteUseCase import com.tangem.domain.swap.usecase.GetSwapQuoteUseCase
import com.tangem.domain.swap.usecase.SelectInitialPairUseCase import com.tangem.domain.swap.usecase.SelectInitialPairUseCase
import com.tangem.domain.tokens.GetMinimumTransactionAmountSyncUseCase import com.tangem.domain.tokens.GetMinimumTransactionAmountSyncUseCase
@ -99,9 +96,9 @@ internal class SwapAmountModel @Inject constructor(
private val params: SwapAmountComponentParams = paramsContainer.require() private val params: SwapAmountComponentParams = paramsContainer.require()
private val swapDirection = params.swapDirection private val swapDirection = params.swapDirection
private var appCurrency = AppCurrency.Default private var appCurrency = AppCurrency.Default
private var userWallet = params.userWallet private val userWallet = params.userWallet
private var primaryCryptoCurrency: CryptoCurrency = params.primaryCryptoCurrencyStatusFlow.value.currency private val primaryCryptoCurrency: CryptoCurrency = params.primaryCryptoCurrencyStatusFlow.value.currency
private var primaryMaximumAmountBoundary: EnterAmountBoundary by Delegates.notNull() private var primaryMaximumAmountBoundary: EnterAmountBoundary by Delegates.notNull()
private var primaryMinimumAmountBoundary: EnterAmountBoundary by Delegates.notNull() private var primaryMinimumAmountBoundary: EnterAmountBoundary by Delegates.notNull()
@ -111,7 +108,7 @@ internal class SwapAmountModel @Inject constructor(
private var userCountry: UserCountry = UserCountry.Other(Locale.getDefault().country) private var userCountry: UserCountry = UserCountry.Other(Locale.getDefault().country)
val bottomSheetNavigation: SlotNavigation<SwapChooseProviderConfig> = SlotNavigation() val bottomSheetNavigation: SlotNavigation<SwapChooseProviderConfig> = SlotNavigation()
private var showBestRateAnimation: Boolean = false private var isShowBestRateAnimation: Boolean = false
val uiState: StateFlow<SwapAmountUM> val uiState: StateFlow<SwapAmountUM>
field = MutableStateFlow(params.amountUM) field = MutableStateFlow(params.amountUM)
@ -124,7 +121,7 @@ internal class SwapAmountModel @Inject constructor(
appCurrency = getSelectedAppCurrencyUseCase.invokeSync().getOrElse { AppCurrency.Default } appCurrency = getSelectedAppCurrencyUseCase.invokeSync().getOrElse { AppCurrency.Default }
userCountry = getUserCountryUseCase.invokeSync().getOrNull() userCountry = getUserCountryUseCase.invokeSync().getOrNull()
?: UserCountry.Other(Locale.getDefault().country) ?: UserCountry.Other(Locale.getDefault().country)
showBestRateAnimation = swapBestRateAnimationStore.getSyncOrNull() isShowBestRateAnimation = swapBestRateAnimationStore.getSyncOrNull()
} }
configAmountNavigation() configAmountNavigation()
subscribeOnCryptoCurrencyStatusFlow() subscribeOnCryptoCurrencyStatusFlow()
@ -169,7 +166,7 @@ internal class SwapAmountModel @Inject constructor(
quoteUM = quoteUM, quoteUM = quoteUM,
secondaryMaximumAmountBoundary = secondaryMaximumAmountBoundary, secondaryMaximumAmountBoundary = secondaryMaximumAmountBoundary,
secondaryMinimumAmountBoundary = secondaryMinimumAmountBoundary, secondaryMinimumAmountBoundary = secondaryMinimumAmountBoundary,
needApplyFCARestrictions = userCountry.needApplyFCARestrictions(), isNeedApplyFCARestrictions = userCountry.needApplyFCARestrictions(),
), ),
) )
} }
@ -270,7 +267,7 @@ internal class SwapAmountModel @Inject constructor(
override fun onSelectTokenClick() { override fun onSelectTokenClick() {
val amountParams = params as? SwapAmountComponentParams.AmountParams ?: return val amountParams = params as? SwapAmountComponentParams.AmountParams ?: return
modelScope.launch { modelScope.launch {
val showSendViaSwapNotification = shouldShowNotificationUseCase( val isShowSendViaSwapNotification = shouldShowNotificationUseCase(
NotificationId.SendViaSwapTokenSelectorNotification.key, NotificationId.SendViaSwapTokenSelectorNotification.key,
) )
val isEditMode = amountParams.currentRoute.firstOrNull()?.isEditMode == true val isEditMode = amountParams.currentRoute.firstOrNull()?.isEditMode == true
@ -281,7 +278,7 @@ internal class SwapAmountModel @Inject constructor(
initialCurrency = primaryCryptoCurrency, initialCurrency = primaryCryptoCurrency,
selectedCurrency = selectedCurrency.takeIf { isEditMode }, selectedCurrency = selectedCurrency.takeIf { isEditMode },
source = AppRoute.ChooseManagedTokens.Source.SendViaSwap, source = AppRoute.ChooseManagedTokens.Source.SendViaSwap,
shouldShowSendViaSwapNotification = showSendViaSwapNotification, shouldShowSendViaSwapNotification = isShowSendViaSwapNotification,
analyticsCategoryName = params.analyticsCategoryName, analyticsCategoryName = params.analyticsCategoryName,
), ),
) )
@ -306,7 +303,7 @@ internal class SwapAmountModel @Inject constructor(
fun onFinishAnimation() { fun onFinishAnimation() {
uiState.update { uiState.update {
(it as? SwapAmountUM.Content)?.copy(showBestRateAnimation = false) ?: it (it as? SwapAmountUM.Content)?.copy(isShowBestRateAnimation = false) ?: it
} }
} }
@ -367,7 +364,7 @@ internal class SwapAmountModel @Inject constructor(
swapDirection = swapDirection, swapDirection = swapDirection,
clickIntents = this, clickIntents = this,
isBalanceHidden = params.isBalanceHidingFlow.value, isBalanceHidden = params.isBalanceHidingFlow.value,
showBestRateAnimation = showBestRateAnimation, isShowBestRateAnimation = isShowBestRateAnimation,
isSingleWallet = isOnlyOneWallet, isSingleWallet = isOnlyOneWallet,
isAccountsMode = params.isAccountModeFlow.value, isAccountsMode = params.isAccountModeFlow.value,
account = params.accountFlow.value, account = params.accountFlow.value,
@ -418,7 +415,7 @@ internal class SwapAmountModel @Inject constructor(
swapDirection = swapDirection, swapDirection = swapDirection,
clickIntents = this, clickIntents = this,
isBalanceHidden = params.isBalanceHidingFlow.value, isBalanceHidden = params.isBalanceHidingFlow.value,
showBestRateAnimation = showBestRateAnimation, isShowBestRateAnimation = isShowBestRateAnimation,
isSingleWallet = isOnlyOneWallet, isSingleWallet = isOnlyOneWallet,
isAccountsMode = isAccountsMode, isAccountsMode = isAccountsMode,
account = account, account = account,
@ -532,7 +529,7 @@ internal class SwapAmountModel @Inject constructor(
swapDirection = swapDirection, swapDirection = swapDirection,
clickIntents = this@SwapAmountModel, clickIntents = this@SwapAmountModel,
isBalanceHidden = params.isBalanceHidingFlow.value, isBalanceHidden = params.isBalanceHidingFlow.value,
showBestRateAnimation = showBestRateAnimation, isShowBestRateAnimation = isShowBestRateAnimation,
isSingleWallet = isOnlyOneWallet, isSingleWallet = isOnlyOneWallet,
isAccountsMode = params.isAccountModeFlow.value, isAccountsMode = params.isAccountModeFlow.value,
account = params.accountFlow.value, account = params.accountFlow.value,
@ -540,6 +537,7 @@ internal class SwapAmountModel @Inject constructor(
) )
startLoadingQuotesTask(isSilentReload = false) startLoadingQuotesTask(isSilentReload = false)
} else { } else {
@Suppress("NullableToStringCall")
Timber.e( Timber.e(
""" """
Invalid cryptocurrencies status: Invalid cryptocurrencies status:
@ -596,18 +594,18 @@ internal class SwapAmountModel @Inject constructor(
val isAmountScreen = params is SwapAmountComponentParams.AmountParams val isAmountScreen = params is SwapAmountComponentParams.AmountParams
val isAmountError = fromAmount?.amountTextField?.isError == true || fromAmountValue.isNullOrZero() val isAmountError = fromAmount?.amountTextField?.isError == true || fromAmountValue.isNullOrZero()
if (isAmountScreen && isAmountError) { if (isAmountScreen && isAmountError) {
uiState.transformerUpdate(SwapQuoteEmptyStateTransformer) uiState.transformerUpdate(SwapQuoteEmptyStateTransformer); return
return
} }
if (!isSilentReload) uiState.transformerUpdate(SwapQuoteLoadingStateTransformer) if (!isSilentReload) uiState.transformerUpdate(SwapQuoteLoadingStateTransformer)
modelScope.launch { modelScope.launch {
val quotes = state.swapCurrencies.getGroupWithDirection(state.swapDirection).available.filter { val quotes = state.swapCurrencies.getGroupWithDirection(state.swapDirection).available
it.currencyStatus.currency.id == toCryptoCurrency.id .asSequence()
}.flatMap { .filter { swapCurrencyStatus -> swapCurrencyStatus.currencyStatus.currency.id == toCryptoCurrency.id }
it.providers .flatMap(SwapCryptoCurrency::providers)
}.map { provider -> .toList()
.map { provider ->
async { async {
getSwapQuoteUseCase( getSwapQuoteUseCase(
userWallet = userWallet, userWallet = userWallet,
@ -647,7 +645,7 @@ internal class SwapAmountModel @Inject constructor(
secondaryMaximumAmountBoundary = secondaryMaximumAmountBoundary, secondaryMaximumAmountBoundary = secondaryMaximumAmountBoundary,
secondaryMinimumAmountBoundary = secondaryMinimumAmountBoundary, secondaryMinimumAmountBoundary = secondaryMinimumAmountBoundary,
isSilentReload = isSilentReload, isSilentReload = isSilentReload,
needApplyFcaRestrictions = userCountry.needApplyFCARestrictions(), isNeedApplyFcaRestrictions = userCountry.needApplyFCARestrictions(),
), ),
) )
feeSelectorReloadTrigger.triggerUpdate() feeSelectorReloadTrigger.triggerUpdate()

View file

@ -24,7 +24,7 @@ internal class SwapAmountPrimaryReadyStateTransformer(
private val clickIntents: AmountScreenClickIntents, private val clickIntents: AmountScreenClickIntents,
private val swapDirection: SwapDirection, private val swapDirection: SwapDirection,
private val isBalanceHidden: Boolean, private val isBalanceHidden: Boolean,
private val showBestRateAnimation: Boolean, private val isShowBestRateAnimation: Boolean,
private val isSingleWallet: Boolean, private val isSingleWallet: Boolean,
private val isAccountsMode: Boolean, private val isAccountsMode: Boolean,
private val account: Account.CryptoPortfolio?, private val account: Account.CryptoPortfolio?,
@ -60,8 +60,8 @@ internal class SwapAmountPrimaryReadyStateTransformer(
swapQuotes = persistentListOf(), swapQuotes = persistentListOf(),
selectedQuote = SwapQuoteUM.Empty, selectedQuote = SwapQuoteUM.Empty,
appCurrency = appCurrency, appCurrency = appCurrency,
showBestRateAnimation = showBestRateAnimation, isShowBestRateAnimation = isShowBestRateAnimation,
showFCAWarning = false, isShowFCAWarning = false,
) )
} }
} }

View file

@ -25,7 +25,7 @@ internal class SwapAmountSecondaryReadyStateTransformer(
private val clickIntents: AmountScreenClickIntents, private val clickIntents: AmountScreenClickIntents,
private val swapDirection: SwapDirection, private val swapDirection: SwapDirection,
private val isBalanceHidden: Boolean, private val isBalanceHidden: Boolean,
private val showBestRateAnimation: Boolean, private val isShowBestRateAnimation: Boolean,
private val isSingleWallet: Boolean, private val isSingleWallet: Boolean,
private val isAccountsMode: Boolean, private val isAccountsMode: Boolean,
private val account: Account.CryptoPortfolio?, private val account: Account.CryptoPortfolio?,
@ -59,8 +59,8 @@ internal class SwapAmountSecondaryReadyStateTransformer(
swapQuotes = persistentListOf(), swapQuotes = persistentListOf(),
selectedQuote = SwapQuoteUM.Empty, selectedQuote = SwapQuoteUM.Empty,
appCurrency = appCurrency, appCurrency = appCurrency,
showBestRateAnimation = showBestRateAnimation, isShowBestRateAnimation = isShowBestRateAnimation,
showFCAWarning = false, isShowFCAWarning = false,
) )
} }
} }

View file

@ -19,7 +19,7 @@ internal class SwapAmountSelectQuoteTransformer(
private val quoteUM: SwapQuoteUM, private val quoteUM: SwapQuoteUM,
private val secondaryMaximumAmountBoundary: EnterAmountBoundary?, private val secondaryMaximumAmountBoundary: EnterAmountBoundary?,
private val secondaryMinimumAmountBoundary: EnterAmountBoundary?, private val secondaryMinimumAmountBoundary: EnterAmountBoundary?,
private val needApplyFCARestrictions: Boolean, private val isNeedApplyFCARestrictions: Boolean,
) : Transformer<SwapAmountUM> { ) : Transformer<SwapAmountUM> {
override fun transform(prevState: SwapAmountUM): SwapAmountUM { override fun transform(prevState: SwapAmountUM): SwapAmountUM {
if (prevState !is SwapAmountUM.Content) return prevState if (prevState !is SwapAmountUM.Content) return prevState
@ -31,7 +31,7 @@ internal class SwapAmountSelectQuoteTransformer(
return prevState.copy( return prevState.copy(
isPrimaryButtonEnabled = quoteUM is SwapQuoteUM.Content, isPrimaryButtonEnabled = quoteUM is SwapQuoteUM.Content,
selectedQuote = quoteUM, selectedQuote = quoteUM,
showFCAWarning = needApplyFCARestrictions && quoteUM.provider?.isRestrictedByFCA() == true, isShowFCAWarning = isNeedApplyFCARestrictions && quoteUM.provider?.isRestrictedByFCA() == true,
primaryAmount = if (prevState.selectedAmountType == SwapAmountType.From) { primaryAmount = if (prevState.selectedAmountType == SwapAmountType.From) {
val swapAmountField = prevState.primaryAmount as? SwapAmountFieldUM.Content val swapAmountField = prevState.primaryAmount as? SwapAmountFieldUM.Content
val amountField = swapAmountField?.amountField as? AmountState.Data val amountField = swapAmountField?.amountField as? AmountState.Data

View file

@ -22,14 +22,14 @@ internal class SwapAmountSetQuotesTransformer(
private val secondaryMaximumAmountBoundary: EnterAmountBoundary?, private val secondaryMaximumAmountBoundary: EnterAmountBoundary?,
private val secondaryMinimumAmountBoundary: EnterAmountBoundary?, private val secondaryMinimumAmountBoundary: EnterAmountBoundary?,
private val isSilentReload: Boolean, private val isSilentReload: Boolean,
private val needApplyFcaRestrictions: Boolean, private val isNeedApplyFcaRestrictions: Boolean,
) : Transformer<SwapAmountUM> { ) : Transformer<SwapAmountUM> {
override fun transform(prevState: SwapAmountUM): SwapAmountUM { override fun transform(prevState: SwapAmountUM): SwapAmountUM {
if (prevState !is SwapAmountUM.Content) return prevState if (prevState !is SwapAmountUM.Content) return prevState
val isSingleProvider = quotes.filter { val isSingleProvider = quotes.filter { swapQuoteUM ->
it is SwapQuoteUM.Content || it is SwapQuoteUM.Allowance || swapQuoteUM is SwapQuoteUM.Content || swapQuoteUM is SwapQuoteUM.Allowance ||
(it as? SwapQuoteUM.Error)?.expressError is ExpressError.AmountError (swapQuoteUM as? SwapQuoteUM.Error)?.expressError is ExpressError.AmountError
}.isSingleItem() }.isSingleItem()
val sortedQuotes = quotes.sortedWith(SwapQuotesComparator) val sortedQuotes = quotes.sortedWith(SwapQuotesComparator)
@ -49,7 +49,7 @@ internal class SwapAmountSetQuotesTransformer(
quoteUM = selectedQuote, quoteUM = selectedQuote,
secondaryMaximumAmountBoundary = secondaryMaximumAmountBoundary, secondaryMaximumAmountBoundary = secondaryMaximumAmountBoundary,
secondaryMinimumAmountBoundary = secondaryMinimumAmountBoundary, secondaryMinimumAmountBoundary = secondaryMinimumAmountBoundary,
needApplyFCARestrictions = needApplyFcaRestrictions && isNeedApplyFCARestrictions = isNeedApplyFcaRestrictions &&
selectedQuote.provider?.isRestrictedByFCA() == true, selectedQuote.provider?.isRestrictedByFCA() == true,
) )

View file

@ -88,7 +88,7 @@ internal fun SwapAmountBlockContent(
SwapChooseProviderContent( SwapChooseProviderContent(
isBestRate = isBestRate, isBestRate = isBestRate,
isSingleProvider = quoteContent?.isSingleProvider == true, isSingleProvider = quoteContent?.isSingleProvider == true,
showBestRateAnimation = amountUM.showBestRateAnimation, showBestRateAnimation = amountUM.isShowBestRateAnimation,
expressProvider = amountUM.selectedQuote.provider, expressProvider = amountUM.selectedQuote.provider,
onClick = onProviderSelectClick, onClick = onProviderSelectClick,
onFinishAnimation = onFinishAnimation, onFinishAnimation = onFinishAnimation,
@ -98,7 +98,7 @@ internal fun SwapAmountBlockContent(
start.linkTo(parent.start) start.linkTo(parent.start)
end.linkTo(parent.end) end.linkTo(parent.end)
}, },
showFCAWarning = amountUM.showFCAWarning, showFCAWarning = amountUM.isShowFCAWarning,
) )
} }
} }

View file

@ -175,7 +175,7 @@ private fun SwapAmountBlock(
selectedQuote = selectedQuote, selectedQuote = selectedQuote,
isSelectedAmountType = isSelectedAmountType, isSelectedAmountType = isSelectedAmountType,
isFixedRate = isFixedRate, isFixedRate = isFixedRate,
onExpandEditField = clickIntents::onExpandEditField, onExpandEditField = { clickIntents.onExpandEditField(amountFieldUM.amountType) },
onSelectTokenClick = clickIntents::onSelectTokenClick, onSelectTokenClick = clickIntents::onSelectTokenClick,
onMaxAmountClick = clickIntents::onMaxValueClick, onMaxAmountClick = clickIntents::onMaxValueClick,
) )
@ -195,14 +195,14 @@ private fun SwapAmountEditBlock(
verticalArrangement = Arrangement.spacedBy(12.dp), verticalArrangement = Arrangement.spacedBy(12.dp),
modifier = modifier.padding(top = 48.dp, bottom = 28.dp), modifier = modifier.padding(top = 48.dp, bottom = 28.dp),
) { ) {
when (val amountFieldUM = amountFieldUM.amountField) { when (val amountField = amountFieldUM.amountField) {
!is AmountState.Data -> { !is AmountState.Data -> {
TextShimmer( TextShimmer(
style = TangemTheme.typography.caption2, style = TangemTheme.typography.caption2,
modifier = Modifier.width(60.dp), modifier = Modifier.width(60.dp),
) )
} }
else -> AccountTitle(amountFieldUM.accountTitleUM) else -> AccountTitle(amountField.accountTitleUM)
} }
AmountFieldV2( AmountFieldV2(
amountUM = amountFieldUM.amountField, amountUM = amountFieldUM.amountField,
@ -221,7 +221,7 @@ private fun SwapAmountInfo(
selectedQuote: SwapQuoteUM?, selectedQuote: SwapQuoteUM?,
isSelectedAmountType: Boolean, isSelectedAmountType: Boolean,
isFixedRate: Boolean, isFixedRate: Boolean,
onExpandEditField: (SwapAmountType) -> Unit, onExpandEditField: () -> Unit,
onMaxAmountClick: () -> Unit, onMaxAmountClick: () -> Unit,
onSelectTokenClick: () -> Unit, onSelectTokenClick: () -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
@ -237,7 +237,7 @@ private fun SwapAmountInfo(
enabled = (amountFieldUM as? SwapAmountFieldUM.Content)?.isClickEnabled == true, enabled = (amountFieldUM as? SwapAmountFieldUM.Content)?.isClickEnabled == true,
onClick = { onClick = {
if (isFixedRate) { if (isFixedRate) {
onExpandEditField(amountFieldUM.amountType) onExpandEditField()
} else { } else {
onSelectTokenClick() onSelectTokenClick()
} }

View file

@ -90,8 +90,8 @@ internal data object SwapAmountContentPreview {
secondaryCryptoCurrencyStatus = cryptoCurrencyStatus, secondaryCryptoCurrencyStatus = cryptoCurrencyStatus,
swapRateType = ExpressRateType.Float, swapRateType = ExpressRateType.Float,
appCurrency = AppCurrency.Default, appCurrency = AppCurrency.Default,
showBestRateAnimation = false, isShowBestRateAnimation = false,
showFCAWarning = false, isShowFCAWarning = false,
) )
val defaultState = SwapAmountUM.Content( val defaultState = SwapAmountUM.Content(
@ -129,8 +129,8 @@ internal data object SwapAmountContentPreview {
secondaryCryptoCurrencyStatus = cryptoCurrencyStatus, secondaryCryptoCurrencyStatus = cryptoCurrencyStatus,
swapRateType = ExpressRateType.Float, swapRateType = ExpressRateType.Float,
isPrimaryButtonEnabled = true, isPrimaryButtonEnabled = true,
showBestRateAnimation = false, isShowBestRateAnimation = false,
showFCAWarning = true, isShowFCAWarning = true,
) )
val defaultStateAccount: SwapAmountUM.Content val defaultStateAccount: SwapAmountUM.Content

View file

@ -25,13 +25,13 @@ internal class SwapChooseProviderModel @Inject constructor(
private val params: SwapChooseProviderComponent.Params = paramsContainer.require() private val params: SwapChooseProviderComponent.Params = paramsContainer.require()
private val needApplyFCARestrictions = params.userCountry.needApplyFCARestrictions() private val isNeedApplyFCARestrictions = params.userCountry.needApplyFCARestrictions()
private val swapProviderListItemConverter by lazy(LazyThreadSafetyMode.NONE) { private val swapProviderListItemConverter by lazy(LazyThreadSafetyMode.NONE) {
SwapProviderListItemConverter( SwapProviderListItemConverter(
cryptoCurrency = params.cryptoCurrency, cryptoCurrency = params.cryptoCurrency,
selectedProvider = params.selectedProvider, selectedProvider = params.selectedProvider,
needApplyFCARestrictions = needApplyFCARestrictions, isNeedApplyFCARestrictions = isNeedApplyFCARestrictions,
needBestRateBadge = params.providers.filterIsInstance<SwapQuoteUM.Content>().isSingleItem().not(), needBestRateBadge = params.providers.filterIsInstance<SwapQuoteUM.Content>().isSingleItem().not(),
) )
} }
@ -45,13 +45,13 @@ internal class SwapChooseProviderModel @Inject constructor(
} }
private fun getInitialState(): SwapChooseProviderBottomSheetContent { private fun getInitialState(): SwapChooseProviderBottomSheetContent {
val filteredProviderList = params.providers.filter { val filteredProviderList = params.providers.filter { swapQuoteUM ->
it is SwapQuoteUM.Content || swapQuoteUM is SwapQuoteUM.Content ||
it is SwapQuoteUM.Allowance || swapQuoteUM is SwapQuoteUM.Allowance ||
(it as? SwapQuoteUM.Error)?.expressError is ExpressError.AmountError (swapQuoteUM as? SwapQuoteUM.Error)?.expressError is ExpressError.AmountError
} }
return SwapChooseProviderBottomSheetContent( return SwapChooseProviderBottomSheetContent(
isApplyFCARestrictions = needApplyFCARestrictions && params.selectedProvider.isRestrictedByFCA(), isApplyFCARestrictions = isNeedApplyFCARestrictions && params.selectedProvider.isRestrictedByFCA(),
providerList = swapProviderListItemConverter.convertList(filteredProviderList) providerList = swapProviderListItemConverter.convertList(filteredProviderList)
.filterNotNull() .filterNotNull()
.toPersistentList(), .toPersistentList(),

View file

@ -21,14 +21,14 @@ import com.tangem.utils.converter.Converter
internal class SwapProviderListItemConverter( internal class SwapProviderListItemConverter(
private val cryptoCurrency: CryptoCurrency, private val cryptoCurrency: CryptoCurrency,
private val selectedProvider: ExpressProvider, private val selectedProvider: ExpressProvider,
private val needApplyFCARestrictions: Boolean, private val isNeedApplyFCARestrictions: Boolean,
needBestRateBadge: Boolean, needBestRateBadge: Boolean,
) : Converter<SwapQuoteUM, SwapProviderListItem?> { ) : Converter<SwapQuoteUM, SwapProviderListItem?> {
private val providerStateConverter = SwapProviderStateConverter( private val providerStateConverter = SwapProviderStateConverter(
cryptoCurrency = cryptoCurrency, cryptoCurrency = cryptoCurrency,
selectedProvider = selectedProvider, selectedProvider = selectedProvider,
needApplyFCARestrictions = needApplyFCARestrictions, isNeedApplyFCARestrictions = isNeedApplyFCARestrictions,
isNeedBestRateBadge = needBestRateBadge, isNeedBestRateBadge = needBestRateBadge,
) )
@ -78,7 +78,7 @@ internal class SwapProviderListItemConverter(
}, },
) )
} }
is SwapQuoteUM.Content -> if (needApplyFCARestrictions && value.provider.isRestrictedByFCA()) { is SwapQuoteUM.Content -> if (isNeedApplyFCARestrictions && value.provider.isRestrictedByFCA()) {
ProviderChooseUM.ExtraUM.Action( ProviderChooseUM.ExtraUM.Action(
text = resourceReference(R.string.express_provider_fca_warning_list), text = resourceReference(R.string.express_provider_fca_warning_list),
) )

View file

@ -20,7 +20,7 @@ internal class SwapProviderStateConverter(
private val cryptoCurrency: CryptoCurrency, private val cryptoCurrency: CryptoCurrency,
private val selectedProvider: ExpressProvider, private val selectedProvider: ExpressProvider,
private val isNeedBestRateBadge: Boolean, private val isNeedBestRateBadge: Boolean,
private val needApplyFCARestrictions: Boolean, private val isNeedApplyFCARestrictions: Boolean,
) : Converter<SwapQuoteUM, SwapProviderState> { ) : Converter<SwapQuoteUM, SwapProviderState> {
override fun convert(value: SwapQuoteUM): SwapProviderState { override fun convert(value: SwapQuoteUM): SwapProviderState {
@ -41,7 +41,7 @@ internal class SwapProviderStateConverter(
} }
val additionalBadge = when { val additionalBadge = when {
needApplyFCARestrictions && provider.isRestrictedByFCA() -> AdditionalBadge.FCAWarningList isNeedApplyFCARestrictions && provider.isRestrictedByFCA() -> AdditionalBadge.FCAWarningList
isNeedBestRateBadge && isBestRate -> AdditionalBadge.BestTrade isNeedBestRateBadge && isBestRate -> AdditionalBadge.BestTrade
else -> AdditionalBadge.Empty else -> AdditionalBadge.Empty
} }
@ -59,7 +59,7 @@ internal class SwapProviderStateConverter(
private fun SwapQuoteUM.Error.convertToErrorContent(): SwapProviderState { private fun SwapQuoteUM.Error.convertToErrorContent(): SwapProviderState {
val additionalBadge = when { val additionalBadge = when {
needApplyFCARestrictions && provider.isRestrictedByFCA() -> AdditionalBadge.FCAWarningList isNeedApplyFCARestrictions && provider.isRestrictedByFCA() -> AdditionalBadge.FCAWarningList
else -> AdditionalBadge.Empty else -> AdditionalBadge.Empty
} }

View file

@ -66,8 +66,8 @@ internal class SwapChooseTokenNetworkModel @Inject constructor(
} }
private fun initContent() { private fun initContent() {
val userWallet = getUserWalletUseCase(params.userWalletId).getOrElse { val userWallet = getUserWalletUseCase(params.userWalletId).getOrElse { error ->
Timber.e("Failed to get user wallet: $it") Timber.e("Failed to get user wallet: $error")
swapChooseTokenAlertFactory.getGenericErrorState(params.onDismiss) swapChooseTokenAlertFactory.getGenericErrorState(params.onDismiss)
return return
} }
@ -87,8 +87,8 @@ internal class SwapChooseTokenNetworkModel @Inject constructor(
cryptoCurrencyList = cryptoCurrencyList + params.initialCurrency, cryptoCurrencyList = cryptoCurrencyList + params.initialCurrency,
filterProviderTypes = SEND_WITH_SWAP_PROVIDER_TYPES, filterProviderTypes = SEND_WITH_SWAP_PROVIDER_TYPES,
swapTxType = SwapTxType.SendWithSwap, swapTxType = SwapTxType.SendWithSwap,
).getOrElse { ).getOrElse { error ->
Timber.e(it.toString()) Timber.e(error.toString())
uiState.update( uiState.update(
SwapChooseErrorStateTransformer( SwapChooseErrorStateTransformer(
tokenName = params.token.name, tokenName = params.token.name,

View file

@ -91,7 +91,8 @@ internal class SwapAlertFactory @Inject constructor(
destinationAddress = confirmData?.enteredDestination.orEmpty(), destinationAddress = confirmData?.enteredDestination.orEmpty(),
tokenSymbol = confirmData?.toCryptoCurrencyStatus?.currency?.symbol.orEmpty(), tokenSymbol = confirmData?.toCryptoCurrencyStatus?.currency?.symbol.orEmpty(),
amount = confirmData?.enteredAmount?.toString().orEmpty(), amount = confirmData?.enteredAmount?.toString().orEmpty(),
fee = confirmData?.fee?.amount?.value?.toString().orEmpty(), fee = confirmData?.fee?.amount?.value?.toString()
.orEmpty(),
), ),
) )

View file

@ -15,7 +15,7 @@ internal sealed class ConfirmUM {
data class Content( data class Content(
override val isPrimaryButtonEnabled: Boolean = false, override val isPrimaryButtonEnabled: Boolean = false,
val isTransactionInProcess: Boolean, val isTransactionInProcess: Boolean,
val showTapHelp: Boolean, val isShowTapHelp: Boolean,
val sendingFooter: TextReference, val sendingFooter: TextReference,
val notifications: ImmutableList<NotificationUM>, val notifications: ImmutableList<NotificationUM>,
val tosUM: TosUM?, val tosUM: TosUM?,

View file

@ -13,7 +13,7 @@ import com.tangem.features.send.v2.api.analytics.CommonSendAnalyticEvents
internal sealed class SendWithSwapAnalyticEvents( internal sealed class SendWithSwapAnalyticEvents(
event: String, event: String,
params: Map<String, String> = mapOf(), params: Map<String, String> = emptyMap(),
) : AnalyticsEvent(category = CommonSendAnalyticEvents.SEND_CATEGORY, event = event, params = params) { ) : AnalyticsEvent(category = CommonSendAnalyticEvents.SEND_CATEGORY, event = event, params = params) {
data class TransactionScreenOpened( data class TransactionScreenOpened(

View file

@ -94,11 +94,7 @@ internal class SendWithSwapConfirmModel @Inject constructor(
field = MutableStateFlow(params.sendWithSwapUM) field = MutableStateFlow(params.sendWithSwapUM)
val primaryCurrencyStatus: CryptoCurrencyStatus = params.primaryCryptoCurrencyStatusFlow.value val primaryCurrencyStatus: CryptoCurrencyStatus = params.primaryCryptoCurrencyStatusFlow.value
val secondaryCurrencyStatus: CryptoCurrencyStatus? = amountUM?.secondaryCryptoCurrencyStatus
val primaryFeePaidCurrencyStatus: CryptoCurrencyStatus = params.primaryFeePaidCurrencyStatusFlow.value val primaryFeePaidCurrencyStatus: CryptoCurrencyStatus = params.primaryFeePaidCurrencyStatusFlow.value
val secondaryCurrency: CryptoCurrency = requireNotNull(amountUM?.secondaryCryptoCurrencyStatus?.currency) {
"Crypto currency must not be null"
}
private val swapTransactionSender = swapTransactionSenderFactory.create(params.userWallet) private val swapTransactionSender = swapTransactionSenderFactory.create(params.userWallet)
@ -111,6 +107,11 @@ internal class SendWithSwapConfirmModel @Inject constructor(
private val feeSelectorUM private val feeSelectorUM
get() = uiState.value.feeSelectorUM as? FeeSelectorUM.Content get() = uiState.value.feeSelectorUM as? FeeSelectorUM.Content
val secondaryCurrencyStatus: CryptoCurrencyStatus? = amountUM?.secondaryCryptoCurrencyStatus
val secondaryCurrency: CryptoCurrency = requireNotNull(amountUM?.secondaryCryptoCurrencyStatus?.currency) {
"Crypto currency must not be null"
}
val confirmData: ConfirmData val confirmData: ConfirmData
get() { get() {
val amountUM = amountUM val amountUM = amountUM
@ -270,13 +271,13 @@ internal class SendWithSwapConfirmModel @Inject constructor(
uiState.transformerUpdate(SendWithSwapConfirmSendingStateTransformer(false)) uiState.transformerUpdate(SendWithSwapConfirmSendingStateTransformer(false))
swapAlertFactory.getSendTransactionErrorState( swapAlertFactory.getSendTransactionErrorState(
error = error, error = error,
onFailedTxEmailClick = { onFailedTxEmailClick = { _ ->
modelScope.launch { modelScope.launch {
swapAlertFactory.onFailedTxEmailClick( swapAlertFactory.onFailedTxEmailClick(
userWallet = params.userWallet, userWallet = params.userWallet,
cryptoCurrency = confirmData.fromCryptoCurrencyStatus?.currency, cryptoCurrency = confirmData.fromCryptoCurrencyStatus?.currency,
confirmData = confirmData, confirmData = confirmData,
errorMessage = error.toString(), errorMessage = error?.toString().orEmpty(),
) )
} }
}, },
@ -320,8 +321,8 @@ internal class SendWithSwapConfirmModel @Inject constructor(
modelScope.launch { modelScope.launch {
val isShowTapHelp = isSendTapHelpEnabledUseCase.invokeSync().getOrElse { false } val isShowTapHelp = isSendTapHelpEnabledUseCase.invokeSync().getOrElse { false }
if (confirmUM is ConfirmUM.Empty) { if (confirmUM is ConfirmUM.Empty) {
uiState.update { uiState.update { state ->
it.copy( state.copy(
confirmUM = SendWithSwapConfirmInitialStateTransformer( confirmUM = SendWithSwapConfirmInitialStateTransformer(
isShowTapHelp = isShowTapHelp, isShowTapHelp = isShowTapHelp,
).transform(uiState.value.confirmUM), ).transform(uiState.value.confirmUM),
@ -335,9 +336,9 @@ internal class SendWithSwapConfirmModel @Inject constructor(
private fun subscribeOnTapHelpUpdates() { private fun subscribeOnTapHelpUpdates() {
isSendTapHelpEnabledUseCase().getOrNull() isSendTapHelpEnabledUseCase().getOrNull()
?.onEach { showTapHelp -> ?.onEach { showTapHelp ->
uiState.update { uiState.update { state ->
val confirmUM = it.confirmUM as? ConfirmUM.Content val confirmUM = state.confirmUM as? ConfirmUM.Content
it.copy(confirmUM = confirmUM?.copy(showTapHelp = showTapHelp) ?: it.confirmUM) state.copy(confirmUM = confirmUM?.copy(isShowTapHelp = showTapHelp) ?: state.confirmUM)
} }
}?.launchIn(modelScope) }?.launchIn(modelScope)
} }
@ -376,12 +377,12 @@ internal class SendWithSwapConfirmModel @Inject constructor(
flow2 = swapNotificationsUpdateListener.hasErrorFlow, flow2 = swapNotificationsUpdateListener.hasErrorFlow,
) { hasSendError, hasSwapError -> ) { hasSendError, hasSwapError ->
val hasError = hasSendError || hasSwapError val hasError = hasSendError || hasSwapError
uiState.update { uiState.update { state ->
val feeUM = it.feeSelectorUM as? FeeSelectorUM.Content val feeUM = state.feeSelectorUM as? FeeSelectorUM.Content
it.copy( state.copy(
confirmUM = (it.confirmUM as? ConfirmUM.Content)?.copy( confirmUM = (state.confirmUM as? ConfirmUM.Content)?.copy(
isPrimaryButtonEnabled = !hasError && feeUM != null, isPrimaryButtonEnabled = !hasError && feeUM != null,
) ?: it.confirmUM, ) ?: state.confirmUM,
) )
} }
}.launchIn(modelScope) }.launchIn(modelScope)

View file

@ -98,8 +98,8 @@ internal class SwapTransactionSender @AssistedInject constructor(
toAddress = destination, toAddress = destination,
expressProvider = provider, expressProvider = provider,
rateType = rateType, rateType = rateType,
expressOperationType, expressOperationType = expressOperationType,
).getOrElse { onExpressError(it); return } ).getOrElse { error -> onExpressError(error); return }
createAndSendCexTransaction( createAndSendCexTransaction(
fromAmount = fromAmount, fromAmount = fromAmount,
@ -141,9 +141,9 @@ internal class SwapTransactionSender @AssistedInject constructor(
destination = swapTransaction.txTo, destination = swapTransaction.txTo,
userWalletId = userWallet.walletId, userWalletId = userWallet.walletId,
network = fromStatus.currency.network, network = fromStatus.currency.network,
).getOrElse { ).getOrElse { error ->
Timber.e(it, "Failed to create swap CEX tx data") Timber.e(error, "Failed to create swap CEX tx data")
onSendError(SendTransactionError.UnknownError(Exception(it))) onSendError(SendTransactionError.UnknownError(Exception(error)))
return return
} }

View file

@ -12,7 +12,7 @@ internal class SendWithSwapConfirmInitialStateTransformer(
return ConfirmUM.Content( return ConfirmUM.Content(
isPrimaryButtonEnabled = false, isPrimaryButtonEnabled = false,
isTransactionInProcess = false, isTransactionInProcess = false,
showTapHelp = isShowTapHelp, isShowTapHelp = isShowTapHelp,
sendingFooter = TextReference.EMPTY, sendingFooter = TextReference.EMPTY,
notifications = persistentListOf(), notifications = persistentListOf(),
tosUM = null, tosUM = null,

View file

@ -109,16 +109,16 @@ internal class SendWithSwapConfirmationNotificationsTransformer : Transformer<Se
val expressProvider = (swapAmountUM as? SwapAmountUM.Content)?.selectedQuote?.provider ?: return null val expressProvider = (swapAmountUM as? SwapAmountUM.Content)?.selectedQuote?.provider ?: return null
return ConfirmUM.Content.TosUM( return ConfirmUM.Content.TosUM(
tosLink = expressProvider.termsOfUse?.let { tosLink = expressProvider.termsOfUse?.let { termsOfUse ->
ConfirmUM.Content.LegalUM( ConfirmUM.Content.LegalUM(
title = resourceReference(R.string.common_terms_of_use), title = resourceReference(R.string.common_terms_of_use),
link = it, link = termsOfUse,
) )
}, },
policyLink = expressProvider.privacyPolicy?.let { policyLink = expressProvider.privacyPolicy?.let { privacyPolicy ->
ConfirmUM.Content.LegalUM( ConfirmUM.Content.LegalUM(
title = resourceReference(R.string.common_privacy_policy), title = resourceReference(R.string.common_privacy_policy),
link = it, link = privacyPolicy,
) )
}, },
) )

View file

@ -132,8 +132,8 @@ internal class SendWithSwapModel @Inject constructor(
} }
override fun resetSendWithSwapNavigation(resetNavigation: Boolean) { override fun resetSendWithSwapNavigation(resetNavigation: Boolean) {
uiState.update { uiState.update { state ->
it.copy( state.copy(
destinationUM = DestinationUM.Empty(), destinationUM = DestinationUM.Empty(),
feeSelectorUM = FeeSelectorUM.Loading, feeSelectorUM = FeeSelectorUM.Loading,
confirmUM = ConfirmUM.Empty, confirmUM = ConfirmUM.Empty,
@ -166,8 +166,8 @@ internal class SendWithSwapModel @Inject constructor(
userWallet = wallet userWallet = wallet
getPrimaryCurrencyStatusUpdates(params.currency) getPrimaryCurrencyStatusUpdates(params.currency)
}, },
ifLeft = { ifLeft = { error ->
Timber.w(it.toString()) Timber.w(error.toString())
swapAlertFactory.getGenericErrorState( swapAlertFactory.getGenericErrorState(
expressError = ExpressError.UnknownError, expressError = ExpressError.UnknownError,
onFailedTxEmailClick = { onFailedTxEmailClick = {
@ -175,7 +175,7 @@ internal class SendWithSwapModel @Inject constructor(
swapAlertFactory.onFailedTxEmailClick( swapAlertFactory.onFailedTxEmailClick(
userWallet = userWallet, userWallet = userWallet,
cryptoCurrency = params.currency, cryptoCurrency = params.currency,
errorMessage = it.toString(), errorMessage = error.toString(),
) )
} }
}, },

View file

@ -344,7 +344,7 @@ private fun SendWithSwapSuccessContent_Preview() {
txUrl = "https://tangem.com", txUrl = "https://tangem.com",
provider = ExpressProvider( provider = ExpressProvider(
providerId = "changelly", providerId = "changelly",
rateTypes = listOf(), rateTypes = emptyList(),
name = "Changelly", name = "Changelly",
type = ExpressProviderType.CEX, type = ExpressProviderType.CEX,
imageLarge = "https://s3.eu-central-1.amazonaws.com/tangem.api/express/changelly-1024.png", imageLarge = "https://s3.eu-central-1.amazonaws.com/tangem.api/express/changelly-1024.png",

View file

@ -36,7 +36,7 @@ internal fun SendWithSwapContent(
stackState: ChildStack<SendWithSwapRoute, ComposableContentComponent>, stackState: ChildStack<SendWithSwapRoute, ComposableContentComponent>,
onLinkClick: (String) -> Unit, onLinkClick: (String) -> Unit,
) { ) {
val navigationUM = navigationUM as? NavigationUM.Content ?: return val navigationUMContent = navigationUM as? NavigationUM.Content ?: return
Column( Column(
modifier = Modifier modifier = Modifier
@ -47,9 +47,9 @@ internal fun SendWithSwapContent(
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
) { ) {
AppBarWithBackButton( AppBarWithBackButton(
text = navigationUM.title.resolveReference(), text = navigationUMContent.title.resolveReference(),
onBackClick = navigationUM.backIconClick, onBackClick = navigationUMContent.backIconClick,
iconRes = navigationUM.additionalIconRes, iconRes = navigationUMContent.additionalIconRes,
modifier = Modifier.height(TangemTheme.dimens.size56), modifier = Modifier.height(TangemTheme.dimens.size56),
) )
Children( Children(
@ -93,7 +93,7 @@ internal fun SendWithSwapContent(
) )
} }
NavigationPrimaryButton( NavigationPrimaryButton(
navigationUM.primaryButton, navigationUMContent.primaryButton,
modifier = Modifier.padding( modifier = Modifier.padding(
start = 16.dp, start = 16.dp,
end = 16.dp, end = 16.dp,

View file

@ -22,12 +22,10 @@
<ID>MultilineLambdaItParameter:TesterAccountsViewModel.kt$TesterAccountsViewModel${ it.copy( accountListBottomSheetConfig = it.accountListBottomSheetConfig.copy( isAccountsShown = false, ), ) }</ID> <ID>MultilineLambdaItParameter:TesterAccountsViewModel.kt$TesterAccountsViewModel${ it.copy( accountListBottomSheetConfig = it.accountListBottomSheetConfig.copy( isAccountsShown = false, ), ) }</ID>
<ID>MultilineLambdaItParameter:TesterAccountsViewModel.kt$TesterAccountsViewModel${ it.copy( walletSelector = it.walletSelector.copy(selected = userWallet), accountListBottomSheetConfig = it.accountListBottomSheetConfig.copy( accounts = getWalletAccounts(userWallet.walletId), ), ) }</ID> <ID>MultilineLambdaItParameter:TesterAccountsViewModel.kt$TesterAccountsViewModel${ it.copy( walletSelector = it.walletSelector.copy(selected = userWallet), accountListBottomSheetConfig = it.accountListBottomSheetConfig.copy( accounts = getWalletAccounts(userWallet.walletId), ), ) }</ID>
<ID>MultilineLambdaItParameter:TesterActionsScreen.kt${ builder.setStream( FileProvider.getUriForFile(activity, "${activity.packageName}.provider", it), ) }</ID> <ID>MultilineLambdaItParameter:TesterActionsScreen.kt${ builder.setStream( FileProvider.getUriForFile(activity, "${activity.packageName}.provider", it), ) }</ID>
<ID>MultilineLambdaItParameter:TesterActivity.kt$TesterActivity${ val route = when (it) { ButtonUM.FEATURE_TOGGLES -&gt; TesterScreen.FEATURE_TOGGLES ButtonUM.EXCLUDED_BLOCKCHAINS -&gt; TesterScreen.EXCLUDED_BLOCKCHAINS ButtonUM.ENVIRONMENT_TOGGLES -&gt; TesterScreen.ENVIRONMENTS_TOGGLES ButtonUM.BLOCKCHAIN_PROVIDERS -&gt; TesterScreen.BLOCKCHAIN_PROVIDERS ButtonUM.TESTER_ACTIONS -&gt; TesterScreen.TESTER_ACTIONS ButtonUM.TEST_PUSHES -&gt; TesterScreen.TEST_PUSHES ButtonUM.ACCOUNTS -&gt; TesterScreen.ACCOUNTS } innerTesterRouter.open(route) }</ID>
<ID>NoNameShadowing:AccountsScreen.kt$content</ID> <ID>NoNameShadowing:AccountsScreen.kt$content</ID>
<ID>NoNameShadowing:BlockchainProvidersViewModel.kt$BlockchainProvidersViewModel${ onAddProviderClick(id = blockchain.id, url = it) }</ID> <ID>NoNameShadowing:BlockchainProvidersViewModel.kt$BlockchainProvidersViewModel${ onAddProviderClick(id = blockchain.id, url = it) }</ID>
<ID>NoNameShadowing:BlockchainProvidersViewModel.kt$BlockchainProvidersViewModel${ onPublicProviderUrlChange(id = blockchain.id, url = it) }</ID> <ID>NoNameShadowing:BlockchainProvidersViewModel.kt$BlockchainProvidersViewModel${ onPublicProviderUrlChange(id = blockchain.id, url = it) }</ID>
<ID>NoNameShadowing:EnvironmentsTogglesViewModel.kt$EnvironmentsTogglesViewModel${ it.environment == currentEnvironment }</ID> <ID>NoNameShadowing:EnvironmentsTogglesViewModel.kt$EnvironmentsTogglesViewModel${ it.environment == currentEnvironment }</ID>
<ID>NoNameShadowing:TesterActivity.kt$TesterActivity${ val route = when (it) { ButtonUM.FEATURE_TOGGLES -&gt; TesterScreen.FEATURE_TOGGLES ButtonUM.EXCLUDED_BLOCKCHAINS -&gt; TesterScreen.EXCLUDED_BLOCKCHAINS ButtonUM.ENVIRONMENT_TOGGLES -&gt; TesterScreen.ENVIRONMENTS_TOGGLES ButtonUM.BLOCKCHAIN_PROVIDERS -&gt; TesterScreen.BLOCKCHAIN_PROVIDERS ButtonUM.TESTER_ACTIONS -&gt; TesterScreen.TESTER_ACTIONS ButtonUM.TEST_PUSHES -&gt; TesterScreen.TEST_PUSHES ButtonUM.ACCOUNTS -&gt; TesterScreen.ACCOUNTS } innerTesterRouter.open(route) }</ID>
<ID>PropertyUsedBeforeDeclaration:BlockchainProvidersViewModel.kt$BlockchainProvidersViewModel$_state</ID> <ID>PropertyUsedBeforeDeclaration:BlockchainProvidersViewModel.kt$BlockchainProvidersViewModel$_state</ID>
<ID>PropertyUsedBeforeDeclaration:BlockchainProvidersViewModel.kt$BlockchainProvidersViewModel$searchQuery</ID> <ID>PropertyUsedBeforeDeclaration:BlockchainProvidersViewModel.kt$BlockchainProvidersViewModel$searchQuery</ID>
<ID>PropertyUsedBeforeDeclaration:EnvironmentsTogglesViewModel.kt$EnvironmentsTogglesViewModel$_uiState</ID> <ID>PropertyUsedBeforeDeclaration:EnvironmentsTogglesViewModel.kt$EnvironmentsTogglesViewModel$_uiState</ID>

View file

@ -24,7 +24,6 @@
<ID>MultilineLambdaItParameter:TokenDetailsModel.kt$TokenDetailsModel${ internalUiState.value = stateFactory.getStateWithUpdatedHidden( isBalanceHidden = it.isBalanceHidden, ) }</ID> <ID>MultilineLambdaItParameter:TokenDetailsModel.kt$TokenDetailsModel${ internalUiState.value = stateFactory.getStateWithUpdatedHidden( isBalanceHidden = it.isBalanceHidden, ) }</ID>
<ID>MultilineLambdaItParameter:TokenDetailsModel.kt$TokenDetailsModel${ sendButtonsEvents(it.states) internalUiState.value = stateFactory.getManageButtonsState(actions = it.states) }</ID> <ID>MultilineLambdaItParameter:TokenDetailsModel.kt$TokenDetailsModel${ sendButtonsEvents(it.states) internalUiState.value = stateFactory.getManageButtonsState(actions = it.states) }</ID>
<ID>MultilineLambdaItParameter:TokenDetailsModel.kt$TokenDetailsModel${ val updatedState = stateFactory.getStateWithNotifications(it) notificationsAnalyticsSender.send(internalUiState.value, updatedState.notifications) internalUiState.value = updatedState }</ID> <ID>MultilineLambdaItParameter:TokenDetailsModel.kt$TokenDetailsModel${ val updatedState = stateFactory.getStateWithNotifications(it) notificationsAnalyticsSender.send(internalUiState.value, updatedState.notifications) internalUiState.value = updatedState }</ID>
<ID>MultilineLambdaItParameter:TokenDetailsOnrampTransactionStateConverter.kt$TokenDetailsOnrampTransactionStateConverter${ analyticsEventHandler.send(TokenOnrampAnalyticsEvent.GoToProvider) clickIntents.onGoToProviderClick(it) }</ID>
<ID>MultilineLambdaItParameter:TokenDetailsScreen.kt${ Notification( modifier = itemModifier.animateItem(), config = it.config, iconTint = when (it) { is TokenDetailsNotification.Informational -&gt; TangemTheme.colors.icon.accent is TokenDetailsNotification.UsedOutdatedData -&gt; TangemTheme.colors.text.attention else -&gt; null }, ) }</ID> <ID>MultilineLambdaItParameter:TokenDetailsScreen.kt${ Notification( modifier = itemModifier.animateItem(), config = it.config, iconTint = when (it) { is TokenDetailsNotification.Informational -&gt; TangemTheme.colors.icon.accent is TokenDetailsNotification.UsedOutdatedData -&gt; TangemTheme.colors.text.attention else -&gt; null }, ) }</ID>
<ID>MultilineLambdaItParameter:TokenDetailsTopAppBar.kt${ TangemDropdownItem( item = it, dismissParent = { showDropdownMenu = false }, ) }</ID> <ID>MultilineLambdaItParameter:TokenDetailsTopAppBar.kt${ TangemDropdownItem( item = it, dismissParent = { showDropdownMenu = false }, ) }</ID>
<ID>MultilineLambdaItParameter:TokenStakingBlock.kt${ when (it) { is StakingBlockUM.TemporaryUnavailable -&gt; StakingTemporaryUnavailableBlock() is StakingBlockUM.Loading -&gt; StakingLoading() is StakingBlockUM.Staked -&gt; StakingBalanceBlock( state = it, isBalanceHidden = isBalanceHidden, ) is StakingBlockUM.StakeAvailable -&gt; StakingAvailableContent( state = it, ) } }</ID> <ID>MultilineLambdaItParameter:TokenStakingBlock.kt${ when (it) { is StakingBlockUM.TemporaryUnavailable -&gt; StakingTemporaryUnavailableBlock() is StakingBlockUM.Loading -&gt; StakingLoading() is StakingBlockUM.Staked -&gt; StakingBalanceBlock( state = it, isBalanceHidden = isBalanceHidden, ) is StakingBlockUM.StakeAvailable -&gt; StakingAvailableContent( state = it, ) } }</ID>

View file

@ -45,7 +45,6 @@
<ID>MultilineLambdaItParameter:SetRefreshStateTransformer.kt$SetRefreshStateTransformer${ it.mapNotNull { button -&gt; when (button) { is WalletManageButton.Buy -&gt; button.copy(enabled = isButtonsEnabled) is WalletManageButton.Send -&gt; button.copy(enabled = isButtonsEnabled) is WalletManageButton.Sell -&gt; button.copy(enabled = isButtonsEnabled) is WalletManageButton.Receive -&gt; button is WalletManageButton.Stake -&gt; null is WalletManageButton.Swap -&gt; null } } }</ID> <ID>MultilineLambdaItParameter:SetRefreshStateTransformer.kt$SetRefreshStateTransformer${ it.mapNotNull { button -&gt; when (button) { is WalletManageButton.Buy -&gt; button.copy(enabled = isButtonsEnabled) is WalletManageButton.Send -&gt; button.copy(enabled = isButtonsEnabled) is WalletManageButton.Sell -&gt; button.copy(enabled = isButtonsEnabled) is WalletManageButton.Receive -&gt; button is WalletManageButton.Stake -&gt; null is WalletManageButton.Swap -&gt; null } } }</ID>
<ID>MultilineLambdaItParameter:SetVisaInfoTransformer.kt$SetVisaInfoTransformer${ if (it is RefreshTokenExpiredException) { return getRefreshTokenExpiredState(prevState) } return prevState.copy( buttons = createVisaButtonsDimmed(), walletCardState = getErrorWalletCardState(prevState.walletCardState), balancesAndLimitBlockState = BalancesAndLimitsBlockState.Error, ) }</ID> <ID>MultilineLambdaItParameter:SetVisaInfoTransformer.kt$SetVisaInfoTransformer${ if (it is RefreshTokenExpiredException) { return getRefreshTokenExpiredState(prevState) } return prevState.copy( buttons = createVisaButtonsDimmed(), walletCardState = getErrorWalletCardState(prevState.walletCardState), balancesAndLimitBlockState = BalancesAndLimitsBlockState.Error, ) }</ID>
<ID>MultilineLambdaItParameter:SingleWalletExpressStatusesSubscriber.kt$SingleWalletExpressStatusesSubscriber${ Timber.e("Unable to get primary currency status: $it") return@onEach }</ID> <ID>MultilineLambdaItParameter:SingleWalletExpressStatusesSubscriber.kt$SingleWalletExpressStatusesSubscriber${ Timber.e("Unable to get primary currency status: $it") return@onEach }</ID>
<ID>MultilineLambdaItParameter:SingleWalletOnrampTransactionConverter.kt$SingleWalletOnrampTransactionConverter${ analyticsEventHandler.send(TokenOnrampAnalyticsEvent.GoToProvider) clickIntents.onGoToProviderClick(it) }</ID>
<ID>MultilineLambdaItParameter:TokenListAnalyticsSender.kt$TokenListAnalyticsSender${ val status = it.value if (status is CryptoCurrencyStatus.Loaded) { sendTokenBalancesForSpecificBlockchains(it, status) } }</ID> <ID>MultilineLambdaItParameter:TokenListAnalyticsSender.kt$TokenListAnalyticsSender${ val status = it.value if (status is CryptoCurrencyStatus.Loaded) { sendTokenBalancesForSpecificBlockchains(it, status) } }</ID>
<ID>MultilineLambdaItParameter:TokenListStateConverter.kt$TokenListStateConverter${ if (isExtend) { clickIntents.onAccountCollapseClick(it) } else { clickIntents.onAccountExpandClick(it) } }</ID> <ID>MultilineLambdaItParameter:TokenListStateConverter.kt$TokenListStateConverter${ if (isExtend) { clickIntents.onAccountCollapseClick(it) } else { clickIntents.onAccountExpandClick(it) } }</ID>
<ID>MultilineLambdaItParameter:TxHistorySubscriber.kt$TxHistorySubscriber${ SetTxHistoryCountErrorTransformer( userWallet = userWallet, error = it, pendingTransactions = status.value.pendingTransactions, clickIntents = clickIntents, ) }</ID> <ID>MultilineLambdaItParameter:TxHistorySubscriber.kt$TxHistorySubscriber${ SetTxHistoryCountErrorTransformer( userWallet = userWallet, error = it, pendingTransactions = status.value.pendingTransactions, clickIntents = clickIntents, ) }</ID>