Updated on 2026-08-14

This commit is contained in:
Tangem 2026-02-11 17:48:20 +05:00
parent 6ed1946ac3
commit aac48015b3
88 changed files with 335 additions and 239 deletions

View file

@ -48,7 +48,6 @@ class AccountPortfolioItemUMConverter(
) )
UserWalletItemUM.Information.Loaded(text) UserWalletItemUM.Information.Loaded(text)
} }
is Account.Payment -> TODO("[REDACTED_JIRA]")
} }
private fun getImageState(account: Account.CryptoPortfolio) = when (account) { private fun getImageState(account: Account.CryptoPortfolio) = when (account) {
@ -56,7 +55,6 @@ class AccountPortfolioItemUMConverter(
name = account.accountName.toUM().value, name = account.accountName.toUM().value,
icon = CryptoPortfolioIconConverter.convert(account.icon), icon = CryptoPortfolioIconConverter.convert(account.icon),
) )
is Account.Payment -> TODO("[REDACTED_JIRA]")
} }
private fun getBalanceInfo(): UserWalletItemUM.Balance { private fun getBalanceInfo(): UserWalletItemUM.Balance {

View file

@ -82,7 +82,7 @@ fun PortfolioSelectRow(
@Immutable @Immutable
data class PortfolioSelectUM( data class PortfolioSelectUM(
val icon: AccountIconUM.CryptoPortfolio?, val icon: AccountIconUM?,
val name: TextReference, val name: TextReference,
val isAccountMode: Boolean, val isAccountMode: Boolean,
val isMultiChoice: Boolean, val isMultiChoice: Boolean,

View file

@ -1,5 +1,6 @@
package com.tangem.common.ui.amountScreen.converters package com.tangem.common.ui.amountScreen.converters
import com.tangem.common.ui.account.AccountIconUM
import com.tangem.common.ui.account.AccountTitleUM import com.tangem.common.ui.account.AccountTitleUM
import com.tangem.common.ui.account.CryptoPortfolioIconConverter import com.tangem.common.ui.account.CryptoPortfolioIconConverter
import com.tangem.common.ui.account.toUM import com.tangem.common.ui.account.toUM
@ -11,12 +12,12 @@ class AmountAccountConverter(
private val prefixText: TextReference, private val prefixText: TextReference,
private val isAccountsMode: Boolean, private val isAccountsMode: Boolean,
private val walletTitle: TextReference, private val walletTitle: TextReference,
) : Converter<Account.CryptoPortfolio?, AccountTitleUM> { ) : Converter<Account?, AccountTitleUM> {
override fun convert(value: Account.CryptoPortfolio?): AccountTitleUM { override fun convert(value: Account?): AccountTitleUM {
return if (value != null && isAccountsMode) { return if (value != null && isAccountsMode) {
AccountTitleUM.Account( AccountTitleUM.Account(
name = value.accountName.toUM().value, name = value.accountName.toUM().value,
icon = CryptoPortfolioIconConverter.convert(value.icon), icon = getAccountIcon(account = value),
prefixText = prefixText, prefixText = prefixText,
) )
} else { } else {
@ -25,4 +26,11 @@ class AmountAccountConverter(
) )
} }
} }
private fun getAccountIcon(account: Account): AccountIconUM {
return when (account) {
is Account.CryptoPortfolio -> CryptoPortfolioIconConverter.convert(account.icon)
is Account.Payment -> AccountIconUM.Payment
}
}
} }

View file

@ -33,10 +33,10 @@ internal class DefaultSingleAccountProducer @AssistedInject constructor(
private val dispatchers: CoroutineDispatcherProvider, private val dispatchers: CoroutineDispatcherProvider,
) : SingleAccountProducer { ) : SingleAccountProducer {
override val fallback: Option<Account.CryptoPortfolio> override val fallback: Option<Account>
get() = none() get() = none()
override fun produce(): Flow<Account.CryptoPortfolio> { override fun produce(): Flow<Account> {
return singleAccountListSupplier( return singleAccountListSupplier(
params = SingleAccountListProducer.Params(userWalletId = params.accountId.userWalletId), params = SingleAccountListProducer.Params(userWalletId = params.accountId.userWalletId),
) )

View file

@ -19,6 +19,7 @@ import com.tangem.datasource.api.tangemTech.models.account.WalletAccountDTO
import com.tangem.datasource.local.datastore.RuntimeStateStore import com.tangem.datasource.local.datastore.RuntimeStateStore
import com.tangem.domain.account.models.AccountList import com.tangem.domain.account.models.AccountList
import com.tangem.domain.account.models.ArchivedAccount import com.tangem.domain.account.models.ArchivedAccount
import com.tangem.domain.models.account.Account
import com.tangem.domain.models.account.Account.CryptoPortfolio import com.tangem.domain.models.account.Account.CryptoPortfolio
import com.tangem.domain.models.account.AccountId import com.tangem.domain.models.account.AccountId
import com.tangem.domain.models.account.AccountName import com.tangem.domain.models.account.AccountName

View file

@ -60,8 +60,8 @@ internal class DefaultSwapTransactionRepository(
userWalletId: UserWalletId, userWalletId: UserWalletId,
fromCryptoCurrency: CryptoCurrency, fromCryptoCurrency: CryptoCurrency,
toCryptoCurrency: CryptoCurrency, toCryptoCurrency: CryptoCurrency,
fromAccount: Account.CryptoPortfolio?, fromAccount: Account?,
toAccount: Account.CryptoPortfolio?, toAccount: Account?,
transaction: SwapTransactionModel, transaction: SwapTransactionModel,
) { ) {
transaction.status?.let { swapTxList -> transaction.status?.let { swapTxList ->
@ -244,8 +244,8 @@ internal class DefaultSwapTransactionRepository(
userWalletId: UserWalletId, userWalletId: UserWalletId,
fromCryptoCurrency: CryptoCurrency, fromCryptoCurrency: CryptoCurrency,
toCryptoCurrency: CryptoCurrency, toCryptoCurrency: CryptoCurrency,
fromAccount: Account.CryptoPortfolio?, fromAccount: Account?,
toAccount: Account.CryptoPortfolio?, toAccount: Account?,
transactions: List<SwapTransactionDTO>, transactions: List<SwapTransactionDTO>,
): List<SwapTransactionListDTO> { ): List<SwapTransactionListDTO> {
return addOrReplace( return addOrReplace(

View file

@ -101,8 +101,8 @@ internal class SavedSwapTransactionListConverter(
userWalletId: UserWalletId, userWalletId: UserWalletId,
fromCryptoCurrency: CryptoCurrency, fromCryptoCurrency: CryptoCurrency,
toCryptoCurrency: CryptoCurrency, toCryptoCurrency: CryptoCurrency,
fromAccount: Account.CryptoPortfolio?, fromAccount: Account?,
toAccount: Account.CryptoPortfolio?, toAccount: Account?,
tokenTransactions: List<SwapTransactionDTO>, tokenTransactions: List<SwapTransactionDTO>,
) = SwapTransactionListDTO( ) = SwapTransactionListDTO(
userWalletId = userWalletId.stringValue, userWalletId = userWalletId.stringValue,

View file

@ -9,6 +9,7 @@ import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.data.walletconnect.utils.* import com.tangem.data.walletconnect.utils.*
import com.tangem.datasource.local.walletconnect.WalletConnectStore import com.tangem.datasource.local.walletconnect.WalletConnectStore
import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles
import com.tangem.domain.models.account.Account
import com.tangem.domain.models.account.AccountId import com.tangem.domain.models.account.AccountId
import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.walletconnect.WcAnalyticEvents import com.tangem.domain.walletconnect.WcAnalyticEvents
@ -116,7 +117,7 @@ internal class DefaultWcSessionsManager(
val wcSessions = savedPending.plus(inStore).mapNotNull { storeSession -> val wcSessions = savedPending.plus(inStore).mapNotNull { storeSession ->
val wallet = wallets.find { it.walletId == storeSession.walletId } ?: return@mapNotNull null val wallet = wallets.find { it.walletId == storeSession.walletId } ?: return@mapNotNull null
val sdkSession = inSdk.find { it.topic == storeSession.topic } ?: return@mapNotNull null val sdkSession = inSdk.find { it.topic == storeSession.topic } ?: return@mapNotNull null
val account = storeSession.accountId?.let { wcNetworksConverter.getAccount(it) } val account = storeSession.accountId?.let { wcNetworksConverter.getAccount(it) } as? Account.CryptoPortfolio
if (accountsFeatureToggles.isFeatureEnabled && account == null) { if (accountsFeatureToggles.isFeatureEnabled && account == null) {
return@mapNotNull null return@mapNotNull null
} }

View file

@ -5,7 +5,6 @@ import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.data.walletconnect.sign.SignStateConverter.toPreSign import com.tangem.data.walletconnect.sign.SignStateConverter.toPreSign
import com.tangem.data.walletconnect.sign.SignStateConverter.toResult import com.tangem.data.walletconnect.sign.SignStateConverter.toResult
import com.tangem.data.walletconnect.sign.SignStateConverter.toSigning import com.tangem.data.walletconnect.sign.SignStateConverter.toSigning
import com.tangem.domain.models.account.derivationIndex
import com.tangem.domain.walletconnect.WcAnalyticEvents import com.tangem.domain.walletconnect.WcAnalyticEvents
import com.tangem.domain.walletconnect.model.WcRequestError import com.tangem.domain.walletconnect.model.WcRequestError
import com.tangem.domain.walletconnect.model.WcRequestError.Companion.code import com.tangem.domain.walletconnect.model.WcRequestError.Companion.code

View file

@ -13,6 +13,7 @@ import com.tangem.domain.account.supplier.SingleAccountSupplier
import com.tangem.domain.models.account.Account import com.tangem.domain.models.account.Account
import com.tangem.domain.models.account.AccountId import com.tangem.domain.models.account.AccountId
import com.tangem.domain.models.account.AccountStatus import com.tangem.domain.models.account.AccountStatus
import com.tangem.domain.models.account.filterCryptoPortfolio
import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.network.Network import com.tangem.domain.models.network.Network
import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.models.wallet.UserWallet
@ -146,10 +147,12 @@ internal class WcNetworksConverter @Inject constructor(
.filterIsInstance<CryptoCurrency.Coin>().map(CryptoCurrency.Coin::network) .filterIsInstance<CryptoCurrency.Coin>().map(CryptoCurrency.Coin::network)
} }
private suspend fun getAccountStatus(accountId: AccountId): AccountStatus? { private suspend fun getAccountStatus(accountId: AccountId): AccountStatus.CryptoPortfolio? {
return singleAccountStatusListSupplier.getSyncOrNull( return singleAccountStatusListSupplier.getSyncOrNull(
SingleAccountStatusListProducer.Params(accountId.userWalletId), SingleAccountStatusListProducer.Params(accountId.userWalletId),
)?.accountStatuses?.find { it.account.accountId == accountId } )?.accountStatuses
?.filterCryptoPortfolio()
?.find { it.account.accountId == accountId }
} }
suspend fun getAccountNetworks(accountId: AccountId): List<Network> { suspend fun getAccountNetworks(accountId: AccountId): List<Network> {

View file

@ -5,6 +5,7 @@ import com.tangem.domain.models.TokensGroupType
import com.tangem.domain.models.TokensSortType import com.tangem.domain.models.TokensSortType
import com.tangem.domain.models.TotalFiatBalance import com.tangem.domain.models.TotalFiatBalance
import com.tangem.domain.models.account.AccountStatus import com.tangem.domain.models.account.AccountStatus
import com.tangem.domain.models.account.filterCryptoPortfolio
import com.tangem.domain.models.currency.CryptoCurrencyStatus import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.models.wallet.UserWalletId import com.tangem.domain.models.wallet.UserWalletId
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@ -33,13 +34,16 @@ data class AccountStatusList(
) { ) {
val mainAccount: AccountStatus.CryptoPortfolio val mainAccount: AccountStatus.CryptoPortfolio
get() = accountStatuses.first { accountStatus -> get() = accountStatuses
when (accountStatus) { .filterCryptoPortfolio()
is AccountStatus.CryptoPortfolio -> accountStatus.account.isMainAccount .first { accountStatus ->
when (accountStatus) {
is AccountStatus.CryptoPortfolio -> accountStatus.account.isMainAccount
}
} }
} as AccountStatus.CryptoPortfolio
fun flattenCurrencies(): List<CryptoCurrencyStatus> = accountStatuses fun flattenCurrencies(): List<CryptoCurrencyStatus> = accountStatuses
.filterCryptoPortfolio()
.map { accountStatus -> accountStatus.flattenCurrencies() } .map { accountStatus -> accountStatus.flattenCurrencies() }
.flatten() .flatten()

View file

@ -5,10 +5,10 @@ import com.tangem.domain.models.account.Account
import com.tangem.domain.models.account.AccountId import com.tangem.domain.models.account.AccountId
/** /**
* Produces a flow of [Account.CryptoPortfolio] for a single account identified by [Params.accountId]. * Produces a flow of [Account] for a single account identified by [Params.accountId].
* The flow emits updates whenever the account's portfolio changes. * The flow emits updates whenever the account's portfolio changes.
*/ */
interface SingleAccountProducer : FlowProducer<Account.CryptoPortfolio> { interface SingleAccountProducer : FlowProducer<Account> {
data class Params(val accountId: AccountId) data class Params(val accountId: AccountId)

View file

@ -28,7 +28,7 @@ interface AccountsCRUDRepository {
* Retrieves a specific account by its unique identifier * Retrieves a specific account by its unique identifier
* *
* @param accountId the unique identifier of the account * @param accountId the unique identifier of the account
* @return an [Option] containing the [Account.CryptoPortfolio] if found, or `Option.None` if not * @return an [Option] containing the [Account] if found, or `Option.None` if not
*/ */
suspend fun getAccountSync(accountId: AccountId): Option<Account.CryptoPortfolio> suspend fun getAccountSync(accountId: AccountId): Option<Account.CryptoPortfolio>

View file

@ -3,9 +3,12 @@ package com.tangem.domain.account.supplier
import com.tangem.domain.account.producer.SingleAccountProducer import com.tangem.domain.account.producer.SingleAccountProducer
import com.tangem.domain.core.flow.FlowCachingSupplier import com.tangem.domain.core.flow.FlowCachingSupplier
import com.tangem.domain.models.account.Account import com.tangem.domain.models.account.Account
import com.tangem.domain.models.account.AccountId
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.filterIsInstance
/** /**
* Supplies instances of [SingleAccountProducer] that produce flows of [Account.CryptoPortfolio] * Supplies instances of [SingleAccountProducer] that produce flows of [Account]
* for individual accounts. Each producer is uniquely identified by its [SingleAccountProducer.Params]. * for individual accounts. Each producer is uniquely identified by its [SingleAccountProducer.Params].
* *
* @property factory A factory to create instances of [SingleAccountProducer]. * @property factory A factory to create instances of [SingleAccountProducer].
@ -14,4 +17,9 @@ import com.tangem.domain.models.account.Account
abstract class SingleAccountSupplier( abstract class SingleAccountSupplier(
override val factory: SingleAccountProducer.Factory, override val factory: SingleAccountProducer.Factory,
override val keyCreator: (SingleAccountProducer.Params) -> String, override val keyCreator: (SingleAccountProducer.Params) -> String,
) : FlowCachingSupplier<SingleAccountProducer, SingleAccountProducer.Params, Account.CryptoPortfolio>() ) : FlowCachingSupplier<SingleAccountProducer, SingleAccountProducer.Params, Account>() {
fun filterPaymentAccount(accountId: AccountId): Flow<Account.Payment> {
return invoke(params = SingleAccountProducer.Params(accountId)).filterIsInstance()
}
}

View file

@ -294,6 +294,7 @@ internal class DefaultSingleAccountStatusListProducer @AssistedInject constructo
return map { accountStatus -> return map { accountStatus ->
when (accountStatus) { when (accountStatus) {
is AccountStatus.CryptoPortfolio -> accountStatus.tokenList.totalFiatBalance is AccountStatus.CryptoPortfolio -> accountStatus.tokenList.totalFiatBalance
is AccountStatus.Payment -> accountStatus.totalFiatBalance
} }
} }
} }

View file

@ -9,7 +9,7 @@ import com.tangem.domain.account.repository.AccountsCRUDRepository
import com.tangem.domain.account.status.producer.SingleAccountStatusListProducer import com.tangem.domain.account.status.producer.SingleAccountStatusListProducer
import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier
import com.tangem.domain.models.account.AccountId import com.tangem.domain.models.account.AccountId
import com.tangem.domain.models.account.AccountStatus import com.tangem.domain.models.account.filterCryptoPortfolio
import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.wallet.UserWalletId import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.referral.ReferralRepository import com.tangem.domain.referral.ReferralRepository
@ -68,7 +68,7 @@ class ArchiveCryptoPortfolioUseCase(
val account = accountStatusList.accountStatuses val account = accountStatusList.accountStatuses
.asSequence() .asSequence()
.filterIsInstance<AccountStatus.CryptoPortfolio>() .filterCryptoPortfolio()
.firstOrNull { it.accountId == accountId } .firstOrNull { it.accountId == accountId }
ensureNotNull(account) { ensureNotNull(account) {

View file

@ -48,10 +48,12 @@ class ToggleTokenListGroupingUseCaseV2(
account.copy(tokenList = account.tokenList.reverseGroupType()) account.copy(tokenList = account.tokenList.reverseGroupType())
} }
val updatedCryptoAccount =
updatedAccountList.firstOrNull { it is AccountStatus.CryptoPortfolio } as? AccountStatus.CryptoPortfolio
accountStatusList.copy( accountStatusList.copy(
accountStatuses = updatedAccountList, accountStatuses = updatedAccountList,
groupType = when (updatedAccountList.firstOrNull()?.getCryptoTokenList()) { groupType = when (updatedCryptoAccount?.tokenList) {
is TokenList.GroupedByNetwork -> TokensGroupType.NETWORK is TokenList.GroupedByNetwork -> TokensGroupType.NETWORK
is TokenList.Ungrouped -> TokensGroupType.NONE is TokenList.Ungrouped -> TokensGroupType.NONE
else -> accountStatusList.groupType else -> accountStatusList.groupType

View file

@ -7,6 +7,7 @@ import com.tangem.domain.account.status.model.AccountCryptoCurrencyStatuses
import com.tangem.domain.models.account.Account import com.tangem.domain.models.account.Account
import com.tangem.domain.models.account.AccountStatus import com.tangem.domain.models.account.AccountStatus
import com.tangem.domain.models.account.DerivationIndex import com.tangem.domain.models.account.DerivationIndex
import com.tangem.domain.models.account.filterCryptoPortfolio
import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.network.Network import com.tangem.domain.models.network.Network
import com.tangem.lib.crypto.derivation.AccountNodeRecognizer import com.tangem.lib.crypto.derivation.AccountNodeRecognizer
@ -49,7 +50,7 @@ internal object AccountCryptoCurrencyStatusFinder {
): AccountCryptoCurrencyStatus? { ): AccountCryptoCurrencyStatus? {
return accountStatusList.getExpectedAccountStatuses(network) return accountStatusList.getExpectedAccountStatuses(network)
.asSequence() .asSequence()
.filterIsInstance<AccountStatus.CryptoPortfolio>() .filterCryptoPortfolio()
.mapNotNull { accountStatus -> .mapNotNull { accountStatus ->
val status = accountStatus.flattenCurrencies().firstOrNull { it.currency.id == currencyId } val status = accountStatus.flattenCurrencies().firstOrNull { it.currency.id == currencyId }
?: return@mapNotNull null ?: return@mapNotNull null
@ -78,7 +79,7 @@ internal object AccountCryptoCurrencyStatusFinder {
return accountStatusList.getExpectedAccountStatuses(networks) return accountStatusList.getExpectedAccountStatuses(networks)
.asSequence() .asSequence()
.filterIsInstance<AccountStatus.CryptoPortfolio>() .filterCryptoPortfolio()
.associate { accountStatus -> .associate { accountStatus ->
val statuses = accountStatus.flattenCurrencies() val statuses = accountStatus.flattenCurrencies()
.filter { it.currency.id in currencyIds } .filter { it.currency.id in currencyIds }
@ -108,7 +109,7 @@ internal object AccountCryptoCurrencyStatusFinder {
derivationPath = derivationPath, derivationPath = derivationPath,
) )
.asSequence() .asSequence()
.filterIsInstance<AccountStatus.CryptoPortfolio>() .filterCryptoPortfolio()
.mapNotNull { accountStatus -> .mapNotNull { accountStatus ->
val status = accountStatus.flattenCurrencies().firstOrNull { val status = accountStatus.flattenCurrencies().firstOrNull {
val currency = it.currency val currency = it.currency
@ -156,8 +157,8 @@ internal object AccountCryptoCurrencyStatusFinder {
DerivationIndex.Main.value -> listOf(mainAccount) DerivationIndex.Main.value -> listOf(mainAccount)
// currency only in the account with specific derivation index or in the main account // currency only in the account with specific derivation index or in the main account
else -> { else -> {
val accountStatus = accountStatuses.firstOrNull { val accountStatus = accountStatuses.firstOrNull { accountStatus ->
val cryptoPortfolio = it.account as? Account.CryptoPortfolio ?: return@firstOrNull false val cryptoPortfolio = accountStatus.account as? Account.CryptoPortfolio ?: return@firstOrNull false
cryptoPortfolio.derivationIndex.value == possibleAccountIndex cryptoPortfolio.derivationIndex.value == possibleAccountIndex
} }
@ -172,8 +173,8 @@ internal object AccountCryptoCurrencyStatusFinder {
if (possibleAccountIndexes.isEmpty()) return this@getExpectedAccountStatuses.accountStatuses if (possibleAccountIndexes.isEmpty()) return this@getExpectedAccountStatuses.accountStatuses
val accountStatuses = this@getExpectedAccountStatuses.accountStatuses.filter { val accountStatuses = this@getExpectedAccountStatuses.accountStatuses.filter { accountStatus ->
val cryptoPortfolio = it.account as? Account.CryptoPortfolio ?: return@filter false val cryptoPortfolio = accountStatus.account as? Account.CryptoPortfolio ?: return@filter false
cryptoPortfolio.derivationIndex.value in possibleAccountIndexes cryptoPortfolio.derivationIndex.value in possibleAccountIndexes
} }

View file

@ -109,7 +109,7 @@ sealed interface Account {
raise(AccountNameError(cause = it)) raise(AccountNameError(cause = it))
} }
val derivationIndex = DerivationIndex(value = derivationIndex).getOrElse { val index = DerivationIndex(value = derivationIndex).getOrElse {
raise(DerivationIndexError(cause = it)) raise(DerivationIndexError(cause = it))
} }
@ -117,7 +117,7 @@ sealed interface Account {
accountId = accountId, accountId = accountId,
accountName = accountName, accountName = accountName,
icon = icon, icon = icon,
derivationIndex = derivationIndex, derivationIndex = index,
cryptoCurrencies = cryptoCurrencies, cryptoCurrencies = cryptoCurrencies,
) )
} }
@ -175,11 +175,12 @@ sealed interface Account {
} }
} }
class Payment : Account { @Serializable
override val accountId: AccountId data class Payment(
get() = TODO("Not yet implemented") override val accountId: AccountId,
override val accountName: AccountName override val accountName: AccountName,
get() = TODO("Not yet implemented") val cryptoCurrencies: List<CryptoCurrency>,
) : Account {
init { init {
error("Not yet implemented") error("Not yet implemented")
@ -190,5 +191,5 @@ sealed interface Account {
val Account.derivationIndex: DerivationIndex? val Account.derivationIndex: DerivationIndex?
get() = when (this) { get() = when (this) {
is Account.CryptoPortfolio -> derivationIndex is Account.CryptoPortfolio -> derivationIndex
is Account.Payment -> TODO("[REDACTED_JIRA]") is Account.Payment -> null
} }

View file

@ -71,5 +71,9 @@ data class AccountId private constructor(
return AccountId(value = value, userWalletId = userWalletId) return AccountId(value = value, userWalletId = userWalletId)
} }
fun forPaymentAccount(userWalletId: UserWalletId): AccountId {
return AccountId(value = "payment_$userWalletId", userWalletId = userWalletId)
}
} }
} }

View file

@ -1,6 +1,7 @@
package com.tangem.domain.models.account package com.tangem.domain.models.account
import com.tangem.domain.core.lce.Lce import com.tangem.domain.core.lce.Lce
import com.tangem.domain.models.TotalFiatBalance
import com.tangem.domain.models.currency.CryptoCurrencyStatus import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.models.quote.PriceChange import com.tangem.domain.models.quote.PriceChange
import com.tangem.domain.models.tokenlist.TokenList import com.tangem.domain.models.tokenlist.TokenList
@ -33,13 +34,23 @@ sealed interface AccountStatus {
override val account: Account.CryptoPortfolio, override val account: Account.CryptoPortfolio,
val tokenList: TokenList, val tokenList: TokenList,
val priceChangeLce: Lce<Unit, PriceChange>, val priceChangeLce: Lce<Unit, PriceChange>,
) : AccountStatus {
fun flattenCurrencies(): List<CryptoCurrencyStatus> {
return tokenList.flattenCurrencies()
}
}
@Serializable
data class Payment(
override val account: Account.Payment,
val totalFiatBalance: TotalFiatBalance,
) : AccountStatus ) : AccountStatus
}
fun flattenCurrencies(): List<CryptoCurrencyStatus> = when (this) { fun Iterable<AccountStatus>.filterCryptoPortfolio(): List<AccountStatus.CryptoPortfolio> {
is CryptoPortfolio -> tokenList.flattenCurrencies() return filterIsInstance<AccountStatus.CryptoPortfolio>()
} }
fun getCryptoTokenList(): TokenList = when (this) { fun Sequence<AccountStatus>.filterCryptoPortfolio(): Sequence<AccountStatus.CryptoPortfolio> {
is CryptoPortfolio -> tokenList return filterIsInstance<AccountStatus.CryptoPortfolio>()
}
} }

View file

@ -14,8 +14,8 @@ data class SwapTransactionListModel(
val toCryptoCurrencyId: String, val toCryptoCurrencyId: String,
val fromCryptoCurrency: CryptoCurrency, val fromCryptoCurrency: CryptoCurrency,
val toCryptoCurrency: CryptoCurrency, val toCryptoCurrency: CryptoCurrency,
val fromAccount: Account.CryptoPortfolio?, val fromAccount: Account?,
val toAccount: Account.CryptoPortfolio?, val toAccount: Account?,
val transactions: List<SwapTransactionModel>, val transactions: List<SwapTransactionModel>,
) )

View file

@ -30,8 +30,8 @@ interface SwapTransactionRepository {
userWalletId: UserWalletId, userWalletId: UserWalletId,
fromCryptoCurrency: CryptoCurrency, fromCryptoCurrency: CryptoCurrency,
toCryptoCurrency: CryptoCurrency, toCryptoCurrency: CryptoCurrency,
fromAccount: Account.CryptoPortfolio?, fromAccount: Account?,
toAccount: Account.CryptoPortfolio?, toAccount: Account?,
transaction: SwapTransactionModel, transaction: SwapTransactionModel,
) )

View file

@ -22,8 +22,8 @@ class SwapTransactionSentUseCase(
userWallet: UserWallet, userWallet: UserWallet,
fromCryptoCurrencyStatus: CryptoCurrencyStatus, fromCryptoCurrencyStatus: CryptoCurrencyStatus,
toCryptoCurrencyStatus: CryptoCurrencyStatus, toCryptoCurrencyStatus: CryptoCurrencyStatus,
fromAccount: Account.CryptoPortfolio?, fromAccount: Account?,
toAccount: Account.CryptoPortfolio?, toAccount: Account?,
swapDataTransactionModel: SwapDataTransactionModel, swapDataTransactionModel: SwapDataTransactionModel,
provider: ExpressProvider, provider: ExpressProvider,
txHash: String, txHash: String,

View file

@ -8,7 +8,7 @@ import com.tangem.domain.models.wallet.UserWallet
data class WcSession( data class WcSession(
val wallet: UserWallet, val wallet: UserWallet,
val account: Account?, val account: Account.CryptoPortfolio?,
val networks: Set<Network>, val networks: Set<Network>,
val sdkModel: WcSdkSession, val sdkModel: WcSdkSession,
val securityStatus: CheckDAppResult, val securityStatus: CheckDAppResult,

View file

@ -60,5 +60,7 @@ interface PortfolioSelectorController {
suspend fun isAccountModeSync(): Boolean suspend fun isAccountModeSync(): Boolean
fun selectAccount(accountId: AccountId?) fun selectAccount(accountId: AccountId?)
fun selectedAccountWithData(portfolioFetcher: PortfolioFetcher): Flow<Pair<UserWallet, AccountStatus>?> fun selectedAccountWithData(
portfolioFetcher: PortfolioFetcher,
): Flow<Pair<UserWallet, AccountStatus.CryptoPortfolio>?>
} }

View file

@ -3,6 +3,7 @@ package com.tangem.features.account.selector
import com.tangem.domain.account.usecase.IsAccountsModeEnabledUseCase import com.tangem.domain.account.usecase.IsAccountsModeEnabledUseCase
import com.tangem.domain.models.account.AccountId import com.tangem.domain.models.account.AccountId
import com.tangem.domain.models.account.AccountStatus import com.tangem.domain.models.account.AccountStatus
import com.tangem.domain.models.account.filterCryptoPortfolio
import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.models.wallet.UserWallet
import com.tangem.features.account.PortfolioFetcher import com.tangem.features.account.PortfolioFetcher
import com.tangem.features.account.PortfolioSelectorController import com.tangem.features.account.PortfolioSelectorController
@ -35,21 +36,23 @@ internal class DefaultPortfolioSelectorController @Inject constructor(
_selectedAccount.tryEmit(accountId) _selectedAccount.tryEmit(accountId)
} }
override fun selectedAccountWithData(portfolioFetcher: PortfolioFetcher): Flow<Pair<UserWallet, AccountStatus>?> = override fun selectedAccountWithData(
combine( portfolioFetcher: PortfolioFetcher,
flow = _selectedAccount, ): Flow<Pair<UserWallet, AccountStatus.CryptoPortfolio>?> = combine(
flow2 = portfolioFetcher.data, flow = _selectedAccount,
transform = { accountId, data -> flow2 = portfolioFetcher.data,
accountId ?: return@combine null transform = { accountId, data ->
var result: Pair<UserWallet, AccountStatus>? = null accountId ?: return@combine null
var result: Pair<UserWallet, AccountStatus.CryptoPortfolio>? = null
data.balances.forEach { wallet, balance -> data.balances.forEach { wallet, balance ->
val accountStatuses = balance.accountsBalance.accountStatuses val accountStatuses = balance.accountsBalance.accountStatuses
.find { accountId == it.account.accountId } .filterCryptoPortfolio()
if (accountStatuses != null) result = balance.userWallet to accountStatuses .find { accountId == it.account.accountId }
} if (accountStatuses != null) result = balance.userWallet to accountStatuses
}
return@combine result return@combine result
}, },
) )
} }

View file

@ -184,6 +184,7 @@ internal class PortfolioSelectorModel @Inject constructor(
val account = accountStatus.account val account = accountStatus.account
val accountBalance = when (accountStatus) { val accountBalance = when (accountStatus) {
is AccountStatus.CryptoPortfolio -> accountStatus.tokenList.totalFiatBalance is AccountStatus.CryptoPortfolio -> accountStatus.tokenList.totalFiatBalance
is AccountStatus.Payment -> accountStatus.totalFiatBalance
} }
val accountItemUM = AccountPortfolioItemUMConverter( val accountItemUM = AccountPortfolioItemUMConverter(
onClick = { selectorController.selectAccount(account.accountId) }, onClick = { selectorController.selectAccount(account.accountId) },

View file

@ -325,6 +325,7 @@ internal class AddToPortfolioModel @Inject constructor(
): CryptoCurrency? { ): CryptoCurrency? {
val accountIndex = when (val accountStatus = account.account) { val accountIndex = when (val accountStatus = account.account) {
is AccountStatus.CryptoPortfolio -> accountStatus.account.derivationIndex is AccountStatus.CryptoPortfolio -> accountStatus.account.derivationIndex
is AccountStatus.Payment -> TODO("[REDACTED_JIRA]")
} }
return getTokenMarketCryptoCurrency( return getTokenMarketCryptoCurrency(
userWalletId = userWallet.walletId, userWalletId = userWallet.walletId,

View file

@ -174,6 +174,7 @@ internal class AddToPortfolioPreselectedDataModel @Inject constructor(
val availableToAddAccounts = accounts.mapNotNull { accountStatus -> val availableToAddAccounts = accounts.mapNotNull { accountStatus ->
val accountIndex = when (accountStatus) { val accountIndex = when (accountStatus) {
is AccountStatus.CryptoPortfolio -> accountStatus.account.derivationIndex is AccountStatus.CryptoPortfolio -> accountStatus.account.derivationIndex
is AccountStatus.Payment -> TODO("[REDACTED_JIRA]")
} }
val cryptoCurrency = getTokenMarketCryptoCurrency( val cryptoCurrency = getTokenMarketCryptoCurrency(
@ -220,6 +221,7 @@ internal class AddToPortfolioPreselectedDataModel @Inject constructor(
): CryptoCurrency? { ): CryptoCurrency? {
val accountIndex = when (val accountStatus = account.account) { val accountIndex = when (val accountStatus = account.account) {
is AccountStatus.CryptoPortfolio -> accountStatus.account.derivationIndex is AccountStatus.CryptoPortfolio -> accountStatus.account.derivationIndex
is AccountStatus.Payment -> TODO("[REDACTED_JIRA]")
} }
return getTokenMarketCryptoCurrency( return getTokenMarketCryptoCurrency(
userWalletId = userWallet.walletId, userWalletId = userWallet.walletId,

View file

@ -13,7 +13,7 @@ import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.iconResId import com.tangem.core.ui.extensions.iconResId
import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.extensions.stringReference
import com.tangem.domain.models.account.AccountStatus import com.tangem.domain.models.account.AccountStatus.*
import com.tangem.features.feed.components.market.details.portfolio.add.SelectedNetwork import com.tangem.features.feed.components.market.details.portfolio.add.SelectedNetwork
import com.tangem.features.feed.components.market.details.portfolio.add.SelectedPortfolio import com.tangem.features.feed.components.market.details.portfolio.add.SelectedPortfolio
import com.tangem.features.feed.components.market.details.portfolio.add.impl.AddTokenComponent import com.tangem.features.feed.components.market.details.portfolio.add.impl.AddTokenComponent
@ -36,7 +36,7 @@ internal class AddTokenUiBuilder @Inject constructor(
} }
private fun createPortfolio(selectedPortfolio: SelectedPortfolio): PortfolioSelectUM { private fun createPortfolio(selectedPortfolio: SelectedPortfolio): PortfolioSelectUM {
val accountIcon: AccountIconUM.CryptoPortfolio? val accountIcon: AccountIconUM?
val portfolioName: TextReference val portfolioName: TextReference
when (selectedPortfolio.isAccountMode) { when (selectedPortfolio.isAccountMode) {
false -> { false -> {
@ -47,7 +47,8 @@ internal class AddTokenUiBuilder @Inject constructor(
val accountStatus = selectedPortfolio.account.account val accountStatus = selectedPortfolio.account.account
portfolioName = accountStatus.account.accountName.toUM().value portfolioName = accountStatus.account.accountName.toUM().value
accountIcon = when (accountStatus) { accountIcon = when (accountStatus) {
is AccountStatus.CryptoPortfolio -> CryptoPortfolioIconConverter.convert(accountStatus.account.icon) is CryptoPortfolio -> CryptoPortfolioIconConverter.convert(accountStatus.account.icon)
is Payment -> AccountIconUM.Payment
} }
} }
} }

View file

@ -202,6 +202,7 @@ internal class NewMarketsPortfolioDelegate @AssistedInject constructor(
val currencyId = status.currency.id.rawCurrencyId ?: return@filter false val currencyId = status.currency.id.rawCurrencyId ?: return@filter false
getTokenIdIfL2Network(currencyId.value) == currencyRawId.value getTokenIdIfL2Network(currencyId.value) == currencyRawId.value
} }
is AccountStatus.Payment -> TODO("[REDACTED_JIRA]")
} }
return accountStatuses.map { accountStatus -> return accountStatuses.map { accountStatus ->
AccountWithAdded( AccountWithAdded(

View file

@ -214,9 +214,10 @@ internal class CustomTokenSelectorModel @Inject constructor(
val accounts = singleAccountStatusListSupplier(mode.userWalletId) val accounts = singleAccountStatusListSupplier(mode.userWalletId)
.first().accountStatuses .first().accountStatuses
val accountStatus = accounts.find { val accountStatus = accounts.find { account ->
when (it) { when (account) {
is AccountStatus.CryptoPortfolio -> it.sameNodeAndNotMain() is AccountStatus.CryptoPortfolio -> account.sameNodeAndNotMain()
is AccountStatus.Payment -> TODO("[REDACTED_JIRA]")
} }
} }

View file

@ -12,6 +12,7 @@ import com.tangem.domain.managetokens.model.CurrencyUnsupportedState
import com.tangem.domain.managetokens.model.ManageTokensListConfig import com.tangem.domain.managetokens.model.ManageTokensListConfig
import com.tangem.domain.managetokens.model.ManagedCryptoCurrency import com.tangem.domain.managetokens.model.ManagedCryptoCurrency
import com.tangem.domain.managetokens.repository.CustomTokensRepository import com.tangem.domain.managetokens.repository.CustomTokensRepository
import com.tangem.domain.models.account.Account
import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.network.Network import com.tangem.domain.models.network.Network
import com.tangem.domain.models.wallet.UserWalletId import com.tangem.domain.models.wallet.UserWalletId
@ -88,7 +89,7 @@ internal class ManageTokensUseCasesFacade @AssistedInject constructor(
val account = singleAccountSupplier.getSyncOrNull( val account = singleAccountSupplier.getSyncOrNull(
params = SingleAccountProducer.Params(accountId = mode.accountId), params = SingleAccountProducer.Params(accountId = mode.accountId),
) ) as? Account.CryptoPortfolio
?: return IllegalStateException("Account not found").left() ?: return IllegalStateException("Account not found").left()
(account.cryptoCurrencies + added - removed).any { (account.cryptoCurrencies + added - removed).any {

View file

@ -315,6 +315,7 @@ internal class AddToPortfolioModel @Inject constructor(
): CryptoCurrency? { ): CryptoCurrency? {
val accountIndex = when (account.account) { val accountIndex = when (account.account) {
is AccountStatus.CryptoPortfolio -> account.account.account.derivationIndex is AccountStatus.CryptoPortfolio -> account.account.account.derivationIndex
is AccountStatus.Payment -> TODO("[REDACTED_JIRA]")
} }
return getTokenMarketCryptoCurrency( return getTokenMarketCryptoCurrency(
userWalletId = userWallet.walletId, userWalletId = userWallet.walletId,

View file

@ -13,7 +13,7 @@ import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.iconResId import com.tangem.core.ui.extensions.iconResId
import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.extensions.stringReference
import com.tangem.domain.models.account.AccountStatus import com.tangem.domain.models.account.AccountStatus.*
import com.tangem.features.markets.impl.R import com.tangem.features.markets.impl.R
import com.tangem.features.markets.portfolio.add.api.SelectedNetwork import com.tangem.features.markets.portfolio.add.api.SelectedNetwork
import com.tangem.features.markets.portfolio.add.api.SelectedPortfolio import com.tangem.features.markets.portfolio.add.api.SelectedPortfolio
@ -36,7 +36,7 @@ internal class AddTokenUiBuilder @Inject constructor(
} }
private fun createPortfolio(selectedPortfolio: SelectedPortfolio): PortfolioSelectUM { private fun createPortfolio(selectedPortfolio: SelectedPortfolio): PortfolioSelectUM {
val accountIcon: AccountIconUM.CryptoPortfolio? val accountIcon: AccountIconUM?
val portfolioName: TextReference val portfolioName: TextReference
when (selectedPortfolio.isAccountMode) { when (selectedPortfolio.isAccountMode) {
false -> { false -> {
@ -47,7 +47,8 @@ internal class AddTokenUiBuilder @Inject constructor(
val accountStatus = selectedPortfolio.account.account val accountStatus = selectedPortfolio.account.account
portfolioName = accountStatus.account.accountName.toUM().value portfolioName = accountStatus.account.accountName.toUM().value
accountIcon = when (accountStatus) { accountIcon = when (accountStatus) {
is AccountStatus.CryptoPortfolio -> CryptoPortfolioIconConverter.convert(accountStatus.account.icon) is CryptoPortfolio -> CryptoPortfolioIconConverter.convert(accountStatus.account.icon)
is Payment -> AccountIconUM.Payment
} }
} }
} }

View file

@ -203,6 +203,7 @@ internal class NewMarketsPortfolioDelegate @AssistedInject constructor(
val currencyId = status.currency.id.rawCurrencyId ?: return@filter false val currencyId = status.currency.id.rawCurrencyId ?: return@filter false
getTokenIdIfL2Network(currencyId.value) == currencyRawId.value getTokenIdIfL2Network(currencyId.value) == currencyRawId.value
} }
is AccountStatus.Payment -> TODO("[REDACTED_JIRA]")
} }
return accountStatuses.map { accountStatus -> return accountStatuses.map { accountStatus ->
AccountWithAdded( AccountWithAdded(

View file

@ -45,6 +45,7 @@ internal class HotCryptoPortfolioDataLoader @Inject constructor(
val accountsWithHotCrypto = walletAccounts.accountStatuses.map { accountStatus -> val accountsWithHotCrypto = walletAccounts.accountStatuses.map { accountStatus ->
val account: AccountStatus.CryptoPortfolio = when (accountStatus) { val account: AccountStatus.CryptoPortfolio = when (accountStatus) {
is AccountStatus.CryptoPortfolio -> accountStatus is AccountStatus.CryptoPortfolio -> accountStatus
is AccountStatus.Payment -> TODO("[REDACTED_JIRA]")
} }
val addedHotCrypto = mapOfAddedCurrencies[account.account].orEmpty() val addedHotCrypto = mapOfAddedCurrencies[account.account].orEmpty()
HotCryptoPortfolioData.Account( HotCryptoPortfolioData.Account(

View file

@ -37,7 +37,7 @@ internal class OnrampAddTokenUiBuilder @Inject constructor(
} }
private suspend fun createPortfolio(tokenToAdd: AddHotCryptoData): PortfolioSelectUM { private suspend fun createPortfolio(tokenToAdd: AddHotCryptoData): PortfolioSelectUM {
val accountIcon: AccountIconUM.CryptoPortfolio? val accountIcon: AccountIconUM?
val portfolioName: TextReference val portfolioName: TextReference
val isAccountMode = isAccountsModeEnabledUseCase.invokeSync() val isAccountMode = isAccountsModeEnabledUseCase.invokeSync()
when (isAccountMode) { when (isAccountMode) {
@ -50,6 +50,7 @@ internal class OnrampAddTokenUiBuilder @Inject constructor(
portfolioName = accountStatus.account.accountName.toUM().value portfolioName = accountStatus.account.accountName.toUM().value
accountIcon = when (accountStatus) { accountIcon = when (accountStatus) {
is AccountStatus.CryptoPortfolio -> CryptoPortfolioIconConverter.convert(accountStatus.account.icon) is AccountStatus.CryptoPortfolio -> CryptoPortfolioIconConverter.convert(accountStatus.account.icon)
is AccountStatus.Payment -> AccountIconUM.Payment
} }
} }
} }

View file

@ -23,7 +23,9 @@ internal class LoadingAccountTokenItemConverter(
).convert(TotalFiatBalance.Failed), ).convert(TotalFiatBalance.Failed),
isExpanded = true, isExpanded = true,
isCollapsable = false, isCollapsable = false,
tokens = currencies.flattenCurrencies().map(LoadingTokenListItemConverter::convert).toPersistentList(), tokens = currencies.flattenCurrencies()
.map { LoadingTokenListItemConverter.convert(it.currency) }
.toPersistentList(),
) )
} }
} }

View file

@ -3,6 +3,7 @@ package com.tangem.features.onramp.swap.availablepairs.entity.converters
import com.tangem.core.ui.components.currency.icon.CurrencyIconState import com.tangem.core.ui.components.currency.icon.CurrencyIconState
import com.tangem.core.ui.components.token.state.TokenItemState import com.tangem.core.ui.components.token.state.TokenItemState
import com.tangem.core.ui.components.tokenlist.state.TokensListItemUM import com.tangem.core.ui.components.tokenlist.state.TokensListItemUM
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrencyStatus import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.utils.converter.Converter import com.tangem.utils.converter.Converter
@ -11,12 +12,12 @@ import com.tangem.utils.converter.Converter
* *
[REDACTED_AUTHOR] [REDACTED_AUTHOR]
*/ */
internal object LoadingTokenListItemConverter : Converter<CryptoCurrencyStatus, TokensListItemUM.Token> { internal object LoadingTokenListItemConverter : Converter<CryptoCurrency, TokensListItemUM.Token> {
override fun convert(value: CryptoCurrencyStatus): TokensListItemUM.Token { override fun convert(value: CryptoCurrency): TokensListItemUM.Token {
return TokensListItemUM.Token( return TokensListItemUM.Token(
state = TokenItemState.Loading( state = TokenItemState.Loading(
id = value.currency.id.value, id = value.id.value,
iconState = CurrencyIconState.Loading, iconState = CurrencyIconState.Loading,
titleState = TokenItemState.TitleState.Loading, titleState = TokenItemState.TitleState.Loading,
subtitleState = TokenItemState.SubtitleState.Loading, subtitleState = TokenItemState.SubtitleState.Loading,

View file

@ -18,7 +18,9 @@ internal class SetLoadingTokenItemsTransformer(
override fun transform(prevState: TokenListUM): TokenListUM { override fun transform(prevState: TokenListUM): TokenListUM {
return prevState.copy( return prevState.copy(
availableItems = LoadingTokenListItemConverter.convertList(input = statuses).toImmutableList(), availableItems = LoadingTokenListItemConverter.convertList(
input = statuses.map(CryptoCurrencyStatus::currency),
).toImmutableList(),
unavailableItems = persistentListOf(), unavailableItems = persistentListOf(),
warning = null, warning = null,
) )

View file

@ -21,6 +21,7 @@ import com.tangem.domain.core.utils.lceLoading
import com.tangem.domain.markets.GetMarketsTokenListFlowUseCase import com.tangem.domain.markets.GetMarketsTokenListFlowUseCase
import com.tangem.domain.models.account.Account import com.tangem.domain.models.account.Account
import com.tangem.domain.models.account.AccountStatus import com.tangem.domain.models.account.AccountStatus
import com.tangem.domain.models.account.filterCryptoPortfolio
import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrencyStatus import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.models.tokenlist.TokenList import com.tangem.domain.models.tokenlist.TokenList
@ -287,7 +288,7 @@ internal class AvailableSwapPairsModel @Inject constructor(
): TokenListUMTransformer { ): TokenListUMTransformer {
val (appCurrency, isBalanceHidden) = appCurrencyAndBalanceHiding val (appCurrency, isBalanceHidden) = appCurrencyAndBalanceHiding
val filterByQueryAccountList = accountList val filterByQueryAccountList: Map<Account.CryptoPortfolio, List<CryptoCurrencyStatus>> = accountList
.associate { accountStatus -> .associate { accountStatus ->
when (accountStatus) { when (accountStatus) {
is AccountStatus.CryptoPortfolio -> { is AccountStatus.CryptoPortfolio -> {
@ -300,6 +301,7 @@ internal class AvailableSwapPairsModel @Inject constructor(
accountStatus.account to statuses accountStatus.account to statuses
} }
is AccountStatus.Payment -> TODO("[REDACTED_JIRA]")
} }
} }
.filterValues { it.isNotEmpty() } .filterValues { it.isNotEmpty() }
@ -360,7 +362,7 @@ internal class AvailableSwapPairsModel @Inject constructor(
onRefresh = { onRefresh = {
modelScope.launch { modelScope.launch {
if (networkInfo != null) { if (networkInfo != null) {
accountList.filterIsInstance<AccountStatus.CryptoPortfolio>() accountList.filterCryptoPortfolio()
.forEach { (_, currencies) -> .forEach { (_, currencies) ->
updateAvailablePairs(networkInfo, currencies.flattenCurrencies()) updateAvailablePairs(networkInfo, currencies.flattenCurrencies())
} }
@ -384,7 +386,7 @@ internal class AvailableSwapPairsModel @Inject constructor(
val accountList = accountListFlow.firstOrNull() ?: return@collectLatest val accountList = accountListFlow.firstOrNull() ?: return@collectLatest
updateAvailablePairs( updateAvailablePairs(
networkInfo = networkInfo, networkInfo = networkInfo,
statuses = accountList.filterIsInstance<AccountStatus.CryptoPortfolio>() statuses = accountList.filterCryptoPortfolio()
.flatMap { accountStatus -> .flatMap { accountStatus ->
accountStatus.flattenCurrencies() accountStatus.flattenCurrencies()
}.toSet().toList(), }.toSet().toList(),

View file

@ -2,6 +2,8 @@ package com.tangem.features.onramp.tokenlist.entity.transformer
import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.models.account.AccountStatus import com.tangem.domain.models.account.AccountStatus
import com.tangem.domain.models.account.filterCryptoPortfolio
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.features.onramp.swap.availablepairs.entity.converters.LoadingAccountTokenItemConverter import com.tangem.features.onramp.swap.availablepairs.entity.converters.LoadingAccountTokenItemConverter
import com.tangem.features.onramp.swap.availablepairs.entity.converters.LoadingTokenListItemConverter import com.tangem.features.onramp.swap.availablepairs.entity.converters.LoadingTokenListItemConverter
import com.tangem.features.onramp.tokenlist.entity.TokenListUM import com.tangem.features.onramp.tokenlist.entity.TokenListUM
@ -22,6 +24,7 @@ internal class SetLoadingAccountTokenListTransformer(
val totalTokensCount = accountList.sumOf { account -> val totalTokensCount = accountList.sumOf { account ->
when (account) { when (account) {
is AccountStatus.CryptoPortfolio -> account.tokenList.flattenCurrencies().size is AccountStatus.CryptoPortfolio -> account.tokenList.flattenCurrencies().size
is AccountStatus.Payment -> TODO("[REDACTED_JIRA]")
} }
} }
@ -31,7 +34,7 @@ internal class SetLoadingAccountTokenListTransformer(
tokensListData = if (isAccountsMode) { tokensListData = if (isAccountsMode) {
TokenListUMData.AccountList( TokenListUMData.AccountList(
tokensList = accountListItemConverter.convertList( tokensList = accountListItemConverter.convertList(
accountList.filterIsInstance<AccountStatus.CryptoPortfolio>(), accountList.filterCryptoPortfolio(),
).toPersistentList(), ).toPersistentList(),
totalTokensCount = totalTokensCount, totalTokensCount = totalTokensCount,
) )
@ -40,8 +43,9 @@ internal class SetLoadingAccountTokenListTransformer(
tokensList = accountList.flatMap { account -> tokensList = accountList.flatMap { account ->
when (account) { when (account) {
is AccountStatus.CryptoPortfolio -> LoadingTokenListItemConverter.convertList( is AccountStatus.CryptoPortfolio -> LoadingTokenListItemConverter.convertList(
account.tokenList.flattenCurrencies(), account.tokenList.flattenCurrencies().map(CryptoCurrencyStatus::currency),
) )
is AccountStatus.Payment -> TODO("[REDACTED_JIRA]")
} }
}.toPersistentList(), }.toPersistentList(),
totalTokensCount = totalTokensCount, totalTokensCount = totalTokensCount,

View file

@ -295,13 +295,16 @@ internal class OnrampTokenListModel @Inject constructor(
) )
} }
private fun AccountStatusList.filterAccountsByQuery(query: String) = accountStatuses.asSequence() private fun AccountStatusList.filterAccountsByQuery(
query: String,
): Map<Account.CryptoPortfolio, List<CryptoCurrencyStatus>> = accountStatuses.asSequence()
.associate { accountStatus -> .associate { accountStatus ->
when (accountStatus) { when (accountStatus) {
is AccountStatus.CryptoPortfolio -> { is AccountStatus.CryptoPortfolio -> {
val filteredList = accountStatus.tokenList.flattenCurrencies().filterByQuery(query = query) val filteredList = accountStatus.tokenList.flattenCurrencies().filterByQuery(query = query)
accountStatus.account to filteredList accountStatus.account to filteredList
} }
is AccountStatus.Payment -> TODO("[REDACTED_JIRA]")
} }
}.filter { (_, value) -> value.isNotEmpty() } }.filter { (_, value) -> value.isNotEmpty() }

View file

@ -6,6 +6,7 @@ import com.tangem.domain.account.producer.SingleAccountProducer
import com.tangem.domain.account.status.usecase.ManageCryptoCurrenciesUseCase import com.tangem.domain.account.status.usecase.ManageCryptoCurrenciesUseCase
import com.tangem.domain.account.supplier.SingleAccountSupplier import com.tangem.domain.account.supplier.SingleAccountSupplier
import com.tangem.domain.models.PortfolioId import com.tangem.domain.models.PortfolioId
import com.tangem.domain.models.account.Account
import com.tangem.domain.models.account.DerivationIndex import com.tangem.domain.models.account.DerivationIndex
import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.wallet.UserWalletId import com.tangem.domain.models.wallet.UserWalletId
@ -55,7 +56,10 @@ internal class ReferralInteractorImpl(
) )
?: error("Account not found: ${portfolioId.accountId}") ?: error("Account not found: ${portfolioId.accountId}")
account.derivationIndex when (account) {
is Account.CryptoPortfolio -> account.derivationIndex
is Account.Payment -> TODO("[REDACTED_JIRA]")
}
} }
is PortfolioId.Wallet -> null is PortfolioId.Wallet -> null
} }

View file

@ -127,6 +127,7 @@ internal class ReferralModel @Inject constructor(
val cryptoPortfolio = when (selectedAccount) { val cryptoPortfolio = when (selectedAccount) {
is AccountStatus.CryptoPortfolio -> selectedAccount is AccountStatus.CryptoPortfolio -> selectedAccount
is AccountStatus.Payment -> TODO("[REDACTED_JIRA]")
} }
val awardCryptoCurrency = referralInteractor.getCryptoCurrency( val awardCryptoCurrency = referralInteractor.getCryptoCurrency(

View file

@ -21,6 +21,7 @@ import com.tangem.core.decompose.model.getOrCreateModel
import com.tangem.core.decompose.navigation.inner.InnerRouter import com.tangem.core.decompose.navigation.inner.InnerRouter
import com.tangem.core.ui.decompose.ComposableContentComponent import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.resourceReference
import com.tangem.domain.models.account.derivationIndex
import com.tangem.domain.models.currency.CryptoCurrencyStatus import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.features.send.v2.api.FeeSelectorBlockComponent import com.tangem.features.send.v2.api.FeeSelectorBlockComponent
import com.tangem.features.send.v2.api.SendComponent import com.tangem.features.send.v2.api.SendComponent

View file

@ -22,14 +22,17 @@ internal class SendAnalyticHelper @Inject constructor(
cryptoCurrency: CryptoCurrency, cryptoCurrency: CryptoCurrency,
sendUM: SendUM, sendUM: SendUM,
feeToken: CryptoCurrency, feeToken: CryptoCurrency,
account: Account.CryptoPortfolio?, account: Account?,
) { ) {
val destinationUM = sendUM.destinationUM as? DestinationUM.Content val destinationUM = sendUM.destinationUM as? DestinationUM.Content
val feeSelectorUM = sendUM.feeSelectorUM as? FeeSelectorUM.Content ?: return val feeSelectorUM = sendUM.feeSelectorUM as? FeeSelectorUM.Content ?: return
val feeType = feeSelectorUM.toAnalyticType() val feeType = feeSelectorUM.toAnalyticType()
val feeTokenSymbol = feeToken.symbol val feeTokenSymbol = feeToken.symbol
val isNotMainAccount = account != null && !account.isMainAccount val derivationIndex = when (account) {
val derivationIndex = if (isNotMainAccount) account.derivationIndex.value else null is Account.CryptoPortfolio -> if (!account.isMainAccount) account.derivationIndex else null
is Account.Payment -> null
null -> null
}
analyticsEventHandler.send( analyticsEventHandler.send(
SendAnalyticEvents.TransactionScreenOpened( SendAnalyticEvents.TransactionScreenOpened(
token = cryptoCurrency.symbol, token = cryptoCurrency.symbol,
@ -37,7 +40,7 @@ internal class SendAnalyticHelper @Inject constructor(
blockchain = cryptoCurrency.network.name, blockchain = cryptoCurrency.network.name,
isNonceNotEmpty = feeSelectorUM.feeNonce is FeeNonce.Nonce, isNonceNotEmpty = feeSelectorUM.feeNonce is FeeNonce.Nonce,
ensStatus = getEnsStatus(sendUM), ensStatus = getEnsStatus(sendUM),
derivationIndex = derivationIndex, derivationIndex = derivationIndex?.value,
feeToken = feeTokenSymbol, feeToken = feeTokenSymbol,
), ),
) )

View file

@ -158,7 +158,7 @@ internal class SendConfirmComponent(
val feeCryptoCurrencyStatus: CryptoCurrencyStatus, val feeCryptoCurrencyStatus: CryptoCurrencyStatus,
val cryptoCurrencyStatusFlow: StateFlow<CryptoCurrencyStatus>, val cryptoCurrencyStatusFlow: StateFlow<CryptoCurrencyStatus>,
val feeCryptoCurrencyStatusFlow: StateFlow<CryptoCurrencyStatus>, val feeCryptoCurrencyStatusFlow: StateFlow<CryptoCurrencyStatus>,
val accountFlow: StateFlow<Account.CryptoPortfolio?>, val accountFlow: StateFlow<Account?>,
val isAccountModeFlow: StateFlow<Boolean>, val isAccountModeFlow: StateFlow<Boolean>,
val appCurrency: AppCurrency, val appCurrency: AppCurrency,
val callback: ModelCallback, val callback: ModelCallback,

View file

@ -147,7 +147,7 @@ internal class SendModel @Inject constructor(
), ),
) )
val accountFlow: StateFlow<Account.CryptoPortfolio?> val accountFlow: StateFlow<Account?>
field = MutableStateFlow(null) field = MutableStateFlow(null)
val isAccountModeFlow: StateFlow<Boolean> val isAccountModeFlow: StateFlow<Boolean>
field = MutableStateFlow(false) field = MutableStateFlow(false)

View file

@ -24,7 +24,7 @@ internal sealed class SendAmountComponentParams {
abstract val cryptoCurrency: CryptoCurrency abstract val cryptoCurrency: CryptoCurrency
abstract val cryptoCurrencyStatusFlow: StateFlow<CryptoCurrencyStatus> abstract val cryptoCurrencyStatusFlow: StateFlow<CryptoCurrencyStatus>
abstract val isBalanceHidingFlow: StateFlow<Boolean> abstract val isBalanceHidingFlow: StateFlow<Boolean>
abstract val accountFlow: StateFlow<Account.CryptoPortfolio?> abstract val accountFlow: StateFlow<Account?>
abstract val isAccountModeFlow: StateFlow<Boolean> abstract val isAccountModeFlow: StateFlow<Boolean>
data class AmountParams( data class AmountParams(
@ -37,7 +37,7 @@ internal sealed class SendAmountComponentParams {
override val cryptoCurrencyStatusFlow: StateFlow<CryptoCurrencyStatus>, override val cryptoCurrencyStatusFlow: StateFlow<CryptoCurrencyStatus>,
override val isBalanceHidingFlow: StateFlow<Boolean>, override val isBalanceHidingFlow: StateFlow<Boolean>,
override val analyticsSendSource: CommonSendAnalyticEvents.CommonSendSource, override val analyticsSendSource: CommonSendAnalyticEvents.CommonSendSource,
override val accountFlow: StateFlow<Account.CryptoPortfolio?>, override val accountFlow: StateFlow<Account?>,
override val isAccountModeFlow: StateFlow<Boolean>, override val isAccountModeFlow: StateFlow<Boolean>,
val callback: ModelCallback, val callback: ModelCallback,
val currentRoute: StateFlow<CommonSendRoute>, val currentRoute: StateFlow<CommonSendRoute>,
@ -53,7 +53,7 @@ internal sealed class SendAmountComponentParams {
override val cryptoCurrencyStatusFlow: StateFlow<CryptoCurrencyStatus>, override val cryptoCurrencyStatusFlow: StateFlow<CryptoCurrencyStatus>,
override val isBalanceHidingFlow: StateFlow<Boolean>, override val isBalanceHidingFlow: StateFlow<Boolean>,
override val analyticsSendSource: CommonSendAnalyticEvents.CommonSendSource, override val analyticsSendSource: CommonSendAnalyticEvents.CommonSendSource,
override val accountFlow: StateFlow<Account.CryptoPortfolio?>, override val accountFlow: StateFlow<Account?>,
override val isAccountModeFlow: StateFlow<Boolean>, override val isAccountModeFlow: StateFlow<Boolean>,
val userWallet: UserWallet, val userWallet: UserWallet,
val blockClickEnableFlow: StateFlow<Boolean>, val blockClickEnableFlow: StateFlow<Boolean>,

View file

@ -149,7 +149,7 @@ internal class SendAmountModel @Inject constructor(
private suspend fun initMinBoundary( private suspend fun initMinBoundary(
cryptoCurrencyStatus: CryptoCurrencyStatus, cryptoCurrencyStatus: CryptoCurrencyStatus,
account: Account.CryptoPortfolio?, account: Account?,
isAccountsMode: Boolean, isAccountsMode: Boolean,
) { ) {
minAmountBoundary = getMinimumTransactionAmountSyncUseCase( minAmountBoundary = getMinimumTransactionAmountSyncUseCase(
@ -178,11 +178,7 @@ internal class SendAmountModel @Inject constructor(
} }
} }
private fun initialState( private fun initialState(cryptoCurrencyStatus: CryptoCurrencyStatus, account: Account?, isAccountsMode: Boolean) {
cryptoCurrencyStatus: CryptoCurrencyStatus,
account: Account.CryptoPortfolio?,
isAccountsMode: Boolean,
) {
val userWallet = userWallet val userWallet = userWallet
if (uiState.value is AmountState.Empty && userWallet != null) { if (uiState.value is AmountState.Empty && userWallet != null) {
val isOnlyOneWallet = getWalletsUseCase.invokeSync().size == 1 val isOnlyOneWallet = getWalletsUseCase.invokeSync().size == 1

View file

@ -14,7 +14,7 @@ import com.tangem.core.ui.extensions.resourceReference
import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles
import com.tangem.domain.account.status.supplier.MultiAccountStatusListSupplier import com.tangem.domain.account.status.supplier.MultiAccountStatusListSupplier
import com.tangem.domain.account.usecase.IsAccountsModeEnabledUseCase import com.tangem.domain.account.usecase.IsAccountsModeEnabledUseCase
import com.tangem.domain.models.account.Account import com.tangem.domain.models.account.filterCryptoPortfolio
import com.tangem.domain.models.network.CryptoCurrencyAddress import com.tangem.domain.models.network.CryptoCurrencyAddress
import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.models.wallet.isLocked import com.tangem.domain.models.wallet.isLocked
@ -272,36 +272,40 @@ internal class SendDestinationModel @Inject constructor(
return combine( return combine(
flow = getWalletsUseCase().conflate(), flow = getWalletsUseCase().conflate(),
flow2 = multiAccountStatusListSupplier().conflate(), flow2 = multiAccountStatusListSupplier().conflate(),
) { wallets, accountList -> ) { wallets, accountStatusLists ->
val cryptoCurrencyNetwork = cryptoCurrency.network val cryptoCurrencyNetwork = cryptoCurrency.network
coroutineScope { coroutineScope {
accountList.mapNotNull { accountStatusList -> accountStatusLists.mapNotNull { accountStatusList ->
val wallet = val wallet = wallets
wallets.filterNot { it.isLocked }.firstOrNull { it.walletId == accountStatusList.userWalletId } .filterNot { it.isLocked }
?: return@mapNotNull null .firstOrNull { it.walletId == accountStatusList.userWalletId }
?: return@mapNotNull null
async { async {
accountStatusList.accountStatuses.map { accountStatus -> accountStatusList.flattenCurrencies()
async { .filter { it.currency.network.rawId == cryptoCurrencyNetwork.rawId }
accountStatus.flattenCurrencies() .mapNotNull { cryptoCurrencyStatus ->
.filter { it.currency.network.rawId == cryptoCurrencyNetwork.rawId } val address = cryptoCurrencyStatus.value.networkAddress?.defaultAddress?.value
.mapNotNull { cryptoCurrencyStatus -> ?: return@mapNotNull null
val address = cryptoCurrencyStatus.value.networkAddress?.defaultAddress?.value
?: return@mapNotNull null
async { // Find the corresponding account from accountStatuses
DestinationWalletUM( val account = accountStatusList.accountStatuses
name = wallet.name, .filterCryptoPortfolio()
address = address, .firstOrNull { accountStatus ->
cryptoCurrency = cryptoCurrencyStatus.currency, accountStatus.tokenList
userWalletId = wallet.walletId, .flattenCurrencies()
account = accountStatus.account as? Account.CryptoPortfolio, .any { it.currency.id == cryptoCurrencyStatus.currency.id }
) }?.account
}
}.awaitAll() DestinationWalletUM(
name = wallet.name,
address = address,
cryptoCurrency = cryptoCurrencyStatus.currency,
userWalletId = wallet.walletId,
account = account,
)
} }
}.awaitAll().flatten()
} }
}.awaitAll().flatten() }.awaitAll().flatten()
} }

View file

@ -1,9 +1,11 @@
package com.tangem.features.send.v2.subcomponents.destination.model.converters package com.tangem.features.send.v2.subcomponents.destination.model.converters
import com.tangem.common.ui.account.AccountIconUM
import com.tangem.common.ui.account.AccountTitleUM import com.tangem.common.ui.account.AccountTitleUM
import com.tangem.common.ui.account.CryptoPortfolioIconConverter import com.tangem.common.ui.account.CryptoPortfolioIconConverter
import com.tangem.common.ui.account.toUM import com.tangem.common.ui.account.toUM
import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.extensions.stringReference
import com.tangem.domain.models.account.Account
import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.features.send.v2.api.subcomponents.destination.entity.DestinationRecipientListUM import com.tangem.features.send.v2.api.subcomponents.destination.entity.DestinationRecipientListUM
import com.tangem.features.send.v2.subcomponents.destination.model.transformers.WALLET_DEFAULT_COUNT import com.tangem.features.send.v2.subcomponents.destination.model.transformers.WALLET_DEFAULT_COUNT
@ -59,7 +61,12 @@ internal class SendRecipientWalletListConverter(
accountTitleUM = if (account != null && isAccountsMode) { accountTitleUM = if (account != null && isAccountsMode) {
AccountTitleUM.Account( AccountTitleUM.Account(
name = account.accountName.toUM().value, name = account.accountName.toUM().value,
icon = CryptoPortfolioIconConverter.convert(account.icon), icon = when (account) {
is Account.CryptoPortfolio -> CryptoPortfolioIconConverter.convert(
account.icon,
)
is Account.Payment -> AccountIconUM.Payment
},
prefixText = stringReference(StringsSigns.DOT), prefixText = stringReference(StringsSigns.DOT),
) )
} else { } else {

View file

@ -20,5 +20,5 @@ data class DestinationWalletUM(
val userWalletId: UserWalletId, val userWalletId: UserWalletId,
val address: String, val address: String,
val cryptoCurrency: CryptoCurrency, val cryptoCurrency: CryptoCurrency,
val account: Account.CryptoPortfolio? = null, val account: Account? = null,
) )

View file

@ -24,7 +24,7 @@ internal sealed class SwapAmountComponentParams {
abstract val primaryCryptoCurrencyStatusFlow: StateFlow<CryptoCurrencyStatus> abstract val primaryCryptoCurrencyStatusFlow: StateFlow<CryptoCurrencyStatus>
abstract val secondaryCryptoCurrency: CryptoCurrency? abstract val secondaryCryptoCurrency: CryptoCurrency?
abstract val filterProviderTypes: List<ExpressProviderType> abstract val filterProviderTypes: List<ExpressProviderType>
abstract val accountFlow: StateFlow<Account.CryptoPortfolio?> abstract val accountFlow: StateFlow<Account?>
abstract val isAccountModeFlow: StateFlow<Boolean> abstract val isAccountModeFlow: StateFlow<Boolean>
data class AmountParams( data class AmountParams(
@ -37,7 +37,7 @@ internal sealed class SwapAmountComponentParams {
override val secondaryCryptoCurrency: CryptoCurrency?, override val secondaryCryptoCurrency: CryptoCurrency?,
override val filterProviderTypes: List<ExpressProviderType> = emptyList(), override val filterProviderTypes: List<ExpressProviderType> = emptyList(),
override val analyticsSendSource: CommonSendAnalyticEvents.CommonSendSource, override val analyticsSendSource: CommonSendAnalyticEvents.CommonSendSource,
override val accountFlow: StateFlow<Account.CryptoPortfolio?>, override val accountFlow: StateFlow<Account?>,
override val isAccountModeFlow: StateFlow<Boolean>, override val isAccountModeFlow: StateFlow<Boolean>,
val title: TextReference, val title: TextReference,
val callback: SwapAmountComponent.ModelCallback, val callback: SwapAmountComponent.ModelCallback,
@ -54,7 +54,7 @@ internal sealed class SwapAmountComponentParams {
override val secondaryCryptoCurrency: CryptoCurrency?, override val secondaryCryptoCurrency: CryptoCurrency?,
override val filterProviderTypes: List<ExpressProviderType> = emptyList(), override val filterProviderTypes: List<ExpressProviderType> = emptyList(),
override val analyticsSendSource: CommonSendAnalyticEvents.CommonSendSource, override val analyticsSendSource: CommonSendAnalyticEvents.CommonSendSource,
override val accountFlow: StateFlow<Account.CryptoPortfolio?>, override val accountFlow: StateFlow<Account?>,
override val isAccountModeFlow: StateFlow<Boolean>, override val isAccountModeFlow: StateFlow<Boolean>,
val blockClickEnableFlow: StateFlow<Boolean>, val blockClickEnableFlow: StateFlow<Boolean>,
) : SwapAmountComponentParams() ) : SwapAmountComponentParams()

View file

@ -30,7 +30,7 @@ internal class SwapAmountFieldConverter(
private val clickIntents: AmountScreenClickIntents, private val clickIntents: AmountScreenClickIntents,
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?,
) { ) {
private val iconStateConverter = CryptoCurrencyToIconStateConverter() private val iconStateConverter = CryptoCurrencyToIconStateConverter()

View file

@ -21,7 +21,7 @@ internal class SwapAmountBalanceHiddenTransformer(
private val swapDirection: SwapDirection, private val swapDirection: SwapDirection,
private val clickIntents: AmountScreenClickIntents, private val clickIntents: AmountScreenClickIntents,
private val isAccountsMode: Boolean, private val isAccountsMode: Boolean,
private val account: Account.CryptoPortfolio?, private val account: Account?,
) : Transformer<SwapAmountUM> { ) : Transformer<SwapAmountUM> {
override fun transform(prevState: SwapAmountUM): SwapAmountUM { override fun transform(prevState: SwapAmountUM): SwapAmountUM {

View file

@ -27,7 +27,7 @@ internal class SwapAmountPrimaryReadyStateTransformer(
private val isShowBestRateAnimation: 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?,
) : Transformer<SwapAmountUM> { ) : Transformer<SwapAmountUM> {
private val amountFieldConverter = SwapAmountFieldConverter( private val amountFieldConverter = SwapAmountFieldConverter(

View file

@ -28,7 +28,7 @@ internal class SwapAmountSecondaryReadyStateTransformer(
private val isShowBestRateAnimation: 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?,
) : Transformer<SwapAmountUM> { ) : Transformer<SwapAmountUM> {
private val amountFieldConverter = SwapAmountFieldConverter( private val amountFieldConverter = SwapAmountFieldConverter(

View file

@ -18,7 +18,7 @@ internal data class ConfirmData(
val feeError: GetFeeError?, val feeError: GetFeeError?,
val fromCryptoCurrencyStatus: CryptoCurrencyStatus?, val fromCryptoCurrencyStatus: CryptoCurrencyStatus?,
val toCryptoCurrencyStatus: CryptoCurrencyStatus?, val toCryptoCurrencyStatus: CryptoCurrencyStatus?,
val fromAccount: Account.CryptoPortfolio?, val fromAccount: Account?,
val quote: SwapQuoteUM?, val quote: SwapQuoteUM?,
val rateType: ExpressRateType?, val rateType: ExpressRateType?,
) )

View file

@ -20,6 +20,7 @@ import com.tangem.core.decompose.navigation.inner.InnerRouter
import com.tangem.core.navigation.url.UrlOpener import com.tangem.core.navigation.url.UrlOpener
import com.tangem.core.ui.decompose.ComposableContentComponent import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.resourceReference
import com.tangem.domain.models.account.Account
import com.tangem.domain.swap.models.R import com.tangem.domain.swap.models.R
import com.tangem.domain.swap.models.SwapDirection import com.tangem.domain.swap.models.SwapDirection
import com.tangem.features.send.v2.api.analytics.CommonSendAnalyticEvents import com.tangem.features.send.v2.api.analytics.CommonSendAnalyticEvents
@ -110,8 +111,11 @@ internal class DefaultSendWithSwapComponent @AssistedInject constructor(
} }
is SendWithSwapConfirmComponent -> { is SendWithSwapConfirmComponent -> {
val fromCurrency = params.currency val fromCurrency = params.currency
val fromDerivationIndex = model.accountFlow.value?.derivationIndex?.value val fromDerivationIndex = when (val account = model.accountFlow.value) {
.takeIf { model.isAccountModeFlow.value } is Account.CryptoPortfolio -> account.derivationIndex.value
is Account.Payment -> TODO("[REDACTED_JIRA]")
null -> null
}.takeIf { model.isAccountModeFlow.value }
analyticsEventHandler.send( analyticsEventHandler.send(
CommonSendAnalyticEvents.ConfirmationScreenOpened( CommonSendAnalyticEvents.ConfirmationScreenOpened(
categoryName = model.analyticCategoryName, categoryName = model.analyticCategoryName,

View file

@ -181,7 +181,7 @@ internal class SendWithSwapConfirmComponent @AssistedInject constructor(
val isBalanceHidingFlow: StateFlow<Boolean>, val isBalanceHidingFlow: StateFlow<Boolean>,
val primaryCryptoCurrencyStatusFlow: StateFlow<CryptoCurrencyStatus>, val primaryCryptoCurrencyStatusFlow: StateFlow<CryptoCurrencyStatus>,
val primaryFeePaidCurrencyStatusFlow: StateFlow<CryptoCurrencyStatus>, // doesn't change if select gasless fee val primaryFeePaidCurrencyStatusFlow: StateFlow<CryptoCurrencyStatus>, // doesn't change if select gasless fee
val accountFlow: StateFlow<Account.CryptoPortfolio?>, val accountFlow: StateFlow<Account?>,
val isAccountModeFlow: StateFlow<Boolean>, val isAccountModeFlow: StateFlow<Boolean>,
val callback: ModelCallback, val callback: ModelCallback,
) )

View file

@ -24,6 +24,7 @@ import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.wrappedList import com.tangem.core.ui.extensions.wrappedList
import com.tangem.domain.express.models.ExpressOperationType import com.tangem.domain.express.models.ExpressOperationType
import com.tangem.domain.express.models.ExpressProviderType import com.tangem.domain.express.models.ExpressProviderType
import com.tangem.domain.models.account.derivationIndex
import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrencyStatus import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.models.wallet.isHotWallet import com.tangem.domain.models.wallet.isHotWallet

View file

@ -129,7 +129,7 @@ internal class SwapTransactionSender @AssistedInject constructor(
fromAmount: BigDecimal, fromAmount: BigDecimal,
fromStatus: CryptoCurrencyStatus, fromStatus: CryptoCurrencyStatus,
toStatus: CryptoCurrencyStatus, toStatus: CryptoCurrencyStatus,
fromAccount: Account.CryptoPortfolio?, fromAccount: Account?,
fee: Fee, fee: Fee,
feeExtended: TransactionFeeExtended?, feeExtended: TransactionFeeExtended?,
provider: ExpressProvider, provider: ExpressProvider,

View file

@ -96,7 +96,7 @@ internal class SendWithSwapModel @Inject constructor(
), ),
) )
val accountFlow: StateFlow<Account.CryptoPortfolio?> val accountFlow: StateFlow<Account?>
field = MutableStateFlow(null) field = MutableStateFlow(null)
val isAccountModeFlow: StateFlow<Boolean> val isAccountModeFlow: StateFlow<Boolean>

View file

@ -18,7 +18,7 @@ interface SwapComponent : ComposableContentComponent {
val screenSource: String, val screenSource: String,
val tangemPayInput: TangemPayInput? = null, val tangemPayInput: TangemPayInput? = null,
val preselectedToToken: CryptoCurrencyStatus? = null, val preselectedToToken: CryptoCurrencyStatus? = null,
val preselectedAccount: Account.CryptoPortfolio? = null, val preselectedAccount: Account? = null,
) { ) {
data class TangemPayInput( data class TangemPayInput(
val cryptoAmount: BigDecimal, val cryptoAmount: BigDecimal,

View file

@ -47,8 +47,8 @@ internal class DefaultSwapTransactionRepository(
userWalletId: UserWalletId, userWalletId: UserWalletId,
fromCryptoCurrency: CryptoCurrency, fromCryptoCurrency: CryptoCurrency,
toCryptoCurrency: CryptoCurrency, toCryptoCurrency: CryptoCurrency,
fromAccount: Account.CryptoPortfolio?, fromAccount: Account?,
toAccount: Account.CryptoPortfolio?, toAccount: Account?,
transaction: SavedSwapTransactionModel, transaction: SavedSwapTransactionModel,
) { ) {
transaction.status?.let { status -> transaction.status?.let { status ->
@ -248,8 +248,8 @@ internal class DefaultSwapTransactionRepository(
userWalletId: UserWalletId, userWalletId: UserWalletId,
fromCryptoCurrency: CryptoCurrency, fromCryptoCurrency: CryptoCurrency,
toCryptoCurrency: CryptoCurrency, toCryptoCurrency: CryptoCurrency,
fromAccount: Account.CryptoPortfolio?, fromAccount: Account?,
toAccount: Account.CryptoPortfolio?, toAccount: Account?,
transactions: List<SavedSwapTransactionModel>, transactions: List<SavedSwapTransactionModel>,
): List<SavedSwapTransactionListModelInner> { ): List<SavedSwapTransactionListModelInner> {
return addOrReplace( return addOrReplace(

View file

@ -120,8 +120,8 @@ internal class SavedSwapTransactionListConverter(
userWalletId: UserWalletId, userWalletId: UserWalletId,
fromCryptoCurrency: CryptoCurrency, fromCryptoCurrency: CryptoCurrency,
toCryptoCurrency: CryptoCurrency, toCryptoCurrency: CryptoCurrency,
fromAccount: Account.CryptoPortfolio?, fromAccount: Account?,
toAccount: Account.CryptoPortfolio?, toAccount: Account?,
tokenTransactions: List<SavedSwapTransactionModel>, tokenTransactions: List<SavedSwapTransactionModel>,
) = SavedSwapTransactionListModelInner( ) = SavedSwapTransactionListModelInner(
userWalletId = userWalletId.stringValue, userWalletId = userWalletId.stringValue,
@ -161,10 +161,7 @@ internal class SavedSwapTransactionListConverter(
} }
} }
private fun findAccountByDerivationIndex( private fun findAccountByDerivationIndex(accountList: AccountList?, derivationIndex: DerivationIndex?): Account? {
accountList: AccountList?,
derivationIndex: DerivationIndex?,
): Account.CryptoPortfolio? {
return accountList?.accounts?.asSequence()?.filterIsInstance<Account.CryptoPortfolio>() return accountList?.accounts?.asSequence()?.filterIsInstance<Account.CryptoPortfolio>()
?.firstOrNull { it.derivationIndex == derivationIndex } ?.firstOrNull { it.derivationIndex == derivationIndex }
} }

View file

@ -80,8 +80,8 @@ interface SwapInteractor {
swapData: SwapDataModel?, swapData: SwapDataModel?,
currencyToSend: CryptoCurrencyStatus, currencyToSend: CryptoCurrencyStatus,
currencyToGet: CryptoCurrencyStatus, currencyToGet: CryptoCurrencyStatus,
fromAccount: Account.CryptoPortfolio?, fromAccount: Account?,
toAccount: Account.CryptoPortfolio?, toAccount: Account?,
amountToSwap: String, amountToSwap: String,
includeFeeInAmount: IncludeFeeInAmount, includeFeeInAmount: IncludeFeeInAmount,
fee: TxFee?, fee: TxFee?,
@ -129,8 +129,8 @@ interface SwapInteractor {
suspend fun storeSwapTransaction( suspend fun storeSwapTransaction(
currencyToSend: CryptoCurrencyStatus, currencyToSend: CryptoCurrencyStatus,
currencyToGet: CryptoCurrencyStatus, currencyToGet: CryptoCurrencyStatus,
fromAccount: Account.CryptoPortfolio?, fromAccount: Account?,
toAccount: Account.CryptoPortfolio?, toAccount: Account?,
amount: SwapAmount, amount: SwapAmount,
swapProvider: SwapProvider, swapProvider: SwapProvider,
swapDataModel: SwapDataModel, swapDataModel: SwapDataModel,
@ -154,9 +154,9 @@ interface SwapInteractor {
@Suppress("LongParameterList") @Suppress("LongParameterList")
suspend fun loadFeeForSwapTransaction( suspend fun loadFeeForSwapTransaction(
fromToken: CryptoCurrencyStatus, fromToken: CryptoCurrencyStatus,
fromAccount: Account.CryptoPortfolio?, fromAccount: Account?,
toToken: CryptoCurrencyStatus, toToken: CryptoCurrencyStatus,
toAccount: Account.CryptoPortfolio?, toAccount: Account?,
amount: String, amount: String,
reduceBalanceBy: BigDecimal, reduceBalanceBy: BigDecimal,
provider: SwapProvider, provider: SwapProvider,
@ -176,9 +176,9 @@ interface SwapInteractor {
@Suppress("LongParameterList") @Suppress("LongParameterList")
suspend fun loadFeeForSwapTransaction( suspend fun loadFeeForSwapTransaction(
fromToken: CryptoCurrencyStatus, fromToken: CryptoCurrencyStatus,
fromAccount: Account.CryptoPortfolio?, fromAccount: Account?,
toToken: CryptoCurrencyStatus, toToken: CryptoCurrencyStatus,
toAccount: Account.CryptoPortfolio?, toAccount: Account?,
amount: String, amount: String,
reduceBalanceBy: BigDecimal, reduceBalanceBy: BigDecimal,
provider: SwapProvider, provider: SwapProvider,

View file

@ -29,6 +29,7 @@ import com.tangem.domain.demo.IsDemoCardUseCase
import com.tangem.domain.exchange.RampStateManager import com.tangem.domain.exchange.RampStateManager
import com.tangem.domain.express.models.ExpressOperationType import com.tangem.domain.express.models.ExpressOperationType
import com.tangem.domain.models.account.Account import com.tangem.domain.models.account.Account
import com.tangem.domain.models.account.AccountStatus
import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrencyStatus import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.models.network.Network import com.tangem.domain.models.network.Network
@ -180,17 +181,11 @@ internal class SwapInteractorImpl @AssistedInject constructor(
SingleAccountStatusListProducer.Params(userWalletId), SingleAccountStatusListProducer.Params(userWalletId),
)?.accountStatuses.orEmpty() )?.accountStatuses.orEmpty()
val walletAccountCurrencyStatusesExceptInitial = walletAccountCurrencyStatuses val walletAccountCurrencyStatusesExceptInitial: Map<Account, List<CryptoCurrencyStatus>> =
.mapNotNull { accountStatus -> walletAccountCurrencyStatuses.mapNotNull { accountStatus ->
val filteredCurrencies = accountStatus.flattenCurrencies().filter { status -> val filteredCurrencies = when (accountStatus) {
val isDifferentCurrency = status.currency.network.backendId != currency.network.backendId || is AccountStatus.CryptoPortfolio -> accountStatus.flattenCurrencies().filterCurrencies(currency)
status.currency.getContractAddress() != currency.getContractAddress() is AccountStatus.Payment -> TODO("[REDACTED_JIRA]")
val hasValidStatus =
status.value is CryptoCurrencyStatus.Loaded || status.value is CryptoCurrencyStatus.NoAccount
val isNotCustomToken = !status.currency.isCustom
hasValidStatus && isDifferentCurrency && isNotCustomToken
} }
if (filteredCurrencies.isNotEmpty()) { if (filteredCurrencies.isNotEmpty()) {
@ -234,6 +229,17 @@ internal class SwapInteractorImpl @AssistedInject constructor(
) )
} }
private fun List<CryptoCurrencyStatus>.filterCurrencies(currency: CryptoCurrency) = this.filter { status ->
val isDifferentCurrency = status.currency.network.backendId != currency.network.backendId ||
status.currency.getContractAddress() != currency.getContractAddress()
val hasValidStatus =
status.value is CryptoCurrencyStatus.Loaded || status.value is CryptoCurrencyStatus.NoAccount
val isNotCustomToken = !status.currency.isCustom
hasValidStatus && isDifferentCurrency && isNotCustomToken
}
private suspend fun getToCurrenciesGroup( private suspend fun getToCurrenciesGroup(
currency: CryptoCurrency, currency: CryptoCurrency,
leastPairs: List<SwapPairLeast>, leastPairs: List<SwapPairLeast>,
@ -293,7 +299,7 @@ internal class SwapInteractorImpl @AssistedInject constructor(
val isUnavailable = providers.isNullOrEmpty() val isUnavailable = providers.isNullOrEmpty()
AccountSwapCurrency( AccountSwapCurrency(
isAvailable = !isUnavailable, isAvailable = !isUnavailable,
account = cryptoPortfolio, account = accountEntry,
cryptoCurrencyStatus = currencyStatus, cryptoCurrencyStatus = currencyStatus,
providers = providers.orEmpty(), providers = providers.orEmpty(),
) )
@ -400,7 +406,9 @@ internal class SwapInteractorImpl @AssistedInject constructor(
""" """
Find the best quote Find the best quote
|- fromToken: $fromToken |- fromToken: $fromToken
|- fromAccount: $fromAccount
|- toToken: $toToken |- toToken: $toToken
|- toAccount: $toAccount
|- providers: $providers |- providers: $providers
|- amountToSwap: $amountToSwap |- amountToSwap: $amountToSwap
|- selectedFee: $txFeeSealedState |- selectedFee: $txFeeSealedState
@ -767,8 +775,8 @@ internal class SwapInteractorImpl @AssistedInject constructor(
swapData: SwapDataModel?, swapData: SwapDataModel?,
currencyToSend: CryptoCurrencyStatus, currencyToSend: CryptoCurrencyStatus,
currencyToGet: CryptoCurrencyStatus, currencyToGet: CryptoCurrencyStatus,
fromAccount: Account.CryptoPortfolio?, fromAccount: Account?,
toAccount: Account.CryptoPortfolio?, toAccount: Account?,
amountToSwap: String, amountToSwap: String,
includeFeeInAmount: IncludeFeeInAmount, includeFeeInAmount: IncludeFeeInAmount,
fee: TxFee?, fee: TxFee?,
@ -848,8 +856,8 @@ internal class SwapInteractorImpl @AssistedInject constructor(
swapData: SwapDataModel, swapData: SwapDataModel,
currencyToSendStatus: CryptoCurrencyStatus, currencyToSendStatus: CryptoCurrencyStatus,
currencyToGetStatus: CryptoCurrencyStatus, currencyToGetStatus: CryptoCurrencyStatus,
fromAccount: Account.CryptoPortfolio?, fromAccount: Account?,
toAccount: Account.CryptoPortfolio?, toAccount: Account?,
amountToSwap: String, amountToSwap: String,
txFee: TxFee, txFee: TxFee,
): SwapTransactionState { ): SwapTransactionState {
@ -890,8 +898,8 @@ internal class SwapInteractorImpl @AssistedInject constructor(
swapData: SwapDataModel, swapData: SwapDataModel,
currencyToSendStatus: CryptoCurrencyStatus, currencyToSendStatus: CryptoCurrencyStatus,
currencyToGetStatus: CryptoCurrencyStatus, currencyToGetStatus: CryptoCurrencyStatus,
fromAccount: Account.CryptoPortfolio?, fromAccount: Account?,
toAccount: Account.CryptoPortfolio?, toAccount: Account?,
amountToSwap: String, amountToSwap: String,
): SwapTransactionState { ): SwapTransactionState {
val dexTransaction = swapData.transaction as? ExpressTransactionModel.DEX val dexTransaction = swapData.transaction as? ExpressTransactionModel.DEX
@ -919,8 +927,8 @@ internal class SwapInteractorImpl @AssistedInject constructor(
swapData: SwapDataModel, swapData: SwapDataModel,
currencyToSendStatus: CryptoCurrencyStatus, currencyToSendStatus: CryptoCurrencyStatus,
currencyToGetStatus: CryptoCurrencyStatus, currencyToGetStatus: CryptoCurrencyStatus,
fromAccount: Account.CryptoPortfolio?, fromAccount: Account?,
toAccount: Account.CryptoPortfolio?, toAccount: Account?,
amount: SwapAmount, amount: SwapAmount,
txData: TransactionData, txData: TransactionData,
payInAddress: String, payInAddress: String,
@ -988,8 +996,8 @@ internal class SwapInteractorImpl @AssistedInject constructor(
private suspend fun onSwapCex( private suspend fun onSwapCex(
currencyToSend: CryptoCurrencyStatus, currencyToSend: CryptoCurrencyStatus,
currencyToGet: CryptoCurrencyStatus, currencyToGet: CryptoCurrencyStatus,
fromAccount: Account.CryptoPortfolio?, fromAccount: Account?,
toAccount: Account.CryptoPortfolio?, toAccount: Account?,
amount: SwapAmount, amount: SwapAmount,
txFee: TxFee?, txFee: TxFee?,
swapProvider: SwapProvider, swapProvider: SwapProvider,
@ -1150,8 +1158,8 @@ internal class SwapInteractorImpl @AssistedInject constructor(
override suspend fun storeSwapTransaction( override suspend fun storeSwapTransaction(
currencyToSend: CryptoCurrencyStatus, currencyToSend: CryptoCurrencyStatus,
currencyToGet: CryptoCurrencyStatus, currencyToGet: CryptoCurrencyStatus,
fromAccount: Account.CryptoPortfolio?, fromAccount: Account?,
toAccount: Account.CryptoPortfolio?, toAccount: Account?,
amount: SwapAmount, amount: SwapAmount,
swapProvider: SwapProvider, swapProvider: SwapProvider,
swapDataModel: SwapDataModel, swapDataModel: SwapDataModel,
@ -1187,9 +1195,9 @@ internal class SwapInteractorImpl @AssistedInject constructor(
@Suppress("LongParameterList") @Suppress("LongParameterList")
override suspend fun loadFeeForSwapTransaction( override suspend fun loadFeeForSwapTransaction(
fromToken: CryptoCurrencyStatus, fromToken: CryptoCurrencyStatus,
fromAccount: Account.CryptoPortfolio?, fromAccount: Account?,
toToken: CryptoCurrencyStatus, toToken: CryptoCurrencyStatus,
toAccount: Account.CryptoPortfolio?, toAccount: Account?,
amount: String, amount: String,
reduceBalanceBy: BigDecimal, reduceBalanceBy: BigDecimal,
provider: SwapProvider, provider: SwapProvider,
@ -1225,9 +1233,9 @@ internal class SwapInteractorImpl @AssistedInject constructor(
override suspend fun loadFeeForSwapTransaction( override suspend fun loadFeeForSwapTransaction(
fromToken: CryptoCurrencyStatus, fromToken: CryptoCurrencyStatus,
fromAccount: Account.CryptoPortfolio?, fromAccount: Account?,
toToken: CryptoCurrencyStatus, toToken: CryptoCurrencyStatus,
toAccount: Account.CryptoPortfolio?, toAccount: Account?,
amount: String, amount: String,
reduceBalanceBy: BigDecimal, reduceBalanceBy: BigDecimal,
provider: SwapProvider, provider: SwapProvider,

View file

@ -17,8 +17,8 @@ interface SwapTransactionRepository {
userWalletId: UserWalletId, userWalletId: UserWalletId,
fromCryptoCurrency: CryptoCurrency, fromCryptoCurrency: CryptoCurrency,
toCryptoCurrency: CryptoCurrency, toCryptoCurrency: CryptoCurrency,
fromAccount: Account.CryptoPortfolio?, fromAccount: Account?,
toAccount: Account.CryptoPortfolio?, toAccount: Account?,
transaction: SavedSwapTransactionModel, transaction: SavedSwapTransactionModel,
) )

View file

@ -13,8 +13,8 @@ data class SavedSwapTransactionListModel(
val toCryptoCurrencyId: String, val toCryptoCurrencyId: String,
val fromCryptoCurrency: CryptoCurrency, val fromCryptoCurrency: CryptoCurrency,
val toCryptoCurrency: CryptoCurrency, val toCryptoCurrency: CryptoCurrency,
val fromAccount: Account.CryptoPortfolio?, val fromAccount: Account?,
val toAccount: Account.CryptoPortfolio?, val toAccount: Account?,
val transactions: List<SavedSwapTransactionModel>, val transactions: List<SavedSwapTransactionModel>,
) )

View file

@ -36,8 +36,8 @@ sealed class SwapTransactionState {
data class StoreTransactionData( data class StoreTransactionData(
val currencyToSend: CryptoCurrencyStatus, val currencyToSend: CryptoCurrencyStatus,
val currencyToGet: CryptoCurrencyStatus, val currencyToGet: CryptoCurrencyStatus,
val fromAccount: Account.CryptoPortfolio?, val fromAccount: Account?,
val toAccount: Account.CryptoPortfolio?, val toAccount: Account?,
val amount: SwapAmount, val amount: SwapAmount,
val swapProvider: SwapProvider, val swapProvider: SwapProvider,
val swapDataModel: SwapDataModel, val swapDataModel: SwapDataModel,

View file

@ -22,6 +22,7 @@ import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
import com.tangem.domain.models.account.Account import com.tangem.domain.models.account.Account
import com.tangem.domain.models.account.AccountId import com.tangem.domain.models.account.AccountId
import com.tangem.domain.models.account.AccountStatus import com.tangem.domain.models.account.AccountStatus
import com.tangem.domain.models.account.filterCryptoPortfolio
import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.models.wallet.UserWalletId import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.wallets.analytics.WalletSettingsAnalyticEvents import com.tangem.domain.wallets.analytics.WalletSettingsAnalyticEvents
@ -84,11 +85,11 @@ internal class AccountItemsDelegate @Inject constructor(
return WalletSettingsAccountsUM.Account(state = accountItemUM) return WalletSettingsAccountsUM.Account(state = accountItemUM)
} }
fun mapAccount(account: AccountStatus): WalletSettingsAccountsUM = when (account) { fun mapAccount(account: AccountStatus.CryptoPortfolio): WalletSettingsAccountsUM = when (account) {
is AccountStatus.CryptoPortfolio -> account.mapCryptoPortfolio() is AccountStatus.CryptoPortfolio -> account.mapCryptoPortfolio()
} }
val accounts = accountStatusList.accountStatuses val accounts = accountStatusList.accountStatuses.filterCryptoPortfolio()
val header = WalletSettingsAccountsUM.Header( val header = WalletSettingsAccountsUM.Header(
id = "accounts_header", id = "accounts_header",

View file

@ -2,7 +2,7 @@ package com.tangem.feature.wallet.presentation.organizetokens.utils
import com.tangem.domain.account.models.AccountStatusList import com.tangem.domain.account.models.AccountStatusList
import com.tangem.domain.account.status.model.AccountCryptoCurrencies import com.tangem.domain.account.status.model.AccountCryptoCurrencies
import com.tangem.domain.models.account.Account import com.tangem.domain.models.account.filterCryptoPortfolio
import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.tokenlist.TokenList import com.tangem.domain.models.tokenlist.TokenList
import com.tangem.feature.wallet.presentation.organizetokens.model.DraggableItem import com.tangem.feature.wallet.presentation.organizetokens.model.DraggableItem
@ -34,6 +34,7 @@ internal class CryptoCurrenciesIdsResolver {
} }
} }
@Suppress("UseOrEmpty")
fun resolveV2(tokensListUM: OrganizeTokensListUM, accountStatusList: AccountStatusList?): AccountCryptoCurrencies { fun resolveV2(tokensListUM: OrganizeTokensListUM, accountStatusList: AccountStatusList?): AccountCryptoCurrencies {
val draggableTokens = when (tokensListUM) { val draggableTokens = when (tokensListUM) {
OrganizeTokensListUM.EmptyList -> return emptyMap() OrganizeTokensListUM.EmptyList -> return emptyMap()
@ -43,10 +44,11 @@ internal class CryptoCurrenciesIdsResolver {
} }
return accountStatusList?.accountStatuses return accountStatusList?.accountStatuses
?.filter { it.getCryptoTokenList() != TokenList.Empty } ?.filterCryptoPortfolio()
?.filter { it.tokenList != TokenList.Empty }
?.associate { accountStatus -> ?.associate { accountStatus ->
val currencies = accountStatus.flattenCurrencies() val currencies = accountStatus.flattenCurrencies()
accountStatus.account as Account.CryptoPortfolio to draggableTokens accountStatus.account to draggableTokens
.asSequence() .asSequence()
.filter { it.accountId == accountStatus.account.accountId.value } .filter { it.accountId == accountStatus.account.accountId.value }
.mapNotNull { sortedToken -> .mapNotNull { sortedToken ->

View file

@ -6,7 +6,7 @@ import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.models.TokensGroupType import com.tangem.domain.models.TokensGroupType
import com.tangem.domain.models.TokensSortType import com.tangem.domain.models.TokensSortType
import com.tangem.domain.models.TotalFiatBalance import com.tangem.domain.models.TotalFiatBalance
import com.tangem.domain.models.account.AccountStatus import com.tangem.domain.models.account.filterCryptoPortfolio
import com.tangem.domain.models.tokenlist.TokenList import com.tangem.domain.models.tokenlist.TokenList
import com.tangem.feature.wallet.presentation.organizetokens.model.DraggableItem import com.tangem.feature.wallet.presentation.organizetokens.model.DraggableItem
import com.tangem.feature.wallet.presentation.organizetokens.model.OrganizeTokensListUM import com.tangem.feature.wallet.presentation.organizetokens.model.OrganizeTokensListUM
@ -61,7 +61,7 @@ internal class AccountTokenItemConverter(
isGrouped = isGrouping, isGrouped = isGrouping,
items = value.accountStatuses items = value.accountStatuses
.asSequence() .asSequence()
.filterIsInstance<AccountStatus.CryptoPortfolio>() .filterCryptoPortfolio()
.flatMap { accountStatus -> .flatMap { accountStatus ->
if (accountStatus.tokenList != TokenList.Empty) { if (accountStatus.tokenList != TokenList.Empty) {
buildList { buildList {

View file

@ -2,7 +2,6 @@ package com.tangem.feature.wallet.presentation.organizetokens.utils.converter.it
import com.tangem.domain.account.status.model.AccountCryptoCurrencyStatus import com.tangem.domain.account.status.model.AccountCryptoCurrencyStatus
import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.models.account.Account
import com.tangem.domain.models.account.AccountStatus import com.tangem.domain.models.account.AccountStatus
import com.tangem.domain.models.tokenlist.TokenList import com.tangem.domain.models.tokenlist.TokenList
import com.tangem.feature.wallet.presentation.organizetokens.model.DraggableItem import com.tangem.feature.wallet.presentation.organizetokens.model.DraggableItem
@ -13,27 +12,26 @@ import kotlinx.collections.immutable.toPersistentList
internal class OrganizedTokenListConverter( internal class OrganizedTokenListConverter(
private val appCurrency: AppCurrency, private val appCurrency: AppCurrency,
) : Converter<AccountStatus, PersistentList<DraggableItem>> { ) : Converter<AccountStatus.CryptoPortfolio, PersistentList<DraggableItem>> {
private val tokensConverter by lazy { CryptoCurrencyToDraggableItemConverterV2(appCurrency) } private val tokensConverter by lazy { CryptoCurrencyToDraggableItemConverterV2(appCurrency) }
private val groupsConverter by lazy { private val groupsConverter by lazy {
NetworkGroupToDraggableItemsConverterV2(tokensConverter) NetworkGroupToDraggableItemsConverterV2(tokensConverter)
} }
override fun convert(value: AccountStatus): PersistentList<DraggableItem> { override fun convert(value: AccountStatus.CryptoPortfolio): PersistentList<DraggableItem> {
val cryptoAccount = value.account as? Account.CryptoPortfolio ?: return persistentListOf() return when (val tokenList = value.tokenList) {
return when (val tokenList = value.getCryptoTokenList()) {
is TokenList.GroupedByNetwork -> groupsConverter.convertList( is TokenList.GroupedByNetwork -> groupsConverter.convertList(
tokenList.groups.map { cryptoAccount to it }, tokenList.groups.map { value.account to it },
) )
.flatten() .flatten()
.toPersistentList() .toPersistentList()
is TokenList.Ungrouped -> tokensConverter.convertList( is TokenList.Ungrouped -> tokensConverter.convertList(
value.flattenCurrencies().map { value.flattenCurrencies().map { cryptoCurrencyStatus ->
AccountCryptoCurrencyStatus( AccountCryptoCurrencyStatus(
account = cryptoAccount, account = value.account,
status = it, status = cryptoCurrencyStatus,
) )
}, },
).toPersistentList() ).toPersistentList()

View file

@ -241,10 +241,11 @@ internal class GetSingleWalletWarningsFactory @Inject constructor(
} }
} }
private fun getAccountStatusFlow(userWallet: UserWallet): Flow<AccountStatus> { private fun getAccountStatusFlow(userWallet: UserWallet): Flow<AccountStatus.CryptoPortfolio> {
val accountId = AccountId.forMainCryptoPortfolio(userWalletId = userWallet.walletId) val accountId = AccountId.forMainCryptoPortfolio(userWalletId = userWallet.walletId)
return singleAccountStatusSupplier(SingleAccountStatusProducer.Params(accountId)) return singleAccountStatusSupplier(SingleAccountStatusProducer.Params(accountId))
.filterIsInstance<AccountStatus.CryptoPortfolio>()
.distinctUntilChanged() .distinctUntilChanged()
.conflate() .conflate()
} }

View file

@ -14,6 +14,7 @@ import com.tangem.domain.models.TotalFiatBalance
import com.tangem.domain.models.account.Account import com.tangem.domain.models.account.Account
import com.tangem.domain.models.account.AccountId import com.tangem.domain.models.account.AccountId
import com.tangem.domain.models.account.AccountStatus import com.tangem.domain.models.account.AccountStatus
import com.tangem.domain.models.account.filterCryptoPortfolio
import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrencyStatus import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.models.tokenlist.TokenList import com.tangem.domain.models.tokenlist.TokenList
@ -144,6 +145,7 @@ internal class TokenListStateConverter(
} }
val accountItems = accountList.accountStatuses val accountItems = accountList.accountStatuses
.filterCryptoPortfolio()
.map { accountStatus -> .map { accountStatus ->
when (accountStatus) { when (accountStatus) {
is AccountStatus.CryptoPortfolio -> accountStatus.map() is AccountStatus.CryptoPortfolio -> accountStatus.map()

View file

@ -4,6 +4,7 @@ import com.tangem.domain.account.models.AccountStatusList
import com.tangem.domain.account.status.producer.SingleAccountStatusListProducer import com.tangem.domain.account.status.producer.SingleAccountStatusListProducer
import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier
import com.tangem.domain.models.account.AccountStatus import com.tangem.domain.models.account.AccountStatus
import com.tangem.domain.models.account.filterCryptoPortfolio
import com.tangem.domain.models.currency.CryptoCurrencyStatus import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.models.wallet.UserWallet
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
@ -45,11 +46,9 @@ internal abstract class BasicWalletSubscriber : WalletSubscriber() {
protected fun getMainAccountStatusFlow(): Flow<AccountStatus.CryptoPortfolio> { protected fun getMainAccountStatusFlow(): Flow<AccountStatus.CryptoPortfolio> {
return getAccountStatusListFlow() return getAccountStatusListFlow()
.mapNotNull { accountStatusList -> .mapNotNull { accountStatusList ->
accountStatusList.accountStatuses.find { accountStatus -> accountStatusList.accountStatuses
when (accountStatus) { .filterCryptoPortfolio()
is AccountStatus.CryptoPortfolio -> accountStatus.account.isMainAccount .find { accountStatus -> accountStatus.account.isMainAccount }
}
} as? AccountStatus.CryptoPortfolio
} }
.distinctUntilChanged() .distinctUntilChanged()
.conflate() .conflate()

View file

@ -27,7 +27,6 @@ import com.tangem.domain.account.supplier.SingleAccountListSupplier
import com.tangem.domain.account.usecase.IsAccountsModeEnabledUseCase import com.tangem.domain.account.usecase.IsAccountsModeEnabledUseCase
import com.tangem.domain.models.account.Account import com.tangem.domain.models.account.Account
import com.tangem.domain.models.account.AccountStatus import com.tangem.domain.models.account.AccountStatus
import com.tangem.domain.models.account.derivationIndex
import com.tangem.domain.models.network.Network import com.tangem.domain.models.network.Network
import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.models.wallet.UserWalletId import com.tangem.domain.models.wallet.UserWalletId
@ -105,7 +104,7 @@ internal class WcPairModel @Inject constructor(
private val selectedUserWalletFlow: MutableStateFlow<UserWallet> by lazy { private val selectedUserWalletFlow: MutableStateFlow<UserWallet> by lazy {
MutableStateFlow(getWalletsUseCase.invokeSync().first { it.walletId == params.userWalletId }) MutableStateFlow(getWalletsUseCase.invokeSync().first { it.walletId == params.userWalletId })
} }
private val selectedPortfolio = MutableSharedFlow<Pair<UserWallet, AccountStatus>>( private val selectedPortfolio = MutableSharedFlow<Pair<UserWallet, AccountStatus.CryptoPortfolio>>(
replay = 1, replay = 1,
onBufferOverflow = BufferOverflow.DROP_OLDEST, onBufferOverflow = BufferOverflow.DROP_OLDEST,
) )
@ -171,7 +170,7 @@ internal class WcPairModel @Inject constructor(
private suspend fun handlePairState( private suspend fun handlePairState(
pairState: WcPairState, pairState: WcPairState,
portfolios: PortfolioFetcher.Data? = null, portfolios: PortfolioFetcher.Data? = null,
selected: Pair<UserWallet, AccountStatus>? = null, selected: Pair<UserWallet, AccountStatus.CryptoPortfolio>? = null,
isAccountMode: Boolean? = null, isAccountMode: Boolean? = null,
) { ) {
when (pairState) { when (pairState) {
@ -206,7 +205,7 @@ internal class WcPairModel @Inject constructor(
private suspend fun handleProposalState( private suspend fun handleProposalState(
pairState: WcPairState.Proposal, pairState: WcPairState.Proposal,
portfolios: PortfolioFetcher.Data? = null, portfolios: PortfolioFetcher.Data? = null,
selected: Pair<UserWallet, AccountStatus>? = null, selected: Pair<UserWallet, AccountStatus.CryptoPortfolio>? = null,
) { ) {
val availableWallets = pairState.dAppSession.proposalNetwork.keys val availableWallets = pairState.dAppSession.proposalNetwork.keys
.filter { !it.isLocked && it.isMultiCurrency } .filter { !it.isLocked && it.isMultiCurrency }
@ -266,7 +265,7 @@ internal class WcPairModel @Inject constructor(
} }
private suspend fun tryToCreatePortfolioSelectRow( private suspend fun tryToCreatePortfolioSelectRow(
selectedPortfolio: Pair<UserWallet, AccountStatus>?, selectedPortfolio: Pair<UserWallet, AccountStatus.CryptoPortfolio>?,
portfolios: PortfolioFetcher.Data?, portfolios: PortfolioFetcher.Data?,
): PortfolioSelectUM? { ): PortfolioSelectUM? {
selectedPortfolio ?: return null selectedPortfolio ?: return null
@ -274,7 +273,6 @@ internal class WcPairModel @Inject constructor(
val (wallet, portfolioAccount) = selectedPortfolio val (wallet, portfolioAccount) = selectedPortfolio
val account = when (val account = portfolioAccount.account) { val account = when (val account = portfolioAccount.account) {
is Account.CryptoPortfolio -> account is Account.CryptoPortfolio -> account
is Account.Payment -> TODO("[REDACTED_JIRA]")
} }
val isAccountMode = selectorController.isAccountMode.first() val isAccountMode = selectorController.isAccountMode.first()
val icon: AccountIconUM.CryptoPortfolio? val icon: AccountIconUM.CryptoPortfolio?

View file

@ -48,7 +48,7 @@ internal class WcSessionsAccountModeTransformer(
) )
items.add(walletHeader) items.add(walletHeader)
accountList.accounts.forEach accountsForEach@{ account -> accountList.accounts.filterIsInstance<Account.CryptoPortfolio>().forEach accountsForEach@{ account ->
val accountSessions = sessions.filter { it.account?.accountId == account.accountId } val accountSessions = sessions.filter { it.account?.accountId == account.accountId }
if (accountSessions.isEmpty()) return@accountsForEach if (accountSessions.isEmpty()) return@accountsForEach
val connectedApps = accountSessions.map { dappSession -> val connectedApps = accountSessions.map { dappSession ->
@ -65,7 +65,6 @@ internal class WcSessionsAccountModeTransformer(
} }
val accountIcon = when (account) { val accountIcon = when (account) {
is Account.CryptoPortfolio -> account.icon is Account.CryptoPortfolio -> account.icon
is Account.Payment -> TODO("[REDACTED_JIRA]")
} }
val accountTitle = AccountTitleUM.Account( val accountTitle = AccountTitleUM.Account(

View file

@ -19,13 +19,12 @@ internal class WcPortfolioNameDelegate @AssistedInject constructor(
isAccountsModeEnabledUseCase: IsAccountsModeEnabledUseCase, isAccountsModeEnabledUseCase: IsAccountsModeEnabledUseCase,
@Assisted private val scope: CoroutineScope, @Assisted private val scope: CoroutineScope,
) { ) {
val isAccountMode = isAccountsModeEnabledUseCase.invoke() private val isAccountMode = isAccountsModeEnabledUseCase.invoke()
.stateIn(scope = scope, started = SharingStarted.Eagerly, initialValue = false) .stateIn(scope = scope, started = SharingStarted.Eagerly, initialValue = false)
fun createAccountTitleUM(value: WcSession): AccountTitleUM? { fun createAccountTitleUM(value: WcSession): AccountTitleUM? {
val account = when (val account = value.account) { val account = when (val account = value.account) {
is Account.CryptoPortfolio -> account is Account.CryptoPortfolio -> account
is Account.Payment -> TODO("[REDACTED_JIRA]")
null -> null null -> null
} }

View file

@ -11,7 +11,6 @@ import com.tangem.core.decompose.model.ParamsContainer
import com.tangem.core.decompose.navigation.Router import com.tangem.core.decompose.navigation.Router
import com.tangem.core.decompose.ui.UiMessageSender import com.tangem.core.decompose.ui.UiMessageSender
import com.tangem.core.ui.clipboard.ClipboardManager import com.tangem.core.ui.clipboard.ClipboardManager
import com.tangem.domain.models.account.derivationIndex
import com.tangem.domain.walletconnect.WcAnalyticEvents import com.tangem.domain.walletconnect.WcAnalyticEvents
import com.tangem.domain.walletconnect.WcRequestUseCaseFactory import com.tangem.domain.walletconnect.WcRequestUseCaseFactory
import com.tangem.domain.walletconnect.usecase.method.WcAddNetworkUseCase import com.tangem.domain.walletconnect.usecase.method.WcAddNetworkUseCase

View file

@ -23,7 +23,6 @@ import com.tangem.core.ui.components.bottomsheets.message.MessageBottomSheetUMV2
import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.wrappedList import com.tangem.core.ui.extensions.wrappedList
import com.tangem.domain.core.lce.Lce import com.tangem.domain.core.lce.Lce
import com.tangem.domain.models.account.derivationIndex
import com.tangem.domain.models.currency.CryptoCurrencyStatus import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.models.network.Network import com.tangem.domain.models.network.Network
import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.models.wallet.UserWallet

View file

@ -12,7 +12,6 @@ import com.tangem.core.decompose.model.ParamsContainer
import com.tangem.core.decompose.navigation.Router import com.tangem.core.decompose.navigation.Router
import com.tangem.core.decompose.ui.UiMessageSender import com.tangem.core.decompose.ui.UiMessageSender
import com.tangem.core.ui.clipboard.ClipboardManager import com.tangem.core.ui.clipboard.ClipboardManager
import com.tangem.domain.models.account.derivationIndex
import com.tangem.domain.walletconnect.WcAnalyticEvents import com.tangem.domain.walletconnect.WcAnalyticEvents
import com.tangem.domain.walletconnect.WcRequestUseCaseFactory import com.tangem.domain.walletconnect.WcRequestUseCaseFactory
import com.tangem.domain.walletconnect.model.WcEthMethod import com.tangem.domain.walletconnect.model.WcEthMethod