Updated on 2026-08-14

This commit is contained in:
Tangem 2024-03-04 19:40:21 +00:00
parent 95f1c123ba
commit a2d8d157bc
8 changed files with 28 additions and 13 deletions

View file

@ -29,7 +29,7 @@ internal class DefaultTokensListRepository(
private val testnetTokensStorage: TestnetTokensStorage,
) : TokensListRepository {
override fun getAvailableTokens(searchText: String?): Flow<PagingData<Token>> {
override fun getAvailableTokens(searchText: String?, needFilterExcluded: Boolean): Flow<PagingData<Token>> {
return Pager(
config = PagingConfig(
pageSize = 100,
@ -42,6 +42,7 @@ internal class DefaultTokensListRepository(
dispatchers = dispatchers,
getSelectedWalletSyncUseCase = getSelectedWalletSyncUseCase,
searchText = searchText,
needFilterExcluded = needFilterExcluded,
)
getSelectedWalletSyncUseCase().fold(

View file

@ -27,8 +27,10 @@ internal class TangemApiTokensPagingSource(
private val dispatchers: CoroutineDispatcherProvider,
private val getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase,
private val searchText: String?,
needFilterExcluded: Boolean = false,
) : PagingSource<Int, Token>() {
private val coinsResponseConverter = CoinsResponseConverter(needFilterExcluded)
override fun getRefreshKey(state: PagingState<Int, Token>): Int? {
return state.anchorPosition?.let { anchorPosition ->
state.closestPageToPosition(anchorPosition)?.prevKey?.plus(other = 1)
@ -41,7 +43,7 @@ internal class TangemApiTokensPagingSource(
return runCatching(dispatchers.io) {
val supportedBlockchains = getSelectedWalletSyncUseCase().fold(
ifLeft = { Blockchain.values().toList() },
ifLeft = { Blockchain.entries },
ifRight = { it.scanResponse.card.supportedBlockchains(it.scanResponse.cardTypesResolver) },
)
@ -55,7 +57,7 @@ internal class TangemApiTokensPagingSource(
}.fold(
onSuccess = { response ->
LoadResult.Page(
data = CoinsResponseConverter.convert(response),
data = coinsResponseConverter.convert(response),
prevKey = if (page == 0) null else page.minus(other = 1),
nextKey = if (response.coins.isEmpty()) null else page.plus(other = 1),
)

View file

@ -3,6 +3,7 @@ package com.tangem.tap.features.tokens.impl.data.converters
import com.tangem.blockchain.common.Blockchain
import com.tangem.datasource.api.tangemTech.models.CoinsResponse
import com.tangem.domain.common.extensions.fromNetworkId
import com.tangem.domain.common.extensions.isSupportedInApp
import com.tangem.tap.features.tokens.impl.domain.models.Token
import com.tangem.utils.converter.Converter
@ -11,9 +12,7 @@ import com.tangem.utils.converter.Converter
*
[REDACTED_AUTHOR]
*/
internal object CoinsResponseConverter : Converter<CoinsResponse, List<Token>> {
private const val DEFAULT_IMAGE_HOST = "https://s3.eu-central-1.amazonaws.com/tangem.api/coins/"
internal class CoinsResponseConverter(val needFilterExcluded: Boolean) : Converter<CoinsResponse, List<Token>> {
override fun convert(value: CoinsResponse): List<Token> {
return value.coins.map { token ->
@ -25,6 +24,10 @@ internal object CoinsResponseConverter : Converter<CoinsResponse, List<Token>> {
networks = token.networks.mapNotNull { network ->
val blockchain = Blockchain.fromNetworkId(network.networkId) ?: return@mapNotNull null
if (needFilterExcluded && !blockchain.isSupportedInApp()) {
return@mapNotNull null
}
// filter tokens, if contractAddress != null, assume that it is a token
if (network.contractAddress != null &&
!blockchain.canHandleTokens()
@ -47,4 +50,8 @@ internal object CoinsResponseConverter : Converter<CoinsResponse, List<Token>> {
fun getIconUrl(id: String, imageHost: String? = null): String {
return "${imageHost ?: DEFAULT_IMAGE_HOST}large/$id.png"
}
private companion object {
const val DEFAULT_IMAGE_HOST = "https://s3.eu-central-1.amazonaws.com/tangem.api/coins/"
}
}

View file

@ -13,13 +13,14 @@ import com.tangem.utils.converter.Converter
*/
internal object TestnetTokensConfigConverter : Converter<TestnetTokensConfig, List<Token>> {
private val coinsResponseConverter = CoinsResponseConverter(needFilterExcluded = false)
override fun convert(value: TestnetTokensConfig): List<Token> {
return value.tokens.map { token ->
Token(
id = token.id,
name = token.name,
symbol = token.symbol,
iconUrl = CoinsResponseConverter.getIconUrl(token.id),
iconUrl = coinsResponseConverter.getIconUrl(token.id),
networks = token.networks?.mapNotNull { network ->
val blockchain = Blockchain.fromNetworkId(network.id) ?: return@mapNotNull null
@ -27,7 +28,7 @@ internal object TestnetTokensConfigConverter : Converter<TestnetTokensConfig, Li
id = network.id,
blockchain = blockchain,
address = network.address,
iconUrl = CoinsResponseConverter.getIconUrl(network.id),
iconUrl = coinsResponseConverter.getIconUrl(network.id),
decimalCount = network.decimalCount,
)
}.orEmpty(),

View file

@ -11,7 +11,10 @@ import kotlinx.coroutines.flow.Flow
*/
internal class DefaultTokensListInteractor(private val repository: TokensListRepository) : TokensListInteractor {
override fun getTokensList(searchText: String): Flow<PagingData<Token>> {
return repository.getAvailableTokens(searchText = searchText.ifBlank(defaultValue = { null }))
override fun getTokensList(searchText: String, needFilterExcluded: Boolean): Flow<PagingData<Token>> {
return repository.getAvailableTokens(
searchText = searchText.ifBlank(defaultValue = { null }),
needFilterExcluded = needFilterExcluded,
)
}
}

View file

@ -12,5 +12,5 @@ import kotlinx.coroutines.flow.Flow
internal interface TokensListInteractor {
/** Get tokens list using filter by text [searchText] */
fun getTokensList(searchText: String): Flow<PagingData<Token>>
fun getTokensList(searchText: String, needFilterExcluded: Boolean): Flow<PagingData<Token>>
}

View file

@ -15,8 +15,9 @@ internal interface TokensListRepository {
* Get available tokens list
*
* @param searchText search text
* @param needFilterExcluded flag that determines if excluded tokens should be filtered
*
* @throws com.tangem.datasource.api.common.response.ApiResponseError
*/
fun getAvailableTokens(searchText: String?): Flow<PagingData<Token>>
fun getAvailableTokens(searchText: String?, needFilterExcluded: Boolean): Flow<PagingData<Token>>
}

View file

@ -250,7 +250,7 @@ internal class TokensListViewModel @Inject constructor(
}
private fun getTokensListBySearchText(text: String): Flow<PagingData<TokenItemState>> {
return interactor.getTokensList(searchText = text)
return interactor.getTokensList(searchText = text, needFilterExcluded = !isManageAccess)
.mapToTokenItemState()
.cachedIn(viewModelScope)
}