Updated on 2026-08-14
This commit is contained in:
parent
8262c72f40
commit
65a2c8e9db
7 changed files with 180 additions and 75 deletions
|
|
@ -67,6 +67,8 @@ internal data class AddCustomTokenChooseTokenBottomSheet(
|
|||
* @property tokenSymbolInputField input field to enter the token symbol
|
||||
* @property decimalsInputField input field to enter the token decimals
|
||||
* @property derivationPathSelectorField selector field to select the derivation path
|
||||
* @property derivationPathInputField input field for a custom derivation path
|
||||
* @property showTokenFields if token fields should be shown
|
||||
*/
|
||||
internal data class AddCustomTokenForm(
|
||||
val contractAddressInputField: AddCustomTokenInputField.ContactAddress,
|
||||
|
|
@ -75,6 +77,8 @@ internal data class AddCustomTokenForm(
|
|||
val tokenSymbolInputField: AddCustomTokenInputField.TokenSymbol,
|
||||
val decimalsInputField: AddCustomTokenInputField.Decimals,
|
||||
val derivationPathSelectorField: AddCustomTokenSelectorField.DerivationPath?,
|
||||
val derivationPathInputField: AddCustomTokenInputField.DerivationPath?,
|
||||
val showTokenFields: Boolean = false,
|
||||
)
|
||||
|
||||
/** Base input field model of add custom token screen */
|
||||
|
|
@ -174,6 +178,25 @@ internal sealed interface AddCustomTokenInputField {
|
|||
override val placeholder: TextReference,
|
||||
val isEnabled: Boolean,
|
||||
) : AddCustomTokenInputField
|
||||
|
||||
/**
|
||||
* Input field model to enter a custom derivation path
|
||||
*
|
||||
* @property value current value
|
||||
* @property onValueChange lambda be invoked when value is been changed
|
||||
* @property keyboardOptions keyboard options
|
||||
* @property label label
|
||||
* @property placeholder placeholder (hint)
|
||||
* @property showField whether the field should be shown
|
||||
*/
|
||||
data class DerivationPath(
|
||||
override val value: String,
|
||||
override val onValueChange: (String) -> Unit,
|
||||
override val keyboardOptions: KeyboardOptions,
|
||||
override val label: TextReference,
|
||||
override val placeholder: TextReference,
|
||||
val showField: Boolean = false,
|
||||
) : AddCustomTokenInputField
|
||||
}
|
||||
|
||||
/** Base selector field model of add custom token screen */
|
||||
|
|
@ -251,10 +274,15 @@ internal sealed interface AddCustomTokenSelectorField {
|
|||
override val title: TextReference,
|
||||
override val blockchain: Blockchain,
|
||||
val subtitle: TextReference,
|
||||
val type: DerivationPathSelectorType = DerivationPathSelectorType.BLOCKCHAIN,
|
||||
) : SelectorItem
|
||||
}
|
||||
}
|
||||
|
||||
enum class DerivationPathSelectorType {
|
||||
DEFAULT, CUSTOM, BLOCKCHAIN
|
||||
}
|
||||
|
||||
/**
|
||||
* Warning model of add custom token screen
|
||||
*
|
||||
|
|
@ -276,6 +304,10 @@ internal sealed class AddCustomTokenWarning(val description: TextReference) {
|
|||
object UnsupportedSolanaToken : AddCustomTokenWarning(
|
||||
description = TextReference.Res(R.string.alert_manage_tokens_unsupported_message),
|
||||
)
|
||||
|
||||
object WrongDerivationPath : AddCustomTokenWarning(
|
||||
description = TextReference.Res(R.string.custom_token_invalid_derivation_path),
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -4,14 +4,7 @@ import androidx.compose.foundation.text.KeyboardOptions
|
|||
import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.tap.features.customtoken.impl.presentation.models.AddCustomTokenChooseTokenBottomSheet
|
||||
import com.tangem.tap.features.customtoken.impl.presentation.models.AddCustomTokenFloatingButton
|
||||
import com.tangem.tap.features.customtoken.impl.presentation.models.AddCustomTokenForm
|
||||
import com.tangem.tap.features.customtoken.impl.presentation.models.AddCustomTokenInputField
|
||||
import com.tangem.tap.features.customtoken.impl.presentation.models.AddCustomTokenSelectorField
|
||||
import com.tangem.tap.features.customtoken.impl.presentation.models.AddCustomTokenTestBlock
|
||||
import com.tangem.tap.features.customtoken.impl.presentation.models.AddCustomTokenWarning
|
||||
import com.tangem.tap.features.customtoken.impl.presentation.models.AddCustomTokensToolbar
|
||||
import com.tangem.tap.features.customtoken.impl.presentation.models.*
|
||||
import com.tangem.tap.features.customtoken.impl.presentation.states.AddCustomTokenStateHolder
|
||||
import com.tangem.tap.features.details.ui.cardsettings.TextReference
|
||||
import com.tangem.wallet.R
|
||||
|
|
@ -85,6 +78,7 @@ internal object AddCustomTokenPreviewData {
|
|||
onMenuItemClick = {},
|
||||
isEnabled = true,
|
||||
),
|
||||
derivationPathInputField = null,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,31 +1,11 @@
|
|||
package com.tangem.tap.features.customtoken.impl.presentation.ui.components
|
||||
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.slideInVertically
|
||||
import androidx.compose.animation.slideOutVertically
|
||||
import androidx.compose.animation.*
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.Card
|
||||
import androidx.compose.material.DropdownMenuItem
|
||||
import androidx.compose.material.ExperimentalMaterialApi
|
||||
import androidx.compose.material.ExposedDropdownMenuBox
|
||||
import androidx.compose.material.ExposedDropdownMenuDefaults
|
||||
import androidx.compose.material.LinearProgressIndicator
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.OutlinedTextField
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
|
|
@ -62,12 +42,13 @@ internal fun AddCustomTokenForm(model: AddCustomTokenForm) {
|
|||
modifier = Modifier.padding(TangemTheme.dimens.spacing16),
|
||||
verticalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing8),
|
||||
) {
|
||||
InputField(model = model.contractAddressInputField)
|
||||
if (model.showTokenFields) InputField(model = model.contractAddressInputField)
|
||||
SelectorField(model = model.networkSelectorField)
|
||||
InputField(model = model.tokenNameInputField)
|
||||
InputField(model = model.tokenSymbolInputField)
|
||||
InputField(model = model.decimalsInputField)
|
||||
if (model.showTokenFields) InputField(model = model.tokenNameInputField)
|
||||
if (model.showTokenFields) InputField(model = model.tokenSymbolInputField)
|
||||
if (model.showTokenFields) InputField(model = model.decimalsInputField)
|
||||
model.derivationPathSelectorField?.let { SelectorField(model = it) }
|
||||
if (model.derivationPathInputField?.showField == true) InputField(model = model.derivationPathInputField)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -103,6 +84,7 @@ private fun TextField(model: AddCustomTokenInputField, isError: Boolean) {
|
|||
is AddCustomTokenInputField.Decimals -> model.isEnabled
|
||||
is AddCustomTokenInputField.TokenName -> model.isEnabled
|
||||
is AddCustomTokenInputField.TokenSymbol -> model.isEnabled
|
||||
is AddCustomTokenInputField.DerivationPath -> true
|
||||
}
|
||||
|
||||
OutlinedTextField(
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import com.tangem.blockchain.common.DerivationStyle
|
|||
import com.tangem.blockchain.common.Token
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.crypto.hdWallet.DerivationPath
|
||||
import com.tangem.crypto.hdWallet.HDWalletError
|
||||
import com.tangem.domain.AddCustomTokenError
|
||||
import com.tangem.domain.common.TapWorkarounds.derivationStyle
|
||||
import com.tangem.domain.common.extensions.*
|
||||
|
|
@ -135,18 +136,28 @@ internal class AddCustomTokenViewModel @Inject constructor(
|
|||
tokenSymbolInputField = createTokenSymbolInputField(),
|
||||
decimalsInputField = createDecimalsInputField(),
|
||||
derivationPathSelectorField = createDerivationPathsSelectorField(),
|
||||
derivationPathInputField = createDerivationPathInputField(),
|
||||
)
|
||||
}
|
||||
|
||||
fun createDerivationPathSelectorItem(blockchain: Blockchain): SelectorItem.TitleWithSubtitle {
|
||||
return if (blockchain == Blockchain.Unknown) {
|
||||
SelectorItem.TitleWithSubtitle(
|
||||
fun createDerivationPathSelectorAdditionalItem(
|
||||
blockchain: Blockchain,
|
||||
type: DerivationPathSelectorType = DerivationPathSelectorType.BLOCKCHAIN,
|
||||
): SelectorItem.TitleWithSubtitle {
|
||||
return when (type) {
|
||||
DerivationPathSelectorType.DEFAULT -> SelectorItem.TitleWithSubtitle(
|
||||
title = TextReference.Res(R.string.custom_token_derivation_path_default),
|
||||
subtitle = TextReference.Res(R.string.custom_token_derivation_path_default),
|
||||
blockchain = Blockchain.Unknown,
|
||||
type = DerivationPathSelectorType.DEFAULT,
|
||||
)
|
||||
} else {
|
||||
SelectorItem.TitleWithSubtitle(
|
||||
DerivationPathSelectorType.CUSTOM -> SelectorItem.TitleWithSubtitle(
|
||||
title = TextReference.Res(R.string.custom_token_custom_derivation),
|
||||
subtitle = TextReference.Res(R.string.custom_token_custom_derivation),
|
||||
blockchain = Blockchain.Unknown,
|
||||
type = DerivationPathSelectorType.CUSTOM,
|
||||
)
|
||||
DerivationPathSelectorType.BLOCKCHAIN -> SelectorItem.TitleWithSubtitle(
|
||||
title = blockchain.derivationPath(DerivationStyle.LEGACY)?.rawPath?.let(TextReference::Str)
|
||||
?: TextReference.Res(R.string.custom_token_derivation_path_default),
|
||||
subtitle = TextReference.Str(blockchain.fullName),
|
||||
|
|
@ -175,7 +186,7 @@ internal class AddCustomTokenViewModel @Inject constructor(
|
|||
onValueChange = actionsHandler::onContactAddressValueChange,
|
||||
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
|
||||
label = TextReference.Res(R.string.custom_token_contract_address_input_title),
|
||||
placeholder = TextReference.Str(value = "0x0000000000000000000000000000000000000000"),
|
||||
placeholder = TextReference.Str(value = CONTRACT_ADDRESS_PLACEHOLDER),
|
||||
isLoading = false,
|
||||
isError = false,
|
||||
error = null,
|
||||
|
|
@ -196,8 +207,7 @@ internal class AddCustomTokenViewModel @Inject constructor(
|
|||
val defaultNetwork = createNetworkSelectorItem(blockchain = Blockchain.Unknown)
|
||||
return listOf(defaultNetwork) + Blockchain.values()
|
||||
.filter { blockchain ->
|
||||
(blockchain.isEvm() || blockchain.canHandleTokens()) &&
|
||||
reduxStateHolder.scanResponse?.card?.supportedBlockchains()?.contains(blockchain) == true
|
||||
reduxStateHolder.scanResponse?.card?.supportedBlockchains()?.contains(blockchain) == true
|
||||
}
|
||||
.sortedBy(Blockchain::fullName)
|
||||
.map(::createNetworkSelectorItem)
|
||||
|
|
@ -231,7 +241,7 @@ internal class AddCustomTokenViewModel @Inject constructor(
|
|||
onValueChange = actionsHandler::onDecimalsValueChange,
|
||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Next),
|
||||
label = TextReference.Res(R.string.custom_token_decimals_input_title),
|
||||
placeholder = TextReference.Str(value = "8"),
|
||||
placeholder = TextReference.Str(value = DECIMALS_PLACEHOLDER),
|
||||
isEnabled = false,
|
||||
)
|
||||
}
|
||||
|
|
@ -250,11 +260,31 @@ internal class AddCustomTokenViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun getDerivationPathsSelectorItems(): List<SelectorItem.TitleWithSubtitle> {
|
||||
val defaultDerivationPath = createDerivationPathSelectorItem(Blockchain.Unknown)
|
||||
return listOf(defaultDerivationPath) + Blockchain.values()
|
||||
.filter { blockchain -> blockchain.isEvm() && blockchain.isSupportedInApp() && !blockchain.isTestnet() }
|
||||
return listOf(
|
||||
createDerivationPathSelectorAdditionalItem(
|
||||
blockchain = Blockchain.Unknown,
|
||||
type = DerivationPathSelectorType.DEFAULT,
|
||||
),
|
||||
createDerivationPathSelectorAdditionalItem(
|
||||
blockchain = Blockchain.Unknown,
|
||||
type = DerivationPathSelectorType.CUSTOM,
|
||||
),
|
||||
) + Blockchain.values()
|
||||
.filter { blockchain -> blockchain.isSupportedInApp() && !blockchain.isTestnet() }
|
||||
.sortedBy(Blockchain::fullName)
|
||||
.map(::createDerivationPathSelectorItem)
|
||||
.map(::createDerivationPathSelectorAdditionalItem)
|
||||
}
|
||||
|
||||
private fun createDerivationPathInputField(): AddCustomTokenInputField.DerivationPath? {
|
||||
if (reduxStateHolder.scanResponse?.card?.settings?.isHDWalletAllowed == false) return null
|
||||
|
||||
return AddCustomTokenInputField.DerivationPath(
|
||||
value = "",
|
||||
onValueChange = actionsHandler::onDerivationPathValueChange,
|
||||
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
|
||||
label = TextReference.Res(R.string.custom_token_custom_derivation),
|
||||
placeholder = TextReference.Str(value = DERIVATION_PATH_PLACEHOLDER),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -306,25 +336,16 @@ internal class AddCustomTokenViewModel @Inject constructor(
|
|||
Timber.e(it)
|
||||
}
|
||||
|
||||
updateDerivationPathSelector()
|
||||
updateWarnings()
|
||||
updateFloatingButton()
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateDerivationPathSelector() {
|
||||
uiState = uiState.copySealed(
|
||||
form = uiState.form.copy(
|
||||
derivationPathSelectorField = uiState.form.derivationPathSelectorField?.copy(
|
||||
isEnabled = uiState.form.networkSelectorField.selectedItem.blockchain.isEvm(),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun isDerivationPathSelected(): Boolean {
|
||||
return with(uiState.form.derivationPathSelectorField?.selectedItem?.blockchain) {
|
||||
this != null && this != Blockchain.Unknown
|
||||
this != null && this != Blockchain.Unknown ||
|
||||
uiState.form.derivationPathSelectorField?.selectedItem?.type == DerivationPathSelectorType.CUSTOM &&
|
||||
!uiState.warnings.contains(AddCustomTokenWarning.WrongDerivationPath)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -397,6 +418,7 @@ internal class AddCustomTokenViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun updateFloatingButton() {
|
||||
uiState = updateStateWithDerivationError(uiState)
|
||||
if (isCustomTokenAlreadyAdded()) {
|
||||
uiState = uiState.copySealed(
|
||||
warnings = uiState.warnings + AddCustomTokenWarning.TokenAlreadyAdded,
|
||||
|
|
@ -405,6 +427,7 @@ internal class AddCustomTokenViewModel @Inject constructor(
|
|||
return
|
||||
}
|
||||
|
||||
val isCorrectDerivationInput = !uiState.warnings.contains(AddCustomTokenWarning.WrongDerivationPath)
|
||||
val state = when {
|
||||
isAllTokenFieldsFilled() && isNetworkSelected() -> {
|
||||
val networkSelectorValue = uiState.form.networkSelectorField.selectedItem.blockchain
|
||||
|
|
@ -418,7 +441,8 @@ internal class AddCustomTokenViewModel @Inject constructor(
|
|||
|
||||
uiState.copySealed(
|
||||
floatingButton = uiState.floatingButton.copy(
|
||||
isEnabled = error is ContractAddressValidatorResult.Success && isSupportedToken,
|
||||
isEnabled = error is ContractAddressValidatorResult.Success &&
|
||||
isSupportedToken && isCorrectDerivationInput,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -430,17 +454,43 @@ internal class AddCustomTokenViewModel @Inject constructor(
|
|||
else -> {
|
||||
uiState.copySealed(
|
||||
floatingButton = uiState.floatingButton.copy(
|
||||
isEnabled = if (isNetworkSelected()) !isBlockchainAlreadyAdded() else false,
|
||||
isEnabled = if (isNetworkSelected()) {
|
||||
!isBlockchainAlreadyAdded() && isCorrectDerivationInput
|
||||
} else {
|
||||
false
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
uiState = state.copySealed(
|
||||
warnings = uiState.warnings - AddCustomTokenWarning.TokenAlreadyAdded,
|
||||
warnings = state.warnings - AddCustomTokenWarning.TokenAlreadyAdded,
|
||||
)
|
||||
}
|
||||
|
||||
private fun updateStateWithDerivationError(uiState: AddCustomTokenStateHolder): AddCustomTokenStateHolder {
|
||||
val updatedWarnings = if (isWrongDerivationPathEntered(
|
||||
derivationPathSelectorType = uiState.form.derivationPathSelectorField?.selectedItem?.type,
|
||||
derivationPath = getDerivationPath(),
|
||||
)
|
||||
) {
|
||||
uiState.warnings + AddCustomTokenWarning.WrongDerivationPath
|
||||
} else {
|
||||
uiState.warnings - AddCustomTokenWarning.WrongDerivationPath
|
||||
}
|
||||
return uiState.copySealed(
|
||||
warnings = updatedWarnings,
|
||||
)
|
||||
}
|
||||
|
||||
private fun isWrongDerivationPathEntered(
|
||||
derivationPathSelectorType: DerivationPathSelectorType?,
|
||||
derivationPath: DerivationPath?,
|
||||
): Boolean {
|
||||
return derivationPathSelectorType == DerivationPathSelectorType.CUSTOM && derivationPath == null
|
||||
}
|
||||
|
||||
private fun isCustomTokenAlreadyAdded(): Boolean {
|
||||
return when (getCustomTokenType()) {
|
||||
CustomTokenType.TOKEN -> isTokenAlreadyAdded()
|
||||
|
|
@ -520,16 +570,36 @@ internal class AddCustomTokenViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun getDerivationPath(): DerivationPath? {
|
||||
return when (uiState.form.derivationPathSelectorField?.selectedItem?.type) {
|
||||
DerivationPathSelectorType.CUSTOM ->
|
||||
createDerivationPathOrNull(uiState.form.derivationPathInputField?.value ?: "")
|
||||
else ->
|
||||
getDerivationPathForBlockchain(uiState.form.derivationPathSelectorField?.selectedItem?.blockchain)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createDerivationPathOrNull(rawPath: String): DerivationPath? {
|
||||
return try {
|
||||
DerivationPath(rawPath)
|
||||
} catch (error: HDWalletError) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private fun getDerivationPathForBlockchain(blockchain: Blockchain?): DerivationPath? {
|
||||
if (blockchain == null) return null
|
||||
|
||||
val derivationStyle = if (!isDerivationPathSelected()) {
|
||||
reduxStateHolder.scanResponse?.card?.derivationStyle
|
||||
} else {
|
||||
DerivationStyle.LEGACY
|
||||
}
|
||||
|
||||
return when (val derivationNetwork = uiState.form.derivationPathSelectorField?.selectedItem?.blockchain) {
|
||||
Blockchain.Unknown -> uiState.form.networkSelectorField.selectedItem.blockchain
|
||||
else -> derivationNetwork
|
||||
}?.derivationPath(derivationStyle)
|
||||
val derivationNetwork = if (blockchain == Blockchain.Unknown) {
|
||||
uiState.form.networkSelectorField.selectedItem.blockchain
|
||||
} else {
|
||||
blockchain
|
||||
}
|
||||
return derivationNetwork.derivationPath(derivationStyle)
|
||||
}
|
||||
|
||||
private inner class ActionsHandler(private val featureRouter: CustomTokenRouter) {
|
||||
|
|
@ -566,7 +636,6 @@ internal class AddCustomTokenViewModel @Inject constructor(
|
|||
|
||||
is ContractAddressValidatorResult.Error -> {
|
||||
handleContractAddressErrorValidation(type = validatorResult.type)
|
||||
updateDerivationPathSelector()
|
||||
updateWarnings()
|
||||
updateFloatingButton()
|
||||
}
|
||||
|
|
@ -574,11 +643,13 @@ internal class AddCustomTokenViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
fun onNetworkSelectorItemClick(index: Int) {
|
||||
val selectedItem = requireNotNull(uiState.form.networkSelectorField.items.getOrNull(index))
|
||||
uiState = uiState.copySealed(
|
||||
form = uiState.form.copy(
|
||||
networkSelectorField = uiState.form.networkSelectorField.copy(
|
||||
selectedItem = requireNotNull(uiState.form.networkSelectorField.items.getOrNull(index)),
|
||||
selectedItem = selectedItem,
|
||||
),
|
||||
showTokenFields = selectedItem.blockchain.canHandleTokens(),
|
||||
),
|
||||
)
|
||||
onContactAddressValueChange(uiState.form.contractAddressInputField.value)
|
||||
|
|
@ -612,12 +683,26 @@ internal class AddCustomTokenViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
fun onDerivationPathSelectorItemClick(index: Int) {
|
||||
val field = requireNotNull(uiState.form.derivationPathSelectorField)
|
||||
val derivationSelector = requireNotNull(uiState.form.derivationPathSelectorField)
|
||||
val selected = requireNotNull(derivationSelector.items.getOrNull(index))
|
||||
val derivationInputField = requireNotNull(uiState.form.derivationPathInputField)
|
||||
uiState = uiState.copySealed(
|
||||
form = uiState.form.copy(
|
||||
derivationPathSelectorField = field.copy(
|
||||
selectedItem = requireNotNull(field.items.getOrNull(index)),
|
||||
derivationPathSelectorField = derivationSelector.copy(
|
||||
selectedItem = selected,
|
||||
),
|
||||
derivationPathInputField = derivationInputField.copy(
|
||||
showField = selected.type == DerivationPathSelectorType.CUSTOM,
|
||||
),
|
||||
),
|
||||
)
|
||||
updateFloatingButton()
|
||||
}
|
||||
|
||||
fun onDerivationPathValueChange(enteredValue: String) {
|
||||
uiState = uiState.copySealed(
|
||||
form = uiState.form.copy(
|
||||
derivationPathInputField = uiState.form.derivationPathInputField?.copy(value = enteredValue),
|
||||
),
|
||||
)
|
||||
updateFloatingButton()
|
||||
|
|
@ -691,7 +776,11 @@ internal class AddCustomTokenViewModel @Inject constructor(
|
|||
decimalsInputField = decimalsInputField.copy(value = "", isEnabled = false),
|
||||
derivationPathSelectorField = derivationPathSelectorField?.copy(
|
||||
isEnabled = true,
|
||||
selectedItem = formStateBuilder.createDerivationPathSelectorItem(Blockchain.Unknown),
|
||||
selectedItem = formStateBuilder
|
||||
.createDerivationPathSelectorAdditionalItem(
|
||||
blockchain = Blockchain.Unknown,
|
||||
type = DerivationPathSelectorType.DEFAULT,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
|
@ -722,5 +811,8 @@ internal class AddCustomTokenViewModel @Inject constructor(
|
|||
TestTokenItem(name = "USDT (invalid - 1/3 of address)", address = "Es9vMFrzaCERmJ"),
|
||||
TestTokenItem(name = "ETH (full)", address = "2FPyTwcZLUg1MDrwsyoP4D6s1tM7hAkHYRjkNb5w6Pxk"),
|
||||
)
|
||||
const val DERIVATION_PATH_PLACEHOLDER = "m/44'/0'/0'/0/0"
|
||||
const val DECIMALS_PLACEHOLDER = "8"
|
||||
const val CONTRACT_ADDRESS_PLACEHOLDER = "0x0000000000000000000000000000000000000000"
|
||||
}
|
||||
}
|
||||
|
|
@ -84,9 +84,11 @@
|
|||
<string name="custom_token_creation_error_network_not_selected">Пожалуйста, выберите сеть</string>
|
||||
<string name="custom_token_creation_error_required_field">Обязательное поле</string>
|
||||
<string name="custom_token_creation_error_wrong_decimals">Количество знаков после запятой должно быть корректным числом не больше %d</string>
|
||||
<string name="custom_token_custom_derivation">Своя деривация</string>
|
||||
<string name="custom_token_decimals_input_title">Знаков после запятой</string>
|
||||
<string name="custom_token_derivation_path_default">По умолчанию</string>
|
||||
<string name="custom_token_derivation_path_input_title">Деривация по BIP44</string>
|
||||
<string name="custom_token_invalid_derivation_path">Введенный путь деривации некорректен</string>
|
||||
<string name="custom_token_name_input_placeholder">Например, USD Coin</string>
|
||||
<string name="custom_token_name_input_title">Название токена</string>
|
||||
<string name="custom_token_network_input_not_selected">Не выбрано</string>
|
||||
|
|
|
|||
|
|
@ -82,9 +82,11 @@
|
|||
<string name="custom_token_creation_error_network_not_selected">Please select the network</string>
|
||||
<string name="custom_token_creation_error_required_field">Required field</string>
|
||||
<string name="custom_token_creation_error_wrong_decimals">Decimal number must be a valid integer, no higher than %d</string>
|
||||
<string name="custom_token_custom_derivation">Custom derivation</string>
|
||||
<string name="custom_token_decimals_input_title">Decimals</string>
|
||||
<string name="custom_token_derivation_path_default">Default</string>
|
||||
<string name="custom_token_derivation_path_input_title">BIP44 coin type</string>
|
||||
<string name="custom_token_invalid_derivation_path">The derivation path you\'ve entered is not valid</string>
|
||||
<string name="custom_token_name_input_placeholder">E.g. USD Coin</string>
|
||||
<string name="custom_token_name_input_title">Name</string>
|
||||
<string name="custom_token_network_input_not_selected">Not selected</string>
|
||||
|
|
|
|||
|
|
@ -177,4 +177,5 @@ fun Blockchain.isSupportedInApp(): Boolean {
|
|||
|
||||
private val excludedBlockchains = listOf(
|
||||
Blockchain.SaltPay,
|
||||
Blockchain.Unknown,
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue