Updated on 2026-08-14

This commit is contained in:
Tangem 2025-11-07 10:40:40 +05:00
parent d1191ec881
commit 96e28b2d1f
6 changed files with 112 additions and 21 deletions

View file

@ -136,4 +136,24 @@ internal object AccountStatusUseCaseModule {
parallelUpdatingScope = CoroutineScope(SupervisorJob() + dispatchers.default),
)
}
@Provides
@Singleton
fun provideToggleTokenListSortingUseCaseV2(
dispatchers: CoroutineDispatcherProvider,
): ToggleTokenListSortingUseCaseV2 {
return ToggleTokenListSortingUseCaseV2(
dispatchers = dispatchers,
)
}
@Provides
@Singleton
fun provideToggleTokenListGroupingUseCaseV2(
dispatchers: CoroutineDispatcherProvider,
): ToggleTokenListGroupingUseCaseV2 {
return ToggleTokenListGroupingUseCaseV2(
dispatchers = dispatchers,
)
}
}

View file

@ -4,6 +4,7 @@ import arrow.core.Either
import arrow.core.raise.ensure
import com.tangem.domain.account.models.AccountStatusList
import com.tangem.domain.core.utils.eitherOn
import com.tangem.domain.models.TokensGroupType
import com.tangem.domain.models.TotalFiatBalance
import com.tangem.domain.models.account.AccountStatus
import com.tangem.domain.models.tokenlist.TokenList
@ -42,11 +43,18 @@ class ToggleTokenListGroupingUseCaseV2(
TokenListSortingError.TokenListIsLoading
}
accountStatusList.copy(
accountStatuses = accountStatusList.accountStatuses.map { account ->
if (account !is AccountStatus.CryptoPortfolio) return@map account
val updatedAccountList = accountStatusList.accountStatuses.map { account ->
if (account !is AccountStatus.CryptoPortfolio) return@map account
account.copy(tokenList = account.tokenList.reverseGroupType())
account.copy(tokenList = account.tokenList.reverseGroupType())
}
accountStatusList.copy(
accountStatuses = updatedAccountList,
groupType = when (updatedAccountList.firstOrNull()?.getCryptoTokenList()) {
is TokenList.GroupedByNetwork -> TokensGroupType.NETWORK
is TokenList.Ungrouped -> TokensGroupType.NONE
else -> accountStatusList.groupType
},
)
}

View file

@ -64,7 +64,7 @@ class ToggleTokenListGroupingUseCaseV2Test {
currencies = listOf(mockk(relaxed = true)),
)
val accountStatusList = createAccountStatusList(tokenList)
val accountStatusList = createAccountStatusList(tokenList, TokensGroupType.NONE)
// Act
val actual = useCase(accountStatusList)
@ -86,7 +86,7 @@ class ToggleTokenListGroupingUseCaseV2Test {
sortedBy = TokensSortType.BALANCE,
)
val accountStatusList = createAccountStatusList(tokenList)
val accountStatusList = createAccountStatusList(tokenList, TokensGroupType.NONE)
val updatedTokenList = createGroupedByNetwork(
statuses = listOf(
@ -101,7 +101,7 @@ class ToggleTokenListGroupingUseCaseV2Test {
val actual = useCase(accountStatusList)
// Assert
val expected = createAccountStatusList(updatedTokenList).right()
val expected = createAccountStatusList(updatedTokenList, TokensGroupType.NETWORK).right()
Truth.assertThat(actual).isEqualTo(expected)
}
@ -116,7 +116,7 @@ class ToggleTokenListGroupingUseCaseV2Test {
),
)
val accountStatusList = createAccountStatusList(tokenList)
val accountStatusList = createAccountStatusList(tokenList, TokensGroupType.NONE)
val updatedTokenList = createGroupedByNetwork(
statuses = listOf(
@ -130,7 +130,7 @@ class ToggleTokenListGroupingUseCaseV2Test {
val actual = useCase(accountStatusList)
// Assert
val expected = createAccountStatusList(updatedTokenList).right()
val expected = createAccountStatusList(updatedTokenList, TokensGroupType.NETWORK).right()
Truth.assertThat(actual).isEqualTo(expected)
}
@ -146,7 +146,7 @@ class ToggleTokenListGroupingUseCaseV2Test {
sortedBy = TokensSortType.BALANCE,
)
val accountStatusList = createAccountStatusList(tokenList)
val accountStatusList = createAccountStatusList(tokenList, TokensGroupType.NETWORK)
val updatedTokenList = createUngrouped(
statuses = listOf(
@ -161,7 +161,7 @@ class ToggleTokenListGroupingUseCaseV2Test {
val actual = useCase(accountStatusList)
// Assert
val expected = createAccountStatusList(updatedTokenList).right()
val expected = createAccountStatusList(updatedTokenList, TokensGroupType.NONE).right()
Truth.assertThat(actual).isEqualTo(expected)
}
@ -176,7 +176,7 @@ class ToggleTokenListGroupingUseCaseV2Test {
),
)
val accountStatusList = createAccountStatusList(tokenList)
val accountStatusList = createAccountStatusList(tokenList, TokensGroupType.NETWORK)
val updatedTokenList = createUngrouped(
statuses = listOf(
@ -190,11 +190,11 @@ class ToggleTokenListGroupingUseCaseV2Test {
val actual = useCase(accountStatusList)
// Assert
val expected = createAccountStatusList(updatedTokenList).right()
val expected = createAccountStatusList(updatedTokenList, TokensGroupType.NONE).right()
Truth.assertThat(actual).isEqualTo(expected)
}
private fun createAccountStatusList(tokenList: TokenList): AccountStatusList {
private fun createAccountStatusList(tokenList: TokenList, groupType: TokensGroupType): AccountStatusList {
val accountStatus = AccountStatus.CryptoPortfolio(
account = Account.CryptoPortfolio.createMainAccount(userWalletId),
tokenList = tokenList,
@ -207,7 +207,7 @@ class ToggleTokenListGroupingUseCaseV2Test {
totalAccounts = 1,
totalFiatBalance = tokenList.totalFiatBalance,
sortType = tokenList.sortedBy,
groupType = TokensGroupType.NONE,
groupType = groupType,
)
}
}

View file

@ -11,6 +11,9 @@ import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles
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.account.status.usecase.ApplyTokenListSortingUseCaseV2
import com.tangem.domain.account.status.usecase.ToggleTokenListGroupingUseCaseV2
import com.tangem.domain.account.status.usecase.ToggleTokenListSortingUseCaseV2
import com.tangem.domain.account.usecase.IsAccountsModeEnabledUseCase
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.appcurrency.model.AppCurrency
@ -55,6 +58,9 @@ internal class OrganizeTokensModel @Inject constructor(
private val accountsFeatureToggles: AccountsFeatureToggles,
private val isAccountsModeEnabledUseCase: IsAccountsModeEnabledUseCase,
private val singleAccountStatusListSupplier: SingleAccountStatusListSupplier,
private val toggleTokenListGroupingUseCaseV2: ToggleTokenListGroupingUseCaseV2,
private val toggleTokenListSortingUseCaseV2: ToggleTokenListSortingUseCaseV2,
private val applyTokenListSortingUseCaseV2: ApplyTokenListSortingUseCaseV2,
) : Model(), OrganizeTokensIntents {
private val selectedAppCurrencyFlow = createSelectedAppCurrencyFlow()
@ -82,6 +88,8 @@ internal class OrganizeTokensModel @Inject constructor(
private var cachedTokenList: TokenList? = null
private var cachedAccountStatusList: AccountStatusList? = null
private var isAccountsModeEnabled: Boolean = false
val uiState: StateFlow<OrganizeTokensState> = stateHolder.stateFlow
val onBack = MutableSharedFlow<Unit>()
@ -112,7 +120,13 @@ internal class OrganizeTokensModel @Inject constructor(
analyticsEventsHandler.send(PortfolioOrganizeTokensAnalyticsEvent.ByBalance)
modelScope.launch {
// todo account token list sorting
toggleTokenListSortingUseCaseV2(list).fold(
ifLeft = stateHolder::updateStateWithError,
ifRight = {
stateHolder.updateStateAfterTokenListSortingV2(it, isAccountsModeEnabled)
cachedAccountStatusList = it
},
)
}
} else {
val list = cachedTokenList ?: return
@ -134,10 +148,18 @@ internal class OrganizeTokensModel @Inject constructor(
override fun onGroupClick() {
if (accountsFeatureToggles.isFeatureEnabled) {
cachedAccountStatusList ?: return
val list = cachedAccountStatusList ?: return
analyticsEventsHandler.send(PortfolioOrganizeTokensAnalyticsEvent.Group)
modelScope.launch {
// todo account token list grouping
toggleTokenListGroupingUseCaseV2(list).fold(
ifLeft = stateHolder::updateStateWithError,
ifRight = {
stateHolder.updateStateAfterTokenListSortingV2(it, isAccountsModeEnabled)
cachedAccountStatusList = it
},
)
}
} else {
val list = cachedTokenList ?: return
@ -172,8 +194,11 @@ internal class OrganizeTokensModel @Inject constructor(
isSortedByBalance = isSortedByBalance,
)
// val sorted = resolver.resolveV2(tokensListUM, cachedAccountStatusList)
TODO("Implement account token list sorting")
applyTokenListSortingUseCaseV2(
sortedTokensIdsByAccount = resolver.resolveV2(tokensListUM, cachedAccountStatusList),
isGroupedByNetwork = isGroupedByNetwork,
isSortedByBalance = isSortedByBalance,
)
} else {
val listState = uiState.value.itemsState
@ -215,7 +240,7 @@ internal class OrganizeTokensModel @Inject constructor(
SingleAccountStatusListProducer.Params(userWalletId),
) ?: return@launch
val isAccountsModeEnabled = isAccountsModeEnabledUseCase.invokeSync()
isAccountsModeEnabled = isAccountsModeEnabledUseCase.invokeSync()
stateHolder.updateStateWithAccountList(
accountStatusList = accountList,

View file

@ -79,6 +79,18 @@ internal class OrganizeTokensStateHolder(
}
}
fun updateStateAfterTokenListSortingV2(accountStatusList: AccountStatusList, isAccountsModeEnabled: Boolean) {
updateState {
TokenListToStateConverterV2(
accountStatusList = accountStatusList,
isAccountsMode = isAccountsModeEnabled,
appCurrency = appCurrencyProvider(),
).transform(this).copy(
scrollListToTop = triggeredEvent(Unit, ::consumeScrollListToTopEvent),
)
}
}
fun updateStateToDisplayProgress() {
updateState { inProgressStateConverter.convert(value = this) }
}

View file

@ -1,9 +1,13 @@
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.currency.CryptoCurrency
import com.tangem.domain.models.tokenlist.TokenList
import com.tangem.feature.wallet.presentation.organizetokens.model.DraggableItem
import com.tangem.feature.wallet.presentation.organizetokens.model.OrganizeTokensListState
import com.tangem.feature.wallet.presentation.organizetokens.model.OrganizeTokensListUM
internal class CryptoCurrenciesIdsResolver {
@ -29,4 +33,26 @@ internal class CryptoCurrenciesIdsResolver {
currencyStatus?.currency?.id
}
}
fun resolveV2(tokensListUM: OrganizeTokensListUM, accountStatusList: AccountStatusList?): AccountCryptoCurrencies {
val draggableTokens = when (tokensListUM) {
OrganizeTokensListUM.EmptyList -> return emptyMap()
is OrganizeTokensListUM.AccountList,
is OrganizeTokensListUM.TokensList,
-> tokensListUM.items.filterIsInstance<DraggableItem.Token>()
}
return accountStatusList?.accountStatuses
?.filter { it.getCryptoTokenList() != TokenList.Empty }
?.associate { accountStatus ->
val currencies = accountStatus.flattenCurrencies()
accountStatus.account as Account.CryptoPortfolio to draggableTokens
.asSequence()
.filter { it.accountId == accountStatus.account.accountId.value }
.mapNotNull { sortedToken ->
currencies.firstOrNull { it.currency.id.value == sortedToken.id }?.currency
}
.toList()
} ?: emptyMap()
}
}