Updated on 2026-08-14

This commit is contained in:
Tangem 2022-05-24 18:41:52 +03:00
parent cfae358cd5
commit 98c7221e7b
4 changed files with 118 additions and 76 deletions

View file

@ -20,7 +20,11 @@ import com.tangem.domain.common.form.*
import com.tangem.domain.features.addCustomToken.*
import com.tangem.domain.features.addCustomToken.CustomTokenFieldId.*
import com.tangem.domain.features.addCustomToken.redux.AddCustomTokenAction.*
import com.tangem.domain.redux.*
import com.tangem.domain.redux.BaseStoreHub
import com.tangem.domain.redux.DomainState
import com.tangem.domain.redux.ReStoreReducer
import com.tangem.domain.redux.domainStore
import com.tangem.domain.redux.extensions.dispatchOnMain
import com.tangem.domain.redux.global.DomainGlobalAction
import com.tangem.domain.redux.global.DomainGlobalState
import com.tangem.network.api.tangemTech.CoinsResponse
@ -105,14 +109,14 @@ internal class AddCustomTokenHub : BaseStoreHub<AddCustomTokenState>("AddCustomT
null -> {
// valid contract address
ContractAddress.removeError()
changeBlockchainNetworkList()
reassembleBlockchainNetworkList()
findTokenAndUpdateFields(contractAddress)
}
AddCustomTokenError.InvalidContractAddress -> {
// invalid contract address
ContractAddress.addError(error)
updateTokenDetailFields(hubState.tokensAnyFieldsIsFilled())
changeBlockchainNetworkList()
reassembleBlockchainNetworkList()
checkAndUpdateAddButton()
}
AddCustomTokenError.FieldIsEmpty -> {
@ -120,7 +124,7 @@ internal class AddCustomTokenHub : BaseStoreHub<AddCustomTokenState>("AddCustomT
ContractAddress.removeError()
clearTokenDetailsFields()
updateTokenDetailFields(false)
changeBlockchainNetworkList()
reassembleBlockchainNetworkList()
checkAndUpdateAddButton()
}
}
@ -129,21 +133,22 @@ internal class AddCustomTokenHub : BaseStoreHub<AddCustomTokenState>("AddCustomT
null -> {
// valid contract address
ContractAddress.removeError()
changeBlockchainNetworkList()
reassembleBlockchainNetworkList()
findTokenAndUpdateFields(contractAddress)
}
else -> {
ContractAddress.removeError()
clearTokenDetailsFields()
updateTokenDetailFields(false)
changeBlockchainNetworkList()
reassembleBlockchainNetworkList()
checkAndUpdateAddButton()
}
}
}
updateDerivationPath(Network.getFieldValue())
}
private suspend fun changeBlockchainNetworkList() {
private suspend fun reassembleBlockchainNetworkList() {
val state = hubState
val networkBlockchainList = Network.getField<TokenBlockchainField>().itemList
val card = requireNotNull(globalState.scanResponse?.card)
@ -159,13 +164,12 @@ internal class AddCustomTokenHub : BaseStoreHub<AddCustomTokenState>("AddCustomT
val listSameSize = networkBlockchainList.size == newNetworkBlockchainList.size
val newListLessThanOld = networkBlockchainList.size > newNetworkBlockchainList.size
if (listSameSize || newListLessThanOld) {
// check selected blockchain
// check selected blockchain
val selectedBlockchain = Network.getFieldValue<Blockchain>()
val defaultSelection = Blockchain.Unknown
if (!newNetworkBlockchainList.contains(selectedBlockchain)
&& newNetworkBlockchainList.contains(defaultSelection)
) {
// selectedBlockchain not present in the new list. Change selection to default
&& newNetworkBlockchainList.contains(defaultSelection)) {
// selectedBlockchain not present in the new list. Change selection to default
newNetworkField.data = Field.Data(defaultSelection, false)
}
}
@ -175,6 +179,31 @@ internal class AddCustomTokenHub : BaseStoreHub<AddCustomTokenState>("AddCustomT
dispatchOnMain(UpdateForm(hubState))
}
private suspend fun updateDerivationPath(blockchainNetwork: Blockchain) {
val state = hubState
val derivationIsSupportedByNetwork = blockchainNetwork.isEvm() || blockchainNetwork == Blockchain.Unknown
if (DerivationPath.isFilled() && !derivationIsSupportedByNetwork) {
// reset to default
val derivationField = DerivationPath.getField<TokenDerivationPathField>()
derivationField.data = derivationField.data.copy(
value = Blockchain.Unknown,
isUserInput = false
)
state.setField(derivationField)
dispatchOnMain(UpdateForm(hubState))
}
if (state.screenState.derivationPath.isEnabled != derivationIsSupportedByNetwork) {
val action = Screen.UpdateTokenFields(listOf(
DerivationPath to state.screenState.derivationPath.copy(
isEnabled = derivationIsSupportedByNetwork,
),
))
dispatchOnMain(action)
}
}
private suspend fun requestInfoAboutToken(
contractAddress: String,
): List<CoinsResponse.Coin> {
@ -382,6 +411,58 @@ internal class AddCustomTokenHub : BaseStoreHub<AddCustomTokenState>("AddCustomT
derivationStyle = hubState.cardDerivationStyle
)
private suspend fun fillTokenFields(
token: CoinsResponse.Coin,
coinNetwork: CoinsResponse.Coin.Network,
) {
val blockchain = Blockchain.fromNetworkId(coinNetwork.networkId) ?: Blockchain.Unknown
Network.setFieldValue(Field.Data(blockchain, false))
Name.setFieldValue(Field.Data(token.name, false))
Symbol.setFieldValue(Field.Data(token.symbol, false))
Decimals.setFieldValue(Field.Data(coinNetwork.decimalCount.toString(), false))
dispatchOnMain(UpdateForm(hubState))
}
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 updateTokenDetailFields(isEnabled: Boolean = true) {
val state = hubState
val action = Screen.UpdateTokenFields(listOf(
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 updateBlockchainNetworkField(isEnabled: Boolean) {
val action = Screen.UpdateTokenFields(listOf(
Name to hubState.screenState.name.copy(isEnabled = isEnabled),
))
dispatchOnMain(action)
}
private suspend fun updateAddButton(isEnabled: Boolean) {
dispatchOnMain(Screen.UpdateAddButton(ViewStates.AddButton(isEnabled)))
}
private fun canHandleToken(blockchain: Blockchain): Boolean {
val card = globalState.scanResponse?.card ?: return false
return card.canHandleToken(blockchain)
}
@Throws
private fun throwUnAppropriateInitialization(objName: String) {
throw AddCustomTokenException.UnAppropriateInitializationException(
"AddCustomTokenHub", "$objName must be not NULL"
)
}
private suspend fun CustomTokenFieldId.addError(error: AddCustomTokenError) {
dispatchOnMain(FieldError.Add(this, error))
}
@ -469,46 +550,6 @@ internal class AddCustomTokenHub : BaseStoreHub<AddCustomTokenState>("AddCustomT
return error
}
private suspend fun fillTokenFields(
token: CoinsResponse.Coin,
coinNetwork: CoinsResponse.Coin.Network,
) {
val blockchain = Blockchain.fromNetworkId(coinNetwork.networkId) ?: Blockchain.Unknown
Network.setFieldValue(Field.Data(blockchain, false))
Name.setFieldValue(Field.Data(token.name, false))
Symbol.setFieldValue(Field.Data(token.symbol, false))
Decimals.setFieldValue(Field.Data(coinNetwork.decimalCount.toString(), false))
dispatchOnMain(UpdateForm(hubState))
}
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 updateTokenDetailFields(isEnabled: Boolean = true) {
val state = hubState
val action = Screen.UpdateTokenFields(listOf(
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 updateBlockchainNetworkField(isEnabled: Boolean) {
val action = Screen.UpdateTokenFields(listOf(
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)))
}
@ -520,18 +561,6 @@ internal class AddCustomTokenHub : BaseStoreHub<AddCustomTokenState>("AddCustomT
private suspend fun AddCustomTokenError.Warning.replaceBy(to: AddCustomTokenError.Warning) {
dispatchOnMain(Warning.Replace(setOf(this), setOf(to)))
}
private fun canHandleToken(blockchain: Blockchain): Boolean {
val card = globalState.scanResponse?.card ?: return false
return card.canHandleToken(blockchain)
}
@Throws
private fun throwUnAppropriateInitialization(objName: String) {
throw AddCustomTokenException.UnAppropriateInitializationException(
"AddCustomTokenHub", "$objName must be not NULL"
)
}
}
private class AddCustomTokenReducer(
@ -671,6 +700,13 @@ private class AddCustomTokenReducer(
newScreenState.copy(decimals = it.second)
}
}
DerivationPath -> {
if (state.screenState.derivationPath == it.second) {
newScreenState
} else {
newScreenState.copy(derivationPath = it.second)
}
}
else -> newScreenState
}
}

View file

@ -206,7 +206,7 @@ data class AddCustomTokenState(
private fun getSupportedDerivations(card: Card): List<Blockchain> {
val evmBlockchains = Blockchain.values().filter {
card.isTestCard == it.isTestnet() && it.getChainId() != null
card.isTestCard == it.isTestnet() && it.isEvm()
}
return listOf(Blockchain.Unknown) + evmBlockchains
}

View file

@ -2,8 +2,6 @@ package com.tangem.domain.redux
import android.webkit.ValueCallback
import com.tangem.domain.common.FeatureCoroutineExceptionHandler
import com.tangem.domain.common.extensions.withIOContext
import com.tangem.domain.common.extensions.withMainContext
import com.tangem.domain.redux.global.DomainGlobalState
import kotlinx.coroutines.*
import org.rekotlin.Action
@ -105,13 +103,4 @@ internal abstract class BaseStoreHub<State>(
protected abstract fun getHubState(storeState: DomainState): State
protected abstract fun updateStoreState(storeState: DomainState, newHubState: State): DomainState
}
internal suspend inline fun ReStoreHub<*, *>.dispatchOnMain(vararg actions: Action) {
withMainContext { actions.forEach { domainStore.dispatch(it) } }
}
internal suspend inline fun ReStoreHub<*, *>.dispatchOnIO(vararg actions: Action) {
withIOContext { actions.forEach { domainStore.dispatch(it) } }
}
}

View file

@ -0,0 +1,17 @@
package com.tangem.domain.redux.extensions
import com.tangem.domain.common.extensions.withIOContext
import com.tangem.domain.common.extensions.withMainContext
import com.tangem.domain.redux.domainStore
import org.rekotlin.Action
/**
[REDACTED_AUTHOR]
*/
internal suspend inline fun dispatchOnMain(vararg actions: Action) {
withMainContext { actions.forEach { domainStore.dispatch(it) } }
}
internal suspend inline fun dispatchOnIO(vararg actions: Action) {
withIOContext { actions.forEach { domainStore.dispatch(it) } }
}