diff --git a/app/src/main/java/com/tangem/tap/domain/model/TotalFiatBalance.kt b/app/src/main/java/com/tangem/tap/domain/model/TotalFiatBalance.kt index dd9a0b27a1..9fa5b24fd8 100644 --- a/app/src/main/java/com/tangem/tap/domain/model/TotalFiatBalance.kt +++ b/app/src/main/java/com/tangem/tap/domain/model/TotalFiatBalance.kt @@ -6,16 +6,18 @@ import java.math.BigDecimal * Represents fiat balance of [WalletStoreModel] list * @property amount Amount of the total balance * */ -sealed class TotalFiatBalance { - open val amount: BigDecimal = BigDecimal.ZERO +sealed interface TotalFiatBalance { + val amount: BigDecimal? - object Loading : TotalFiatBalance() + object Loading : TotalFiatBalance { + override val amount: BigDecimal? = null + } data class Error( - override val amount: BigDecimal, - ) : TotalFiatBalance() + override val amount: BigDecimal?, + ) : TotalFiatBalance data class Loaded( override val amount: BigDecimal, - ) : TotalFiatBalance() + ) : TotalFiatBalance } \ No newline at end of file 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 b9e83390a0..5f2e67153b 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 @@ -16,6 +16,7 @@ import java.math.BigDecimal * 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 + * @param isCustom shows that currency is a custom * */ data class WalletDataModel( val currency: Currency, @@ -24,6 +25,7 @@ data class WalletDataModel( val existentialDeposit: BigDecimal?, val fiatRate: BigDecimal?, val isCardSingleToken: Boolean, + val isCustom: Boolean, val historyTransactions: List?, ) { @@ -59,9 +61,7 @@ data class WalletDataModel( data class NoAccount( val amountToCreateAccount: BigDecimal?, - ) : Status() { - override val isErrorStatus: Boolean = true - } + ) : Status() data class Unreachable( override val errorMessage: String?, 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 aef5c1ea76..f5d0d3b6fd 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 @@ -2,12 +2,14 @@ package com.tangem.tap.domain.model.builders import com.tangem.blockchain.blockchains.polkadot.ExistentialDepositProvider import com.tangem.blockchain.common.Blockchain +import com.tangem.blockchain.common.DerivationStyle import com.tangem.blockchain.common.Token import com.tangem.blockchain.common.WalletManager import com.tangem.common.hdWallet.DerivationPath -import com.tangem.domain.common.util.UserWalletId +import com.tangem.domain.common.TapWorkarounds.derivationStyle import com.tangem.tap.common.extensions.getBlockchainTxHistory import com.tangem.tap.common.extensions.getTokenTxHistory +import com.tangem.tap.domain.model.UserWallet import com.tangem.tap.domain.model.WalletDataModel import com.tangem.tap.domain.model.WalletStoreModel import com.tangem.tap.domain.tokens.models.BlockchainNetwork @@ -26,23 +28,23 @@ interface WalletStoreBuilder { companion object { operator fun invoke( - userWalletId: UserWalletId, + userWallet: UserWallet, blockchainNetwork: BlockchainNetwork, ): BlockchainNetworkWalletStoreBuilder { - return BlockchainNetworkWalletStoreBuilderImpl(userWalletId, blockchainNetwork) + return BlockchainNetworkWalletStoreBuilderImpl(userWallet, blockchainNetwork) } operator fun invoke( - userWalletId: UserWalletId, + userWallet: UserWallet, walletManager: WalletManager, ): WalletMangerWalletStoreBuilder { - return WalletMangerWalletStoreBuilderImpl(userWalletId, walletManager) + return WalletMangerWalletStoreBuilderImpl(userWallet, walletManager) } } } private class BlockchainNetworkWalletStoreBuilderImpl( - private val userWalletId: UserWalletId, + private val userWallet: UserWallet, private val blockchainNetwork: BlockchainNetwork, ) : WalletStoreBuilder.BlockchainNetworkWalletStoreBuilder { private var walletManager: WalletManager? = null @@ -52,11 +54,12 @@ private class BlockchainNetworkWalletStoreBuilderImpl( } override fun build(): WalletStoreModel { - val blockchainWalletData = blockchainNetwork.getBlockchainWalletData(walletManager) - val tokensWalletsData = blockchainNetwork.getTokensWalletsData(walletManager) + val cardDerivationStyle = userWallet.scanResponse.card.derivationStyle + val blockchainWalletData = blockchainNetwork.getBlockchainWalletData(walletManager, cardDerivationStyle) + val tokensWalletsData = blockchainNetwork.getTokensWalletsData(walletManager, cardDerivationStyle) return WalletStoreModel( - userWalletId = userWalletId, + userWalletId = userWallet.walletId, blockchain = blockchainNetwork.blockchain, derivationPath = blockchainNetwork.derivationPath?.let { DerivationPath(it) }, walletsData = listOf(blockchainWalletData) + tokensWalletsData, @@ -68,7 +71,7 @@ private class BlockchainNetworkWalletStoreBuilderImpl( } private class WalletMangerWalletStoreBuilderImpl( - private val userWalletId: UserWalletId, + private val userWallet: UserWallet, private val walletManager: WalletManager, ) : WalletStoreBuilder.WalletMangerWalletStoreBuilder { @@ -78,7 +81,7 @@ private class WalletMangerWalletStoreBuilderImpl( val tokenWalletsData = wallet.getTokens().firstOrNull()?.toTokenWalletData(walletManager) return WalletStoreModel( - userWalletId = userWalletId, + userWalletId = userWallet.walletId, blockchain = wallet.blockchain, derivationPath = wallet.publicKey.derivationPath, walletsData = listOf(blockchainWalletData) + listOfNotNull(tokenWalletsData), @@ -89,35 +92,45 @@ private class WalletMangerWalletStoreBuilderImpl( } } -private fun BlockchainNetwork.getBlockchainWalletData(walletManager: WalletManager?): WalletDataModel { +private fun BlockchainNetwork.getBlockchainWalletData( + walletManager: WalletManager?, + cardDerivationStyle: DerivationStyle?, +): WalletDataModel { + val currency = Currency.Blockchain( + blockchain = blockchain, + derivationPath = derivationPath, + ) return WalletDataModel( - currency = Currency.Blockchain( - blockchain = blockchain, - derivationPath = derivationPath, - ), + currency = currency, status = WalletDataModel.Loading, walletAddresses = walletManager?.wallet?.createAddressesData().orEmpty(), existentialDeposit = getExistentialDeposit(walletManager), fiatRate = null, isCardSingleToken = false, + isCustom = currency.isCustomCurrency(cardDerivationStyle), historyTransactions = walletManager?.getBlockchainTxHistory(), ) } -private fun BlockchainNetwork.getTokensWalletsData(walletManager: WalletManager?): List { +private fun BlockchainNetwork.getTokensWalletsData( + walletManager: WalletManager?, + cardDerivationStyle: DerivationStyle?, +): List { return this.tokens .map { token -> + val currency = Currency.Token( + token = token, + blockchain = blockchain, + derivationPath = derivationPath, + ) WalletDataModel( - currency = Currency.Token( - token = token, - blockchain = blockchain, - derivationPath = derivationPath, - ), + currency = currency, status = WalletDataModel.Loading, walletAddresses = walletManager?.wallet?.createAddressesData().orEmpty(), existentialDeposit = getExistentialDeposit(walletManager), fiatRate = null, isCardSingleToken = walletManager?.cardTokens?.contains(token) ?: false, + isCustom = currency.isCustomCurrency(cardDerivationStyle), historyTransactions = walletManager?.getTokenTxHistory(token), ) } @@ -135,6 +148,7 @@ private fun Blockchain.toBlockchainWalletData(walletManager: WalletManager): Wal existentialDeposit = getExistentialDeposit(walletManager), fiatRate = null, isCardSingleToken = false, + isCustom = false, historyTransactions = walletManager.getBlockchainTxHistory(), ) } @@ -152,6 +166,7 @@ private fun Token.toTokenWalletData(walletManager: WalletManager): WalletDataMod existentialDeposit = getExistentialDeposit(walletManager), fiatRate = null, isCardSingleToken = walletManager.cardTokens.contains(this), + isCustom = false, historyTransactions = walletManager.getTokenTxHistory(this), ) } 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 b0224afdac..9136094e8b 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 @@ -27,7 +27,9 @@ internal class DefaultTotalFiatBalanceCalculator : TotalFiatBalanceCalculator { when (walletsData.findStatus()) { TotalFiatBalanceStatus.Loading -> TotalFiatBalance.Loading TotalFiatBalanceStatus.Error -> TotalFiatBalance.Error(calculateAmount()) - TotalFiatBalanceStatus.Loaded -> TotalFiatBalance.Loaded(calculateAmount()) + TotalFiatBalanceStatus.Loaded -> TotalFiatBalance.Loaded( + amount = calculateAmount() ?: BigDecimal.ZERO, + ) } } } @@ -47,7 +49,8 @@ internal class DefaultTotalFiatBalanceCalculator : TotalFiatBalanceCalculator { is WalletDataModel.VerifiedOnline, is WalletDataModel.SameCurrencyTransactionInProgress, is WalletDataModel.TransactionInProgress, - is WalletDataModel.NoAccount -> if (walletData.fiatRate == null) { + is WalletDataModel.NoAccount, + -> if (walletData.isCustom || walletData.fiatRate == null) { TotalFiatBalanceStatus.Error } else { TotalFiatBalanceStatus.Loaded @@ -60,14 +63,17 @@ internal class DefaultTotalFiatBalanceCalculator : TotalFiatBalanceCalculator { } } - private fun Sequence.calculateTotalFiatAmount(): BigDecimal { + private fun Sequence.calculateTotalFiatAmount(): BigDecimal? { return this + .filterNot { it.isCustom } .map { walletData -> walletData.fiatRate + ?.takeUnless { walletData.status.isErrorStatus } ?.let { walletData.status.amount.toFiatValue(it) } - ?: BigDecimal.ZERO } - .reduce(BigDecimal::plus) + .reduce { acc, value -> + value?.let { acc?.plus(it) } + } } private fun getCurrentStatus( @@ -88,8 +94,6 @@ internal class DefaultTotalFiatBalanceCalculator : TotalFiatBalanceCalculator { } private enum class TotalFiatBalanceStatus { - Loading, - Error, - Loaded, + Loading, Error, Loaded, } } \ No newline at end of file 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 aff78739f8..2c74eba8ba 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 @@ -175,7 +175,7 @@ internal class DefaultWalletCurrenciesManager( .flatMap { walletManager -> walletStoresRepository.storeOrUpdate( userWalletId = userWalletId, - walletStore = WalletStoreBuilder(userWalletId, blockchainNetwork) + walletStore = WalletStoreBuilder(userWallet, blockchainNetwork) .walletManager(walletManager) .build(), ) diff --git a/app/src/main/java/com/tangem/tap/domain/walletStores/implementation/DefaultWalletStoresManager.kt b/app/src/main/java/com/tangem/tap/domain/walletStores/implementation/DefaultWalletStoresManager.kt index 58ee4e72e0..06b2f358ae 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletStores/implementation/DefaultWalletStoresManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletStores/implementation/DefaultWalletStoresManager.kt @@ -137,7 +137,7 @@ internal class DefaultWalletStoresManager( { walletManager -> walletStoresRepository.storeOrUpdate( userWalletId = userWalletId, - walletStore = WalletStoreBuilder(userWalletId, blockchainNetwork) + walletStore = WalletStoreBuilder(userWallet, blockchainNetwork) .walletManager(walletManager) .build(), ) @@ -171,7 +171,7 @@ internal class DefaultWalletStoresManager( val userWalletId = userWallet.walletId walletStoresRepository.storeOrUpdate( userWalletId = userWalletId, - walletStore = WalletStoreBuilder(userWalletId, walletManager) + walletStore = WalletStoreBuilder(userWallet, walletManager) .build(), ) } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/models/TotalBalance.kt b/app/src/main/java/com/tangem/tap/features/wallet/models/TotalBalance.kt index 5d63e8b816..a57bf4e6da 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/models/TotalBalance.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/models/TotalBalance.kt @@ -6,6 +6,6 @@ import java.math.BigDecimal data class TotalBalance( val state: ProgressState, - val fiatAmount: BigDecimal, + val fiatAmount: BigDecimal?, val fiatCurrency: FiatCurrency, ) \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/view/TotalBalanceCard.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/view/TotalBalanceCard.kt index 5a39cf2b28..f17f324571 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/view/TotalBalanceCard.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/view/TotalBalanceCard.kt @@ -37,6 +37,7 @@ import com.tangem.tap.common.entities.FiatCurrency import com.tangem.tap.common.extensions.formatWithSpaces import com.tangem.tap.features.wallet.models.TotalBalance import com.tangem.tap.features.wallet.redux.ProgressState +import com.tangem.tap.features.wallet.redux.WalletState.Companion.UNKNOWN_AMOUNT_SIGN import com.tangem.wallet.R import com.valentinilk.shimmer.shimmer import java.math.BigDecimal @@ -91,7 +92,7 @@ internal class TotalBalanceCard @JvmOverloads constructor( ProgressState.Refreshing, ProgressState.Done, -> TotalBalanceCardState.Success( - amount = status.fiatAmount, + amount = status.fiatAmount ?: BigDecimal.ZERO, fiatCurrency = status.fiatCurrency, onChangeFiatCurrencyClick = onChangeCurrencyClick, ) @@ -232,9 +233,11 @@ private fun LoadedAmount( @Composable private fun buildAmountString( - amount: BigDecimal, + amount: BigDecimal?, fiatCurrencySymbol: String, ): AnnotatedString { + if (amount == null) return AnnotatedString(text = UNKNOWN_AMOUNT_SIGN) + val format = DecimalFormat.getInstance(Locale.getDefault()) as DecimalFormat val scaledAmount = amount .setScale(2, RoundingMode.HALF_UP) @@ -255,12 +258,12 @@ private fun buildAmountString( } private sealed interface TotalBalanceCardState { - val amount: BigDecimal + val amount: BigDecimal? val onChangeFiatCurrencyClick: () -> Unit val fiatCurrency: FiatCurrency object Empty : TotalBalanceCardState { - override val amount: BigDecimal = BigDecimal.ZERO + override val amount: BigDecimal? = null override val fiatCurrency: FiatCurrency = FiatCurrency.Default override val onChangeFiatCurrencyClick: () -> Unit = { /* no-op */ } } @@ -273,7 +276,7 @@ private sealed interface TotalBalanceCardState { } data class Failure( - override val amount: BigDecimal, + override val amount: BigDecimal?, override val fiatCurrency: FiatCurrency, override val onChangeFiatCurrencyClick: () -> Unit, ) : TotalBalanceCardState 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 626857097f..d22d12d85c 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 @@ -3,23 +3,24 @@ package com.tangem.tap.features.walletSelector.ui import com.tangem.tap.common.entities.FiatCurrency import com.tangem.tap.common.extensions.toFormattedFiatValue import com.tangem.tap.domain.model.TotalFiatBalance +import com.tangem.tap.features.wallet.redux.WalletState.Companion.UNKNOWN_AMOUNT_SIGN import com.tangem.tap.features.walletSelector.redux.UserWalletModel 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 List.toUiModels( appCurrency: FiatCurrency, ): Sequence { return this.asSequence().map { userWalletModel -> with(userWalletModel) { - 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.Error -> UserWalletItem.Balance.Error( + amount = fiatBalance.amount?.toFormattedFiatValue(appCurrency.symbol) ?: UNKNOWN_AMOUNT_SIGN, + ) + is TotalFiatBalance.Loaded -> UserWalletItem.Balance.Loaded( + amount = fiatBalance.amount.toFormattedFiatValue(appCurrency.symbol), + ) is TotalFiatBalance.Loading -> UserWalletItem.Balance.Loading } when (type) {