Updated on 2026-08-14

This commit is contained in:
Tangem 2026-02-09 20:34:51 +03:00
parent 20e2ffa64c
commit 47a7c02d29
4 changed files with 92 additions and 10 deletions

View file

@ -30,6 +30,10 @@ class JobHolder {
job = null
}
suspend fun join() {
job?.join()
}
fun isEmpty() = job == null
}

View file

@ -50,6 +50,7 @@ dependencies {
implementation(projects.domain.account.status)
implementation(projects.domain.appTheme)
implementation(projects.domain.appTheme.models)
implementation(projects.data.common)
/** DI */
implementation(deps.hilt.android)
@ -68,6 +69,10 @@ dependencies {
implementation(deps.compose.shimmer)
implementation(deps.compose.coil)
/** Tangem libraries */
implementation(tangemDeps.blockchain)
implementation(projects.libs.blockchainSdk)
/** Other */
implementation(deps.decompose.ext.compose)
implementation(deps.kotlin.immutable.collections)

View file

@ -8,18 +8,28 @@ import com.arkivanov.decompose.router.stack.StackNavigation
import com.arkivanov.decompose.router.stack.popToFirst
import com.arkivanov.decompose.router.stack.pushNew
import com.arkivanov.decompose.router.stack.replaceAll
import com.tangem.blockchainsdk.utils.toBlockchain
import com.tangem.blockchainsdk.utils.toCoinId
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.model.ParamsContainer
import com.tangem.core.ui.components.token.state.TokenItemState
import com.tangem.core.ui.components.tokenlist.state.TokensListItemUM
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.data.common.currency.getCoinId
import com.tangem.data.common.currency.getTokenId
import com.tangem.data.common.currency.isCustomCoin
import com.tangem.data.common.currency.isCustomToken
import com.tangem.data.common.network.NetworkFactory
import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles
import com.tangem.domain.account.usecase.IsAccountsModeEnabledUseCase
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.models.account.AccountStatus
import com.tangem.domain.models.account.derivationIndex
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.onramp.GetHotCryptoUseCase
import com.tangem.domain.onramp.model.HotCryptoCurrency
import com.tangem.domain.tokens.GetSingleCryptoCurrencyStatusUseCase
@ -70,6 +80,7 @@ internal class HotCryptoModel @Inject constructor(
private val accountsFeatureToggles: AccountsFeatureToggles,
private val isAccountsModeEnabledUseCase: IsAccountsModeEnabledUseCase,
val portfolioSelectorController: PortfolioSelectorController,
private val networkFactory: NetworkFactory,
private val portfolioFetcherFactory: PortfolioFetcher.Factory,
) : Model(), OnrampAddTokenComponent.Callbacks by callbackDelegate {
@ -172,10 +183,15 @@ internal class HotCryptoModel @Inject constructor(
if (isSingleAccount) {
val account = hotCryptoPortfolioData.wallet.accounts.first().account
val tokenToAdd = AddHotCryptoData(
val cryptoCurrency = updateCryptoCurrency(
cryptoCurrency = currency.cryptoCurrency,
userWallet = userWallet,
account = account,
)
val tokenToAdd = AddHotCryptoData(
cryptoCurrency = requireNotNull(cryptoCurrency),
userWallet = userWallet,
account = account,
isMorePortfolioAvailable = false,
)
hotCryptoToAddDataFlow.emit(tokenToAdd)
@ -188,10 +204,15 @@ internal class HotCryptoModel @Inject constructor(
.selectedAccountWithData(requireNotNull(portfolioFetcher))
.filterNotNull()
.map { (_, selectedAccount) ->
AddHotCryptoData(
val cryptoCurrency = updateCryptoCurrency(
cryptoCurrency = currency.cryptoCurrency,
userWallet = userWallet,
account = selectedAccount,
)
AddHotCryptoData(
cryptoCurrency = requireNotNull(cryptoCurrency),
userWallet = userWallet,
account = selectedAccount,
isMorePortfolioAvailable = true,
)
}
@ -251,6 +272,47 @@ internal class HotCryptoModel @Inject constructor(
return@isEnabled isNotAddedHotCrypto
}
}
// todo account move to common module
private fun updateCryptoCurrency(
cryptoCurrency: CryptoCurrency,
userWallet: UserWallet,
account: AccountStatus,
): CryptoCurrency? {
val derivationIndex = account.account.derivationIndex ?: return null
val blockchain = cryptoCurrency.network.toBlockchain()
val network = networkFactory.create(
blockchain = blockchain,
extraDerivationPath = null,
accountIndex = derivationIndex,
userWallet = userWallet,
) ?: return null
return when (cryptoCurrency) {
is CryptoCurrency.Coin -> {
val id = getCoinId(network, network.toBlockchain().toCoinId())
cryptoCurrency.copy(
id = id,
network = network,
isCustom = isCustomCoin(network),
)
}
is CryptoCurrency.Token -> {
val id = getTokenId(
network = network,
rawTokenId = cryptoCurrency.id.rawCurrencyId,
contractAddress = cryptoCurrency.contractAddress,
)
cryptoCurrency.copy(
id = id,
network = network,
isCustom = isCustomToken(id, network),
)
}
}
}
}
@ModelScoped

View file

@ -10,6 +10,8 @@ import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.message.ToastMessage
import com.tangem.domain.account.status.usecase.GetAccountCurrencyStatusUseCase
import com.tangem.domain.account.status.usecase.ManageCryptoCurrenciesUseCase
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.wallets.usecase.BackendId
import com.tangem.domain.wallets.usecase.ColdWalletAndHasMissedDerivationsUseCase
@ -47,10 +49,14 @@ internal class OnrampAddTokenModel @Inject constructor(
params.tokenToAdd
.distinctUntilChanged()
.mapLatest { tokenToAdd: AddHotCryptoData ->
addTokenJob.cancel()
addTokenJob.join()
val backendId = tokenToAdd.cryptoCurrency.network.backendId
val userWalletId = tokenToAdd.account.accountId.userWalletId
val isTangemIconVisible = needColdWalletInteraction(userWalletId, backendId)
val isTangemIconVisible = needColdWalletInteraction(
walletId = userWalletId,
backendId = backendId,
cryptoCurrency = tokenToAdd.cryptoCurrency,
)
uiBuilder.updateContent(
tokenToAdd = tokenToAdd,
isTangemIconVisible = isTangemIconVisible,
@ -79,7 +85,9 @@ internal class OnrampAddTokenModel @Inject constructor(
userWalletId = accountId.userWalletId,
currencyId = cryptoCurrency.id,
network = cryptoCurrency.network,
).firstOrNull()
)
.filter { (_, status) -> status.value !is CryptoCurrencyStatus.Loading }
.firstOrNull()
if (status == null) {
processError(error = null)
} else {
@ -88,11 +96,14 @@ internal class OnrampAddTokenModel @Inject constructor(
uiState.value = um.toggleProgress(false)
}
private suspend fun needColdWalletInteraction(walletId: UserWalletId, backendId: BackendId): Boolean =
coldWalletAndHasMissedDerivationsUseCase.invoke(
userWalletId = walletId,
networksWithDerivationPath = mapOf(backendId to null),
)
private suspend fun needColdWalletInteraction(
walletId: UserWalletId,
backendId: BackendId,
cryptoCurrency: CryptoCurrency,
): Boolean = coldWalletAndHasMissedDerivationsUseCase.invoke(
userWalletId = walletId,
networksWithDerivationPath = mapOf(backendId to cryptoCurrency.network.derivationPath.value),
)
private fun processError(error: Throwable?) {
val message = error?.message?.let { stringReference(it) }