diff --git a/app/src/main/java/com/tangem/tap/common/DialogManager.kt b/app/src/main/java/com/tangem/tap/common/DialogManager.kt index f25d1ddf4c..94dd3ff6c1 100644 --- a/app/src/main/java/com/tangem/tap/common/DialogManager.kt +++ b/app/src/main/java/com/tangem/tap/common/DialogManager.kt @@ -17,10 +17,11 @@ import com.tangem.tap.features.onboarding.AddressInfoBottomSheetDialog import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction import com.tangem.tap.features.onboarding.products.twins.ui.dialog.CreateWalletInterruptDialog import com.tangem.tap.features.onboarding.products.wallet.redux.BackupDialog +import com.tangem.tap.features.onboarding.products.wallet.redux.OnboardingDialog +import com.tangem.tap.features.onboarding.products.wallet.saltPay.dialog.InterruptOnboardingDialog import com.tangem.tap.features.onboarding.products.wallet.saltPay.dialog.NoFundsForActivationDialog import com.tangem.tap.features.onboarding.products.wallet.saltPay.dialog.RegistrationErrorDialog import com.tangem.tap.features.onboarding.products.wallet.saltPay.dialog.SaltPayDialog -import com.tangem.tap.features.onboarding.products.wallet.saltPay.dialog.TryToInterruptRegistrationDialog import com.tangem.tap.features.onboarding.products.wallet.ui.dialogs.AddMoreBackupCardsDialog import com.tangem.tap.features.onboarding.products.wallet.ui.dialogs.BackupInProgressDialog import com.tangem.tap.features.onboarding.products.wallet.ui.dialogs.ConfirmDiscardingBackupDialog @@ -72,8 +73,8 @@ class DialogManager : StoreSubscriber { is AppDialog.ScanFailsDialog -> ScanFailsDialog.create(context) is AppDialog.AddressInfoDialog -> AddressInfoBottomSheetDialog(state.dialog, context) is AppDialog.TestActionsDialog -> TestActionsBottomSheetDialog(state.dialog, context) - is TwinCardsAction.Wallet.ShowInterruptDialog -> - CreateWalletInterruptDialog.create(state.dialog, context) + is TwinCardsAction.Wallet.ShowInterruptDialog -> CreateWalletInterruptDialog.create(state.dialog, context) + is OnboardingDialog.InterruptOnboarding -> InterruptOnboardingDialog.create(context, state.dialog) is WalletConnectDialog.UnsupportedCard -> SimpleAlertDialog.create( titleRes = R.string.wallet_connect_title, @@ -109,10 +110,8 @@ class DialogManager : StoreSubscriber { ChooseNetworkDialog.create(state.dialog.session, state.dialog.networks, context) is WalletConnectDialog.ClipboardOrScanQr -> ClipboardOrScanQrDialog.create(state.dialog.clipboardUri, context) - is WalletConnectDialog.RequestTransaction -> - TransactionDialog.create(state.dialog.dialogData, context) - is WalletConnectDialog.PersonalSign -> - PersonalSignDialog.create(state.dialog.data, context) + is WalletConnectDialog.RequestTransaction -> TransactionDialog.create(state.dialog.dialogData, context) + is WalletConnectDialog.PersonalSign -> PersonalSignDialog.create(state.dialog.data, context) is WalletConnectDialog.BnbTransactionDialog -> BnbTransactionDialog.create( data = state.dialog.data, @@ -132,7 +131,6 @@ class DialogManager : StoreSubscriber { is BackupDialog.UnfinishedBackupFound -> UnfinishedBackupFoundDialog.create(context) is BackupDialog.ConfirmDiscardingBackup -> ConfirmDiscardingBackupDialog.create(context) is SaltPayDialog.Activation.NoGas -> NoFundsForActivationDialog.create(context) - is SaltPayDialog.Activation.TryToInterrupt -> TryToInterruptRegistrationDialog.create(context, state.dialog) is SaltPayDialog.Activation.OnError -> RegistrationErrorDialog.create(context, state.dialog) is WalletDialog.CurrencySelectionDialog -> CurrencySelectionDialog.create(state.dialog, context) is WalletDialog.ChooseTradeActionDialog -> ChooseTradeActionBottomSheetDialog(context) diff --git a/app/src/main/java/com/tangem/tap/common/extensions/Specific.kt b/app/src/main/java/com/tangem/tap/common/extensions/Specific.kt index 795bc8e268..8ff6116155 100644 --- a/app/src/main/java/com/tangem/tap/common/extensions/Specific.kt +++ b/app/src/main/java/com/tangem/tap/common/extensions/Specific.kt @@ -68,7 +68,7 @@ fun BigDecimal.toFormattedFiatValue( ): String { val fiatValue = this.setScale(2, RoundingMode.HALF_UP) .let { if (formatWithSpaces) it.formatWithSpaces() else it } - return " ${fiatValue}  $fiatCurrencyName" + return " $fiatValue $fiatCurrencyName" } fun BigDecimal.stripZeroPlainString(): String = this.stripTrailingZeros().toPlainString() diff --git a/app/src/main/java/com/tangem/tap/domain/configurable/config/ConfigManager.kt b/app/src/main/java/com/tangem/tap/domain/configurable/config/ConfigManager.kt index 67b78dff14..989d16359e 100644 --- a/app/src/main/java/com/tangem/tap/domain/configurable/config/ConfigManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/configurable/config/ConfigManager.kt @@ -101,6 +101,7 @@ class ConfigManager { ), infuraProjectId = values.infuraProjectId, tronGridApiKey = values.tronGridApiKey, + saltPayAuthToken = values.saltPay.credentials.token, ), appsFlyerDevKey = values.appsFlyer.appsFlyerDevKey, amplitudeApiKey = values.amplitudeApiKey, @@ -129,6 +130,7 @@ class ConfigManager { subdomain = values.bscQuiknodeSubdomain, ), infuraProjectId = values.infuraProjectId, + saltPayAuthToken = values.saltPay.credentials.token, ), appsFlyerDevKey = values.appsFlyer.appsFlyerDevKey, amplitudeApiKey = values.amplitudeApiKey, diff --git a/app/src/main/java/com/tangem/tap/domain/model/WalletDataModel.kt b/app/src/main/java/com/tangem/tap/domain/model/WalletDataModel.kt index 4462f4d8ec..3429afa07c 100644 --- a/app/src/main/java/com/tangem/tap/domain/model/WalletDataModel.kt +++ b/app/src/main/java/com/tangem/tap/domain/model/WalletDataModel.kt @@ -14,6 +14,7 @@ import java.math.BigDecimal * @param existentialDeposit Amount that must be held on currency's balance, if balance is below that amount all * founds will be destroyed. Null if currency don't have existential deposit * @param fiatRate Wallet's fiat rate, used to calculate fiat balance. Null if not provided + * @param isCardSingleToken shows that [Currency] is a card token * */ data class WalletDataModel( val currency: Currency, @@ -21,6 +22,7 @@ data class WalletDataModel( val walletAddresses: List, val existentialDeposit: BigDecimal?, val fiatRate: BigDecimal?, + val isCardSingleToken: Boolean, ) { /** diff --git a/app/src/main/java/com/tangem/tap/domain/model/WalletStoreModel.kt b/app/src/main/java/com/tangem/tap/domain/model/WalletStoreModel.kt index a0511784e2..7bca1028c0 100644 --- a/app/src/main/java/com/tangem/tap/domain/model/WalletStoreModel.kt +++ b/app/src/main/java/com/tangem/tap/domain/model/WalletStoreModel.kt @@ -6,10 +6,12 @@ import com.tangem.common.hdWallet.DerivationPath import com.tangem.domain.common.util.UserWalletId import com.tangem.tap.domain.model.WalletStoreModel.WalletRent import com.tangem.tap.domain.tokens.models.BlockchainNetwork +import com.tangem.tap.features.wallet.models.Currency import java.math.BigDecimal /** * Contains info about the blockchain and its currencies + * * @param userWalletId ID of the associated [UserWallet] * @param blockchain [Blockchain] of this WalletStore * @param derivationPath [DerivationPath] of this store, null if the card does not support the @@ -21,6 +23,9 @@ import java.math.BigDecimal * TODO: Remove after WalletMiddleware refactoring * @param walletManager [WalletManager], may be null if it fails to create this manager. * TODO: Remove after WalletMiddleware refactoring + * + * @property blockchainWalletData Returns the [WalletDataModel] of the blockchain of this wallet store + * or throw [NoSuchElementException] if this wallet store not contains [WalletDataModel] of the blockchain * */ data class WalletStoreModel( val userWalletId: UserWalletId, @@ -34,6 +39,9 @@ data class WalletStoreModel( val walletManager: WalletManager?, ) { + val blockchainWalletData: WalletDataModel + get() = walletsData.first { it.currency is Currency.Blockchain } + /** * Represents wallet blockchain rent * @param rent Amount that will be charged in overtime if the blockchain does not have an amount greater than diff --git a/app/src/main/java/com/tangem/tap/domain/model/builders/WalletStoreBuilder.kt b/app/src/main/java/com/tangem/tap/domain/model/builders/WalletStoreBuilder.kt index e76a291668..651ab25018 100644 --- a/app/src/main/java/com/tangem/tap/domain/model/builders/WalletStoreBuilder.kt +++ b/app/src/main/java/com/tangem/tap/domain/model/builders/WalletStoreBuilder.kt @@ -73,13 +73,13 @@ private class WalletMangerWalletStoreBuilderImpl( override fun build(): WalletStoreModel { val wallet = walletManager.wallet val blockchainWalletData = wallet.blockchain.toBlockchainWalletData(walletManager) - val tokenWalletsData = wallet.getTokens().firstOrNull()?.toTokenWalletData(walletManager) + val tokenWalletsData = walletManager.cardTokens.map { it.toTokenWalletData(walletManager) } return WalletStoreModel( userWalletId = userWalletId, blockchain = wallet.blockchain, derivationPath = wallet.publicKey.derivationPath, - walletsData = (listOf(blockchainWalletData) + listOfNotNull(tokenWalletsData)), + walletsData = (listOf(blockchainWalletData) + tokenWalletsData), walletRent = null, walletManager = walletManager, blockchainNetwork = BlockchainNetwork.fromWalletManager(walletManager), @@ -97,6 +97,7 @@ private fun BlockchainNetwork.getBlockchainWalletData(walletManager: WalletManag walletAddresses = walletManager?.wallet?.createAddressesData().orEmpty(), existentialDeposit = getExistentialDeposit(walletManager), fiatRate = null, + isCardSingleToken = false, ) } @@ -113,6 +114,7 @@ private fun BlockchainNetwork.getTokensWalletsData(walletManager: WalletManager? walletAddresses = walletManager?.wallet?.createAddressesData().orEmpty(), existentialDeposit = getExistentialDeposit(walletManager), fiatRate = null, + isCardSingleToken = walletManager?.cardTokens?.contains(token) ?: false, ) } } @@ -128,6 +130,7 @@ private fun Blockchain.toBlockchainWalletData(walletManager: WalletManager): Wal walletAddresses = wallet.createAddressesData(), existentialDeposit = getExistentialDeposit(walletManager), fiatRate = null, + isCardSingleToken = false, ) } @@ -143,6 +146,7 @@ private fun Token.toTokenWalletData(walletManager: WalletManager): WalletDataMod walletAddresses = wallet.createAddressesData(), existentialDeposit = getExistentialDeposit(walletManager), fiatRate = null, + isCardSingleToken = walletManager.cardTokens.contains(this), ) } diff --git a/app/src/main/java/com/tangem/tap/domain/scanCard/ScanCardProcessor.kt b/app/src/main/java/com/tangem/tap/domain/scanCard/ScanCardProcessor.kt index b9e8f526f9..4dc0722d61 100644 --- a/app/src/main/java/com/tangem/tap/domain/scanCard/ScanCardProcessor.kt +++ b/app/src/main/java/com/tangem/tap/domain/scanCard/ScanCardProcessor.kt @@ -70,7 +70,6 @@ object ScanCardProcessor { result .doOnFailure { error -> - onProgressStateChange(false) onScanStateChange(false) onFailure(error) } @@ -87,7 +86,6 @@ object ScanCardProcessor { nextHandler = { scanResponse1 -> showDisclaimerIfNeed( scanResponse = scanResponse1, - onProgressStateChange = onProgressStateChange, disclaimerWillShow = disclaimerWillShow, onFailure = onFailure, nextHandler = { scanResponse2 -> @@ -144,7 +142,6 @@ object ScanCardProcessor { private suspend inline fun showDisclaimerIfNeed( scanResponse: ScanResponse, crossinline disclaimerWillShow: () -> Unit = {}, - crossinline onProgressStateChange: suspend (showProgress: Boolean) -> Unit, crossinline nextHandler: suspend (ScanResponse) -> Unit, crossinline onFailure: suspend (error: TangemError) -> Unit, ) { @@ -167,7 +164,6 @@ object ScanCardProcessor { }, onDismiss = { scope.launch(Dispatchers.Main) { - onProgressStateChange(false) onFailure(TangemSdkError.UserCancelled()) } }, @@ -208,14 +204,12 @@ object ScanCardProcessor { } else { delay(DELAY_SDK_DIALOG_CLOSE) onSuccess(scanResponse) - onProgressStateChange(false) } } is Result.Failure -> { SaltPayExceptionHandler.handle(result.error) delay(DELAY_SDK_DIALOG_CLOSE) onFailure(TangemSdkError.ExceptionError(result.error)) - onProgressStateChange(false) } } } @@ -223,10 +217,10 @@ object ScanCardProcessor { delay(DELAY_SDK_DIALOG_CLOSE) if (scanResponse.card.backupStatus?.isActive == false) { showSaltPayTapVisaLogoCardDialog() + onProgressStateChange(false) } else { onSuccess(scanResponse) } - onProgressStateChange(false) } } else { if (OnboardingHelper.isOnboardingCase(scanResponse)) { @@ -242,7 +236,6 @@ object ScanCardProcessor { } else { delay(DELAY_SDK_DIALOG_CLOSE) onSuccess(scanResponse) - onProgressStateChange(false) } } } 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 12fd8abb1e..71f3f0a663 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 @@ -43,7 +43,8 @@ internal class DefaultTotalFiatBalanceCalculator : TotalFiatBalanceCalculator { private fun Sequence.mapToStatus(): Sequence { return this.map { walletData -> - when (walletData.status) { + if (walletData.fiatRate == null) TotalFiatBalanceStatus.Error + else when (walletData.status) { is WalletDataModel.VerifiedOnline, is WalletDataModel.SameCurrencyTransactionInProgress, is WalletDataModel.TransactionInProgress, diff --git a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletAmountsRepository.kt b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletAmountsRepository.kt index 444d6fc480..93c70be9ef 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletAmountsRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletAmountsRepository.kt @@ -27,6 +27,7 @@ import com.tangem.tap.domain.walletStores.repository.WalletAmountsRepository import com.tangem.tap.domain.walletStores.repository.implementation.utils.replaceWalletStore import com.tangem.tap.domain.walletStores.repository.implementation.utils.replaceWalletStores import com.tangem.tap.domain.walletStores.repository.implementation.utils.updateWithAmounts +import com.tangem.tap.domain.walletStores.repository.implementation.utils.updateWithDemoAmounts import com.tangem.tap.domain.walletStores.repository.implementation.utils.updateWithError import com.tangem.tap.domain.walletStores.repository.implementation.utils.updateWithFiatRates import com.tangem.tap.domain.walletStores.repository.implementation.utils.updateWithMissedDerivation @@ -34,6 +35,7 @@ import com.tangem.tap.domain.walletStores.repository.implementation.utils.update import com.tangem.tap.domain.walletStores.repository.implementation.utils.updateWithUnreachable import com.tangem.tap.domain.walletStores.storage.WalletManagerStorage import com.tangem.tap.domain.walletStores.storage.WalletStoresStorage +import com.tangem.tap.features.demo.DemoHelper import com.tangem.tap.features.wallet.models.PendingTransactionType import com.tangem.tap.features.wallet.models.filterByCoin import com.tangem.tap.features.wallet.models.getPendingTransactions @@ -207,6 +209,8 @@ internal class DefaultWalletAmountsRepository( updateWalletStoreWithAmounts( walletStore = walletStore, updatedWallet = walletManager.wallet, + // fixme move DemoHelper to Demo core module maybe + isDemo = DemoHelper.isDemoCardId(scanResponse.card.cardId), ) } .flatMap { fetchWalletStoreRentIfNeeded(walletStore, walletManager) } @@ -296,6 +300,7 @@ internal class DefaultWalletAmountsRepository( private suspend fun updateWalletStoreWithAmounts( walletStore: WalletStoreModel, updatedWallet: Wallet, + isDemo: Boolean, ) = withContext(Dispatchers.Default) { Timber.d( """ @@ -309,7 +314,11 @@ internal class DefaultWalletAmountsRepository( prevState.replaceWalletStore( walletStoreToUpdate = walletStore, update = { - it.updateWithAmounts(wallet = updatedWallet) + if (isDemo) { + it.updateWithDemoAmounts(wallet = updatedWallet) + } else { + it.updateWithAmounts(wallet = updatedWallet) + } }, ) } diff --git a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/utils/WalletDataOperations.kt b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/utils/WalletDataOperations.kt index 64e2241737..cb49fe33c1 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/utils/WalletDataOperations.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/utils/WalletDataOperations.kt @@ -7,6 +7,7 @@ import com.tangem.common.core.TangemError import com.tangem.tap.domain.extensions.amountToCreateAccount import com.tangem.tap.domain.getFirstToken import com.tangem.tap.domain.model.WalletDataModel +import com.tangem.tap.features.demo.DemoHelper import com.tangem.tap.features.wallet.models.Currency import com.tangem.tap.features.wallet.models.getPendingTransactions import java.math.BigDecimal @@ -74,12 +75,25 @@ internal fun WalletDataModel.updateWithAmount(wallet: Wallet): WalletDataModel { ) } +internal fun WalletDataModel.updateWithDemoAmount(wallet: Wallet): WalletDataModel { + val amount = DemoHelper.config.getBalance(wallet.blockchain) + return this.copy( + status = WalletDataModel.VerifiedOnline(amount = amount.value ?: BigDecimal.ZERO), + ) +} + internal fun List.updateWithAmounts(wallet: Wallet): List { return this.map { walletData -> walletData.updateWithAmount(wallet) } } +internal fun List.updateWithDemoAmounts(wallet: Wallet): List { + return this.map { walletData -> + walletData.updateWithDemoAmount(wallet) + } +} + internal fun WalletDataModel.updateWithError( wallet: Wallet, error: TangemError, @@ -164,7 +178,7 @@ internal fun List.updateWithSelf( val updatedWalletsData = arrayListOf() newWalletsData.forEach { newWalletData -> - val walletDataToUpdate = oldWalletsData.find(newWalletData::isSameWalletData) + val walletDataToUpdate = oldWalletsData.firstOrNull(newWalletData::isSameWalletData) if (walletDataToUpdate != null) { updatedWalletsData.add(walletDataToUpdate.updateWithSelf(newWalletData)) } else { @@ -176,5 +190,5 @@ internal fun List.updateWithSelf( } internal fun WalletDataModel.isSameWalletData(other: WalletDataModel): Boolean { - return currency == other.currency + return this.currency == other.currency } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/utils/WalletStoreOperations.kt b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/utils/WalletStoreOperations.kt index 0e9e9d8715..0c3e47861c 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/utils/WalletStoreOperations.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/utils/WalletStoreOperations.kt @@ -49,6 +49,14 @@ internal fun WalletStoreModel.updateWithAmounts( ) } +internal fun WalletStoreModel.updateWithDemoAmounts( + wallet: Wallet, +): WalletStoreModel { + return this.copy( + walletsData = walletsData.updateWithDemoAmounts(wallet = wallet), + ) +} + internal fun WalletStoreModel.updateWithFiatRates( rates: Map, ): WalletStoreModel { @@ -96,6 +104,9 @@ private inline fun List.replaceWalletStores( walletStoresToUpdate.forEach { walletStoreToUpdate -> val index = mutableStores.indexOfFirst(walletStoreToUpdate::isSameWalletStore) + // Can be possible if user hides wallet store when it's tokens is loading + if (index == -1) return@forEach + val currentWalletStore = mutableStores[index] val updatedWalletStore = update(currentWalletStore) @@ -116,6 +127,7 @@ private inline fun List.replaceWalletStores( } internal fun WalletStoreModel.isSameWalletStore(other: WalletStoreModel): Boolean { - return this.blockchain == other.blockchain && + return this.userWalletId == other.userWalletId && + this.blockchain == other.blockchain && this.derivationPath == other.derivationPath } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/home/compose/views/HomeButtons.kt b/app/src/main/java/com/tangem/tap/features/home/compose/views/HomeButtons.kt index cea593e6fe..b5ca216aeb 100644 --- a/app/src/main/java/com/tangem/tap/features/home/compose/views/HomeButtons.kt +++ b/app/src/main/java/com/tangem/tap/features/home/compose/views/HomeButtons.kt @@ -95,6 +95,7 @@ fun ProgressButton( Button( modifier = modifier, onClick = onClick, + enabled = !inProgress, colors = ButtonDefaults.textButtonColors( backgroundColor = backgroundColor, contentColor = contentColor, 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 b85a6601c5..76048ed0f4 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 @@ -79,10 +79,9 @@ private fun readCard(analyticsEvent: AnalyticsEvent?) = scope.launch { onProgressStateChange = { showProgress -> if (showProgress) { changeButtonState(ButtonState.PROGRESS) + } else { + changeButtonState(ButtonState.ENABLED) } - // else { //todo hide this because - // changeButtonState(ButtonState.ENABLED) - // } }, onScanStateChange = { scanInProgress -> store.dispatch(HomeAction.ScanInProgress(scanInProgress)) @@ -103,19 +102,23 @@ private fun readCard(analyticsEvent: AnalyticsEvent?) = scope.launch { scope.launch { store.onUserWalletSelected(userWallet) } } .doOnResult { - changeButtonState(ButtonState.ENABLED) - store.dispatchOnMain(NavigationAction.NavigateTo(AppScreen.Wallet)) + navigateTo(AppScreen.Wallet) } } else { store.onCardScanned(scanResponse) - changeButtonState(ButtonState.ENABLED) - store.dispatchOnMain(NavigationAction.NavigateTo(AppScreen.Wallet)) + navigateTo(AppScreen.Wallet) } } }, ) } +private suspend fun navigateTo(appScreen: AppScreen) { + store.dispatchOnMain(NavigationAction.NavigateTo(appScreen)) + delay(200) + changeButtonState(ButtonState.ENABLED) +} + private fun changeButtonState(state: ButtonState) { store.dispatchOnMain(HomeAction.ChangeScanCardButtonState(IndeterminateProgressButton(state))) } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt index 84e02b7b66..939236339c 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt @@ -22,7 +22,6 @@ import com.tangem.tap.domain.tokens.models.BlockchainNetwork import com.tangem.tap.features.demo.DemoHelper import com.tangem.tap.features.home.redux.HomeAction import com.tangem.tap.features.onboarding.OnboardingHelper -import com.tangem.tap.features.onboarding.products.wallet.saltPay.dialog.SaltPayDialog import com.tangem.tap.features.onboarding.products.wallet.saltPay.redux.OnboardingSaltPayAction import com.tangem.tap.features.onboarding.products.wallet.saltPay.redux.OnboardingSaltPayState import com.tangem.tap.features.wallet.redux.Artwork @@ -188,12 +187,7 @@ private fun handleWalletAction(action: Action, state: () -> AppState?, dispatch: } newAction?.let { store.dispatch(it) } } - OnboardingWalletAction.OnBackPressed -> { - when { - onboardingWalletState.isSaltPay -> handleOnBackPressedSaltPay(onboardingWalletState) - else -> handleOnBackPressed(onboardingWalletState) - } - } + OnboardingWalletAction.OnBackPressed -> handleOnBackPressed(onboardingWalletState) } } @@ -408,30 +402,33 @@ private fun initSaltPayOnBackupFinishedIfNeeded( } } -private fun handleOnBackPressedSaltPay(state: OnboardingWalletState) { +private fun handleOnBackPressed(state: OnboardingWalletState) { when (state.backupState.backupStep) { - BackupStep.Finished -> { - store.dispatchDialogShow( - SaltPayDialog.Activation.TryToInterrupt( - onOk = { store.dispatch(NavigationAction.PopBackTo()) }, - onCancel = { /* do nothing */ }, - ), - ) + BackupStep.InitBackup, BackupStep.ScanOriginCard, BackupStep.AddBackupCards, BackupStep.EnterAccessCode, + BackupStep.ReenterAccessCode, BackupStep.SetAccessCode, BackupStep.WritePrimaryCard, + -> { + showInterruptOnboardingDialog() + } + is BackupStep.WriteBackupCard -> { + store.dispatch(GlobalAction.ShowDialog(BackupDialog.BackupInProgress)) + } + BackupStep.Finished -> { + if (state.isSaltPay) { + showInterruptOnboardingDialog() + } else { + store.dispatch(NavigationAction.PopBackTo()) + } } - else -> handleOnBackPressed(state) } } -private fun handleOnBackPressed(state: OnboardingWalletState) { - when (state.backupState.backupStep) { - BackupStep.InitBackup, BackupStep.Finished -> store.dispatch(NavigationAction.PopBackTo()) - BackupStep.ScanOriginCard, BackupStep.AddBackupCards, BackupStep.EnterAccessCode, - BackupStep.ReenterAccessCode, BackupStep.SetAccessCode, BackupStep.WritePrimaryCard, - -> { - store.dispatch(BackupAction.DiscardBackup) - store.dispatch(NavigationAction.PopBackTo()) - } - is BackupStep.WriteBackupCard -> - store.dispatch(GlobalAction.ShowDialog(BackupDialog.BackupInProgress)) - } +private fun showInterruptOnboardingDialog() { + store.dispatchDialogShow( + OnboardingDialog.InterruptOnboarding( + onOk = { + store.dispatch(BackupAction.DiscardBackup) + store.dispatch(NavigationAction.PopBackTo()) + }, + ), + ) } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletState.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletState.kt index 6fc233d092..4e3cad3657 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletState.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletState.kt @@ -2,6 +2,7 @@ package com.tangem.tap.features.onboarding.products.wallet.redux import android.graphics.Bitmap import com.tangem.common.CardFilter +import com.tangem.common.extensions.VoidCallback import com.tangem.domain.common.SaltPayWorkaround import com.tangem.tap.common.redux.StateDialog import com.tangem.tap.features.onboarding.products.wallet.saltPay.redux.OnboardingSaltPayState @@ -104,9 +105,13 @@ sealed class BackupStep { object Finished : BackupStep() } +sealed class OnboardingDialog : StateDialog { + data class InterruptOnboarding(val onOk: VoidCallback) : BackupDialog() +} + sealed class BackupDialog : StateDialog { - object AddMoreBackupCards : StateDialog - object BackupInProgress : StateDialog - object UnfinishedBackupFound : StateDialog - object ConfirmDiscardingBackup : StateDialog + object AddMoreBackupCards : BackupDialog() + object BackupInProgress : BackupDialog() + object UnfinishedBackupFound : BackupDialog() + object ConfirmDiscardingBackup : BackupDialog() } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/GnosisRegistrator.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/GnosisRegistrator.kt index f0319a11ba..42c54a9395 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/GnosisRegistrator.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/GnosisRegistrator.kt @@ -38,11 +38,11 @@ class GnosisRegistrator( } private val otpProcessorContractAddress: String = when (walletManager.wallet.blockchain) { - Blockchain.SaltPay -> "0x3B4397C817A26521Df8bD01a949AFDE2251d91C2" + Blockchain.SaltPay -> "0xc659f4FEd7A84a188F54cBA4A7a49D77c1a20522" else -> throw IllegalArgumentException("GnosisRegistrator supports only the SaltPay blockchain") } - private val addressTreasureSafe = "0x8e9260a049d3Aa9ac60D0d4F27017320E0e2396B" + private val addressTreasureSafe = "0x24A3c2382497075b6D93258f5938f7B661c06318" private val atomicNonce = AtomicLong() diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/SaltPayConfig.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/SaltPayConfig.kt index d853819a57..19048168de 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/SaltPayConfig.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/SaltPayConfig.kt @@ -1,6 +1,7 @@ package com.tangem.tap.features.onboarding.products.wallet.saltPay import com.tangem.tap.common.zendesk.ZendeskConfig +import org.spongycastle.util.encoders.Base64.toBase64String /** [REDACTED_AUTHOR] @@ -8,12 +9,14 @@ import com.tangem.tap.common.zendesk.ZendeskConfig data class SaltPayConfig( val zendesk: ZendeskConfig, val kycProvider: KYCProvider, + val credentials: Credentials, ) { companion object { fun stub(): SaltPayConfig { return SaltPayConfig( zendesk = ZendeskConfig("", "", "", "", ""), kycProvider = KYCProvider("", "", "", ""), + credentials = Credentials("", ""), ) } } @@ -24,4 +27,11 @@ data class KYCProvider( val externalIdParameterKey: String, val sidParameterKey: String, val sidValue: String, -) \ No newline at end of file +) + +data class Credentials( + val user: String, + val password: String, +) { + val token: String by lazy { "Basic ${toBase64String("$user:$password".toByteArray())}" } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/dialog/TryToInterruptRegistrationDialog.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/dialog/InterruptOnboardingDialog.kt similarity index 79% rename from app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/dialog/TryToInterruptRegistrationDialog.kt rename to app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/dialog/InterruptOnboardingDialog.kt index 6f02df9120..1636675ae1 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/dialog/TryToInterruptRegistrationDialog.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/dialog/InterruptOnboardingDialog.kt @@ -4,20 +4,21 @@ import android.app.Dialog import android.content.Context import androidx.appcompat.app.AlertDialog import com.tangem.tap.common.extensions.dispatchDialogHide +import com.tangem.tap.features.onboarding.products.wallet.redux.OnboardingDialog import com.tangem.tap.store import com.tangem.wallet.R /** [REDACTED_AUTHOR] */ -class TryToInterruptRegistrationDialog { +class InterruptOnboardingDialog { companion object { - fun create(context: Context, dialog: SaltPayDialog.Activation.TryToInterrupt): Dialog { + fun create(context: Context, dialog: OnboardingDialog.InterruptOnboarding): Dialog { return AlertDialog.Builder(context).apply { setTitle(context.getString(R.string.onboarding_exit_alert_title)) setMessage(context.getString(R.string.onboarding_exit_alert_message)) setPositiveButton(R.string.common_ok) { _, _ -> dialog.onOk() } - setNegativeButton(R.string.common_cancel) { _, _ -> dialog.onCancel() } + setNegativeButton(R.string.common_cancel) { _, _ -> } setOnDismissListener { store.dispatchDialogHide() } setCancelable(false) }.create() diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/dialog/SaltPayDialog.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/dialog/SaltPayDialog.kt index fda1331a37..b8b512aef1 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/dialog/SaltPayDialog.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/dialog/SaltPayDialog.kt @@ -1,6 +1,5 @@ package com.tangem.tap.features.onboarding.products.wallet.saltPay.dialog -import com.tangem.common.extensions.VoidCallback import com.tangem.tap.common.redux.StateDialog import com.tangem.tap.features.onboarding.products.wallet.saltPay.message.SaltPayActivationError @@ -11,6 +10,5 @@ sealed class SaltPayDialog : StateDialog { sealed class Activation : SaltPayDialog() { object NoGas : SaltPayDialog() data class OnError(val error: SaltPayActivationError) : SaltPayDialog() - data class TryToInterrupt(val onOk: VoidCallback, val onCancel: VoidCallback) : SaltPayDialog() } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayMiddleware.kt index ce3390eba1..b7bcb4761b 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayMiddleware.kt @@ -6,11 +6,11 @@ import com.tangem.blockchain.extensions.successOr import com.tangem.common.Filter import com.tangem.common.extensions.guard import com.tangem.common.services.Result -import com.tangem.domain.common.extensions.successOr -import com.tangem.domain.common.extensions.withMainContext +import com.tangem.core.analytics.Analytics import com.tangem.datasource.api.paymentology.KYCStatus import com.tangem.datasource.api.paymentology.RegistrationResponse -import com.tangem.core.analytics.Analytics +import com.tangem.domain.common.extensions.successOr +import com.tangem.domain.common.extensions.withMainContext import com.tangem.tap.common.analytics.events.Onboarding import com.tangem.tap.common.extensions.dispatchDebugErrorNotification import com.tangem.tap.common.extensions.dispatchOnMain @@ -286,7 +286,7 @@ suspend fun SaltPayActivationManager.update( return Result.Failure(ex) } - // checkGasIfNeeded(this, newStep).successOr { return it } + checkGasIfNeeded(this, newStep).successOr { return it } Timber.d("update: success: %s", newStep) return Result.Success(newStep) 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 75b79e6a61..155ce6ebd7 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,6 +1,6 @@ package com.tangem.tap.features.wallet.redux.middlewares -import com.tangem.blockchain.common.AmountType +import com.tangem.blockchain.common.Blockchain import com.tangem.common.extensions.isZero import com.tangem.tap.common.extensions.stripZeroPlainString import com.tangem.tap.common.extensions.toFiatRateString @@ -10,7 +10,6 @@ import com.tangem.tap.common.extensions.toFormattedFiatValue import com.tangem.tap.domain.model.TotalFiatBalance import com.tangem.tap.domain.model.WalletDataModel import com.tangem.tap.domain.model.WalletStoreModel -import com.tangem.tap.features.wallet.models.Currency import com.tangem.tap.features.wallet.models.TotalBalance import com.tangem.tap.features.wallet.models.WalletRent import com.tangem.tap.features.wallet.redux.ProgressState @@ -24,11 +23,9 @@ import com.tangem.tap.features.wallet.ui.TokenData import com.tangem.tap.store import java.math.BigDecimal -internal fun List.mapToReduxModels( - isMultiWalletAllowed: Boolean, -): List { +internal fun List.mapToReduxModels(): List { return this.map { walletStoreModel -> - walletStoreModel.mapToReduxModel(isMultiWalletAllowed) + walletStoreModel.mapToReduxModel() } } @@ -44,100 +41,150 @@ internal fun TotalFiatBalance.mapToReduxModel(): TotalBalance { ) } -internal fun WalletStoreModel.mapToReduxModel( - isMultiWalletAllowed: Boolean, -): WalletStore { +internal fun WalletStoreModel.mapToReduxModel(): WalletStore { + val appCurrencySymbol = store.state.globalState.appCurrency.symbol return WalletStore( walletManager = walletManager, blockchainNetwork = blockchainNetwork, - walletsData = walletsData.mapToReduxModel(isMultiWalletAllowed, walletRent), + walletsData = walletsData.mapToReduxModels(walletRent, appCurrencySymbol), ) + .updateTokenModels(blockchainWalletData.status.amount) + .setupIfHadCardSingleToken( + blockchain = blockchain, + walletsDataModel = walletsData, + appCurrencySymbol = appCurrencySymbol, + blockchainWalletData = blockchainWalletData.mapToReduxModel( + walletRent = walletRent, + appCurrencySymbol = appCurrencySymbol, + ), + ) } -private fun List.mapToReduxModel( - isMultiWalletAllowed: Boolean, +private fun List.mapToReduxModels( walletRent: WalletStoreModel.WalletRent?, + appCurrencySymbol: String, ): List { return this.map { walletDataModel -> - with(walletDataModel) { - val amount = status.amount - val amountFormatted = amount.toFormattedCurrencyString( - decimals = currency.decimals, - currency = currency.currencySymbol, - ) - val appCurrency = store.state.globalState.appCurrency - val fiatAmount = fiatRate?.let { status.amount.toFiatValue(it) } - val fiatAmountFormatted = fiatAmount - ?.takeIf { !status.isErrorStatus } - ?.toFormattedFiatValue(appCurrency.symbol) - val fiatRateFormatted = fiatRate?.toFiatRateString(appCurrency.symbol) - val blockchainAmountValue = getBlockchainAmount() - - WalletData( - currency = currency, - walletAddresses = walletAddresses.getOrNull(0)?.let { selectedAddress -> - WalletAddresses( - selectedAddress = selectedAddress, - list = walletAddresses, - ) - }, - existentialDepositString = existentialDeposit?.toPlainString(), - fiatRate = fiatRate, - fiatRateString = fiatRateFormatted, - pendingTransactions = status.pendingTransactions, - mainButton = WalletMainButton.SendButton( - enabled = !blockchainAmountValue.isZero() - && !status.amount.isZero() - && status.pendingTransactions.isEmpty(), - ), - walletRent = walletRent?.let { - WalletRent( - minRentValue = "${it.rent.stripZeroPlainString()} ${currency.blockchain.currency}", - rentExemptValue = "${it.exemptionAmount.stripZeroPlainString()} ${currency.blockchain.currency}", - ) - }, - currencyData = BalanceWidgetData( - status = when (status) { - is WalletDataModel.Loading -> BalanceStatus.Loading - is WalletDataModel.NoAccount -> BalanceStatus.NoAccount - is WalletDataModel.SameCurrencyTransactionInProgress -> BalanceStatus.SameCurrencyTransactionInProgress - is WalletDataModel.TransactionInProgress -> BalanceStatus.TransactionInProgress - is WalletDataModel.Unreachable -> BalanceStatus.Unreachable - is WalletDataModel.MissedDerivation -> BalanceStatus.MissedDerivation - is WalletDataModel.VerifiedOnline -> BalanceStatus.VerifiedOnline - }, - currency = currency.currencyName, - currencySymbol = currency.currencySymbol, - blockchainAmount = blockchainAmountValue, - amount = amount, - amountFormatted = amountFormatted, - fiatAmount = fiatAmount, - fiatAmountFormatted = fiatAmountFormatted, - token = when { - !isMultiWalletAllowed && currency is Currency.Token -> { - TokenData( - amount = amount, - amountFormatted = amountFormatted, - fiatAmount = fiatAmount, - fiatAmountFormatted = fiatAmountFormatted, - tokenSymbol = currency.currencySymbol, - fiatRate = fiatRate, - fiatRateString = fiatRateFormatted, - ) - } - else -> null - }, - amountToCreateAccount = (status as? WalletDataModel.NoAccount) - ?.amountToCreateAccount - ?.toString(), - errorMessage = status.errorMessage, - ), - ) - } + walletDataModel.mapToReduxModel(walletRent, appCurrencySymbol) } } -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 +private fun WalletDataModel.mapToReduxModel( + walletRent: WalletStoreModel.WalletRent?, + appCurrencySymbol: String, +): WalletData { + val amount = status.amount + val amountFormatted = amount.toFormattedCurrencyString( + decimals = currency.decimals, + currency = currency.currencySymbol, + ) + val fiatAmount = fiatRate?.let { status.amount.toFiatValue(it) } + val fiatAmountFormatted = fiatAmount + ?.takeIf { !status.isErrorStatus } + ?.toFormattedFiatValue(appCurrencySymbol) + val fiatRateFormatted = fiatRate?.toFiatRateString(appCurrencySymbol) + + return WalletData( + currency = currency, + walletAddresses = walletAddresses.getOrNull(0)?.let { selectedAddress -> + WalletAddresses( + selectedAddress = selectedAddress, + list = walletAddresses, + ) + }, + existentialDepositString = existentialDeposit?.toPlainString(), + fiatRate = fiatRate, + fiatRateString = fiatRateFormatted, + pendingTransactions = status.pendingTransactions, + mainButton = WalletMainButton.SendButton( + enabled = !status.amount.isZero() && status.pendingTransactions.isEmpty(), + ), + walletRent = walletRent?.let { + WalletRent( + minRentValue = "${it.rent.stripZeroPlainString()} ${currency.blockchain.currency}", + rentExemptValue = "${it.exemptionAmount.stripZeroPlainString()} ${currency.blockchain.currency}", + ) + }, + currencyData = BalanceWidgetData( + status = when (status) { + is WalletDataModel.Loading -> BalanceStatus.Loading + is WalletDataModel.NoAccount -> BalanceStatus.NoAccount + is WalletDataModel.SameCurrencyTransactionInProgress -> BalanceStatus.SameCurrencyTransactionInProgress + is WalletDataModel.TransactionInProgress -> BalanceStatus.TransactionInProgress + is WalletDataModel.Unreachable -> BalanceStatus.Unreachable + is WalletDataModel.MissedDerivation -> BalanceStatus.MissedDerivation + is WalletDataModel.VerifiedOnline -> BalanceStatus.VerifiedOnline + }, + currency = currency.currencyName, + currencySymbol = currency.currencySymbol, + blockchainAmount = BigDecimal.ZERO, + amount = amount, + amountFormatted = amountFormatted, + fiatAmount = fiatAmount, + fiatAmountFormatted = fiatAmountFormatted, + token = null, + amountToCreateAccount = (status as? WalletDataModel.NoAccount) + ?.amountToCreateAccount + ?.toString(), + errorMessage = status.errorMessage, + ), + ) +} + +private fun WalletStore.updateTokenModels(blockchainAmount: BigDecimal): WalletStore { + val updatedTokensWalletData = walletsData.filter { it.currency.isToken() }.map { + it.copy( + mainButton = when (it.mainButton) { + is WalletMainButton.SendButton -> { + WalletMainButton.SendButton(it.mainButton.enabled && !blockchainAmount.isZero()) + } + is WalletMainButton.CreateWalletButton -> it.mainButton + }, + currencyData = it.currencyData.copy( + blockchainAmount = blockchainAmount, + ), + ) + } + return updateWallets(updatedTokensWalletData) +} + +private fun WalletStore.setupIfHadCardSingleToken( + blockchain: Blockchain, + walletsDataModel: List, + appCurrencySymbol: String, + blockchainWalletData: WalletData, +): WalletStore { + // Card with single token contains only 2 model - blockchain and token + if (walletsData.size != 2) return this + + val cardSingleTokenWalletData = walletsDataModel.firstOrNull { + it.currency.isToken() && it.currency.blockchain == blockchain && it.isCardSingleToken + } ?: return this + + val blockchainWalletDataWithSingleToken = blockchainWalletData.copy( + currencyData = blockchainWalletData.currencyData.copy( + token = cardSingleTokenWalletData.toTokenData(appCurrencySymbol), + ), + ) + return updateWallets(listOf(blockchainWalletDataWithSingleToken)) +} + +private fun WalletDataModel.toTokenData(appCurrencySymbol: String): TokenData { + val amount = status.amount + val fiatAmount = fiatRate?.let { status.amount.toFiatValue(it) } + + return TokenData( + amount = amount, + amountFormatted = amount.toFormattedCurrencyString( + decimals = currency.decimals, + currency = currency.currencySymbol, + ), + fiatAmount = fiatAmount, + fiatAmountFormatted = fiatAmount + ?.takeIf { !status.isErrorStatus } + ?.toFormattedFiatValue(appCurrencySymbol), + tokenSymbol = currency.currencySymbol, + fiatRate = fiatRate, + fiatRateString = fiatRate?.toFiatRateString(appCurrencySymbol), + ) } \ 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 80b1ddfc2b..03b26092b2 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 @@ -318,7 +318,7 @@ class WalletMiddleware { } } - val reduxWalletStores = wallStores.mapToReduxModels(state.isMultiwalletAllowed) + val reduxWalletStores = wallStores.mapToReduxModels() store.dispatchOnMain( WalletAction.WalletStoresChanged.UpdateWalletStores( reduxWalletStores = reduxWalletStores, 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 e65f402169..e38d9d947b 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 @@ -16,6 +16,8 @@ import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.LinearLayoutManager import androidx.transition.TransitionInflater import by.kirich1409.viewbindingdelegate.viewBinding +import com.badoo.mvicore.DiffStrategy +import com.badoo.mvicore.ModelWatcher import com.badoo.mvicore.modelWatcher import com.tangem.common.doOnResult import com.tangem.core.analytics.Analytics @@ -39,6 +41,8 @@ import com.tangem.tap.common.redux.navigation.NavigationAction import com.tangem.tap.domain.tokens.models.BlockchainNetwork import com.tangem.tap.features.wallet.models.Currency import com.tangem.tap.features.wallet.models.PendingTransaction +import com.tangem.tap.features.wallet.models.WalletWarning +import com.tangem.tap.features.wallet.redux.AddressData import com.tangem.tap.features.wallet.redux.ErrorType import com.tangem.tap.features.wallet.redux.ProgressState import com.tangem.tap.features.wallet.redux.WalletAction @@ -67,7 +71,13 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), private val binding: FragmentWalletDetailsBinding by viewBinding(FragmentWalletDetailsBinding::bind) - private val walletDataWatcher = modelWatcher { + private val walletDataWatcher: ModelWatcher = modelWatcher { + val addressCardStrategy: DiffStrategy = { old, new -> + old.currency != new.currency || + old.walletAddresses?.selectedAddress != new.walletAddresses?.selectedAddress || + old.shouldShowMultipleAddress() != new.shouldShowMultipleAddress() + } + WalletData::pendingTransactions { showPendingTransactionsIfPresent(it) } @@ -77,25 +87,35 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), WalletData::currencyData { setupBalanceData(it) } + WalletData::walletAddresses { walletAddresses -> + setupCopyAndShareButtons(walletAddresses?.selectedAddress?.address) + } + WalletData::assembleWarnings { warnings -> + handleWarnings(warnings) + } (WalletData::currencyData or WalletData::currency) { walletData -> setupCurrency(walletData.currencyData, walletData.currency) setupSwipeRefresh(walletData.currencyData, walletData.currency) } + watch({ it }, addressCardStrategy) { walletData -> + setupAddressCard( + shouldShowMultipleAddress = walletData.shouldShowMultipleAddress(), + selectedAddress = walletData.walletAddresses?.selectedAddress, + currency = walletData.currency, + ) + } } - private val walletStateWatcher = modelWatcher { - (WalletState::selectedCurrency or WalletState::selectedWalletData) { state -> - val selectedWalletData = state.selectedWalletData - if (selectedWalletData != null) { - walletDataWatcher.invoke(selectedWalletData) - setupButtons(selectedWalletData, state.isExchangeServiceFeatureOn) - setupAddressCard(selectedWalletData) - handleWarnings(selectedWalletData) + private val walletStateWatcher: ModelWatcher = modelWatcher { + WalletState::selectedWalletData { selectedWallet -> + if (selectedWallet != null) { + walletDataWatcher.invoke(selectedWallet) } } - (WalletState::selectedCurrency or WalletState::isExchangeServiceFeatureOn) { state -> - if (state.selectedWalletData != null) { - setupButtons(state.selectedWalletData!!, state.isExchangeServiceFeatureOn) + (WalletState::selectedWalletData or WalletState::isExchangeServiceFeatureOn) { state -> + val selectedWallet = state.selectedWalletData + if (selectedWallet != null) { + setupButtonsRow(selectedWallet, state.isExchangeServiceFeatureOn) } } (WalletState::state or WalletState::error) { state -> @@ -132,8 +152,6 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), override fun onStop() { super.onStop() store.unsubscribe(this) - walletDataWatcher.clear() - walletStateWatcher.clear() } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { @@ -147,6 +165,11 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), setupTestActionButton() } + override fun onDestroyView() { + super.onDestroyView() + clearWatchers() + } + private fun setupTransactionsRecyclerView() = with(binding) { pendingTransactionAdapter = PendingTransactionsAdapter() rvPendingTransaction.layoutManager = LinearLayoutManager(requireContext()) @@ -251,19 +274,21 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), currencyData.status == BalanceStatus.Refreshing } - private fun setupButtons(selectedWallet: WalletData, isExchangeServiceFeatureOn: Boolean) = with(binding) { - lWalletDetails.btnCopy.setOnClickListener { - selectedWallet.walletAddresses?.selectedAddress?.address?.let { addressString -> - store.dispatch(WalletAction.CopyAddress(addressString, requireContext())) + private fun setupCopyAndShareButtons(walletAddress: String?) { + binding.lWalletDetails.btnCopy.setOnClickListener { + if (walletAddress != null) { + store.dispatch(WalletAction.CopyAddress(walletAddress, requireContext())) } } - lWalletDetails.btnShare.setOnClickListener { - selectedWallet.walletAddresses?.selectedAddress?.address?.let { addressString -> - store.dispatch(WalletAction.ShareAddress(addressString, requireContext())) + binding.lWalletDetails.btnShare.setOnClickListener { + if (walletAddress != null) { + store.dispatch(WalletAction.ShareAddress(walletAddress, requireContext())) } } + } - rowButtons.updateButtonsVisibility( + private fun setupButtonsRow(selectedWallet: WalletData, isExchangeServiceFeatureOn: Boolean) { + binding.rowButtons.updateButtonsVisibility( exchangeServiceFeatureOn = isExchangeServiceFeatureOn, buyAllowed = selectedWallet.isAvailableToBuy, sellAllowed = selectedWallet.isAvailableToSell, @@ -271,9 +296,9 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), ) } - private fun handleWarnings(selectedWallet: WalletData) = with(binding) { + private fun handleWarnings(warnings: List) = with(binding) { val converter = WalletWarningConverter(requireContext()) - val warningDetails = selectedWallet.assembleWarnings().map { converter.convert(it) } + val warningDetails = warnings.map { converter.convert(it) } warningMessagesAdapter.submitList(warningDetails) rvWarningMessages.show(warningDetails.isNotEmpty()) @@ -294,51 +319,59 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), binding.rvPendingTransaction.show(pendingTransactions.isNotEmpty()) } - private fun setupAddressCard(state: WalletData) = with(binding.lWalletDetails) { - if (state.walletAddresses != null) { - if (state.shouldShowMultipleAddress() && state.currency is Currency.Blockchain) { - (cardBalance as? ViewGroup)?.beginDelayedTransition() - chipGroupAddressType.show() - chipGroupAddressType.fitChipsByGroupWidth() + private fun setupAddressCard( + shouldShowMultipleAddress: Boolean, + selectedAddress: AddressData?, + currency: Currency, + ) = with(binding.lWalletDetails) { + if (selectedAddress == null) return@with - val checkedId = - MultipleAddressUiHelper.typeToId(state.walletAddresses.selectedAddress.type) - if (checkedId != View.NO_ID) chipGroupAddressType.check(checkedId) + setupAddressTypeChips(shouldShowMultipleAddress, selectedAddress, currency) - chipGroupAddressType.setOnCheckedChangeListener { group, checkedId -> - if (checkedId == -1) return@setOnCheckedChangeListener - val type = - MultipleAddressUiHelper.idToType(checkedId, state.currency.blockchain) - type?.let { store.dispatch(WalletAction.ChangeSelectedAddress(type)) } - } - } else { - chipGroupAddressType.hide() - } - tvAddress.text = state.walletAddresses.selectedAddress.address - tvExplore.setOnClickListener { - store.dispatch( - WalletAction.ExploreAddress( - state.walletAddresses.selectedAddress.exploreUrl, - requireContext(), - ), - ) - } - ivQrCode.setImageBitmap(state.walletAddresses.selectedAddress.shareUrl.toQrCode()) + tvAddress.text = selectedAddress.address + tvExplore.setOnClickListener { + store.dispatch(WalletAction.ExploreAddress(selectedAddress.exploreUrl, requireContext())) + } + ivQrCode.setImageBitmap(selectedAddress.shareUrl.toQrCode()) - tvReceiveMessage.text = when (val currency = state.currency) { - is Currency.Blockchain -> tvReceiveMessage.getString( - id = R.string.address_qr_code_message_format, - currency.blockchain.fullName, - currency.currencySymbol, - currency.blockchain.fullName, - ) - is Currency.Token -> tvReceiveMessage.getString( - id = R.string.address_qr_code_message_format, - currency.token.name, - currency.currencySymbol, - currency.blockchain.fullName, - ) + tvReceiveMessage.text = when (currency) { + is Currency.Blockchain -> tvReceiveMessage.getString( + id = R.string.address_qr_code_message_format, + currency.blockchain.fullName, + currency.currencySymbol, + currency.blockchain.fullName, + ) + is Currency.Token -> tvReceiveMessage.getString( + id = R.string.address_qr_code_message_format, + currency.token.name, + currency.currencySymbol, + currency.blockchain.fullName, + ) + } + } + + private fun setupAddressTypeChips( + shouldShowMultipleAddress: Boolean, + selectedAddress: AddressData, + currency: Currency, + ) = with(binding.lWalletDetails) { + if (shouldShowMultipleAddress && currency is Currency.Blockchain) { + (cardBalance as? ViewGroup)?.beginDelayedTransition() + chipGroupAddressType.show() + chipGroupAddressType.fitChipsByGroupWidth() + + val checkedId = + MultipleAddressUiHelper.typeToId(selectedAddress.type) + if (checkedId != View.NO_ID) chipGroupAddressType.check(checkedId) + + chipGroupAddressType.setOnCheckedChangeListener { _, checkedId -> + if (checkedId == -1) return@setOnCheckedChangeListener + val type = + MultipleAddressUiHelper.idToType(checkedId, currency.blockchain) + type?.let { store.dispatch(WalletAction.ChangeSelectedAddress(type)) } } + } else { + chipGroupAddressType.hide() } } @@ -425,6 +458,11 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), inflater.inflate(R.menu.menu_wallet_details, menu) } + private fun clearWatchers() { + walletDataWatcher.clear() + walletStateWatcher.clear() + } + private fun TextView.setWarningStatus(mainMessage: Int, error: String? = null) { val text = getString(mainMessage).appendIfNotNull(error, "\nError: ") setStatus(text, R.color.warning, R.drawable.ic_warning_small) diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/SingleWalletView.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/SingleWalletView.kt index 18ebc3dd4b..e7587a6983 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/SingleWalletView.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/SingleWalletView.kt @@ -12,6 +12,7 @@ import com.tangem.tap.common.extensions.show import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsState import com.tangem.tap.features.wallet.models.Currency import com.tangem.tap.features.wallet.models.PendingTransaction +import com.tangem.tap.features.wallet.models.PendingTransactionType import com.tangem.tap.features.wallet.redux.WalletAction import com.tangem.tap.features.wallet.redux.WalletData import com.tangem.tap.features.wallet.redux.WalletMainButton @@ -72,8 +73,11 @@ class SingleWalletView : WalletView() { } private fun showPendingTransactionsIfPresent(pendingTransactions: List) { - pendingTransactionAdapter.submitList(pendingTransactions) - binding?.rvPendingTransaction?.show(pendingTransactions.isNotEmpty()) + val knownTransactions = pendingTransactions.filterNot { + it.type == PendingTransactionType.Unknown + } + pendingTransactionAdapter.submitList(knownTransactions) + binding?.rvPendingTransaction?.show(knownTransactions.isNotEmpty()) } private fun setupBalance(state: WalletState, primaryWallet: WalletData) { diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorAction.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorAction.kt index 0985f4b68c..0fd46c00ba 100644 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorAction.kt +++ b/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorAction.kt @@ -24,8 +24,8 @@ internal sealed interface WalletSelectorAction : Action { val walletsStores: Map>, ) : WalletSelectorAction - data class BalanceLoaded( - val userWalletModel: UserWalletModel, + data class BalancesLoaded( + val userWalletModels: List, ) : WalletSelectorAction object UnlockWithBiometry : WalletSelectorAction { 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 4405407dcd..9d690e7df7 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 @@ -35,7 +35,6 @@ import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.launch import org.rekotlin.Middleware import timber.log.Timber -import java.math.BigDecimal internal class WalletSelectorMiddleware { val middleware: Middleware = { _, appStateProvider -> @@ -81,7 +80,7 @@ internal class WalletSelectorMiddleware { is WalletSelectorAction.SelectedWalletChanged, is WalletSelectorAction.UnlockWithBiometry.Error, is WalletSelectorAction.UnlockWithBiometry.Success, - is WalletSelectorAction.BalanceLoaded, + is WalletSelectorAction.BalancesLoaded, is WalletSelectorAction.IsLockedChanged, is WalletSelectorAction.HandleError, is WalletSelectorAction.CloseError, @@ -104,20 +103,10 @@ internal class WalletSelectorMiddleware { 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 (wallet != updatedWallet) { - store.dispatchOnMain(WalletSelectorAction.BalanceLoaded(updatedWallet)) - } - } + val updatedWallets = state.wallets.updateWalletStoresAndCalculateFiatBalance(updatedWalletStores) + if (updatedWallets != state.wallets) { + store.dispatchOnMain(WalletSelectorAction.BalancesLoaded(updatedWallets)) + } } } @@ -314,18 +303,28 @@ internal class WalletSelectorMiddleware { } } + private suspend fun List.updateWalletStoresAndCalculateFiatBalance( + walletStores: Map>, + ): List { + return this + .associateWith { walletStores[it.id] } + .map { (wallet, walletStores) -> + wallet.updateWalletStoresAndCalculateFiatBalance(walletStores) + } + } + private suspend fun UserWalletModel.updateWalletStoresAndCalculateFiatBalance( - walletStores: List, + walletStores: List?, ): UserWalletModel { return this.copy( type = when (type) { is UserWalletModel.Type.MultiCurrency -> type.copy( - tokensCount = walletStores.flatMap { it.walletsData }.size, + tokensCount = walletStores?.flatMap { it.walletsData }?.size ?: 0, ) is UserWalletModel.Type.SingleCurrency -> type }, fiatBalance = totalFiatBalanceCalculator.calculate( - walletStores = walletStores, + walletStores = walletStores.orEmpty(), initial = TotalFiatBalance.Loading, ), ) diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorReducer.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorReducer.kt index b64fe0a3ce..277d3f45dd 100644 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/walletSelector/redux/WalletSelectorReducer.kt @@ -24,8 +24,8 @@ internal object WalletSelectorReducer { is WalletSelectorAction.IsLockedChanged -> state.copy( isLocked = action.isLocked, ) - is WalletSelectorAction.BalanceLoaded -> state.copy( - wallets = state.wallets.updateWithBalance(action.userWalletModel), + is WalletSelectorAction.BalancesLoaded -> state.copy( + wallets = action.userWalletModels, ) is WalletSelectorAction.HandleError -> state.copy(error = action.error) is WalletSelectorAction.CloseError -> state.copy(error = null) @@ -85,19 +85,6 @@ internal object WalletSelectorReducer { } } - private fun List.updateWithBalance( - userWalletModel: UserWalletModel, - ): List { - return ArrayList(this).apply { - val index = indexOfFirst { it.id == userWalletModel.id } - if (index == -1) { - add(userWalletModel) - } else { - this[index] = userWalletModel - } - } - } - private fun UserWallet.getType(prevType: UserWalletModel.Type? = null): UserWalletModel.Type { return if (isMultiCurrency) { UserWalletModel.Type.MultiCurrency( diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/Mapper.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/Mapper.kt index e5dc088a55..5d18c5baa9 100644 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/Mapper.kt +++ b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/Mapper.kt @@ -9,6 +9,7 @@ import com.tangem.tap.features.walletSelector.redux.WalletSelectorState import com.tangem.tap.features.walletSelector.ui.model.MultiCurrencyUserWalletItem import com.tangem.tap.features.walletSelector.ui.model.SingleCurrencyUserWalletItem import com.tangem.tap.features.walletSelector.ui.model.UserWalletItem +import java.math.BigDecimal internal fun WalletSelectorScreenState.updateWithNewState( newState: WalletSelectorState, @@ -50,10 +51,14 @@ private fun List.toUiModels( ): Sequence { return this.asSequence().map { userWalletModel -> with(userWalletModel) { - val balance = UserWalletItem.Balance( - amount = fiatBalance.amount.toFormattedFiatValue(appCurrency.symbol), - isLoading = fiatBalance is TotalFiatBalance.Loading, - ) + val formatAmount = { amount: BigDecimal -> + amount.toFormattedFiatValue(appCurrency.symbol) + } + val balance = when (fiatBalance) { + is TotalFiatBalance.Error -> UserWalletItem.Balance.Error(formatAmount(fiatBalance.amount)) + is TotalFiatBalance.Loaded -> UserWalletItem.Balance.Loaded(formatAmount(fiatBalance.amount)) + is TotalFiatBalance.Loading -> UserWalletItem.Balance.Loading + } when (type) { is UserWalletModel.Type.MultiCurrency -> MultiCurrencyUserWalletItem( id = id, diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/MockData.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/MockData.kt index 65349386dc..db09868d03 100644 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/MockData.kt +++ b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/MockData.kt @@ -9,9 +9,8 @@ import com.tangem.tap.features.walletSelector.ui.model.UserWalletItem internal object MockData { private val multiCurrencyUserWallet = MultiCurrencyUserWalletItem( id = UserWalletId("wallet_1"), - balance = UserWalletItem.Balance( + balance = UserWalletItem.Balance.Loaded( amount = "6781.05 $", - isLoading = false, ), name = "Wallet", imageUrl = "https://app.tangem.com/cards/card_default.png", @@ -22,9 +21,8 @@ internal object MockData { private val singleCurrencyUserWallet = SingleCurrencyUserWalletItem( id = UserWalletId("wallet_4"), - balance = UserWalletItem.Balance( + balance = UserWalletItem.Balance.Loaded( amount = "6781.05 $", - isLoading = false, ), name = "Wallet", imageUrl = "https://app.tangem.com/cards/card_default.png", diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/WalletItem.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/WalletItem.kt index 3b6f021dba..6e67669815 100644 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/WalletItem.kt +++ b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/components/WalletItem.kt @@ -180,15 +180,24 @@ private fun TokensInfo( if (isLocked) { LockedPlaceholder() } else { - if (balance.isLoading) { - LoadingTokensInfo( - isMultiCurrencyWallet = tokensCount != null, - ) - } else { - LoadedTokensInfo( - balanceAmount = balance.amount, - tokensCount = tokensCount, - ) + when (balance) { + is UserWalletItem.Balance.Error -> { + LoadedTokensInfo( + balanceAmount = balance.amount, + tokensCount = tokensCount, + showWarning = true, + ) + } + is UserWalletItem.Balance.Loaded -> { + LoadedTokensInfo( + balanceAmount = balance.amount, + tokensCount = tokensCount, + showWarning = false, + ) + } + is UserWalletItem.Balance.Loading -> { + LoadingTokensInfo(isMultiCurrencyWallet = tokensCount != null) + } } } } @@ -234,17 +243,31 @@ private fun LoadedTokensInfo( modifier: Modifier = Modifier, balanceAmount: String, tokensCount: Int?, + showWarning: Boolean, ) { Column( modifier = modifier, horizontalAlignment = Alignment.End, ) { - Text( - text = balanceAmount, - style = TangemTheme.typography.subtitle1, - color = TangemTheme.colors.text.primary1, - textAlign = TextAlign.End, - ) + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing4), + ) { + Text( + text = balanceAmount, + style = TangemTheme.typography.subtitle1, + color = TangemTheme.colors.text.primary1, + textAlign = TextAlign.End, + ) + if (showWarning) { + Icon( + modifier = Modifier.size(TangemTheme.dimens.size16), + painter = painterResource(id = R.drawable.ic_alert_24), + tint = TangemTheme.colors.icon.attention, + contentDescription = null, + ) + } + } if (tokensCount != null) { SpacerH2() Text( diff --git a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/model/UserWalletItem.kt b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/model/UserWalletItem.kt index ddd7518ca6..eeca9d7611 100644 --- a/app/src/main/java/com/tangem/tap/features/walletSelector/ui/model/UserWalletItem.kt +++ b/app/src/main/java/com/tangem/tap/features/walletSelector/ui/model/UserWalletItem.kt @@ -9,10 +9,13 @@ internal sealed interface UserWalletItem { val balance: Balance val isLocked: Boolean - data class Balance( - val amount: String, - val isLoading: Boolean, - ) + sealed interface Balance { + object Loading : Balance + + data class Error(val amount: String) : Balance + + data class Loaded(val amount: String) : Balance + } } internal data class MultiCurrencyUserWalletItem( diff --git a/app/src/main/res/layout/fragment_wallet.xml b/app/src/main/res/layout/fragment_wallet.xml index b3d1b54730..50b77c777f 100644 --- a/app/src/main/res/layout/fragment_wallet.xml +++ b/app/src/main/res/layout/fragment_wallet.xml @@ -151,13 +151,12 @@ android:id="@+id/rv_pending_transaction" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="16dp" + android:layout_marginTop="12dp" android:nestedScrollingEnabled="false" android:overScrollMode="never" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@id/l_card_total_balance" - app:layout_goneMarginTop="12dp" /> + app:layout_constraintTop_toBottomOf="@id/rv_warning_messages" /> + app:layout_constraintTop_toBottomOf="@id/l_card_total_balance" /> + app:layout_constraintTop_toBottomOf="@id/rv_warning_messages" /> + + diff --git a/domain/src/main/java/com/tangem/domain/common/SaltPayWorkaround.kt b/domain/src/main/java/com/tangem/domain/common/SaltPayWorkaround.kt index 39378b30a9..1328643534 100644 --- a/domain/src/main/java/com/tangem/domain/common/SaltPayWorkaround.kt +++ b/domain/src/main/java/com/tangem/domain/common/SaltPayWorkaround.kt @@ -11,7 +11,7 @@ object SaltPayWorkaround { Blockchain.SaltPay -> Token( name = "WXDAI", symbol = "wxDAI", - contractAddress = "0x4346186e7461cB4DF06bCFCB4cD591423022e417", + contractAddress = "0x4200000000000000000000000000000000000006", decimals = 18, id = "wrapped-xdai", )