Updated on 2026-08-14

This commit is contained in:
Tangem 2024-02-21 13:42:29 +01:00
parent 15fb5b3954
commit ff1ac5d0e7
6 changed files with 79 additions and 37 deletions

View file

@ -87,7 +87,7 @@ internal class AddCustomTokenViewModel @Inject constructor(
currentCryptoCurrencies = getSelectedWalletSyncUseCase().fold(
ifLeft = { emptyList() },
ifRight = { selectedWallet ->
getCurrenciesUseCase(selectedWallet.walletId).fold(
getCurrenciesUseCase.getSync(selectedWallet.walletId).fold(
ifLeft = { emptyList() },
ifRight = { it },
)

View file

@ -49,7 +49,11 @@ internal class TokensListMigration(
is Either.Right -> {
currentUserWallet = selectedWalletEither.value
when (val currenciesEither = getCurrenciesUseCase(userWalletId = selectedWalletEither.value.walletId)) {
when (
val currenciesEither = getCurrenciesUseCase.getSync(
userWalletId = selectedWalletEither.value.walletId,
)
) {
is Either.Left -> {
Timber.e(currenciesEither.value.toString())
TokensListCryptoCurrencies(coins = emptyList(), tokens = emptyList())

View file

@ -1,16 +1,27 @@
package com.tangem.domain.tokens
import arrow.core.Either
import arrow.core.left
import arrow.core.raise.catch
import arrow.core.raise.either
import arrow.core.right
import com.tangem.domain.tokens.error.GetCurrenciesError
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.tokens.repository.CurrenciesRepository
import com.tangem.domain.wallets.models.UserWalletId
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.map
class GetCryptoCurrenciesUseCase(private val currenciesRepository: CurrenciesRepository) {
suspend operator fun invoke(
operator fun invoke(userWalletId: UserWalletId): Flow<Either<GetCurrenciesError, List<CryptoCurrency>>> {
return currenciesRepository.getMultiCurrencyWalletCurrenciesUpdates(userWalletId)
.map<List<CryptoCurrency>, Either<GetCurrenciesError, List<CryptoCurrency>>> { it.right() }
.catch { emit(GetCurrenciesError.DataError(it).left()) }
}
suspend fun getSync(
userWalletId: UserWalletId,
refresh: Boolean = false,
): Either<GetCurrenciesError, List<CryptoCurrency>> {

View file

@ -424,7 +424,7 @@ internal class AddCustomTokenViewModel @Inject constructor(
selectedWallet: UserWallet,
cryptoCurrency: CryptoCurrency,
): Boolean {
val currenciesList = getCurrenciesUseCase(selectedWallet.walletId).getOrElse { emptyList() }
val currenciesList = getCurrenciesUseCase.getSync(selectedWallet.walletId).getOrElse { emptyList() }
return when (cryptoCurrency) {
is CryptoCurrency.Coin -> {
currenciesList.any {

View file

@ -33,11 +33,15 @@ import com.tangem.utils.Provider
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import com.tangem.utils.coroutines.Debouncer
import com.tangem.utils.coroutines.Debouncer.Companion.DEFAULT_WAIT_TIME_MS
import com.tangem.utils.coroutines.JobHolder
import com.tangem.utils.coroutines.saveIn
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import kotlinx.coroutines.plus
import kotlinx.coroutines.withContext
import timber.log.Timber
import java.util.Collections
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.CopyOnWriteArrayList
import javax.inject.Inject
import kotlin.collections.set
import kotlin.properties.Delegates
@ -62,8 +66,6 @@ internal class ManageTokensViewModel @Inject constructor(
private val analyticsEventHandler: AnalyticsEventHandler,
) : ViewModel(), ManageTokensClickIntents, ManageTokensUiEvents {
private val debouncer = Debouncer()
private val stateFactory = ManageTokensStateFactory(
currentStateProvider = Provider { uiState },
clickIntents = this,
@ -73,11 +75,17 @@ internal class ManageTokensViewModel @Inject constructor(
var uiState: ManageTokensState by mutableStateOf(stateFactory.getInitialState(flowOf(PagingData.from(emptyList()))))
private set
private var allAddedCurrencies: MutableList<CryptoCurrency> = mutableListOf()
private val currenciesListJobHolder: JobHolder = JobHolder()
private var wallets: List<UserWallet> by Delegates.notNull()
private val debouncer = Debouncer()
private var addedCurrenciesByWallet: MutableMap<UserWallet, MutableList<CryptoCurrency>> = mutableMapOf()
private var allAddedCurrencies: MutableList<CryptoCurrency> = Collections.synchronizedList(
mutableListOf<CryptoCurrency>(),
)
private var wallets: CopyOnWriteArrayList<UserWallet> by Delegates.notNull()
private var addedCurrenciesByWallet: MutableMap<UserWallet, MutableList<CryptoCurrency>> = ConcurrentHashMap()
private var selectedWallet: UserWallet? = null
@ -114,34 +122,53 @@ internal class ManageTokensViewModel @Inject constructor(
getWalletsUseCase()
.distinctUntilChanged()
.collectLatest { userWallets ->
wallets = userWallets.filter { it.isMultiCurrency && !it.isLocked }
wallets.map { wallet ->
val currencies = getCurrenciesUseCase(wallet.walletId).fold(
ifLeft = { emptyList() },
ifRight = { it },
)
allAddedCurrencies += currencies
addedCurrenciesByWallet[wallet] = currencies.toMutableList()
}
withContext(dispatchers.main) {
uiState = uiState.copy(tokens = getInitialTokensList())
}
selectedWallet = getSelectedWalletSyncUseCase().fold(
ifLeft = { null },
ifRight = { if (!it.isMultiCurrency || it.isLocked) null else it },
)
if (selectedWallet == null && wallets.isNotEmpty()) {
selectWalletUseCase(wallets.first().walletId)
selectedWallet = wallets.first()
}
updateDerivationNotificationState()
withContext(dispatchers.main) {
uiState = stateFactory.updateChooseWalletState(wallets, userWallets, selectedWallet)
}
launch {
subscribeToCurrencies(userWallets)
}.saveIn(currenciesListJobHolder)
}
}
}
private suspend fun subscribeToCurrencies(userWallets: List<UserWallet>) {
wallets = CopyOnWriteArrayList(userWallets.filter { it.isMultiCurrency && !it.isLocked })
combine(wallets.map { getCurrenciesUseCase.invoke(it.walletId).distinctUntilChanged() }) {
allAddedCurrencies.clear()
addedCurrenciesByWallet.clear()
val walletsWithCurrencies = wallets.zip(
it.map { currencyList ->
currencyList.getOrElse {
Timber.e("Couldn't retrieve currency list")
emptyList()
}
},
)
allAddedCurrencies = walletsWithCurrencies.flatMap { it.second }.toMutableList()
walletsWithCurrencies.forEach { (wallet, currencies) ->
addedCurrenciesByWallet[wallet] = currencies.toMutableList()
}
withContext(dispatchers.main) {
uiState = uiState.copy(tokens = getInitialTokensList())
}
selectedWallet = getSelectedWalletSyncUseCase().fold(
ifLeft = { null },
ifRight = { if (!it.isMultiCurrency || it.isLocked) null else it },
)
if (selectedWallet == null && wallets.isNotEmpty()) {
selectWalletUseCase(wallets.first().walletId)
selectedWallet = wallets.first()
}
updateDerivationNotificationState()
withContext(dispatchers.main) {
uiState = stateFactory.updateChooseWalletState(wallets, userWallets, selectedWallet)
}
}.collect()
}
private fun getInitialTokensList(searchText: String = ""): Flow<PagingData<TokenItemState>> {
return getGlobalTokenListUseCase(searchText = searchText).map {
it.map { token -> tokenConverter.convert(token) }

View file

@ -324,7 +324,7 @@ internal class SendViewModel @Inject constructor(
.filterNot { it.walletId == userWalletId || it.isLocked }
.map { wallet ->
async(dispatchers.io) {
getCryptoCurrenciesUseCase(wallet.walletId)
getCryptoCurrenciesUseCase.getSync(wallet.walletId)
.fold(
ifRight = { currencyItem ->
val walletCurrency = currencyItem.firstOrNull {