From de03cc28b636ef9448a8d88c07c85debcc4c9425 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 23 Mar 2022 20:49:07 +0300 Subject: [PATCH] Updated on 2026-08-14 --- .../tap/features/wallet/redux/WalletState.kt | 39 ++++++++++------- .../redux/middlewares/WalletMiddleware.kt | 42 +++++++++++++------ .../wallet/redux/reducers/WalletReducer.kt | 25 ++++++++++- 3 files changed, 77 insertions(+), 29 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt index 92491013ad..e8521c17d9 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt @@ -34,6 +34,7 @@ data class WalletState( val mainWarningsList: List = mutableListOf(), val wallets: List = emptyList(), val walletManagers: List = emptyList(), + val walletManagersThrottling: MutableMap = mutableMapOf(), val isMultiwalletAllowed: Boolean = false, val cardCurrency: CryptoCurrencyName? = null, val selectedWallet: Currency? = null, @@ -54,8 +55,8 @@ data class WalletState( val primaryWallet = if (wallets.isNotEmpty()) wallets[0] else null val shouldShowDetails: Boolean = - primaryWallet?.currencyData?.status != BalanceStatus.EmptyCard && - primaryWallet?.currencyData?.status != BalanceStatus.UnknownBlockchain + primaryWallet?.currencyData?.status != BalanceStatus.EmptyCard && + primaryWallet?.currencyData?.status != BalanceStatus.UnknownBlockchain val blockchains: List get() = walletManagers.map { it.wallet.blockchain } @@ -63,6 +64,8 @@ data class WalletState( val currencies: List get() = wallets.mapNotNull { it.currency } + val throttlingDuration = 10000L + fun getWalletManager(token: Token?): WalletManager? { if (token == null) return null return walletManagers.find { it.wallet.blockchain == token.blockchain } @@ -101,10 +104,10 @@ data class WalletState( if (!isPrimaryCurrency(walletData)) { val walletManager = getWalletManager(walletData.currency) - ?: return true + ?: return true if (walletData.currency is Currency.Blockchain && - walletManager.cardTokens.isNotEmpty() + walletManager.cardTokens.isNotEmpty() ) { return false } @@ -113,22 +116,22 @@ data class WalletState( if (walletData.currency is Currency.Blockchain) { return wallet.recentTransactions.toPendingTransactions(wallet.address).isEmpty() && - wallet.amounts.toSendableAmounts().isEmpty() + wallet.amounts.toSendableAmounts().isEmpty() } else if (walletData.currency is Currency.Token) ( - return wallet.recentTransactions.toPendingTransactionsForToken( - walletData.currency.token, wallet.address).isEmpty() - && wallet.amounts[AmountType.Token(token = walletData.currency.token)] - ?.isAboveZero() != true - ) + return wallet.recentTransactions.toPendingTransactionsForToken( + walletData.currency.token, wallet.address).isEmpty() + && wallet.amounts[AmountType.Token(token = walletData.currency.token)] + ?.isAboveZero() != true + ) } return false } private fun isPrimaryCurrency(walletData: WalletData): Boolean { return (walletData.currency is Currency.Blockchain && - walletData.currency.blockchain == store.state.walletState.primaryBlockchain) - || (walletData.currency is Currency.Token && - walletData.currency.token == store.state.walletState.primaryToken) + walletData.currency.blockchain == store.state.walletState.primaryBlockchain) + || (walletData.currency is Currency.Token && + walletData.currency.token == store.state.walletState.primaryToken) } fun replaceWalletInWallets(walletData: WalletData?): List { @@ -149,7 +152,7 @@ data class WalletState( val remainingWallets: MutableList = newWallets.toMutableList() val updatedWallets = wallets.map { wallet -> val newWallet = newWallets - .firstOrNull { wallet.currency == it.currency } + .firstOrNull { wallet.currency == it.currency } if (newWallet == null) { wallet } else { @@ -176,9 +179,15 @@ data class WalletState( fun addWalletManagers(newWalletManagers: List): WalletState { val updatedWalletManagers = this.walletManagers + - newWalletManagers.filterNot { this.blockchains.contains(it.wallet.blockchain) } + newWalletManagers.filterNot { this.blockchains.contains(it.wallet.blockchain) } return copy(walletManagers = updatedWalletManagers) } + + fun isThrottling(walletManager: WalletManager): Boolean { + val inThrottlingUpTo = walletManagersThrottling[walletManager.wallet.blockchain] ?: return false + val diff = System.currentTimeMillis() - inThrottlingUpTo + return diff < 0 + } } sealed class WalletDialog : StateDialog { 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 379008a18b..28abc867e9 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 @@ -29,9 +29,7 @@ import com.tangem.tap.network.NetworkStateChanged import com.tangem.tap.scope import com.tangem.tap.store import com.tangem.tap.tangemSdkManager -import kotlinx.coroutines.async -import kotlinx.coroutines.awaitAll -import kotlinx.coroutines.launch +import kotlinx.coroutines.* import org.rekotlin.Action import org.rekotlin.DispatchFunction import org.rekotlin.Middleware @@ -61,14 +59,32 @@ class WalletMiddleware { is WalletAction.Warnings -> warningsMiddleware.handle(action, globalState) is WalletAction.MultiWallet -> multiWalletMiddleware.handle(action, walletState, globalState) is WalletAction.LoadWallet -> { - scope.launch { - if (action.blockchain == null) { - walletState.walletManagers.map { walletManager -> - async { globalState.tapWalletManager.loadWalletData(walletManager) } - }.awaitAll() - } else { - val walletManager = walletState.getWalletManager(action.blockchain) - walletManager?.let { globalState.tapWalletManager.loadWalletData(it) } + if (action.blockchain == null) { + val throttledWalletManagers = walletState.walletManagers.filter { walletState.isThrottling(it) } + val freeWalletManagers = walletState.walletManagers.filter { !walletState.isThrottling(it) } + scope.launch { + freeWalletManagers.map { walletManager -> + async { globalState.tapWalletManager.loadWalletData(walletManager) } + }.awaitAll() + + delay(500) + launch(Dispatchers.Main) { + throttledWalletManagers.forEach { store.dispatch(WalletAction.LoadWallet.Success(it.wallet)) } + } + } + + } else { + val walletManager = walletState.getWalletManager(action.blockchain) ?: return + + scope.launch { + if (walletState.isThrottling(walletManager)) { + delay(500) + launch(Dispatchers.Main) { + store.dispatch(WalletAction.LoadWallet.Success(walletManager.wallet)) + } + } else { + globalState.tapWalletManager.loadWalletData(walletManager) + } } } } @@ -230,12 +246,12 @@ class WalletMiddleware { when (currency) { is Currency.Blockchain -> { val amountToSend = amounts?.find { it.currencySymbol == currency.blockchain.currency } - ?: return WalletAction.Send.ChooseCurrency(amounts) + ?: return WalletAction.Send.ChooseCurrency(amounts) PrepareSendScreen(amountToSend, selectedWalletData.fiatRate, walletManager) } is Currency.Token -> { val amountToSend = amounts?.find { it.currencySymbol == currency.token.symbol } - ?: return WalletAction.Send.ChooseCurrency(amounts) + ?: return WalletAction.Send.ChooseCurrency(amounts) prepareSendActionForToken(amountToSend, state, selectedWalletData, wallet, walletManager) } } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt index af75afcb1b..4077d877ee 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt @@ -94,8 +94,20 @@ private fun internalReduce(action: Action, state: AppState): WalletState { } is WalletAction.LoadWallet -> { if (action.blockchain == null) { - val wallets = newState.wallets.map { wallet -> + // update throttling + val updatedThrottling = newState.walletManagersThrottling + newState.walletManagers.forEach { + val now = System.currentTimeMillis() + val currentThrottling = newState.walletManagersThrottling[it.wallet.blockchain] ?: 0L + if (currentThrottling == 0L || currentThrottling < now) { + val newThrottlingUpTo = now + newState.throttlingDuration + updatedThrottling[it.wallet.blockchain] = newThrottlingUpTo + } + } + newState = newState.copy(walletManagersThrottling = updatedThrottling) + + val wallets = newState.wallets.map { wallet -> wallet.copy( currencyData = wallet.currencyData.copy( status = BalanceStatus.Loading, @@ -113,6 +125,17 @@ private fun internalReduce(action: Action, state: AppState): WalletState { } else { val walletManager = newState.getWalletManager(action.blockchain) ?: return newState val blockchain = walletManager.wallet.blockchain + + // update throttling + val now = System.currentTimeMillis() + val currentThrottling = newState.walletManagersThrottling[blockchain] ?: 0L + if (currentThrottling == 0L || currentThrottling < now) { + val newThrottlingUpTo = now + newState.throttlingDuration + val newMap = newState.walletManagersThrottling.toMutableMap() + newMap[blockchain] = newThrottlingUpTo + newState = newState.copy(walletManagersThrottling = newMap) + } + val currencies = listOf(Currency.Blockchain(blockchain)) + walletManager.cardTokens.map { Currency.Token(it) } val newWallets = newState.wallets.filter { currencies.contains(it.currency) }