Updated on 2026-08-14

This commit is contained in:
Tangem 2026-04-08 15:25:25 +02:00
parent 9944036c4d
commit 9c8bfd4139
15 changed files with 394 additions and 92 deletions

View file

@ -3,5 +3,5 @@ package com.tangem.domain.search.model
data class SearchResult(
val textHints: List<SearchTextHint>,
val recentTokens: List<RecentSearchToken>,
val userAssets: List<UserAssetSearchEntry>,
val userAssets: List<UserAssetSearchItem>,
)

View file

@ -2,6 +2,7 @@ package com.tangem.domain.search.model
import com.tangem.domain.models.account.AccountId
import com.tangem.domain.models.account.AccountName
import com.tangem.domain.models.account.CryptoPortfolioIcon
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.models.wallet.UserWalletId
@ -10,5 +11,6 @@ data class UserAssetSearchEntry(
val userWalletName: String,
val accountId: AccountId,
val accountName: AccountName,
val accountIcon: CryptoPortfolioIcon,
val currencyStatus: CryptoCurrencyStatus,
)

View file

@ -0,0 +1,13 @@
package com.tangem.domain.search.model
sealed interface UserAssetSearchItem {
data class Single(val entry: UserAssetSearchEntry) : UserAssetSearchItem
data class Grouped(
val tokenName: String,
val tokenSymbol: String,
val tokenIconUrl: String?,
val entries: List<UserAssetSearchEntry>,
) : UserAssetSearchItem
}

View file

@ -9,10 +9,12 @@ import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.models.wallet.isLocked
import com.tangem.domain.search.model.SearchResult
import com.tangem.domain.search.model.UserAssetSearchEntry
import com.tangem.domain.search.model.UserAssetSearchItem
import com.tangem.domain.search.repository.SearchRepository
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map
import java.math.BigDecimal
/**
* Primary search use case that produces [SearchResult] based on the current query.
@ -70,9 +72,12 @@ class GetSearchResultsUseCase(
if (unlockedWallets.isEmpty()) return@combine emptyList()
statusLists
val entries = statusLists
.filter { it.userWalletId in unlockedWallets }
.flatMap { statusList -> extractMatchingAssets(statusList, unlockedWallets, lowerQuery) }
val shouldGroup = needsGrouping(unlockedWallets.values, statusLists)
groupAndSort(entries, shouldGroup)
}.map { userAssets ->
SearchResult(
textHints = emptyList(),
@ -82,6 +87,44 @@ class GetSearchResultsUseCase(
}
}
private fun needsGrouping(unlockedWallets: Collection<UserWallet>, statusLists: List<AccountStatusList>): Boolean {
if (unlockedWallets.size > 1) return true
val totalAccounts = statusLists
.filter { sl -> unlockedWallets.any { it.walletId == sl.userWalletId } }
.sumOf { it.accountStatuses.filterCryptoPortfolio().size }
return totalAccounts > 1
}
private fun groupAndSort(entries: List<UserAssetSearchEntry>, shouldGroup: Boolean): List<UserAssetSearchItem> {
if (!shouldGroup) {
return entries
.map { UserAssetSearchItem.Single(it) }
.sortedByDescending { it.entry.currencyStatus.value.fiatAmount ?: BigDecimal.ZERO }
}
val grouped = entries.groupBy { entry ->
val rawId = entry.currencyStatus.currency.id.rawCurrencyId
rawId?.value ?: "${entry.currencyStatus.currency.name}|${entry.currencyStatus.currency.symbol}"
}
return grouped.map { (_, groupEntries) ->
val assetInfo = groupEntries.first()
UserAssetSearchItem.Grouped(
tokenName = assetInfo.currencyStatus.currency.name,
tokenSymbol = assetInfo.currencyStatus.currency.symbol,
tokenIconUrl = assetInfo.currencyStatus.currency.iconUrl,
entries = groupEntries,
)
}.sortedByDescending { item ->
when (item) {
is UserAssetSearchItem.Grouped ->
item.entries.sumOf { it.currencyStatus.value.fiatAmount ?: BigDecimal.ZERO }
}
}
}
private fun extractMatchingAssets(
statusList: AccountStatusList,
wallets: Map<UserWalletId, UserWallet>,
@ -103,6 +146,7 @@ class GetSearchResultsUseCase(
userWalletName = wallet.name,
accountId = accountStatus.accountId,
accountName = accountStatus.account.accountName,
accountIcon = accountStatus.account.icon,
currencyStatus = currencyStatus,
)
}