Updated on 2026-08-14

This commit is contained in:
Tangem 2024-07-23 12:02:56 +03:00
parent 4ec02d0447
commit f426a1f922
26 changed files with 748 additions and 247 deletions

View file

@ -10,7 +10,7 @@ import com.tangem.domain.markets.repositories.MarketsTokenRepository
import com.tangem.pagination.*
import com.tangem.pagination.fetcher.LimitOffsetBatchFetcher
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.*
import java.util.concurrent.atomic.AtomicLong
internal class DefaultMarketsTokenRepository(
private val marketsApi: TangemTechMarketsApi,
@ -20,42 +20,61 @@ internal class DefaultMarketsTokenRepository(
private val tokenListConverter = TokenMarketListConverter()
private val tokenMarketsFetcher
get() = LimitOffsetBatchFetcher(
prefetchDistance = 150,
batchSize = 100,
subFetcher = object : LimitOffsetBatchFetcher.SubFetcher<TokenMarketListConfig, List<TokenMarket>> {
private fun createTokenMarketsFetcher(firstBatchSize: Int, nextBatchSize: Int) = LimitOffsetBatchFetcher(
prefetchDistance = firstBatchSize,
batchSize = nextBatchSize,
subFetcher = object : LimitOffsetBatchFetcher.SubFetcher<TokenMarketListConfig, List<TokenMarket>> {
var requestTimeStamp: Long? = null // TODO when backend is ready
val requestTimeStamp = AtomicLong(0)
override suspend fun fetch(
request: LimitOffsetBatchFetcher.Request<TokenMarketListConfig>,
lastResult: BatchFetchResult<List<TokenMarket>>?,
): BatchFetchResult<List<TokenMarket>> {
val res = retryOnError(priority = true) {
marketsApi.getCoinsList(
currency = request.params.fiatPriceCurrency,
interval = request.params.priceChangeInterval.toRequestParam(),
order = request.params.order.toRequestParam(),
search = request.params.searchText,
generalCoins = request.params.showUnder100kMarketCapTokens.not(),
offset = request.offset,
limit = request.limit,
).getOrThrow()
}
override suspend fun fetch(
request: LimitOffsetBatchFetcher.Request<TokenMarketListConfig>,
lastResult: BatchFetchResult<List<TokenMarket>>?,
isFirstBatchFetching: Boolean,
): BatchFetchResult<List<TokenMarket>> {
val searchText =
if (request.params.searchText.isNullOrBlank()) null else request.params.searchText
val last = res.tokens.size < request.limit
return BatchFetchResult.Success(
data = tokenListConverter.convert(res),
last = last,
)
val requestCall = suspend {
marketsApi.getCoinsList(
currency = request.params.fiatPriceCurrency,
interval = request.params.priceChangeInterval.toRequestParam(),
order = request.params.order.toRequestParam(),
search = searchText,
generalCoins = request.params.showUnder100kMarketCapTokens.not(),
offset = request.offset,
limit = request.limit,
).getOrThrow()
}
},
)
// we shouldn't infinitely retry on the first batch request
val res = if (isFirstBatchFetching) {
requestCall()
} else {
retryOnError(priority = true) {
requestCall()
}
}
if (isFirstBatchFetching) {
requestTimeStamp.set(0) // TODO when backend is ready
}
val last = res.tokens.size < request.limit
return BatchFetchResult.Success(
data = tokenListConverter.convert(res),
last = last,
empty = res.tokens.isEmpty(),
)
}
},
)
override fun getTokenListFlow(
batchingContext: BatchingContext<Int, TokenMarketListConfig, TokenMarketUpdateRequest>,
firstBatchSize: Int,
nextBatchSize: Int,
): BatchFlow<Int, List<TokenMarket>, TokenMarketUpdateRequest> {
val tokenMarketsUpdateFetcher = MarketsBatchUpdateFetcher(
tangemTechApi = tangemTechApi,
@ -66,7 +85,7 @@ internal class DefaultMarketsTokenRepository(
fetchDispatcher = dispatcherProvider.io,
context = batchingContext,
generateNewKey = { it.size },
batchFetcher = tokenMarketsFetcher,
batchFetcher = createTokenMarketsFetcher(firstBatchSize = firstBatchSize, nextBatchSize = nextBatchSize),
updateFetcher = tokenMarketsUpdateFetcher,
).toBatchFlow()
}

View file

@ -9,6 +9,14 @@ import com.tangem.utils.converter.Converter
class TokenMarketListConverter : Converter<TokenMarketListResponse, List<TokenMarket>> {
override fun convert(value: TokenMarketListResponse): List<TokenMarket> {
val imageHost = value.imageHost ?: run {
if (value.tokens.isEmpty()) {
return emptyList()
} else {
error("imageHost cannot be null")
}
}
return value.tokens.map { token ->
TokenMarket(
id = token.id,
@ -16,7 +24,7 @@ class TokenMarketListConverter : Converter<TokenMarketListResponse, List<TokenMa
symbol = token.symbol,
marketRating = token.marketRating,
marketCap = token.marketCap,
imageHost = value.imageHost,
imageHost = imageHost,
tokenQuotes = TokenQuotes(
currentPrice = token.currentPrice,
priceChanges = mapOf(