Updated on 2026-08-14

This commit is contained in:
Tangem 2022-04-13 10:30:27 +03:00
parent 35d74021ac
commit 0a25bbedbb
17 changed files with 224 additions and 173 deletions

View file

@ -0,0 +1,31 @@
package com.tangem.tap.common.compose
import androidx.annotation.StringRes
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import com.tangem.blockchain.common.Blockchain
import com.tangem.domain.common.form.Field
@Composable
fun BlockchainSpinner(
@StringRes title: Int,
itemList: List<Blockchain>,
selectedItem: Field.Data<Blockchain>,
isEnabled: Boolean = true,
textFieldConverter: (Blockchain) -> String,
dropdownItemView: @Composable ((Blockchain) -> Unit)? = null,
onItemSelected: (Blockchain) -> Unit,
) {
OutlinedSpinner(
modifier = Modifier.fillMaxWidth(),
label = stringResource(id = title),
itemList = itemList,
selectedItem = selectedItem,
textFieldConverter = textFieldConverter,
dropdownItemView = dropdownItemView,
isEnabled = isEnabled,
onItemSelected = onItemSelected
)
}

View file

@ -4,8 +4,8 @@ import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.LocalTextStyle
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.runtime.*
@ -22,6 +22,7 @@ import com.tangem.domain.DomainStateDialog
import com.tangem.domain.redux.domainStore
import com.tangem.domain.redux.global.DomainGlobalAction
import com.tangem.domain.redux.global.DomainGlobalState
import com.tangem.tap.features.tokens.addCustomToken.compose.SelectTokenNetworkDialog
import org.rekotlin.StoreSubscriber
@Composable
@ -56,15 +57,7 @@ fun ShowTheDialog(dialogState: MutableState<DomainStateDialog?>) {
val onDismissRequest = { domainStore.dispatch(DomainGlobalAction.ShowDialog(null)) }
when (val dialog = dialogState.value) {
is DomainDialog.SelectTokenDialog -> {
SimpleDialog(
title = "Select a token",
items = dialog.items,
itemNameConverter = dialog.itemNameConverter,
onSelect = dialog.onSelect,
onDismissRequest = onDismissRequest
)
}
is DomainDialog.SelectTokenDialog -> SelectTokenNetworkDialog(dialog, onDismissRequest)
}
}
@ -75,9 +68,9 @@ fun ShowTheDialog(dialogState: MutableState<DomainStateDialog?>) {
fun <T> SimpleDialog(
title: String,
items: List<T>,
itemNameConverter: (T) -> String,
onSelect: (T) -> Unit,
onDismissRequest: () -> Unit
onDismissRequest: () -> Unit,
itemContent: @Composable (T) -> Unit,
) {
Dialog(
properties = DialogProperties(false, false),
@ -85,7 +78,7 @@ fun <T> SimpleDialog(
) {
Surface(
modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(8.dp)
shape = MaterialTheme.shapes.medium
) {
Column(
modifier = Modifier.padding(22.dp)
@ -112,11 +105,7 @@ fun <T> SimpleDialog(
onDismissRequest()
},
verticalAlignment = Alignment.CenterVertically,
) {
Text(
text = itemNameConverter(item),
)
}
) { itemContent(item) }
}
}
}

View file

@ -5,6 +5,8 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.tooling.preview.Preview
import com.tangem.blockchain.common.Blockchain
import com.tangem.common.extensions.VoidCallback
@ -14,17 +16,16 @@ import com.tangem.tap.common.extensions.ValueCallback
/**
[REDACTED_AUTHOR]
*/
private class OutlinedSpinner
@OptIn(ExperimentalMaterialApi::class)
@Composable
fun <T> OutlinedSpinner(
modifier: Modifier = Modifier,
title: String,
label: String,
itemList: List<T>,
selectedItem: Field.Data<T>,
onItemSelected: ValueCallback<T>,
itemNameConverter: (T) -> String = { it.toString() },
textFieldConverter: (T) -> String = { it.toString() },
dropdownItemView: @Composable ((T) -> Unit)? = null,
isEnabled: Boolean = true,
onClose: VoidCallback = {}
) {
@ -48,24 +49,27 @@ fun <T> OutlinedSpinner(
expanded = rIsExpanded.value,
onExpandedChange = { rIsExpanded.value = !rIsExpanded.value },
) {
OutlinedTextField(
modifier = modifier,
readOnly = true,
enabled = isEnabled,
value = itemNameConverter(rSelectedItem.value),
onValueChange = {},
label = { Text(title) },
trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = rIsExpanded.value) },
)
ProvideTextStyle(value = TextStyle(color = Color.Blue)) {
OutlinedTextField(
modifier = modifier,
readOnly = true,
enabled = isEnabled,
value = textFieldConverter(rSelectedItem.value),
onValueChange = {},
label = { Text(label) },
trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = rIsExpanded.value) },
)
}
ExposedDropdownMenu(
expanded = rIsExpanded.value,
onDismissRequest = onDismissRequest,
) {
itemList.forEach { item ->
DropdownMenuItem(
onClick = { onItemSelectedInternal(item) }
) {
Text(itemNameConverter(item))
DropdownMenuItem(onClick = { onItemSelectedInternal(item) }) {
when (dropdownItemView) {
null -> Text(textFieldConverter(item))
else -> dropdownItemView(item)
}
}
}
}
@ -77,7 +81,7 @@ fun <T> OutlinedSpinner(
fun TestSpinnerPreview() {
Scaffold() {
OutlinedSpinner(
title = "Blockchain name",
label = "Blockchain name",
itemList = listOf(Blockchain.values()),
selectedItem = Field.Data(Blockchain.Avalanche),
onItemSelected = {},

View file

@ -28,8 +28,6 @@ import com.tangem.tap.common.compose.extensions.stringResourceDefault
/**
[REDACTED_AUTHOR]
*/
private class OutlinedTextFieldWidget
@Composable
fun OutlinedTextFieldWidget(
modifier: Modifier = Modifier,
@ -90,7 +88,7 @@ private fun OutlinedProgressTextField(
val rTextDebouncer = valueDebouncerAsState(debounce, onTextChanged)
val rText = remember { mutableStateOf(textFieldData.value) }
fun updateFieldValueAndEmmit(value: String){
fun updateFieldValueAndEmmit(value: String) {
rText.value = value
rTextDebouncer.emmit(value)
}

View file

@ -40,28 +40,28 @@ fun SpacerH24(modifier: Modifier = Modifier) {
// ***************************** Vertical
@Composable
fun SpacerV(width: Dp, modifier: Modifier = Modifier) {
fun SpacerW(width: Dp, modifier: Modifier = Modifier) {
Spacer(modifier = modifier.width(width))
}
@Composable
fun SpacerV4(modifier: Modifier = Modifier) {
SpacerV(4.dp, modifier)
fun SpacerW4(modifier: Modifier = Modifier) {
SpacerW(4.dp, modifier)
}
@Composable
fun SpacerV8(modifier: Modifier = Modifier) {
SpacerV(8.dp, modifier)
fun SpacerW8(modifier: Modifier = Modifier) {
SpacerW(8.dp, modifier)
}
@Composable
fun SpacerV16(modifier: Modifier = Modifier) {
SpacerV(16.dp, modifier)
fun SpacerW16(modifier: Modifier = Modifier) {
SpacerW(16.dp, modifier)
}
@Composable
fun SpacerV24(modifier: Modifier = Modifier) {
SpacerV(24.dp, modifier)
fun SpacerW24(modifier: Modifier = Modifier) {
SpacerW(24.dp, modifier)
}
// ***************************** Size

View file

@ -0,0 +1,27 @@
package com.tangem.tap.common.compose
import androidx.compose.foundation.layout.Column
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.sp
/**
[REDACTED_AUTHOR]
* Compose views are not typically used as a main or base view.
*/
@Composable
fun TitleSubtitle(
title: String,
subtitle: String
) {
Column() {
Text(text = title)
Text(
text = subtitle,
fontSize = 12.sp,
color = Color.Gray
)
}
}

View file

@ -13,7 +13,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.tangem.tap.common.compose.SpacerV4
import com.tangem.tap.common.compose.SpacerW4
@Composable
fun StoriesProgressBar(
@ -68,7 +68,7 @@ fun StoriesProgressBar(
) {}
}
if (index != steps) {
SpacerV4()
SpacerW4()
}
}
}

View file

@ -35,10 +35,15 @@ class CustomTokenWarningConverter(
override fun convertError(error: DomainError): String {
val customTokenWarning = (error as? AddCustomTokenWarning) ?: throw UnsupportedOperationException()
val resId = when (customTokenWarning) {
val rawMessage = when (customTokenWarning) {
AddCustomTokenWarning.PotentialScamToken -> R.string.custom_token_validation_error_not_found
AddCustomTokenWarning.TokenAlreadyAdded -> R.string.custom_token_validation_error_already_added
AddCustomTokenWarning.Network.CheckAddressRequestError -> "CheckAddressRequestError"
}
return when (rawMessage) {
is Int -> context.getString(rawMessage)
is String -> rawMessage
else -> "Unknown error: ${customTokenWarning::class.java.simpleName}"
}
return context.getString(resId)
}
}

View file

@ -2,12 +2,10 @@ package com.tangem.tap.features.tokens.addCustomToken.compose
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.Scaffold
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.material.rememberScaffoldState
import androidx.compose.material.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@ -29,10 +27,7 @@ import com.tangem.domain.features.addCustomToken.redux.AddCustomTokenState
import com.tangem.domain.features.addCustomToken.redux.ScreenState
import com.tangem.domain.features.addCustomToken.redux.ViewStates
import com.tangem.domain.redux.domainStore
import com.tangem.tap.common.compose.ComposeDialogManager
import com.tangem.tap.common.compose.OutlinedTextFieldWidget
import com.tangem.tap.common.compose.SpacerH8
import com.tangem.tap.common.compose.keyboardObserverAsState
import com.tangem.tap.common.compose.*
import com.tangem.tap.features.tokens.addCustomToken.CustomTokenErrorConverter
import com.tangem.tap.features.tokens.addCustomToken.CustomTokenWarningConverter
import com.tangem.wallet.R
@ -52,12 +47,12 @@ fun AddCustomTokenScreen(state: MutableState<AddCustomTokenState>) {
) {
Box(Modifier.fillMaxSize()) {
LazyColumn(
contentPadding = PaddingValues(bottom = 80.dp)
contentPadding = PaddingValues(bottom = 90.dp)
) {
item {
Surface(
modifier = Modifier.padding(16.dp),
shape = RoundedCornerShape(4.dp),
shape = MaterialTheme.shapes.small,
elevation = 4.dp,
) {
Column(
@ -143,7 +138,7 @@ private fun TokenNameView(screenFieldData: ScreenFieldData) {
error = screenFieldData.error,
errorConverter = screenFieldData.errorConverter,
) {
domainStore.dispatch(OnTokenFieldChanged(screenFieldData.field.id, Field.Data(it)))
domainStore.dispatch(OnTokenNameChanged(Field.Data(it)))
}
SpacerH8()
}
@ -153,14 +148,14 @@ private fun TokenNetworkView(screenFieldData: ScreenFieldData) {
if (!screenFieldData.viewState.isVisible) return
val notSelected = stringResource(id = R.string.custom_token_network_input_not_selected)
val networkField = screenFieldData.field as TokenNetworkField
val networkField = screenFieldData.field as TokenBlockchainField
TokenNetworkSpinner(
BlockchainSpinner(
title = R.string.custom_token_network_input_title,
itemList = networkField.itemList,
selectedItem = networkField.data,
isEnabled = screenFieldData.viewState.isEnabled,
itemNameConverter = { AddCustomTokenState.convertBlockchainName(it, notSelected) },
textFieldConverter = { AddCustomTokenState.convertBlockchainName(it, notSelected) },
) { domainStore.dispatch(OnTokenNetworkChanged(Field.Data(it))) }
SpacerH8()
}
@ -178,7 +173,7 @@ private fun TokenSymbolView(screenFieldData: ScreenFieldData) {
isEnabled = screenFieldData.viewState.isEnabled,
error = screenFieldData.error,
errorConverter = screenFieldData.errorConverter,
) { domainStore.dispatch(OnTokenFieldChanged(screenFieldData.field.id, Field.Data(it))) }
) { domainStore.dispatch(OnTokenSymbolChanged(Field.Data(it))) }
SpacerH8()
}
@ -207,12 +202,17 @@ private fun TokenDerivationPathView(screenFieldData: ScreenFieldData) {
val notSelected = stringResource(id = R.string.custom_token_derivation_path_default)
val networkField = screenFieldData.field as TokenDerivationPathField
TokenNetworkSpinner(
title = R.string.custom_token_network_input_title,
BlockchainSpinner(
title = R.string.custom_token_derivation_path_input_title,
itemList = networkField.itemList,
selectedItem = networkField.data,
isEnabled = screenFieldData.viewState.isEnabled,
itemNameConverter = { AddCustomTokenState.convertDerivationPathName(it, notSelected) },
textFieldConverter = { AddCustomTokenState.convertBlockchainName(it, notSelected) },
dropdownItemView = { blockchain ->
val derivationPathLabel = AddCustomTokenState.convertDerivationPathLabel(blockchain, notSelected)
val blockchainName = AddCustomTokenState.convertBlockchainName(blockchain, notSelected)
TitleSubtitle(derivationPathLabel, blockchainName)
}
) { domainStore.dispatch(OnTokenDerivationPathChanged(Field.Data(it))) }
SpacerH8()
}
@ -227,13 +227,13 @@ private fun Warnings(warnings: List<AddCustomTokenWarning>) {
Column {
warnings.forEachIndexed { index, item ->
val modifier = when (index) {
0 -> Modifier.padding(16.dp, 0.dp, 16.dp, 16.dp)
warnings.lastIndex -> Modifier.padding(16.dp, 16.dp, 16.dp, 16.dp)
else -> Modifier.padding(16.dp, 16.dp, 16.dp, 0.dp)
0 -> Modifier.padding(16.dp, 16.dp, 16.dp, 0.dp)
warnings.lastIndex -> Modifier.padding(16.dp, 8.dp, 16.dp, 16.dp)
else -> Modifier.padding(16.dp, 8.dp, 16.dp, 0.dp)
}
Surface(
modifier = modifier.fillMaxWidth(),
shape = RoundedCornerShape(4.dp),
shape = MaterialTheme.shapes.small,
color = colorResource(id = R.color.darkGray2),
contentColor = colorResource(id = R.color.darkGray3)
) {
@ -248,6 +248,30 @@ private fun Warnings(warnings: List<AddCustomTokenWarning>) {
}
}
@Composable
private fun AddButton(
modifier: Modifier = Modifier,
isEnabled: Boolean,
textId: Int = R.string.common_add,
onClick: () -> Unit,
) {
Button(
textId = textId,
isEnabled = isEnabled,
modifier = modifier
.height(52.dp)
.padding(horizontal = 16.dp)
.fillMaxWidth(),
leadingView = {
Icon(
imageVector = Icons.Filled.Add,
contentDescription = "Add",
)
},
onClick = onClick
)
}
private data class ScreenFieldData(
val field: DataField<*>,
val error: AddCustomTokenError?,

View file

@ -1,66 +0,0 @@
package com.tangem.tap.features.tokens.addCustomToken.compose
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Icon
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.tangem.blockchain.common.Blockchain
import com.tangem.domain.common.form.Field
import com.tangem.tap.common.compose.Button
import com.tangem.tap.common.compose.OutlinedSpinner
import com.tangem.tap.common.extensions.ValueCallback
import com.tangem.wallet.R
/**
[REDACTED_AUTHOR]
*/
@Composable
fun TokenNetworkSpinner(
title: Int,
itemList: List<Blockchain>,
selectedItem: Field.Data<Blockchain>,
isEnabled: Boolean = true,
itemNameConverter: (Blockchain) -> String,
onItemSelected: ValueCallback<Blockchain>,
) {
OutlinedSpinner(
modifier = Modifier.fillMaxWidth(),
title = stringResource(id = title),
itemList = itemList,
selectedItem = selectedItem,
itemNameConverter = itemNameConverter,
isEnabled = isEnabled,
onItemSelected = onItemSelected
)
}
@Composable
fun AddButton(
modifier: Modifier = Modifier,
isEnabled: Boolean,
textId: Int = R.string.common_add,
onClick: () -> Unit,
) {
Button(
textId = textId,
isEnabled = isEnabled,
modifier = modifier
.height(52.dp)
.padding(horizontal = 16.dp)
.fillMaxWidth(),
leadingView = {
Icon(
imageVector = Icons.Filled.Add,
contentDescription = "Add",
)
},
onClick = onClick
)
}

View file

@ -0,0 +1,21 @@
package com.tangem.tap.features.tokens.addCustomToken.compose
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import com.tangem.domain.DomainDialog
import com.tangem.tap.common.compose.SimpleDialog
import com.tangem.tap.common.compose.TitleSubtitle
import com.tangem.wallet.R
/**
[REDACTED_AUTHOR]
*/
@Composable
fun SelectTokenNetworkDialog(dialog: DomainDialog.SelectTokenDialog, onDismissRequest: () -> Unit) {
SimpleDialog(
title = stringResource(id = R.string.custom_token_type_network),
items = dialog.items,
onSelect = dialog.onSelect,
onDismissRequest = onDismissRequest
) { contract -> TitleSubtitle(dialog.networkIdConverter(contract.networkId), contract.address) }
}

View file

@ -12,7 +12,7 @@ sealed class DomainDialog : DomainStateDialog {
data class SelectTokenDialog(
val items: List<Coins.CheckAddressResponse.Token.Contract>,
val itemNameConverter: (Coins.CheckAddressResponse.Token.Contract) -> String,
val networkIdConverter: (String) -> String,
val onSelect: (Coins.CheckAddressResponse.Token.Contract) -> Unit,
val onClose: VoidCallback = {}
) : DomainDialog()

View file

@ -15,35 +15,36 @@ class AddCustomTokenManager(
suspend fun checkAddress(
contractAddress: String,
networkId: String? = null
): List<Coins.CheckAddressResponse.Token> {
): Result<List<Coins.CheckAddressResponse.Token>> {
val result = tangemTechService.coins.checkAddress(contractAddress, networkId)
return when (result) {
is Result.Success -> {
val resultTokens = result.data.tokens
val newTokensList = mutableListOf<Coins.CheckAddressResponse.Token>()
resultTokens.forEach {
val contractsWithTheSameAddress = it.contracts.filter { it.address == contractAddress }
var tokensList = mutableListOf<Coins.CheckAddressResponse.Token>()
resultTokens.forEach { token ->
val contractsWithTheSameAddress = token.contracts
.filter { it.address == contractAddress }
.filter { it.decimalCount != null }
if (contractsWithTheSameAddress.isNotEmpty()) {
val newToken = it.copy(contracts = contractsWithTheSameAddress)
newTokensList.add(newToken)
val newToken = token.copy(contracts = contractsWithTheSameAddress)
tokensList.add(newToken)
}
}
when {
if (tokensList.size > 1) {
// https://tangem.slack.com/archives/GMXC6PP71/p1649672562078679
newTokensList.size > 1 -> listOf(newTokensList[0])
else -> newTokensList
tokensList = mutableListOf(tokensList[0])
}
Result.Success(tokensList)
}
is Result.Failure -> emptyList()
is Result.Failure -> result
}
}
suspend fun tokens(): List<Coins.TokensResponse.Token> {
val result = tangemTechService.coins.tokens()
return when (result) {
return when (val result = tangemTechService.coins.tokens()) {
is Result.Success -> {
val currencies = result.data.tokens
currencies.filter {
val tokens = result.data.tokens
tokens.filter {
it.contracts.isNullOrEmpty()
}
}

View file

@ -18,4 +18,8 @@ sealed class AddCustomTokenError : AnError(ERROR_CODE_ADD_CUSTOM_TOKEN, "Add cus
sealed class AddCustomTokenWarning : AnError(ERROR_CODE_ADD_CUSTOM_TOKEN, "Add custom token - warning") {
object PotentialScamToken : AddCustomTokenWarning()
object TokenAlreadyAdded : AddCustomTokenWarning()
sealed class Network : AddCustomTokenWarning() {
object CheckAddressRequestError : Network()
}
}

View file

@ -21,7 +21,7 @@ data class TokenField(
override val id: FieldId,
) : BaseDataField<String>(id, Field.Data(""))
data class TokenNetworkField(
data class TokenBlockchainField(
override val id: FieldId,
val itemList: List<Blockchain>,
) : BaseDataField<Blockchain>(id, Field.Data(Blockchain.Unknown))

View file

@ -25,6 +25,9 @@ import org.rekotlin.Action
*/
internal class AddCustomTokenHub : BaseStoreHub<AddCustomTokenState>("AddCustomTokenHub") {
private val hubState: AddCustomTokenState
get() = domainStore.state.addCustomTokensState
override fun getHubState(storeState: DomainState): AddCustomTokenState {
return storeState.addCustomTokensState
}
@ -41,7 +44,6 @@ internal class AddCustomTokenHub : BaseStoreHub<AddCustomTokenState>("AddCustomT
if (action !is AddCustomTokenAction) return
// val card = storeState.globalState.scanResponse?.card
// ?: throw IllegalStateException("ScanResponse must be set before showing the AddCustomToken screen")
val hubState = storeState.addCustomTokensState
when (action) {
is OnCreate -> {
@ -102,7 +104,7 @@ internal class AddCustomTokenHub : BaseStoreHub<AddCustomTokenState>("AddCustomT
// dispatchOnMain()
}
is FillTokenFields -> {
val networkField = getField<TokenNetworkField>(Network, hubState)
val networkField = getField<TokenBlockchainField>(Network, hubState)
val nameField = getField<TokenField>(Name, hubState)
val symbolField = getField<TokenField>(Symbol, hubState)
val decimalsField = getField<TokenField>(Decimals, hubState)
@ -127,13 +129,22 @@ internal class AddCustomTokenHub : BaseStoreHub<AddCustomTokenState>("AddCustomT
): List<Coins.CheckAddressResponse.Token> {
dispatchOnMain(Screen.UpdateTokenFields(listOf(ContractAddress to ViewStates.TokenField(isLoading = true))))
val tokenManager = hubState.addCustomTokenManager
val field = getField<TokenNetworkField>(Network, hubState)
val field = getField<TokenBlockchainField>(Network, hubState)
val selectedNetworkId: String? = field.data.value.let {
if (it == Blockchain.Unknown) null else it
}?.toNetworkId()
val foundTokens = tokenManager.checkAddress(contractAddress, selectedNetworkId)
// delay(1000)
val result = when (val foundTokensResult = tokenManager.checkAddress(contractAddress, selectedNetworkId)) {
is Result.Success -> foundTokensResult.data
is Result.Failure -> {
// val warning = AddCustomTokenWarning.Network.CheckAddressRequestError
// dispatchOnMain(Warning.Add(setOf(warning)))
emptyList()
}
}
dispatchOnMain(Screen.UpdateTokenFields(listOf(ContractAddress to ViewStates.TokenField(isLoading = false))))
return foundTokens
return result
}
private suspend fun checkToken(
@ -171,12 +182,18 @@ internal class AddCustomTokenHub : BaseStoreHub<AddCustomTokenState>("AddCustomT
else -> {
val dialog = DomainDialog.SelectTokenDialog(
items = contracts,
itemNameConverter = { it.address },
networkIdConverter = { networkId ->
val blockchain = Blockchain.fromNetworkId(networkId)
if (blockchain == Blockchain.Unknown) {
throw DomainException.SelectTokeNetworkException(networkId)
}
AddCustomTokenState.convertBlockchainName(blockchain, "")
},
onSelect = { selectedContract ->
hubScope.launch {
// find how to connect to the upper coroutineContext and dispatch through them
dispatchOnMain(FillTokenFields(token, selectedContract))
dispatchOnMain(FillTokenFields(token, selectedContract))
dispatchOnMain(actionsLockTokenFields())
}
},
)
@ -237,7 +254,7 @@ internal class AddCustomTokenHub : BaseStoreHub<AddCustomTokenState>("AddCustomT
updateFormState(state)
}
is OnTokenNetworkChanged -> {
val field: TokenNetworkField = getField(Network, state)
val field: TokenBlockchainField = getField(Network, state)
field.data = action.value
updateFormState(state)
}

View file

@ -49,22 +49,17 @@ data class AddCustomTokenState(
companion object {
fun convertBlockchainName(blockchain: Blockchain, unknown: String): String = when (blockchain) {
Blockchain.Unknown -> unknown
Blockchain.Cardano -> "Cardano"
Blockchain.CardanoShelley -> "Cardano Shelley"
else -> blockchain.fullName
}
fun convertDerivationPathName(blockchain: Blockchain, unknown: String): String = when (blockchain) {
Blockchain.Unknown -> unknown
Blockchain.BSC -> "BNB Smart Chain"
Blockchain.Fantom -> "Fantom Opera"
else -> blockchain.fullName
fun convertDerivationPathLabel(blockchain: Blockchain, unknown: String): String {
return blockchain.derivationPath()?.rawPath ?: unknown
}
private fun createFormFields(): List<DataField<*>> {
return listOf(
TokenField(ContractAddress),
TokenNetworkField(Network, getSupportedNetworks()),
TokenBlockchainField(Network, getSupportedNetworks()),
TokenField(Name),
TokenField(Symbol),
TokenField(Decimals),
@ -84,6 +79,7 @@ data class AddCustomTokenState(
private fun getSupportedNetworks(): List<Blockchain> {
return listOf(
Blockchain.Unknown,
Blockchain.Ethereum,
Blockchain.BSC,
Blockchain.Binance,