Updated on 2026-08-14

This commit is contained in:
Tangem 2024-09-06 14:07:51 +05:00
parent b535ca1558
commit 9a574200b5
9 changed files with 191 additions and 11 deletions

View file

@ -96,4 +96,10 @@ internal object ManageTokensDomainModule {
fun provideCheckHasLinkedTokensUseCase(repository: ManageTokensRepository): CheckHasLinkedTokensUseCase { fun provideCheckHasLinkedTokensUseCase(repository: ManageTokensRepository): CheckHasLinkedTokensUseCase {
return CheckHasLinkedTokensUseCase(repository) return CheckHasLinkedTokensUseCase(repository)
} }
@Provides
@Singleton
fun provideCheckCurrencyUnsupportedUseCase(repository: ManageTokensRepository): CheckCurrencyUnsupportedUseCase {
return CheckCurrencyUnsupportedUseCase(repository)
}
} }

View file

@ -14,13 +14,13 @@ import com.tangem.datasource.local.preferences.AppPreferencesStore
import com.tangem.datasource.local.preferences.PreferencesKeys import com.tangem.datasource.local.preferences.PreferencesKeys
import com.tangem.datasource.local.preferences.utils.getObjectSyncOrNull import com.tangem.datasource.local.preferences.utils.getObjectSyncOrNull
import com.tangem.datasource.local.userwallet.UserWalletsStore import com.tangem.datasource.local.userwallet.UserWalletsStore
import com.tangem.domain.common.extensions.canHandleBlockchain
import com.tangem.domain.common.extensions.canHandleToken
import com.tangem.domain.common.extensions.supportedBlockchains import com.tangem.domain.common.extensions.supportedBlockchains
import com.tangem.domain.common.extensions.supportedTokens
import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.common.util.derivationStyleProvider import com.tangem.domain.common.util.derivationStyleProvider
import com.tangem.domain.managetokens.model.ManageTokensListBatchFlow import com.tangem.domain.managetokens.model.*
import com.tangem.domain.managetokens.model.ManageTokensListBatchingContext
import com.tangem.domain.managetokens.model.ManageTokensListConfig
import com.tangem.domain.managetokens.model.ManagedCryptoCurrency
import com.tangem.domain.managetokens.model.ManagedCryptoCurrency.SourceNetwork import com.tangem.domain.managetokens.model.ManagedCryptoCurrency.SourceNetwork
import com.tangem.domain.managetokens.repository.ManageTokensRepository import com.tangem.domain.managetokens.repository.ManageTokensRepository
import com.tangem.domain.tokens.model.Network import com.tangem.domain.tokens.model.Network
@ -175,7 +175,51 @@ internal class DefaultManageTokensRepository(
key = PreferencesKeys.getUserTokensKey(key.stringValue), key = PreferencesKeys.getUserTokensKey(key.stringValue),
) )
} }
// endregion
data class TokenWithSourceNetwork(val token: ManagedCryptoCurrency.Token, val sourceNetwork: SourceNetwork) override suspend fun checkCurrencyUnsupportedState(
userWalletId: UserWalletId,
sourceNetwork: SourceNetwork,
): CurrencyUnsupportedState? {
val userWallet = getUserWallet(userWalletId = userWalletId)
val blockchain = getBlockchain(sourceNetwork.id)
return when (sourceNetwork) {
is SourceNetwork.Default -> checkTokenUnsupportedState(userWallet = userWallet, blockchain = blockchain)
is SourceNetwork.Main -> checkBlockchainUnsupportedState(userWallet = userWallet, blockchain = blockchain)
}
}
private fun checkBlockchainUnsupportedState(
userWallet: UserWallet,
blockchain: Blockchain,
): CurrencyUnsupportedState? {
val canHandleBlockchain = userWallet.scanResponse.card.canHandleBlockchain(
blockchain = blockchain,
cardTypesResolver = userWallet.cardTypesResolver,
)
return if (!canHandleBlockchain) {
CurrencyUnsupportedState.UnsupportedNetwork(networkName = blockchain.getNetworkName())
} else {
null
}
}
private fun checkTokenUnsupportedState(
userWallet: UserWallet,
blockchain: Blockchain,
): CurrencyUnsupportedState.Token? {
val cardTypesResolver = userWallet.scanResponse.cardTypesResolver
val supportedTokens = userWallet.scanResponse.card.supportedTokens(cardTypesResolver)
return when {
// refactor this later by moving all this logic in card config
blockchain == Blockchain.Solana && !supportedTokens.contains(Blockchain.Solana) -> {
CurrencyUnsupportedState.Token.NetworkTokensUnsupported(networkName = blockchain.getNetworkName())
}
!userWallet.scanResponse.card.canHandleToken(supportedTokens, blockchain, cardTypesResolver) -> {
CurrencyUnsupportedState.Token.UnsupportedCurve(networkName = blockchain.getNetworkName())
}
else -> null
}
}
} }

View file

@ -0,0 +1,21 @@
package com.tangem.domain.managetokens
import arrow.core.Either
import com.tangem.domain.managetokens.model.CurrencyUnsupportedState
import com.tangem.domain.managetokens.model.ManagedCryptoCurrency
import com.tangem.domain.managetokens.repository.ManageTokensRepository
import com.tangem.domain.wallets.models.UserWalletId
class CheckCurrencyUnsupportedUseCase(
private val repository: ManageTokensRepository,
) {
suspend operator fun invoke(
userWalletId: UserWalletId,
sourceNetwork: ManagedCryptoCurrency.SourceNetwork,
): Either<Throwable, CurrencyUnsupportedState?> {
return Either.catch {
repository.checkCurrencyUnsupportedState(userWalletId, sourceNetwork)
}
}
}

View file

@ -0,0 +1,12 @@
package com.tangem.domain.managetokens.model
sealed class CurrencyUnsupportedState {
abstract val networkName: String
sealed class Token : CurrencyUnsupportedState() {
data class NetworkTokensUnsupported(override val networkName: String) : Token()
data class UnsupportedCurve(override val networkName: String) : Token()
}
data class UnsupportedNetwork(override val networkName: String) : CurrencyUnsupportedState()
}

View file

@ -1,5 +1,6 @@
package com.tangem.domain.managetokens.repository package com.tangem.domain.managetokens.repository
import com.tangem.domain.managetokens.model.CurrencyUnsupportedState
import com.tangem.domain.managetokens.model.ManageTokensListBatchFlow import com.tangem.domain.managetokens.model.ManageTokensListBatchFlow
import com.tangem.domain.managetokens.model.ManageTokensListBatchingContext import com.tangem.domain.managetokens.model.ManageTokensListBatchingContext
import com.tangem.domain.managetokens.model.ManagedCryptoCurrency import com.tangem.domain.managetokens.model.ManagedCryptoCurrency
@ -16,4 +17,9 @@ interface ManageTokensRepository {
tempAddedTokens: Map<ManagedCryptoCurrency.Token, Set<Network>>, tempAddedTokens: Map<ManagedCryptoCurrency.Token, Set<Network>>,
tempRemovedTokens: Map<ManagedCryptoCurrency.Token, Set<Network>>, tempRemovedTokens: Map<ManagedCryptoCurrency.Token, Set<Network>>,
): Boolean ): Boolean
suspend fun checkCurrencyUnsupportedState(
userWalletId: UserWalletId,
sourceNetwork: ManagedCryptoCurrency.SourceNetwork,
): CurrencyUnsupportedState?
} }

View file

@ -0,0 +1,22 @@
package com.tangem.features.managetokens.ui.dialog
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import com.tangem.core.ui.components.BasicDialog
import com.tangem.core.ui.components.DialogButtonUM
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.features.managetokens.impl.R
@Composable
internal fun CurrencyUnsupportedDialog(title: TextReference, message: TextReference, onDismiss: () -> Unit) {
BasicDialog(
title = title.resolveReference(),
message = message.resolveReference(),
confirmButton = DialogButtonUM(
title = stringResource(R.string.common_ok),
onClick = onDismiss,
),
onDismissDialog = onDismiss,
)
}

