Updated on 2026-08-14
This commit is contained in:
parent
e0a845a474
commit
9bcf93922c
12 changed files with 213 additions and 121 deletions
|
|
@ -9,9 +9,13 @@ 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.DialogMessage
|
||||
import com.tangem.domain.managetokens.CreateCryptoCurrencyUseCase
|
||||
import com.tangem.domain.managetokens.FindTokenUseCase
|
||||
import com.tangem.domain.managetokens.ValidateTokenFormUseCase
|
||||
import com.tangem.domain.managetokens.model.exceptoin.CustomTokenFormValidationException
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.wallets.usecase.ColdWalletAndHasMissedDerivationsUseCase
|
||||
import com.tangem.features.managetokens.analytics.CustomTokenAnalyticsEvent
|
||||
import com.tangem.features.managetokens.component.CustomTokenFormComponent
|
||||
import com.tangem.features.managetokens.entity.customtoken.ClickableFieldUM
|
||||
|
|
@ -41,6 +45,10 @@ internal class CustomTokenFormModel @Inject constructor(
|
|||
private val messageSender: UiMessageSender,
|
||||
private val customTokenFormManager: CustomCurrencyFormBuilder,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
private val coldWalletAndHasMissedDerivationsUseCase: ColdWalletAndHasMissedDerivationsUseCase,
|
||||
private val createCryptoCurrencyUseCase: CreateCryptoCurrencyUseCase,
|
||||
private val findTokenUseCase: FindTokenUseCase,
|
||||
private val validateTokenFormUseCase: ValidateTokenFormUseCase,
|
||||
paramsContainer: ParamsContainer,
|
||||
customTokenFormUseCasesFacadeFactory: CustomTokenFormUseCasesFacade.Factory,
|
||||
) : Model() {
|
||||
|
|
@ -48,7 +56,13 @@ internal class CustomTokenFormModel @Inject constructor(
|
|||
private val params: CustomTokenFormComponent.Params = paramsContainer.require()
|
||||
private var createdCurrency: CryptoCurrency? = null
|
||||
private var useCasesFacade: CustomTokenFormUseCasesFacade = customTokenFormUseCasesFacadeFactory.create(params.mode)
|
||||
private val customCurrencyValidator = CustomCurrencyValidator(useCasesFacade)
|
||||
private val customCurrencyValidator = CustomCurrencyValidator(
|
||||
userWalletId = params.mode.userWalletId,
|
||||
useCasesFacade = useCasesFacade,
|
||||
createCryptoCurrencyUseCase = createCryptoCurrencyUseCase,
|
||||
findTokenUseCase = findTokenUseCase,
|
||||
validateTokenFormUseCase = validateTokenFormUseCase,
|
||||
)
|
||||
|
||||
val state: MutableStateFlow<CustomTokenFormUM> = MutableStateFlow(
|
||||
value = getInitialState(),
|
||||
|
|
@ -164,8 +178,9 @@ internal class CustomTokenFormModel @Inject constructor(
|
|||
isAlreadyAdded: Boolean,
|
||||
isCustom: Boolean,
|
||||
) = modelScope.launch {
|
||||
val needColdWalletInteraction = useCasesFacade.needColdWalletInteraction(
|
||||
network = mapOf(currency.network.backendId to getDerivationPath().value),
|
||||
val needColdWalletInteraction = coldWalletAndHasMissedDerivationsUseCase.invoke(
|
||||
userWalletId = params.mode.userWalletId,
|
||||
networksWithDerivationPath = mapOf(currency.network.backendId to getDerivationPath().value),
|
||||
)
|
||||
|
||||
state.update { state ->
|
||||
|
|
|
|||
|
|
@ -1,11 +1,15 @@
|
|||
package com.tangem.features.managetokens.utils
|
||||
|
||||
import arrow.core.getOrElse
|
||||
import com.tangem.domain.managetokens.CreateCryptoCurrencyUseCase
|
||||
import com.tangem.domain.managetokens.FindTokenUseCase
|
||||
import com.tangem.domain.managetokens.ValidateTokenFormUseCase
|
||||
import com.tangem.domain.managetokens.model.AddCustomTokenForm
|
||||
import com.tangem.domain.managetokens.model.exceptoin.CustomTokenFormValidationException
|
||||
import com.tangem.domain.managetokens.model.exceptoin.FindTokenException
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.features.managetokens.utils.list.CustomTokenFormUseCasesFacade
|
||||
import com.tangem.utils.coroutines.JobHolder
|
||||
import com.tangem.utils.coroutines.saveInAndJoin
|
||||
|
|
@ -15,7 +19,11 @@ import kotlinx.coroutines.launch
|
|||
import timber.log.Timber
|
||||
|
||||
internal class CustomCurrencyValidator(
|
||||
private val userWalletId: UserWalletId,
|
||||
private val useCasesFacade: CustomTokenFormUseCasesFacade,
|
||||
private val createCryptoCurrencyUseCase: CreateCryptoCurrencyUseCase,
|
||||
private val findTokenUseCase: FindTokenUseCase,
|
||||
private val validateTokenFormUseCase: ValidateTokenFormUseCase,
|
||||
) {
|
||||
|
||||
private val validateFormJobHolder = JobHolder()
|
||||
|
|
@ -41,10 +49,7 @@ internal class CustomCurrencyValidator(
|
|||
) = coroutineScope {
|
||||
updateStatus(Status.Validating)
|
||||
|
||||
val result = useCasesFacade.validateTokenFormUseCase(
|
||||
networkId = networkId,
|
||||
formValues = formValues,
|
||||
)
|
||||
val result = validateTokenFormUseCase(networkId = networkId, formValues = formValues)
|
||||
|
||||
val validatedForm = result.getOrElse { e ->
|
||||
updateStatus(Status.FormValidationException(e))
|
||||
|
|
@ -90,7 +95,8 @@ internal class CustomCurrencyValidator(
|
|||
|
||||
updateStatus(Status.SearchingToken)
|
||||
|
||||
val foundToken = useCasesFacade.findTokenUseCase(
|
||||
val foundToken = findTokenUseCase.invoke(
|
||||
userWalletId = userWalletId,
|
||||
contractAddress = validatedForm.contractAddress,
|
||||
networkId = networkId,
|
||||
derivationPath = derivationPath,
|
||||
|
|
@ -121,7 +127,8 @@ internal class CustomCurrencyValidator(
|
|||
) {
|
||||
updateStatus(Status.SearchingToken)
|
||||
|
||||
val token = useCasesFacade.findTokenUseCase(
|
||||
val token = findTokenUseCase.invoke(
|
||||
userWalletId = userWalletId,
|
||||
contractAddress = validatedForm.contractAddress,
|
||||
networkId = networkId,
|
||||
derivationPath = derivationPath,
|
||||
|
|
@ -148,7 +155,8 @@ internal class CustomCurrencyValidator(
|
|||
derivationPath: Network.DerivationPath,
|
||||
validatedForm: AddCustomTokenForm.Validated.All?,
|
||||
) {
|
||||
val currency = useCasesFacade.createCryptoCurrencyUseCase(
|
||||
val currency = createCryptoCurrencyUseCase.invoke(
|
||||
userWalletId = userWalletId,
|
||||
networkId = networkId,
|
||||
derivationPath = derivationPath,
|
||||
formValues = validatedForm,
|
||||
|
|
|
|||
|
|
@ -1,47 +1,30 @@
|
|||
package com.tangem.features.managetokens.utils.list
|
||||
|
||||
import arrow.core.Either
|
||||
import arrow.core.NonEmptyList
|
||||
import arrow.core.left
|
||||
import arrow.core.right
|
||||
import com.tangem.domain.account.producer.SingleAccountProducer
|
||||
import com.tangem.domain.account.status.usecase.SaveCryptoCurrenciesUseCase
|
||||
import com.tangem.domain.account.supplier.SingleAccountSupplier
|
||||
import com.tangem.domain.managetokens.CheckIsCurrencyNotAddedUseCase
|
||||
import com.tangem.domain.managetokens.CreateCryptoCurrencyUseCase
|
||||
import com.tangem.domain.managetokens.FindTokenUseCase
|
||||
import com.tangem.domain.managetokens.ValidateTokenFormUseCase
|
||||
import com.tangem.domain.managetokens.model.AddCustomTokenForm
|
||||
import com.tangem.domain.managetokens.model.exceptoin.CustomTokenFormValidationException
|
||||
import com.tangem.domain.managetokens.model.exceptoin.FindTokenException
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.tokens.AddCryptoCurrenciesUseCase
|
||||
import com.tangem.domain.wallets.usecase.ColdWalletAndHasMissedDerivationsUseCase
|
||||
import com.tangem.domain.wallets.usecase.DerivePublicKeysUseCase
|
||||
import com.tangem.features.managetokens.component.AddCustomTokenMode
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
internal class CustomTokenFormUseCasesFacade @AssistedInject constructor(
|
||||
private val addCryptoCurrenciesUseCase: AddCryptoCurrenciesUseCase,
|
||||
private val derivePublicKeysUseCase: DerivePublicKeysUseCase,
|
||||
private val validateTokenFormUseCase: ValidateTokenFormUseCase,
|
||||
private val createCryptoCurrencyUseCase: CreateCryptoCurrencyUseCase,
|
||||
private val findTokenUseCase: FindTokenUseCase,
|
||||
private val checkIsCurrencyNotAddedUseCase: CheckIsCurrencyNotAddedUseCase,
|
||||
private val coldWalletAndHasMissedDerivationsUseCase: ColdWalletAndHasMissedDerivationsUseCase,
|
||||
private val saveCryptoCurrenciesUseCase: SaveCryptoCurrenciesUseCase,
|
||||
private val singleAccountSupplier: SingleAccountSupplier,
|
||||
@Assisted private val mode: AddCustomTokenMode,
|
||||
) {
|
||||
|
||||
suspend fun needColdWalletInteraction(network: Map<String, String?>): Boolean = when (mode) {
|
||||
is AddCustomTokenMode.Account -> TODO("Account")
|
||||
is AddCustomTokenMode.Wallet -> coldWalletAndHasMissedDerivationsUseCase.invoke(
|
||||
userWalletId = mode.userWalletId,
|
||||
networksWithDerivationPath = network,
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun addCryptoCurrenciesUseCase(currency: CryptoCurrency): Either<Throwable, Unit> = when (mode) {
|
||||
is AddCustomTokenMode.Account -> {
|
||||
saveCryptoCurrenciesUseCase(accountId = mode.accountId, add = currency)
|
||||
|
|
@ -67,7 +50,19 @@ internal class CustomTokenFormUseCasesFacade @AssistedInject constructor(
|
|||
derivationPath: Network.DerivationPath,
|
||||
contractAddress: String?,
|
||||
): Either<Throwable, Boolean> = when (mode) {
|
||||
is AddCustomTokenMode.Account -> TODO("Account")
|
||||
is AddCustomTokenMode.Account -> {
|
||||
val account = singleAccountSupplier.getSyncOrNull(
|
||||
params = SingleAccountProducer.Params(accountId = mode.accountId),
|
||||
)
|
||||
?: return IllegalStateException("Account not found").left()
|
||||
|
||||
account.cryptoCurrencies.none { currency ->
|
||||
networkId == currency.network.id &&
|
||||
derivationPath == currency.network.derivationPath &&
|
||||
contractAddress.equals(currency.id.contractAddress, ignoreCase = true)
|
||||
}
|
||||
.right()
|
||||
}
|
||||
is AddCustomTokenMode.Wallet -> checkIsCurrencyNotAddedUseCase.invoke(
|
||||
userWalletId = mode.userWalletId,
|
||||
networkId = networkId,
|
||||
|
|
@ -76,45 +71,6 @@ internal class CustomTokenFormUseCasesFacade @AssistedInject constructor(
|
|||
)
|
||||
}
|
||||
|
||||
suspend fun createCryptoCurrencyUseCase(
|
||||
networkId: Network.ID,
|
||||
derivationPath: Network.DerivationPath,
|
||||
formValues: AddCustomTokenForm.Validated.All?,
|
||||
): Either<Throwable, CryptoCurrency> = when (mode) {
|
||||
is AddCustomTokenMode.Account -> TODO("Account")
|
||||
is AddCustomTokenMode.Wallet -> createCryptoCurrencyUseCase.invoke(
|
||||
userWalletId = mode.userWalletId,
|
||||
networkId = networkId,
|
||||
derivationPath = derivationPath,
|
||||
formValues = formValues,
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun findTokenUseCase(
|
||||
contractAddress: String,
|
||||
networkId: Network.ID,
|
||||
derivationPath: Network.DerivationPath,
|
||||
): Either<FindTokenException, CryptoCurrency.Token> = when (mode) {
|
||||
is AddCustomTokenMode.Account -> TODO("Account")
|
||||
is AddCustomTokenMode.Wallet -> findTokenUseCase.invoke(
|
||||
userWalletId = mode.userWalletId,
|
||||
contractAddress = contractAddress,
|
||||
networkId = networkId,
|
||||
derivationPath = derivationPath,
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun validateTokenFormUseCase(
|
||||
networkId: Network.ID,
|
||||
formValues: AddCustomTokenForm.Raw,
|
||||
): Either<NonEmptyList<CustomTokenFormValidationException>, AddCustomTokenForm.Validated> = when (mode) {
|
||||
is AddCustomTokenMode.Account -> TODO("Account")
|
||||
is AddCustomTokenMode.Wallet -> validateTokenFormUseCase.invoke(
|
||||
networkId = networkId,
|
||||
formValues = formValues,
|
||||
)
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory {
|
||||
fun create(mode: AddCustomTokenMode): CustomTokenFormUseCasesFacade
|
||||
|
|
|
|||
|
|
@ -90,8 +90,9 @@ internal class ManageTokensListManager @AssistedInject constructor(
|
|||
*/
|
||||
suspend fun launchPagination(isCollapsed: Boolean) = coroutineScope {
|
||||
val loadUserTokensFromRemote = when (mode) {
|
||||
is ManageTokensMode.Wallet -> source == ManageTokensSource.ONBOARDING
|
||||
is ManageTokensMode.Wallet,
|
||||
is ManageTokensMode.Account,
|
||||
-> source == ManageTokensSource.ONBOARDING
|
||||
ManageTokensMode.None,
|
||||
-> false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,11 @@ package com.tangem.features.managetokens.utils.list
|
|||
|
||||
import arrow.core.Either
|
||||
import arrow.core.left
|
||||
import arrow.core.right
|
||||
import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles
|
||||
import com.tangem.domain.account.producer.SingleAccountProducer
|
||||
import com.tangem.domain.account.status.usecase.SaveCryptoCurrenciesUseCase
|
||||
import com.tangem.domain.account.supplier.SingleAccountSupplier
|
||||
import com.tangem.domain.managetokens.*
|
||||
import com.tangem.domain.managetokens.model.CurrencyUnsupportedState
|
||||
import com.tangem.domain.managetokens.model.ManageTokensListConfig
|
||||
|
|
@ -28,6 +32,8 @@ internal class ManageTokensUseCasesFacade @AssistedInject constructor(
|
|||
private val saveManagedTokensUseCase: SaveManagedTokensUseCase,
|
||||
private val saveCryptoCurrenciesUseCase: SaveCryptoCurrenciesUseCase,
|
||||
private val customTokensRepository: CustomTokensRepository,
|
||||
private val accountsFeatureToggles: AccountsFeatureToggles,
|
||||
private val singleAccountSupplier: SingleAccountSupplier,
|
||||
@Assisted private val mode: ManageTokensMode,
|
||||
) {
|
||||
|
||||
|
|
@ -35,12 +41,21 @@ internal class ManageTokensUseCasesFacade @AssistedInject constructor(
|
|||
get() = IllegalStateException("Unsupported")
|
||||
|
||||
fun manageTokensListConfig(searchText: String?): ManageTokensListConfig {
|
||||
val userWalletId: UserWalletId? = when (mode) {
|
||||
is ManageTokensMode.Account -> TODO("Account")
|
||||
ManageTokensMode.None -> null
|
||||
is ManageTokensMode.Wallet -> mode.userWalletId
|
||||
return when (mode) {
|
||||
is ManageTokensMode.Account -> {
|
||||
ManageTokensListConfig.Account(accountId = mode.accountId, searchText = searchText)
|
||||
}
|
||||
is ManageTokensMode.Wallet -> {
|
||||
ManageTokensListConfig.Wallet(userWalletId = mode.userWalletId, searchText = searchText)
|
||||
}
|
||||
ManageTokensMode.None -> {
|
||||
if (accountsFeatureToggles.isFeatureEnabled) {
|
||||
ManageTokensListConfig.Account(accountId = null, searchText = searchText)
|
||||
} else {
|
||||
ManageTokensListConfig.Wallet(userWalletId = null, searchText = searchText)
|
||||
}
|
||||
}
|
||||
}
|
||||
return ManageTokensListConfig(userWalletId, searchText)
|
||||
}
|
||||
|
||||
suspend fun removeCustomCurrencyUseCase(customCurrency: ManagedCryptoCurrency.Custom): Either<Throwable, Unit> {
|
||||
|
|
@ -67,7 +82,21 @@ internal class ManageTokensUseCasesFacade @AssistedInject constructor(
|
|||
tempRemovedTokens: Map<ManagedCryptoCurrency.Token, Set<Network>>,
|
||||
): Either<Throwable, Boolean> {
|
||||
return when (mode) {
|
||||
is ManageTokensMode.Account -> TODO("Account")
|
||||
is ManageTokensMode.Account -> {
|
||||
val added = tempAddedTokens.mapToCryptoCurrencies(userWalletId = mode.accountId.userWalletId)
|
||||
val removed = tempRemovedTokens.mapToCryptoCurrencies(userWalletId = mode.accountId.userWalletId)
|
||||
|
||||
val account = singleAccountSupplier.getSyncOrNull(
|
||||
params = SingleAccountProducer.Params(accountId = mode.accountId),
|
||||
)
|
||||
?: return IllegalStateException("Account not found").left()
|
||||
|
||||
(account.cryptoCurrencies + added - removed).any {
|
||||
it is CryptoCurrency.Token && it.network.backendId == network.backendId &&
|
||||
it.network.derivationPath == network.derivationPath
|
||||
}
|
||||
.right()
|
||||
}
|
||||
is ManageTokensMode.Wallet -> checkHasLinkedTokensUseCase.invoke(
|
||||
userWalletId = mode.userWalletId,
|
||||
network = network,
|
||||
|
|
@ -82,7 +111,10 @@ internal class ManageTokensUseCasesFacade @AssistedInject constructor(
|
|||
sourceNetwork: ManagedCryptoCurrency.SourceNetwork,
|
||||
): Either<Throwable, CurrencyUnsupportedState?> {
|
||||
return when (mode) {
|
||||
is ManageTokensMode.Account -> TODO("Account")
|
||||
is ManageTokensMode.Account -> checkCurrencyUnsupportedUseCase.invoke(
|
||||
userWalletId = mode.accountId.userWalletId,
|
||||
sourceNetwork = sourceNetwork,
|
||||
)
|
||||
is ManageTokensMode.Wallet -> checkCurrencyUnsupportedUseCase.invoke(
|
||||
userWalletId = mode.userWalletId,
|
||||
sourceNetwork = sourceNetwork,
|
||||
|
|
@ -92,7 +124,10 @@ internal class ManageTokensUseCasesFacade @AssistedInject constructor(
|
|||
}
|
||||
|
||||
suspend fun needColdWalletInteraction(network: Map<String, Nothing?>): Boolean = when (mode) {
|
||||
is ManageTokensMode.Account -> TODO("Account")
|
||||
is ManageTokensMode.Account -> coldWalletAndHasMissedDerivationsUseCase.invoke(
|
||||
userWalletId = mode.accountId.userWalletId,
|
||||
networksWithDerivationPath = network,
|
||||
)
|
||||
is ManageTokensMode.Wallet -> coldWalletAndHasMissedDerivationsUseCase.invoke(
|
||||
userWalletId = mode.userWalletId,
|
||||
networksWithDerivationPath = network,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue