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

@ -60,5 +60,7 @@ interface PortfolioSelectorController {
suspend fun isAccountModeSync(): Boolean
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.models.account.AccountId
import com.tangem.domain.models.account.AccountStatus
import com.tangem.domain.models.account.filterCryptoPortfolio
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.features.account.PortfolioFetcher
import com.tangem.features.account.PortfolioSelectorController
@ -35,21 +36,23 @@ internal class DefaultPortfolioSelectorController @Inject constructor(
_selectedAccount.tryEmit(accountId)
}
override fun selectedAccountWithData(portfolioFetcher: PortfolioFetcher): Flow<Pair<UserWallet, AccountStatus>?> =
combine(
flow = _selectedAccount,
flow2 = portfolioFetcher.data,
transform = { accountId, data ->
accountId ?: return@combine null
var result: Pair<UserWallet, AccountStatus>? = null
override fun selectedAccountWithData(
portfolioFetcher: PortfolioFetcher,
): Flow<Pair<UserWallet, AccountStatus.CryptoPortfolio>?> = combine(
flow = _selectedAccount,
flow2 = portfolioFetcher.data,
transform = { accountId, data ->
accountId ?: return@combine null
var result: Pair<UserWallet, AccountStatus.CryptoPortfolio>? = null
data.balances.forEach { wallet, balance ->
val accountStatuses = balance.accountsBalance.accountStatuses
.find { accountId == it.account.accountId }
if (accountStatuses != null) result = balance.userWallet to accountStatuses
}
data.balances.forEach { wallet, balance ->
val accountStatuses = balance.accountsBalance.accountStatuses
.filterCryptoPortfolio()
.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 accountBalance = when (accountStatus) {
is AccountStatus.CryptoPortfolio -> accountStatus.tokenList.totalFiatBalance
is AccountStatus.Payment -> accountStatus.totalFiatBalance
}
val accountItemUM = AccountPortfolioItemUMConverter(
onClick = { selectorController.selectAccount(account.accountId) },

View file

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

View file

@ -174,6 +174,7 @@ internal class AddToPortfolioPreselectedDataModel @Inject constructor(
val availableToAddAccounts = accounts.mapNotNull { accountStatus ->
val accountIndex = when (accountStatus) {
is AccountStatus.CryptoPortfolio -> accountStatus.account.derivationIndex
is AccountStatus.Payment -> TODO("[REDACTED_JIRA]")
}
val cryptoCurrency = getTokenMarketCryptoCurrency(
@ -220,6 +221,7 @@ internal class AddToPortfolioPreselectedDataModel @Inject constructor(
): CryptoCurrency? {
val accountIndex = when (val accountStatus = account.account) {
is AccountStatus.CryptoPortfolio -> accountStatus.account.derivationIndex
is AccountStatus.Payment -> TODO("[REDACTED_JIRA]")
}
return getTokenMarketCryptoCurrency(
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.resourceReference
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.SelectedPortfolio
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 {
val accountIcon: AccountIconUM.CryptoPortfolio?
val accountIcon: AccountIconUM?
val portfolioName: TextReference
when (selectedPortfolio.isAccountMode) {
false -> {
@ -47,7 +47,8 @@ internal class AddTokenUiBuilder @Inject constructor(
val accountStatus = selectedPortfolio.account.account
portfolioName = accountStatus.account.accountName.toUM().value
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
getTokenIdIfL2Network(currencyId.value) == currencyRawId.value
}
is AccountStatus.Payment -> TODO("[REDACTED_JIRA]")
}
return accountStatuses.map { accountStatus ->
AccountWithAdded(

View file

@ -214,9 +214,10 @@ internal class CustomTokenSelectorModel @Inject constructor(
val accounts = singleAccountStatusListSupplier(mode.userWalletId)
.first().accountStatuses
val accountStatus = accounts.find {
when (it) {
is AccountStatus.CryptoPortfolio -> it.sameNodeAndNotMain()
val accountStatus = accounts.find { account ->
when (account) {
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.ManagedCryptoCurrency
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.network.Network
import com.tangem.domain.models.wallet.UserWalletId
@ -88,7 +89,7 @@ internal class ManageTokensUseCasesFacade @AssistedInject constructor(
val account = singleAccountSupplier.getSyncOrNull(
params = SingleAccountProducer.Params(accountId = mode.accountId),
)
) as? Account.CryptoPortfolio
?: return IllegalStateException("Account not found").left()
(account.cryptoCurrencies + added - removed).any {

View file

@ -315,6 +315,7 @@ internal class AddToPortfolioModel @Inject constructor(
): CryptoCurrency? {
val accountIndex = when (account.account) {
is AccountStatus.CryptoPortfolio -> account.account.account.derivationIndex
is AccountStatus.Payment -> TODO("[REDACTED_JIRA]")
}
return getTokenMarketCryptoCurrency(
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.resourceReference
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.portfolio.add.api.SelectedNetwork
import com.tangem.features.markets.portfolio.add.api.SelectedPortfolio
@ -36,7 +36,7 @@ internal class AddTokenUiBuilder @Inject constructor(
}
private fun createPortfolio(selectedPortfolio: SelectedPortfolio): PortfolioSelectUM {
val accountIcon: AccountIconUM.CryptoPortfolio?
val accountIcon: AccountIconUM?
val portfolioName: TextReference
when (selectedPortfolio.isAccountMode) {
false -> {
@ -47,7 +47,8 @@ internal class AddTokenUiBuilder @Inject constructor(
val accountStatus = selectedPortfolio.account.account
portfolioName = accountStatus.account.accountName.toUM().value
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
getTokenIdIfL2Network(currencyId.value) == currencyRawId.value
}
is AccountStatus.Payment -> TODO("[REDACTED_JIRA]")
}
return accountStatuses.map { accountStatus ->
AccountWithAdded(

View file

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

View file

@ -37,7 +37,7 @@ internal class OnrampAddTokenUiBuilder @Inject constructor(
}
private suspend fun createPortfolio(tokenToAdd: AddHotCryptoData): PortfolioSelectUM {
val accountIcon: AccountIconUM.CryptoPortfolio?
val accountIcon: AccountIconUM?
val portfolioName: TextReference
val isAccountMode = isAccountsModeEnabledUseCase.invokeSync()
when (isAccountMode) {
@ -50,6 +50,7 @@ internal class OnrampAddTokenUiBuilder @Inject constructor(
portfolioName = accountStatus.account.accountName.toUM().value
accountIcon = when (accountStatus) {
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),
isExpanded = true,
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.token.state.TokenItemState
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.utils.converter.Converter
@ -11,12 +12,12 @@ import com.tangem.utils.converter.Converter
*
[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(
state = TokenItemState.Loading(
id = value.currency.id.value,
id = value.id.value,
iconState = CurrencyIconState.Loading,
titleState = TokenItemState.TitleState.Loading,
subtitleState = TokenItemState.SubtitleState.Loading,

View file

@ -18,7 +18,9 @@ internal class SetLoadingTokenItemsTransformer(
override fun transform(prevState: TokenListUM): TokenListUM {
return prevState.copy(
availableItems = LoadingTokenListItemConverter.convertList(input = statuses).toImmutableList(),
availableItems = LoadingTokenListItemConverter.convertList(
input = statuses.map(CryptoCurrencyStatus::currency),
).toImmutableList(),
unavailableItems = persistentListOf(),
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.models.account.Account
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.CryptoCurrencyStatus
import com.tangem.domain.models.tokenlist.TokenList
@ -287,7 +288,7 @@ internal class AvailableSwapPairsModel @Inject constructor(
): TokenListUMTransformer {
val (appCurrency, isBalanceHidden) = appCurrencyAndBalanceHiding
val filterByQueryAccountList = accountList
val filterByQueryAccountList: Map<Account.CryptoPortfolio, List<CryptoCurrencyStatus>> = accountList
.associate { accountStatus ->
when (accountStatus) {
is AccountStatus.CryptoPortfolio -> {
@ -300,6 +301,7 @@ internal class AvailableSwapPairsModel @Inject constructor(
accountStatus.account to statuses
}
is AccountStatus.Payment -> TODO("[REDACTED_JIRA]")
}
}
.filterValues { it.isNotEmpty() }
@ -360,7 +362,7 @@ internal class AvailableSwapPairsModel @Inject constructor(
onRefresh = {
modelScope.launch {
if (networkInfo != null) {
accountList.filterIsInstance<AccountStatus.CryptoPortfolio>()
accountList.filterCryptoPortfolio()
.forEach { (_, currencies) ->
updateAvailablePairs(networkInfo, currencies.flattenCurrencies())
}
@ -384,7 +386,7 @@ internal class AvailableSwapPairsModel @Inject constructor(
val accountList = accountListFlow.firstOrNull() ?: return@collectLatest
updateAvailablePairs(
networkInfo = networkInfo,
statuses = accountList.filterIsInstance<AccountStatus.CryptoPortfolio>()
statuses = accountList.filterCryptoPortfolio()
.flatMap { accountStatus ->
accountStatus.flattenCurrencies()
}.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.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.LoadingTokenListItemConverter
import com.tangem.features.onramp.tokenlist.entity.TokenListUM
@ -22,6 +24,7 @@ internal class SetLoadingAccountTokenListTransformer(
val totalTokensCount = accountList.sumOf { account ->
when (account) {
is AccountStatus.CryptoPortfolio -> account.tokenList.flattenCurrencies().size
is AccountStatus.Payment -> TODO("[REDACTED_JIRA]")
}
}
@ -31,7 +34,7 @@ internal class SetLoadingAccountTokenListTransformer(
tokensListData = if (isAccountsMode) {
TokenListUMData.AccountList(
tokensList = accountListItemConverter.convertList(
accountList.filterIsInstance<AccountStatus.CryptoPortfolio>(),
accountList.filterCryptoPortfolio(),
).toPersistentList(),
totalTokensCount = totalTokensCount,
)
@ -40,8 +43,9 @@ internal class SetLoadingAccountTokenListTransformer(
tokensList = accountList.flatMap { account ->
when (account) {
is AccountStatus.CryptoPortfolio -> LoadingTokenListItemConverter.convertList(
account.tokenList.flattenCurrencies(),
account.tokenList.flattenCurrencies().map(CryptoCurrencyStatus::currency),
)
is AccountStatus.Payment -> TODO("[REDACTED_JIRA]")
}
}.toPersistentList(),
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 ->
when (accountStatus) {
is AccountStatus.CryptoPortfolio -> {
val filteredList = accountStatus.tokenList.flattenCurrencies().filterByQuery(query = query)
accountStatus.account to filteredList
}
is AccountStatus.Payment -> TODO("[REDACTED_JIRA]")
}
}.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.supplier.SingleAccountSupplier
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.currency.CryptoCurrency
import com.tangem.domain.models.wallet.UserWalletId
@ -55,7 +56,10 @@ internal class ReferralInteractorImpl(
)
?: 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
}

View file

@ -127,6 +127,7 @@ internal class ReferralModel @Inject constructor(
val cryptoPortfolio = when (selectedAccount) {
is AccountStatus.CryptoPortfolio -> selectedAccount
is AccountStatus.Payment -> TODO("[REDACTED_JIRA]")
}
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.ui.decompose.ComposableContentComponent
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.domain.models.account.derivationIndex
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.features.send.v2.api.FeeSelectorBlockComponent
import com.tangem.features.send.v2.api.SendComponent

View file

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

View file

@ -158,7 +158,7 @@ internal class SendConfirmComponent(
val feeCryptoCurrencyStatus: CryptoCurrencyStatus,
val cryptoCurrencyStatusFlow: StateFlow<CryptoCurrencyStatus>,
val feeCryptoCurrencyStatusFlow: StateFlow<CryptoCurrencyStatus>,
val accountFlow: StateFlow<Account.CryptoPortfolio?>,
val accountFlow: StateFlow<Account?>,
val isAccountModeFlow: StateFlow<Boolean>,
val appCurrency: AppCurrency,
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)
val isAccountModeFlow: StateFlow<Boolean>
field = MutableStateFlow(false)

View file

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

View file

@ -149,7 +149,7 @@ internal class SendAmountModel @Inject constructor(
private suspend fun initMinBoundary(
cryptoCurrencyStatus: CryptoCurrencyStatus,
account: Account.CryptoPortfolio?,
account: Account?,
isAccountsMode: Boolean,
) {
minAmountBoundary = getMinimumTransactionAmountSyncUseCase(
@ -178,11 +178,7 @@ internal class SendAmountModel @Inject constructor(
}
}
private fun initialState(
cryptoCurrencyStatus: CryptoCurrencyStatus,
account: Account.CryptoPortfolio?,
isAccountsMode: Boolean,
) {
private fun initialState(cryptoCurrencyStatus: CryptoCurrencyStatus, account: Account?, isAccountsMode: Boolean) {
val userWallet = userWallet
if (uiState.value is AmountState.Empty && userWallet != null) {
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.status.supplier.MultiAccountStatusListSupplier
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.wallet.UserWallet
import com.tangem.domain.models.wallet.isLocked
@ -272,36 +272,40 @@ internal class SendDestinationModel @Inject constructor(
return combine(
flow = getWalletsUseCase().conflate(),
flow2 = multiAccountStatusListSupplier().conflate(),
) { wallets, accountList ->
) { wallets, accountStatusLists ->
val cryptoCurrencyNetwork = cryptoCurrency.network
coroutineScope {
accountList.mapNotNull { accountStatusList ->
val wallet =
wallets.filterNot { it.isLocked }.firstOrNull { it.walletId == accountStatusList.userWalletId }
?: return@mapNotNull null
accountStatusLists.mapNotNull { accountStatusList ->
val wallet = wallets
.filterNot { it.isLocked }
.firstOrNull { it.walletId == accountStatusList.userWalletId }
?: return@mapNotNull null
async {
accountStatusList.accountStatuses.map { accountStatus ->
async {
accountStatus.flattenCurrencies()
.filter { it.currency.network.rawId == cryptoCurrencyNetwork.rawId }
.mapNotNull { cryptoCurrencyStatus ->
val address = cryptoCurrencyStatus.value.networkAddress?.defaultAddress?.value
?: return@mapNotNull null
accountStatusList.flattenCurrencies()
.filter { it.currency.network.rawId == cryptoCurrencyNetwork.rawId }
.mapNotNull { cryptoCurrencyStatus ->
val address = cryptoCurrencyStatus.value.networkAddress?.defaultAddress?.value
?: return@mapNotNull null
async {
DestinationWalletUM(
name = wallet.name,
address = address,
cryptoCurrency = cryptoCurrencyStatus.currency,
userWalletId = wallet.walletId,
account = accountStatus.account as? Account.CryptoPortfolio,
)
}
}.awaitAll()
// Find the corresponding account from accountStatuses
val account = accountStatusList.accountStatuses
.filterCryptoPortfolio()
.firstOrNull { accountStatus ->
accountStatus.tokenList
.flattenCurrencies()
.any { it.currency.id == cryptoCurrencyStatus.currency.id }
}?.account
DestinationWalletUM(
name = wallet.name,
address = address,
cryptoCurrency = cryptoCurrencyStatus.currency,
userWalletId = wallet.walletId,
account = account,
)
}
}.awaitAll().flatten()
}
}.awaitAll().flatten()
}

View file

@ -1,9 +1,11 @@
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.CryptoPortfolioIconConverter
import com.tangem.common.ui.account.toUM
import com.tangem.core.ui.extensions.stringReference
import com.tangem.domain.models.account.Account
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.features.send.v2.api.subcomponents.destination.entity.DestinationRecipientListUM
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.Account(
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),
)
} else {

View file

@ -20,5 +20,5 @@ data class DestinationWalletUM(
val userWalletId: UserWalletId,
val address: String,
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 secondaryCryptoCurrency: CryptoCurrency?
abstract val filterProviderTypes: List<ExpressProviderType>
abstract val accountFlow: StateFlow<Account.CryptoPortfolio?>
abstract val accountFlow: StateFlow<Account?>
abstract val isAccountModeFlow: StateFlow<Boolean>
data class AmountParams(
@ -37,7 +37,7 @@ internal sealed class SwapAmountComponentParams {
override val secondaryCryptoCurrency: CryptoCurrency?,
override val filterProviderTypes: List<ExpressProviderType> = emptyList(),
override val analyticsSendSource: CommonSendAnalyticEvents.CommonSendSource,
override val accountFlow: StateFlow<Account.CryptoPortfolio?>,
override val accountFlow: StateFlow<Account?>,
override val isAccountModeFlow: StateFlow<Boolean>,
val title: TextReference,
val callback: SwapAmountComponent.ModelCallback,
@ -54,7 +54,7 @@ internal sealed class SwapAmountComponentParams {
override val secondaryCryptoCurrency: CryptoCurrency?,
override val filterProviderTypes: List<ExpressProviderType> = emptyList(),
override val analyticsSendSource: CommonSendAnalyticEvents.CommonSendSource,
override val accountFlow: StateFlow<Account.CryptoPortfolio?>,
override val accountFlow: StateFlow<Account?>,
override val isAccountModeFlow: StateFlow<Boolean>,
val blockClickEnableFlow: StateFlow<Boolean>,
) : SwapAmountComponentParams()

View file

@ -30,7 +30,7 @@ internal class SwapAmountFieldConverter(
private val clickIntents: AmountScreenClickIntents,
private val isSingleWallet: Boolean,
private val isAccountsMode: Boolean,
private val account: Account.CryptoPortfolio?,
private val account: Account?,
) {
private val iconStateConverter = CryptoCurrencyToIconStateConverter()

View file

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

View file

@ -27,7 +27,7 @@ internal class SwapAmountPrimaryReadyStateTransformer(
private val isShowBestRateAnimation: Boolean,
private val isSingleWallet: Boolean,
private val isAccountsMode: Boolean,
private val account: Account.CryptoPortfolio?,
private val account: Account?,
) : Transformer<SwapAmountUM> {
private val amountFieldConverter = SwapAmountFieldConverter(

View file

@ -28,7 +28,7 @@ internal class SwapAmountSecondaryReadyStateTransformer(
private val isShowBestRateAnimation: Boolean,
private val isSingleWallet: Boolean,
private val isAccountsMode: Boolean,
private val account: Account.CryptoPortfolio?,
private val account: Account?,
) : Transformer<SwapAmountUM> {
private val amountFieldConverter = SwapAmountFieldConverter(

View file

@ -18,7 +18,7 @@ internal data class ConfirmData(
val feeError: GetFeeError?,
val fromCryptoCurrencyStatus: CryptoCurrencyStatus?,
val toCryptoCurrencyStatus: CryptoCurrencyStatus?,
val fromAccount: Account.CryptoPortfolio?,
val fromAccount: Account?,
val quote: SwapQuoteUM?,
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.ui.decompose.ComposableContentComponent
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.SwapDirection
import com.tangem.features.send.v2.api.analytics.CommonSendAnalyticEvents
@ -110,8 +111,11 @@ internal class DefaultSendWithSwapComponent @AssistedInject constructor(
}
is SendWithSwapConfirmComponent -> {
val fromCurrency = params.currency
val fromDerivationIndex = model.accountFlow.value?.derivationIndex?.value
.takeIf { model.isAccountModeFlow.value }
val fromDerivationIndex = when (val account = model.accountFlow.value) {
is Account.CryptoPortfolio -> account.derivationIndex.value
is Account.Payment -> TODO("[REDACTED_JIRA]")
null -> null
}.takeIf { model.isAccountModeFlow.value }
analyticsEventHandler.send(
CommonSendAnalyticEvents.ConfirmationScreenOpened(
categoryName = model.analyticCategoryName,

View file

@ -181,7 +181,7 @@ internal class SendWithSwapConfirmComponent @AssistedInject constructor(
val isBalanceHidingFlow: StateFlow<Boolean>,
val primaryCryptoCurrencyStatusFlow: StateFlow<CryptoCurrencyStatus>,
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 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.domain.express.models.ExpressOperationType
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.CryptoCurrencyStatus
import com.tangem.domain.models.wallet.isHotWallet

View file

@ -129,7 +129,7 @@ internal class SwapTransactionSender @AssistedInject constructor(
fromAmount: BigDecimal,
fromStatus: CryptoCurrencyStatus,
toStatus: CryptoCurrencyStatus,
fromAccount: Account.CryptoPortfolio?,
fromAccount: Account?,
fee: Fee,
feeExtended: TransactionFeeExtended?,
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)
val isAccountModeFlow: StateFlow<Boolean>

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -36,8 +36,8 @@ sealed class SwapTransactionState {
data class StoreTransactionData(
val currencyToSend: CryptoCurrencyStatus,
val currencyToGet: CryptoCurrencyStatus,
val fromAccount: Account.CryptoPortfolio?,
val toAccount: Account.CryptoPortfolio?,
val fromAccount: Account?,
val toAccount: Account?,
val amount: SwapAmount,
val swapProvider: SwapProvider,
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.AccountId
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.UserWalletId
import com.tangem.domain.wallets.analytics.WalletSettingsAnalyticEvents
@ -84,11 +85,11 @@ internal class AccountItemsDelegate @Inject constructor(
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()
}
val accounts = accountStatusList.accountStatuses
val accounts = accountStatusList.accountStatuses.filterCryptoPortfolio()
val header = WalletSettingsAccountsUM.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.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.tokenlist.TokenList
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 {
val draggableTokens = when (tokensListUM) {
OrganizeTokensListUM.EmptyList -> return emptyMap()
@ -43,10 +44,11 @@ internal class CryptoCurrenciesIdsResolver {
}
return accountStatusList?.accountStatuses
?.filter { it.getCryptoTokenList() != TokenList.Empty }
?.filterCryptoPortfolio()
?.filter { it.tokenList != TokenList.Empty }
?.associate { accountStatus ->
val currencies = accountStatus.flattenCurrencies()
accountStatus.account as Account.CryptoPortfolio to draggableTokens
accountStatus.account to draggableTokens
.asSequence()
.filter { it.accountId == accountStatus.account.accountId.value }
.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.TokensSortType
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.feature.wallet.presentation.organizetokens.model.DraggableItem
import com.tangem.feature.wallet.presentation.organizetokens.model.OrganizeTokensListUM
@ -61,7 +61,7 @@ internal class AccountTokenItemConverter(
isGrouped = isGrouping,
items = value.accountStatuses
.asSequence()
.filterIsInstance<AccountStatus.CryptoPortfolio>()
.filterCryptoPortfolio()
.flatMap { accountStatus ->
if (accountStatus.tokenList != TokenList.Empty) {
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.appcurrency.model.AppCurrency
import com.tangem.domain.models.account.Account
import com.tangem.domain.models.account.AccountStatus
import com.tangem.domain.models.tokenlist.TokenList
import com.tangem.feature.wallet.presentation.organizetokens.model.DraggableItem
@ -13,27 +12,26 @@ import kotlinx.collections.immutable.toPersistentList
internal class OrganizedTokenListConverter(
private val appCurrency: AppCurrency,
) : Converter<AccountStatus, PersistentList<DraggableItem>> {
) : Converter<AccountStatus.CryptoPortfolio, PersistentList<DraggableItem>> {
private val tokensConverter by lazy { CryptoCurrencyToDraggableItemConverterV2(appCurrency) }
private val groupsConverter by lazy {
NetworkGroupToDraggableItemsConverterV2(tokensConverter)
}
override fun convert(value: AccountStatus): PersistentList<DraggableItem> {
val cryptoAccount = value.account as? Account.CryptoPortfolio ?: return persistentListOf()
return when (val tokenList = value.getCryptoTokenList()) {
override fun convert(value: AccountStatus.CryptoPortfolio): PersistentList<DraggableItem> {
return when (val tokenList = value.tokenList) {
is TokenList.GroupedByNetwork -> groupsConverter.convertList(
tokenList.groups.map { cryptoAccount to it },
tokenList.groups.map { value.account to it },
)
.flatten()
.toPersistentList()
is TokenList.Ungrouped -> tokensConverter.convertList(
value.flattenCurrencies().map {
value.flattenCurrencies().map { cryptoCurrencyStatus ->
AccountCryptoCurrencyStatus(
account = cryptoAccount,
status = it,
account = value.account,
status = cryptoCurrencyStatus,
)
},
).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)
return singleAccountStatusSupplier(SingleAccountStatusProducer.Params(accountId))
.filterIsInstance<AccountStatus.CryptoPortfolio>()
.distinctUntilChanged()
.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.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.CryptoCurrencyStatus
import com.tangem.domain.models.tokenlist.TokenList
@ -144,6 +145,7 @@ internal class TokenListStateConverter(
}
val accountItems = accountList.accountStatuses
.filterCryptoPortfolio()
.map { accountStatus ->
when (accountStatus) {
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.supplier.SingleAccountStatusListSupplier
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.wallet.UserWallet
import kotlinx.coroutines.flow.Flow
@ -45,11 +46,9 @@ internal abstract class BasicWalletSubscriber : WalletSubscriber() {
protected fun getMainAccountStatusFlow(): Flow<AccountStatus.CryptoPortfolio> {
return getAccountStatusListFlow()
.mapNotNull { accountStatusList ->
accountStatusList.accountStatuses.find { accountStatus ->
when (accountStatus) {
is AccountStatus.CryptoPortfolio -> accountStatus.account.isMainAccount
}
} as? AccountStatus.CryptoPortfolio
accountStatusList.accountStatuses
.filterCryptoPortfolio()
.find { accountStatus -> accountStatus.account.isMainAccount }
}
.distinctUntilChanged()
.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.models.account.Account
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.wallet.UserWallet
import com.tangem.domain.models.wallet.UserWalletId
@ -105,7 +104,7 @@ internal class WcPairModel @Inject constructor(
private val selectedUserWalletFlow: MutableStateFlow<UserWallet> by lazy {
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,
onBufferOverflow = BufferOverflow.DROP_OLDEST,
)
@ -171,7 +170,7 @@ internal class WcPairModel @Inject constructor(
private suspend fun handlePairState(
pairState: WcPairState,
portfolios: PortfolioFetcher.Data? = null,
selected: Pair<UserWallet, AccountStatus>? = null,
selected: Pair<UserWallet, AccountStatus.CryptoPortfolio>? = null,
isAccountMode: Boolean? = null,
) {
when (pairState) {
@ -206,7 +205,7 @@ internal class WcPairModel @Inject constructor(
private suspend fun handleProposalState(
pairState: WcPairState.Proposal,
portfolios: PortfolioFetcher.Data? = null,
selected: Pair<UserWallet, AccountStatus>? = null,
selected: Pair<UserWallet, AccountStatus.CryptoPortfolio>? = null,
) {
val availableWallets = pairState.dAppSession.proposalNetwork.keys
.filter { !it.isLocked && it.isMultiCurrency }
@ -266,7 +265,7 @@ internal class WcPairModel @Inject constructor(
}
private suspend fun tryToCreatePortfolioSelectRow(
selectedPortfolio: Pair<UserWallet, AccountStatus>?,
selectedPortfolio: Pair<UserWallet, AccountStatus.CryptoPortfolio>?,
portfolios: PortfolioFetcher.Data?,
): PortfolioSelectUM? {
selectedPortfolio ?: return null
@ -274,7 +273,6 @@ internal class WcPairModel @Inject constructor(
val (wallet, portfolioAccount) = selectedPortfolio
val account = when (val account = portfolioAccount.account) {
is Account.CryptoPortfolio -> account
is Account.Payment -> TODO("[REDACTED_JIRA]")
}
val isAccountMode = selectorController.isAccountMode.first()
val icon: AccountIconUM.CryptoPortfolio?

View file

@ -48,7 +48,7 @@ internal class WcSessionsAccountModeTransformer(
)
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 }
if (accountSessions.isEmpty()) return@accountsForEach
val connectedApps = accountSessions.map { dappSession ->
@ -65,7 +65,6 @@ internal class WcSessionsAccountModeTransformer(
}
val accountIcon = when (account) {
is Account.CryptoPortfolio -> account.icon
is Account.Payment -> TODO("[REDACTED_JIRA]")
}
val accountTitle = AccountTitleUM.Account(

View file

@ -19,13 +19,12 @@ internal class WcPortfolioNameDelegate @AssistedInject constructor(
isAccountsModeEnabledUseCase: IsAccountsModeEnabledUseCase,
@Assisted private val scope: CoroutineScope,
) {
val isAccountMode = isAccountsModeEnabledUseCase.invoke()
private val isAccountMode = isAccountsModeEnabledUseCase.invoke()
.stateIn(scope = scope, started = SharingStarted.Eagerly, initialValue = false)
fun createAccountTitleUM(value: WcSession): AccountTitleUM? {
val account = when (val account = value.account) {
is Account.CryptoPortfolio -> account
is Account.Payment -> TODO("[REDACTED_JIRA]")
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.ui.UiMessageSender
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.WcRequestUseCaseFactory
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.wrappedList
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.network.Network
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.ui.UiMessageSender
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.WcRequestUseCaseFactory
import com.tangem.domain.walletconnect.model.WcEthMethod