View file

@ -6,13 +6,11 @@ import com.tangem.core.decompose.ui.UiMessageSender
import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.message.SnackbarMessage import com.tangem.core.ui.message.SnackbarMessage
import com.tangem.domain.managetokens.CheckCurrencyUnsupportedUseCase
import com.tangem.domain.managetokens.GetManagedTokensUseCase import com.tangem.domain.managetokens.GetManagedTokensUseCase
import com.tangem.domain.managetokens.RemoveCustomManagedCryptoCurrencyUseCase import com.tangem.domain.managetokens.RemoveCustomManagedCryptoCurrencyUseCase
import com.tangem.domain.managetokens.model.ManageTokensListBatchingContext
import com.tangem.domain.managetokens.model.ManageTokensListConfig
import com.tangem.domain.managetokens.model.ManageTokensUpdateAction
import com.tangem.domain.managetokens.model.ManagedCryptoCurrency
import com.tangem.domain.managetokens.CheckHasLinkedTokensUseCase import com.tangem.domain.managetokens.CheckHasLinkedTokensUseCase
import com.tangem.domain.managetokens.model.*
import com.tangem.domain.tokens.model.Network import com.tangem.domain.tokens.model.Network
import com.tangem.domain.wallets.models.UserWalletId import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.features.managetokens.entity.item.CurrencyItemUM import com.tangem.features.managetokens.entity.item.CurrencyItemUM
@ -39,6 +37,7 @@ internal class ManageTokensListManager @Inject constructor(
private val getManagedTokensUseCase: GetManagedTokensUseCase, private val getManagedTokensUseCase: GetManagedTokensUseCase,
private val checkHasLinkedTokensUseCase: CheckHasLinkedTokensUseCase, private val checkHasLinkedTokensUseCase: CheckHasLinkedTokensUseCase,
private val removeCustomCurrencyUseCase: RemoveCustomManagedCryptoCurrencyUseCase, private val removeCustomCurrencyUseCase: RemoveCustomManagedCryptoCurrencyUseCase,
private val checkCurrencyUnsupportedUseCase: CheckCurrencyUnsupportedUseCase,
private val messageSender: UiMessageSender, private val messageSender: UiMessageSender,
private val dispatchers: CoroutineDispatcherProvider, private val dispatchers: CoroutineDispatcherProvider,
) : ManageTokensUiActions { ) : ManageTokensUiActions {
@ -223,4 +222,32 @@ internal class ManageTokensListManager @Inject constructor(
false false
} }
} }
override suspend fun checkCurrencyUnsupportedState(
userWalletId: UserWalletId,
sourceNetwork: ManagedCryptoCurrency.SourceNetwork,
): CurrencyUnsupportedState? {
return checkCurrencyUnsupportedUseCase(
userWalletId = userWalletId,
sourceNetwork = sourceNetwork,
).getOrElse {
Timber.e(
it,
"""
Failed to check currency unsupported state
|- User wallet ID: $userWalletId
|- Source Network: $sourceNetwork
""".trimIndent(),
)
val message = SnackbarMessage(
message = it.localizedMessage
?.let(::stringReference)
?: resourceReference(R.string.common_error),
)
messageSender.send(message)
null
}
}
} }

View file

@ -1,5 +1,6 @@
package com.tangem.features.managetokens.utils.list package com.tangem.features.managetokens.utils.list
import com.tangem.domain.managetokens.model.CurrencyUnsupportedState
import com.tangem.domain.managetokens.model.ManagedCryptoCurrency import com.tangem.domain.managetokens.model.ManagedCryptoCurrency
import com.tangem.domain.tokens.model.Network import com.tangem.domain.tokens.model.Network
import com.tangem.domain.wallets.models.UserWalletId import com.tangem.domain.wallets.models.UserWalletId
@ -15,4 +16,9 @@ internal interface ManageTokensUiActions {
fun checkNeedToShowRemoveNetworkWarning(currency: ManagedCryptoCurrency.Token, network: Network): Boolean fun checkNeedToShowRemoveNetworkWarning(currency: ManagedCryptoCurrency.Token, network: Network): Boolean
suspend fun checkHasLinkedTokens(userWalletId: UserWalletId, network: Network): Boolean suspend fun checkHasLinkedTokens(userWalletId: UserWalletId, network: Network): Boolean
suspend fun checkCurrencyUnsupportedState(
userWalletId: UserWalletId,
sourceNetwork: ManagedCryptoCurrency.SourceNetwork,
): CurrencyUnsupportedState?
} }

