Updated on 2026-08-14
This commit is contained in:
parent
eabdb1f383
commit
0263ee0a28
5 changed files with 117 additions and 75 deletions
|
|
@ -20,6 +20,7 @@ import com.tangem.tap.domain.walletStores.repository.WalletStoresRepository
|
|||
import com.tangem.tap.features.wallet.models.Currency
|
||||
import com.tangem.tap.features.wallet.models.toBlockchainNetworks
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.firstOrNull
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
internal class DefaultWalletCurrenciesManager(
|
||||
|
|
@ -64,7 +65,15 @@ internal class DefaultWalletCurrenciesManager(
|
|||
saveUserCurrencies(card, newCurrencies)
|
||||
}
|
||||
.flatMap {
|
||||
walletAmountsRepository.updateAmountsForUserWallet(
|
||||
val updatedBlockchains = updatedBlockchainNetworks
|
||||
.map { it.blockchain }
|
||||
val updatedWalletStores = walletStoresRepository.get(userWallet.walletId)
|
||||
.firstOrNull()
|
||||
?.filter { it.blockchain in updatedBlockchains }
|
||||
?: return@flatMap CompletionResult.Success(Unit)
|
||||
|
||||
walletAmountsRepository.updateAmountsForWalletStores(
|
||||
walletStores = updatedWalletStores,
|
||||
userWallet = userWallet,
|
||||
fiatCurrency = appCurrencyProvider(),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -29,6 +29,12 @@ interface WalletAmountsRepository {
|
|||
fiatCurrency: FiatCurrency,
|
||||
): CompletionResult<Unit>
|
||||
|
||||
suspend fun updateAmountsForWalletStores(
|
||||
walletStores: List<WalletStoreModel>,
|
||||
userWallet: UserWallet,
|
||||
fiatCurrency: FiatCurrency,
|
||||
): CompletionResult<Unit>
|
||||
|
||||
/**
|
||||
* Fetch wallet amounts and fiat rates then update [com.tangem.tap.domain.walletStores.storage.WalletStoresStorage]
|
||||
* and [com.tangem.tap.domain.walletStores.storage.WalletManagerStorage] with new data
|
||||
|
|
|
|||
|
|
@ -41,7 +41,8 @@ import com.tangem.tap.network.NetworkConnectivity
|
|||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.awaitAll
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.flow.firstOrNull
|
||||
import kotlinx.coroutines.withContext
|
||||
import timber.log.Timber
|
||||
import java.math.BigDecimal
|
||||
|
|
@ -60,7 +61,7 @@ internal class DefaultWalletAmountsRepository(
|
|||
else withContext(Dispatchers.Default) {
|
||||
awaitAll(
|
||||
async { fetchAmountsForUserWallets(userWallets) },
|
||||
async { fetchFiatRates(userWallets, fiatCurrency) },
|
||||
async { fetchFiatRates(userWallets, walletStores = null, fiatCurrency) },
|
||||
)
|
||||
.fold()
|
||||
}
|
||||
|
|
@ -73,46 +74,40 @@ internal class DefaultWalletAmountsRepository(
|
|||
return updateAmountsForUserWallets(listOf(userWallet), fiatCurrency)
|
||||
}
|
||||
|
||||
override suspend fun updateAmountsForWalletStores(
|
||||
walletStores: List<WalletStoreModel>,
|
||||
userWallet: UserWallet,
|
||||
fiatCurrency: FiatCurrency,
|
||||
): CompletionResult<Unit> {
|
||||
return if (walletStores.isEmpty()) CompletionResult.Success(Unit)
|
||||
else withContext(Dispatchers.Default) {
|
||||
val userWalletId = userWallet.walletId
|
||||
val scanResponse = userWallet.scanResponse
|
||||
|
||||
awaitAll(
|
||||
async { fetchAmountForWalletStores(userWalletId, scanResponse, walletStores) },
|
||||
async { fetchFiatRates(listOf(userWallet), walletStores, fiatCurrency) },
|
||||
)
|
||||
.fold()
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun updateAmountsForWalletStore(
|
||||
walletStore: WalletStoreModel,
|
||||
userWallet: UserWallet,
|
||||
fiatCurrency: FiatCurrency,
|
||||
): CompletionResult<Unit> = withContext(Dispatchers.Default) {
|
||||
val walletId = userWallet.walletId
|
||||
val scanResponse = userWallet.scanResponse
|
||||
|
||||
awaitAll(
|
||||
async {
|
||||
// TODO: Find wallet manager via [com.tangem.tap.domain.walletStores.repository.WalletManagersRepository]
|
||||
val walletManager = walletStore.walletManager
|
||||
fetchAmountsForWalletStore(walletId, scanResponse, walletStore, walletManager)
|
||||
},
|
||||
async { fetchFiatRates(listOf(userWallet), fiatCurrency) },
|
||||
)
|
||||
.fold()
|
||||
}
|
||||
|
||||
private suspend fun fetchAmountsForUserWallets(
|
||||
userWallets: List<UserWallet>,
|
||||
): CompletionResult<Unit> = withContext(Dispatchers.Default) {
|
||||
userWallets.map { async { fetchAmountsForUserWallet(it) } }
|
||||
.awaitAll()
|
||||
.fold()
|
||||
): CompletionResult<Unit> {
|
||||
return updateAmountsForWalletStores(listOf(walletStore), userWallet, fiatCurrency)
|
||||
}
|
||||
|
||||
private suspend fun fetchFiatRates(
|
||||
userWallets: List<UserWallet>,
|
||||
walletStores: List<WalletStoreModel>?,
|
||||
fiatCurrency: FiatCurrency,
|
||||
): CompletionResult<Unit> {
|
||||
val walletsIds = userWallets.map { it.walletId }
|
||||
val walletStores = walletsIds
|
||||
.flatMap {
|
||||
walletStoresStorage.getAll()
|
||||
.first()
|
||||
.getOrElse(it) { emptyList() }
|
||||
}
|
||||
val walletStoresInternal = walletStores ?: getWalletStores(userWallets)
|
||||
|
||||
val currencies = walletStores
|
||||
val currencies = walletStoresInternal
|
||||
.asSequence()
|
||||
.flatMap { it.walletsData }
|
||||
.map { it.currency }
|
||||
|
|
@ -129,7 +124,7 @@ internal class DefaultWalletAmountsRepository(
|
|||
return when (fiatRatesResult) {
|
||||
is Result.Success -> {
|
||||
updateWalletStoresWithFiatRates(
|
||||
walletStores = walletStores,
|
||||
walletStores = walletStoresInternal,
|
||||
fiatRates = fiatRatesResult.data.rates,
|
||||
)
|
||||
|
||||
|
|
@ -145,7 +140,6 @@ internal class DefaultWalletAmountsRepository(
|
|||
error,
|
||||
"""
|
||||
Unable to fetch fiat rates
|
||||
|- User wallets ids: $walletsIds
|
||||
|- Coins ids: $coinsIds
|
||||
""".trimIndent(),
|
||||
)
|
||||
|
|
@ -155,20 +149,34 @@ internal class DefaultWalletAmountsRepository(
|
|||
}
|
||||
}
|
||||
|
||||
private suspend fun fetchAmountsForUserWallets(
|
||||
userWallets: List<UserWallet>,
|
||||
): CompletionResult<Unit> = withContext(Dispatchers.Default) {
|
||||
userWallets.map { async { fetchAmountsForUserWallet(it) } }
|
||||
.awaitAll()
|
||||
.fold()
|
||||
}
|
||||
|
||||
private suspend fun fetchAmountsForUserWallet(
|
||||
userWallet: UserWallet,
|
||||
): CompletionResult<Unit> = withContext(Dispatchers.Default) {
|
||||
val walletId = userWallet.walletId
|
||||
val userWalletId = userWallet.walletId
|
||||
val scanResponse = userWallet.scanResponse
|
||||
val walletStores = walletStoresStorage.getAll()
|
||||
.first()
|
||||
.getOrElse(walletId) { emptyList() }
|
||||
val walletStores = getWalletStores(listOf(userWallet))
|
||||
|
||||
fetchAmountForWalletStores(userWalletId, scanResponse, walletStores)
|
||||
}
|
||||
|
||||
private suspend fun fetchAmountForWalletStores(
|
||||
userWalletId: UserWalletId,
|
||||
scanResponse: ScanResponse,
|
||||
walletStores: List<WalletStoreModel>,
|
||||
): CompletionResult<Unit> = coroutineScope {
|
||||
walletStores.map { walletStore ->
|
||||
async {
|
||||
// TODO: Find wallet manager via [com.tangem.tap.domain.walletStores.repository.WalletManagersRepository]
|
||||
val walletManager = walletStore.walletManager
|
||||
fetchAmountsForWalletStore(walletId, scanResponse, walletStore, walletManager)
|
||||
fetchAmountsForWalletStore(userWalletId, scanResponse, walletStore, walletManager)
|
||||
}
|
||||
}
|
||||
.awaitAll()
|
||||
|
|
@ -176,7 +184,7 @@ internal class DefaultWalletAmountsRepository(
|
|||
}
|
||||
|
||||
private suspend fun fetchAmountsForWalletStore(
|
||||
walletId: UserWalletId,
|
||||
userWalletId: UserWalletId,
|
||||
scanResponse: ScanResponse,
|
||||
walletStore: WalletStoreModel,
|
||||
walletManager: WalletManager?,
|
||||
|
|
@ -186,11 +194,15 @@ internal class DefaultWalletAmountsRepository(
|
|||
}
|
||||
|
||||
return when {
|
||||
hasMissedDerivations -> updateWalletStoreWithMissedDerivation(walletStore)
|
||||
walletManager == null -> updateWalletStoreWithUnreachable(walletStore)
|
||||
hasMissedDerivations -> {
|
||||
updateWalletStoreWithMissedDerivation(walletStore)
|
||||
}
|
||||
walletManager == null -> {
|
||||
updateWalletStoreWithUnreachable(walletStore)
|
||||
}
|
||||
else -> {
|
||||
withInternetConnection { walletManager.update() }
|
||||
.map { updateWalletManagerWithAmounts(walletId, walletManager) }
|
||||
.map { updateWalletManagerWithAmounts(userWalletId, walletManager) }
|
||||
.flatMap {
|
||||
updateWalletStoreWithAmounts(
|
||||
walletStore = walletStore,
|
||||
|
|
@ -248,35 +260,6 @@ internal class DefaultWalletAmountsRepository(
|
|||
return CompletionResult.Success(Unit)
|
||||
}
|
||||
|
||||
private suspend inline fun withInternetConnection(crossinline block: suspend () -> Unit): CompletionResult<Unit> {
|
||||
return if (!NetworkConnectivity.getInstance().isOnlineOrConnecting()) {
|
||||
val error = WalletStoresError.NoInternetConnection
|
||||
Timber.e(error)
|
||||
CompletionResult.Failure(error)
|
||||
} else withContext(Dispatchers.IO) {
|
||||
catching { block() }
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun updateWalletManagerWithAmounts(
|
||||
walletId: UserWalletId,
|
||||
walletManager: WalletManager,
|
||||
) = withContext(Dispatchers.Default) {
|
||||
walletManagersStorage.update { prevManagers ->
|
||||
val newManagersForUserWallet = prevManagers[walletId].orEmpty()
|
||||
.toMutableList()
|
||||
.apply {
|
||||
replaceByOrAdd(walletManager) {
|
||||
it.wallet.blockchain == it.wallet.blockchain
|
||||
}
|
||||
}
|
||||
|
||||
prevManagers.apply {
|
||||
set(walletId, newManagersForUserWallet)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun updateWalletStoreWithError(
|
||||
walletStore: WalletStoreModel,
|
||||
wallet: Wallet,
|
||||
|
|
@ -425,4 +408,44 @@ internal class DefaultWalletAmountsRepository(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend inline fun withInternetConnection(crossinline block: suspend () -> Unit): CompletionResult<Unit> {
|
||||
return if (!NetworkConnectivity.getInstance().isOnlineOrConnecting()) {
|
||||
val error = WalletStoresError.NoInternetConnection
|
||||
Timber.e(error)
|
||||
CompletionResult.Failure(error)
|
||||
} else withContext(Dispatchers.IO) {
|
||||
catching { block() }
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun updateWalletManagerWithAmounts(
|
||||
userWalletId: UserWalletId,
|
||||
walletManager: WalletManager,
|
||||
) = withContext(Dispatchers.Default) {
|
||||
walletManagersStorage.update { prevManagers ->
|
||||
val newManagersForUserWallet = prevManagers[userWalletId].orEmpty()
|
||||
.toMutableList()
|
||||
.apply {
|
||||
replaceByOrAdd(walletManager) {
|
||||
it.wallet.blockchain == it.wallet.blockchain
|
||||
}
|
||||
}
|
||||
|
||||
prevManagers.apply {
|
||||
set(userWalletId, newManagersForUserWallet)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun getWalletStores(userWallets: List<UserWallet>): List<WalletStoreModel> {
|
||||
return userWallets
|
||||
.map { it.walletId }
|
||||
.flatMap { userWalletId ->
|
||||
walletStoresStorage.getAll()
|
||||
.firstOrNull()
|
||||
?.get(userWalletId)
|
||||
.orEmpty()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -62,9 +62,11 @@ internal fun WalletStoreModel.updateWithSelf(
|
|||
): WalletStoreModel {
|
||||
val oldStore = this
|
||||
return oldStore.copy(
|
||||
walletManager = newWalletStore.walletManager,
|
||||
walletRent = newWalletStore.walletRent,
|
||||
derivationPath = newWalletStore.derivationPath,
|
||||
walletsData = oldStore.walletsData.updateWithSelf(newWalletStore.walletsData),
|
||||
walletRent = newWalletStore.walletRent,
|
||||
blockchainNetwork = newWalletStore.blockchainNetwork,
|
||||
walletManager = newWalletStore.walletManager,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import com.tangem.tap.common.analytics.events.MainScreen
|
|||
import com.tangem.tap.common.analytics.events.Token.ButtonRemoveToken
|
||||
import com.tangem.tap.common.extensions.dispatchDialogShow
|
||||
import com.tangem.tap.common.extensions.dispatchErrorNotification
|
||||
import com.tangem.tap.common.extensions.dispatchOnMain
|
||||
import com.tangem.tap.common.extensions.safeUpdate
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.common.redux.global.GlobalState
|
||||
|
|
@ -181,7 +182,7 @@ class MultiWalletMiddleware {
|
|||
private fun scanAndUpdateCard(
|
||||
selectedUserWallet: UserWallet,
|
||||
state: WalletState?,
|
||||
) = scope.launch {
|
||||
) = scope.launch(Dispatchers.Default) {
|
||||
Analytics.send(MainScreen.CardWasScanned())
|
||||
ScanCardProcessor.scan(
|
||||
cardId = selectedUserWallet.cardId,
|
||||
|
|
@ -196,6 +197,7 @@ class MultiWalletMiddleware {
|
|||
},
|
||||
)
|
||||
.doOnSuccess { updatedUserWallet ->
|
||||
store.dispatchOnMain(WalletAction.MultiWallet.AddMissingDerivations(emptyList()))
|
||||
store.state.globalState.tapWalletManager.loadData(updatedUserWallet, refresh = true)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue