Updated on 2026-08-14
This commit is contained in:
parent
9cc51216bc
commit
c8c122b848
34 changed files with 383 additions and 303 deletions
|
|
@ -1,14 +1,14 @@
|
|||
package com.tangem.common.test.data.quote
|
||||
|
||||
import com.tangem.datasource.api.tangemTech.models.QuotesResponse
|
||||
import com.tangem.datasource.local.quote.converter.QuoteConverter
|
||||
import com.tangem.datasource.local.quote.converter.QuoteStatusConverter
|
||||
import com.tangem.domain.models.StatusSource
|
||||
import com.tangem.domain.tokens.model.Quote
|
||||
import com.tangem.domain.tokens.model.QuoteStatus
|
||||
|
||||
fun QuotesResponse.Quote.toDomain(rawCurrencyId: String, source: StatusSource = StatusSource.ACTUAL): Quote {
|
||||
return QuoteConverter(source = source).convert(value = mapOf(rawCurrencyId to this).entries.first())
|
||||
fun QuotesResponse.Quote.toDomain(rawCurrencyId: String, source: StatusSource = StatusSource.ACTUAL): QuoteStatus {
|
||||
return QuoteStatusConverter(source = source).convert(value = mapOf(rawCurrencyId to this).entries.first())
|
||||
}
|
||||
|
||||
fun Pair<String, QuotesResponse.Quote>.toDomain(source: StatusSource = StatusSource.ACTUAL): Quote {
|
||||
return QuoteConverter(source = source).convert(value = mapOf(this).entries.first())
|
||||
fun Pair<String, QuotesResponse.Quote>.toDomain(source: StatusSource = StatusSource.ACTUAL): QuoteStatus {
|
||||
return QuoteStatusConverter(source = source).convert(value = mapOf(this).entries.first())
|
||||
}
|
||||
|
|
@ -3,21 +3,20 @@ package com.tangem.datasource.local.quote.converter
|
|||
import com.tangem.datasource.api.tangemTech.models.QuotesResponse
|
||||
import com.tangem.domain.models.StatusSource
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.Quote
|
||||
import com.tangem.domain.tokens.model.QuoteStatus
|
||||
import com.tangem.utils.converter.Converter
|
||||
import com.tangem.utils.extensions.orZero
|
||||
|
||||
/**
|
||||
* Converter from [QuotesResponse.Quote] to [Quote.Value]
|
||||
* Converter from [QuotesResponse.Quote] to [QuoteStatus]
|
||||
*
|
||||
* @property source status source
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
class QuoteConverter(
|
||||
class QuoteStatusConverter(
|
||||
private val source: StatusSource,
|
||||
) :
|
||||
Converter<Map.Entry<String, QuotesResponse.Quote>, Quote.Value> {
|
||||
) : Converter<Map.Entry<String, QuotesResponse.Quote>, QuoteStatus> {
|
||||
|
||||
/**
|
||||
* Secondary constructor
|
||||
|
|
@ -28,14 +27,16 @@ class QuoteConverter(
|
|||
source = if (isCached) StatusSource.CACHE else StatusSource.ACTUAL,
|
||||
)
|
||||
|
||||
override fun convert(value: Map.Entry<String, QuotesResponse.Quote>): Quote.Value {
|
||||
override fun convert(value: Map.Entry<String, QuotesResponse.Quote>): QuoteStatus {
|
||||
val (currencyId, quote) = value
|
||||
|
||||
return Quote.Value(
|
||||
return QuoteStatus(
|
||||
rawCurrencyId = CryptoCurrency.RawID(currencyId),
|
||||
fiatRate = quote.price.orZero(),
|
||||
priceChange = quote.priceChange24h.orZero().movePointLeft(2),
|
||||
source = source,
|
||||
value = QuoteStatus.Data(
|
||||
source = source,
|
||||
fiatRate = quote.price.orZero(),
|
||||
priceChange = quote.priceChange24h.orZero().movePointLeft(2),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -11,7 +11,7 @@ import com.tangem.domain.models.currency.CryptoCurrency
|
|||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.onramp.model.HotCryptoCurrency
|
||||
import com.tangem.domain.tokens.model.Quote
|
||||
import com.tangem.domain.tokens.model.QuoteStatus
|
||||
import com.tangem.utils.converter.Converter
|
||||
import java.math.BigDecimal
|
||||
|
||||
|
|
@ -40,7 +40,7 @@ internal class HotCryptoCurrencyConverter(
|
|||
|
||||
return HotCryptoCurrency(
|
||||
cryptoCurrency = currency.setupIconUrl(id = rawId.value),
|
||||
quote = createQuote(
|
||||
quoteStatus = createQuote(
|
||||
fiatRate = value.currentPrice,
|
||||
priceChange = value.priceChangePercentage,
|
||||
rawCurrencyId = rawId,
|
||||
|
|
@ -89,16 +89,18 @@ internal class HotCryptoCurrencyConverter(
|
|||
fiatRate: BigDecimal?,
|
||||
priceChange: BigDecimal?,
|
||||
rawCurrencyId: CryptoCurrency.RawID,
|
||||
): Quote {
|
||||
): QuoteStatus {
|
||||
return if (fiatRate != null && priceChange != null) {
|
||||
Quote.Value(
|
||||
QuoteStatus(
|
||||
rawCurrencyId = rawCurrencyId,
|
||||
fiatRate = fiatRate,
|
||||
priceChange = priceChange.movePointLeft(2),
|
||||
source = StatusSource.ACTUAL, // It doesn't matter
|
||||
value = QuoteStatus.Data(
|
||||
fiatRate = fiatRate,
|
||||
priceChange = priceChange.movePointLeft(2),
|
||||
source = StatusSource.ACTUAL, // It doesn't matter
|
||||
),
|
||||
)
|
||||
} else {
|
||||
Quote.Empty(rawCurrencyId)
|
||||
QuoteStatus(rawCurrencyId = rawCurrencyId)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package com.tangem.data.quotes
|
|||
import com.tangem.data.quotes.store.QuotesStoreV2
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.quotes.QuotesRepositoryV2
|
||||
import com.tangem.domain.tokens.model.Quote
|
||||
import com.tangem.domain.tokens.model.QuoteStatus
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
|
|
@ -17,9 +17,10 @@ internal class DefaultQuotesRepositoryV2 @Inject constructor(
|
|||
private val quotesStore: QuotesStoreV2,
|
||||
) : QuotesRepositoryV2 {
|
||||
|
||||
override suspend fun getMultiQuoteSyncOrNull(currenciesIds: Set<CryptoCurrency.RawID>): Set<Quote>? {
|
||||
override suspend fun getMultiQuoteSyncOrNull(currenciesIds: Set<CryptoCurrency.RawID>): Set<QuoteStatus>? {
|
||||
return quotesStore.getAllSyncOrNull()?.mapTo(hashSetOf()) {
|
||||
it.takeIf { it.rawCurrencyId in currenciesIds } ?: Quote.Empty(it.rawCurrencyId)
|
||||
it.takeIf { it.rawCurrencyId in currenciesIds }
|
||||
?: QuoteStatus(rawCurrencyId = it.rawCurrencyId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -7,7 +7,7 @@ import com.tangem.datasource.appcurrency.AppCurrencyResponseStore
|
|||
import com.tangem.domain.core.utils.EitherFlow
|
||||
import com.tangem.domain.quotes.multi.MultiQuoteFetcher
|
||||
import com.tangem.domain.quotes.multi.MultiQuoteUpdater
|
||||
import com.tangem.domain.tokens.model.Quote
|
||||
import com.tangem.domain.tokens.model.QuoteStatus
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import com.tangem.utils.coroutines.JobHolder
|
||||
import com.tangem.utils.coroutines.saveIn
|
||||
|
|
@ -61,7 +61,7 @@ internal class DefaultMultiQuoteUpdater @Inject constructor(
|
|||
.filterNotNull()
|
||||
.mapLatest { appCurrency ->
|
||||
val currenciesIds = quotesStore.getAllSyncOrNull().orEmpty()
|
||||
.mapTo(destination = hashSetOf(), transform = Quote::rawCurrencyId)
|
||||
.mapTo(destination = hashSetOf(), transform = QuoteStatus::rawCurrencyId)
|
||||
|
||||
multiQuoteFetcher(
|
||||
params = MultiQuoteFetcher.Params(currenciesIds = currenciesIds, appCurrencyId = appCurrency.id),
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ package com.tangem.data.quotes.single
|
|||
|
||||
import com.tangem.data.quotes.store.QuotesStoreV2
|
||||
import com.tangem.domain.quotes.single.SingleQuoteProducer
|
||||
import com.tangem.domain.tokens.model.Quote
|
||||
import com.tangem.domain.tokens.model.QuoteStatus
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
|
|
@ -24,9 +24,9 @@ internal class DefaultSingleQuoteProducer @AssistedInject constructor(
|
|||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
) : SingleQuoteProducer {
|
||||
|
||||
override val fallback: Quote = Quote.Empty(rawCurrencyId = params.rawCurrencyId)
|
||||
override val fallback: QuoteStatus = QuoteStatus(rawCurrencyId = params.rawCurrencyId)
|
||||
|
||||
override fun produce(): Flow<Quote> {
|
||||
override fun produce(): Flow<QuoteStatus> {
|
||||
return quotesStore.get()
|
||||
.mapNotNull { quotes -> quotes.firstOrNull { it.rawCurrencyId == params.rawCurrencyId } }
|
||||
.distinctUntilChanged()
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ package com.tangem.data.quotes.store
|
|||
import androidx.datastore.core.DataStore
|
||||
import com.tangem.datasource.api.tangemTech.models.QuotesResponse
|
||||
import com.tangem.datasource.local.datastore.RuntimeSharedStore
|
||||
import com.tangem.datasource.local.quote.converter.QuoteConverter
|
||||
import com.tangem.datasource.local.quote.converter.QuoteStatusConverter
|
||||
import com.tangem.domain.models.StatusSource
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.Quote
|
||||
import com.tangem.domain.tokens.model.QuoteStatus
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import com.tangem.utils.extensions.addOrReplace
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
|
@ -26,7 +26,7 @@ internal typealias CurrencyIdWithQuote = Map<String, QuotesResponse.Quote>
|
|||
* @param dispatchers dispatchers
|
||||
*/
|
||||
internal class DefaultQuotesStoreV2(
|
||||
private val runtimeStore: RuntimeSharedStore<Set<Quote>>,
|
||||
private val runtimeStore: RuntimeSharedStore<Set<QuoteStatus>>,
|
||||
private val persistenceDataStore: DataStore<CurrencyIdWithQuote>,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
) : QuotesStoreV2 {
|
||||
|
|
@ -40,14 +40,14 @@ internal class DefaultQuotesStoreV2(
|
|||
if (cachedStatuses.isNullOrEmpty()) return@launch
|
||||
|
||||
runtimeStore.store(
|
||||
value = QuoteConverter(isCached = true).convertSet(input = cachedStatuses.entries),
|
||||
value = QuoteStatusConverter(isCached = true).convertSet(input = cachedStatuses.entries),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun get(): Flow<Set<Quote>> = runtimeStore.get()
|
||||
override fun get(): Flow<Set<QuoteStatus>> = runtimeStore.get()
|
||||
|
||||
override suspend fun getAllSyncOrNull(): Set<Quote>? = runtimeStore.getSyncOrNull()
|
||||
override suspend fun getAllSyncOrNull(): Set<QuoteStatus>? = runtimeStore.getSyncOrNull()
|
||||
|
||||
override suspend fun refresh(currenciesIds: Set<CryptoCurrency.RawID>) {
|
||||
updateStatusSourceInRuntime(currenciesIds = currenciesIds, source = StatusSource.CACHE)
|
||||
|
|
@ -56,7 +56,7 @@ internal class DefaultQuotesStoreV2(
|
|||
override suspend fun storeActual(values: Map<String, QuotesResponse.Quote>) {
|
||||
coroutineScope {
|
||||
launch {
|
||||
val quotes = QuoteConverter(isCached = false).convertSet(input = values.entries)
|
||||
val quotes = QuoteStatusConverter(isCached = false).convertSet(input = values.entries)
|
||||
storeInRuntimeStore(values = quotes)
|
||||
}
|
||||
launch { storeInPersistenceStore(values = values) }
|
||||
|
|
@ -66,14 +66,14 @@ internal class DefaultQuotesStoreV2(
|
|||
override suspend fun storeError(currenciesIds: Set<CryptoCurrency.RawID>) {
|
||||
updateStatusSourceInRuntime(
|
||||
currenciesIds = currenciesIds,
|
||||
ifNotFound = Quote::Empty,
|
||||
ifNotFound = ::QuoteStatus,
|
||||
source = StatusSource.ONLY_CACHE,
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun updateStatusSourceInRuntime(
|
||||
currenciesIds: Set<CryptoCurrency.RawID>,
|
||||
ifNotFound: (CryptoCurrency.RawID) -> Quote? = { null },
|
||||
ifNotFound: (CryptoCurrency.RawID) -> QuoteStatus? = { null },
|
||||
source: StatusSource,
|
||||
) {
|
||||
runtimeStore.update(default = emptySet()) { stored ->
|
||||
|
|
@ -82,14 +82,14 @@ internal class DefaultQuotesStoreV2(
|
|||
?: ifNotFound(id)
|
||||
?: return@mapNotNullTo null
|
||||
|
||||
quote.copySealed(source = source)
|
||||
quote.copy(value = quote.value.copySealed(source = source))
|
||||
}
|
||||
|
||||
stored.addOrReplace(items = updatedQuotes) { old, new -> old.rawCurrencyId == new.rawCurrencyId }
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun storeInRuntimeStore(values: Set<Quote>) {
|
||||
private suspend fun storeInRuntimeStore(values: Set<QuoteStatus>) {
|
||||
runtimeStore.update(default = emptySet()) { saved ->
|
||||
saved.addOrReplace(items = values) { prev, new -> prev.rawCurrencyId == new.rawCurrencyId }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,17 +2,17 @@ package com.tangem.data.quotes.store
|
|||
|
||||
import com.tangem.datasource.api.tangemTech.models.QuotesResponse
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.Quote
|
||||
import com.tangem.domain.tokens.model.QuoteStatus
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
/** Store of [Quote]'es set */
|
||||
/** Store of [QuoteStatus]'es set */
|
||||
internal interface QuotesStoreV2 {
|
||||
|
||||
/** Get flow of quotes */
|
||||
fun get(): Flow<Set<Quote>>
|
||||
fun get(): Flow<Set<QuoteStatus>>
|
||||
|
||||
/** Get all quotes synchronously or null */
|
||||
suspend fun getAllSyncOrNull(): Set<Quote>?
|
||||
suspend fun getAllSyncOrNull(): Set<QuoteStatus>?
|
||||
|
||||
/** Refresh status of [currenciesIds] */
|
||||
suspend fun refresh(currenciesIds: Set<CryptoCurrency.RawID>)
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ import java.math.BigDecimal
|
|||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal class DefaultMultiQuoteFetcherTest {
|
||||
internal class DefaultMultiQuoteStatusFetcherTest {
|
||||
|
||||
private val tangemTechApi = mockk<TangemTechApi>(relaxed = true)
|
||||
private val appCurrencyResponseStore = mockk<AppCurrencyResponseStore>(relaxed = true)
|
||||
|
|
@ -16,7 +16,7 @@ import org.junit.Test
|
|||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal class DefaultMultiQuoteUpdaterTest {
|
||||
internal class DefaultMultiQuoteStatusUpdaterTest {
|
||||
|
||||
private val appCurrencyResponseStore: AppCurrencyResponseStore = mockk()
|
||||
private val quotesStore: QuotesStoreV2 = mockk()
|
||||
|
|
@ -21,7 +21,7 @@ import kotlinx.coroutines.test.runTest
|
|||
import org.junit.Test
|
||||
import java.math.BigDecimal
|
||||
|
||||
internal class DefaultSingleQuoteFetcherTest {
|
||||
internal class DefaultSingleQuoteStatusFetcherTest {
|
||||
|
||||
private val tangemTechApi = mockk<TangemTechApi>(relaxed = true)
|
||||
private val appCurrencyResponseStore = mockk<AppCurrencyResponseStore>(relaxed = true)
|
||||
|
|
@ -6,7 +6,7 @@ import com.tangem.data.quotes.store.QuotesStoreV2
|
|||
import com.tangem.domain.models.StatusSource
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.quotes.single.SingleQuoteProducer
|
||||
import com.tangem.domain.tokens.model.Quote
|
||||
import com.tangem.domain.tokens.model.QuoteStatus
|
||||
import com.tangem.utils.coroutines.TestingCoroutineDispatcherProvider
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
|
|
@ -19,7 +19,7 @@ import java.math.BigDecimal
|
|||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal class DefaultSingleQuoteProducerTest {
|
||||
internal class DefaultSingleQuoteStatusProducerTest {
|
||||
|
||||
private val params = SingleQuoteProducer.Params(
|
||||
rawCurrencyId = CryptoCurrency.RawID(value = "BTC"),
|
||||
|
|
@ -35,11 +35,11 @@ internal class DefaultSingleQuoteProducerTest {
|
|||
|
||||
@Test
|
||||
fun `test that flow is mapped for network from params`() = runTest {
|
||||
val status = Quote.Empty(rawCurrencyId = params.rawCurrencyId)
|
||||
val status = QuoteStatus(rawCurrencyId = params.rawCurrencyId)
|
||||
val storeQuote = flowOf(
|
||||
setOf(
|
||||
status,
|
||||
Quote.Empty(rawCurrencyId = CryptoCurrency.RawID(value = "ETH")),
|
||||
QuoteStatus(rawCurrencyId = CryptoCurrency.RawID(value = "ETH")),
|
||||
),
|
||||
)
|
||||
|
||||
|
|
@ -57,7 +57,7 @@ internal class DefaultSingleQuoteProducerTest {
|
|||
|
||||
@Test
|
||||
fun `test that flow is updated if quote is updated`() = runTest {
|
||||
val storeQuote = MutableSharedFlow<Set<Quote>>(replay = 2, extraBufferCapacity = 1)
|
||||
val storeQuote = MutableSharedFlow<Set<QuoteStatus>>(replay = 2, extraBufferCapacity = 1)
|
||||
|
||||
every { quotesStore.get() } returns storeQuote
|
||||
|
||||
|
|
@ -66,7 +66,7 @@ internal class DefaultSingleQuoteProducerTest {
|
|||
verify { quotesStore.get() }
|
||||
|
||||
// first emit
|
||||
val status = Quote.Empty(rawCurrencyId = params.rawCurrencyId)
|
||||
val status = QuoteStatus(rawCurrencyId = params.rawCurrencyId)
|
||||
storeQuote.emit(value = setOf(status))
|
||||
|
||||
val values1 = getEmittedValues(flow = actual)
|
||||
|
|
@ -75,11 +75,13 @@ internal class DefaultSingleQuoteProducerTest {
|
|||
Truth.assertThat(values1).isEqualTo(listOf(status))
|
||||
|
||||
// second emit
|
||||
val updatedStatus = Quote.Value(
|
||||
val updatedStatus = QuoteStatus(
|
||||
rawCurrencyId = params.rawCurrencyId,
|
||||
fiatRate = BigDecimal.ONE,
|
||||
priceChange = BigDecimal.ZERO,
|
||||
source = StatusSource.ACTUAL,
|
||||
value = QuoteStatus.Data(
|
||||
fiatRate = BigDecimal.ONE,
|
||||
priceChange = BigDecimal.ZERO,
|
||||
source = StatusSource.ACTUAL,
|
||||
),
|
||||
)
|
||||
storeQuote.emit(value = setOf(updatedStatus))
|
||||
|
||||
|
|
@ -91,7 +93,7 @@ internal class DefaultSingleQuoteProducerTest {
|
|||
|
||||
@Test
|
||||
fun `test that flow is filtered the same status`() = runTest {
|
||||
val storeQuote = MutableSharedFlow<Set<Quote>>(replay = 2, extraBufferCapacity = 1)
|
||||
val storeQuote = MutableSharedFlow<Set<QuoteStatus>>(replay = 2, extraBufferCapacity = 1)
|
||||
|
||||
every { quotesStore.get() } returns storeQuote
|
||||
|
||||
|
|
@ -100,7 +102,7 @@ internal class DefaultSingleQuoteProducerTest {
|
|||
verify { quotesStore.get() }
|
||||
|
||||
// first emit
|
||||
val status = Quote.Empty(rawCurrencyId = params.rawCurrencyId)
|
||||
val status = QuoteStatus(rawCurrencyId = params.rawCurrencyId)
|
||||
storeQuote.emit(value = setOf(status))
|
||||
|
||||
val values1 = getEmittedValues(flow = actual)
|
||||
|
|
@ -120,11 +122,13 @@ internal class DefaultSingleQuoteProducerTest {
|
|||
@Test
|
||||
fun `test if flow throws exception`() = runTest {
|
||||
val exception = IllegalStateException()
|
||||
val status = Quote.Value(
|
||||
val status = QuoteStatus(
|
||||
rawCurrencyId = params.rawCurrencyId,
|
||||
fiatRate = BigDecimal.ONE,
|
||||
priceChange = BigDecimal.ZERO,
|
||||
source = StatusSource.ACTUAL,
|
||||
value = QuoteStatus.Data(
|
||||
fiatRate = BigDecimal.ONE,
|
||||
priceChange = BigDecimal.ZERO,
|
||||
source = StatusSource.ACTUAL,
|
||||
),
|
||||
)
|
||||
|
||||
val innerFlow = MutableStateFlow(value = false)
|
||||
|
|
@ -146,7 +150,7 @@ internal class DefaultSingleQuoteProducerTest {
|
|||
val values1 = getEmittedValues(flow = actual)
|
||||
|
||||
Truth.assertThat(values1.size).isEqualTo(1)
|
||||
val fallbackStatus = Quote.Empty(rawCurrencyId = params.rawCurrencyId)
|
||||
val fallbackStatus = QuoteStatus(rawCurrencyId = params.rawCurrencyId)
|
||||
Truth.assertThat(values1).isEqualTo(listOf(fallbackStatus))
|
||||
|
||||
innerFlow.emit(value = true)
|
||||
|
|
@ -160,7 +164,7 @@ internal class DefaultSingleQuoteProducerTest {
|
|||
fun `test if flow doesn't contain network from params`() = runTest {
|
||||
val storeFlow = flowOf(
|
||||
setOf(
|
||||
Quote.Empty(rawCurrencyId = CryptoCurrency.RawID(value = "ETH")),
|
||||
QuoteStatus(rawCurrencyId = CryptoCurrency.RawID(value = "ETH")),
|
||||
),
|
||||
)
|
||||
|
||||
|
|
@ -6,7 +6,7 @@ import com.tangem.common.test.data.quote.toDomain
|
|||
import com.tangem.common.test.datastore.MockStateDataStore
|
||||
import com.tangem.common.test.utils.getEmittedValues
|
||||
import com.tangem.datasource.local.datastore.RuntimeSharedStore
|
||||
import com.tangem.domain.tokens.model.Quote
|
||||
import com.tangem.domain.tokens.model.QuoteStatus
|
||||
import com.tangem.utils.coroutines.TestingCoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Test
|
||||
|
|
@ -17,7 +17,7 @@ import java.math.BigDecimal
|
|||
*/
|
||||
internal class QuotesStoreGetMethodTest {
|
||||
|
||||
private val runtimeStore = RuntimeSharedStore<Set<Quote>>()
|
||||
private val runtimeStore = RuntimeSharedStore<Set<QuoteStatus>>()
|
||||
private val persistenceStore = MockStateDataStore<CurrencyIdWithQuote>(default = emptyMap())
|
||||
|
||||
private val store = DefaultQuotesStoreV2(
|
||||
|
|
@ -32,7 +32,7 @@ internal class QuotesStoreGetMethodTest {
|
|||
|
||||
val values = getEmittedValues(flow = actual)
|
||||
|
||||
Truth.assertThat(values).isEqualTo(emptyList<Set<Quote>>())
|
||||
Truth.assertThat(values).isEqualTo(emptyList<Set<QuoteStatus>>())
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -43,7 +43,7 @@ internal class QuotesStoreGetMethodTest {
|
|||
|
||||
val values = getEmittedValues(flow = actual)
|
||||
|
||||
Truth.assertThat(values).isEqualTo(listOf(emptySet<Quote>()))
|
||||
Truth.assertThat(values).isEqualTo(listOf(emptySet<QuoteStatus>()))
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -74,7 +74,7 @@ internal class QuotesStoreGetMethodTest {
|
|||
|
||||
val actual = store.getAllSyncOrNull()
|
||||
|
||||
Truth.assertThat(actual).isEqualTo(emptySet<Quote>())
|
||||
Truth.assertThat(actual).isEqualTo(emptySet<QuoteStatus>())
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import com.tangem.common.test.data.quote.toDomain
|
|||
import com.tangem.common.test.datastore.MockStateDataStore
|
||||
import com.tangem.datasource.local.datastore.RuntimeSharedStore
|
||||
import com.tangem.domain.models.StatusSource
|
||||
import com.tangem.domain.tokens.model.Quote
|
||||
import com.tangem.domain.tokens.model.QuoteStatus
|
||||
import com.tangem.utils.coroutines.TestingCoroutineDispatcherProvider
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
|
|
@ -23,7 +23,7 @@ internal class QuotesStoreInitializationTest {
|
|||
|
||||
@Test
|
||||
fun `test initialization if cache store is empty`() = runTest {
|
||||
val runtimeStore = RuntimeSharedStore<Set<Quote>>()
|
||||
val runtimeStore = RuntimeSharedStore<Set<QuoteStatus>>()
|
||||
val persistenceStore: DataStore<CurrencyIdWithQuote> = mockk()
|
||||
|
||||
every { persistenceStore.data } returns emptyFlow()
|
||||
|
|
@ -39,7 +39,7 @@ internal class QuotesStoreInitializationTest {
|
|||
|
||||
@Test
|
||||
fun `test initialization if cache store contains empty map`() = runTest {
|
||||
val runtimeStore = RuntimeSharedStore<Set<Quote>>()
|
||||
val runtimeStore = RuntimeSharedStore<Set<QuoteStatus>>()
|
||||
val persistenceStore = MockStateDataStore<CurrencyIdWithQuote>(default = emptyMap())
|
||||
|
||||
DefaultQuotesStoreV2(
|
||||
|
|
@ -53,7 +53,7 @@ internal class QuotesStoreInitializationTest {
|
|||
|
||||
@Test
|
||||
fun `test initialization if cache store is not empty`() = runTest {
|
||||
val runtimeStore = RuntimeSharedStore<Set<Quote>>()
|
||||
val runtimeStore = RuntimeSharedStore<Set<QuoteStatus>>()
|
||||
val persistenceStore = MockStateDataStore<CurrencyIdWithQuote>(default = emptyMap())
|
||||
|
||||
val btcQuote = "BTC" to MockQuoteResponseFactory.createSinglePrice(BigDecimal.ZERO)
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import com.tangem.common.test.datastore.MockStateDataStore
|
|||
import com.tangem.datasource.local.datastore.RuntimeSharedStore
|
||||
import com.tangem.domain.models.StatusSource
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.Quote
|
||||
import com.tangem.domain.tokens.model.QuoteStatus
|
||||
import com.tangem.utils.coroutines.TestingCoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.firstOrNull
|
||||
import kotlinx.coroutines.test.runTest
|
||||
|
|
@ -19,7 +19,7 @@ import java.math.BigDecimal
|
|||
*/
|
||||
internal class QuotesStoreUpdateMethodsTest {
|
||||
|
||||
private val runtimeStore = RuntimeSharedStore<Set<Quote>>()
|
||||
private val runtimeStore = RuntimeSharedStore<Set<QuoteStatus>>()
|
||||
private val persistenceStore = MockStateDataStore<CurrencyIdWithQuote>(default = emptyMap())
|
||||
|
||||
private val store = DefaultQuotesStoreV2(
|
||||
|
|
@ -37,8 +37,8 @@ internal class QuotesStoreUpdateMethodsTest {
|
|||
|
||||
store.refresh(currenciesIds = currenciesIds)
|
||||
|
||||
Truth.assertThat(runtimeStore.getSyncOrNull()).isEqualTo(emptySet<Quote>())
|
||||
Truth.assertThat(persistenceStore.data.firstOrNull()).isEqualTo(emptyMap<String, Set<Quote>>())
|
||||
Truth.assertThat(runtimeStore.getSyncOrNull()).isEqualTo(emptySet<QuoteStatus>())
|
||||
Truth.assertThat(persistenceStore.data.firstOrNull()).isEqualTo(emptyMap<String, Set<QuoteStatus>>())
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -50,10 +50,12 @@ internal class QuotesStoreUpdateMethodsTest {
|
|||
|
||||
store.refresh(currenciesIds = setOf(quote.rawCurrencyId))
|
||||
|
||||
val runtimeExpected = setOf(quote.copySealed(source = StatusSource.CACHE))
|
||||
val runtimeExpected = setOf(
|
||||
quote.copy(value = quote.value.copySealed(source = StatusSource.CACHE)),
|
||||
)
|
||||
|
||||
Truth.assertThat(runtimeStore.getSyncOrNull()).isEqualTo(runtimeExpected)
|
||||
Truth.assertThat(persistenceStore.data.firstOrNull()).isEqualTo(emptyMap<String, Set<Quote>>())
|
||||
Truth.assertThat(persistenceStore.data.firstOrNull()).isEqualTo(emptyMap<String, Set<QuoteStatus>>())
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -94,10 +96,12 @@ internal class QuotesStoreUpdateMethodsTest {
|
|||
|
||||
store.storeError(currenciesIds = currenciesIds)
|
||||
|
||||
val runtimeExpected = currenciesIds.map(Quote::Empty).toSet()
|
||||
val runtimeExpected = currenciesIds
|
||||
.map { QuoteStatus(rawCurrencyId = it, value = QuoteStatus.Empty) }
|
||||
.toSet()
|
||||
|
||||
Truth.assertThat(runtimeStore.getSyncOrNull()).isEqualTo(runtimeExpected)
|
||||
Truth.assertThat(persistenceStore.data.firstOrNull()).isEqualTo(emptyMap<String, Set<Quote>>())
|
||||
Truth.assertThat(persistenceStore.data.firstOrNull()).isEqualTo(emptyMap<String, Set<QuoteStatus>>())
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -107,7 +111,7 @@ internal class QuotesStoreUpdateMethodsTest {
|
|||
runtimeStore.store(
|
||||
value = setOf(
|
||||
status.toDomain(rawCurrencyId = "BTC", source = StatusSource.CACHE),
|
||||
Quote.Empty(rawCurrencyId = CryptoCurrency.RawID(value = "ETH")),
|
||||
QuoteStatus(rawCurrencyId = CryptoCurrency.RawID(value = "ETH"), value = QuoteStatus.Empty),
|
||||
),
|
||||
)
|
||||
|
||||
|
|
@ -120,10 +124,10 @@ internal class QuotesStoreUpdateMethodsTest {
|
|||
|
||||
val runtimeExpected = setOf(
|
||||
status.toDomain(rawCurrencyId = "BTC", source = StatusSource.ONLY_CACHE),
|
||||
Quote.Empty(rawCurrencyId = CryptoCurrency.RawID(value = "ETH")),
|
||||
QuoteStatus(rawCurrencyId = CryptoCurrency.RawID(value = "ETH"), value = QuoteStatus.Empty),
|
||||
)
|
||||
|
||||
Truth.assertThat(runtimeStore.getSyncOrNull()).isEqualTo(runtimeExpected)
|
||||
Truth.assertThat(persistenceStore.data.firstOrNull()).isEqualTo(emptyMap<String, Set<Quote>>())
|
||||
Truth.assertThat(persistenceStore.data.firstOrNull()).isEqualTo(emptyMap<String, Set<QuoteStatus>>())
|
||||
}
|
||||
}
|
||||
|
|
@ -6,7 +6,7 @@ import arrow.core.toOption
|
|||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.quotes.single.SingleQuoteProducer
|
||||
import com.tangem.domain.quotes.single.SingleQuoteSupplier
|
||||
import com.tangem.domain.tokens.model.Quote
|
||||
import com.tangem.domain.tokens.model.QuoteStatus
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
|
|
@ -20,13 +20,13 @@ class GetCurrencyQuotesUseCase(
|
|||
currencyID: CryptoCurrency.ID,
|
||||
interval: PriceChangeInterval,
|
||||
refresh: Boolean,
|
||||
): Flow<Option<Quote.Value>> {
|
||||
): Flow<Option<QuoteStatus.Data>> {
|
||||
val rawId = currencyID.rawCurrencyId ?: return flowOf(None)
|
||||
|
||||
return singleQuoteSupplier(
|
||||
params = SingleQuoteProducer.Params(rawCurrencyId = rawId),
|
||||
)
|
||||
.map { (it as? Quote.Value).toOption() }
|
||||
.map { (it.value as? QuoteStatus.Data).toOption() }
|
||||
.catch { emit(None) }
|
||||
}
|
||||
}
|
||||
|
|
@ -6,7 +6,7 @@ import com.tangem.domain.nft.models.NFTSalePrice
|
|||
import com.tangem.domain.nft.repository.NFTRepository
|
||||
import com.tangem.domain.quotes.single.SingleQuoteProducer
|
||||
import com.tangem.domain.quotes.single.SingleQuoteSupplier
|
||||
import com.tangem.domain.tokens.model.Quote
|
||||
import com.tangem.domain.tokens.model.fold
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
|
@ -31,12 +31,15 @@ class GetNFTPriceUseCase(
|
|||
assetId = nftAsset.id,
|
||||
)
|
||||
|
||||
val quoteValue = quote as? Quote.Value
|
||||
|
||||
if (nftPrice !is NFTSalePrice.Value) {
|
||||
nftPrice
|
||||
} else {
|
||||
nftPrice.copy(fiatValue = quoteValue?.fiatRate?.multiply(nftPrice.value))
|
||||
nftPrice.copy(
|
||||
fiatValue = quote.fold(
|
||||
onData = { fiatRate.multiply(nftPrice.value) },
|
||||
onEmpty = { null },
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
package com.tangem.domain.onramp.model
|
||||
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.Quote
|
||||
import com.tangem.domain.tokens.model.QuoteStatus
|
||||
|
||||
/**
|
||||
* Hot crypto currency
|
||||
*
|
||||
* @property cryptoCurrency crypto currency
|
||||
* @property quote quote
|
||||
* @property quoteStatus quote status
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
data class HotCryptoCurrency(
|
||||
val cryptoCurrency: CryptoCurrency,
|
||||
val quote: Quote,
|
||||
val quoteStatus: QuoteStatus,
|
||||
)
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
package com.tangem.domain.quotes
|
||||
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.Quote
|
||||
import com.tangem.domain.tokens.model.QuoteStatus
|
||||
|
||||
/**
|
||||
* Quotes repository
|
||||
|
|
@ -11,5 +11,5 @@ import com.tangem.domain.tokens.model.Quote
|
|||
interface QuotesRepositoryV2 {
|
||||
|
||||
/** Get quotes by [currenciesIds] synchronously or null */
|
||||
suspend fun getMultiQuoteSyncOrNull(currenciesIds: Set<CryptoCurrency.RawID>): Set<Quote>?
|
||||
suspend fun getMultiQuoteSyncOrNull(currenciesIds: Set<CryptoCurrency.RawID>): Set<QuoteStatus>?
|
||||
}
|
||||
|
|
@ -2,14 +2,14 @@ package com.tangem.domain.quotes.single
|
|||
|
||||
import com.tangem.domain.core.flow.FlowProducer
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.Quote
|
||||
import com.tangem.domain.tokens.model.QuoteStatus
|
||||
|
||||
/**
|
||||
* Producer of quote [CryptoCurrency.RawID]
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
interface SingleQuoteProducer : FlowProducer<Quote> {
|
||||
interface SingleQuoteProducer : FlowProducer<QuoteStatus> {
|
||||
|
||||
data class Params(val rawCurrencyId: CryptoCurrency.RawID)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package com.tangem.domain.quotes.single
|
||||
|
||||
import com.tangem.domain.core.flow.FlowCachingSupplier
|
||||
import com.tangem.domain.tokens.model.Quote
|
||||
import com.tangem.domain.tokens.model.QuoteStatus
|
||||
|
||||
/**
|
||||
* Supplier of quote [SingleQuoteProducer.Params]
|
||||
|
|
@ -14,4 +14,4 @@ import com.tangem.domain.tokens.model.Quote
|
|||
abstract class SingleQuoteSupplier(
|
||||
override val factory: SingleQuoteProducer.Factory,
|
||||
override val keyCreator: (SingleQuoteProducer.Params) -> String,
|
||||
) : FlowCachingSupplier<SingleQuoteProducer, SingleQuoteProducer.Params, Quote>()
|
||||
) : FlowCachingSupplier<SingleQuoteProducer, SingleQuoteProducer.Params, QuoteStatus>()
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
package com.tangem.domain.tokens.model
|
||||
|
||||
import com.tangem.domain.models.StatusSource
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import java.math.BigDecimal
|
||||
|
||||
sealed interface Quote {
|
||||
|
||||
val rawCurrencyId: CryptoCurrency.RawID
|
||||
|
||||
fun copySealed(source: StatusSource): Quote {
|
||||
return when (this) {
|
||||
is Empty -> this
|
||||
is Value -> copy(source = source)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents unknown financial information for a specific cryptocurrency.
|
||||
*
|
||||
* @property rawCurrencyId The raw cryptocurrency ID.
|
||||
*/
|
||||
data class Empty(override val rawCurrencyId: CryptoCurrency.RawID) : Quote
|
||||
|
||||
/**
|
||||
* Represents financial information for a specific cryptocurrency, including its fiat exchange rate and price change.
|
||||
*
|
||||
* @property rawCurrencyId The unique identifier of the cryptocurrency for which the financial information is provided.
|
||||
* @property fiatRate The current fiat exchange rate for the cryptocurrency.
|
||||
* @property priceChange The price change for the cryptocurrency.
|
||||
* @property source source of data
|
||||
*/
|
||||
data class Value(
|
||||
override val rawCurrencyId: CryptoCurrency.RawID,
|
||||
val fiatRate: BigDecimal,
|
||||
val priceChange: BigDecimal,
|
||||
val source: StatusSource,
|
||||
) : Quote
|
||||
}
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
package com.tangem.domain.tokens.model
|
||||
|
||||
import com.tangem.domain.models.StatusSource
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import java.math.BigDecimal
|
||||
|
||||
/**
|
||||
* Represents the status of a specific currency quote
|
||||
*
|
||||
* @property rawCurrencyId the unique identifier of the cryptocurrency for which the financial information is provided
|
||||
* @property value the specific status value
|
||||
*/
|
||||
data class QuoteStatus(val rawCurrencyId: CryptoCurrency.RawID, val value: Value) {
|
||||
|
||||
/** Constructor for creating the [Empty] status of a specific currency quote */
|
||||
constructor(rawCurrencyId: CryptoCurrency.RawID) : this(rawCurrencyId = rawCurrencyId, value = Empty)
|
||||
|
||||
/** Represents the various possible statuses of a quote */
|
||||
sealed interface Value {
|
||||
|
||||
/** Status source */
|
||||
val source: StatusSource
|
||||
|
||||
fun copySealed(source: StatusSource): Value {
|
||||
return when (this) {
|
||||
is Empty -> this
|
||||
is Data -> copy(source = source)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Represents unknown financial information for a specific cryptocurrency */
|
||||
data object Empty : Value {
|
||||
override val source: StatusSource = StatusSource.ACTUAL
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents financial information for a specific cryptocurrency, including its fiat exchange rate and
|
||||
* price change.
|
||||
*
|
||||
* @property source status source
|
||||
* @property fiatRate the current fiat exchange rate for the cryptocurrency
|
||||
* @property priceChange the price change for the cryptocurrency
|
||||
*/
|
||||
data class Data(
|
||||
override val source: StatusSource,
|
||||
val fiatRate: BigDecimal,
|
||||
val priceChange: BigDecimal,
|
||||
) : Value
|
||||
}
|
||||
|
||||
/** Applies the given [function] if [QuoteStatus.Value] is [QuoteStatus.Data] or does nothing */
|
||||
inline fun QuoteStatus.mapData(function: QuoteStatus.Data.() -> Unit): QuoteStatus {
|
||||
if (value is QuoteStatus.Data) value.function()
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the given [onData] or [onEmpty] functions depending on [QuoteStatus.Data] or [QuoteStatus.Empty]
|
||||
*
|
||||
* @param T type of result
|
||||
*/
|
||||
inline fun <T> QuoteStatus.fold(onData: QuoteStatus.Data.() -> T, onEmpty: QuoteStatus.Empty.() -> T): T {
|
||||
return when (value) {
|
||||
is QuoteStatus.Data -> value.onData()
|
||||
is QuoteStatus.Empty -> value.onEmpty()
|
||||
}
|
||||
}
|
||||
|
|
@ -6,7 +6,7 @@ package com.tangem.domain.tokens.model
|
|||
* @property id The unique identifier of the token.
|
||||
* @property networks List of networks associated with the token.
|
||||
* @property isAvailable Indicates whether this token is supported in Tangem app.
|
||||
* @property quote Equivalent prices for the token.
|
||||
* @property quoteStatus Equivalent prices for the token.
|
||||
* @property name The name of the token.
|
||||
* @property symbol The brief name of the token, e.g., "BTC".
|
||||
* @property iconUrl URL of the token's icon.
|
||||
|
|
@ -15,7 +15,7 @@ data class Token(
|
|||
val id: String,
|
||||
val networks: List<Network>,
|
||||
val isAvailable: Boolean,
|
||||
val quote: Quote?,
|
||||
val quoteStatus: QuoteStatus?,
|
||||
val name: String,
|
||||
val symbol: String,
|
||||
val iconUrl: String,
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ import com.tangem.domain.staking.single.SingleYieldBalanceProducer
|
|||
import com.tangem.domain.staking.single.SingleYieldBalanceSupplier
|
||||
import com.tangem.domain.tokens.TokensFeatureToggles
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.tokens.model.Quote
|
||||
import com.tangem.domain.tokens.model.QuoteStatus
|
||||
import com.tangem.domain.tokens.operations.CurrenciesStatusesOperations.Error
|
||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||
import com.tangem.domain.tokens.utils.CurrencyStatusProxyCreator
|
||||
|
|
@ -52,7 +52,7 @@ abstract class BaseCurrencyStatusOperations(
|
|||
|
||||
protected val currencyStatusProxyCreator = CurrencyStatusProxyCreator(stakingRepository)
|
||||
|
||||
protected abstract fun getQuotes(id: CryptoCurrency.RawID): Flow<Either<Error, Set<Quote>>>
|
||||
protected abstract fun getQuotes(id: CryptoCurrency.RawID): Flow<Either<Error, Set<QuoteStatus>>>
|
||||
|
||||
protected abstract fun getNetworksStatuses(
|
||||
userWalletId: UserWalletId,
|
||||
|
|
@ -120,7 +120,7 @@ abstract class BaseCurrencyStatusOperations(
|
|||
combine(quoteFlow, statusFlow, yieldBalanceFlow) { maybeQuote, maybeNetworkStatus, maybeYieldBalance ->
|
||||
currencyStatusProxyCreator.createCurrencyStatus(
|
||||
currency = currency,
|
||||
maybeQuote = maybeQuote,
|
||||
maybeQuoteStatus = maybeQuote,
|
||||
maybeNetworkStatus = maybeNetworkStatus,
|
||||
maybeYieldBalance = maybeYieldBalance,
|
||||
)
|
||||
|
|
@ -129,7 +129,7 @@ abstract class BaseCurrencyStatusOperations(
|
|||
combine(quoteFlow, statusFlow) { maybeQuote, maybeNetworkStatus ->
|
||||
currencyStatusProxyCreator.createCurrencyStatus(
|
||||
currency = currency,
|
||||
maybeQuote = maybeQuote,
|
||||
maybeQuoteStatus = maybeQuote,
|
||||
maybeNetworkStatus = maybeNetworkStatus,
|
||||
maybeYieldBalance = null,
|
||||
)
|
||||
|
|
@ -210,7 +210,7 @@ abstract class BaseCurrencyStatusOperations(
|
|||
|
||||
return currencyStatusProxyCreator.createCurrencyStatus(
|
||||
currency = currency,
|
||||
maybeQuote = quote,
|
||||
maybeQuoteStatus = quote,
|
||||
maybeNetworkStatus = networkStatuses,
|
||||
maybeYieldBalance = yieldBalances,
|
||||
)
|
||||
|
|
@ -303,7 +303,7 @@ abstract class BaseCurrencyStatusOperations(
|
|||
|
||||
return currencyStatusProxyCreator.createCurrencyStatus(
|
||||
currency = currency,
|
||||
maybeQuote = quotes,
|
||||
maybeQuoteStatus = quotes,
|
||||
maybeNetworkStatus = networkStatus,
|
||||
maybeYieldBalance = yieldBalances,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ import com.tangem.domain.staking.single.SingleYieldBalanceSupplier
|
|||
import com.tangem.domain.tokens.TokensFeatureToggles
|
||||
import com.tangem.domain.tokens.error.TokenListError
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.tokens.model.Quote
|
||||
import com.tangem.domain.tokens.model.QuoteStatus
|
||||
import com.tangem.domain.tokens.operations.CurrenciesStatusesOperations.Error
|
||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||
import com.tangem.domain.tokens.utils.extractAddress
|
||||
|
|
@ -121,7 +121,7 @@ class CachedCurrenciesStatusesOperations(
|
|||
val (networks, currenciesIds) = getIds(currencies)
|
||||
|
||||
fun createCurrenciesStatuses(
|
||||
maybeQuotes: Either<TokenListError, Set<Quote>>?,
|
||||
maybeQuotes: Either<TokenListError, Set<QuoteStatus>>?,
|
||||
maybeNetworkStatuses: Either<TokenListError, Set<NetworkStatus>>?,
|
||||
maybeYieldBalances: Either<TokenListError, YieldBalanceList>?,
|
||||
isUpdating: Boolean,
|
||||
|
|
@ -212,7 +212,7 @@ class CachedCurrenciesStatusesOperations(
|
|||
|
||||
private fun createCurrenciesStatuses(
|
||||
currencies: NonEmptyList<CryptoCurrency>,
|
||||
maybeQuotes: Either<TokenListError, Set<Quote>>?,
|
||||
maybeQuotes: Either<TokenListError, Set<QuoteStatus>>?,
|
||||
maybeNetworkStatuses: Either<TokenListError, Set<NetworkStatus>>?,
|
||||
maybeYieldBalances: Either<TokenListError, YieldBalanceList>?,
|
||||
isUpdating: Boolean,
|
||||
|
|
@ -238,7 +238,7 @@ class CachedCurrenciesStatusesOperations(
|
|||
|
||||
val currencyStatus = currencyStatusProxyCreator.createCurrencyStatus(
|
||||
currency = currency,
|
||||
quote = quote,
|
||||
quoteStatus = quote,
|
||||
networkStatus = networkStatus,
|
||||
yieldBalance = yieldBalance,
|
||||
ignoreQuote = quotesRetrievingFailed,
|
||||
|
|
@ -272,7 +272,7 @@ class CachedCurrenciesStatusesOperations(
|
|||
.distinctUntilChanged()
|
||||
}
|
||||
|
||||
private fun getQuotes(tokensIds: NonEmptySet<CryptoCurrency.ID>): Flow<Either<TokenListError, Set<Quote>>> {
|
||||
private fun getQuotes(tokensIds: NonEmptySet<CryptoCurrency.ID>): Flow<Either<TokenListError, Set<QuoteStatus>>> {
|
||||
return getQuotesUpdates(
|
||||
rawCurrencyIds = tokensIds.mapNotNullTo(
|
||||
destination = hashSetOf(),
|
||||
|
|
@ -281,11 +281,11 @@ class CachedCurrenciesStatusesOperations(
|
|||
)
|
||||
}
|
||||
|
||||
override fun getQuotes(id: CryptoCurrency.RawID): Flow<Either<Error, Set<Quote>>> {
|
||||
override fun getQuotes(id: CryptoCurrency.RawID): Flow<Either<Error, Set<QuoteStatus>>> {
|
||||
return singleQuoteSupplier(
|
||||
params = SingleQuoteProducer.Params(rawCurrencyId = id),
|
||||
)
|
||||
.map<Quote, Either<Error, Set<Quote>>> { setOf(it).right() }
|
||||
.map<QuoteStatus, Either<Error, Set<QuoteStatus>>> { setOf(it).right() }
|
||||
.distinctUntilChanged()
|
||||
}
|
||||
|
||||
|
|
@ -353,9 +353,11 @@ class CachedCurrenciesStatusesOperations(
|
|||
}
|
||||
|
||||
// temporary code because token list is built using networks list
|
||||
private fun getQuotesUpdates(rawCurrencyIds: Set<CryptoCurrency.RawID>): EitherFlow<TokenListError, Set<Quote>> {
|
||||
private fun getQuotesUpdates(
|
||||
rawCurrencyIds: Set<CryptoCurrency.RawID>,
|
||||
): EitherFlow<TokenListError, Set<QuoteStatus>> {
|
||||
return channelFlow {
|
||||
val state = MutableStateFlow(emptySet<Quote>())
|
||||
val state = MutableStateFlow(emptySet<QuoteStatus>())
|
||||
|
||||
rawCurrencyIds.onEach {
|
||||
launch {
|
||||
|
|
@ -375,7 +377,7 @@ class CachedCurrenciesStatusesOperations(
|
|||
.onEach(::send)
|
||||
.launchIn(scope = this)
|
||||
}
|
||||
.map<Set<Quote>, Either<TokenListError, Set<Quote>>> { it.right() }
|
||||
.map<Set<QuoteStatus>, Either<TokenListError, Set<QuoteStatus>>> { it.right() }
|
||||
.distinctUntilChanged()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,28 +5,22 @@ import com.tangem.domain.models.currency.CryptoCurrency
|
|||
import com.tangem.domain.models.network.NetworkStatus
|
||||
import com.tangem.domain.staking.model.stakekit.YieldBalance
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.tokens.model.Quote
|
||||
import com.tangem.domain.tokens.model.QuoteStatus
|
||||
import java.math.BigDecimal
|
||||
|
||||
internal class CurrencyStatusOperations(
|
||||
private val currency: CryptoCurrency,
|
||||
private val quote: Quote?,
|
||||
private val quoteStatus: QuoteStatus?,
|
||||
private val networkStatus: NetworkStatus?,
|
||||
private val yieldBalance: YieldBalance?,
|
||||
private val ignoreQuote: Boolean,
|
||||
) {
|
||||
|
||||
private val Quote?.fiatRate: BigDecimal?
|
||||
get() = when (this) {
|
||||
is Quote.Value -> this.fiatRate
|
||||
is Quote.Empty, null -> null
|
||||
}
|
||||
private val QuoteStatus?.fiatRate: BigDecimal?
|
||||
get() = (this?.value as? QuoteStatus.Data)?.fiatRate
|
||||
|
||||
private val Quote?.priceChange: BigDecimal?
|
||||
get() = when (this) {
|
||||
is Quote.Value -> this.priceChange
|
||||
is Quote.Empty, null -> null
|
||||
}
|
||||
private val QuoteStatus?.priceChange: BigDecimal?
|
||||
get() = (this?.value as? QuoteStatus.Data)?.priceChange
|
||||
|
||||
fun createTokenStatus(): CryptoCurrencyStatus = CryptoCurrencyStatus(currency, createStatus())
|
||||
|
||||
|
|
@ -41,12 +35,12 @@ internal class CurrencyStatusOperations(
|
|||
}
|
||||
|
||||
private fun createMissedDerivationStatus(): CryptoCurrencyStatus.MissedDerivation =
|
||||
CryptoCurrencyStatus.MissedDerivation(priceChange = quote?.priceChange, fiatRate = quote?.fiatRate)
|
||||
CryptoCurrencyStatus.MissedDerivation(priceChange = quoteStatus?.priceChange, fiatRate = quoteStatus?.fiatRate)
|
||||
|
||||
private fun createUnreachableStatus(status: NetworkStatus.Unreachable): CryptoCurrencyStatus.Unreachable {
|
||||
return CryptoCurrencyStatus.Unreachable(
|
||||
priceChange = quote?.priceChange,
|
||||
fiatRate = quote?.fiatRate,
|
||||
priceChange = quoteStatus?.priceChange,
|
||||
fiatRate = quoteStatus?.fiatRate,
|
||||
networkAddress = status.address,
|
||||
)
|
||||
}
|
||||
|
|
@ -54,13 +48,13 @@ internal class CurrencyStatusOperations(
|
|||
private fun createNoAccountStatus(status: NetworkStatus.NoAccount): CryptoCurrencyStatus.NoAccount {
|
||||
return CryptoCurrencyStatus.NoAccount(
|
||||
amountToCreateAccount = status.amountToCreateAccount,
|
||||
fiatAmount = if (quote == null) null else BigDecimal.ZERO,
|
||||
priceChange = quote?.priceChange,
|
||||
fiatRate = quote?.fiatRate,
|
||||
fiatAmount = if (quoteStatus == null) null else BigDecimal.ZERO,
|
||||
priceChange = quoteStatus?.priceChange,
|
||||
fiatRate = quoteStatus?.fiatRate,
|
||||
networkAddress = status.address,
|
||||
sources = CryptoCurrencyStatus.Sources(
|
||||
networkSource = status.source,
|
||||
quoteSource = (quote as? Quote.Value)?.source ?: StatusSource.ACTUAL,
|
||||
quoteSource = quoteStatus?.value?.source ?: StatusSource.ACTUAL,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -75,7 +69,10 @@ internal class CurrencyStatusOperations(
|
|||
return CryptoCurrencyStatus.Loading
|
||||
}
|
||||
is NetworkStatus.Amount.NotFound -> {
|
||||
return CryptoCurrencyStatus.NoAmount(priceChange = quote?.priceChange, fiatRate = quote?.fiatRate)
|
||||
return CryptoCurrencyStatus.NoAmount(
|
||||
priceChange = quoteStatus?.priceChange,
|
||||
fiatRate = quoteStatus?.fiatRate,
|
||||
)
|
||||
}
|
||||
is NetworkStatus.Amount.Loaded -> amount.value
|
||||
}
|
||||
|
|
@ -96,24 +93,27 @@ internal class CurrencyStatusOperations(
|
|||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
val quoteValue = quoteStatus?.value
|
||||
|
||||
// order is important for correct total balance calculation
|
||||
return when {
|
||||
currency is CryptoCurrency.Token && currency.isCustom -> CryptoCurrencyStatus.Custom(
|
||||
amount = amount,
|
||||
fiatAmount = calculateFiatAmountOrNull(amount, quote?.fiatRate),
|
||||
fiatRate = quote?.fiatRate,
|
||||
priceChange = quote?.priceChange,
|
||||
fiatAmount = calculateFiatAmountOrNull(amount, quoteStatus?.fiatRate),
|
||||
fiatRate = quoteStatus?.fiatRate,
|
||||
priceChange = quoteStatus?.priceChange,
|
||||
hasCurrentNetworkTransactions = hasCurrentNetworkTransactions,
|
||||
pendingTransactions = currentTransactions,
|
||||
networkAddress = networkStatusValue.address,
|
||||
yieldBalance = currentYieldBalance,
|
||||
sources = CryptoCurrencyStatus.Sources(
|
||||
networkSource = networkStatusValue.source,
|
||||
quoteSource = (quote as? Quote.Value)?.source ?: StatusSource.ACTUAL,
|
||||
quoteSource = quoteStatus?.value?.source ?: StatusSource.ACTUAL,
|
||||
yieldBalanceSource = currentYieldBalance?.source ?: StatusSource.ACTUAL,
|
||||
),
|
||||
)
|
||||
quote is Quote.Empty || ignoreQuote -> CryptoCurrencyStatus.NoQuote(
|
||||
quoteValue is QuoteStatus.Empty || ignoreQuote -> CryptoCurrencyStatus.NoQuote(
|
||||
amount = amount,
|
||||
hasCurrentNetworkTransactions = hasCurrentNetworkTransactions,
|
||||
pendingTransactions = currentTransactions,
|
||||
|
|
@ -121,22 +121,22 @@ internal class CurrencyStatusOperations(
|
|||
yieldBalance = currentYieldBalance,
|
||||
sources = CryptoCurrencyStatus.Sources(
|
||||
networkSource = networkStatusValue.source,
|
||||
quoteSource = (quote as? Quote.Value)?.source ?: StatusSource.ACTUAL,
|
||||
quoteSource = quoteStatus?.value?.source ?: StatusSource.ACTUAL,
|
||||
yieldBalanceSource = currentYieldBalance?.source ?: StatusSource.ACTUAL,
|
||||
),
|
||||
)
|
||||
quote is Quote.Value -> CryptoCurrencyStatus.Loaded(
|
||||
quoteValue is QuoteStatus.Data -> CryptoCurrencyStatus.Loaded(
|
||||
amount = amount,
|
||||
fiatAmount = calculateFiatAmount(amount, quote.fiatRate),
|
||||
fiatRate = quote.fiatRate,
|
||||
priceChange = quote.priceChange,
|
||||
fiatAmount = calculateFiatAmount(amount, quoteValue.fiatRate),
|
||||
fiatRate = quoteValue.fiatRate,
|
||||
priceChange = quoteValue.priceChange,
|
||||
hasCurrentNetworkTransactions = hasCurrentNetworkTransactions,
|
||||
pendingTransactions = currentTransactions,
|
||||
networkAddress = networkStatusValue.address,
|
||||
yieldBalance = currentYieldBalance,
|
||||
sources = CryptoCurrencyStatus.Sources(
|
||||
networkSource = networkStatusValue.source,
|
||||
quoteSource = quote.source,
|
||||
quoteSource = quoteValue.source,
|
||||
yieldBalanceSource = currentYieldBalance?.source ?: StatusSource.ACTUAL,
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import com.tangem.domain.staking.model.stakekit.YieldBalance
|
|||
import com.tangem.domain.staking.model.stakekit.YieldBalanceList
|
||||
import com.tangem.domain.staking.repositories.StakingRepository
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.tokens.model.Quote
|
||||
import com.tangem.domain.tokens.model.QuoteStatus
|
||||
import com.tangem.domain.tokens.operations.CurrenciesStatusesOperations.Error
|
||||
import com.tangem.domain.tokens.operations.CurrencyStatusOperations
|
||||
|
||||
|
|
@ -27,14 +27,14 @@ class CurrencyStatusProxyCreator(
|
|||
|
||||
fun createCurrencyStatus(
|
||||
currency: CryptoCurrency,
|
||||
maybeQuote: Either<Error, Quote?>,
|
||||
maybeQuoteStatus: Either<Error, QuoteStatus?>,
|
||||
maybeNetworkStatus: Either<Error, NetworkStatus?>,
|
||||
maybeYieldBalance: Either<Error, YieldBalance>?,
|
||||
): Either<Error, CryptoCurrencyStatus> = either {
|
||||
var quoteRetrievingFailed = false
|
||||
|
||||
val networkStatus = maybeNetworkStatus.bind()
|
||||
val quote = arrow.core.raise.recover({ maybeQuote.bind() }) {
|
||||
val quote = arrow.core.raise.recover({ maybeQuoteStatus.bind() }) {
|
||||
quoteRetrievingFailed = true
|
||||
null
|
||||
}
|
||||
|
|
@ -42,7 +42,7 @@ class CurrencyStatusProxyCreator(
|
|||
|
||||
createCurrencyStatus(
|
||||
currency = currency,
|
||||
quote = quote,
|
||||
quoteStatus = quote,
|
||||
networkStatus = networkStatus,
|
||||
ignoreQuote = quoteRetrievingFailed,
|
||||
yieldBalance = yieldBalance,
|
||||
|
|
@ -51,14 +51,14 @@ class CurrencyStatusProxyCreator(
|
|||
|
||||
fun createCurrenciesStatuses(
|
||||
currencies: NonEmptyList<CryptoCurrency>,
|
||||
maybeQuotes: Either<Error, Set<Quote>>?,
|
||||
maybeQuotes: Either<Error, Set<QuoteStatus>>?,
|
||||
maybeNetworkStatuses: Either<Error, Set<NetworkStatus>>?,
|
||||
maybeYieldBalances: Either<Error, YieldBalanceList>?,
|
||||
): Either<Error, List<CryptoCurrencyStatus>> = either {
|
||||
var quotesRetrievingFailed = false
|
||||
|
||||
val networksStatuses = maybeNetworkStatuses?.bind()?.toNonEmptySetOrNull()
|
||||
val quotes: Set<Quote>? = maybeQuotes?.fold(
|
||||
val quoteStatuses: Set<QuoteStatus>? = maybeQuotes?.fold(
|
||||
ifLeft = {
|
||||
quotesRetrievingFailed = true
|
||||
null
|
||||
|
|
@ -74,7 +74,7 @@ class CurrencyStatusProxyCreator(
|
|||
val yieldBalances = maybeYieldBalances?.getOrNull()
|
||||
|
||||
currencies.map { currency ->
|
||||
val quote = quotes?.firstOrNull { it.rawCurrencyId == currency.id.rawCurrencyId }
|
||||
val quote = quoteStatuses?.firstOrNull { it.rawCurrencyId == currency.id.rawCurrencyId }
|
||||
val networkStatus = networksStatuses?.firstOrNull { it.network == currency.network }
|
||||
val address = extractAddress(networkStatus)
|
||||
|
||||
|
|
@ -89,7 +89,7 @@ class CurrencyStatusProxyCreator(
|
|||
}
|
||||
createCurrencyStatus(
|
||||
currency = currency,
|
||||
quote = quote,
|
||||
quoteStatus = quote,
|
||||
networkStatus = networkStatus,
|
||||
ignoreQuote = quotesRetrievingFailed,
|
||||
yieldBalance = yieldBalance,
|
||||
|
|
@ -99,14 +99,14 @@ class CurrencyStatusProxyCreator(
|
|||
|
||||
fun createCurrencyStatus(
|
||||
currency: CryptoCurrency,
|
||||
quote: Quote?,
|
||||
quoteStatus: QuoteStatus?,
|
||||
networkStatus: NetworkStatus?,
|
||||
ignoreQuote: Boolean,
|
||||
yieldBalance: YieldBalance?,
|
||||
): CryptoCurrencyStatus {
|
||||
val currencyStatusOperations = CurrencyStatusOperations(
|
||||
currency = currency,
|
||||
quote = quote,
|
||||
quoteStatus = quoteStatus,
|
||||
networkStatus = networkStatus,
|
||||
ignoreQuote = ignoreQuote,
|
||||
yieldBalance = yieldBalance,
|
||||
|
|
|
|||
|
|
@ -3,83 +3,103 @@ package com.tangem.domain.tokens.mock
|
|||
import arrow.core.nonEmptySetOf
|
||||
import com.tangem.domain.models.StatusSource
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.Quote
|
||||
import com.tangem.domain.tokens.model.QuoteStatus
|
||||
import java.math.BigDecimal
|
||||
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
internal object MockQuotes {
|
||||
|
||||
val quote1 = Quote.Value(
|
||||
val quote1 = QuoteStatus(
|
||||
rawCurrencyId = MockTokens.token1.id.rawCurrencyId!!,
|
||||
fiatRate = BigDecimal("1.23"),
|
||||
priceChange = BigDecimal("0.01"),
|
||||
source = StatusSource.ACTUAL,
|
||||
value = QuoteStatus.Data(
|
||||
fiatRate = BigDecimal("1.23"),
|
||||
priceChange = BigDecimal("0.01"),
|
||||
source = StatusSource.ACTUAL,
|
||||
),
|
||||
)
|
||||
|
||||
val quote2 = Quote.Value(
|
||||
val quote2 = QuoteStatus(
|
||||
rawCurrencyId = MockTokens.token2.id.rawCurrencyId!!,
|
||||
fiatRate = BigDecimal("2.34"),
|
||||
priceChange = BigDecimal("-0.02"),
|
||||
source = StatusSource.ACTUAL,
|
||||
value = QuoteStatus.Data(
|
||||
fiatRate = BigDecimal("2.34"),
|
||||
priceChange = BigDecimal("-0.02"),
|
||||
source = StatusSource.ACTUAL,
|
||||
),
|
||||
)
|
||||
|
||||
val quote3 = Quote.Value(
|
||||
val quote3 = QuoteStatus(
|
||||
rawCurrencyId = MockTokens.token3.id.rawCurrencyId!!,
|
||||
fiatRate = BigDecimal("3.45"),
|
||||
priceChange = BigDecimal("0.03"),
|
||||
source = StatusSource.ACTUAL,
|
||||
value = QuoteStatus.Data(
|
||||
fiatRate = BigDecimal("3.45"),
|
||||
priceChange = BigDecimal("0.03"),
|
||||
source = StatusSource.ACTUAL,
|
||||
),
|
||||
)
|
||||
|
||||
val quote4 = Quote.Value(
|
||||
val quote4 = QuoteStatus(
|
||||
rawCurrencyId = MockTokens.token4.id.rawCurrencyId!!,
|
||||
fiatRate = BigDecimal("4.56"),
|
||||
priceChange = BigDecimal("-0.04"),
|
||||
source = StatusSource.ACTUAL,
|
||||
value = QuoteStatus.Data(
|
||||
fiatRate = BigDecimal("4.56"),
|
||||
priceChange = BigDecimal("-0.04"),
|
||||
source = StatusSource.ACTUAL,
|
||||
),
|
||||
)
|
||||
|
||||
val quote5 = Quote.Value(
|
||||
val quote5 = QuoteStatus(
|
||||
rawCurrencyId = MockTokens.token5.id.rawCurrencyId!!,
|
||||
fiatRate = BigDecimal("5.67"),
|
||||
priceChange = BigDecimal("0.05"),
|
||||
source = StatusSource.ACTUAL,
|
||||
value = QuoteStatus.Data(
|
||||
fiatRate = BigDecimal("5.67"),
|
||||
priceChange = BigDecimal("0.05"),
|
||||
source = StatusSource.ACTUAL,
|
||||
),
|
||||
)
|
||||
|
||||
val quote6 = Quote.Value(
|
||||
val quote6 = QuoteStatus(
|
||||
rawCurrencyId = MockTokens.token6.id.rawCurrencyId!!,
|
||||
fiatRate = BigDecimal("6.78"),
|
||||
priceChange = BigDecimal("-0.06"),
|
||||
source = StatusSource.ACTUAL,
|
||||
value = QuoteStatus.Data(
|
||||
fiatRate = BigDecimal("6.78"),
|
||||
priceChange = BigDecimal("-0.06"),
|
||||
source = StatusSource.ACTUAL,
|
||||
),
|
||||
)
|
||||
|
||||
val quote7 = Quote.Value(
|
||||
val quote7 = QuoteStatus(
|
||||
rawCurrencyId = MockTokens.token7.id.rawCurrencyId!!,
|
||||
fiatRate = BigDecimal("7.89"),
|
||||
priceChange = BigDecimal("0.07"),
|
||||
source = StatusSource.ACTUAL,
|
||||
value = QuoteStatus.Data(
|
||||
fiatRate = BigDecimal("7.89"),
|
||||
priceChange = BigDecimal("0.07"),
|
||||
source = StatusSource.ACTUAL,
|
||||
),
|
||||
)
|
||||
|
||||
val quote8 = Quote.Value(
|
||||
val quote8 = QuoteStatus(
|
||||
rawCurrencyId = MockTokens.token8.id.rawCurrencyId!!,
|
||||
fiatRate = BigDecimal("8.90"),
|
||||
priceChange = BigDecimal("-0.08"),
|
||||
source = StatusSource.ACTUAL,
|
||||
value = QuoteStatus.Data(
|
||||
fiatRate = BigDecimal("8.90"),
|
||||
priceChange = BigDecimal("-0.08"),
|
||||
source = StatusSource.ACTUAL,
|
||||
),
|
||||
)
|
||||
|
||||
val quote9 = Quote.Value(
|
||||
val quote9 = QuoteStatus(
|
||||
rawCurrencyId = MockTokens.token9.id.rawCurrencyId!!,
|
||||
fiatRate = BigDecimal("9.01"),
|
||||
priceChange = BigDecimal("0.09"),
|
||||
source = StatusSource.ACTUAL,
|
||||
value = QuoteStatus.Data(
|
||||
fiatRate = BigDecimal("9.01"),
|
||||
priceChange = BigDecimal("0.09"),
|
||||
source = StatusSource.ACTUAL,
|
||||
),
|
||||
)
|
||||
|
||||
val quote10 = Quote.Value(
|
||||
val quote10 = QuoteStatus(
|
||||
rawCurrencyId = MockTokens.token10.id.rawCurrencyId!!,
|
||||
fiatRate = BigDecimal("10.12"),
|
||||
priceChange = BigDecimal("-0.10"),
|
||||
source = StatusSource.ACTUAL,
|
||||
value = QuoteStatus.Data(
|
||||
fiatRate = BigDecimal("10.12"),
|
||||
priceChange = BigDecimal("-0.10"),
|
||||
source = StatusSource.ACTUAL,
|
||||
),
|
||||
)
|
||||
|
||||
val quote11 = Quote.Empty(CryptoCurrency.RawID("null"))
|
||||
val quote11 = QuoteStatus(rawCurrencyId = CryptoCurrency.RawID("null"), value = QuoteStatus.Empty)
|
||||
|
||||
val quotes = nonEmptySetOf(
|
||||
quote1, quote2, quote3, quote4, quote5, quote6, quote7, quote8, quote9, quote10,
|
||||
|
|
|
|||
|
|
@ -4,7 +4,8 @@ import arrow.core.nonEmptyListOf
|
|||
import com.tangem.domain.models.network.NetworkAddress
|
||||
import com.tangem.domain.models.network.NetworkStatus
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.tokens.model.Quote
|
||||
import com.tangem.domain.tokens.model.QuoteStatus
|
||||
import com.tangem.domain.tokens.model.fold
|
||||
import java.math.BigDecimal
|
||||
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
|
|
@ -13,8 +14,8 @@ internal object MockTokensStates {
|
|||
val tokenState1 = CryptoCurrencyStatus(
|
||||
currency = MockTokens.token1,
|
||||
value = CryptoCurrencyStatus.Unreachable(
|
||||
priceChange = MockQuotes.quote1.priceChange,
|
||||
fiatRate = MockQuotes.quote1.fiatRate,
|
||||
priceChange = MockQuotes.quote1.getPriceChange(),
|
||||
fiatRate = MockQuotes.quote1.getFiatRate(),
|
||||
networkAddress = NetworkAddress.Single(
|
||||
defaultAddress = NetworkAddress.Address(value = "mock", NetworkAddress.Address.Type.Primary),
|
||||
),
|
||||
|
|
@ -24,8 +25,8 @@ internal object MockTokensStates {
|
|||
val tokenState2 = CryptoCurrencyStatus(
|
||||
currency = MockTokens.token2,
|
||||
value = CryptoCurrencyStatus.Unreachable(
|
||||
priceChange = MockQuotes.quote2.priceChange,
|
||||
fiatRate = MockQuotes.quote2.fiatRate,
|
||||
priceChange = MockQuotes.quote2.getPriceChange(),
|
||||
fiatRate = MockQuotes.quote2.getFiatRate(),
|
||||
networkAddress = NetworkAddress.Single(
|
||||
defaultAddress = NetworkAddress.Address(value = "mock", NetworkAddress.Address.Type.Primary),
|
||||
),
|
||||
|
|
@ -35,8 +36,8 @@ internal object MockTokensStates {
|
|||
val tokenState3 = CryptoCurrencyStatus(
|
||||
currency = MockTokens.token3,
|
||||
value = CryptoCurrencyStatus.Unreachable(
|
||||
priceChange = MockQuotes.quote3.priceChange,
|
||||
fiatRate = MockQuotes.quote3.fiatRate,
|
||||
priceChange = MockQuotes.quote3.getPriceChange(),
|
||||
fiatRate = MockQuotes.quote3.getFiatRate(),
|
||||
networkAddress = NetworkAddress.Single(
|
||||
defaultAddress = NetworkAddress.Address(value = "mock", NetworkAddress.Address.Type.Primary),
|
||||
),
|
||||
|
|
@ -46,24 +47,24 @@ internal object MockTokensStates {
|
|||
val tokenState4 = CryptoCurrencyStatus(
|
||||
currency = MockTokens.token4,
|
||||
value = CryptoCurrencyStatus.MissedDerivation(
|
||||
priceChange = MockQuotes.quote4.priceChange,
|
||||
fiatRate = MockQuotes.quote4.fiatRate,
|
||||
priceChange = MockQuotes.quote4.getPriceChange(),
|
||||
fiatRate = MockQuotes.quote4.getFiatRate(),
|
||||
),
|
||||
)
|
||||
|
||||
val tokenState5 = CryptoCurrencyStatus(
|
||||
currency = MockTokens.token5,
|
||||
value = CryptoCurrencyStatus.MissedDerivation(
|
||||
priceChange = MockQuotes.quote5.priceChange,
|
||||
fiatRate = MockQuotes.quote5.fiatRate,
|
||||
priceChange = MockQuotes.quote5.getPriceChange(),
|
||||
fiatRate = MockQuotes.quote5.getFiatRate(),
|
||||
),
|
||||
)
|
||||
|
||||
val tokenState6 = CryptoCurrencyStatus(
|
||||
currency = MockTokens.token6,
|
||||
value = CryptoCurrencyStatus.MissedDerivation(
|
||||
priceChange = MockQuotes.quote6.priceChange,
|
||||
fiatRate = MockQuotes.quote6.fiatRate,
|
||||
priceChange = MockQuotes.quote6.getPriceChange(),
|
||||
fiatRate = MockQuotes.quote6.getFiatRate(),
|
||||
),
|
||||
)
|
||||
|
||||
|
|
@ -71,8 +72,8 @@ internal object MockTokensStates {
|
|||
currency = MockTokens.token7,
|
||||
value = CryptoCurrencyStatus.NoAccount(
|
||||
fiatAmount = BigDecimal.ZERO,
|
||||
priceChange = MockQuotes.quote7.priceChange,
|
||||
fiatRate = MockQuotes.quote7.fiatRate,
|
||||
priceChange = MockQuotes.quote7.getPriceChange(),
|
||||
fiatRate = MockQuotes.quote7.getFiatRate(),
|
||||
amountToCreateAccount = MockNetworks.amountToCreateAccount,
|
||||
networkAddress = NetworkAddress.Single(
|
||||
defaultAddress = NetworkAddress.Address(value = "mock", NetworkAddress.Address.Type.Primary),
|
||||
|
|
@ -85,8 +86,8 @@ internal object MockTokensStates {
|
|||
currency = MockTokens.token8,
|
||||
value = CryptoCurrencyStatus.NoAccount(
|
||||
fiatAmount = BigDecimal.ZERO,
|
||||
priceChange = MockQuotes.quote8.priceChange,
|
||||
fiatRate = MockQuotes.quote8.fiatRate,
|
||||
priceChange = MockQuotes.quote8.getPriceChange(),
|
||||
fiatRate = MockQuotes.quote8.getFiatRate(),
|
||||
amountToCreateAccount = MockNetworks.amountToCreateAccount,
|
||||
networkAddress = NetworkAddress.Single(
|
||||
defaultAddress = NetworkAddress.Address(value = "mock", NetworkAddress.Address.Type.Primary),
|
||||
|
|
@ -99,8 +100,8 @@ internal object MockTokensStates {
|
|||
currency = MockTokens.token9,
|
||||
value = CryptoCurrencyStatus.NoAccount(
|
||||
fiatAmount = BigDecimal.ZERO,
|
||||
priceChange = MockQuotes.quote9.priceChange,
|
||||
fiatRate = MockQuotes.quote9.fiatRate,
|
||||
priceChange = MockQuotes.quote9.getPriceChange(),
|
||||
fiatRate = MockQuotes.quote9.getFiatRate(),
|
||||
amountToCreateAccount = MockNetworks.amountToCreateAccount,
|
||||
networkAddress = NetworkAddress.Single(
|
||||
defaultAddress = NetworkAddress.Address(value = "mock", NetworkAddress.Address.Type.Primary),
|
||||
|
|
@ -113,8 +114,8 @@ internal object MockTokensStates {
|
|||
currency = MockTokens.token10,
|
||||
value = CryptoCurrencyStatus.NoAccount(
|
||||
fiatAmount = BigDecimal.ZERO,
|
||||
priceChange = MockQuotes.quote10.priceChange,
|
||||
fiatRate = MockQuotes.quote10.fiatRate,
|
||||
priceChange = MockQuotes.quote10.getPriceChange(),
|
||||
fiatRate = MockQuotes.quote10.getFiatRate(),
|
||||
amountToCreateAccount = MockNetworks.amountToCreateAccount,
|
||||
networkAddress = NetworkAddress.Single(
|
||||
defaultAddress = NetworkAddress.Address(value = "mock", NetworkAddress.Address.Type.Primary),
|
||||
|
|
@ -145,8 +146,8 @@ internal object MockTokensStates {
|
|||
)?.value ?: BigDecimal.ZERO
|
||||
val quote = MockQuotes.quotes.first { it.rawCurrencyId == status.currency.id.rawCurrencyId }
|
||||
|
||||
val value = when (quote) {
|
||||
is Quote.Empty -> CryptoCurrencyStatus.NoQuote(
|
||||
val value = when (val value = quote.value) {
|
||||
is QuoteStatus.Empty -> CryptoCurrencyStatus.NoQuote(
|
||||
amount = status.value.amount!!,
|
||||
pendingTransactions = emptySet(),
|
||||
hasCurrentNetworkTransactions = false,
|
||||
|
|
@ -156,11 +157,11 @@ internal object MockTokensStates {
|
|||
yieldBalance = null,
|
||||
sources = CryptoCurrencyStatus.Sources(),
|
||||
)
|
||||
is Quote.Value -> CryptoCurrencyStatus.Loaded(
|
||||
is QuoteStatus.Data -> CryptoCurrencyStatus.Loaded(
|
||||
amount = amount,
|
||||
fiatAmount = amount * quote.fiatRate,
|
||||
fiatRate = quote.fiatRate,
|
||||
priceChange = quote.priceChange,
|
||||
fiatAmount = amount * value.fiatRate,
|
||||
fiatRate = value.fiatRate,
|
||||
priceChange = value.priceChange,
|
||||
pendingTransactions = emptySet(),
|
||||
hasCurrentNetworkTransactions = false,
|
||||
networkAddress = requireNotNull(networkStatus.value as? NetworkStatus.Verified).address,
|
||||
|
|
@ -187,4 +188,7 @@ internal object MockTokensStates {
|
|||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun QuoteStatus.getPriceChange(): BigDecimal? = fold(onData = { priceChange }, onEmpty = { null })
|
||||
private fun QuoteStatus.getFiatRate(): BigDecimal? = fold(onData = { fiatRate }, onEmpty = { null })
|
||||
}
|
||||
|
|
@ -10,7 +10,8 @@ import com.tangem.core.ui.format.bigdecimal.format
|
|||
import com.tangem.core.ui.format.bigdecimal.percent
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.onramp.model.HotCryptoCurrency
|
||||
import com.tangem.domain.tokens.model.Quote
|
||||
import com.tangem.domain.tokens.model.QuoteStatus
|
||||
import com.tangem.domain.tokens.model.fold
|
||||
import com.tangem.utils.converter.Converter
|
||||
import java.math.BigDecimal
|
||||
|
||||
|
|
@ -30,7 +31,7 @@ internal class HotTokenItemStateConverter(
|
|||
id = value.cryptoCurrency.id.value,
|
||||
iconState = CryptoCurrencyToIconStateConverter().convert(value.cryptoCurrency),
|
||||
titleState = TokenItemState.TitleState.Content(text = stringReference(value.cryptoCurrency.name)),
|
||||
subtitleState = value.quote.getCryptoPriceState(appCurrency),
|
||||
subtitleState = value.quoteStatus.getCryptoPriceState(appCurrency),
|
||||
fiatAmountState = null,
|
||||
subtitle2State = null,
|
||||
onItemClick = onItemClick.let { onItemClick -> { onItemClick(it, value) } },
|
||||
|
|
@ -38,17 +39,17 @@ internal class HotTokenItemStateConverter(
|
|||
)
|
||||
}
|
||||
|
||||
private fun Quote.getCryptoPriceState(appCurrency: AppCurrency): TokenItemState.SubtitleState {
|
||||
return when (this) {
|
||||
is Quote.Empty -> TokenItemState.SubtitleState.Unknown
|
||||
is Quote.Value -> {
|
||||
private fun QuoteStatus.getCryptoPriceState(appCurrency: AppCurrency): TokenItemState.SubtitleState {
|
||||
return fold(
|
||||
onData = {
|
||||
TokenItemState.SubtitleState.CryptoPriceContent(
|
||||
price = fiatRate.getFormattedCryptoPrice(appCurrency),
|
||||
priceChangePercent = priceChange.format { percent() },
|
||||
type = priceChange.getPriceChangeType(),
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
onEmpty = { TokenItemState.SubtitleState.Unknown },
|
||||
)
|
||||
}
|
||||
|
||||
private fun BigDecimal.getFormattedCryptoPrice(appCurrency: AppCurrency): String {
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ import com.tangem.domain.tokens.GetCurrencyCheckUseCase
|
|||
import com.tangem.domain.tokens.GetMultiCryptoCurrencyStatusUseCase
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.tokens.model.FeePaidCurrency
|
||||
import com.tangem.domain.tokens.model.Quote
|
||||
import com.tangem.domain.tokens.model.QuoteStatus
|
||||
import com.tangem.domain.tokens.model.warnings.CryptoCurrencyCheck
|
||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||
import com.tangem.domain.tokens.repository.CurrencyChecksRepository
|
||||
|
|
@ -1034,7 +1034,7 @@ internal class SwapInteractorImpl @AssistedInject constructor(
|
|||
val rates = getQuotes(fromToken.currency.id)
|
||||
val fromTokenSwapInfo = TokenSwapInfo(
|
||||
tokenAmount = amount,
|
||||
amountFiat = rates[fromToken.currency.id]?.fiatRate?.multiply(amount.value)
|
||||
amountFiat = rates[fromToken.currency.id]?.multiply(amount.value)
|
||||
?: BigDecimal.ZERO,
|
||||
cryptoCurrencyStatus = fromToken,
|
||||
)
|
||||
|
|
@ -1130,7 +1130,7 @@ internal class SwapInteractorImpl @AssistedInject constructor(
|
|||
else -> getNativeToken(networkId = fromToken.network.backendId).id
|
||||
}
|
||||
val rates = getQuotes(feeCurrencyId)
|
||||
return rates[feeCurrencyId]?.fiatRate?.let { rate ->
|
||||
return rates[feeCurrencyId]?.let { rate ->
|
||||
fees.map { fee ->
|
||||
rate.multiply(fee).format {
|
||||
fiat(
|
||||
|
|
@ -1233,7 +1233,7 @@ internal class SwapInteractorImpl @AssistedInject constructor(
|
|||
val rates = getQuotes(fromToken.currency.id)
|
||||
val fromTokenSwapInfo = TokenSwapInfo(
|
||||
tokenAmount = amount,
|
||||
amountFiat = rates[fromToken.currency.id]?.fiatRate?.multiply(amount.value)
|
||||
amountFiat = rates[fromToken.currency.id]?.multiply(amount.value)
|
||||
?: BigDecimal.ZERO,
|
||||
cryptoCurrencyStatus = fromToken,
|
||||
)
|
||||
|
|
@ -1307,20 +1307,20 @@ internal class SwapInteractorImpl @AssistedInject constructor(
|
|||
fromTokenInfo = TokenSwapInfo(
|
||||
tokenAmount = fromTokenAmount,
|
||||
cryptoCurrencyStatus = fromTokenStatus,
|
||||
amountFiat = rates[fromToken.id]?.fiatRate?.multiply(fromTokenAmount.value)
|
||||
amountFiat = rates[fromToken.id]?.multiply(fromTokenAmount.value)
|
||||
?: BigDecimal.ZERO,
|
||||
),
|
||||
toTokenInfo = TokenSwapInfo(
|
||||
tokenAmount = toTokenAmount,
|
||||
cryptoCurrencyStatus = toTokenStatus,
|
||||
amountFiat = rates[toToken.id]?.fiatRate?.multiply(toTokenAmount.value)
|
||||
amountFiat = rates[toToken.id]?.multiply(toTokenAmount.value)
|
||||
?: BigDecimal.ZERO,
|
||||
),
|
||||
priceImpact = calculatePriceImpact(
|
||||
fromTokenAmount = fromTokenAmount.value,
|
||||
fromRate = rates[fromToken.id]?.fiatRate?.toDouble() ?: 0.0,
|
||||
fromRate = rates[fromToken.id]?.toDouble() ?: 0.0,
|
||||
toTokenAmount = toTokenAmount.value,
|
||||
toRate = rates[toToken.id]?.fiatRate?.toDouble() ?: 0.0,
|
||||
toRate = rates[toToken.id]?.toDouble() ?: 0.0,
|
||||
),
|
||||
swapDataModel = swapData,
|
||||
txFee = txFeeState,
|
||||
|
|
@ -1795,18 +1795,20 @@ internal class SwapInteractorImpl @AssistedInject constructor(
|
|||
return PriceImpact.Value(value)
|
||||
}
|
||||
|
||||
private suspend fun getQuotes(vararg ids: CryptoCurrency.ID): Map<CryptoCurrency.ID, Quote.Value> {
|
||||
private suspend fun getQuotes(vararg ids: CryptoCurrency.ID): Map<CryptoCurrency.ID, BigDecimal> {
|
||||
val set = ids.mapNotNull { it.rawCurrencyId }
|
||||
.toSet()
|
||||
.getQuotesOrEmpty()
|
||||
.filterIsInstance<Quote.Value>()
|
||||
|
||||
return ids
|
||||
.mapNotNull { id -> set.find { it.rawCurrencyId == id.rawCurrencyId }?.let { id to it } }
|
||||
.mapNotNull { id ->
|
||||
set.find { it.rawCurrencyId == id.rawCurrencyId && it.value is QuoteStatus.Data }
|
||||
?.let { id to (it.value as QuoteStatus.Data).fiatRate }
|
||||
}
|
||||
.toMap()
|
||||
}
|
||||
|
||||
private suspend fun Set<CryptoCurrency.RawID>.getQuotesOrEmpty(): Set<Quote> {
|
||||
private suspend fun Set<CryptoCurrency.RawID>.getQuotesOrEmpty(): Set<QuoteStatus> {
|
||||
return runCatching { quotesRepositoryV2.getMultiQuoteSyncOrNull(currenciesIds = this) }
|
||||
.getOrNull()
|
||||
.orEmpty()
|
||||
|
|
|
|||
|
|
@ -17,8 +17,9 @@ import com.tangem.core.ui.utils.toDateFormatWithTodayYesterday
|
|||
import com.tangem.core.ui.utils.toTimeFormat
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.Quote
|
||||
import com.tangem.domain.tokens.model.QuoteStatus
|
||||
import com.tangem.domain.tokens.model.analytics.TokenExchangeAnalyticsEvent
|
||||
import com.tangem.domain.tokens.model.mapData
|
||||
import com.tangem.feature.swap.domain.models.domain.ExchangeStatus
|
||||
import com.tangem.feature.swap.domain.models.domain.ExchangeStatus.Companion.isFailed
|
||||
import com.tangem.feature.swap.domain.models.domain.ExchangeStatusModel
|
||||
|
|
@ -57,7 +58,7 @@ internal class TokenDetailsSwapTransactionsStateConverter(
|
|||
|
||||
fun convert(
|
||||
savedTransactions: List<SavedSwapTransactionListModel>,
|
||||
quotes: Set<Quote>,
|
||||
quoteStatuses: Set<QuoteStatus>,
|
||||
): PersistentList<ExchangeUM> {
|
||||
val result = mutableListOf<ExchangeUM>()
|
||||
|
||||
|
|
@ -73,12 +74,17 @@ internal class TokenDetailsSwapTransactionsStateConverter(
|
|||
val fromAmount = transaction.fromCryptoAmount
|
||||
var toFiatAmount: BigDecimal? = null
|
||||
var fromFiatAmount: BigDecimal? = null
|
||||
quotes.forEach { quote ->
|
||||
if (quote is Quote.Value && quote.rawCurrencyId == toCryptoCurrencyRawId) {
|
||||
toFiatAmount = quote.fiatRate.multiply(toAmount)
|
||||
quoteStatuses.forEach { quote ->
|
||||
quote.mapData {
|
||||
if (quote.rawCurrencyId == toCryptoCurrencyRawId) {
|
||||
toFiatAmount = fiatRate.multiply(toAmount)
|
||||
}
|
||||
}
|
||||
if (quote is Quote.Value && quote.rawCurrencyId == fromCryptoCurrencyRawId) {
|
||||
fromFiatAmount = quote.fiatRate.multiply(fromAmount)
|
||||
|
||||
quote.mapData {
|
||||
if (quote.rawCurrencyId == fromCryptoCurrencyRawId) {
|
||||
fromFiatAmount = fiatRate.multiply(fromAmount)
|
||||
}
|
||||
}
|
||||
}
|
||||
val statusModel = transaction.status
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import com.tangem.domain.appcurrency.model.AppCurrency
|
|||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.quotes.QuotesRepositoryV2
|
||||
import com.tangem.domain.tokens.AddCryptoCurrenciesUseCase
|
||||
import com.tangem.domain.tokens.model.Quote
|
||||
import com.tangem.domain.tokens.model.QuoteStatus
|
||||
import com.tangem.domain.tokens.model.analytics.TokenExchangeAnalyticsEvent
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.feature.swap.domain.SwapTransactionRepository
|
||||
|
|
@ -66,7 +66,7 @@ internal class ExchangeStatusFactory @AssistedInject constructor(
|
|||
|
||||
getExchangeStatusState(
|
||||
savedTransactions = savedTransactions,
|
||||
quotes = quotes,
|
||||
quoteStatuses = quotes,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -155,7 +155,7 @@ internal class ExchangeStatusFactory @AssistedInject constructor(
|
|||
|
||||
private fun getExchangeStatusState(
|
||||
savedTransactions: List<SavedSwapTransactionListModel>?,
|
||||
quotes: Set<Quote>,
|
||||
quoteStatuses: Set<QuoteStatus>,
|
||||
): PersistentList<ExchangeUM> {
|
||||
if (savedTransactions == null) {
|
||||
return persistentListOf()
|
||||
|
|
@ -163,7 +163,7 @@ internal class ExchangeStatusFactory @AssistedInject constructor(
|
|||
|
||||
return swapTransactionsStateConverter.convert(
|
||||
savedTransactions = savedTransactions,
|
||||
quotes = quotes,
|
||||
quoteStatuses = quoteStatuses,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -187,7 +187,7 @@ internal class ExchangeStatusFactory @AssistedInject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private suspend fun Set<CryptoCurrency.ID>.getQuotesOrEmpty(): Set<Quote> {
|
||||
private suspend fun Set<CryptoCurrency.ID>.getQuotesOrEmpty(): Set<QuoteStatus> {
|
||||
val rawIds = mapNotNull { it.rawCurrencyId }.toSet()
|
||||
|
||||
return runCatching { quotesRepositoryV2.getMultiQuoteSyncOrNull(currenciesIds = rawIds) }
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue