Updated on 2026-08-14

This commit is contained in:
Tangem 2025-06-25 17:19:42 +05:00
parent 058a6ab4d5
commit 451fdc5e0b
37 changed files with 748 additions and 226 deletions

View file

@ -6,41 +6,70 @@ import androidx.compose.foundation.layout.*
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Devices
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.tangem.blockchain.common.Amount
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchain.common.transaction.Fee
import com.tangem.common.ui.amountScreen.utils.getFiatString
import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.decompose.model.getOrCreateModel
import com.tangem.core.ui.components.SpacerWMax
import com.tangem.core.ui.components.TextShimmer
import com.tangem.core.ui.components.atoms.text.EllipsisText
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.format.bigdecimal.BigDecimalFormatConstants.EMPTY_BALANCE_SIGN
import com.tangem.core.ui.format.bigdecimal.crypto
import com.tangem.core.ui.format.bigdecimal.fee
import com.tangem.core.ui.format.bigdecimal.format
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.features.send.v2.api.FeeSelectorBlockComponent
import com.tangem.features.send.v2.api.params.FeeSelectorParams
import com.tangem.features.send.v2.feeselector.entity.FeeFiatRateUM
import com.tangem.features.send.v2.feeselector.entity.FeeItem
import com.tangem.features.send.v2.feeselector.entity.FeeSelectorUM
import com.tangem.features.send.v2.feeselector.entity.PrimaryButtonConfig
import com.tangem.features.send.v2.feeselector.model.FeeSelectorModel
import com.tangem.features.send.v2.impl.R
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import kotlinx.collections.immutable.persistentListOf
import java.math.BigDecimal
@Suppress("UnusedPrivateMember")
internal class DefaultFeeSelectorBlockComponent @AssistedInject constructor(
@Assisted appComponentContext: AppComponentContext,
@Assisted params: Unit,
@Assisted params: FeeSelectorParams.FeeSelectorBlockParams,
) : FeeSelectorBlockComponent, AppComponentContext by appComponentContext {
private val model: FeeSelectorModel = getOrCreateModel(params = params)
@Composable
override fun Content(modifier: Modifier) {
FeeSelectorBlockContent(modifier = modifier)
val state by model.uiState.collectAsStateWithLifecycle()
FeeSelectorBlockContent(modifier = modifier, state = state)
}
@AssistedFactory
interface Factory : FeeSelectorBlockComponent.Factory {
override fun create(context: AppComponentContext, params: Unit): DefaultFeeSelectorBlockComponent
override fun create(
context: AppComponentContext,
params: FeeSelectorParams.FeeSelectorBlockParams,
): DefaultFeeSelectorBlockComponent
}
}
@Composable
private fun FeeSelectorBlockContent(modifier: Modifier = Modifier) {
private fun FeeSelectorBlockContent(state: FeeSelectorUM, modifier: Modifier = Modifier) {
Row(
modifier = modifier
.background(TangemTheme.colors.background.action)
@ -67,26 +96,90 @@ private fun FeeSelectorBlockContent(modifier: Modifier = Modifier) {
contentDescription = null,
tint = TangemTheme.colors.icon.informative,
)
Spacer(modifier = Modifier.weight(1f))
Text(
text = "~ 0.25 \$",
style = TangemTheme.typography.body1,
color = TangemTheme.colors.text.tertiary,
)
Icon(
modifier = Modifier.size(width = 18.dp, height = 24.dp),
painter = painterResource(id = R.drawable.ic_select_18_24),
contentDescription = null,
tint = TangemTheme.colors.icon.informative,
)
SpacerWMax()
when (state) {
is FeeSelectorUM.Content -> FeeContent(state)
is FeeSelectorUM.Loading -> FeeLoading()
is FeeSelectorUM.Error -> FeeError()
}
}
}
@Composable
private fun RowScope.FeeError() {
Text(
text = EMPTY_BALANCE_SIGN,
color = TangemTheme.colors.text.primary1,
style = TangemTheme.typography.body2,
)
}
@Composable
private fun RowScope.FeeLoading() {
TextShimmer(
radius = TangemTheme.dimens.radius3,
style = TangemTheme.typography.body1,
modifier = Modifier.width(width = TangemTheme.dimens.size90),
)
}
@Composable
private fun RowScope.FeeContent(state: FeeSelectorUM.Content) {
EllipsisText(
text = if (state.feeFiatRateUM != null) {
getFiatString(
value = state.selectedFeeItem.fee.amount.value,
rate = state.feeFiatRateUM.rate,
appCurrency = state.feeFiatRateUM.appCurrency,
approximate = state.isFeeApproximate,
)
} else {
state.selectedFeeItem.fee.amount.value.format {
crypto(
symbol = state.selectedFeeItem.fee.amount.currencySymbol,
decimals = state.selectedFeeItem.fee.amount.decimals,
).fee(canBeLower = state.isFeeApproximate)
}
},
style = TangemTheme.typography.body1,
color = TangemTheme.colors.text.tertiary,
textAlign = TextAlign.End,
modifier = Modifier
.weight(1f)
.padding(start = TangemTheme.dimens.spacing4),
)
Icon(
modifier = Modifier.size(width = 18.dp, height = 24.dp),
painter = painterResource(id = R.drawable.ic_select_18_24),
contentDescription = null,
tint = TangemTheme.colors.icon.informative,
)
}
@Preview(showBackground = true, device = Devices.PIXEL_7_PRO)
@Preview(showBackground = true, device = Devices.PIXEL_7_PRO, uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
private fun FeeSelectorBlockContent_Preview() {
TangemThemePreview {
FeeSelectorBlockContent(modifier = Modifier.fillMaxWidth())
val feeItem = FeeItem.Market(
Fee.Common(amount = Amount(value = BigDecimal("0.0002876"), blockchain = Blockchain.Ethereum)),
)
FeeSelectorBlockContent(
modifier = Modifier.fillMaxWidth(),
state = FeeSelectorUM.Content(
doneButtonConfig = PrimaryButtonConfig(enabled = true, onClick = {}),
feeItems = persistentListOf(feeItem),
onFeeSelected = {},
selectedFeeItem = feeItem,
isFeeApproximate = false,
feeFiatRateUM = FeeFiatRateUM(
rate = BigDecimal("2500"),
appCurrency = AppCurrency.Default,
),
displayNonceInput = false,
nonce = null,
onNonceChange = {},
),
)
}
}

View file

@ -1,9 +1,10 @@
package com.tangem.features.send.v2.feeselector.entity
import androidx.compose.runtime.Immutable
import com.tangem.blockchain.common.Amount
import com.tangem.blockchain.common.transaction.Fee
import com.tangem.core.ui.extensions.TextReference
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.transaction.error.GetFeeError
import com.tangem.features.send.v2.subcomponents.fee.ui.state.CustomFeeFieldUM
import kotlinx.collections.immutable.ImmutableList
import java.math.BigDecimal
@ -12,33 +13,44 @@ import java.math.BigInteger
@Immutable
internal sealed class FeeSelectorUM {
data object Loading : FeeSelectorUM()
abstract val doneButtonConfig: PrimaryButtonConfig
data class Loading(private val onDone: () -> Unit) : FeeSelectorUM() {
override val doneButtonConfig = PrimaryButtonConfig(enabled = false, onClick = onDone)
}
data class Error(val error: GetFeeError, private val onDone: () -> Unit) : FeeSelectorUM() {
override val doneButtonConfig = PrimaryButtonConfig(enabled = false, onClick = onDone)
}
data class Content(
val isDoneEnabled: Boolean,
override val doneButtonConfig: PrimaryButtonConfig,
val feeItems: ImmutableList<FeeItem>,
val onFeeSelected: (FeeItem) -> Unit,
val selectedFeeItem: FeeItem,
val isFeeApproximate: Boolean,
val feeFiatRateDataHolder: FeeFiatRateDataHolder?,
val feeFiatRateUM: FeeFiatRateUM?,
val displayNonceInput: Boolean,
val nonce: BigInteger?,
val onNonceChange: (String) -> Unit,
) : FeeSelectorUM()
}
internal data class PrimaryButtonConfig(val enabled: Boolean, val onClick: () -> Unit)
@Immutable
data class FeeFiatRateDataHolder(
internal data class FeeFiatRateUM(
val rate: BigDecimal,
val appCurrency: AppCurrency,
)
@Immutable
internal sealed class FeeItem {
abstract val onSelect: () -> Unit
abstract val fee: Fee
data class Suggested(val title: TextReference, val amount: Amount, override val onSelect: () -> Unit) : FeeItem()
data class Slow(val amount: Amount, override val onSelect: () -> Unit) : FeeItem()
data class Market(val amount: Amount, override val onSelect: () -> Unit) : FeeItem()
data class Fast(val amount: Amount, override val onSelect: () -> Unit) : FeeItem()
data class Custom(val customValues: ImmutableList<CustomFeeFieldUM>, override val onSelect: () -> Unit) : FeeItem()
data class Suggested(val title: TextReference, override val fee: Fee) : FeeItem()
data class Slow(override val fee: Fee) : FeeItem()
data class Market(override val fee: Fee) : FeeItem()
data class Fast(override val fee: Fee) : FeeItem()
data class Custom(override val fee: Fee, val customValues: ImmutableList<CustomFeeFieldUM>) : FeeItem()
}

View file

@ -1,31 +1,101 @@
package com.tangem.features.send.v2.feeselector.model
import androidx.compose.runtime.Stable
import arrow.core.getOrElse
import com.tangem.blockchain.common.AmountType
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.model.ParamsContainer
import com.tangem.core.decompose.navigation.Router
import com.tangem.features.send.v2.api.FeeSelectorComponent
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.transaction.usecase.IsFeeApproximateUseCase
import com.tangem.features.send.v2.api.params.FeeSelectorParams
import com.tangem.features.send.v2.feeselector.entity.FeeItem
import com.tangem.features.send.v2.feeselector.entity.FeeSelectorUM
import com.tangem.features.send.v2.feeselector.model.transformers.FeeItemSelectedTransformer
import com.tangem.features.send.v2.feeselector.model.transformers.FeeSelectorErrorTransformer
import com.tangem.features.send.v2.feeselector.model.transformers.FeeSelectorLoadedTransformer
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import com.tangem.utils.transformer.update
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
import javax.inject.Inject
@Stable
@ModelScoped
internal class FeeSelectorModel @Inject constructor(
paramsContainer: ParamsContainer,
private val isFeeApproximateUseCase: IsFeeApproximateUseCase,
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
private val router: Router,
override val dispatchers: CoroutineDispatcherProvider,
) : Model() {
@Suppress("UnusedPrivateMember")
private val params = paramsContainer.require<FeeSelectorComponent.Params>()
private val params = paramsContainer.require<FeeSelectorParams.FeeSelectorBlockParams>()
private var appCurrency: AppCurrency = AppCurrency.Default
val uiState: StateFlow<FeeSelectorUM>
field = MutableStateFlow<FeeSelectorUM>(FeeSelectorUM.Loading)
field = MutableStateFlow<FeeSelectorUM>(FeeSelectorUM.Loading(onDone = ::onDone))
init {
initAppCurrency()
loadFee()
}
fun dismiss() {
router.pop()
}
private fun initAppCurrency() {
modelScope.launch {
appCurrency = getSelectedAppCurrencyUseCase.invokeSync().getOrElse { AppCurrency.Default }
}
}
private fun loadFee() {
modelScope.launch {
params.onLoadFee()
.fold(
ifLeft = { uiState.update(FeeSelectorErrorTransformer(it)) },
ifRight = {
uiState.update(
FeeSelectorLoadedTransformer(
cryptoCurrencyStatus = params.cryptoCurrencyStatus,
appCurrency = appCurrency,
fees = it,
suggestedFeeState = params.suggestedFeeState,
isFeeApproximate = isFeeApproximate(it.normal.amount.type),
onFeeSelected = ::onFeeItemSelected,
onCustomFeeValueChange = ::onCustomFeeValueChange,
onNextClick = ::onNextClick,
),
)
},
)
}
}
private fun isFeeApproximate(amountType: AmountType): Boolean {
val networkId = params.network.id
return isFeeApproximateUseCase(networkId = networkId, amountType = amountType)
}
private fun onFeeItemSelected(feeItem: FeeItem) {
uiState.update(FeeItemSelectedTransformer(feeItem))
}
@Suppress("UnusedPrivateMember")
private fun onCustomFeeValueChange(index: Int, value: String) {
// TODO: [REDACTED_JIRA]
}
private fun onNextClick() {
// TODO: [REDACTED_JIRA]
}
private fun onDone() {
// TODO: [REDACTED_JIRA]
}
}

View file

@ -0,0 +1,64 @@
package com.tangem.features.send.v2.feeselector.model.transformers
import com.tangem.blockchain.common.transaction.Fee
import com.tangem.blockchain.common.transaction.TransactionFee
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.features.send.v2.api.params.FeeSelectorParams
import com.tangem.features.send.v2.feeselector.entity.FeeItem
import com.tangem.utils.converter.Converter
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toImmutableList
internal class FeeItemConverter(
private val suggestedFeeState: FeeSelectorParams.SuggestedFeeState,
private val normalFee: Fee,
private val onCustomFeeValueChange: (Int, String) -> Unit,
private val onNextClick: () -> Unit,
private val appCurrency: AppCurrency,
cryptoCurrencyStatus: CryptoCurrencyStatus,
) : Converter<TransactionFee, ImmutableList<FeeItem>> {
private val customFeeFieldConverter = FeeSelectorCustomFieldConverter(
onCustomFeeValueChange = onCustomFeeValueChange,
onNextClick = onNextClick,
appCurrency = appCurrency,
feeCryptoCurrencyStatus = cryptoCurrencyStatus,
normalFee = normalFee,
)
override fun convert(value: TransactionFee): ImmutableList<FeeItem> {
val fees = mutableListOf<FeeItem>()
when (suggestedFeeState) {
FeeSelectorParams.SuggestedFeeState.None -> Unit
is FeeSelectorParams.SuggestedFeeState.Suggestion -> fees.add(
FeeItem.Suggested(
title = suggestedFeeState.title,
fee = suggestedFeeState.fee,
),
)
}
when (value) {
is TransactionFee.Choosable -> {
fees.add(FeeItem.Slow(fee = value.minimum))
fees.add(FeeItem.Market(fee = value.normal))
fees.add(FeeItem.Fast(fee = value.priority))
}
is TransactionFee.Single -> {
fees.add(FeeItem.Market(fee = value.normal))
}
}
val customFeeFields = customFeeFieldConverter.convert(normalFee)
if (customFeeFields.isNotEmpty()) {
fees.add(
FeeItem.Custom(
fee = customFeeFieldConverter.convertBack(customFeeFields),
customValues = customFeeFields,
),
)
}
return fees.toImmutableList()
}
}

View file

@ -0,0 +1,13 @@
package com.tangem.features.send.v2.feeselector.model.transformers
import com.tangem.features.send.v2.feeselector.entity.FeeItem
import com.tangem.features.send.v2.feeselector.entity.FeeSelectorUM
import com.tangem.utils.transformer.Transformer
internal class FeeItemSelectedTransformer(private val selectedFeeItem: FeeItem) : Transformer<FeeSelectorUM> {
override fun transform(prevState: FeeSelectorUM): FeeSelectorUM {
prevState as? FeeSelectorUM.Content ?: return prevState
return prevState.copy(selectedFeeItem = selectedFeeItem)
}
}

View file

@ -0,0 +1,114 @@
package com.tangem.features.send.v2.feeselector.model.transformers
import com.tangem.blockchain.common.transaction.Fee
import com.tangem.blockchain.common.transaction.TransactionFee
import com.tangem.core.ui.utils.parseToBigDecimal
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.features.send.v2.subcomponents.fee.model.converters.custom.bitcoin.BitcoinCustomFeeConverter
import com.tangem.features.send.v2.subcomponents.fee.model.converters.custom.ethereum.EthereumCustomFeeConverter
import com.tangem.features.send.v2.subcomponents.fee.model.converters.custom.kaspa.KaspaCustomFeeConverter
import com.tangem.features.send.v2.subcomponents.fee.ui.state.CustomFeeFieldUM
import com.tangem.features.send.v2.subcomponents.fee.ui.state.FeeSelectorUM
import com.tangem.utils.converter.TwoWayConverter
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
internal class FeeSelectorCustomFieldConverter(
private val onCustomFeeValueChange: (Int, String) -> Unit,
private val onNextClick: () -> Unit,
private val appCurrency: AppCurrency,
private val feeCryptoCurrencyStatus: CryptoCurrencyStatus,
private val normalFee: Fee,
) : TwoWayConverter<Fee, ImmutableList<CustomFeeFieldUM>> {
private val ethereumCustomFeeConverter by lazy(LazyThreadSafetyMode.NONE) {
EthereumCustomFeeConverter(
onCustomFeeValueChange = onCustomFeeValueChange,
onNextClick = onNextClick,
appCurrency = appCurrency,
feeCryptoCurrencyStatus = feeCryptoCurrencyStatus,
)
}
private val bitcoinCustomFeeConverter by lazy(LazyThreadSafetyMode.NONE) {
BitcoinCustomFeeConverter(
onCustomFeeValueChange = onCustomFeeValueChange,
onNextClick = onNextClick,
appCurrency = appCurrency,
feeCryptoCurrencyStatus = feeCryptoCurrencyStatus,
)
}
private val kaspaCustomFeeConverter by lazy(LazyThreadSafetyMode.NONE) {
KaspaCustomFeeConverter(
onCustomFeeValueChange = onCustomFeeValueChange,
appCurrency = appCurrency,
feeCryptoCurrencyStatus = feeCryptoCurrencyStatus,
)
}
override fun convert(value: Fee): ImmutableList<CustomFeeFieldUM> {
return when (value) {
is Fee.Ethereum -> ethereumCustomFeeConverter.convert(value)
is Fee.Bitcoin -> bitcoinCustomFeeConverter.convert(value)
is Fee.Kaspa -> kaspaCustomFeeConverter.convert(value)
else -> persistentListOf()
}
}
override fun convertBack(value: ImmutableList<CustomFeeFieldUM>): Fee {
return if (value.isEmpty()) {
normalFee
} else {
when (normalFee) {
is Fee.Ethereum -> ethereumCustomFeeConverter.convertBack(normalFee = normalFee, value = value)
is Fee.Bitcoin -> bitcoinCustomFeeConverter.convertBack(normalFee = normalFee, value = value)
is Fee.Kaspa -> kaspaCustomFeeConverter.convertBack(normalFee = normalFee, value = value)
else -> {
val customFee = value.firstOrNull()
Fee.Common(
normalFee.amount.copy(
value = customFee?.value?.parseToBigDecimal(customFee.decimals),
),
)
}
}
}
}
fun onValueChange(feeSelectorState: FeeSelectorUM.Content, index: Int, value: String) =
when (val fee = feeSelectorState.fees.normal) {
is Fee.Ethereum -> ethereumCustomFeeConverter.onValueChange(
feeValue = fee,
customValues = feeSelectorState.customValues,
index = index,
value = value,
)
is Fee.Bitcoin -> bitcoinCustomFeeConverter.onValueChange(
customValues = feeSelectorState.customValues,
index = index,
value = value,
txSize = fee.txSize,
)
is Fee.Kaspa -> kaspaCustomFeeConverter.onValueChange(
customValues = feeSelectorState.customValues,
index = index,
value = value,
)
else -> feeSelectorState.customValues
}
fun tryAutoFixValue(feeSelectorState: FeeSelectorUM.Content) = when (feeSelectorState.fees) {
is TransactionFee.Choosable -> feeSelectorState.fees.minimum
is TransactionFee.Single -> feeSelectorState.fees.normal
}.let {
when (it) {
is Fee.Kaspa -> kaspaCustomFeeConverter.tryAutoFixValue(
minimumFee = it,
customValues = feeSelectorState.customValues,
)
else -> feeSelectorState.customValues
}
}
}

View file

@ -0,0 +1,12 @@
package com.tangem.features.send.v2.feeselector.model.transformers
import com.tangem.domain.transaction.error.GetFeeError
import com.tangem.features.send.v2.feeselector.entity.FeeSelectorUM
import com.tangem.utils.transformer.Transformer
internal class FeeSelectorErrorTransformer(private val error: GetFeeError) : Transformer<FeeSelectorUM> {
override fun transform(prevState: FeeSelectorUM): FeeSelectorUM {
return FeeSelectorUM.Error(error = error, onDone = prevState.doneButtonConfig.onClick)
}
}

View file

@ -0,0 +1,54 @@
package com.tangem.features.send.v2.feeselector.model.transformers
import com.tangem.blockchain.common.transaction.TransactionFee
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.features.send.v2.api.params.FeeSelectorParams
import com.tangem.features.send.v2.feeselector.entity.FeeFiatRateUM
import com.tangem.features.send.v2.feeselector.entity.FeeItem
import com.tangem.features.send.v2.feeselector.entity.FeeSelectorUM
import com.tangem.utils.transformer.Transformer
import kotlinx.collections.immutable.ImmutableList
@Suppress("LongParameterList")
internal class FeeSelectorLoadedTransformer(
private val cryptoCurrencyStatus: CryptoCurrencyStatus,
private val appCurrency: AppCurrency,
private val fees: TransactionFee,
private val suggestedFeeState: FeeSelectorParams.SuggestedFeeState,
private val isFeeApproximate: Boolean,
private val onFeeSelected: (FeeItem) -> Unit,
private val onCustomFeeValueChange: (Int, String) -> Unit,
private val onNextClick: () -> Unit,
) : Transformer<FeeSelectorUM> {
private val feeItemsConverter = FeeItemConverter(
suggestedFeeState = suggestedFeeState,
normalFee = fees.normal,
onCustomFeeValueChange = onCustomFeeValueChange,
onNextClick = onNextClick,
appCurrency = appCurrency,
cryptoCurrencyStatus = cryptoCurrencyStatus,
)
override fun transform(prevState: FeeSelectorUM): FeeSelectorUM {
val feeItems: ImmutableList<FeeItem> = feeItemsConverter.convert(fees)
val selectedFee = feeItems.find { it is FeeItem.Suggested } ?: feeItems.first { it is FeeItem.Market }
return FeeSelectorUM.Content(
doneButtonConfig = prevState.doneButtonConfig.copy(enabled = true),
feeItems = feeItems,
selectedFeeItem = selectedFee,
isFeeApproximate = isFeeApproximate,
onFeeSelected = onFeeSelected,
feeFiatRateUM = cryptoCurrencyStatus.value.fiatRate?.let { rate ->
FeeFiatRateUM(
rate = rate,
appCurrency = appCurrency,
)
},
displayNonceInput = false,
nonce = null,
onNonceChange = {},
)
}
}

View file

@ -31,6 +31,7 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.util.fastForEachIndexed
import com.tangem.blockchain.common.Amount
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchain.common.transaction.Fee
import com.tangem.common.ui.amountScreen.utils.getFiatReference
import com.tangem.core.ui.components.PrimaryButton
import com.tangem.core.ui.components.atoms.text.EllipsisText
@ -47,9 +48,10 @@ import com.tangem.core.ui.format.bigdecimal.format
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.features.send.v2.feeselector.entity.FeeFiatRateDataHolder
import com.tangem.features.send.v2.feeselector.entity.FeeFiatRateUM
import com.tangem.features.send.v2.feeselector.entity.FeeItem
import com.tangem.features.send.v2.feeselector.entity.FeeSelectorUM
import com.tangem.features.send.v2.feeselector.entity.PrimaryButtonConfig
import com.tangem.features.send.v2.impl.R
import com.tangem.features.send.v2.subcomponents.fee.ui.state.CustomFeeFieldUM
import com.tangem.utils.StringsSigns
@ -88,8 +90,8 @@ internal fun FeeSelectorModalBottomSheet(state: FeeSelectorUM, onDismiss: () ->
.fillMaxWidth()
.padding(16.dp),
text = stringResourceSafe(R.string.common_done),
onClick = onDismiss,
enabled = state.isDoneEnabled,
onClick = state.doneButtonConfig.onClick,
enabled = state.doneButtonConfig.enabled,
)
},
)
@ -114,7 +116,7 @@ private fun FeeSelectorItems(state: FeeSelectorUM.Content, modifier: Modifier =
},
label = "Fee selector icon background change",
)
val onSelect by rememberUpdatedState(item.onSelect)
val onSelect by rememberUpdatedState(state.onFeeSelected)
val itemModifier = Modifier
.fillMaxWidth()
.background(TangemTheme.colors.background.primary)
@ -133,7 +135,7 @@ private fun FeeSelectorItems(state: FeeSelectorUM.Content, modifier: Modifier =
Modifier
},
)
.clickableSingle(onClick = onSelect)
.clickableSingle(onClick = { onSelect(item) })
when (item) {
is FeeItem.Suggested -> RegularFeeItemContent(
modifier = itemModifier,
@ -142,23 +144,23 @@ private fun FeeSelectorItems(state: FeeSelectorUM.Content, modifier: Modifier =
iconBackgroundColor = iconBackgroundColor,
iconTint = iconTint,
preDot = stringReference(
item.amount.value.format {
item.fee.amount.value.format {
crypto(
symbol = item.amount.currencySymbol,
decimals = item.amount.decimals,
symbol = item.fee.amount.currencySymbol,
decimals = item.fee.amount.decimals,
).fee(canBeLower = state.isFeeApproximate)
},
),
postDot = if (state.feeFiatRateDataHolder != null) {
postDot = if (state.feeFiatRateUM != null) {
getFiatReference(
value = item.amount.value,
rate = state.feeFiatRateDataHolder.rate,
appCurrency = state.feeFiatRateDataHolder.appCurrency,
value = item.fee.amount.value,
rate = state.feeFiatRateUM.rate,
appCurrency = state.feeFiatRateUM.appCurrency,
)
} else {
null
},
ellipsizeOffset = item.amount.currencySymbol.length,
ellipsizeOffset = item.fee.amount.currencySymbol.length,
showDivider = !isSelected && !lastItem,
)
is FeeItem.Slow -> RegularFeeItemContent(
@ -168,23 +170,23 @@ private fun FeeSelectorItems(state: FeeSelectorUM.Content, modifier: Modifier =
iconBackgroundColor = iconBackgroundColor,
iconTint = iconTint,
preDot = stringReference(
item.amount.value.format {
item.fee.amount.value.format {
crypto(
symbol = item.amount.currencySymbol,
decimals = item.amount.decimals,
symbol = item.fee.amount.currencySymbol,
decimals = item.fee.amount.decimals,
).fee(canBeLower = state.isFeeApproximate)
},
),
postDot = if (state.feeFiatRateDataHolder != null) {
postDot = if (state.feeFiatRateUM != null) {
getFiatReference(
value = item.amount.value,
rate = state.feeFiatRateDataHolder.rate,
appCurrency = state.feeFiatRateDataHolder.appCurrency,
value = item.fee.amount.value,
rate = state.feeFiatRateUM.rate,
appCurrency = state.feeFiatRateUM.appCurrency,
)
} else {
null
},
ellipsizeOffset = item.amount.currencySymbol.length,
ellipsizeOffset = item.fee.amount.currencySymbol.length,
showDivider = !isSelected && !lastItem,
)
is FeeItem.Market -> RegularFeeItemContent(
@ -194,23 +196,23 @@ private fun FeeSelectorItems(state: FeeSelectorUM.Content, modifier: Modifier =
iconBackgroundColor = iconBackgroundColor,
iconTint = iconTint,
preDot = stringReference(
item.amount.value.format {
item.fee.amount.value.format {
crypto(
symbol = item.amount.currencySymbol,
decimals = item.amount.decimals,
symbol = item.fee.amount.currencySymbol,
decimals = item.fee.amount.decimals,
).fee(canBeLower = state.isFeeApproximate)
},
),
postDot = if (state.feeFiatRateDataHolder != null) {
postDot = if (state.feeFiatRateUM != null) {
getFiatReference(
value = item.amount.value,
rate = state.feeFiatRateDataHolder.rate,
appCurrency = state.feeFiatRateDataHolder.appCurrency,
value = item.fee.amount.value,
rate = state.feeFiatRateUM.rate,
appCurrency = state.feeFiatRateUM.appCurrency,
)
} else {
null
},
ellipsizeOffset = item.amount.currencySymbol.length,
ellipsizeOffset = item.fee.amount.currencySymbol.length,
showDivider = !isSelected && !lastItem,
)
is FeeItem.Fast -> RegularFeeItemContent(
@ -220,23 +222,23 @@ private fun FeeSelectorItems(state: FeeSelectorUM.Content, modifier: Modifier =
iconBackgroundColor = iconBackgroundColor,
iconTint = iconTint,
preDot = stringReference(
item.amount.value.format {
item.fee.amount.value.format {
crypto(
symbol = item.amount.currencySymbol,
decimals = item.amount.decimals,
symbol = item.fee.amount.currencySymbol,
decimals = item.fee.amount.decimals,
).fee(canBeLower = state.isFeeApproximate)
},
),
postDot = if (state.feeFiatRateDataHolder != null) {
postDot = if (state.feeFiatRateUM != null) {
getFiatReference(
value = item.amount.value,
rate = state.feeFiatRateDataHolder.rate,
appCurrency = state.feeFiatRateDataHolder.appCurrency,
value = item.fee.amount.value,
rate = state.feeFiatRateUM.rate,
appCurrency = state.feeFiatRateUM.appCurrency,
)
} else {
null
},
ellipsizeOffset = item.amount.currencySymbol.length,
ellipsizeOffset = item.fee.amount.currencySymbol.length,
showDivider = !isSelected && !lastItem,
)
is FeeItem.Custom -> CustomFeeBlock(
@ -471,34 +473,24 @@ private fun FeeSelectorBS_Preview(
private class FeeSelectorUMContentProvider : CollectionPreviewParameterProvider<FeeSelectorUM.Content>(
collection = listOf(
FeeSelectorUM.Content(
isDoneEnabled = false,
doneButtonConfig = PrimaryButtonConfig(enabled = true, onClick = {}),
feeItems = persistentListOf(
FeeItem.Suggested(
title = stringReference("Suggested by Tangem"),
amount = Amount(value = BigDecimal("0.1"), blockchain = Blockchain.Ethereum),
onSelect = onSelectStub,
fee = Fee.Common(Amount(value = BigDecimal("0.1"), blockchain = Blockchain.Ethereum)),
),
FeeItem.Slow(
amount = Amount(value = BigDecimal("0.01"), blockchain = Blockchain.Ethereum),
onSelect = onSelectStub,
),
FeeItem.Market(
amount = Amount(value = BigDecimal("0.02"), blockchain = Blockchain.Ethereum),
onSelect = onSelectStub,
),
FeeItem.Fast(
amount = Amount(value = BigDecimal("0.3"), blockchain = Blockchain.Ethereum),
onSelect = onSelectStub,
),
FeeItem.Custom(customValues = customFeeFields, onSelect = onSelectStub),
FeeItem.Slow(fee = Fee.Common(Amount(value = BigDecimal("0.01"), blockchain = Blockchain.Ethereum))),
FeeItem.Market(fee = Fee.Common(Amount(value = BigDecimal("0.02"), blockchain = Blockchain.Ethereum))),
FeeItem.Fast(fee = Fee.Common(Amount(value = BigDecimal("0.03"), blockchain = Blockchain.Ethereum))),
customFeeItem,
),
onFeeSelected = {},
// selectedFeeItem = FeeItem.Market(
// amount = Amount(value = BigDecimal("0.02"), blockchain = Blockchain.Ethereum),
// onSelect = onSelectStub
// ),
selectedFeeItem = FeeItem.Custom(customValues = customFeeFields, onSelect = onSelectStub),
selectedFeeItem = customFeeItem,
isFeeApproximate = true,
feeFiatRateDataHolder = FeeFiatRateDataHolder(
feeFiatRateUM = FeeFiatRateUM(
rate = BigDecimal.TEN,
appCurrency = AppCurrency.Default,
),
@ -509,43 +501,44 @@ private class FeeSelectorUMContentProvider : CollectionPreviewParameterProvider<
),
)
private val onSelectStub: () -> Unit = {}
private val customFeeFields = persistentListOf(
CustomFeeFieldUM(
value = "0.119806",
onValueChange = {},
keyboardOptions = KeyboardOptions(),
keyboardActions = KeyboardActions(),
symbol = "ETH",
decimals = 8,
title = resourceReference(R.string.send_max_fee),
footer = resourceReference(R.string.send_custom_amount_fee_footer),
label = stringReference("~ 0,03 \$"),
isReadonly = false,
),
CustomFeeFieldUM(
value = "40000",
onValueChange = {},
keyboardOptions = KeyboardOptions(),
keyboardActions = KeyboardActions(),
symbol = "GWEI",
decimals = 8,
title = resourceReference(R.string.send_gas_price),
footer = resourceReference(R.string.send_gas_price_footer),
label = null,
isReadonly = false,
),
CustomFeeFieldUM(
value = "31400",
onValueChange = {},
keyboardOptions = KeyboardOptions(),
keyboardActions = KeyboardActions(),
symbol = null,
decimals = 8,
title = resourceReference(R.string.send_gas_limit),
footer = resourceReference(R.string.send_gas_limit_footer),
label = null,
isReadonly = false,
private val customFeeItem = FeeItem.Custom(
fee = Fee.Common(Amount(value = BigDecimal("0.05"), blockchain = Blockchain.Ethereum)),
customValues = persistentListOf(
CustomFeeFieldUM(
value = "0.119806",
onValueChange = {},
keyboardOptions = KeyboardOptions(),
keyboardActions = KeyboardActions(),
symbol = "ETH",
decimals = 8,
title = resourceReference(R.string.send_max_fee),
footer = resourceReference(R.string.send_custom_amount_fee_footer),
label = stringReference("~ 0,03 \$"),
isReadonly = false,
),
CustomFeeFieldUM(
value = "40000",
onValueChange = {},
keyboardOptions = KeyboardOptions(),
keyboardActions = KeyboardActions(),
symbol = "GWEI",
decimals = 8,
title = resourceReference(R.string.send_gas_price),
footer = resourceReference(R.string.send_gas_price_footer),
label = null,
isReadonly = false,
),
CustomFeeFieldUM(
value = "31400",
onValueChange = {},
keyboardOptions = KeyboardOptions(),
keyboardActions = KeyboardActions(),
symbol = null,
decimals = 8,
title = resourceReference(R.string.send_gas_limit),
footer = resourceReference(R.string.send_gas_limit_footer),
label = null,
isReadonly = false,
),
),
)

View file

@ -24,7 +24,8 @@ internal class SendFeeCustomFieldConverter(
private val ethereumCustomFeeConverter by lazy(LazyThreadSafetyMode.NONE) {
EthereumCustomFeeConverter(
clickIntents = clickIntents,
onCustomFeeValueChange = clickIntents::onCustomFeeValueChange,
onNextClick = clickIntents::onNextClick,
appCurrency = appCurrency,
feeCryptoCurrencyStatus = feeCryptoCurrencyStatus,
)
@ -32,7 +33,8 @@ internal class SendFeeCustomFieldConverter(
private val bitcoinCustomFeeConverter by lazy(LazyThreadSafetyMode.NONE) {
BitcoinCustomFeeConverter(
clickIntents = clickIntents,
onCustomFeeValueChange = clickIntents::onCustomFeeValueChange,
onNextClick = clickIntents::onNextClick,
appCurrency = appCurrency,
feeCryptoCurrencyStatus = feeCryptoCurrencyStatus,
)
@ -40,7 +42,7 @@ internal class SendFeeCustomFieldConverter(
private val kaspaCustomFeeConverter by lazy(LazyThreadSafetyMode.NONE) {
KaspaCustomFeeConverter(
clickIntents = clickIntents,
onCustomFeeValueChange = clickIntents::onCustomFeeValueChange,
appCurrency = appCurrency,
feeCryptoCurrencyStatus = feeCryptoCurrencyStatus,
)

View file

@ -12,7 +12,6 @@ import com.tangem.core.ui.utils.parseToBigDecimal
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.features.send.v2.impl.R
import com.tangem.features.send.v2.subcomponents.fee.model.SendFeeClickIntents
import com.tangem.features.send.v2.subcomponents.fee.model.checkExceedBalance
import com.tangem.features.send.v2.subcomponents.fee.model.converters.custom.CustomFeeConverter
import com.tangem.features.send.v2.subcomponents.fee.ui.state.CustomFeeFieldUM
@ -24,7 +23,8 @@ import java.math.BigDecimal
import java.math.RoundingMode
internal class BitcoinCustomFeeConverter(
private val clickIntents: SendFeeClickIntents,
private val onCustomFeeValueChange: (Int, String) -> Unit,
private val onNextClick: () -> Unit,
private val appCurrency: AppCurrency,
private val feeCryptoCurrencyStatus: CryptoCurrencyStatus,
) : CustomFeeConverter<Fee.Bitcoin> {
@ -40,7 +40,7 @@ internal class BitcoinCustomFeeConverter(
value = feeValue?.parseBigDecimal(value.amount.decimals).orEmpty(),
decimals = value.amount.decimals,
symbol = value.amount.currencySymbol,
onValueChange = { clickIntents.onCustomFeeValueChange(FEE_AMOUNT_INDEX, it) },
onValueChange = { onCustomFeeValueChange(FEE_AMOUNT_INDEX, it) },
keyboardOptions = KeyboardOptions(
imeAction = ImeAction.Companion.Next,
keyboardType = KeyboardType.Companion.Number,
@ -65,7 +65,7 @@ internal class BitcoinCustomFeeConverter(
symbol = "",
title = resourceReference(R.string.send_satoshi_per_byte_title),
footer = resourceReference(R.string.send_satoshi_per_byte_text),
onValueChange = { clickIntents.onCustomFeeValueChange(FEE_SATOSHI_INDEX, it) },
onValueChange = { onCustomFeeValueChange(FEE_SATOSHI_INDEX, it) },
keyboardOptions = KeyboardOptions(
imeAction = if (checkExceedBalance(
feeBalance = currencyStatus.amount,
@ -78,9 +78,7 @@ internal class BitcoinCustomFeeConverter(
},
keyboardType = KeyboardType.Companion.Number,
),
keyboardActions = KeyboardActions(
onDone = { clickIntents.onNextClick() },
),
keyboardActions = KeyboardActions(onDone = { onNextClick() }),
),
)
} else {

View file

@ -11,14 +11,14 @@ import com.tangem.core.ui.utils.parseBigDecimal
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.features.send.v2.impl.R
import com.tangem.features.send.v2.subcomponents.fee.model.SendFeeClickIntents
import com.tangem.features.send.v2.subcomponents.fee.model.checkExceedBalance
import com.tangem.features.send.v2.subcomponents.fee.ui.state.CustomFeeFieldUM
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toImmutableList
internal class EthereumCustomFeeConverter(
private val clickIntents: SendFeeClickIntents,
private val onCustomFeeValueChange: (Int, String) -> Unit,
private val onNextClick: () -> Unit,
private val appCurrency: AppCurrency,
feeCryptoCurrencyStatus: CryptoCurrencyStatus,
) : BaseEthereumCustomFeeConverter<Fee.Ethereum> {
@ -26,13 +26,13 @@ internal class EthereumCustomFeeConverter(
private val currencyStatus = feeCryptoCurrencyStatus.value
private val legacyFeeConverter = EthereumLegacyCustomFeeConverter(
clickIntents = clickIntents,
onCustomFeeValueChange = onCustomFeeValueChange,
appCurrency = appCurrency,
feeCryptoCurrencyStatus = feeCryptoCurrencyStatus,
)
private val eipFeeConverter = EthereumEIPCustomFeeConverter(
clickIntents = clickIntents,
onCustomFeeValueChange = onCustomFeeValueChange,
appCurrency = appCurrency,
feeCryptoCurrencyStatus = feeCryptoCurrencyStatus,
)
@ -84,7 +84,7 @@ internal class EthereumCustomFeeConverter(
value = feeValue?.parseBigDecimal(value.amount.decimals).orEmpty(),
decimals = value.amount.decimals,
symbol = value.amount.currencySymbol,
onValueChange = { clickIntents.onCustomFeeValueChange(FEE_AMOUNT, it) },
onValueChange = { onCustomFeeValueChange(FEE_AMOUNT, it) },
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next, keyboardType = KeyboardType.Number),
title = resourceReference(R.string.send_max_fee),
footer = resourceReference(R.string.send_custom_amount_fee_footer),
@ -106,13 +106,13 @@ internal class EthereumCustomFeeConverter(
symbol = "",
title = resourceReference(R.string.send_gas_limit),
footer = resourceReference(R.string.send_gas_limit_footer),
onValueChange = { clickIntents.onCustomFeeValueChange(getGasLimitIndex(value), it) },
onValueChange = { onCustomFeeValueChange(getGasLimitIndex(value), it) },
keyboardOptions = KeyboardOptions(
imeAction = if (isExceedBalance) ImeAction.None else ImeAction.Done,
keyboardType = KeyboardType.Number,
),
keyboardActions = KeyboardActions(
onDone = { clickIntents.onNextClick() },
onDone = { onNextClick() },
),
)
}

View file

@ -12,7 +12,6 @@ import com.tangem.core.ui.utils.parseToBigDecimal
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.features.send.v2.impl.R
import com.tangem.features.send.v2.subcomponents.fee.model.SendFeeClickIntents
import com.tangem.features.send.v2.subcomponents.fee.model.checkExceedBalance
import com.tangem.features.send.v2.subcomponents.fee.model.converters.custom.ethereum.EthereumCustomFeeConverter.Companion.ETHEREUM_GAS_UNIT
import com.tangem.features.send.v2.subcomponents.fee.model.converters.custom.ethereum.EthereumCustomFeeConverter.Companion.FEE_AMOUNT
@ -26,7 +25,7 @@ import kotlinx.collections.immutable.toImmutableList
import java.math.RoundingMode
internal class EthereumEIPCustomFeeConverter(
private val clickIntents: SendFeeClickIntents,
private val onCustomFeeValueChange: (Int, String) -> Unit,
private val appCurrency: AppCurrency,
private val feeCryptoCurrencyStatus: CryptoCurrencyStatus,
) : BaseEthereumCustomFeeConverter<Fee.Ethereum.EIP1559> {
@ -41,7 +40,7 @@ internal class EthereumEIPCustomFeeConverter(
symbol = ETHEREUM_GAS_UNIT,
title = resourceReference(R.string.send_custom_evm_max_fee),
footer = resourceReference(R.string.send_custom_evm_max_fee_footer),
onValueChange = { clickIntents.onCustomFeeValueChange(MAX_FEE, it) },
onValueChange = { onCustomFeeValueChange(MAX_FEE, it) },
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next, keyboardType = KeyboardType.Number),
keyboardActions = KeyboardActions(),
),
@ -51,7 +50,7 @@ internal class EthereumEIPCustomFeeConverter(
symbol = ETHEREUM_GAS_UNIT,
title = resourceReference(R.string.send_custom_evm_priority_fee),
footer = resourceReference(R.string.send_custom_evm_priority_fee_footer),
onValueChange = { clickIntents.onCustomFeeValueChange(PRIORITY_FEE, it) },
onValueChange = { onCustomFeeValueChange(PRIORITY_FEE, it) },
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next, keyboardType = KeyboardType.Number),
keyboardActions = KeyboardActions(),
),

View file

@ -12,7 +12,6 @@ import com.tangem.core.ui.utils.parseToBigDecimal
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.features.send.v2.impl.R
import com.tangem.features.send.v2.subcomponents.fee.model.SendFeeClickIntents
import com.tangem.features.send.v2.subcomponents.fee.model.checkExceedBalance
import com.tangem.features.send.v2.subcomponents.fee.model.converters.custom.ethereum.EthereumCustomFeeConverter.Companion.ETHEREUM_GAS_UNIT
import com.tangem.features.send.v2.subcomponents.fee.model.converters.custom.ethereum.EthereumCustomFeeConverter.Companion.FEE_AMOUNT
@ -26,7 +25,7 @@ import kotlinx.collections.immutable.toImmutableList
import java.math.RoundingMode
internal class EthereumLegacyCustomFeeConverter(
private val clickIntents: SendFeeClickIntents,
private val onCustomFeeValueChange: (Int, String) -> Unit,
private val appCurrency: AppCurrency,
feeCryptoCurrencyStatus: CryptoCurrencyStatus,
) : BaseEthereumCustomFeeConverter<Fee.Ethereum.Legacy> {
@ -41,7 +40,7 @@ internal class EthereumLegacyCustomFeeConverter(
symbol = ETHEREUM_GAS_UNIT,
title = resourceReference(R.string.send_gas_price),
footer = resourceReference(R.string.send_gas_price_footer),
onValueChange = { clickIntents.onCustomFeeValueChange(GAS_PRICE, it) },
onValueChange = { onCustomFeeValueChange(GAS_PRICE, it) },
keyboardOptions = KeyboardOptions(
imeAction = ImeAction.Next,
keyboardType = KeyboardType.Number,

View file

@ -12,7 +12,6 @@ import com.tangem.core.ui.utils.parseToBigDecimal
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.features.send.v2.impl.R
import com.tangem.features.send.v2.subcomponents.fee.model.SendFeeClickIntents
import com.tangem.features.send.v2.subcomponents.fee.model.converters.custom.CustomFeeConverter
import com.tangem.features.send.v2.subcomponents.fee.ui.state.CustomFeeFieldUM
import kotlinx.collections.immutable.ImmutableList
@ -21,7 +20,7 @@ import kotlinx.collections.immutable.toImmutableList
import java.math.RoundingMode
internal class KaspaCustomFeeConverter(
private val clickIntents: SendFeeClickIntents,
private val onCustomFeeValueChange: (Int, String) -> Unit,
private val appCurrency: AppCurrency,
feeCryptoCurrencyStatus: CryptoCurrencyStatus,
) : CustomFeeConverter<Fee.Kaspa> {
@ -35,7 +34,7 @@ internal class KaspaCustomFeeConverter(
value = feeValue?.parseBigDecimal(value.amount.decimals).orEmpty(),
decimals = value.amount.decimals,
symbol = value.amount.currencySymbol,
onValueChange = { clickIntents.onCustomFeeValueChange(FEE_AMOUNT_INDEX, it) },
onValueChange = { onCustomFeeValueChange(FEE_AMOUNT_INDEX, it) },
keyboardOptions = KeyboardOptions(
imeAction = ImeAction.Companion.Next,
keyboardType = KeyboardType.Companion.Number,