Updated on 2026-08-14

This commit is contained in:
Tangem 2022-04-21 23:18:18 +03:00
parent 5d988b812e
commit 735d07070d
3 changed files with 65 additions and 65 deletions

View file

@ -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<String>() {
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()
}
}

View file

@ -63,24 +63,33 @@ internal class AddCustomTokenHub : BaseStoreHub<AddCustomTokenState>("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<AddCustomTokenState>("AddCustomT
selectedNetwork = action.blockchainNetwork.value
)
updateWarningAlreadyAdded(isAlreadyAdded)
updateAddButton()
checkAndUpdateAddButton()
}
}
is OnTokenDerivationPathChanged -> {
@ -114,19 +123,22 @@ internal class AddCustomTokenHub : BaseStoreHub<AddCustomTokenState>("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<AddCustomTokenState>("AddCustomT
val networkFieldIsFilled = Network.isFilled()
val newNetworkField = Network.getField<TokenBlockchainField>().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<AddCustomTokenState>("AddCustomT
PotentialScamToken.add()
dispatchOnMain(SetFoundTokenId(null))
clearTokenFields()
unlockTokenFields()
updateAddButton()
updateTokenDetailFields(true)
checkAndUpdateAddButton()
return
}
@ -250,14 +262,14 @@ internal class AddCustomTokenHub : BaseStoreHub<AddCustomTokenState>("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<AddCustomTokenState>("AddCustomT
PotentialScamToken.remove()
}
} else {
unlockAddButton()
updateAddButton(true)
PotentialScamToken.add()
}
}
@ -286,8 +298,8 @@ internal class AddCustomTokenHub : BaseStoreHub<AddCustomTokenState>("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<AddCustomTokenState>("AddCustomT
}
}
private suspend fun replaceWarnings(
warningsAdd: MutableSet<AddCustomTokenError.Warning> = mutableSetOf(),
warningsRemove: MutableSet<AddCustomTokenError.Warning> = 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<String>())
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<AddCustomTokenState>("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)))
}

View file

@ -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)