diff --git a/app/src/main/java/com/tangem/tap/MainActivity.kt b/app/src/main/java/com/tangem/tap/MainActivity.kt index 9d9d6d9fa6..b300ea02c8 100644 --- a/app/src/main/java/com/tangem/tap/MainActivity.kt +++ b/app/src/main/java/com/tangem/tap/MainActivity.kt @@ -10,7 +10,6 @@ import androidx.core.view.WindowInsetsControllerCompat import by.kirich1409.viewbindingdelegate.viewBinding import com.google.android.material.snackbar.Snackbar import com.tangem.TangemSdk -import com.tangem.utils.coroutines.FeatureCoroutineExceptionHandler import com.tangem.operations.backup.BackupService import com.tangem.tangem_sdk_new.extensions.init import com.tangem.tap.common.ActivityResultCallbackHolder @@ -27,9 +26,11 @@ import com.tangem.tap.common.shop.googlepay.GooglePayUtil.createPaymentsClient import com.tangem.tap.domain.TangemSdkManager import com.tangem.tap.domain.userWalletList.UserWalletsListManager import com.tangem.tap.domain.userWalletList.di.provideBiometricImplementation +import com.tangem.tap.features.onboarding.products.wallet.redux.BackupAction import com.tangem.tap.features.shop.redux.ShopAction import com.tangem.tap.features.welcome.redux.WelcomeAction import com.tangem.tap.proxy.AppStateHolder +import com.tangem.utils.coroutines.FeatureCoroutineExceptionHandler import com.tangem.wallet.R import com.tangem.wallet.databinding.ActivityMainBinding import dagger.hilt.android.AndroidEntryPoint @@ -127,6 +128,7 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac store.dispatchOnMain(NavigationAction.NavigateTo(AppScreen.Home)) intentHandler.handleWalletConnectLink(intent) } + store.dispatch(BackupAction.CheckForUnfinishedBackup) } intentHandler.handleBackgroundScan(intent) intentHandler.handleSellCurrencyCallback(intent) diff --git a/app/src/main/java/com/tangem/tap/domain/totalBalance/TotalFiatBalanceCalculator.kt b/app/src/main/java/com/tangem/tap/domain/totalBalance/TotalFiatBalanceCalculator.kt index 9790310eb0..a011491b0e 100644 --- a/app/src/main/java/com/tangem/tap/domain/totalBalance/TotalFiatBalanceCalculator.kt +++ b/app/src/main/java/com/tangem/tap/domain/totalBalance/TotalFiatBalanceCalculator.kt @@ -2,33 +2,23 @@ package com.tangem.tap.domain.totalBalance import com.tangem.tap.domain.model.TotalFiatBalance import com.tangem.tap.domain.model.WalletStoreModel -import java.math.BigDecimal interface TotalFiatBalanceCalculator { /** * Calculate total fiat balance for list of [WalletStoreModel] - * @param prevAmount Previous amount, used in [TotalFiatBalance.Refreshing] * @param walletStores List of [WalletStoreModel] to calculate fiat amount * @param initial Initial [TotalFiatBalance] state, used when list of [WalletStoreModel] is empty * @return [TotalFiatBalance] with state found with the [WalletStoreModel] list * */ - suspend fun calculate( - prevAmount: BigDecimal?, - walletStores: List, - initial: TotalFiatBalance, - ): TotalFiatBalance + suspend fun calculate(walletStores: List, initial: TotalFiatBalance): TotalFiatBalance /** * Same as [TotalFiatBalanceCalculator.calculate] but returns null if list of [WalletStoreModel] is empty - * @param prevAmount Previous amount, used in [TotalFiatBalance.Refreshing] * @param walletStores List of [WalletStoreModel] to calculate fiat amount * @return [TotalFiatBalance] with state found with the [WalletStoreModel] list * */ - suspend fun calculateOrNull( - prevAmount: BigDecimal?, - walletStores: List, - ): TotalFiatBalance? + suspend fun calculateOrNull(walletStores: List): TotalFiatBalance? companion object } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/totalBalance/implementation/DefaultTotalFiatBalanceCalculator.kt b/app/src/main/java/com/tangem/tap/domain/totalBalance/implementation/DefaultTotalFiatBalanceCalculator.kt index 0c0f909c80..12fd8abb1e 100644 --- a/app/src/main/java/com/tangem/tap/domain/totalBalance/implementation/DefaultTotalFiatBalanceCalculator.kt +++ b/app/src/main/java/com/tangem/tap/domain/totalBalance/implementation/DefaultTotalFiatBalanceCalculator.kt @@ -10,18 +10,11 @@ import kotlinx.coroutines.withContext import java.math.BigDecimal internal class DefaultTotalFiatBalanceCalculator : TotalFiatBalanceCalculator { - override suspend fun calculate( - prevAmount: BigDecimal?, - walletStores: List, - initial: TotalFiatBalance, - ): TotalFiatBalance { - return calculateOrNull(prevAmount, walletStores) ?: initial + override suspend fun calculate(walletStores: List, initial: TotalFiatBalance): TotalFiatBalance { + return calculateOrNull(walletStores) ?: initial } - override suspend fun calculateOrNull( - prevAmount: BigDecimal?, - walletStores: List, - ): TotalFiatBalance? { + override suspend fun calculateOrNull(walletStores: List): TotalFiatBalance? { return if (walletStores.isEmpty()) { null } else { 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 e000fe1c6d..dd19a02575 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 @@ -128,34 +128,35 @@ internal class DefaultWalletCurrenciesManager( private fun List.addMissingBlockchains(card: CardDTO): List { val newCurrencies = arrayListOf() - for (currency in this.sortedByDescending { it is Currency.Blockchain }) { - when (currency) { - is Currency.Blockchain -> { - newCurrencies.add(currency.updateDerivationPath(card.derivationStyle)) + this + .groupBy { it.blockchain } + .forEach { (blockchain, currencies) -> + val rawDerivationPath: String? + val blockchainCurrency = currencies + .firstOrNull { it is Currency.Blockchain } + as? Currency.Blockchain + + // Add blockchain currency + if (blockchainCurrency != null) { + rawDerivationPath = findDerivationPath(blockchainCurrency, card.derivationStyle) + newCurrencies.add(blockchainCurrency.copy(derivationPath = rawDerivationPath)) + } else { + rawDerivationPath = findDerivationPath(currencies.first(), card.derivationStyle) + newCurrencies.add( + Currency.Blockchain( + blockchain = blockchain, + derivationPath = rawDerivationPath, + ), + ) } - is Currency.Token -> { - val containsTokenBlockchain = newCurrencies.any { - it.isBlockchain() && it.blockchain == currency.blockchain + // Add tokens currencies + currencies + .filterIsInstance() + .forEach { currency -> + newCurrencies.add(currency.copy(derivationPath = rawDerivationPath)) } - - if (containsTokenBlockchain) { - newCurrencies.add(currency.updateDerivationPath(card.derivationStyle)) - } else { - val derivationPath = findDerivationPath(currency, card.derivationStyle) - newCurrencies.add( - Currency.Blockchain( - blockchain = currency.blockchain, - derivationPath = derivationPath, - ), - ) - newCurrencies.add( - currency.copy(derivationPath = derivationPath), - ) - } - } } - } return newCurrencies } @@ -183,22 +184,6 @@ internal class DefaultWalletCurrenciesManager( .fold() } - private fun Currency.updateDerivationPath(cardDerivationStyle: DerivationStyle?): Currency { - val findDerivationPath: () -> String? = { - findDerivationPath(this, cardDerivationStyle) - } - - return when (this) { - is Currency.Blockchain -> this.copy( - derivationPath = findDerivationPath(), - ) - - is Currency.Token -> this.copy( - derivationPath = findDerivationPath(), - ) - } - } - private fun findDerivationPath(currency: Currency, cardDerivationStyle: DerivationStyle?): String? { return currency.derivationPath ?: currency.blockchain.derivationPath(cardDerivationStyle)?.rawPath } diff --git a/app/src/main/java/com/tangem/tap/features/disclaimer/Disclaimer.kt b/app/src/main/java/com/tangem/tap/features/disclaimer/Disclaimer.kt index a3f28bfb73..1f72592557 100644 --- a/app/src/main/java/com/tangem/tap/features/disclaimer/Disclaimer.kt +++ b/app/src/main/java/com/tangem/tap/features/disclaimer/Disclaimer.kt @@ -53,16 +53,16 @@ class Start2CoinDisclaimer(dataProvider: DisclaimerDataProvider) : BaseDisclaime private fun filename(languageCode: String, regionCode: String?): String { return when { - languageCode == "fr" && regionCode == "ch" -> "Start2Coin-fr-ch-tangem.html" - languageCode == "de" && regionCode == "ch" -> "Start2Coin-de-ch-tangem.html" - languageCode == "en" && regionCode == "ch" -> "Start2Coin-en-ch-tangem.html" - languageCode == "it" && regionCode == "ch" -> "Start2Coin-it-ch-tangem.html" - languageCode == "fr" && regionCode == "fr" -> "Start2Coin-fr-fr-atangem.html" - languageCode == "de" && regionCode == "at" -> "Start2Coin-de-at-tangem.html" - regionCode == "fr" -> "Start2Coin-fr-fr-atangem.html" - regionCode == "ch" -> "Start2Coin-en-ch-tangem.html" - regionCode == "at" -> "Start2Coin-de-at-tangem.html" - else -> "Start2Coin-fr-fr-atangem.html" + languageCode == "fr" && regionCode == "ch" -> "start2coin-fr-ch-tangem.html" + languageCode == "de" && regionCode == "ch" -> "start2coin-de-ch-tangem.html" + languageCode == "en" && regionCode == "ch" -> "start2coin-en-ch-tangem.html" + languageCode == "it" && regionCode == "ch" -> "start2coin-it-ch-tangem.html" + languageCode == "fr" && regionCode == "fr" -> "start2coin-fr-fr-tangem.html" + languageCode == "de" && regionCode == "at" -> "start2coin-de-at-tangem.html" + regionCode == "fr" -> "start2coin-fr-fr-tangem.html" + regionCode == "ch" -> "start2coin-en-ch-tangem.html" + regionCode == "at" -> "start2coin-de-at-tangem.html" + else -> "start2coin-fr-fr-tangem.html" } } diff --git a/app/src/main/java/com/tangem/tap/features/home/HomeFragment.kt b/app/src/main/java/com/tangem/tap/features/home/HomeFragment.kt index aef9f11d9d..3c2eb278d7 100644 --- a/app/src/main/java/com/tangem/tap/features/home/HomeFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/home/HomeFragment.kt @@ -19,7 +19,6 @@ import com.tangem.tap.common.redux.navigation.NavigationAction import com.tangem.tap.features.home.compose.StoriesScreen import com.tangem.tap.features.home.redux.HomeAction import com.tangem.tap.features.home.redux.HomeState -import com.tangem.tap.features.onboarding.products.wallet.redux.BackupAction import com.tangem.tap.features.tokens.redux.TokensAction import com.tangem.tap.store import org.rekotlin.StoreSubscriber @@ -39,8 +38,6 @@ class HomeFragment : Fragment(), StoreSubscriber { container: ViewGroup?, savedInstanceState: Bundle?, ): View { - store.dispatch(BackupAction.CheckForUnfinishedBackup) - return ComposeView(inflater.context).apply { setContent { BackHandler { diff --git a/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt b/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt index fdacaa5bd1..167b7ec607 100644 --- a/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt @@ -117,5 +117,5 @@ private fun readCard() = scope.launch { } private fun changeButtonState(state: ButtonState) { - store.dispatch(HomeAction.ChangeScanCardButtonState(IndeterminateProgressButton(state))) + store.dispatchOnMain(HomeAction.ChangeScanCardButtonState(IndeterminateProgressButton(state))) } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/Mapper.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/Mapper.kt index dbb030f67f..75b79e6a61 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/Mapper.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/Mapper.kt @@ -1,5 +1,6 @@ package com.tangem.tap.features.wallet.redux.middlewares +import com.tangem.blockchain.common.AmountType import com.tangem.common.extensions.isZero import com.tangem.tap.common.extensions.stripZeroPlainString import com.tangem.tap.common.extensions.toFiatRateString @@ -21,6 +22,7 @@ import com.tangem.tap.features.wallet.ui.BalanceStatus import com.tangem.tap.features.wallet.ui.BalanceWidgetData import com.tangem.tap.features.wallet.ui.TokenData import com.tangem.tap.store +import java.math.BigDecimal internal fun List.mapToReduxModels( isMultiWalletAllowed: Boolean, @@ -69,6 +71,7 @@ private fun List.mapToReduxModel( ?.takeIf { !status.isErrorStatus } ?.toFormattedFiatValue(appCurrency.symbol) val fiatRateFormatted = fiatRate?.toFiatRateString(appCurrency.symbol) + val blockchainAmountValue = getBlockchainAmount() WalletData( currency = currency, @@ -83,7 +86,9 @@ private fun List.mapToReduxModel( fiatRateString = fiatRateFormatted, pendingTransactions = status.pendingTransactions, mainButton = WalletMainButton.SendButton( - enabled = !status.amount.isZero() && status.pendingTransactions.isEmpty(), + enabled = !blockchainAmountValue.isZero() + && !status.amount.isZero() + && status.pendingTransactions.isEmpty(), ), walletRent = walletRent?.let { WalletRent( @@ -103,7 +108,7 @@ private fun List.mapToReduxModel( }, currency = currency.currencyName, currencySymbol = currency.currencySymbol, - blockchainAmount = status.amount, + blockchainAmount = blockchainAmountValue, amount = amount, amountFormatted = amountFormatted, fiatAmount = fiatAmount, @@ -130,4 +135,9 @@ private fun List.mapToReduxModel( ) } } +} + +private fun WalletDataModel.getBlockchainAmount(): BigDecimal { + val walletStore = store.state.walletState.getWalletStore(currency) ?: return BigDecimal.ZERO + return walletStore.walletManager?.wallet?.amounts?.get(AmountType.Coin)?.value ?: BigDecimal.ZERO } \ No newline at end of file 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 01940aab16..6142599a97 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 @@ -8,10 +8,10 @@ import com.tangem.blockchain.common.WalletManager import com.tangem.common.CompletionResult import com.tangem.common.extensions.isZero import com.tangem.common.services.Result +import com.tangem.core.analytics.Analytics import com.tangem.domain.common.extensions.withMainContext import com.tangem.operations.attestation.Attestation import com.tangem.operations.attestation.OnlineCardVerifier -import com.tangem.core.analytics.Analytics import com.tangem.tap.common.analytics.events.MainScreen import com.tangem.tap.common.analytics.events.Token import com.tangem.tap.common.extensions.copyToClipboard @@ -287,7 +287,7 @@ class WalletMiddleware { is WalletAction.UserWalletChanged -> Unit is WalletAction.WalletStoresChanged -> { updateWalletStores(action.walletStores, walletState) - fetchTotalFiatBalance(action.walletStores, walletState) + fetchTotalFiatBalance(action.walletStores) findMissedDerivations(action.walletStores) tryToShowAppRatingWarning(action.walletStores) } @@ -312,12 +312,9 @@ class WalletMiddleware { } } - private fun fetchTotalFiatBalance(walletStores: List, state: WalletState) { + private fun fetchTotalFiatBalance(walletStores: List) { scope.launch(Dispatchers.Default) { - val totalFiatBalance = totalFiatBalanceCalculator.calculateOrNull( - prevAmount = state.totalBalance?.fiatAmount, - walletStores = walletStores, - )?.mapToReduxModel() + val totalFiatBalance = totalFiatBalanceCalculator.calculateOrNull(walletStores)?.mapToReduxModel() if (totalFiatBalance != null) { store.dispatchOnMain(WalletAction.TotalFiatBalanceChanged(totalFiatBalance)) diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt index 6c3978f7e7..630d934f4b 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt @@ -18,15 +18,16 @@ import androidx.transition.TransitionInflater import by.kirich1409.viewbindingdelegate.viewBinding import com.badoo.mvicore.modelWatcher import com.tangem.common.doOnResult +import com.tangem.core.analytics.Analytics import com.tangem.domain.common.TapWorkarounds.derivationStyle import com.tangem.tangem_sdk_new.extensions.dpToPx import com.tangem.tap.common.SnackbarHandler import com.tangem.tap.common.TestActions -import com.tangem.core.analytics.Analytics import com.tangem.tap.common.analytics.events.DetailsScreen import com.tangem.tap.common.analytics.events.Token import com.tangem.tap.common.extensions.appendIfNotNull import com.tangem.tap.common.extensions.beginDelayedTransition +import com.tangem.tap.common.extensions.dispatchOnMain import com.tangem.tap.common.extensions.fitChipsByGroupWidth import com.tangem.tap.common.extensions.getColor import com.tangem.tap.common.extensions.getString @@ -230,8 +231,8 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), tokens = emptyList(), ) - store.dispatch(WalletAction.LoadWallet(blockchainNetwork)) - store.dispatch(WalletAction.LoadFiatRate(coinsList = listOf(currency))) + store.dispatchOnMain(WalletAction.LoadWallet(blockchainNetwork)) + store.dispatchOnMain(WalletAction.LoadFiatRate(coinsList = listOf(currency))) } } } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt index 108ad69cdd..a20ebd503d 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt @@ -5,9 +5,9 @@ import androidx.core.view.isVisible import androidx.recyclerview.widget.LinearLayoutManager import com.badoo.mvicore.DiffStrategy import com.badoo.mvicore.modelWatcher +import com.tangem.core.analytics.Analytics import com.tangem.domain.common.TapWorkarounds.derivationStyle import com.tangem.domain.common.TapWorkarounds.isTestCard -import com.tangem.core.analytics.Analytics import com.tangem.tap.common.analytics.events.MainScreen import com.tangem.tap.common.analytics.events.Portfolio import com.tangem.tap.common.extensions.animateVisibility @@ -69,7 +69,12 @@ class MultiWalletView : WalletView() { } watch({ it }, totalBalanceStrategy) { walletState -> binding?.let { - handleTotalBalance(it, walletState.totalBalance, walletState.state, walletState.walletsDataFromStores.size) + handleTotalBalance( + binding = it, + totalBalance = walletState.totalBalance, + progressState = walletState.state, + walletsCount = walletState.walletsDataFromStores.size, + ) } } } @@ -175,9 +180,7 @@ class MultiWalletView : WalletView() { walletsCount: Int, ) = with(binding.lCardTotalBalance) { if (walletsCount == 0) { - if (progressState != ProgressState.Loading) { - root.isVisible = false - } + root.isVisible = false } else { if (totalBalance == null) { if (progressState != ProgressState.Loading) { diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorMiddleware.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorMiddleware.kt index 8c0d56cc71..38832e455a 100644 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorMiddleware.kt @@ -6,9 +6,9 @@ import com.tangem.common.doOnFailure import com.tangem.common.doOnSuccess import com.tangem.common.flatMap import com.tangem.common.map +import com.tangem.core.analytics.Analytics import com.tangem.domain.common.ScanResponse import com.tangem.domain.common.util.UserWalletId -import com.tangem.core.analytics.Analytics import com.tangem.tap.common.analytics.events.MyWallets import com.tangem.tap.common.extensions.dispatchOnMain import com.tangem.tap.common.extensions.onUserWalletSelected @@ -98,21 +98,25 @@ internal class WalletSelectorMiddleware { } } - private fun updateBalances(walletStores: Map>, state: WalletSelectorState) { - walletStores.forEach { (walletId, walletStores) -> - scope.launch(Dispatchers.Default) { - val foundWallet = state.wallets - .find { it.id == walletId } + private fun updateBalances( + updatedWalletStores: Map>, + state: WalletSelectorState, + ) { + if (updatedWalletStores.isNotEmpty()) scope.launch(Dispatchers.Default) { + state.wallets + .associateWith { updatedWalletStores[it.id] } + .forEach { (wallet, walletStores) -> + val isWalletTokensEmpty = (wallet.type as? UserWalletModel.Type.MultiCurrency)?.tokensCount == 0 + val updatedWallet = if (walletStores == null && isWalletTokensEmpty) { + wallet.copy(fiatBalance = TotalFiatBalance.Loaded(BigDecimal.ZERO)) + } else { + wallet.updateWalletStoresAndCalculateFiatBalance(walletStores.orEmpty()) + } - if (foundWallet != null) { - val updatedWallet = foundWallet - .updateWalletStoresAndCalculateFiatBalance(walletStores) - - if (foundWallet != updatedWallet) { + if (wallet != updatedWallet) { store.dispatchOnMain(WalletSelectorAction.BalanceLoaded(updatedWallet)) } } - } } } @@ -287,7 +291,6 @@ internal class WalletSelectorMiddleware { selectedUserWallet == null -> { store.dispatchOnMain(NavigationAction.PopBackTo(AppScreen.Welcome)) } - currentSelectedWalletId != selectedUserWallet.walletId -> { store.onUserWalletSelected(selectedUserWallet) } @@ -320,9 +323,8 @@ internal class WalletSelectorMiddleware { is UserWalletModel.Type.SingleCurrency -> type }, fiatBalance = totalFiatBalanceCalculator.calculate( - prevAmount = fiatBalance.amount, walletStores = walletStores, - initial = TotalFiatBalance.Loaded(BigDecimal.ZERO), + initial = TotalFiatBalance.Loading, ), ) }