diff --git a/app/src/main/java/com/tangem/tap/di/domain/ManageTokensDomainModule.kt b/app/src/main/java/com/tangem/tap/di/domain/ManageTokensDomainModule.kt index 611bce95ac..e15eea4635 100644 --- a/app/src/main/java/com/tangem/tap/di/domain/ManageTokensDomainModule.kt +++ b/app/src/main/java/com/tangem/tap/di/domain/ManageTokensDomainModule.kt @@ -96,4 +96,10 @@ internal object ManageTokensDomainModule { fun provideCheckHasLinkedTokensUseCase(repository: ManageTokensRepository): CheckHasLinkedTokensUseCase { return CheckHasLinkedTokensUseCase(repository) } + + @Provides + @Singleton + fun provideCheckCurrencyUnsupportedUseCase(repository: ManageTokensRepository): CheckCurrencyUnsupportedUseCase { + return CheckCurrencyUnsupportedUseCase(repository) + } } \ No newline at end of file diff --git a/data/manage-tokens/src/main/kotlin/com/tangem/data/managetokens/DefaultManageTokensRepository.kt b/data/manage-tokens/src/main/kotlin/com/tangem/data/managetokens/DefaultManageTokensRepository.kt index 90409a1f9d..6c0d025397 100644 --- a/data/manage-tokens/src/main/kotlin/com/tangem/data/managetokens/DefaultManageTokensRepository.kt +++ b/data/manage-tokens/src/main/kotlin/com/tangem/data/managetokens/DefaultManageTokensRepository.kt @@ -14,13 +14,13 @@ import com.tangem.datasource.local.preferences.AppPreferencesStore import com.tangem.datasource.local.preferences.PreferencesKeys import com.tangem.datasource.local.preferences.utils.getObjectSyncOrNull 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.supportedTokens import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.common.util.derivationStyleProvider -import com.tangem.domain.managetokens.model.ManageTokensListBatchFlow -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.* import com.tangem.domain.managetokens.model.ManagedCryptoCurrency.SourceNetwork import com.tangem.domain.managetokens.repository.ManageTokensRepository import com.tangem.domain.tokens.model.Network @@ -175,7 +175,51 @@ internal class DefaultManageTokensRepository( 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 + } + } } \ No newline at end of file diff --git a/domain/manage-tokens/src/main/kotlin/com/tangem/domain/managetokens/CheckCurrencyUnsupportedUseCase.kt b/domain/manage-tokens/src/main/kotlin/com/tangem/domain/managetokens/CheckCurrencyUnsupportedUseCase.kt new file mode 100644 index 0000000000..40dbddf6fd --- /dev/null +++ b/domain/manage-tokens/src/main/kotlin/com/tangem/domain/managetokens/CheckCurrencyUnsupportedUseCase.kt @@ -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 { + return Either.catch { + repository.checkCurrencyUnsupportedState(userWalletId, sourceNetwork) + } + } +} \ No newline at end of file diff --git a/domain/manage-tokens/src/main/kotlin/com/tangem/domain/managetokens/model/CurrencyUnsupportedState.kt b/domain/manage-tokens/src/main/kotlin/com/tangem/domain/managetokens/model/CurrencyUnsupportedState.kt new file mode 100644 index 0000000000..af7a16af06 --- /dev/null +++ b/domain/manage-tokens/src/main/kotlin/com/tangem/domain/managetokens/model/CurrencyUnsupportedState.kt @@ -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() +} \ No newline at end of file diff --git a/domain/manage-tokens/src/main/kotlin/com/tangem/domain/managetokens/repository/ManageTokensRepository.kt b/domain/manage-tokens/src/main/kotlin/com/tangem/domain/managetokens/repository/ManageTokensRepository.kt index c977402d75..cfa44069fe 100644 --- a/domain/manage-tokens/src/main/kotlin/com/tangem/domain/managetokens/repository/ManageTokensRepository.kt +++ b/domain/manage-tokens/src/main/kotlin/com/tangem/domain/managetokens/repository/ManageTokensRepository.kt @@ -1,5 +1,6 @@ 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.ManageTokensListBatchingContext import com.tangem.domain.managetokens.model.ManagedCryptoCurrency @@ -16,4 +17,9 @@ interface ManageTokensRepository { tempAddedTokens: Map>, tempRemovedTokens: Map>, ): Boolean + + suspend fun checkCurrencyUnsupportedState( + userWalletId: UserWalletId, + sourceNetwork: ManagedCryptoCurrency.SourceNetwork, + ): CurrencyUnsupportedState? } \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/ui/dialog/CurrencyUnsupportedDialog.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/ui/dialog/CurrencyUnsupportedDialog.kt new file mode 100644 index 0000000000..659b007c29 --- /dev/null +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/ui/dialog/CurrencyUnsupportedDialog.kt @@ -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, + ) +} \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/list/ManageTokensListManager.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/list/ManageTokensListManager.kt index 3282da26fe..835316aa30 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/list/ManageTokensListManager.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/list/ManageTokensListManager.kt @@ -6,13 +6,11 @@ import com.tangem.core.decompose.ui.UiMessageSender import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.message.SnackbarMessage +import com.tangem.domain.managetokens.CheckCurrencyUnsupportedUseCase import com.tangem.domain.managetokens.GetManagedTokensUseCase 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.model.* import com.tangem.domain.tokens.model.Network import com.tangem.domain.wallets.models.UserWalletId import com.tangem.features.managetokens.entity.item.CurrencyItemUM @@ -39,6 +37,7 @@ internal class ManageTokensListManager @Inject constructor( private val getManagedTokensUseCase: GetManagedTokensUseCase, private val checkHasLinkedTokensUseCase: CheckHasLinkedTokensUseCase, private val removeCustomCurrencyUseCase: RemoveCustomManagedCryptoCurrencyUseCase, + private val checkCurrencyUnsupportedUseCase: CheckCurrencyUnsupportedUseCase, private val messageSender: UiMessageSender, private val dispatchers: CoroutineDispatcherProvider, ) : ManageTokensUiActions { @@ -223,4 +222,32 @@ internal class ManageTokensListManager @Inject constructor( 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 + } + } } \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/list/ManageTokensUiActions.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/list/ManageTokensUiActions.kt index 7b7548289a..d5e583482e 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/list/ManageTokensUiActions.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/list/ManageTokensUiActions.kt @@ -1,5 +1,6 @@ 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.tokens.model.Network import com.tangem.domain.wallets.models.UserWalletId @@ -15,4 +16,9 @@ internal interface ManageTokensUiActions { fun checkNeedToShowRemoveNetworkWarning(currency: ManagedCryptoCurrency.Token, network: Network): Boolean suspend fun checkHasLinkedTokens(userWalletId: UserWalletId, network: Network): Boolean + + suspend fun checkCurrencyUnsupportedState( + userWalletId: UserWalletId, + sourceNetwork: ManagedCryptoCurrency.SourceNetwork, + ): CurrencyUnsupportedState? } \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/list/ManageTokensUiManager.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/list/ManageTokensUiManager.kt index 1cc07f7286..b43eb3542c 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/list/ManageTokensUiManager.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/list/ManageTokensUiManager.kt @@ -1,10 +1,15 @@ package com.tangem.features.managetokens.utils.list 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.domain.managetokens.model.CurrencyUnsupportedState import com.tangem.domain.managetokens.model.ManagedCryptoCurrency import com.tangem.domain.tokens.model.Network 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.HideTokenWarning import com.tangem.features.managetokens.utils.mapper.toUiModel @@ -143,7 +148,13 @@ internal class ManageTokensUiManager( if (currency !is ManagedCryptoCurrency.Token) return@launch 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 { if (actions.checkNeedToShowRemoveNetworkWarning(currency, source.network)) { 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( currency: ManagedCryptoCurrency, network: Network,