Updated on 2026-08-14

This commit is contained in:
Tangem 2025-11-05 13:55:41 +04:00
parent 97363be1e1
commit 866f5927fa
12 changed files with 278 additions and 187 deletions

View file

@ -13,6 +13,7 @@ import javax.inject.Inject
@ModelScoped
internal class WalletContentLoaderFactory @Inject constructor(
private val multiWalletContentLoaderFactory: MultiWalletContentLoaderFactory,
private val multiWalletContentLoaderV2Factory: MultiWalletContentLoaderV2.Factory,
private val singleWalletWithTokenContentLoaderFactory: SingleWalletWithTokenContentLoaderFactory,
private val singleWalletWithTokenContentLoaderV2Factory: SingleWalletWithTokenContentLoaderV2.Factory,
private val accountsFeatureToggles: AccountsFeatureToggles,
@ -28,7 +29,11 @@ internal class WalletContentLoaderFactory @Inject constructor(
): WalletContentLoader? {
return when {
userWallet.isMultiCurrency -> {
multiWalletContentLoaderFactory.create(userWallet, clickIntents)
if (accountsFeatureToggles.isFeatureEnabled) {
multiWalletContentLoaderV2Factory.create(userWallet)
} else {
multiWalletContentLoaderFactory.create(userWallet, clickIntents)
}
}
userWallet is UserWallet.Cold && userWallet.scanResponse.cardTypesResolver.isSingleWalletWithToken() -> {
if (accountsFeatureToggles.isFeatureEnabled) {

View file

@ -12,7 +12,6 @@ import com.tangem.domain.wallets.repository.WalletsRepository
import com.tangem.domain.wallets.usecase.ShouldSaveUserWalletsUseCase
import com.tangem.domain.yield.supply.usecase.YieldSupplyApyFlowUseCase
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
import com.tangem.feature.wallet.presentation.account.AccountDependencies
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsAnalyticsSender
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsSingleEventSender
@ -23,6 +22,7 @@ import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.subscribers.*
@Suppress("LongParameterList")
@Deprecated("Use MultiWalletContentLoaderV2 instead")
@ModelScoped
internal class MultiWalletContentLoader(
private val userWallet: UserWallet,
@ -41,7 +41,6 @@ internal class MultiWalletContentLoader(
private val getStoryContentUseCase: GetStoryContentUseCase,
private val walletsRepository: WalletsRepository,
private val currenciesRepository: CurrenciesRepository,
private val accountDependencies: AccountDependencies,
private val yieldSupplyApyFlowUseCase: YieldSupplyApyFlowUseCase,
private val stakingApyFlowUseCase: StakingApyFlowUseCase,
) : WalletContentLoader(id = userWallet.walletId) {
@ -57,7 +56,6 @@ internal class MultiWalletContentLoader(
tokenListStore = tokenListStore,
getSelectedAppCurrencyUseCase = getSelectedAppCurrencyUseCase,
applyTokenListSortingUseCase = applyTokenListSortingUseCase,
accountDependencies = accountDependencies,
yieldSupplyApyFlowUseCase = yieldSupplyApyFlowUseCase,
stakingApyFlowUseCase = stakingApyFlowUseCase,
).let(::add)

View file

@ -2,12 +2,12 @@ package com.tangem.feature.wallet.presentation.wallet.loaders.implementors
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.nft.GetNFTCollectionsUseCase
import com.tangem.domain.promo.GetStoryContentUseCase
import com.tangem.domain.staking.usecase.StakingApyFlowUseCase
import com.tangem.domain.tokens.ApplyTokenListSortingUseCase
import com.tangem.domain.tokens.repository.CurrenciesRepository
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.staking.usecase.StakingApyFlowUseCase
import com.tangem.domain.wallets.repository.WalletsRepository
import com.tangem.domain.wallets.usecase.ShouldSaveUserWalletsUseCase
import com.tangem.domain.yield.supply.usecase.YieldSupplyApyFlowUseCase
@ -19,10 +19,10 @@ import com.tangem.feature.wallet.presentation.wallet.domain.GetMultiWalletWarnin
import com.tangem.feature.wallet.presentation.wallet.domain.MultiWalletTokenListStore
import com.tangem.feature.wallet.presentation.wallet.domain.WalletWithFundsChecker
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
import com.tangem.feature.wallet.presentation.account.AccountDependencies
import javax.inject.Inject
@Suppress("LongParameterList")
@Deprecated("Use MultiWalletContentLoaderV2.Factory instead")
@ModelScoped
internal class MultiWalletContentLoaderFactory @Inject constructor(
private val stateHolder: WalletStateController,
@ -39,7 +39,6 @@ internal class MultiWalletContentLoaderFactory @Inject constructor(
private val walletsRepository: WalletsRepository,
private val getNFTCollectionsUseCase: GetNFTCollectionsUseCase,
private val currenciesRepository: CurrenciesRepository,
private val accountDependencies: AccountDependencies,
private val yieldSupplyApyFlowUseCase: YieldSupplyApyFlowUseCase,
private val stakingApyFlowUseCase: StakingApyFlowUseCase,
) {
@ -62,7 +61,6 @@ internal class MultiWalletContentLoaderFactory @Inject constructor(
walletsRepository = walletsRepository,
getNFTCollectionsUseCase = getNFTCollectionsUseCase,
currenciesRepository = currenciesRepository,
accountDependencies = accountDependencies,
yieldSupplyApyFlowUseCase = yieldSupplyApyFlowUseCase,
stakingApyFlowUseCase = stakingApyFlowUseCase,
)

View file

@ -0,0 +1,59 @@
package com.tangem.feature.wallet.presentation.wallet.loaders.implementors
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.promo.GetStoryContentUseCase
import com.tangem.domain.wallets.usecase.ShouldSaveUserWalletsUseCase
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsAnalyticsSender
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsSingleEventSender
import com.tangem.feature.wallet.presentation.wallet.domain.GetMultiWalletWarningsFactory
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.subscribers.*
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
@Suppress("LongParameterList")
internal class MultiWalletContentLoaderV2 @AssistedInject constructor(
@Assisted private val userWallet: UserWallet,
private val accountListSubscriberFactory: AccountListSubscriber.Factory,
private val walletNFTListSubscriberV2Factory: WalletNFTListSubscriberV2.Factory,
private val stateController: WalletStateController,
private val clickIntents: WalletClickIntents,
private val walletWarningsAnalyticsSender: WalletWarningsAnalyticsSender,
private val walletWarningsSingleEventSender: WalletWarningsSingleEventSender,
private val getMultiWalletWarningsFactory: GetMultiWalletWarningsFactory,
private val shouldSaveUserWalletsUseCase: ShouldSaveUserWalletsUseCase,
private val getStoryContentUseCase: GetStoryContentUseCase,
private val checkWalletWithFundsSubscriberFactory: CheckWalletWithFundsSubscriber.Factory,
) : WalletContentLoader(id = userWallet.walletId) {
override fun create(): List<WalletSubscriber> = listOf(
accountListSubscriberFactory.create(userWallet = userWallet),
walletNFTListSubscriberV2Factory.create(userWallet = userWallet),
checkWalletWithFundsSubscriberFactory.create(userWallet = userWallet),
MultiWalletWarningsSubscriber(
userWallet = userWallet,
stateHolder = stateController,
clickIntents = clickIntents,
getMultiWalletWarningsFactory = getMultiWalletWarningsFactory,
walletWarningsAnalyticsSender = walletWarningsAnalyticsSender,
walletWarningsSingleEventSender = walletWarningsSingleEventSender,
),
MultiWalletActionButtonsSubscriber(
userWallet = userWallet,
stateHolder = stateController,
getStoryContentUseCase = getStoryContentUseCase,
),
WalletDropDownItemsSubscriber(
stateHolder = stateController,
shouldSaveUserWalletsUseCase = shouldSaveUserWalletsUseCase,
clickIntents = clickIntents,
),
)
@AssistedFactory
interface Factory {
fun create(userWallet: UserWallet): MultiWalletContentLoaderV2
}
}

View file

@ -7,7 +7,6 @@ import com.tangem.domain.staking.usecase.StakingApyFlowUseCase
import com.tangem.domain.wallets.usecase.ShouldSaveUserWalletsUseCase
import com.tangem.domain.yield.supply.usecase.YieldSupplyApyFlowUseCase
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
import com.tangem.feature.wallet.presentation.account.AccountDependencies
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsAnalyticsSender
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsSingleEventSender
@ -32,7 +31,6 @@ internal class SingleWalletWithTokenContentLoader(
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
private val shouldSaveUserWalletsUseCase: ShouldSaveUserWalletsUseCase,
private val getStoryContentUseCase: GetStoryContentUseCase,
private val accountDependencies: AccountDependencies,
private val yieldSupplyApyFlowUseCase: YieldSupplyApyFlowUseCase,
private val stakingApyFlowUseCase: StakingApyFlowUseCase,
) : WalletContentLoader(id = userWallet.walletId) {
@ -47,7 +45,6 @@ internal class SingleWalletWithTokenContentLoader(
walletWithFundsChecker = walletWithFundsChecker,
tokenListStore = tokenListStore,
getSelectedAppCurrencyUseCase = getSelectedAppCurrencyUseCase,
accountDependencies = accountDependencies,
yieldSupplyApyFlowUseCase = yieldSupplyApyFlowUseCase,
stakingApyFlowUseCase = stakingApyFlowUseCase,
).let(::add)

View file

@ -8,7 +8,6 @@ import com.tangem.domain.staking.usecase.StakingApyFlowUseCase
import com.tangem.domain.wallets.usecase.ShouldSaveUserWalletsUseCase
import com.tangem.domain.yield.supply.usecase.YieldSupplyApyFlowUseCase
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
import com.tangem.feature.wallet.presentation.account.AccountDependencies
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsAnalyticsSender
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletWarningsSingleEventSender
@ -33,7 +32,6 @@ internal class SingleWalletWithTokenContentLoaderFactory @Inject constructor(
private val walletWarningsSingleEventSender: WalletWarningsSingleEventSender,
private val shouldSaveUserWalletsUseCase: ShouldSaveUserWalletsUseCase,
private val getStoryContentUseCase: GetStoryContentUseCase,
private val accountDependencies: AccountDependencies,
private val yieldSupplyApyFlowUseCase: YieldSupplyApyFlowUseCase,
private val stakingApyFlowUseCase: StakingApyFlowUseCase,
) {
@ -52,7 +50,6 @@ internal class SingleWalletWithTokenContentLoaderFactory @Inject constructor(
walletWarningsSingleEventSender = walletWarningsSingleEventSender,
getStoryContentUseCase = getStoryContentUseCase,
shouldSaveUserWalletsUseCase = shouldSaveUserWalletsUseCase,
accountDependencies = accountDependencies,
yieldSupplyApyFlowUseCase = yieldSupplyApyFlowUseCase,
stakingApyFlowUseCase = stakingApyFlowUseCase,
)

View file

@ -0,0 +1,57 @@
package com.tangem.feature.wallet.presentation.wallet.subscribers
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.staking.model.stakekit.Yield
import com.tangem.domain.staking.usecase.StakingApyFlowUseCase
import com.tangem.domain.yield.supply.usecase.YieldSupplyApyFlowUseCase
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
import com.tangem.feature.wallet.presentation.account.AccountDependencies
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
import com.tangem.utils.coroutines.combine6
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.distinctUntilChanged
/**
* Subscriber that monitors account list related data and updates the wallet state accordingly.
*
[REDACTED_AUTHOR]
*/
@Suppress("LongParameterList")
internal class AccountListSubscriber @AssistedInject constructor(
@Assisted override val userWallet: UserWallet,
override val accountDependencies: AccountDependencies,
override val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
override val stateController: WalletStateController,
override val clickIntents: WalletClickIntents,
private val yieldSupplyApyFlowUseCase: YieldSupplyApyFlowUseCase,
private val stakingApyFlowUseCase: StakingApyFlowUseCase,
) : BasicAccountListSubscriber() {
override fun create(coroutineScope: CoroutineScope): Flow<*> = combine6(
flow1 = getAccountStatusListFlow(),
flow2 = getAppCurrencyFlow(),
flow3 = accountDependencies.expandedAccountsHolder.expandedAccounts(userWallet),
flow4 = accountDependencies.isAccountsModeEnabledUseCase(),
flow5 = yieldSupplyApyFlow(),
flow6 = stakingApyFlow(),
transform = ::updateState,
)
private fun yieldSupplyApyFlow(): Flow<Map<String, String>> {
return yieldSupplyApyFlowUseCase().distinctUntilChanged()
}
private fun stakingApyFlow(): Flow<Map<String, List<Yield.Validator>>> {
return stakingApyFlowUseCase().distinctUntilChanged()
}
@AssistedFactory
interface Factory {
fun create(userWallet: UserWallet): AccountListSubscriber
}
}

View file

@ -1,7 +1,6 @@
package com.tangem.feature.wallet.presentation.wallet.subscribers
import arrow.core.getOrElse
import com.tangem.domain.account.models.AccountStatusList
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.core.lce.Lce
@ -9,7 +8,6 @@ import com.tangem.domain.core.lce.LceFlow
import com.tangem.domain.core.utils.getOrElse
import com.tangem.domain.models.PortfolioId
import com.tangem.domain.models.TotalFiatBalance
import com.tangem.domain.models.account.AccountStatus
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.models.tokenlist.TokenList
import com.tangem.domain.models.wallet.UserWallet
@ -18,7 +16,6 @@ import com.tangem.domain.staking.usecase.StakingApyFlowUseCase
import com.tangem.domain.tokens.error.TokenListError
import com.tangem.domain.yield.supply.usecase.YieldSupplyApyFlowUseCase
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
import com.tangem.feature.wallet.presentation.account.AccountDependencies
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender
import com.tangem.feature.wallet.presentation.wallet.domain.WalletWithFundsChecker
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
@ -26,43 +23,33 @@ import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetToken
import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetTokenListTransformer
import com.tangem.feature.wallet.presentation.wallet.state.transformers.TokenConverterParams
import com.tangem.utils.coroutines.JobHolder
import com.tangem.utils.coroutines.combine6
import com.tangem.utils.coroutines.saveIn
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.joinAll
import kotlinx.coroutines.launch
import timber.log.Timber
@Deprecated("Use AccountListSubscriber instead")
@Suppress("LongParameterList")
internal abstract class BasicTokenListSubscriber : WalletSubscriber() {
protected abstract val userWallet: UserWallet
protected abstract val stateHolder: WalletStateController
protected abstract val clickIntents: WalletClickIntents
protected abstract val tokenListAnalyticsSender: TokenListAnalyticsSender
protected abstract val walletWithFundsChecker: WalletWithFundsChecker
protected abstract val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase
protected abstract val accountDependencies: AccountDependencies
protected abstract val yieldSupplyApyFlowUseCase: YieldSupplyApyFlowUseCase
protected abstract val stakingApyFlowUseCase: StakingApyFlowUseCase
internal abstract class BasicTokenListSubscriber(
private val userWallet: UserWallet,
private val stateHolder: WalletStateController,
private val clickIntents: WalletClickIntents,
private val tokenListAnalyticsSender: TokenListAnalyticsSender,
private val walletWithFundsChecker: WalletWithFundsChecker,
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
private val yieldSupplyApyFlowUseCase: YieldSupplyApyFlowUseCase,
private val stakingApyFlowUseCase: StakingApyFlowUseCase,
) : WalletSubscriber() {
private val sendAnalyticsJobHolder = JobHolder()
private val onTokenListReceivedJobHolder = JobHolder()
protected val isAccountsEnabled get() = accountDependencies.accountsFeatureToggles.isFeatureEnabled
protected abstract fun tokenListFlow(coroutineScope: CoroutineScope): LceFlow<TokenListError, TokenList>
protected abstract fun accountListFlow(coroutineScope: CoroutineScope): Flow<AccountStatusList>
protected abstract suspend fun onTokenListReceived(maybeTokenList: Lce<TokenListError, TokenList>)
protected open suspend fun onAccountListReceived() = {
// todo account updateSortingIfNeeded? like [onTokenListReceived]
}
override fun create(coroutineScope: CoroutineScope): Flow<*> =
if (isAccountsEnabled) createAccountListFlow(coroutineScope) else createTokenListFlow(coroutineScope)
private fun createTokenListFlow(coroutineScope: CoroutineScope): Flow<*> {
override fun create(coroutineScope: CoroutineScope): Flow<*> {
return combine(
flow = tokenListFlow(coroutineScope)
.onEach { maybeTokenList ->
@ -83,121 +70,41 @@ internal abstract class BasicTokenListSubscriber : WalletSubscriber() {
flow3 = yieldSupplyApyFlow(),
flow4 = stakingApyFlow(),
transform = { maybeTokenList, appCurrency, yieldSupplyApyMap, stakingApyMap ->
singleAccountTransform(
maybeTokenList = maybeTokenList,
val tokenList = maybeTokenList.getOrElse(
ifLoading = { maybeContent ->
val isRefreshing = stateHolder.getWalletState(userWallet.walletId)
?.pullToRefreshConfig
?.isRefreshing == true
maybeContent
?.takeIf { !isRefreshing }
?: return@combine
},
ifError = { e ->
Timber.e("Failed to load token list: $e")
stateHolder.update(
SetTokenListErrorTransformer(
selectedWallet = userWallet,
error = e,
appCurrency = appCurrency,
),
)
return@combine
},
)
updateContent(
params = TokenConverterParams.Wallet(PortfolioId(userWallet.walletId), tokenList),
appCurrency = appCurrency,
portfolioId = PortfolioId(userWallet.walletId),
yieldSupplyApyMap = yieldSupplyApyMap,
stakingApyMap = stakingApyMap,
)
walletWithFundsChecker.check(tokenList)
},
)
}
private suspend fun singleAccountTransform(
maybeTokenList: Lce<TokenListError, TokenList>,
appCurrency: AppCurrency,
portfolioId: PortfolioId,
yieldSupplyApyMap: Map<String, String>,
stakingApyMap: Map<String, List<Yield.Validator>>,
) {
val tokenList = maybeTokenList.getOrElse(
ifLoading = { maybeContent ->
val isRefreshing = stateHolder.getWalletState(userWallet.walletId)
?.pullToRefreshConfig
?.isRefreshing == true
maybeContent
?.takeIf { !isRefreshing }
?: return
},
ifError = { e ->
Timber.e("Failed to load token list: $e")
stateHolder.update(
SetTokenListErrorTransformer(
selectedWallet = userWallet,
error = e,
appCurrency = appCurrency,
),
)
return
},
)
updateContent(
params = TokenConverterParams.Wallet(portfolioId, tokenList),
appCurrency = appCurrency,
yieldSupplyApyMap = yieldSupplyApyMap,
stakingApyMap = stakingApyMap,
)
walletWithFundsChecker.check(tokenList)
}
private fun createAccountListFlow(coroutineScope: CoroutineScope): Flow<*> = combine6(
flow1 = accountListFlow(coroutineScope)
.onEach { accountStatusList ->
coroutineScope.launch {
sendTokenListAnalytics(
flattenCurrencies = accountStatusList.flattenCurrencies(),
totalFiatBalance = accountStatusList.totalFiatBalance,
)
}.saveIn(sendAnalyticsJobHolder)
}
.distinctUntilChanged(),
flow2 = appCurrencyFlow(),
flow3 = accountDependencies.expandedAccountsHolder.expandedAccounts(userWallet),
flow4 = accountDependencies.isAccountsModeEnabledUseCase(),
flow5 = yieldSupplyApyFlow(),
flow6 = stakingApyFlow(),
transform = { accountList, appCurrency, expandedAccounts, isAccountMode, yieldSupplyApyMap, stakingApyMap ->
val accountFlattenTokensList = accountList.flattenTokens()
val accountFlattenCurrencies = accountFlattenTokensList
.map { it.flattenCurrencies() }
.flatten()
val mainAccount = accountList.mainAccount
suspend fun singleAccountTransform(maybeTokenList: Lce<TokenListError, TokenList>) =
this.singleAccountTransform(
maybeTokenList,
appCurrency,
PortfolioId(mainAccount.account.accountId),
yieldSupplyApyMap,
stakingApyMap,
)
when {
!isAccountMode -> when (mainAccount.tokenList.flattenCurrencies().isEmpty()) {
true -> singleAccountTransform(Lce.Error(TokenListError.EmptyTokens))
false -> singleAccountTransform(Lce.Content(mainAccount.tokenList))
}
isAccountMode -> when (accountFlattenCurrencies.isEmpty()) {
true -> stateHolder.update(
SetTokenListErrorTransformer(
selectedWallet = userWallet,
error = TokenListError.EmptyTokens,
appCurrency = appCurrency,
),
)
false -> {
val convertParams = TokenConverterParams.Account(accountList, expandedAccounts)
updateContent(convertParams, appCurrency, yieldSupplyApyMap, stakingApyMap)
accountFlattenTokensList
.map { tokenList -> coroutineScope.launch { walletWithFundsChecker.check(tokenList) } }
.joinAll()
}
}
}
},
)
private fun AccountStatusList.flattenTokens(): List<TokenList> = this.accountStatuses.map {
when (it) {
is AccountStatus.CryptoPortfolio -> it.tokenList
}
}
private suspend fun sendTokenListAnalytics(
flattenCurrencies: List<CryptoCurrencyStatus>?,
totalFiatBalance: TotalFiatBalance?,

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.currency.CryptoCurrencyStatus
import com.tangem.domain.models.wallet.UserWallet
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.conflate
@ -41,16 +42,23 @@ internal abstract class BasicWalletSubscriber : WalletSubscriber() {
*
* @return A [Flow] emitting the [AccountStatus] of the wallet, distinct and conflated.
*/
protected fun getMainAccountStatusFlow(): Flow<AccountStatus> {
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
}
.distinctUntilChanged()
.conflate()
}
protected fun getCryptoCurrencyStatusesFlow(): Flow<List<CryptoCurrencyStatus>> {
return getAccountStatusListFlow()
.mapNotNull(AccountStatusList::flattenCurrencies)
.distinctUntilChanged()
.conflate()
}
}

View file

@ -1,7 +1,5 @@
package com.tangem.feature.wallet.presentation.wallet.subscribers
import com.tangem.domain.account.models.AccountStatusList
import com.tangem.domain.account.status.producer.SingleAccountStatusListProducer
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.core.lce.Lce
import com.tangem.domain.core.lce.LceFlow
@ -15,28 +13,35 @@ import com.tangem.domain.tokens.ApplyTokenListSortingUseCase
import com.tangem.domain.tokens.error.TokenListError
import com.tangem.domain.yield.supply.usecase.YieldSupplyApyFlowUseCase
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
import com.tangem.feature.wallet.presentation.account.AccountDependencies
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender
import com.tangem.feature.wallet.presentation.wallet.domain.MultiWalletTokenListStore
import com.tangem.feature.wallet.presentation.wallet.domain.WalletWithFundsChecker
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
@Deprecated("Use AccountListSubscriber instead")
@Suppress("LongParameterList")
internal class MultiWalletTokenListSubscriber(
override val userWallet: UserWallet,
private val userWallet: UserWallet,
private val tokenListStore: MultiWalletTokenListStore,
private val applyTokenListSortingUseCase: ApplyTokenListSortingUseCase,
override val stateHolder: WalletStateController,
override val clickIntents: WalletClickIntents,
override val tokenListAnalyticsSender: TokenListAnalyticsSender,
override val walletWithFundsChecker: WalletWithFundsChecker,
override val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
override val accountDependencies: AccountDependencies,
override val yieldSupplyApyFlowUseCase: YieldSupplyApyFlowUseCase,
override val stakingApyFlowUseCase: StakingApyFlowUseCase,
) : BasicTokenListSubscriber() {
stateHolder: WalletStateController,
clickIntents: WalletClickIntents,
tokenListAnalyticsSender: TokenListAnalyticsSender,
walletWithFundsChecker: WalletWithFundsChecker,
getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
yieldSupplyApyFlowUseCase: YieldSupplyApyFlowUseCase,
stakingApyFlowUseCase: StakingApyFlowUseCase,
) : BasicTokenListSubscriber(
userWallet = userWallet,
stateHolder = stateHolder,
clickIntents = clickIntents,
tokenListAnalyticsSender = tokenListAnalyticsSender,
walletWithFundsChecker = walletWithFundsChecker,
getSelectedAppCurrencyUseCase = getSelectedAppCurrencyUseCase,
yieldSupplyApyFlowUseCase = yieldSupplyApyFlowUseCase,
stakingApyFlowUseCase = stakingApyFlowUseCase,
) {
override fun tokenListFlow(coroutineScope: CoroutineScope): LceFlow<TokenListError, TokenList> {
tokenListStore.addIfNot(userWallet.walletId, coroutineScope)
@ -44,11 +49,6 @@ internal class MultiWalletTokenListSubscriber(
return tokenListStore.getOrThrow(userWallet.walletId)
}
override fun accountListFlow(coroutineScope: CoroutineScope): Flow<AccountStatusList> {
val params = SingleAccountStatusListProducer.Params(userWallet.walletId)
return accountDependencies.singleAccountStatusListSupplier(params)
}
override suspend fun onTokenListReceived(maybeTokenList: Lce<TokenListError, TokenList>) {
updateSortingIfNeeded(maybeTokenList)
}

View file

@ -1,7 +1,5 @@
package com.tangem.feature.wallet.presentation.wallet.subscribers
import com.tangem.domain.account.models.AccountStatusList
import com.tangem.domain.account.status.producer.SingleAccountStatusListProducer
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.core.lce.Lce
import com.tangem.domain.core.lce.LceFlow
@ -11,28 +9,34 @@ import com.tangem.domain.staking.usecase.StakingApyFlowUseCase
import com.tangem.domain.tokens.error.TokenListError
import com.tangem.domain.yield.supply.usecase.YieldSupplyApyFlowUseCase
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
import com.tangem.feature.wallet.presentation.account.AccountDependencies
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender
import com.tangem.feature.wallet.presentation.wallet.domain.MultiWalletTokenListStore
import com.tangem.feature.wallet.presentation.wallet.domain.WalletWithFundsChecker
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
@Deprecated("Use SingleWalletWithTokenSubscriber instead")
@Suppress("LongParameterList")
internal class SingleWalletWithTokenListSubscriber(
override val userWallet: UserWallet.Cold,
private val userWallet: UserWallet.Cold,
private val tokenListStore: MultiWalletTokenListStore,
override val stateHolder: WalletStateController,
override val clickIntents: WalletClickIntents,
override val tokenListAnalyticsSender: TokenListAnalyticsSender,
override val walletWithFundsChecker: WalletWithFundsChecker,
override val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
override val accountDependencies: AccountDependencies,
override val yieldSupplyApyFlowUseCase: YieldSupplyApyFlowUseCase,
override val stakingApyFlowUseCase: StakingApyFlowUseCase,
) : BasicTokenListSubscriber() {
stateHolder: WalletStateController,
clickIntents: WalletClickIntents,
tokenListAnalyticsSender: TokenListAnalyticsSender,
walletWithFundsChecker: WalletWithFundsChecker,
getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
yieldSupplyApyFlowUseCase: YieldSupplyApyFlowUseCase,
stakingApyFlowUseCase: StakingApyFlowUseCase,
) : BasicTokenListSubscriber(
userWallet = userWallet,
stateHolder = stateHolder,
clickIntents = clickIntents,
tokenListAnalyticsSender = tokenListAnalyticsSender,
walletWithFundsChecker = walletWithFundsChecker,
getSelectedAppCurrencyUseCase = getSelectedAppCurrencyUseCase,
yieldSupplyApyFlowUseCase = yieldSupplyApyFlowUseCase,
stakingApyFlowUseCase = stakingApyFlowUseCase,
) {
override fun tokenListFlow(coroutineScope: CoroutineScope): LceFlow<TokenListError, TokenList> {
tokenListStore.addIfNot(userWallet.walletId, coroutineScope)
@ -40,10 +44,5 @@ internal class SingleWalletWithTokenListSubscriber(
return tokenListStore.getOrThrow(userWallet.walletId)
}
override fun accountListFlow(coroutineScope: CoroutineScope): Flow<AccountStatusList> {
val params = SingleAccountStatusListProducer.Params(userWallet.walletId)
return accountDependencies.singleAccountStatusListSupplier(params)
}
override suspend fun onTokenListReceived(maybeTokenList: Lce<TokenListError, TokenList>) = Unit
}

View file

@ -0,0 +1,66 @@
package com.tangem.feature.wallet.presentation.wallet.subscribers
import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.nft.GetNFTCollectionsUseCase
import com.tangem.domain.wallets.repository.WalletsRepository
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
import com.tangem.feature.wallet.presentation.wallet.state.transformers.RemoveNFTCollectionsTransformer
import com.tangem.feature.wallet.presentation.wallet.state.transformers.SetNFTCollectionsTransformer
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.*
internal class WalletNFTListSubscriberV2 @AssistedInject constructor(
@Assisted override val userWallet: UserWallet,
override val singleAccountStatusListSupplier: SingleAccountStatusListSupplier,
private val walletsRepository: WalletsRepository,
private val getNFTCollectionsUseCase: GetNFTCollectionsUseCase,
private val stateController: WalletStateController,
private val clickIntents: WalletClickIntents,
) : BasicWalletSubscriber() {
@OptIn(ExperimentalCoroutinesApi::class)
override fun create(coroutineScope: CoroutineScope): Flow<*> = combine(
flow = walletsRepository.nftEnabledStatus(userWallet.walletId),
flow2 = getCryptoCurrencyStatusesFlow(),
transform = ::Pair,
)
.distinctUntilChanged()
.flatMapLatest { (nftEnabled, currencies) ->
// if NFT is enabled for this wallet and there are currencies,
// then start observing changes from store and apply transformer if need
if (nftEnabled && currencies.isNotEmpty()) {
getNFTCollectionsUseCase(userWallet.walletId)
.shareIn(
scope = coroutineScope,
started = SharingStarted.WhileSubscribed(),
replay = 1,
)
.onEach {
stateController.update(
SetNFTCollectionsTransformer(
userWalletId = userWallet.walletId,
nftCollections = it,
onItemClick = { clickIntents.onNFTClick(userWallet) },
),
)
}
} else {
// otherwise, hide NFT from wallet
stateController.update(
RemoveNFTCollectionsTransformer(userWallet.walletId),
)
emptyFlow()
}
}
@AssistedFactory
interface Factory {
fun create(userWallet: UserWallet): WalletNFTListSubscriberV2
}
}