diff --git a/domain/src/main/java/com/tangem/domain/common/form/FieldsValidators.kt b/domain/src/main/java/com/tangem/domain/common/form/FieldsValidators.kt index f526b968ab..7b5235d365 100644 --- a/domain/src/main/java/com/tangem/domain/common/form/FieldsValidators.kt +++ b/domain/src/main/java/com/tangem/domain/common/form/FieldsValidators.kt @@ -1,11 +1,13 @@ package com.tangem.domain.common.form +import com.tangem.blockchain.blockchains.binance.BinanceAddressService import com.tangem.blockchain.blockchains.ethereum.EthereumAddressService import com.tangem.blockchain.blockchains.solana.SolanaAddressService import com.tangem.blockchain.common.Blockchain import com.tangem.blockchain.common.address.AddressService import com.tangem.common.Validator import com.tangem.domain.AddCustomTokenError +import timber.log.Timber /** [REDACTED_AUTHOR] @@ -46,12 +48,15 @@ class TokenContractAddressValidator : CustomTokenValidator() { private fun getAddressService(): AddressService { return when (blockchain) { - Blockchain.Solana, Blockchain.SolanaTestnet -> SolanaAddressService() Blockchain.Unknown -> EthereumAddressService() + Blockchain.Solana, Blockchain.SolanaTestnet -> SolanaAddressService() + Blockchain.Binance -> BinanceAddressService() + Blockchain.BinanceTestnet -> BinanceAddressService(true) else -> { if (blockchain.isEvm()) { EthereumAddressService() } else { + Timber.e("Throw for blockchain: ${blockchain.fullName}") throw UnsupportedOperationException() } } diff --git a/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenHub.kt b/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenHub.kt index 33084f8cb8..cc88dc2889 100644 --- a/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenHub.kt +++ b/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenHub.kt @@ -63,24 +63,33 @@ internal class AddCustomTokenHub : BaseStoreHub("AddCustomT when (val error = ContractAddress.validateValue(address)) { null -> { + // valid contract ContractAddress.removeError() - unlockTokenFields() + updateTokenDetailFields(false) changeBlockchainNetworkList() } AddCustomTokenError.FieldIsEmpty -> { + // empty contract address ContractAddress.removeError() + clearTokenDetailsFields() + updateTokenDetailFields(false) changeBlockchainNetworkList() + checkAndUpdateAddButton() return } AddCustomTokenError.InvalidContractAddress -> { ContractAddress.addError(error) - unlockTokenFields() + updateTokenDetailFields(hubState.tokensAnyFieldsIsFilled()) changeBlockchainNetworkList() + checkAndUpdateAddButton() return } else -> {} } - if (!action.contractAddress.isUserInput) return + if (!action.contractAddress.isUserInput) { + checkAndUpdateAddButton() + return + } manageFoundTokenChanges(requestInfoAboutToken(address)) } @@ -98,7 +107,7 @@ internal class AddCustomTokenHub : BaseStoreHub("AddCustomT selectedNetwork = action.blockchainNetwork.value ) updateWarningAlreadyAdded(isAlreadyAdded) - updateAddButton() + checkAndUpdateAddButton() } } is OnTokenDerivationPathChanged -> { @@ -114,19 +123,22 @@ internal class AddCustomTokenHub : BaseStoreHub("AddCustomT ) } updateWarningAlreadyAdded(isAlreadyAdded) - updateAddButton() + checkAndUpdateAddButton() } is OnTokenNameChanged -> { - changeBlockchainNetworkList() - updateAddButton() +// changeBlockchainNetworkList() +// updateTokenDetailFields(hubState.tokensAnyFieldsIsFilled()) + checkAndUpdateAddButton() } is OnTokenSymbolChanged -> { - changeBlockchainNetworkList() - updateAddButton() +// changeBlockchainNetworkList() +// updateTokenDetailFields(hubState.tokensAnyFieldsIsFilled()) + checkAndUpdateAddButton() } is OnTokenDecimalsChanged -> { - changeBlockchainNetworkList() - updateAddButton() +// changeBlockchainNetworkList() +// updateTokenDetailFields(hubState.tokensAnyFieldsIsFilled()) + checkAndUpdateAddButton() } is OnAddCustomTokenClicked -> { val state = hubState @@ -167,6 +179,7 @@ internal class AddCustomTokenHub : BaseStoreHub("AddCustomT val networkFieldIsFilled = Network.isFilled() val newNetworkField = Network.getField().copy(itemList = newNetworkBlockchainList) + newNetworkField.data = Field.Data(Network.getFieldValue(), newNetworkField.data.isUserInput) if (networkFieldIsFilled) { val listSameSize = networkBlockchainList.size == newNetworkBlockchainList.size val newListLessThanOld = networkBlockchainList.size > newNetworkBlockchainList.size @@ -230,9 +243,8 @@ internal class AddCustomTokenHub : BaseStoreHub("AddCustomT PotentialScamToken.add() dispatchOnMain(SetFoundTokenId(null)) - clearTokenFields() - unlockTokenFields() - updateAddButton() + updateTokenDetailFields(true) + checkAndUpdateAddButton() return } @@ -250,14 +262,14 @@ internal class AddCustomTokenHub : BaseStoreHub("AddCustomT val isInAppSavedTokens = isTokenPersistIntoAppSavedTokensList() if (isInAppSavedTokens) { - lockTokenFields() - lockAddButton() + updateTokenDetailFields(false) + updateAddButton(false) PotentialScamToken.replace(TokenAlreadyAdded) } else { // not in the saved tokens list if (singleTokenContract.active) { - lockTokenFields() - unlockAddButton() + updateTokenDetailFields(false) + updateAddButton(true) if (hubState.derivationPathIsSelected()) { PotentialScamToken.add() } else { @@ -265,7 +277,7 @@ internal class AddCustomTokenHub : BaseStoreHub("AddCustomT PotentialScamToken.remove() } } else { - unlockAddButton() + updateAddButton(true) PotentialScamToken.add() } } @@ -286,8 +298,8 @@ internal class AddCustomTokenHub : BaseStoreHub("AddCustomT hubScope.launch { // find how to connect to the upper coroutineContext and dispatch through them fillTokenFields(foundToken, selectedContract) - lockTokenFields() - unlockAddButton() + updateTokenDetailFields(false) + updateAddButton(true) } }, ) @@ -296,54 +308,38 @@ internal class AddCustomTokenHub : BaseStoreHub("AddCustomT } } - private suspend fun replaceWarnings( - warningsAdd: MutableSet = mutableSetOf(), - warningsRemove: MutableSet = mutableSetOf(), - ) { - if (warningsAdd.isNotEmpty() || warningsRemove.isNotEmpty()) { - dispatchOnMain(Warning.Replace(warningsRemove.toSet(), warningsAdd.toSet())) - } - } - - private suspend fun updateAddButton() { + private suspend fun checkAndUpdateAddButton() { val state = hubState if (state.warnings.contains(TokenAlreadyAdded)) { - lockAddButton() + updateAddButton(false) return } when { // token - state.tokensOneFieldsIsFilled() -> { - lockAddButton() + state.tokensFieldsIsFilled() && state.networkIsSelected() -> { + val error = ContractAddress.validateValue(ContractAddress.getFieldValue()) + updateAddButton(error == null) } // token - state.tokensFieldsIsFilled() && state.networkIsSelected() -> { - unlockAddButton() + state.tokensAnyFieldsIsFilled() -> { + updateAddButton(false) } // blockchain else -> { if (state.networkIsSelected()) { val alreadyAdded = isBlockchainPersistIntoAppSavedTokensList() if (alreadyAdded) { - lockAddButton() + updateAddButton(false) } else { - unlockAddButton() + updateAddButton(true) } } else { - lockAddButton() + updateAddButton(false) } } } } - private suspend fun lockAddButton() { - dispatchOnMain(Screen.UpdateAddButton(ViewStates.AddButton(false))) - } - - private suspend fun unlockAddButton() { - dispatchOnMain(Screen.UpdateAddButton(ViewStates.AddButton(true))) - } - /** * These are helper functions. */ @@ -501,35 +497,34 @@ internal class AddCustomTokenHub : BaseStoreHub("AddCustomT dispatchOnMain(UpdateForm(hubState)) } - private suspend fun clearTokenFields() { + private suspend fun clearTokenDetailsFields() { Name.setFieldValue(Field.Data("", false)) Symbol.setFieldValue(Field.Data("", false)) Decimals.setFieldValue(Field.Data("", false)) dispatchOnMain(UpdateForm(hubState)) } - private suspend fun lockTokenFields() { + private suspend fun updateTokenDetailFields(isEnabled: Boolean = true) { val state = hubState val action = Screen.UpdateTokenFields(listOf( - Network to state.screenState.network.copy(isEnabled = false), - Name to state.screenState.name.copy(isEnabled = false), - Symbol to state.screenState.symbol.copy(isEnabled = false), - Decimals to state.screenState.decimals.copy(isEnabled = false), + Name to state.screenState.name.copy(isEnabled = isEnabled), + Symbol to state.screenState.symbol.copy(isEnabled = isEnabled), + Decimals to state.screenState.decimals.copy(isEnabled = isEnabled), )) dispatchOnMain(action) } - private suspend fun unlockTokenFields() { - val state = hubState + private suspend fun updateBlockchainNetworkField(isEnabled: Boolean) { val action = Screen.UpdateTokenFields(listOf( - Network to state.screenState.network.copy(isEnabled = true), - Name to state.screenState.name.copy(isEnabled = true), - Symbol to state.screenState.symbol.copy(isEnabled = true), - Decimals to state.screenState.decimals.copy(isEnabled = true), + Name to hubState.screenState.name.copy(isEnabled = isEnabled), )) dispatchOnMain(action) } + private suspend fun updateAddButton(isEnabled: Boolean) { + dispatchOnMain(Screen.UpdateAddButton(ViewStates.AddButton(isEnabled))) + } + private suspend fun AddCustomTokenError.Warning.add() { dispatchOnMain(Warning.Add(setOf(this))) } diff --git a/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenState.kt b/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenState.kt index f7f01351ec..41080a12a8 100644 --- a/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenState.kt +++ b/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenState.kt @@ -64,14 +64,14 @@ data class AddCustomTokenState( } // except network - fun tokensOneFieldsIsFilled(): Boolean { + fun tokensAnyFieldsIsFilled(): Boolean { val idsToCheck = listOf(ContractAddress, Name, Symbol, Decimals) val fieldsToCheck = form.fieldList.filter { idsToCheck.contains(it.id) } val validator = StringIsEmptyValidator() val errorsList = fieldsToCheck.mapNotNull { field -> validator.validate(field.data.value?.toString()) } - return errorsList.size == 1 + return errorsList.isNotEmpty() } fun networkIsSelected(): Boolean { @@ -85,7 +85,7 @@ data class AddCustomTokenState( } fun getCustomTokenType(): CustomTokenType = when { - tokensOneFieldsIsFilled() || tokensFieldsIsFilled() -> CustomTokenType.Token + tokensAnyFieldsIsFilled() || tokensFieldsIsFilled() -> CustomTokenType.Token else -> CustomTokenType.Blockchain } @@ -172,11 +172,11 @@ data class AddCustomTokenState( Blockchain.Unknown, Blockchain.Ethereum, Blockchain.BSC, - Blockchain.Binance, + Blockchain.Binance, // not evm Blockchain.Polygon, Blockchain.Avalanche, Blockchain.Fantom, - Blockchain.Solana, // should be unsupported for tokens until they are added to the Blockchain SDK + Blockchain.Solana, // not evm. Should be unsupported for tokens until they are added to the Blockchain SDK ) if (type == CustomTokenType.Token) networks.remove(Blockchain.Solana)