Updated on 2026-08-14

This commit is contained in:
Tangem 2026-01-14 12:20:34 +07:00
parent c425d8640d
commit a5b29a4449
8 changed files with 321 additions and 35 deletions

View file

@ -233,15 +233,13 @@ internal class WalletContentClickIntentsImplementor @Inject constructor(
}
override fun onAccountExpandClick(account: Account) {
val userWalletId = stateHolder.getSelectedWalletId()
analyticsEventHandler.send(MainScreenAnalyticsEvent.AccountShowTokens())
accountDependencies.expandedAccountsHolder.expandAccount(userWalletId, account.accountId)
accountDependencies.expandedAccountsHolder.expandAccount(account.accountId)
}
override fun onAccountCollapseClick(account: Account) {
val userWalletId = stateHolder.getSelectedWalletId()
analyticsEventHandler.send(MainScreenAnalyticsEvent.AccountHideTokens())
accountDependencies.expandedAccountsHolder.collapseAccount(userWalletId, account.accountId)
accountDependencies.expandedAccountsHolder.collapseAccount(account.accountId)
}
private fun openYieldSupply(

View file

@ -1,60 +1,100 @@
package com.tangem.feature.wallet.presentation.account
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.domain.account.models.AccountExpandedState
import com.tangem.domain.account.models.AccountList
import com.tangem.domain.account.producer.SingleAccountListProducer
import com.tangem.domain.account.repository.AccountsExpandedRepository
import com.tangem.domain.account.supplier.SingleAccountListSupplier
import com.tangem.domain.account.usecase.IsAccountsModeEnabledUseCase
import com.tangem.domain.models.account.AccountId
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import javax.inject.Inject
@ModelScoped
internal class ExpandedAccountsHolder @Inject constructor(
private val singleAccountListSupplier: SingleAccountListSupplier,
private val isAccountsModeEnabledUseCase: IsAccountsModeEnabledUseCase,
private val accountsExpandedRepository: AccountsExpandedRepository,
private val dispatchers: CoroutineDispatcherProvider,
) {
private val expandedAccounts = MutableStateFlow<Map<UserWalletId, Set<AccountId>>>(mapOf())
private val actionChannel = MutableSharedFlow<Pair<AccountId, Boolean>>(
extraBufferCapacity = 1,
onBufferOverflow = BufferOverflow.DROP_OLDEST,
)
fun expandedAccounts(userWallet: UserWallet): Flow<Set<AccountId>> = channelFlow {
combine(
flow = walletAccounts(userWallet),
flow2 = isAccountsModeEnabledUseCase.invoke(),
transform = { accountList, isAccountsMode ->
val isSingleAccount = accountList.accounts.size == 1
val defaultExpanded = when {
!isAccountsMode -> setOf()
isSingleAccount -> setOf(accountList.mainAccount.accountId)
else -> setOf()
val walletId = userWallet.walletId
val storedState = accountsExpandedRepository.expandedAccounts
.map { it[walletId].orEmpty() }
.stateIn(this)
val isAccountsMode = isAccountsModeEnabledUseCase.invoke()
.stateIn(this)
val initExpandedState = storedState.value
.mapNotNull { it.takeIf { state -> state.isExpanded }?.accountId }
.toSet()
// main state holder
val expandedAccounts = MutableStateFlow(initExpandedState)
actionChannel
.filter { (accountId, _) -> accountId.userWalletId == walletId }
.onEach { (accountId, isExpand) ->
val newState = AccountExpandedState(accountId, isExpand)
launch { accountsExpandedRepository.update(newState) }
if (isExpand) {
expandedAccounts.update { it.plus(accountId) }
} else {
expandedAccounts.update { it.minus(accountId) }
}
expandedAccounts.update { map ->
var expandedSet = map[userWallet.walletId] ?: defaultExpanded
// force expand for single account
if (isSingleAccount || !isAccountsMode) expandedSet = defaultExpanded
map.plus(userWallet.walletId to expandedSet)
}
.launchIn(this)
walletAccounts(walletId).onEach { accountList ->
val idsSet = accountList.accounts.mapTo(mutableSetOf()) { it.accountId }
accountsExpandedRepository.syncStore(walletId, idsSet)
if (!isAccountsMode.value) return@onEach
val isSingleAccount = accountList.accounts.size == 1
val storedMainAccountState = storedState.value
.find { it.accountId == accountList.mainAccount.accountId }
if (isSingleAccount && storedMainAccountState == null) {
// force expand for single and not stored account
expandedAccounts.update { setOf(accountList.mainAccount.accountId) }
}
}.launchIn(this)
combine(
flow = expandedAccounts,
flow2 = isAccountsMode,
transform = { expanded, isAccountMode ->
if (isAccountMode) {
channel.send(expanded)
} else {
channel.send(setOf())
}
},
).launchIn(this)
).collect()
}
.flowOn(dispatchers.default)
.distinctUntilChanged()
expandedAccounts
.mapNotNull { map -> map[userWallet.walletId] }
.onEach { expanded -> channel.send(expanded) }
.collect()
fun expandAccount(accountId: AccountId) {
actionChannel.tryEmit(accountId to true)
}
fun expandAccount(userWalletId: UserWalletId, accountId: AccountId) = expandedAccounts.update { map ->
val expandedSet = map[userWalletId]?.plus(accountId) ?: return@update map
map.plus(userWalletId to expandedSet)
fun collapseAccount(accountId: AccountId) {
actionChannel.tryEmit(accountId to false)
}
fun collapseAccount(userWalletId: UserWalletId, accountId: AccountId) = expandedAccounts.update { map ->
val expandedSet = map[userWalletId]?.minus(accountId) ?: return@update map
map.plus(userWalletId to expandedSet)
}
private fun walletAccounts(userWallet: UserWallet): Flow<AccountList> =
singleAccountListSupplier(SingleAccountListProducer.Params(userWallet.walletId))
private fun walletAccounts(walletId: UserWalletId): Flow<AccountList> = singleAccountListSupplier(walletId)
}