From 480f66e8b2617ccc117dfd5d563402a05d0045b9 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 31 Mar 2023 16:10:58 +0300 Subject: [PATCH] Updated on 2026-08-14 --- .../DefaultWalletCurrenciesManager.kt | 8 ++ .../redux/middlewares/WalletMiddleware.kt | 85 ++++++++++--------- .../tap/features/wallet/ui/WalletViewModel.kt | 10 +++ .../tangem/utils/coroutines/CoroutineExt.kt | 8 ++ 4 files changed, 70 insertions(+), 41 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/domain/walletCurrencies/implementation/DefaultWalletCurrenciesManager.kt b/app/src/main/java/com/tangem/tap/domain/walletCurrencies/implementation/DefaultWalletCurrenciesManager.kt index 97d9eb72e5..d32bdd60ff 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletCurrencies/implementation/DefaultWalletCurrenciesManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletCurrencies/implementation/DefaultWalletCurrenciesManager.kt @@ -61,6 +61,10 @@ internal class DefaultWalletCurrenciesManager( userWallet: UserWallet, currenciesToAdd: List, ): CompletionResult = withContext(Dispatchers.Default) { + if (currenciesToAdd.isEmpty()) { + return@withContext CompletionResult.Success(Unit) + } + val card = userWallet.scanResponse.card val currenciesToAddWithMissingBlockchains = currenciesToAdd.addMissingBlockchainsIfNeeded(card) listeners.forEach { it.willCurrenciesAdd(userWallet, currenciesToAddWithMissingBlockchains) } @@ -86,6 +90,10 @@ internal class DefaultWalletCurrenciesManager( userWallet: UserWallet, currenciesToRemove: List, ): CompletionResult = withContext(Dispatchers.Default) { + if (currenciesToRemove.isEmpty()) { + return@withContext CompletionResult.Success(Unit) + } + listeners.forEach { it.willCurrenciesRemove(userWallet, currenciesToRemove) } val card = userWallet.scanResponse.card val remainingCurrencies = getSavedCurrencies(userWallet.walletId) diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt index fafa99c7b3..2c4ad663cb 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt @@ -42,8 +42,10 @@ import com.tangem.tap.store import com.tangem.tap.tangemSdkManager import com.tangem.tap.totalFiatBalanceCalculator import com.tangem.tap.userWalletsListManager +import com.tangem.utils.coroutines.ifActive import com.tangem.wallet.R import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job import kotlinx.coroutines.delay import kotlinx.coroutines.launch import org.rekotlin.Action @@ -70,6 +72,12 @@ class WalletMiddleware { private val networkConnectionManager: NetworkConnectionManager get() = store.state.daggerGraphState.get(DaggerGraphState::networkConnectionManager) + private var updateWalletStoresJob: Job? = null + set(value) { + field?.cancel() + field = value + } + val walletMiddleware: Middleware = { _, state -> { next -> { action -> @@ -176,11 +184,14 @@ class WalletMiddleware { } is WalletAction.UserWalletChanged -> Unit is WalletAction.WalletStoresChanged -> { - store.state.globalState.topUpController?.walletStoresChanged(action.walletStores) - updateWalletStores(action.walletStores, walletState) - fetchTotalFiatBalance(action.walletStores) - findMissedDerivations(action.walletStores) - tryToShowAppRatingWarning(action.walletStores) + // Cancel update job when new wallet stores received + updateWalletStoresJob = scope.launch(Dispatchers.Default) { + ifActive { updateWalletStores(action.walletStores, walletState) } + ifActive { fetchTotalFiatBalance(action.walletStores) } + ifActive { findMissedDerivations(action.walletStores) } + ifActive { tryToShowAppRatingWarning(action.walletStores) } + ifActive { store.state.globalState.topUpController?.walletStoresChanged(action.walletStores) } + } } is WalletAction.TotalFiatBalanceChanged -> Unit is WalletAction.PopBackToInitialScreen -> { @@ -197,55 +208,47 @@ class WalletMiddleware { } private fun updateWalletStores(walletsStores: List, state: WalletState) { - scope.launch(Dispatchers.Default) { - val reduxWalletStores = walletsStores.mapToReduxModels() - if (!state.isMultiwalletAllowed) { - findSelectedCurrency( - walletsStores = reduxWalletStores, - currentSelectedCurrency = null, - isMultiWalletAllowed = false, - )?.let { - store.dispatchOnMain(WalletAction.MultiWallet.SetSingleWalletCurrency(it)) - } + val reduxWalletStores = walletsStores.mapToReduxModels() + if (!state.isMultiwalletAllowed) { + findSelectedCurrency( + walletsStores = reduxWalletStores, + currentSelectedCurrency = null, + isMultiWalletAllowed = false, + )?.let { + store.dispatchOnMain(WalletAction.MultiWallet.SetSingleWalletCurrency(it)) } - store.dispatchOnMain( - WalletAction.WalletStoresChanged.UpdateWalletStores( - reduxWalletStores = reduxWalletStores, - ), - ) } + store.dispatchOnMain( + WalletAction.WalletStoresChanged.UpdateWalletStores( + reduxWalletStores = reduxWalletStores, + ), + ) } - private fun fetchTotalFiatBalance(walletStores: List) { - scope.launch(Dispatchers.Default) { - val totalFiatBalance = totalFiatBalanceCalculator.calculateOrNull(walletStores)?.mapToReduxModel() + private suspend fun fetchTotalFiatBalance(walletStores: List) { + val totalFiatBalance = totalFiatBalanceCalculator.calculateOrNull(walletStores)?.mapToReduxModel() - if (totalFiatBalance != null) { - store.dispatchOnMain(WalletAction.TotalFiatBalanceChanged(totalFiatBalance)) - } + if (totalFiatBalance != null) { + store.dispatchOnMain(WalletAction.TotalFiatBalanceChanged(totalFiatBalance)) } } private fun findMissedDerivations(wallStores: List) { - scope.launch(Dispatchers.Default) { - val missedDerivations = wallStores - .filter { store -> - store.walletsData.any { it.status is WalletDataModel.MissedDerivation } - } - .map(WalletStoreModel::blockchainNetwork) + val missedDerivations = wallStores + .filter { store -> + store.walletsData.any { it.status is WalletDataModel.MissedDerivation } + } + .map(WalletStoreModel::blockchainNetwork) - store.dispatchOnMain(WalletAction.MultiWallet.AddMissingDerivations(missedDerivations)) - } + store.dispatchOnMain(WalletAction.MultiWallet.AddMissingDerivations(missedDerivations)) } private fun tryToShowAppRatingWarning(walletStores: List) { - scope.launch(Dispatchers.Default) { - warningsMiddleware.tryToShowAppRatingWarning( - hasNonZeroWallets = walletStores - .flatMap { it.walletsData } - .any { it.status.amount.isGreaterThan(BigDecimal.ZERO) }, - ) - } + warningsMiddleware.tryToShowAppRatingWarning( + hasNonZeroWallets = walletStores + .flatMap { it.walletsData } + .any { it.status.amount.isGreaterThan(BigDecimal.ZERO) }, + ) } private fun showSaveWalletIfNeeded() { diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletViewModel.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletViewModel.kt index 93f1c5ff90..2be9db11ee 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletViewModel.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletViewModel.kt @@ -17,8 +17,10 @@ import com.tangem.tap.store import com.tangem.tap.walletStoresManager import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.Job import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.debounce import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.map @@ -98,12 +100,16 @@ internal class WalletViewModel @Inject constructor( } } + @OptIn(FlowPreview::class) private fun bootstrapSelectedWalletStoresChanges(manager: UserWalletsListManager) { observeWalletStoresUpdatesJob = manager.selectedUserWallet .map { it.walletId } .flatMapLatest { selectedUserWalletId -> walletStoresManager.get(selectedUserWalletId) } + .debounce { walletStores -> + if (walletStores.isNotEmpty()) WALLET_STORES_DEBOUNCE_TIMEOUT else 0 + } .onEach { walletStores -> store.dispatch(WalletAction.WalletStoresChanged(walletStores)) } @@ -126,4 +132,8 @@ internal class WalletViewModel @Inject constructor( .select { it.globalState.userWalletsListManager } } } + + companion object { + private const val WALLET_STORES_DEBOUNCE_TIMEOUT = 100L + } } \ No newline at end of file diff --git a/core/utils/src/main/java/com/tangem/utils/coroutines/CoroutineExt.kt b/core/utils/src/main/java/com/tangem/utils/coroutines/CoroutineExt.kt index 4fbd7b0ccb..b9ed8ee566 100644 --- a/core/utils/src/main/java/com/tangem/utils/coroutines/CoroutineExt.kt +++ b/core/utils/src/main/java/com/tangem/utils/coroutines/CoroutineExt.kt @@ -3,7 +3,9 @@ package com.tangem.utils.coroutines import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job +import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.delay +import kotlinx.coroutines.isActive import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @@ -13,6 +15,12 @@ suspend fun runCatching(dispatcher: CoroutineDispatcher, block: suspend () - } } +suspend inline fun ifActive(crossinline block: suspend () -> Unit) = coroutineScope { + if (isActive) { + block() + } +} + class Debouncer { private var debounceJob: Job? = null