Updated on 2026-08-14

This commit is contained in:
Tangem 2025-02-03 12:24:11 +03:00
parent dfa6798f07
commit 5883823eb3
71 changed files with 221 additions and 285 deletions

View file

@ -13,6 +13,7 @@ import com.tangem.core.decompose.context.child
import com.tangem.core.decompose.model.getOrCreateModel
import com.tangem.core.ui.res.LocalMainBottomSheetColor
import com.tangem.core.ui.res.TangemTheme
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.features.markets.details.MarketsTokenDetailsComponent
import com.tangem.features.markets.details.MarketsTokenDetailsComponent.Params
import com.tangem.features.markets.details.impl.analytics.MarketDetailsAnalyticsEvent
@ -38,7 +39,7 @@ internal class DefaultMarketsTokenDetailsComponent @AssistedInject constructor(
// applying l2 compatibility
private val updatedParams = params.copy(
token = params.token.copy(
id = getTokenIdIfL2Network(params.token.id),
id = CryptoCurrency.RawID(getTokenIdIfL2Network(params.token.id.value)),
),
)
private val analyticsParams = params.analyticsParams

View file

@ -134,7 +134,7 @@ internal class MarketsTokenDetailsModel @Inject constructor(
modelScope.launch {
sendFeedbackEmailUseCase(
type = FeedbackEmailType.CurrencyDescriptionError(
currencyId = params.token.id,
currencyId = params.token.id.value,
currencyName = params.token.name,
),
)

View file

@ -9,6 +9,7 @@ import com.tangem.domain.tokens.GetAllWalletsCryptoCurrencyStatusesUseCase
import com.tangem.domain.tokens.GetCryptoCurrencyActionsUseCase
import com.tangem.domain.tokens.GetWalletTotalBalanceUseCase
import com.tangem.domain.tokens.error.TokenListError
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.tokens.model.TotalFiatBalance
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.UserWalletId
@ -37,7 +38,7 @@ internal class PortfolioDataLoader @Inject constructor(
/** Load data by [currencyRawId] */
@OptIn(ExperimentalCoroutinesApi::class)
fun load(currencyRawId: String): Flow<PortfolioData> {
fun load(currencyRawId: CryptoCurrency.RawID): Flow<PortfolioData> {
return combine(
flow = getAllWalletsCryptoCurrenciesData(currencyRawId = currencyRawId),
flow2 = getSelectedAppCurrencyFlow(),
@ -62,7 +63,7 @@ internal class PortfolioDataLoader @Inject constructor(
@OptIn(ExperimentalCoroutinesApi::class)
private fun getAllWalletsCryptoCurrenciesData(
currencyRawId: String,
currencyRawId: CryptoCurrency.RawID,
): Flow<Map<UserWallet, List<PortfolioData.CryptoCurrencyData>>> {
return getAllWalletsCryptoCurrencyStatusesUseCase(currencyRawId)
.distinctUntilChanged()

View file

@ -24,7 +24,7 @@ internal class SelectNetworkUMConverter(
override fun convert(value: TokenMarketParams): SelectNetworkUM {
return SelectNetworkUM(
tokenId = value.id,
tokenId = value.id.value,
iconUrl = value.imageUrl,
tokenName = value.name,
tokenCurrencySymbol = value.symbol,

View file

@ -9,6 +9,7 @@ import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.markets.GetMarketsTokenListFlowUseCase
import com.tangem.domain.markets.TokenMarket
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.features.markets.entry.BottomSheetState
import com.tangem.features.markets.tokenlist.impl.analytics.MarketsListAnalyticsEvent
import com.tangem.features.markets.tokenlist.impl.model.statemanager.MarketsListBatchFlowManager
@ -48,7 +49,7 @@ internal class MarketsListModel @Inject constructor(
initialValue = AppCurrency.Default,
)
private val visibleItemIds = MutableStateFlow<List<String>>(emptyList())
private val visibleItemIds = MutableStateFlow<List<CryptoCurrency.RawID>>(emptyList())
private val marketsListUMStateManager = MarketsListUMStateManager(
currentVisibleIds = Provider { visibleItemIds.value },
@ -72,8 +73,8 @@ internal class MarketsListModel @Inject constructor(
getMarketsTokenListFlowUseCase = getMarketsTokenListFlowUseCase,
batchFlowType = GetMarketsTokenListFlowUseCase.BatchFlowType.Search,
currentAppCurrency = Provider { currentAppCurrency.value },
currentTrendInterval = Provider { marketsListUMStateManager.selectedInterval }, // FIXME fix on backend
currentSortByType = Provider { SortByTypeUM.Rating }, // FIXME maybe fix on backend
currentTrendInterval = Provider { marketsListUMStateManager.selectedInterval },
currentSortByType = Provider { SortByTypeUM.Rating },
currentSearchText = Provider { marketsListUMStateManager.searchQuery },
modelScope = modelScope,
dispatchers = dispatchers,

View file

@ -2,6 +2,7 @@ package com.tangem.features.markets.tokenlist.impl.model.statemanager
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.markets.*
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.features.markets.tokenlist.impl.model.converters.MarketsTokenItemConverter
import com.tangem.features.markets.tokenlist.impl.model.utils.logAction
import com.tangem.features.markets.tokenlist.impl.model.utils.logStatus
@ -302,7 +303,7 @@ internal class MarketsListBatchFlowManager(
}
}
fun getBatchKeysByItemIds(ids: List<String>): Set<Int> {
fun getBatchKeysByItemIds(ids: List<CryptoCurrency.RawID>): Set<Int> {
val currentData = batchFlow.state.value.data
return currentData
@ -311,7 +312,7 @@ internal class MarketsListBatchFlowManager(
.toSet()
}
fun getTokenById(id: String): TokenMarket? {
fun getTokenById(id: CryptoCurrency.RawID): TokenMarket? {
return batchFlow.state.value.data.map { it.data }.flatten().find { it.id == id }
}

View file

@ -6,6 +6,7 @@ import com.tangem.core.ui.components.fields.entity.SearchBarUM
import com.tangem.core.ui.event.consumedEvent
import com.tangem.core.ui.event.triggeredEvent
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.features.markets.impl.R
import com.tangem.features.markets.tokenlist.impl.ui.state.*
import com.tangem.utils.Provider
@ -18,9 +19,9 @@ import kotlinx.coroutines.flow.update
@Stable
internal class MarketsListUMStateManager(
private val currentVisibleIds: Provider<List<String>>,
private val currentVisibleIds: Provider<List<CryptoCurrency.RawID>>,
private val onLoadMoreUiItems: () -> Unit,
private val visibleItemsChanged: (itemsKeys: List<String>) -> Unit,
private val visibleItemsChanged: (itemsKeys: List<CryptoCurrency.RawID>) -> Unit,
private val onRetryButtonClicked: () -> Unit,
private val onTokenClick: (MarketsListItemUM) -> Unit,
) {

View file

@ -36,6 +36,7 @@ import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.LocalMainBottomSheetColor
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.features.markets.entry.BottomSheetState
import com.tangem.features.markets.impl.R
import com.tangem.features.markets.tokenlist.impl.ui.components.MarketsListLazyColumn
@ -298,7 +299,7 @@ private fun Preview() {
items = MarketChartListItemPreviewDataProvider().values
.flatMap { item -> List(size = 10) { item } }
.mapIndexed { index, item ->
item.copy(id = index.toString())
item.copy(id = CryptoCurrency.RawID(index.toString()))
}
.toImmutableList(),
showUnder100kTokensNotification = false,

View file

@ -17,6 +17,7 @@ import com.tangem.core.ui.event.EventEffect
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.features.markets.impl.R
import com.tangem.features.markets.tokenlist.impl.ui.state.ListUM
import kotlinx.coroutines.launch
@ -88,7 +89,7 @@ internal fun MarketsListLazyColumn(
is ListUM.Content -> {
items(
items = state.items,
key = { it.id + TOKEN_LAZY_LIST_ID_SEPARATOR + it.marketCap.toString() },
key = { it.id.value + TOKEN_LAZY_LIST_ID_SEPARATOR + it.marketCap.toString() },
) { item ->
MarketsListItem(
model = item,
@ -193,6 +194,7 @@ private fun VisibleItemsTracker(listState: LazyListState, state: ListUM) {
derivedStateOf {
listState.layoutInfo.visibleItemsInfo.mapNotNull {
(it.key as? String)?.split(TOKEN_LAZY_LIST_ID_SEPARATOR)?.first()
?.let { rawId -> CryptoCurrency.RawID(rawId) }
}
}
}

View file

@ -4,13 +4,14 @@ package com.tangem.features.markets.tokenlist.impl.ui.preview
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
import com.tangem.common.ui.charts.state.MarketChartRawData
import com.tangem.core.ui.components.marketprice.PriceChangeType
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.features.markets.tokenlist.impl.ui.state.MarketsListItemUM
import kotlinx.collections.immutable.persistentListOf
internal class MarketChartListItemPreviewDataProvider : CollectionPreviewParameterProvider<MarketsListItemUM>(
collection = listOf(
MarketsListItemUM(
id = "1",
id = CryptoCurrency.RawID("1"),
name = "Bitcoin",
currencySymbol = "BTC",
iconUrl = "",
@ -25,7 +26,7 @@ internal class MarketChartListItemPreviewDataProvider : CollectionPreviewParamet
isUnder100kMarketCap = false,
),
MarketsListItemUM(
id = "1",
id = CryptoCurrency.RawID("1"),
name = "Bitcoin",
currencySymbol = "BTC",
iconUrl = null,
@ -38,7 +39,7 @@ internal class MarketChartListItemPreviewDataProvider : CollectionPreviewParamet
isUnder100kMarketCap = false,
),
MarketsListItemUM(
id = "1",
id = CryptoCurrency.RawID("1"),
name = "Bitcoin Bitcoin Bitcoin Bitcoin Bitcoin Bitcoin Bitcoin",
currencySymbol = "BTC",
iconUrl = null,
@ -53,7 +54,7 @@ internal class MarketChartListItemPreviewDataProvider : CollectionPreviewParamet
isUnder100kMarketCap = false,
),
MarketsListItemUM(
id = "1",
id = CryptoCurrency.RawID("1"),
name = "Bitcoin",
currencySymbol = "BTC",
iconUrl = null,
@ -68,7 +69,7 @@ internal class MarketChartListItemPreviewDataProvider : CollectionPreviewParamet
isUnder100kMarketCap = false,
),
MarketsListItemUM(
id = "1",
id = CryptoCurrency.RawID("1"),
name = "Bitcoin",
currencySymbol = "BTC",
iconUrl = null,
@ -83,7 +84,7 @@ internal class MarketChartListItemPreviewDataProvider : CollectionPreviewParamet
isUnder100kMarketCap = false,
),
MarketsListItemUM(
id = "1",
id = CryptoCurrency.RawID("1"),
name = "Bitcoin",
currencySymbol = "BTC",
iconUrl = null,

View file

@ -4,10 +4,11 @@ import androidx.compose.runtime.Immutable
import com.tangem.common.ui.charts.state.MarketChartLook
import com.tangem.common.ui.charts.state.MarketChartRawData
import com.tangem.core.ui.components.marketprice.PriceChangeType
import com.tangem.domain.tokens.model.CryptoCurrency
@Immutable
data class MarketsListItemUM(
val id: String,
val id: CryptoCurrency.RawID,
val name: String,
val currencySymbol: String,
val iconUrl: String?,

View file

@ -6,6 +6,7 @@ import com.tangem.core.ui.components.fields.entity.SearchBarUM
import com.tangem.core.ui.event.StateEvent
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.features.markets.impl.R
import kotlinx.collections.immutable.ImmutableList
@ -44,7 +45,7 @@ sealed class ListUM {
val showUnder100kTokensNotification: Boolean,
val showUnder100kTokensNotificationWasHidden: Boolean,
val loadMore: () -> Unit,
val visibleIdsChanged: (List<String>) -> Unit,
val visibleIdsChanged: (List<CryptoCurrency.RawID>) -> Unit,
val onShowTokensUnder100kClicked: () -> Unit,
val triggerScrollReset: StateEvent<Unit>,
val onItemClick: (MarketsListItemUM) -> Unit,

View file

@ -229,7 +229,7 @@ internal class FeeStateFactory(
symbol = this.token.symbol,
contractAddress = this.token.contractAddress,
decimals = this.token.decimals,
id = this.token.id.rawCurrencyId,
id = this.token.id.rawCurrencyId?.value,
),
)
}

View file

@ -89,7 +89,7 @@ internal class RewardsValidatorStateConverter(
formattedCryptoAmount = cryptoAmount,
fiatAmount = fiatValue,
formattedFiatAmount = formattedFiatAmount,
rawCurrencyId = cryptoCurrency.id.rawCurrencyId,
rawCurrencyId = cryptoCurrency.id.rawCurrencyId?.value,
pendingActions = balance.pendingActions.toPersistentList(),
isClickable = true,
type = balance.type,

View file

@ -15,6 +15,7 @@ import com.tangem.domain.staking.model.stakekit.action.StakingActionCommonType
import com.tangem.domain.staking.model.stakekit.transaction.ActionParams
import com.tangem.domain.staking.model.stakekit.transaction.StakingGasEstimate
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.tokens.model.staking.getCurrentToken
import com.tangem.domain.transaction.error.GetFeeError
import com.tangem.domain.transaction.usecase.GetFeeUseCase
import com.tangem.domain.wallets.models.UserWallet

View file

@ -18,6 +18,7 @@ import com.tangem.domain.staking.model.stakekit.transaction.StakingTransaction
import com.tangem.domain.staking.model.stakekit.transaction.StakingTransactionStatus
import com.tangem.domain.staking.model.stakekit.transaction.StakingTransactionType
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.tokens.model.staking.getCurrentToken
import com.tangem.domain.transaction.error.SendTransactionError
import com.tangem.domain.transaction.usecase.SendTransactionUseCase
import com.tangem.domain.txhistory.usecase.GetExplorerTransactionUrlUseCase

View file

@ -2134,14 +2134,17 @@ internal class SwapInteractorImpl @AssistedInject constructor(
}
private suspend fun getQuotes(vararg ids: CryptoCurrency.ID): Map<CryptoCurrency.ID, Quote.Value> {
val set = ids.toSet().getQuotesOrEmpty(false).filterIsInstance<Quote.Value>()
val set = ids.mapNotNull { it.rawCurrencyId }
.toSet()
.getQuotesOrEmpty(false)
.filterIsInstance<Quote.Value>()
return ids
.mapNotNull { id -> set.find { it.rawCurrencyId == id.rawCurrencyId }?.let { id to it } }
.toMap()
}
private suspend fun Set<CryptoCurrency.ID>.getQuotesOrEmpty(refresh: Boolean): Set<Quote> {
private suspend fun Set<CryptoCurrency.RawID>.getQuotesOrEmpty(refresh: Boolean): Set<Quote> {
return try {
quotesRepository.getQuotesSync(this, refresh)
} catch (t: Throwable) {

View file

@ -205,7 +205,8 @@ internal class ExchangeStatusFactory @AssistedInject constructor(
private suspend fun Set<CryptoCurrency.ID>.getQuotesOrEmpty(refresh: Boolean): Set<Quote> {
return try {
quotesRepository.getQuotesSync(this, refresh)
val rawIds = mapNotNull { it.rawCurrencyId }.toSet()
quotesRepository.getQuotesSync(rawIds, refresh)
} catch (t: Throwable) {
emptySet()
}