Updated on 2026-08-14
This commit is contained in:
parent
6246065cab
commit
62a0ccb7d3
5 changed files with 173 additions and 44 deletions
|
|
@ -9,6 +9,7 @@ import com.tangem.domain.tokens.repository.CurrenciesRepository
|
|||
import com.tangem.domain.tokens.repository.NetworksRepository
|
||||
import com.tangem.domain.tokens.repository.QuotesRepository
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
|
|
@ -108,4 +109,12 @@ internal object ManageTokensDomainModule {
|
|||
fun provideCheckCurrencyUnsupportedUseCase(repository: ManageTokensRepository): CheckCurrencyUnsupportedUseCase {
|
||||
return CheckCurrencyUnsupportedUseCase(repository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideDistinctManagedCurrenciesTokenUseCase(
|
||||
coroutineDispatchersProvider: CoroutineDispatcherProvider,
|
||||
): GetDistinctManagedCurrenciesUseCase {
|
||||
return GetDistinctManagedCurrenciesUseCase(coroutineDispatchersProvider)
|
||||
}
|
||||
}
|
||||
|
|
@ -22,4 +22,10 @@ dependencies {
|
|||
|
||||
/* Core */
|
||||
api(projects.core.pagination)
|
||||
testImplementation(projects.core.pagination)
|
||||
|
||||
/* Tests */
|
||||
testImplementation(deps.test.junit)
|
||||
testImplementation(deps.test.coroutine)
|
||||
testImplementation(deps.test.truth)
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package com.tangem.domain.managetokens
|
||||
|
||||
import com.tangem.domain.managetokens.model.ManagedCryptoCurrency
|
||||
import com.tangem.pagination.Batch
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class GetDistinctManagedCurrenciesUseCase(
|
||||
private val coroutineDispatchersProvider: CoroutineDispatcherProvider,
|
||||
) {
|
||||
|
||||
// FIXME: Add interception functionality to BatchFlow state and call this on domain
|
||||
// [REDACTED_JIRA]
|
||||
suspend operator fun invoke(
|
||||
batches: List<Batch<Int, List<ManagedCryptoCurrency>>>,
|
||||
): List<Batch<Int, List<ManagedCryptoCurrency>>> = withContext(coroutineDispatchersProvider.default) {
|
||||
val seenIds = mutableSetOf<ManagedCryptoCurrency.ID>()
|
||||
|
||||
batches.map { batch ->
|
||||
val filtered = batch.data.filter { currency ->
|
||||
seenIds.add(currency.id)
|
||||
}
|
||||
batch.copy(data = filtered)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
package com.tangem.domain.managetokens
|
||||
|
||||
import com.tangem.domain.managetokens.model.ManagedCryptoCurrency
|
||||
import com.tangem.utils.coroutines.TestingCoroutineDispatcherProvider
|
||||
import com.tangem.pagination.Batch
|
||||
import org.junit.Test
|
||||
import java.util.UUID
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.test.runTest
|
||||
|
||||
class GetDistinctManagedTokensUseCaseTest {
|
||||
|
||||
private val useCase = GetDistinctManagedCurrenciesUseCase(TestingCoroutineDispatcherProvider())
|
||||
|
||||
@Test
|
||||
fun `GIVEN generated batch with multiple duplicates WHEN invoke THEN batches with unique manage currencies`() =
|
||||
runTest {
|
||||
// GIVEN
|
||||
val totalBatches = 10
|
||||
val batchSize = 20
|
||||
val duplicatePerBatch = 5
|
||||
val uniquePerBatch = batchSize - duplicatePerBatch
|
||||
val globalTokens = mutableListOf<ManagedCryptoCurrency>()
|
||||
val batches = mutableListOf<Batch<Int, List<ManagedCryptoCurrency>>>()
|
||||
|
||||
repeat(totalBatches) { batchIndex ->
|
||||
val duplicates = if (batchIndex == 0) {
|
||||
emptyList()
|
||||
} else {
|
||||
globalTokens.take(duplicatePerBatch)
|
||||
}
|
||||
|
||||
val newTokens = List(uniquePerBatch) {
|
||||
val token = testToken(id = "token_${batchIndex}_$it")
|
||||
globalTokens += token
|
||||
token
|
||||
}
|
||||
|
||||
val batch = Batch(batchIndex, duplicates + newTokens)
|
||||
batches += batch
|
||||
}
|
||||
|
||||
// WHEN
|
||||
val result = useCase(batches)
|
||||
|
||||
// THEN
|
||||
val seenIds = mutableSetOf<ManagedCryptoCurrency.ID>()
|
||||
|
||||
result.forEach { batch ->
|
||||
batch.data.forEach { token ->
|
||||
assertThat(seenIds).doesNotContain(token.id)
|
||||
seenIds.add(token.id)
|
||||
}
|
||||
}
|
||||
|
||||
val totalTokens = result.sumOf { it.data.size }
|
||||
assertThat(totalTokens).isEqualTo(totalBatches * (batchSize - duplicatePerBatch))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN static batch with multiple duplicates WHEN invoke THEN batches with unique manage currencies`() =
|
||||
runTest {
|
||||
// GIVEN
|
||||
val token1 = testToken(id = "A", name = "Delta")
|
||||
val token2 = testToken(id = "B", name = "Delta")
|
||||
val token3 = testToken(id = "C", name = "Delta")
|
||||
val token4 = testToken(id = "D", name = "Delta")
|
||||
val token5 = testToken(id = "E", name = "Delta")
|
||||
val token6 = testToken(id = "F", name = "Delta")
|
||||
val token7 = testToken(id = "G", name = "Delta")
|
||||
val token8 = testToken(id = "H", name = "Delta")
|
||||
val token9 = testToken(id = "I", name = "Delta")
|
||||
val token10 = testToken(id = "J", name = "Delta")
|
||||
|
||||
val batches = listOf(
|
||||
Batch(0, listOf(token1, token2, token3, token4, token5)),
|
||||
Batch(1, listOf(token1, token7, token8, token9, token6)),
|
||||
Batch(2, listOf(token2, token8, token8, token6, token10)),
|
||||
)
|
||||
|
||||
// WHEN
|
||||
val result = useCase(batches)
|
||||
|
||||
// THEN
|
||||
val seenIds = mutableSetOf<ManagedCryptoCurrency.ID>()
|
||||
|
||||
result.forEach { batch ->
|
||||
batch.data.forEach { token ->
|
||||
assertThat(seenIds).doesNotContain(token.id)
|
||||
seenIds.add(token.id)
|
||||
}
|
||||
}
|
||||
|
||||
val totalTokens = result.sumOf { it.data.size }
|
||||
assertThat(totalTokens).isEqualTo(10)
|
||||
}
|
||||
}
|
||||
|
||||
fun testToken(
|
||||
id: String = UUID.randomUUID().toString(),
|
||||
name: String = "Test Token",
|
||||
symbol: String = "TTK",
|
||||
): ManagedCryptoCurrency {
|
||||
return ManagedCryptoCurrency.Token(
|
||||
id = ManagedCryptoCurrency.ID(id),
|
||||
name = name,
|
||||
symbol = symbol,
|
||||
iconUrl = "null",
|
||||
availableNetworks = emptyList(),
|
||||
addedIn = emptySet(),
|
||||
)
|
||||
}
|
||||
|
|
@ -1,7 +1,5 @@
|
|||
package com.tangem.features.managetokens.utils.list
|
||||
|
||||
import androidx.compose.ui.util.fastForEachIndexed
|
||||
import androidx.compose.ui.util.fastMap
|
||||
import arrow.core.getOrElse
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
|
|
@ -10,10 +8,7 @@ import com.tangem.core.ui.clipboard.ClipboardManager
|
|||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.message.SnackbarMessage
|
||||
import com.tangem.domain.managetokens.CheckCurrencyUnsupportedUseCase
|
||||
import com.tangem.domain.managetokens.CheckHasLinkedTokensUseCase
|
||||
import com.tangem.domain.managetokens.GetManagedTokensUseCase
|
||||
import com.tangem.domain.managetokens.RemoveCustomManagedCryptoCurrencyUseCase
|
||||
import com.tangem.domain.managetokens.*
|
||||
import com.tangem.domain.managetokens.model.*
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
|
@ -43,6 +38,7 @@ import javax.inject.Inject
|
|||
@ModelScoped
|
||||
internal class ManageTokensListManager @Inject constructor(
|
||||
private val getManagedTokensUseCase: GetManagedTokensUseCase,
|
||||
private val getDistinctManagedTokensUseCase: GetDistinctManagedCurrenciesUseCase,
|
||||
private val checkHasLinkedTokensUseCase: CheckHasLinkedTokensUseCase,
|
||||
private val removeCustomCurrencyUseCase: RemoveCustomManagedCryptoCurrencyUseCase,
|
||||
private val checkCurrencyUnsupportedUseCase: CheckCurrencyUnsupportedUseCase,
|
||||
|
|
@ -166,47 +162,27 @@ internal class ManageTokensListManager @Inject constructor(
|
|||
return
|
||||
}
|
||||
|
||||
state.update { state ->
|
||||
val newBatches = distinctCurrencies(batchListState.data)
|
||||
val currentBatches = state.currencyBatches
|
||||
scope.launch {
|
||||
state.update { state ->
|
||||
val newBatches = getDistinctManagedTokensUseCase(batchListState.data)
|
||||
val currentBatches = state.currencyBatches
|
||||
|
||||
// Distinct until changed
|
||||
if (newBatches.size == currentBatches.size &&
|
||||
newBatches.map { it.key } == currentBatches.map { it.key } &&
|
||||
newBatches.flatMap { it.data } == currentBatches.flatMap { it.data }
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
val canEditItems = userWalletId != null
|
||||
state.copy(
|
||||
userWalletId = userWalletId,
|
||||
currencyBatches = newBatches,
|
||||
uiBatches = uiManager.createOrUpdateUiBatches(newBatches, canEditItems),
|
||||
canEditItems = canEditItems,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Add interception functionality to BatchFlow state and do this on domain
|
||||
// [REDACTED_JIRA]
|
||||
private fun distinctCurrencies(
|
||||
batches: List<Batch<Int, List<ManagedCryptoCurrency>>>,
|
||||
): List<Batch<Int, List<ManagedCryptoCurrency>>> {
|
||||
val allCurrenciesIds = mutableListOf<ManagedCryptoCurrency.ID>()
|
||||
|
||||
return batches.fastMap { batch ->
|
||||
val batchCurrencies = batch.data.toMutableList()
|
||||
|
||||
batch.data.fastForEachIndexed { index, currency ->
|
||||
if (currency.id in allCurrenciesIds) {
|
||||
batchCurrencies.removeAt(index)
|
||||
} else {
|
||||
allCurrenciesIds.add(currency.id)
|
||||
// Distinct until changed
|
||||
if (newBatches.size == currentBatches.size &&
|
||||
newBatches.map { it.key } == currentBatches.map { it.key } &&
|
||||
newBatches.flatMap { it.data } == currentBatches.flatMap { it.data }
|
||||
) {
|
||||
return@launch
|
||||
}
|
||||
}
|
||||
|
||||
batch.copy(data = batchCurrencies)
|
||||
val canEditItems = userWalletId != null
|
||||
state.copy(
|
||||
userWalletId = userWalletId,
|
||||
currencyBatches = newBatches,
|
||||
uiBatches = uiManager.createOrUpdateUiBatches(newBatches, canEditItems),
|
||||
canEditItems = canEditItems,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue