Updated on 2026-08-14

This commit is contained in:
Tangem 2026-03-27 08:24:24 +05:00
parent 9ee1319e40
commit c6b2e89890
20 changed files with 142 additions and 4 deletions

View file

@ -27,6 +27,7 @@ internal class QuoteStatusConverter(
source = source,
fiatRate = quote.price.orZero(),
priceChange = quote.priceChange24h.orZero().movePointLeft(2),
fiatRateUSD = quote.priceUsd.orZero(),
),
)
}

View file

@ -14,10 +14,11 @@ import com.tangem.datasource.di.NetworkMoshi
import com.tangem.datasource.local.datastore.RuntimeSharedStore
import com.tangem.datasource.utils.MoshiDataStoreSerializer
import com.tangem.datasource.utils.mapWithStringKeyTypes
import com.tangem.utils.coroutines.AppCoroutineScope
import com.tangem.domain.quotes.GetCurrencyUSDQuoteUseCase
import com.tangem.domain.quotes.QuotesRepository
import com.tangem.domain.quotes.multi.MultiQuoteStatusFetcher
import com.tangem.domain.quotes.multi.MultiQuoteUpdater
import com.tangem.utils.coroutines.AppCoroutineScope
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
@ -72,4 +73,10 @@ internal object QuotesDataModule {
coroutineScope = coroutineScope,
)
}
@Singleton
@Provides
fun provideGetCurrencyUSDQuoteUseCase(quotesRepository: QuotesRepository): GetCurrencyUSDQuoteUseCase {
return GetCurrencyUSDQuoteUseCase(quotesRepository)
}
}

View file

@ -55,7 +55,7 @@ internal class DefaultMultiQuoteStatusFetcher @Inject constructor(
val response = quotesFetcher.fetch(
fiatCurrencyId = appCurrencyId,
currenciesIds = replacementIdsResult.idsForRequest,
fields = setOf(Field.PRICE, Field.PRICE_CHANGE_24H),
fields = setOf(Field.PRICE, Field.PRICE_CHANGE_24H, Field.PRICE_USD),
)
.getOrElse { error("Cause: $it") }

View file

@ -31,4 +31,8 @@ internal class DefaultQuotesRepository(
?: QuoteStatus(rawCurrencyId = currencyId)
}
}
override suspend fun getCurrencyUSDQuote(currencyId: CryptoCurrency.RawID): QuoteStatus? {
return getMultiQuoteSyncOrNull(currenciesIds = setOf(currencyId)).firstOrNull()
}
}

View file

@ -55,6 +55,7 @@ internal class QuoteStatusConverterTest {
priceChange24h = null,
priceChange1w = null,
priceChange30d = null,
priceUsd = null,
),
),
expected = QuoteStatus(
@ -62,6 +63,7 @@ internal class QuoteStatusConverterTest {
value = QuoteStatus.Data(
source = StatusSource.ACTUAL,
fiatRate = BigDecimal.ZERO,
fiatRateUSD = BigDecimal.ZERO,
priceChange = BigDecimal("0.00"),
),
),
@ -74,6 +76,7 @@ internal class QuoteStatusConverterTest {
priceChange24h = null,
priceChange1w = BigDecimal.ZERO,
priceChange30d = BigDecimal.ZERO,
priceUsd = null,
),
),
expected = QuoteStatus(
@ -81,6 +84,7 @@ internal class QuoteStatusConverterTest {
value = QuoteStatus.Data(
source = StatusSource.ACTUAL,
fiatRate = BigDecimal.ZERO,
fiatRateUSD = BigDecimal.ZERO,
priceChange = BigDecimal("0.00"),
),
),
@ -93,6 +97,7 @@ internal class QuoteStatusConverterTest {
priceChange24h = BigDecimal.ONE,
priceChange1w = null,
priceChange30d = null,
priceUsd = BigDecimal.ONE
),
),
expected = QuoteStatus(
@ -100,6 +105,7 @@ internal class QuoteStatusConverterTest {
value = QuoteStatus.Data(
source = StatusSource.ACTUAL,
fiatRate = BigDecimal.ONE,
fiatRateUSD = BigDecimal.ONE,
priceChange = BigDecimal("0.01"),
),
),

View file

@ -240,6 +240,6 @@ internal class DefaultMultiQuoteStatusFetcherTest {
),
)
val fields = setOf(QuotesFetcher.Field.PRICE, QuotesFetcher.Field.PRICE_CHANGE_24H)
val fields = setOf(QuotesFetcher.Field.PRICE, QuotesFetcher.Field.PRICE_CHANGE_24H, QuotesFetcher.Field.PRICE_USD)
}
}

