diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetTokenListUseCase.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetTokenListUseCase.kt index f27dadfec9..59125a081c 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetTokenListUseCase.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetTokenListUseCase.kt @@ -14,10 +14,7 @@ import com.tangem.domain.tokens.repository.QuotesRepository import com.tangem.domain.wallets.models.UserWalletId import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.flatMapMerge -import kotlinx.coroutines.flow.flowOf -import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.* class GetTokenListUseCase( internal val currenciesRepository: CurrenciesRepository, @@ -27,8 +24,8 @@ class GetTokenListUseCase( ) { @OptIn(ExperimentalCoroutinesApi::class) - operator fun invoke(userWalletId: UserWalletId, refresh: Boolean = true): Flow> { - return getTokensStatuses(userWalletId, refresh).flatMapMerge flatMap@{ maybeTokens -> + operator fun invoke(userWalletId: UserWalletId, refresh: Boolean = false): Flow> { + return getTokensStatuses(userWalletId, refresh).flatMapMerge { maybeTokens -> maybeTokens.fold( ifLeft = { error -> flowOf(error.left()) diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/model/CryptoCurrencyStatus.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/model/CryptoCurrencyStatus.kt index 443ccfeca6..1f2db6777f 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/model/CryptoCurrencyStatus.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/model/CryptoCurrencyStatus.kt @@ -86,4 +86,15 @@ data class CryptoCurrencyStatus( override val priceChange: BigDecimal?, override val hasTransactionsInProgress: Boolean, ) : Status() + + /** + * Represents a state where the token is available, but there is no current quote available for it. + * + * @property amount The amount of the token. + * @property hasTransactionsInProgress Indicates if there are any transactions in progress related to the token. + */ + data class NoQuote( + override val amount: BigDecimal, + override val hasTransactionsInProgress: Boolean, + ) : Status() } \ No newline at end of file diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CurrenciesStatusesOperations.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CurrenciesStatusesOperations.kt index 555b0fab08..463205a41c 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CurrenciesStatusesOperations.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CurrenciesStatusesOperations.kt @@ -3,7 +3,8 @@ package com.tangem.domain.tokens.operations import arrow.core.* import arrow.core.raise.* import com.tangem.domain.tokens.GetTokenListUseCase -import com.tangem.domain.tokens.model.* +import com.tangem.domain.tokens.model.CryptoCurrencyStatus +import com.tangem.domain.tokens.model.NetworkStatus import com.tangem.domain.tokens.models.CryptoCurrency import com.tangem.domain.tokens.models.Network import com.tangem.domain.tokens.models.Quote @@ -36,25 +37,41 @@ internal class CurrenciesStatusesOperations( @OptIn(ExperimentalCoroutinesApi::class) fun getCurrenciesStatusesFlow(): Flow>> { - return getMultiCurrencyWalletCurrencies().flatMapMerge flatMap@{ maybeCurrencies -> + return getMultiCurrencyWalletCurrencies().transformLatest { maybeCurrencies -> val nonEmptyCurrencies = maybeCurrencies.fold( ifLeft = { error -> - return@flatMap flowOf(error.left()) + emit(error.left()) + return@transformLatest }, - ifRight = { it.toNonEmptyListOrNull() }, - ) ?: return@flatMap flowOf(emptyList().right()) + ifRight = List::toNonEmptyListOrNull, + ) + + if (nonEmptyCurrencies == null) { + val emptyCurrenciesStatuses = emptyList() + + emit(emptyCurrenciesStatuses.right()) + return@transformLatest + } else if (!refresh) { + val maybeLoadingCurrenciesStatuses = createCurrenciesStatuses( + currencies = nonEmptyCurrencies, + maybeNetworkStatuses = null, + maybeQuotes = null, + ) + + emit(maybeLoadingCurrenciesStatuses) + } val (networksIds, currenciesIds) = getIds(nonEmptyCurrencies) - combine( + val currenciesFlow = combine( getQuotes(currenciesIds), getNetworksStatuses(networksIds), ) { maybeQuotes, maybeNetworksStatuses -> - either { - createCurrenciesStatuses(nonEmptyCurrencies, maybeQuotes.bind(), maybeNetworksStatuses.bind()) - } + createCurrenciesStatuses(nonEmptyCurrencies, maybeQuotes, maybeNetworksStatuses) } - } + + emitAll(currenciesFlow) + }.conflate() } suspend fun getCurrencyStatusFlow(currencyId: CryptoCurrency.ID): Flow> { @@ -76,14 +93,16 @@ internal class CurrenciesStatusesOperations( } private fun getCurrencyStatusFlow(currency: CryptoCurrency): Flow> { - val quoteFlow = getQuotes(nonEmptySetOf(currency.id)) + val (networksIds, currenciesIds) = getIds(nonEmptyListOf(currency)) + + val quoteFlow = getQuotes(currenciesIds) .map { maybeQuotes -> maybeQuotes.map { quotes -> quotes.singleOrNull { it.rawCurrencyId == currency.id.rawCurrencyId } } } - val statusFlow = getNetworksStatuses(nonEmptySetOf(currency.networkId)) + val statusFlow = getNetworksStatuses(networksIds) .map { maybeStatuses -> maybeStatuses.map { statuses -> statuses.singleOrNull { it.networkId == currency.networkId } @@ -91,34 +110,58 @@ internal class CurrenciesStatusesOperations( } return combine(quoteFlow, statusFlow) { maybeQuote, maybeNetworkStatus -> - either { - createStatus(currency, maybeQuote.bind(), maybeNetworkStatus.bind()) - } + createStatus(currency, maybeQuote, maybeNetworkStatus) } } private fun createCurrenciesStatuses( currencies: NonEmptyList, - quotes: Set, - networkStatuses: Set, - ): List { - return currencies.map { currency -> - val quote = quotes.firstOrNull { it.rawCurrencyId == currency.id.rawCurrencyId } - val networkStatus = networkStatuses.firstOrNull { it.networkId == currency.networkId } + maybeQuotes: Either>?, + maybeNetworkStatuses: Either>?, + ): Either> = either { + var quotesRetrievingFailed = false - createStatus(currency, quote, networkStatus) + val networksStatuses = maybeNetworkStatuses?.bind()?.toNonEmptySetOrNull() + val quotes = recover({ maybeQuotes?.bind()?.toNonEmptySetOrNull() }) { + quotesRetrievingFailed = true + null + } + + currencies.map { currency -> + val quote = quotes?.firstOrNull { it.rawCurrencyId == currency.id.rawCurrencyId } + val networkStatus = networksStatuses?.firstOrNull { it.networkId == currency.networkId } + + createStatus(currency, quote, networkStatus, ignoreQuote = quotesRetrievingFailed) } } private fun createStatus( - token: CryptoCurrency, + currency: CryptoCurrency, + maybeQuote: Either, + maybeNetworkStatus: Either, + ): Either = either { + var quoteRetrievingFailed = false + + val networkStatus = maybeNetworkStatus.bind() + val quote = recover({ maybeQuote.bind() }) { + quoteRetrievingFailed = true + null + } + + createStatus(currency, quote, networkStatus, ignoreQuote = quoteRetrievingFailed) + } + + private fun createStatus( + currency: CryptoCurrency, quote: Quote?, networkStatus: NetworkStatus?, + ignoreQuote: Boolean, ): CryptoCurrencyStatus { val currencyStatusOperations = CurrencyStatusOperations( - currency = token, + currency = currency, quote = quote, networkStatus = networkStatus, + ignoreQuote = ignoreQuote, ) return currencyStatusOperations.createTokenStatus() diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CurrencyStatusOperations.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CurrencyStatusOperations.kt index 8653aae3e5..b37f324c1f 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CurrencyStatusOperations.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/CurrencyStatusOperations.kt @@ -10,6 +10,7 @@ internal class CurrencyStatusOperations( private val currency: CryptoCurrency, private val quote: Quote?, private val networkStatus: NetworkStatus?, + private val ignoreQuote: Boolean, ) { fun createTokenStatus(): CryptoCurrencyStatus = CryptoCurrencyStatus(currency, createStatus()) @@ -28,6 +29,10 @@ internal class CurrencyStatusOperations( val amount = status.amounts[currency.id] ?: return CryptoCurrencyStatus.Unreachable return when { + ignoreQuote -> CryptoCurrencyStatus.NoQuote( + amount = amount, + hasTransactionsInProgress = status.hasTransactionsInProgress, + ) currency is CryptoCurrency.Token && currency.isCustom -> CryptoCurrencyStatus.Custom( amount = amount, fiatAmount = calculateFiatAmountOrNull(amount, quote?.fiatRate), diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/TokenListFiatBalanceOperations.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/TokenListFiatBalanceOperations.kt index 830950ae1e..ec63a9fa0c 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/TokenListFiatBalanceOperations.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/TokenListFiatBalanceOperations.kt @@ -27,7 +27,7 @@ internal class TokenListFiatBalanceOperations( break } is CryptoCurrencyStatus.NoAccount -> { - fiatBalance = recalculateBalanceForNoAccountStatus(fiatBalance) + fiatBalance = recalculateBalanceWithoutQuote(fiatBalance) } is CryptoCurrencyStatus.Loaded -> { fiatBalance = recalculateBalance(status, fiatBalance) @@ -35,13 +35,16 @@ internal class TokenListFiatBalanceOperations( is CryptoCurrencyStatus.Custom -> { fiatBalance = recalculateBalance(status, fiatBalance) } + is CryptoCurrencyStatus.NoQuote -> { + fiatBalance = recalculateBalanceWithoutQuote(fiatBalance) + } } } return fiatBalance } - private fun recalculateBalanceForNoAccountStatus(currentBalance: TokenList.FiatBalance): TokenList.FiatBalance { + private fun recalculateBalanceWithoutQuote(currentBalance: TokenList.FiatBalance): TokenList.FiatBalance { return with(currentBalance) { (this as? TokenList.FiatBalance.Loaded)?.copy( isAllAmountsSummarized = false, diff --git a/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/GetPrimaryCurrencyUseCaseTest.kt b/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/GetPrimaryCurrencyUseCaseTest.kt index 707e9e90ef..3d5b25e5eb 100644 --- a/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/GetPrimaryCurrencyUseCaseTest.kt +++ b/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/GetPrimaryCurrencyUseCaseTest.kt @@ -59,9 +59,9 @@ internal class GetPrimaryCurrencyUseCaseTest { } @Test - fun `when quotes getting failed then error should be received`() = runTest { + fun `when quotes getting failed then currency with no quote status should be received`() = runTest { // Given - val expectedResult = CurrencyError.DataError(DataError.NetworkError.NoInternetConnection).left() + val expectedResult = MockTokensStates.noQuotesTokensStatuses.first().right() val useCase = getUseCase(quotes = flowOf(DataError.NetworkError.NoInternetConnection.left())) @@ -100,8 +100,8 @@ internal class GetPrimaryCurrencyUseCaseTest { } @Test - fun `when quotes flow is empty then error should be received`() = runTest { - val expectedResult = CurrencyError.UnableToCreateCurrency.left() + fun `when quotes flow is empty then no quote status should be received`() = runTest { + val expectedResult = MockTokensStates.noQuotesTokensStatuses.first().right() val useCase = getUseCase(quotes = flowOf()) diff --git a/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/GetTokenListUseCaseTest.kt b/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/GetTokenListUseCaseTest.kt index 00d7db54b3..8b9eebf8a8 100644 --- a/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/GetTokenListUseCaseTest.kt +++ b/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/GetTokenListUseCaseTest.kt @@ -10,6 +10,7 @@ import com.tangem.domain.tokens.mock.MockQuotes import com.tangem.domain.tokens.mock.MockTokenLists import com.tangem.domain.tokens.mock.MockTokens import com.tangem.domain.tokens.model.NetworkStatus +import com.tangem.domain.tokens.model.TokenList import com.tangem.domain.tokens.models.CryptoCurrency import com.tangem.domain.tokens.models.Network import com.tangem.domain.tokens.models.Quote @@ -32,7 +33,10 @@ internal class GetTokenListUseCaseTest { @Test fun `when list ungrouped and unsorted then correct token list should be returned`() = runTest { // Given - val expectedResult = MockTokenLists.failedUngroupedTokenList.right() + val expectedResult = listOf( + MockTokenLists.loadingUngroupedTokenList.right(), + MockTokenLists.failedUngroupedTokenList.right(), + ) val useCase = getUseCase( isGrouped = flowOf(false.right()), @@ -40,7 +44,30 @@ internal class GetTokenListUseCaseTest { ) // When - val result = useCase(userWalletId).first() + val result = useCase(userWalletId) + .take(count = 2) + .toList() + + // Then + assertEquals(expectedResult, result) + } + + @Test + fun `when list refreshed then correct token list should be returned`() = runTest { + // Given + val expectedResult = listOf( + MockTokenLists.failedUngroupedTokenList.right(), + ) + + val useCase = getUseCase( + isGrouped = flowOf(false.right()), + isSortedByBalance = flowOf(false.right()), + ) + + // When + val result = useCase(userWalletId, refresh = true) + .take(count = 1) + .toList() // Then assertEquals(expectedResult, result) @@ -61,14 +88,22 @@ internal class GetTokenListUseCaseTest { } @Test - fun `when quotes getting failed then error should be received`() = runTest { + fun `when quotes getting failed then token list without quotes should be received`() = runTest { // Given - val expectedResult = TokenListError.DataError(DataError.NetworkError.NoInternetConnection).left() + val expectedResult = listOf( + MockTokenLists.loadingUngroupedTokenList.right(), + MockTokenLists.noQuotesUngroupedTokenList.right(), + ) - val useCase = getUseCase(quotes = flowOf(DataError.NetworkError.NoInternetConnection.left())) + val useCase = getUseCase( + quotes = flowOf(DataError.NetworkError.NoInternetConnection.left()), + statuses = flowOf(MockNetworks.verifiedNetworksStatuses.right()), + ) // When - val result = useCase(userWalletId).first() + val result = useCase(userWalletId) + .take(count = 2) + .toList() // Then assertEquals(expectedResult, result) @@ -99,7 +134,7 @@ internal class GetTokenListUseCaseTest { val useCase = getUseCase(statuses = flowOf(DataError.NetworkError.NoInternetConnection.left())) // When - val result = useCase(userWalletId).first() + val result = useCase(userWalletId, refresh = true).first() // Then assertEquals(expectedResult, result) @@ -138,6 +173,7 @@ internal class GetTokenListUseCaseTest { // Given val error = DataError.NetworkError.NoInternetConnection.left() val expectedResult = listOf( + MockTokenLists.loadingUngroupedTokenList.right(), MockTokenLists.failedUngroupedTokenList.right(), TokenListError.DataError(DataError.NetworkError.NoInternetConnection).left(), ) @@ -151,7 +187,7 @@ internal class GetTokenListUseCaseTest { // When val result = useCase(userWalletId) - .take(count = 2) + .take(count = 3) .toList() // Then @@ -160,12 +196,17 @@ internal class GetTokenListUseCaseTest { @Test fun `when list grouped then correct token list should be received`() = runTest { - val expectedResult = MockTokenLists.failedGroupedTokenList.right() + val expectedResult = listOf( + MockTokenLists.loadingGroupedTokenList.right(), + MockTokenLists.failedGroupedTokenList.right(), + ) val useCase = getUseCase(isGrouped = flowOf(true.right())) // When - val result = useCase(userWalletId).first() + val result = useCase(userWalletId) + .take(count = 2) + .toList() // Then assertEquals(expectedResult, result) @@ -189,7 +230,10 @@ internal class GetTokenListUseCaseTest { @Test fun `when list is sorted and ungrouped then correct token list should be received`() = runTest { - val expectedResult = MockTokenLists.sortedUngroupedTokenList.right() + val expectedResult = listOf( + MockTokenLists.loadingUngroupedTokenList.copy(sortedBy = TokenList.SortType.BALANCE).right(), + MockTokenLists.sortedUngroupedTokenList.right(), + ) val useCase = getUseCase( statuses = flowOf(MockNetworks.verifiedNetworksStatuses.right()), @@ -198,7 +242,9 @@ internal class GetTokenListUseCaseTest { ) // When - val result = useCase(userWalletId).first() + val result = useCase(userWalletId) + .take(count = 2) + .toList() // Then assertEquals(expectedResult, result) @@ -206,7 +252,10 @@ internal class GetTokenListUseCaseTest { @Test fun `when list is sorted and grouped then correct token list should be received`() = runTest { - val expectedResult = MockTokenLists.sortedGroupedTokenList.right() + val expectedResult = listOf( + MockTokenLists.loadingGroupedTokenList.copy(sortedBy = TokenList.SortType.BALANCE).right(), + MockTokenLists.sortedGroupedTokenList.right(), + ) val useCase = getUseCase( statuses = flowOf(MockNetworks.verifiedNetworksStatuses.right()), @@ -215,7 +264,9 @@ internal class GetTokenListUseCaseTest { ) // When - val result = useCase(userWalletId).first() + val result = useCase(userWalletId) + .take(count = 2) + .toList() // Then assertEquals(expectedResult, result) @@ -236,7 +287,10 @@ internal class GetTokenListUseCaseTest { @Test fun `when networks is empty and list is grouped then ungrouped list should be received`() = runTest { - val expectedResult = TokenListError.UnableToSortTokenList(MockTokenLists.failedUngroupedTokenList).left() + val expectedResult = listOf( + TokenListError.UnableToSortTokenList(MockTokenLists.loadingUngroupedTokenList).left(), + TokenListError.UnableToSortTokenList(MockTokenLists.failedUngroupedTokenList).left(), + ) val useCase = getUseCase( networks = emptySet().right(), @@ -244,7 +298,9 @@ internal class GetTokenListUseCaseTest { ) // When - val result = useCase(userWalletId).first() + val result = useCase(userWalletId) + .take(count = 2) + .toList() // Then assertEquals(expectedResult, result) @@ -265,12 +321,17 @@ internal class GetTokenListUseCaseTest { @Test fun `when networks statuses flow is empty then error should be received`() = runTest { - val expectedResult = TokenListError.EmptyTokens.left() + val expectedResult = listOf( + MockTokenLists.loadingUngroupedTokenList.right(), + TokenListError.EmptyTokens.left(), + ) val useCase = getUseCase(statuses = flowOf()) // When - val result = useCase(userWalletId).first() + val result = useCase(userWalletId) + .take(count = 2) + .toList() // Then assertEquals(expectedResult, result) @@ -290,13 +351,21 @@ internal class GetTokenListUseCaseTest { } @Test - fun `when quotes flow is empty then error should be received`() = runTest { - val expectedResult = TokenListError.EmptyTokens.left() + fun `when quotes flow is empty then list without quotes should be received`() = runTest { + val expectedResult = listOf( + MockTokenLists.loadingUngroupedTokenList.right(), + MockTokenLists.noQuotesUngroupedTokenList.right(), + ) - val useCase = getUseCase(quotes = flowOf()) + val useCase = getUseCase( + statuses = flowOf(MockNetworks.verifiedNetworksStatuses.right()), + quotes = flowOf(), + ) // When - val result = useCase(userWalletId).first() + val result = useCase(userWalletId) + .take(count = 2) + .toList() // Then assertEquals(expectedResult, result) diff --git a/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/mock/MockTokenLists.kt b/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/mock/MockTokenLists.kt index de1f837afd..cbfd65a56f 100644 --- a/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/mock/MockTokenLists.kt +++ b/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/mock/MockTokenLists.kt @@ -41,9 +41,14 @@ internal object MockTokenLists { sortedBy = TokenList.SortType.NONE, ) + val noQuotesUngroupedTokenList = failedUngroupedTokenList.copy( + totalFiatBalance = TokenList.FiatBalance.Loaded(amount = BigDecimal.ZERO, isAllAmountsSummarized = false), + currencies = MockTokensStates.noQuotesTokensStatuses, + ) + val loadingUngroupedTokenList = with(failedUngroupedTokenList) { copy( - currencies = currencies.map { it.copy(value = CryptoCurrencyStatus.Loading) }.toNonEmptyListOrNull()!!, + currencies = currencies.map { it.copy(value = CryptoCurrencyStatus.Loading) }, totalFiatBalance = TokenList.FiatBalance.Loading, ) } @@ -54,8 +59,7 @@ internal object MockTokenLists { groups = groups.map { group -> group.copy( currencies = group.currencies - .map { it.copy(value = CryptoCurrencyStatus.Loading) } - .toNonEmptyListOrNull()!!, + .map { it.copy(value = CryptoCurrencyStatus.Loading) }, ) }.toNonEmptyListOrNull()!!, ) @@ -95,7 +99,6 @@ internal object MockTokenLists { get() { val tokens = MockTokensStates.loadedTokensStates .sortedByDescending { it.value.fiatAmount } - .toNonEmptyListOrNull()!! return unsortedUngroupedTokenList.copy( currencies = tokens, diff --git a/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/mock/MockTokensStates.kt b/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/mock/MockTokensStates.kt index 4dd2d81154..ee6b0a6a1e 100644 --- a/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/mock/MockTokensStates.kt +++ b/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/mock/MockTokensStates.kt @@ -87,4 +87,13 @@ internal object MockTokensStates { ), ) } + + val noQuotesTokensStatuses = loadedTokensStates.map { currency -> + currency.copy( + value = CryptoCurrencyStatus.NoQuote( + amount = currency.value.amount!!, + hasTransactionsInProgress = false, + ), + ) + } } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/factory/WalletSingleCurrencyLoadedBalanceConverter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/factory/WalletSingleCurrencyLoadedBalanceConverter.kt index 143c38fdb4..6abcf3e185 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/factory/WalletSingleCurrencyLoadedBalanceConverter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/factory/WalletSingleCurrencyLoadedBalanceConverter.kt @@ -43,23 +43,14 @@ internal class WalletSingleCurrencyLoadedBalanceConverter( private fun getMarketPriceState(status: CryptoCurrencyStatus.Status, currencyName: String): MarketPriceBlockState { return when (status) { - is CryptoCurrencyStatus.Loaded -> MarketPriceBlockState.Content( + is CryptoCurrencyStatus.NoQuote, + is CryptoCurrencyStatus.Loaded, + -> MarketPriceBlockState.Content( currencyName = currencyName, - price = BigDecimalFormatter.formatFiatAmount( - fiatAmount = status.fiatRate, - fiatCurrencyCode = fiatCurrencyCode, - fiatCurrencySymbol = fiatCurrencySymbol, - ), + price = formatPrice(status), priceChangeConfig = PriceChangeConfig( - valueInPercent = BigDecimalFormatter.formatPercent( - percent = status.priceChange, - useAbsoluteValue = true, - ), - type = if (status.priceChange > BigDecimal.ZERO) { - PriceChangeConfig.Type.UP - } else { - PriceChangeConfig.Type.DOWN - }, + valueInPercent = formatPriceChange(status), + type = getPriceChangeType(status), ), ) is CryptoCurrencyStatus.Loading -> MarketPriceBlockState.Loading(currencyName) @@ -77,7 +68,9 @@ internal class WalletSingleCurrencyLoadedBalanceConverter( ): WalletsListConfig { val selectedWallet = state.walletsListConfig.wallets[state.walletsListConfig.selectedWalletIndex] val updatedWallet = when (status) { - is CryptoCurrencyStatus.Loaded -> { + is CryptoCurrencyStatus.NoQuote, + is CryptoCurrencyStatus.Loaded, + -> { WalletCardState.Content( id = selectedWallet.id, title = selectedWallet.title, @@ -88,11 +81,7 @@ internal class WalletSingleCurrencyLoadedBalanceConverter( ), imageResId = selectedWallet.imageResId, onClick = selectedWallet.onClick, - balance = BigDecimalFormatter.formatFiatAmount( - fiatAmount = status.fiatAmount, - fiatCurrencyCode = fiatCurrencyCode, - fiatCurrencySymbol = fiatCurrencySymbol, - ), + balance = formatFiatAmount(status), ) } is CryptoCurrencyStatus.Loading -> { @@ -124,4 +113,43 @@ internal class WalletSingleCurrencyLoadedBalanceConverter( .set(index = state.walletsListConfig.selectedWalletIndex, element = updatedWallet), ) } + + private fun getPriceChangeType(status: CryptoCurrencyStatus.Status): PriceChangeConfig.Type { + val priceChange = status.priceChange ?: return PriceChangeConfig.Type.DOWN + + return if (priceChange > BigDecimal.ZERO) { + PriceChangeConfig.Type.UP + } else { + PriceChangeConfig.Type.DOWN + } + } + + private fun formatPriceChange(status: CryptoCurrencyStatus.Status): String { + val priceChange = status.priceChange ?: return BigDecimalFormatter.EMPTY_BALANCE_SIGN + + return BigDecimalFormatter.formatPercent( + percent = priceChange, + useAbsoluteValue = true, + ) + } + + private fun formatPrice(status: CryptoCurrencyStatus.Status): String { + val fiatRate = status.fiatRate ?: return BigDecimalFormatter.EMPTY_BALANCE_SIGN + + return BigDecimalFormatter.formatFiatAmount( + fiatAmount = fiatRate, + fiatCurrencyCode = fiatCurrencyCode, + fiatCurrencySymbol = fiatCurrencySymbol, + ) + } + + private fun formatFiatAmount(status: CryptoCurrencyStatus.Status): String { + val fiatAmount = status.fiatAmount ?: return BigDecimalFormatter.EMPTY_BALANCE_SIGN + + return BigDecimalFormatter.formatFiatAmount( + fiatAmount = fiatAmount, + fiatCurrencyCode = fiatCurrencyCode, + fiatCurrencySymbol = fiatCurrencySymbol, + ) + } } \ No newline at end of file diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/utils/CryptoCurrencyStatusToTokenItemConverter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/utils/CryptoCurrencyStatusToTokenItemConverter.kt index a3b84ee0b5..76a4c01582 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/utils/CryptoCurrencyStatusToTokenItemConverter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/utils/CryptoCurrencyStatusToTokenItemConverter.kt @@ -33,6 +33,7 @@ internal class CryptoCurrencyStatusToTokenItemConverter( is CryptoCurrencyStatus.Loading -> TokenItemState.Loading is CryptoCurrencyStatus.Loaded, is CryptoCurrencyStatus.Custom, + is CryptoCurrencyStatus.NoQuote, -> value.mapToTokenItemState() // TODO: Add other token item states, currently not designed is CryptoCurrencyStatus.MissedDerivation,