Updated on 2026-08-14

This commit is contained in:
Tangem 2025-05-23 11:16:28 +03:00
commit ca49abf2b1
892 changed files with 17979 additions and 6555 deletions

View file

@ -15,6 +15,10 @@ dependencies {
implementation(projects.core.ui)
/** Domain models */
api(projects.domain.models)
implementation(projects.domain.tokens.models)
implementation(projects.domain.wallets.models)
/** Compose */
implementation(deps.compose.runtime)
}

View file

@ -2,7 +2,7 @@ package com.tangem.features.tokendetails
import com.tangem.core.decompose.factory.ComponentFactory
import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.wallets.models.UserWalletId
interface TokenDetailsComponent : ComposableContentComponent {

View file

@ -0,0 +1,10 @@
package com.tangem.features.tokendetails.deeplink
import kotlinx.coroutines.CoroutineScope
interface TokenDetailsDeepLinkHandler {
interface Factory {
fun create(coroutineScope: CoroutineScope, queryParams: Map<String, String>): TokenDetailsDeepLinkHandler
}
}

View file

@ -87,6 +87,7 @@ dependencies {
implementation(projects.domain.promo)
implementation(projects.domain.promo.models)
implementation(projects.domain.quotes)
implementation(projects.domain.notifications.models)
/** Temp dependency to swap domain */
implementation(projects.features.swap.domain)

View file

@ -5,6 +5,7 @@ import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.arkivanov.essenty.lifecycle.subscribe
import com.tangem.common.routing.RoutingFeatureToggle
import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.decompose.context.child
import com.tangem.core.decompose.model.getOrCreateModel
@ -12,7 +13,7 @@ import com.tangem.core.deeplink.DeepLinksRegistry
import com.tangem.core.deeplink.global.BuyCurrencyDeepLink
import com.tangem.core.deeplink.utils.registerDeepLinks
import com.tangem.core.ui.components.NavigationBar3ButtonsScrim
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsModel
import com.tangem.feature.tokendetails.presentation.tokendetails.ui.TokenDetailsScreen
import com.tangem.features.markets.token.block.TokenMarketBlockComponent
@ -32,6 +33,7 @@ internal class DefaultTokenDetailsComponent @AssistedInject constructor(
txHistoryComponentFactory: TxHistoryComponent.Factory,
txHistoryFeatureToggles: TxHistoryFeatureToggles,
onrampFeatureToggles: OnrampFeatureToggles,
routingFeatureToggle: RoutingFeatureToggle,
deepLinksRegistry: DeepLinksRegistry,
) : TokenDetailsComponent, AppComponentContext by appComponentContext {
@ -51,20 +53,22 @@ internal class DefaultTokenDetailsComponent @AssistedInject constructor(
onResume = model::onResume,
)
val deeplinks = buildList {
if (!onrampFeatureToggles.isFeatureEnabled) {
add(
BuyCurrencyDeepLink(
onReceive = model::onBuyCurrencyDeepLink,
),
)
if (!routingFeatureToggle.isDeepLinkNavigationEnabled) {
val deeplinks = buildList {
if (!onrampFeatureToggles.isFeatureEnabled) {
add(
BuyCurrencyDeepLink(
onReceive = model::onBuyCurrencyDeepLink,
),
)
}
}
}
registerDeepLinks(
registry = deepLinksRegistry,
deeplinks,
)
registerDeepLinks(
registry = deepLinksRegistry,
deepLinks = deeplinks,
)
}
}
private val tokenMarketBlockComponent = params.currency.toTokenMarketParam()?.let { tokenMarketParams ->

View file

@ -0,0 +1,88 @@
package com.tangem.feature.tokendetails.deeplink
import arrow.core.getOrElse
import com.tangem.common.routing.AppRoute
import com.tangem.common.routing.AppRouter
import com.tangem.domain.notifications.models.NotificationType
import com.tangem.domain.tokens.GetCryptoCurrenciesUseCase
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
import com.tangem.features.tokendetails.deeplink.TokenDetailsDeepLinkHandler
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import timber.log.Timber
internal class DefaultTokenDetailsDeepLinkHandler @AssistedInject constructor(
@Assisted private val scope: CoroutineScope,
@Assisted private val queryParams: Map<String, String>,
private val appRouter: AppRouter,
private val getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase,
private val getCryptoCurrenciesUseCase: GetCryptoCurrenciesUseCase,
) : TokenDetailsDeepLinkHandler {
init {
handleDeepLink()
}
private fun handleDeepLink() {
// It is okay here, we are navigating from outside, and there is no other way to getting UserWallet
val userWalletId = queryParams[WALLET_ID_KEY]?.let(::UserWalletId)
?: getSelectedWalletSyncUseCase().getOrNull()?.walletId
if (userWalletId == null) {
Timber.e("Error on getting user wallet")
return
}
val networkId = queryParams[NETWORK_ID_KEY]
val tokenId = queryParams[TOKEN_ID_KEY]
val type = NotificationType.getType(queryParams[TYPE_KEY])
if (type == NotificationType.Promo) {
scope.launch {
val cryptoCurrency = getCryptoCurrenciesUseCase(userWalletId = userWalletId).getOrElse {
Timber.e("Error on getting crypto currency list")
return@launch
}.firstOrNull {
it.id.rawNetworkId == networkId && it.id.rawCurrencyId?.value == tokenId
}
if (cryptoCurrency == null) {
Timber.e(
"""
Could not get crypto currency for
|- $NETWORK_ID_KEY: $networkId
|- $TOKEN_ID_KEY: $tokenId
""".trimIndent(),
)
return@launch
}
appRouter.push(
AppRoute.CurrencyDetails(
userWalletId = userWalletId,
currency = cryptoCurrency,
),
)
}
}
}
@AssistedFactory
interface Factory : TokenDetailsDeepLinkHandler.Factory {
override fun create(
coroutineScope: CoroutineScope,
queryParams: Map<String, String>,
): DefaultTokenDetailsDeepLinkHandler
}
private companion object {
const val WALLET_ID_KEY = "walletId"
const val NETWORK_ID_KEY = "network_id"
const val TYPE_KEY = "type"
const val TOKEN_ID_KEY = "token_id"
}
}

View file

@ -0,0 +1,20 @@
package com.tangem.feature.tokendetails.deeplink.di
import com.tangem.feature.tokendetails.deeplink.DefaultTokenDetailsDeepLinkHandler
import com.tangem.features.tokendetails.deeplink.TokenDetailsDeepLinkHandler
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
internal interface TokenDetailsDeepLinkModule {
@Binds
@Singleton
fun bindWalletDeepLinkHandlerFactory(
impl: DefaultTokenDetailsDeepLinkHandler.Factory,
): TokenDetailsDeepLinkHandler.Factory
}

View file

@ -5,7 +5,7 @@ import com.tangem.common.routing.AppRouter
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.navigation.share.ShareManager
import com.tangem.core.navigation.url.UrlOpener
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.wallets.models.UserWalletId
import javax.inject.Inject

View file

@ -1,6 +1,6 @@
package com.tangem.feature.tokendetails.presentation.router
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.wallets.models.UserWalletId
internal interface InnerTokenDetailsRouter {

View file

@ -1,7 +1,7 @@
package com.tangem.feature.tokendetails.presentation.tokendetails.analytics
import com.tangem.core.analytics.models.AnalyticsEvent
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.feature.tokendetails.presentation.tokendetails.analytics.utils.toAnalyticsParams
internal open class TokenDetailsAnalyticsEvent(

View file

@ -3,7 +3,7 @@ package com.tangem.feature.tokendetails.presentation.tokendetails.analytics
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.analytics.models.AnalyticsEvent
import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.tokens.model.analytics.TokenSwapPromoAnalyticsEvent
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState
import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.TokenDetailsNotification

View file

@ -1,6 +1,6 @@
package com.tangem.feature.tokendetails.presentation.tokendetails.analytics.utils
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrency
internal fun CryptoCurrency.toAnalyticsParams(): Map<String, String> {
return mapOf(

View file

@ -2,8 +2,8 @@ package com.tangem.feature.tokendetails.presentation.tokendetails.model
import com.tangem.common.ui.bottomsheet.receive.AddressModel
import com.tangem.core.ui.extensions.TextReference
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.promo.models.PromoId
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.tokens.model.ScenarioUnavailabilityReason
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenBalanceSegmentedButtonConfig

View file

@ -34,6 +34,8 @@ import com.tangem.domain.card.GetExtendedPublicKeyForCurrencyUseCase
import com.tangem.domain.card.NetworkHasDerivationUseCase
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.demo.IsDemoCardUseCase
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.network.NetworkAddress
import com.tangem.domain.onramp.model.OnrampSource
import com.tangem.domain.promo.ShouldShowPromoTokenUseCase
import com.tangem.domain.promo.models.PromoId
@ -45,7 +47,9 @@ import com.tangem.domain.staking.GetYieldUseCase
import com.tangem.domain.staking.model.StakingAvailability
import com.tangem.domain.tokens.*
import com.tangem.domain.tokens.legacy.TradeCryptoAction
import com.tangem.domain.tokens.model.*
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.tokens.model.ScenarioUnavailabilityReason
import com.tangem.domain.tokens.model.TokenActionsState
import com.tangem.domain.tokens.model.analytics.TokenReceiveAnalyticsEvent
import com.tangem.domain.tokens.model.analytics.TokenScreenAnalyticsEvent
import com.tangem.domain.tokens.model.analytics.TokenScreenAnalyticsEvent.Companion.toReasonAnalyticsText
@ -91,7 +95,7 @@ import javax.inject.Inject
@ModelScoped
internal class TokenDetailsModel @Inject constructor(
override val dispatchers: CoroutineDispatcherProvider,
private val getCurrencyStatusUpdatesUseCase: GetCurrencyStatusUpdatesUseCase,
private val getSingleCryptoCurrencyStatusUseCase: GetSingleCryptoCurrencyStatusUseCase,
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
private val fetchCurrencyStatusUseCase: FetchCurrencyStatusUseCase,
private val txHistoryItemsCountUseCase: GetTxHistoryItemsCountUseCase,
@ -117,7 +121,6 @@ internal class TokenDetailsModel @Inject constructor(
private val analyticsEventsHandler: AnalyticsEventHandler,
private val vibratorHapticManager: VibratorHapticManager,
private val clipboardManager: ClipboardManager,
private val getCryptoCurrencySyncUseCase: GetCryptoCurrencyStatusSyncUseCase,
private val onrampFeatureToggles: OnrampFeatureToggles,
private val shareManager: ShareManager,
@GlobalUiMessageSender private val uiMessageSender: UiMessageSender,
@ -219,7 +222,7 @@ internal class TokenDetailsModel @Inject constructor(
private fun initButtons() {
// we need also init buttons before start all loading to avoid buttons blocking
modelScope.launch {
val currentCryptoCurrencyStatus = getCryptoCurrencySyncUseCase.invoke(
val currentCryptoCurrencyStatus = getSingleCryptoCurrencyStatusUseCase.invokeMultiWalletSync(
userWalletId = userWalletId,
cryptoCurrencyId = cryptoCurrency.id,
isSingleWalletWithTokens = false,
@ -300,7 +303,7 @@ internal class TokenDetailsModel @Inject constructor(
private fun subscribeOnCurrencyStatusUpdates() {
modelScope.launch(dispatchers.main) {
getCurrencyStatusUpdatesUseCase(
getSingleCryptoCurrencyStatusUseCase.invokeMultiWallet(
userWalletId = userWalletId,
currencyId = cryptoCurrency.id,
isSingleWalletWithTokens = userWallet.scanResponse.cardTypesResolver.isSingleWalletWithToken(),
@ -364,7 +367,6 @@ internal class TokenDetailsModel @Inject constructor(
updateDelayedCurrencyStatusUseCase(
userWalletId = userWalletId,
network = toCryptoCurrency.network,
refresh = true,
)
}
}

View file

@ -11,7 +11,7 @@ import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.extensions.wrappedList
import com.tangem.core.ui.res.TangemTheme
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.features.tokendetails.impl.R
@Immutable

View file

@ -6,7 +6,7 @@ import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.networkIconResId
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.wrappedList
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.tokens.model.warnings.CryptoCurrencyWarning
import com.tangem.features.tokendetails.impl.R
import org.joda.time.DateTime

View file

@ -2,7 +2,7 @@ package com.tangem.feature.tokendetails.presentation.tokendetails.state.express
import com.tangem.common.ui.expressStatus.state.ExpressTransactionStateInfoUM
import com.tangem.common.ui.expressStatus.state.ExpressTransactionStateUM
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.feature.swap.domain.models.domain.ExchangeStatus
import com.tangem.feature.swap.domain.models.domain.SwapProvider
import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.ExchangeStatusNotification

View file

@ -31,7 +31,7 @@ internal class TokenDetailsBalanceSelectStateConverter(
val yieldBalance = cryptoCurrencyStatus.value.yieldBalance as? YieldBalance.Data
val stakingCryptoAmount = yieldBalance?.getTotalWithRewardsStakingBalance(
cryptoCurrencyStatus.currency.network.id.value,
cryptoCurrencyStatus.currency.network.rawId,
)
val stakingFiatAmount = stakingCryptoAmount?.let { cryptoCurrencyStatus.value.fiatRate?.multiply(it) }
copy(

View file

@ -3,7 +3,7 @@ package com.tangem.feature.tokendetails.presentation.tokendetails.state.factory
import com.tangem.core.ui.extensions.getTintForTokenIcon
import com.tangem.core.ui.extensions.networkIconResId
import com.tangem.core.ui.extensions.tryGetBackgroundForTokenIcon
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.feature.tokendetails.presentation.tokendetails.state.IconState
import com.tangem.utils.converter.Converter

View file

@ -88,7 +88,7 @@ internal class TokenDetailsLoadedBalanceConverter(
): TokenDetailsBalanceBlockState {
val stakingCryptoAmount =
(status.value.yieldBalance as? YieldBalance.Data)?.getTotalWithRewardsStakingBalance(
status.currency.network.id.value,
status.currency.network.rawId,
)
val stakingFiatAmount = stakingCryptoAmount?.let { status.value.fiatRate?.multiply(it) }
val isBalanceSelectorEnabled = !stakingCryptoAmount.isNullOrZero()

View file

@ -6,7 +6,7 @@ import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.format.bigdecimal.crypto
import com.tangem.core.ui.format.bigdecimal.format
import com.tangem.core.ui.format.bigdecimal.shorted
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.tokens.model.warnings.CryptoCurrencyWarning
import com.tangem.domain.tokens.model.warnings.HederaWarnings
import com.tangem.domain.tokens.model.warnings.KaspaWarnings

View file

@ -15,9 +15,9 @@ import com.tangem.core.ui.format.bigdecimal.format
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.onramp.model.OnrampStatus
import com.tangem.domain.onramp.model.cache.OnrampTransaction
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.tokens.model.analytics.TokenOnrampAnalyticsEvent
import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsClickIntents

View file

@ -10,9 +10,9 @@ import com.tangem.core.ui.extensions.networkIconResId
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.res.TangemTheme
import com.tangem.domain.card.NetworkHasDerivationUseCase
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.network.Network
import com.tangem.domain.staking.GetStakingIntegrationIdUseCase
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.tokens.model.Network
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsClickIntents
@ -98,7 +98,7 @@ internal class TokenDetailsSkeletonStateConverter(
private fun MutableList<TangemDropdownMenuItem>.addGenerateXPubMenuItem(cryptoCurrency: CryptoCurrency) {
val userWallet = getUserWalletUseCase(userWalletId).getOrNull() ?: return
val isBitcoin = isBitcoin(cryptoCurrency.network.id.value)
val isBitcoin = isBitcoin(cryptoCurrency.network.rawId)
val hasDerivations = networkHasDerivationUseCase(
scanResponse = userWallet.scanResponse,
network = cryptoCurrency.network,

View file

@ -55,7 +55,7 @@ internal class TokenDetailsStakingInfoConverter(
private fun getStakingInfoBlock(status: CryptoCurrencyStatus, state: TokenDetailsState): StakingBlockUM? {
val yieldBalance = status.value.yieldBalance as? YieldBalance.Data
val stakingCryptoAmount = yieldBalance?.getTotalStakingBalance(status.currency.network.id.value)
val stakingCryptoAmount = yieldBalance?.getTotalStakingBalance(status.currency.network.rawId)
val pendingBalances = yieldBalance?.balance?.items ?: emptyList()
val iconState = state.tokenInfoBlockState.iconState
@ -143,7 +143,7 @@ internal class TokenDetailsStakingInfoConverter(
}
private fun getRewardText(status: CryptoCurrencyStatus, stakingRewardAmount: BigDecimal?): TextReference {
val blockchainId = status.currency.network.id.value
val blockchainId = status.currency.network.rawId
val rewardBlockType = when {
isStakingRewardUnavailable(blockchainId) -> RewardBlockType.RewardUnavailable
stakingRewardAmount.isNullOrZero() -> RewardBlockType.NoRewards

View file

@ -2,10 +2,10 @@ package com.tangem.feature.tokendetails.presentation.tokendetails.state.factory
import androidx.paging.PagingData
import arrow.core.Either
import com.tangem.common.ui.tokens.getUnavailabilityReasonText
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
import com.tangem.common.ui.bottomsheet.chooseaddress.ChooseAddressBottomSheetConfig
import com.tangem.common.ui.bottomsheet.receive.TokenReceiveBottomSheetConfig
import com.tangem.common.ui.tokens.getUnavailabilityReasonText
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
import com.tangem.core.ui.components.dropdownmenu.TangemDropdownMenuItem
import com.tangem.core.ui.components.transactions.state.TransactionState
import com.tangem.core.ui.components.transactions.state.TxHistoryState
@ -15,17 +15,23 @@ import com.tangem.core.ui.res.TangemTheme
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.card.NetworkHasDerivationUseCase
import com.tangem.domain.common.CardTypesResolver
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.network.Network
import com.tangem.domain.models.network.NetworkAddress
import com.tangem.domain.models.network.TxInfo
import com.tangem.domain.staking.GetStakingIntegrationIdUseCase
import com.tangem.domain.staking.model.StakingAvailability
import com.tangem.domain.staking.model.StakingEntryInfo
import com.tangem.domain.tokens.error.CurrencyStatusError
import com.tangem.domain.tokens.model.*
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.tokens.model.ScenarioUnavailabilityReason
import com.tangem.domain.tokens.model.TokenActionsState
import com.tangem.domain.tokens.model.warnings.CryptoCurrencyWarning
import com.tangem.domain.txhistory.models.TxHistoryItem
import com.tangem.domain.txhistory.models.TxHistoryListError
import com.tangem.domain.txhistory.models.TxHistoryStateError
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsClickIntents
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenBalanceSegmentedButtonConfig
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsAppBarMenuConfig
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState
@ -33,7 +39,6 @@ import com.tangem.feature.tokendetails.presentation.tokendetails.state.component
import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.txhistory.TokenDetailsLoadedTxHistoryConverter
import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.txhistory.TokenDetailsLoadingTxHistoryConverter
import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.txhistory.TokenDetailsLoadingTxHistoryConverter.TokenDetailsLoadingTxHistoryModel
import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsClickIntents
import com.tangem.features.tokendetails.impl.R
import com.tangem.utils.Provider
import kotlinx.collections.immutable.toImmutableList
@ -167,7 +172,7 @@ internal class TokenDetailsStateFactory(
}
fun getLoadedTxHistoryState(
txHistoryEither: Either<TxHistoryListError, Flow<PagingData<TxHistoryItem>>>,
txHistoryEither: Either<TxHistoryListError, Flow<PagingData<TxInfo>>>,
): TokenDetailsState {
return currentStateProvider().copy(
txHistoryState = loadedTxHistoryConverter.convert(txHistoryEither),

View file

@ -16,7 +16,7 @@ import com.tangem.core.ui.format.bigdecimal.format
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.tokens.model.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.tokens.model.Quote
import com.tangem.domain.tokens.model.analytics.TokenExchangeAnalyticsEvent
import com.tangem.feature.swap.domain.models.domain.ExchangeStatus

View file

@ -5,10 +5,10 @@ import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.datasource.local.swaptx.ExpressAnalyticsStatus
import com.tangem.datasource.local.swaptx.SwapTransactionStatusStore
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.TokensFeatureToggles
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.tokens.model.Quote
import com.tangem.domain.tokens.model.analytics.TokenExchangeAnalyticsEvent
import com.tangem.domain.tokens.repository.QuotesRepository

View file

@ -5,7 +5,7 @@ import com.tangem.common.ui.expressStatus.state.ExpressTransactionStateUM
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.tokens.model.analytics.TokenExchangeAnalyticsEvent
import com.tangem.domain.tokens.model.analytics.TokenOnrampAnalyticsEvent

View file

@ -5,13 +5,13 @@ import com.tangem.common.ui.expressStatus.state.ExpressTransactionStateUM
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.datasource.local.swaptx.ExpressAnalyticsStatus
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.onramp.GetOnrampStatusUseCase
import com.tangem.domain.onramp.GetOnrampTransactionsUseCase
import com.tangem.domain.onramp.OnrampRemoveTransactionUseCase
import com.tangem.domain.onramp.OnrampUpdateTransactionStatusUseCase
import com.tangem.domain.onramp.model.OnrampStatus
import com.tangem.domain.onramp.model.OnrampStatus.Status.*
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.tokens.model.analytics.TokenOnrampAnalyticsEvent
import com.tangem.domain.wallets.models.UserWallet

View file

@ -3,10 +3,10 @@ package com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.
import androidx.paging.PagingData
import arrow.core.Either
import com.tangem.core.ui.components.transactions.state.TxHistoryState
import com.tangem.domain.txhistory.models.TxHistoryItem
import com.tangem.domain.models.network.TxInfo
import com.tangem.domain.txhistory.models.TxHistoryListError
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState
import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsClickIntents
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState
import com.tangem.utils.Provider
import com.tangem.utils.converter.Converter
import kotlinx.coroutines.flow.Flow
@ -16,7 +16,7 @@ internal class TokenDetailsLoadedTxHistoryConverter(
private val clickIntents: TokenDetailsClickIntents,
symbol: String,
decimals: Int,
) : Converter<Either<TxHistoryListError, Flow<PagingData<TxHistoryItem>>>, TxHistoryState> {
) : Converter<Either<TxHistoryListError, Flow<PagingData<TxInfo>>>, TxHistoryState> {
private val txHistoryItemFlowConverter by lazy {
TokenDetailsTxHistoryItemFlowConverter(
@ -27,7 +27,7 @@ internal class TokenDetailsLoadedTxHistoryConverter(
)
}
override fun convert(value: Either<TxHistoryListError, Flow<PagingData<TxHistoryItem>>>): TxHistoryState {
override fun convert(value: Either<TxHistoryListError, Flow<PagingData<TxInfo>>>): TxHistoryState {
return value.fold(ifLeft = ::convertError, ifRight = ::convert)
}
@ -42,7 +42,7 @@ internal class TokenDetailsLoadedTxHistoryConverter(
}
}
private fun convert(items: Flow<PagingData<TxHistoryItem>>): TxHistoryState {
private fun convert(items: Flow<PagingData<TxInfo>>): TxHistoryState {
return txHistoryItemFlowConverter.convert(value = items)
}
}

View file

@ -5,9 +5,9 @@ import com.tangem.core.ui.components.transactions.state.TransactionState
import com.tangem.core.ui.components.transactions.state.TxHistoryState
import com.tangem.core.ui.components.transactions.state.TxHistoryState.TxHistoryItemState
import com.tangem.core.ui.utils.toDateFormatWithTodayYesterday
import com.tangem.domain.txhistory.models.TxHistoryItem
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState
import com.tangem.domain.models.network.TxInfo
import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsClickIntents
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState
import com.tangem.utils.Provider
import com.tangem.utils.converter.Converter
import kotlinx.coroutines.CoroutineScope
@ -20,7 +20,7 @@ internal class TokenDetailsTxHistoryItemFlowConverter(
private val symbol: String,
private val decimals: Int,
private val clickIntents: TokenDetailsClickIntents,
) : Converter<Flow<PagingData<TxHistoryItem>>, TxHistoryState> {
) : Converter<Flow<PagingData<TxInfo>>, TxHistoryState> {
private val txHistoryItemConverter by lazy {
TokenDetailsTxHistoryTransactionStateConverter(
@ -30,7 +30,7 @@ internal class TokenDetailsTxHistoryItemFlowConverter(
)
}
override fun convert(value: Flow<PagingData<TxHistoryItem>>): TxHistoryState {
override fun convert(value: Flow<PagingData<TxInfo>>): TxHistoryState {
val state = currentStateProvider()
val txHistoryContent = if (state.txHistoryState is TxHistoryState.Content) {
state.txHistoryState
@ -43,7 +43,7 @@ internal class TokenDetailsTxHistoryItemFlowConverter(
.onEach { txHistoryStatePagingData ->
txHistoryContent.contentItems.update {
txHistoryStatePagingData
.map<TxHistoryItem, TxHistoryItemState> { item ->
.map<TxInfo, TxHistoryItemState> { item ->
// [createTransactionState] returns timestamp without formatting
TxHistoryItemState.Transaction(state = createTransactionState(item))
}
@ -59,7 +59,7 @@ internal class TokenDetailsTxHistoryItemFlowConverter(
return txHistoryContent
}
private fun createTransactionState(item: TxHistoryItem): TransactionState {
private fun createTransactionState(item: TxInfo): TransactionState {
return txHistoryItemConverter.convert(value = item)
}

View file

@ -10,8 +10,8 @@ import com.tangem.core.ui.extensions.wrappedList
import com.tangem.core.ui.format.bigdecimal.crypto
import com.tangem.core.ui.format.bigdecimal.format
import com.tangem.core.ui.utils.toTimeFormat
import com.tangem.domain.txhistory.models.TxHistoryItem
import com.tangem.domain.txhistory.models.TxHistoryItem.*
import com.tangem.domain.models.network.TxInfo
import com.tangem.domain.models.network.TxInfo.*
import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsClickIntents
import com.tangem.features.tokendetails.impl.R
import com.tangem.utils.StringsSigns.MINUS
@ -23,14 +23,14 @@ internal class TokenDetailsTxHistoryTransactionStateConverter(
private val symbol: String,
private val decimals: Int,
private val clickIntents: TokenDetailsClickIntents,
) : Converter<TxHistoryItem, TransactionState> {
) : Converter<TxInfo, TransactionState> {
override fun convert(value: TxHistoryItem): TransactionState {
override fun convert(value: TxInfo): TransactionState {
return createTransactionStateItem(item = value)
}
@Suppress("LongMethod")
private fun createTransactionStateItem(item: TxHistoryItem): TransactionState {
private fun createTransactionStateItem(item: TxInfo): TransactionState {
return TransactionState.Content(
txHash = item.txHash,
amount = item.getAmount(),
@ -45,7 +45,7 @@ internal class TokenDetailsTxHistoryTransactionStateConverter(
)
}
private fun TxHistoryItem.extractIcon(): Int = if (status == TransactionStatus.Failed) {
private fun TxInfo.extractIcon(): Int = if (status == TransactionStatus.Failed) {
R.drawable.ic_close_24
} else {
when (type) {
@ -67,7 +67,7 @@ internal class TokenDetailsTxHistoryTransactionStateConverter(
}
}
private fun TxHistoryItem.extractTitle(): TextReference = when (val type = type) {
private fun TxInfo.extractTitle(): TextReference = when (val type = type) {
is TransactionType.Approve -> resourceReference(R.string.common_approval)
is TransactionType.Operation -> stringReference(type.name)
is TransactionType.Swap -> resourceReference(R.string.common_swap)
@ -81,38 +81,37 @@ internal class TokenDetailsTxHistoryTransactionStateConverter(
is TransactionType.Staking.Restake -> resourceReference(R.string.staking_restake)
}
private fun TxHistoryItem.extractSubtitle(): TextReference =
when (val interactionAddress = interactionAddressType) {
is InteractionAddressType.Contract -> resourceReference(
id = R.string.transaction_history_contract_address,
formatArgs = wrappedList(interactionAddress.address.toBriefAddressFormat()),
)
is InteractionAddressType.Multiple -> resourceReference(
id = if (isOutgoing) {
R.string.transaction_history_transaction_to_address
} else {
R.string.transaction_history_transaction_from_address
},
formatArgs = wrappedList(resourceReference(R.string.transaction_history_multiple_addresses)),
)
is InteractionAddressType.User -> resourceReference(
id = if (isOutgoing) {
R.string.transaction_history_transaction_to_address
} else {
R.string.transaction_history_transaction_from_address
},
formatArgs = wrappedList(interactionAddress.address.toBriefAddressFormat()),
)
is InteractionAddressType.Validator -> resourceReference(
id = R.string.transaction_history_transaction_validator,
formatArgs = wrappedList(interactionAddress.address.toBriefAddressFormat()),
)
null -> {
TextReference.EMPTY
}
private fun TxInfo.extractSubtitle(): TextReference = when (val interactionAddress = interactionAddressType) {
is InteractionAddressType.Contract -> resourceReference(
id = R.string.transaction_history_contract_address,
formatArgs = wrappedList(interactionAddress.address.toBriefAddressFormat()),
)
is InteractionAddressType.Multiple -> resourceReference(
id = if (isOutgoing) {
R.string.transaction_history_transaction_to_address
} else {
R.string.transaction_history_transaction_from_address
},
formatArgs = wrappedList(resourceReference(R.string.transaction_history_multiple_addresses)),
)
is InteractionAddressType.User -> resourceReference(
id = if (isOutgoing) {
R.string.transaction_history_transaction_to_address
} else {
R.string.transaction_history_transaction_from_address
},
formatArgs = wrappedList(interactionAddress.address.toBriefAddressFormat()),
)
is InteractionAddressType.Validator -> resourceReference(
id = R.string.transaction_history_transaction_validator,
formatArgs = wrappedList(interactionAddress.address.toBriefAddressFormat()),
)
null -> {
TextReference.EMPTY
}
}
private fun TxHistoryItem.extractDirection() = if (isOutgoing) Direction.OUTGOING else Direction.INCOMING
private fun TxInfo.extractDirection() = if (isOutgoing) Direction.OUTGOING else Direction.INCOMING
private fun TransactionStatus.tiUiStatus() = when (this) {
TransactionStatus.Confirmed -> TransactionState.Content.Status.Confirmed
@ -120,7 +119,7 @@ internal class TokenDetailsTxHistoryTransactionStateConverter(
TransactionStatus.Unconfirmed -> TransactionState.Content.Status.Unconfirmed
}
private fun TxHistoryItem.getAmount(): String {
private fun TxInfo.getAmount(): String {
if (type is TransactionType.Staking.Vote ||
type == TransactionType.Staking.ClaimRewards ||
type == TransactionType.Staking.Withdraw

View file

@ -6,9 +6,9 @@ import com.tangem.common.ui.expressStatus.state.*
import com.tangem.core.ui.components.currency.icon.CurrencyIconState
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.tokens.model.CryptoCurrency.ID
import com.tangem.domain.tokens.model.Network
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrency.ID
import com.tangem.domain.models.network.Network
import com.tangem.feature.swap.domain.models.domain.ExchangeProviderType
import com.tangem.feature.swap.domain.models.domain.ExchangeStatus
import com.tangem.feature.swap.domain.models.domain.SwapProvider
@ -85,7 +85,7 @@ class ExpressStatusBottomSheetStateProvider : PreviewParameterProvider<ExpressSt
get() = CryptoCurrency.Coin(
id = ID(
ID.Prefix.COIN_PREFIX,
ID.Body.NetworkId(network.id.value),
ID.Body.NetworkId(network.rawId),
ID.Suffix.RawID("token1"),
),
network = network,
@ -97,7 +97,7 @@ class ExpressStatusBottomSheetStateProvider : PreviewParameterProvider<ExpressSt
)
private val network = Network(
id = Network.ID("network1"),
id = Network.ID(value = "network1", derivationPath = Network.DerivationPath.None),
name = "Network One",
isTestnet = false,
standardType = Network.StandardType.ERC20,