View file

@ -43,6 +43,7 @@ internal class DefaultQuotesRepositoryTest {
value = QuoteStatus.Data(
source = StatusSource.ACTUAL,
fiatRate = BigDecimal.ZERO,
fiatRateUSD = BigDecimal.ZERO,
priceChange = BigDecimal.ZERO,
),
)
@ -100,9 +101,75 @@ internal class DefaultQuotesRepositoryTest {
)
}
@Nested
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
inner class GetCurrencyUSDQuote {
private val btcRawId = CryptoCurrency.RawID(value = "BTC")
private val ethRawId = CryptoCurrency.RawID(value = "ETH")
private val ethQuote = QuoteStatus(
rawCurrencyId = ethRawId,
value = QuoteStatus.Data(
source = StatusSource.ACTUAL,
fiatRate = BigDecimal.ZERO,
fiatRateUSD = BigDecimal.ZERO,
priceChange = BigDecimal.ZERO,
),
)
@ParameterizedTest
@ProvideTestModels
fun getCurrencyUSDQuote(model: GetCurrencyUSDQuoteModel) = runTest {
// Arrange
coEvery { quotesStatusesStore.getAllSyncOrNull() } returns model.initialStore
// Act
val actual = repository.getCurrencyUSDQuote(currencyId = model.currencyId)
// Assert
val expected = model.expected
Truth.assertThat(actual).isEqualTo(expected)
}
private fun provideTestModels() = listOf(
GetCurrencyUSDQuoteModel(
initialStore = null,
currencyId = ethRawId,
expected = QuoteStatus(rawCurrencyId = ethRawId),
),
GetCurrencyUSDQuoteModel(
initialStore = emptySet(),
currencyId = ethRawId,
expected = QuoteStatus(rawCurrencyId = ethRawId),
),
GetCurrencyUSDQuoteModel(
initialStore = setOf(ethQuote),
currencyId = ethRawId,
expected = ethQuote,
),
GetCurrencyUSDQuoteModel(
initialStore = setOf(QuoteStatus(rawCurrencyId = btcRawId)),
currencyId = ethRawId,
expected = QuoteStatus(rawCurrencyId = ethRawId),
),
GetCurrencyUSDQuoteModel(
initialStore = setOf(ethQuote, QuoteStatus(rawCurrencyId = btcRawId)),
currencyId = ethRawId,
expected = ethQuote,
),
)
}
data class GetMultiQuoteSyncOrNullModel(
val initialStore: Set<QuoteStatus>?,
val currencyIds: Set<CryptoCurrency.RawID>,
val expected: Set<QuoteStatus>?,
)
data class GetCurrencyUSDQuoteModel(
val initialStore: Set<QuoteStatus>?,
val currencyId: CryptoCurrency.RawID,
val expected: QuoteStatus?,
)
}

View file

@ -83,6 +83,7 @@ internal class DefaultSingleQuoteStatusProducerTest {
value = QuoteStatus.Data(
fiatRate = BigDecimal.ONE,
priceChange = BigDecimal.ZERO,
fiatRateUSD = BigDecimal.ZERO,
source = StatusSource.ACTUAL,
),
)
@ -129,6 +130,7 @@ internal class DefaultSingleQuoteStatusProducerTest {
rawCurrencyId = params.rawCurrencyId,
value = QuoteStatus.Data(
fiatRate = BigDecimal.ONE,
fiatRateUSD = BigDecimal.ZERO,
priceChange = BigDecimal.ZERO,
source = StatusSource.ACTUAL,
),