View file

@ -1,10 +1,15 @@
package com.tangem.features.managetokens.utils.list package com.tangem.features.managetokens.utils.list
import com.tangem.core.decompose.ui.UiMessageSender import com.tangem.core.decompose.ui.UiMessageSender
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.wrappedList
import com.tangem.core.ui.message.ContentMessage import com.tangem.core.ui.message.ContentMessage
import com.tangem.domain.managetokens.model.CurrencyUnsupportedState
import com.tangem.domain.managetokens.model.ManagedCryptoCurrency import com.tangem.domain.managetokens.model.ManagedCryptoCurrency
import com.tangem.domain.tokens.model.Network import com.tangem.domain.tokens.model.Network
import com.tangem.features.managetokens.entity.item.CurrencyItemUM import com.tangem.features.managetokens.entity.item.CurrencyItemUM
import com.tangem.features.managetokens.impl.R
import com.tangem.features.managetokens.ui.dialog.CurrencyUnsupportedDialog
import com.tangem.features.managetokens.ui.dialog.HasLinkedTokensWarning import com.tangem.features.managetokens.ui.dialog.HasLinkedTokensWarning
import com.tangem.features.managetokens.ui.dialog.HideTokenWarning import com.tangem.features.managetokens.ui.dialog.HideTokenWarning
import com.tangem.features.managetokens.utils.mapper.toUiModel import com.tangem.features.managetokens.utils.mapper.toUiModel
@ -143,7 +148,13 @@ internal class ManageTokensUiManager(
if (currency !is ManagedCryptoCurrency.Token) return@launch if (currency !is ManagedCryptoCurrency.Token) return@launch
if (isSelected) { if (isSelected) {
actions.addCurrency(batchKey, currency, source.network) val userWalletId = state.value.userWalletId
val unsupportedState = userWalletId?.let { actions.checkCurrencyUnsupportedState(it, source) }
if (unsupportedState != null) {
showUnsupportedWarning(unsupportedState)
} else {
actions.addCurrency(batchKey, currency, source.network)
}
} else { } else {
if (actions.checkNeedToShowRemoveNetworkWarning(currency, source.network)) { if (actions.checkNeedToShowRemoveNetworkWarning(currency, source.network)) {
showRemoveNetworkWarning( showRemoveNetworkWarning(
@ -160,6 +171,31 @@ internal class ManageTokensUiManager(
} }
} }
private fun showUnsupportedWarning(unsupportedState: CurrencyUnsupportedState) {
val message = ContentMessage { onDismiss ->
CurrencyUnsupportedDialog(
title = resourceReference(R.string.common_warning),
message = when (unsupportedState) {
is CurrencyUnsupportedState.Token.NetworkTokensUnsupported -> resourceReference(
id = R.string.alert_manage_tokens_unsupported_message,
formatArgs = wrappedList(unsupportedState.networkName),
)
is CurrencyUnsupportedState.Token.UnsupportedCurve -> resourceReference(
id = R.string.alert_manage_tokens_unsupported_curve_message,
formatArgs = wrappedList(unsupportedState.networkName),
)
is CurrencyUnsupportedState.UnsupportedNetwork -> resourceReference(
id = R.string.alert_manage_tokens_unsupported_curve_message,
formatArgs = wrappedList(unsupportedState.networkName),
)
},
onDismiss = onDismiss,
)
}
messageSender.send(message)
}
private suspend fun showRemoveNetworkWarning( private suspend fun showRemoveNetworkWarning(
currency: ManagedCryptoCurrency, currency: ManagedCryptoCurrency,
network: Network, network: Network,