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

@ -13,12 +13,18 @@ fun getFiatReference(value: BigDecimal?, rate: BigDecimal?, appCurrency: AppCurr
return stringReference(formattedFiat)
}
fun getFiatString(value: BigDecimal?, rate: BigDecimal?, appCurrency: AppCurrency): String {
fun getFiatString(
value: BigDecimal?,
rate: BigDecimal?,
appCurrency: AppCurrency,
approximate: Boolean = false,
): String {
if (value == null || rate == null) return EMPTY_BALANCE_SIGN
val feeValue = value.multiply(rate)
return BigDecimalFormatter.formatFiatAmount(
fiatAmount = feeValue,
fiatCurrencyCode = appCurrency.code,
fiatCurrencySymbol = appCurrency.symbol,
withApproximateSign = approximate,
)
}

View file

@ -102,7 +102,7 @@ internal class WcEthSendTransactionUseCase @AssistedInject constructor(
emit(newState)
}
override suspend fun dAppFee(): Fee.Ethereum.Legacy? {
override fun dAppFee(): Fee.Ethereum.Legacy? {
return dAppFee
}

View file

@ -123,7 +123,7 @@ internal class WcEthSignTransactionUseCase @AssistedInject constructor(
emitAll(delegate.invoke(transactionData))
}
override suspend fun dAppFee(): Fee.Ethereum.Legacy? {
override fun dAppFee(): Fee.Ethereum.Legacy? {
return dAppFee
}

View file

@ -34,7 +34,7 @@ interface WcListTransactionUseCase :
* [updateFee] triggered a new [TransactionData] emit
*/
interface WcMutableFee {
suspend fun dAppFee(): Fee?
fun dAppFee(): Fee?
fun updateFee(fee: Fee)
}

View file

@ -16,10 +16,17 @@ dependencies {
/** Domain models */
api(projects.domain.models)
implementation(projects.domain.appCurrency.models)
implementation(projects.domain.wallets.models)
implementation(projects.domain.tokens.models)
implementation(projects.domain.nft.models)
implementation(projects.domain.tokens.models)
implementation(projects.domain.transaction.models)
implementation(projects.domain.wallets.models)
/* Compose */
/** Compose */
implementation(deps.compose.runtime)
/** Tangem */
implementation(tangemDeps.blockchain)
/** Other */
implementation(deps.arrow.core)
}

View file

@ -2,8 +2,9 @@ package com.tangem.features.send.v2.api
import com.tangem.core.decompose.factory.ComponentFactory
import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.features.send.v2.api.params.FeeSelectorParams
interface FeeSelectorBlockComponent : ComposableContentComponent {
interface Factory : ComponentFactory<Unit, FeeSelectorBlockComponent>
interface Factory : ComponentFactory<FeeSelectorParams.FeeSelectorBlockParams, FeeSelectorBlockComponent>
}

View file

@ -0,0 +1,27 @@
package com.tangem.features.send.v2.api.params
import arrow.core.Either
import com.tangem.blockchain.common.transaction.Fee
import com.tangem.blockchain.common.transaction.TransactionFee
import com.tangem.core.ui.extensions.TextReference
import com.tangem.domain.models.network.Network
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.transaction.error.GetFeeError
sealed class FeeSelectorParams {
abstract val onLoadFee: suspend () -> Either<GetFeeError, TransactionFee>
abstract val network: Network
abstract val cryptoCurrencyStatus: CryptoCurrencyStatus
data class FeeSelectorBlockParams(
override val onLoadFee: suspend () -> Either<GetFeeError, TransactionFee>,
override val network: Network,
override val cryptoCurrencyStatus: CryptoCurrencyStatus,
val suggestedFeeState: SuggestedFeeState,
) : FeeSelectorParams()
sealed class SuggestedFeeState {
data object None : SuggestedFeeState()
data class Suggestion(val title: TextReference, val fee: Fee) : SuggestedFeeState()
}
}

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,

View file

@ -30,6 +30,7 @@ dependencies {
implementation(projects.domain.models)
implementation(projects.domain.qrScanning.models)
implementation(projects.domain.tokens.models)
implementation(projects.domain.transaction.models)
implementation(projects.domain.wallets.models)
implementation(projects.domain.walletConnect)
implementation(projects.domain.walletConnect.models)
@ -37,8 +38,10 @@ dependencies {
/** Domain */
implementation(projects.domain.appCurrency)
implementation(projects.domain.balanceHiding)
implementation(projects.domain.legacy)
implementation(projects.domain.qrScanning)
implementation(projects.domain.tokens)
implementation(projects.domain.transaction)
implementation(projects.domain.wallets)
/** DI */

View file

@ -64,12 +64,10 @@ internal class DefaultWcRoutingComponent @AssistedInject constructor(
is WcInnerRoute.SignMessage -> WcSignTransactionContainerComponent(
appComponentContext = childContext,
params = WcTransactionModelParams(config.rawRequest),
feeSelectorBlockComponentFactory = feeSelectorBlockComponentFactory,
)
is WcInnerRoute.AddNetwork -> WcAddNetworkContainerComponent(
appComponentContext = childContext,
params = WcTransactionModelParams(config.rawRequest),
feeSelectorBlockComponentFactory = feeSelectorBlockComponentFactory,
)
is WcInnerRoute.Send -> WcSendTransactionContainerComponent(
appComponentContext = childContext,

View file

@ -5,7 +5,6 @@ import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.decompose.context.childByContext
import com.tangem.core.decompose.model.getOrCreateModel
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
import com.tangem.features.send.v2.api.FeeSelectorBlockComponent
import com.tangem.features.walletconnect.transaction.components.common.WcCommonTransactionComponentDelegate
import com.tangem.features.walletconnect.transaction.components.common.WcTransactionModelParams
import com.tangem.features.walletconnect.transaction.components.common.getWcCommonScreen
@ -15,8 +14,7 @@ import com.tangem.features.walletconnect.transaction.routes.WcTransactionRoutes
internal class WcAddNetworkContainerComponent(
appComponentContext: AppComponentContext,
params: WcTransactionModelParams,
feeSelectorBlockComponentFactory: FeeSelectorBlockComponent.Factory,
) : WcCommonTransactionComponentDelegate(appComponentContext, feeSelectorBlockComponentFactory) {
) : WcCommonTransactionComponentDelegate(appComponentContext) {
private val model: WcAddNetworkModel = getOrCreateModel(params = params)

View file

@ -15,12 +15,10 @@ import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.decompose.navigation.inner.InnerRouter
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.features.send.v2.api.FeeSelectorBlockComponent
import com.tangem.features.walletconnect.transaction.routes.WcTransactionRoutes
internal abstract class WcCommonTransactionComponentDelegate(
private val appComponentContext: AppComponentContext,
private val feeSelectorBlockComponentFactory: FeeSelectorBlockComponent.Factory,
) : AppComponentContext by appComponentContext, ComposableContentComponent {
private var stackNavigation: StackNavigation<WcTransactionRoutes>? = null
@ -31,10 +29,6 @@ internal abstract class WcCommonTransactionComponentDelegate(
InnerRouter<WcTransactionRoutes>(stackNavigation = it, popCallback = { onChildBack() })
}
}
protected val feeSelectorBlockComponent = feeSelectorBlockComponentFactory.create(
context = appComponentContext,
params = Unit,
)
protected fun init(
navigation: StackNavigation<WcTransactionRoutes>,

View file

@ -6,15 +6,28 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
import com.tangem.features.send.v2.api.FeeSelectorBlockComponent
import com.tangem.features.send.v2.api.params.FeeSelectorParams
import com.tangem.features.walletconnect.transaction.model.WcSendTransactionModel
import com.tangem.features.walletconnect.transaction.ui.send.WcSendTransactionModalBottomSheet
internal class WcSendTransactionComponent(
private val appComponentContext: AppComponentContext,
private val model: WcSendTransactionModel,
private val feeSelectorBlockComponent: FeeSelectorBlockComponent,
private val feeSelectorBlockComponentFactory: FeeSelectorBlockComponent.Factory,
) : AppComponentContext by appComponentContext, ComposableBottomSheetComponent {
private val feeSelectorBlockComponent by lazy {
feeSelectorBlockComponentFactory.create(
context = appComponentContext,
params = FeeSelectorParams.FeeSelectorBlockParams(
onLoadFee = model::loadFee,
network = model.useCase.network,
cryptoCurrencyStatus = model.cryptoCurrencyStatus,
suggestedFeeState = model.suggestedFeeState,
),
)
}
override fun dismiss() {
model.dismiss()
}

View file

@ -15,8 +15,8 @@ import com.tangem.features.walletconnect.transaction.routes.WcTransactionRoutes
internal class WcSendTransactionContainerComponent(
appComponentContext: AppComponentContext,
params: WcTransactionModelParams,
feeSelectorBlockComponentFactory: FeeSelectorBlockComponent.Factory,
) : WcCommonTransactionComponentDelegate(appComponentContext, feeSelectorBlockComponentFactory) {
private val feeSelectorBlockComponentFactory: FeeSelectorBlockComponent.Factory,
) : WcCommonTransactionComponentDelegate(appComponentContext) {
private val model: WcSendTransactionModel = getOrCreateModel(params = params)
@ -45,7 +45,7 @@ internal class WcSendTransactionContainerComponent(
return WcSendTransactionComponent(
appComponentContext = appComponentContext,
model = model,
feeSelectorBlockComponent = feeSelectorBlockComponent,
feeSelectorBlockComponentFactory = feeSelectorBlockComponentFactory,
)
}
}

View file

@ -5,14 +5,12 @@ import androidx.compose.runtime.getValue
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
import com.tangem.features.send.v2.api.FeeSelectorBlockComponent
import com.tangem.features.walletconnect.transaction.model.WcSignTransactionModel
import com.tangem.features.walletconnect.transaction.ui.sign.WcSignTransactionModalBottomSheetContent
internal class WcSignTransactionComponent(
private val appComponentContext: AppComponentContext,
private val model: WcSignTransactionModel,
private val feeSelectorBlockComponent: FeeSelectorBlockComponent,
) : AppComponentContext by appComponentContext, ComposableBottomSheetComponent {
override fun dismiss() {
@ -26,7 +24,6 @@ internal class WcSignTransactionComponent(
if (content != null) {
WcSignTransactionModalBottomSheetContent(
state = content!!.transaction,
feeSelectorBlockComponent = feeSelectorBlockComponent,
onClickTransactionRequest = model::showTransactionRequest,
onBack = router::pop,
onDismiss = ::dismiss,

View file

@ -5,7 +5,6 @@ import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.decompose.context.childByContext
import com.tangem.core.decompose.model.getOrCreateModel
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
import com.tangem.features.send.v2.api.FeeSelectorBlockComponent
import com.tangem.features.walletconnect.transaction.components.common.WcCommonTransactionComponentDelegate
import com.tangem.features.walletconnect.transaction.components.common.WcTransactionModelParams
import com.tangem.features.walletconnect.transaction.components.common.getWcCommonScreen
@ -15,8 +14,7 @@ import com.tangem.features.walletconnect.transaction.routes.WcTransactionRoutes
internal class WcSignTransactionContainerComponent(
appComponentContext: AppComponentContext,
params: WcTransactionModelParams,
feeSelectorBlockComponentFactory: FeeSelectorBlockComponent.Factory,
) : WcCommonTransactionComponentDelegate(appComponentContext, feeSelectorBlockComponentFactory) {
) : WcCommonTransactionComponentDelegate(appComponentContext) {
private val model: WcSignTransactionModel = getOrCreateModel(params = params)
@ -45,7 +43,6 @@ internal class WcSignTransactionContainerComponent(
return WcSignTransactionComponent(
appComponentContext = appComponentContext,
model = model,
feeSelectorBlockComponent = feeSelectorBlockComponent,
)
}
}

View file

@ -3,15 +3,13 @@ package com.tangem.features.walletconnect.transaction.converter
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.domain.walletconnect.model.WcEthMethod
import com.tangem.domain.walletconnect.model.WcSolanaMethod
import com.tangem.domain.walletconnect.usecase.method.WcMutableFee
import com.tangem.domain.walletconnect.usecase.method.WcSignState
import com.tangem.domain.walletconnect.usecase.method.WcSignStep
import com.tangem.domain.walletconnect.usecase.method.WcTransactionUseCase
import com.tangem.features.walletconnect.impl.R
import com.tangem.features.walletconnect.transaction.entity.blockaid.WcSendReceiveTransactionCheckResultsUM
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionActionsUM
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionRequestBlockUM
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionRequestInfoItemUM
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionRequestInfoUM
import com.tangem.features.walletconnect.transaction.entity.common.*
import com.tangem.features.walletconnect.transaction.entity.send.WcSendTransactionItemUM
import com.tangem.features.walletconnect.transaction.entity.send.WcSendTransactionUM
import com.tangem.utils.converter.Converter
@ -39,6 +37,7 @@ internal class WcSendTransactionUMConverter @Inject constructor(
onShowVerifiedAlert = value.actions.onShowVerifiedAlert,
),
),
feeState = constructFeeState(useCase = value.useCase),
walletName = value.useCase.session.wallet.name,
networkInfo = networkInfoUMConverter.convert(value.useCase.network),
address = value.useCase.walletAddress.toShortAddressText(),
@ -81,6 +80,12 @@ internal class WcSendTransactionUMConverter @Inject constructor(
else -> null
}
private fun constructFeeState(useCase: WcTransactionUseCase): WcTransactionFeeState {
val mutableFee = useCase as? WcMutableFee ?: return WcTransactionFeeState.None
val dAppFee = mutableFee.dAppFee()
return if (dAppFee != null) WcTransactionFeeState.Success(dAppFee) else WcTransactionFeeState.Loading
}
data class Input(
val useCase: WcTransactionUseCase,
val signState: WcSignState<*>,

View file

@ -0,0 +1,9 @@
package com.tangem.features.walletconnect.transaction.entity.common
import com.tangem.blockchain.common.transaction.Fee
internal sealed class WcTransactionFeeState {
object Loading : WcTransactionFeeState()
data class Success(val fee: Fee) : WcTransactionFeeState()
data object None : WcTransactionFeeState()
}

View file

@ -6,6 +6,7 @@ import com.tangem.features.walletconnect.transaction.entity.blockaid.WcSendRecei
import com.tangem.features.walletconnect.transaction.entity.common.WcCommonTransactionUM
import com.tangem.features.walletconnect.transaction.entity.common.WcNetworkInfoUM
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionAppInfoContentUM
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionFeeState
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionRequestInfoUM
internal data class WcSendTransactionUM(
@ -15,13 +16,13 @@ internal data class WcSendTransactionUM(
) : WcCommonTransactionUM
internal data class WcSendTransactionItemUM(
val feeState: WcTransactionFeeState,
val onDismiss: () -> Unit,
val onSend: () -> Unit,
val appInfo: WcTransactionAppInfoContentUM,
val estimatedWalletChanges: WcSendReceiveTransactionCheckResultsUM?,
val walletName: String,
val networkInfo: WcNetworkInfoUM,
val networkFee: String? = null,
val address: String? = null,
val isLoading: Boolean = false,
) : TangemBottomSheetConfigContent

View file

@ -7,14 +7,25 @@ import com.arkivanov.decompose.router.stack.pop
import com.arkivanov.decompose.router.stack.pushNew
import com.domain.blockaid.models.transaction.ValidationResult
import com.tangem.blockchain.common.TransactionData
import com.tangem.blockchain.common.transaction.TransactionFee
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.core.ui.clipboard.ClipboardManager
import com.tangem.core.ui.extensions.stringReference
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.core.lce.Lce
import com.tangem.domain.models.network.Network
import com.tangem.domain.tokens.GetNetworkCoinStatusUseCase
import com.tangem.domain.tokens.error.CurrencyStatusError
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.transaction.error.GetFeeError
import com.tangem.domain.transaction.usecase.GetFeeUseCase
import com.tangem.domain.walletconnect.WcRequestUseCaseFactory
import com.tangem.domain.walletconnect.usecase.method.*
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.features.send.v2.api.params.FeeSelectorParams
import com.tangem.features.walletconnect.connections.routing.WcInnerRoute
import com.tangem.features.walletconnect.transaction.components.common.WcTransactionModelParams
import com.tangem.features.walletconnect.transaction.converter.WcCommonTransactionUMConverter
@ -29,6 +40,7 @@ import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import java.math.BigDecimal
import javax.inject.Inject
import kotlin.properties.Delegates
@Suppress("LongParameterList")
@Stable
@ -41,6 +53,8 @@ internal class WcSendTransactionModel @Inject constructor(
private val useCaseFactory: WcRequestUseCaseFactory,
private val converter: WcCommonTransactionUMConverter,
private val blockAidUiConverter: WcSendAndReceiveBlockAidUiConverter,
private val getFeeUseCase: GetFeeUseCase,
private val getNetworkCoinUseCase: GetNetworkCoinStatusUseCase,
) : Model(), WcCommonTransactionModel {
private val params = paramsContainer.require<WcTransactionModelParams>()
@ -50,6 +64,10 @@ internal class WcSendTransactionModel @Inject constructor(
val stackNavigation = StackNavigation<WcTransactionRoutes>()
internal var useCase: WcSignUseCase<*> by Delegates.notNull()
internal var cryptoCurrencyStatus: CryptoCurrencyStatus by Delegates.notNull()
internal var suggestedFeeState: FeeSelectorParams.SuggestedFeeState = FeeSelectorParams.SuggestedFeeState.None
private var signState: WcSignState<*> by Delegates.notNull()
private var wcApproval: WcApproval? = null
private var sign: () -> Unit = {}
@ -63,36 +81,65 @@ internal class WcSendTransactionModel @Inject constructor(
when (useCase) {
is WcListTransactionUseCase,
is WcTransactionUseCase,
-> combine(
useCase.invoke(),
useCase.securityStatus,
) { signState, securityCheck -> signState to securityCheck }
.distinctUntilChanged()
.collectLatest {
val (signState, securityCheck) = it
if (signingIsDone(signState, useCase)) return@collectLatest
val signModel: Any = signState.signModel
val isMutableFee = useCase is WcMutableFee
val dAppFee = if (isMutableFee) useCase.dAppFee() else null
val selectedFee = when (signModel) {
is TransactionData.Compiled -> signModel.fee
is TransactionData.Uncompiled -> signModel.fee
else -> null
-> {
this@WcSendTransactionModel.cryptoCurrencyStatus =
getCryptoCurrencyStatus(userWallet = useCase.wallet, network = useCase.network)
.onLeft { unknownMethodRunnable() }
.getOrNull() ?: return@launch
this@WcSendTransactionModel.useCase = useCase
(useCase as? WcMutableFee)
?.dAppFee()
?.let { dAppFee ->
suggestedFeeState = FeeSelectorParams.SuggestedFeeState.Suggestion(
title = stringReference(useCase.session.sdkModel.appMetaData.name),
fee = dAppFee,
)
}
val isDAppFeeSelected = dAppFee != null && dAppFee == selectedFee
combine(
useCase.invoke(),
useCase.securityStatus,
) { signState, securityCheck -> signState to securityCheck }
.distinctUntilChanged()
.collectLatest { (signState, securityCheck) ->
if (signingIsDone(signState, useCase)) return@collectLatest
val isSecurityCheckContent = securityCheck is Lce.Content
var isApprovalMethod = isSecurityCheckContent &&
securityCheck.content is BlockAidTransactionCheck.Result.Approval
wcApproval = useCase as? WcApproval
sign = { useCase.sign() }
buildUiState(securityCheck, useCase, signState)
}
this@WcSendTransactionModel.signState = signState
val isSecurityCheckContent = securityCheck is Lce.Content
var isApprovalMethod = isSecurityCheckContent &&
securityCheck.content is BlockAidTransactionCheck.Result.Approval
wcApproval = useCase as? WcApproval
sign = { useCase.sign() }
buildUiState(securityCheck, useCase, signState)
}
}
else -> unknownMethodRunnable()
}
}
}
suspend fun loadFee(): Either<GetFeeError, TransactionFee> {
val signModel = signState.signModel
val transactionData = signModel as? TransactionData.Uncompiled ?: error("TransactionData must be Uncompiled")
return getFeeUseCase.invoke(
userWallet = useCase.wallet,
network = useCase.network,
transactionData = transactionData,
)
}
private suspend fun getCryptoCurrencyStatus(
userWallet: UserWallet,
network: Network,
): Either<CurrencyStatusError, CryptoCurrencyStatus> {
return getNetworkCoinUseCase.invokeSync(
userWalletId = userWallet.walletId,
networkId = network.id,
derivationPath = network.derivationPath,
isSingleWalletWithTokens = userWallet is UserWallet.Cold &&
userWallet.scanResponse.cardTypesResolver.isSingleWalletWithToken(),
)
}
private suspend fun buildUiState(
securityCheck: Lce<Throwable, BlockAidTransactionCheck.Result>,
useCase: WcSignUseCase<*>,

View file

@ -14,11 +14,13 @@ import com.tangem.core.ui.components.divider.DividerWithPadding
import com.tangem.core.ui.res.TangemTheme
import com.tangem.features.send.v2.api.FeeSelectorBlockComponent
import com.tangem.features.walletconnect.transaction.entity.common.WcNetworkInfoUM
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionFeeState
@Composable
internal fun WcSendTransactionItems(
walletName: String,
networkInfo: WcNetworkInfoUM,
feeState: WcTransactionFeeState,
feeSelectorBlockComponent: FeeSelectorBlockComponent,
modifier: Modifier = Modifier,
address: String? = null,
@ -52,6 +54,8 @@ internal fun WcSendTransactionItems(
)
}
DividerWithPadding(start = 40.dp, end = 12.dp)
feeSelectorBlockComponent.Content(Modifier)
if (feeState != WcTransactionFeeState.None) {
feeSelectorBlockComponent.Content(Modifier)
}
}
}

View file

@ -34,6 +34,7 @@ import com.tangem.features.walletconnect.transaction.entity.blockaid.WcEstimated
import com.tangem.features.walletconnect.transaction.entity.blockaid.WcSendReceiveTransactionCheckResultsUM
import com.tangem.features.walletconnect.transaction.entity.common.WcNetworkInfoUM
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionAppInfoContentUM
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionFeeState
import com.tangem.features.walletconnect.transaction.entity.send.WcSendTransactionItemUM
import com.tangem.features.walletconnect.transaction.ui.blockaid.TransactionCheckResultsItem
import com.tangem.features.walletconnect.transaction.ui.common.WcSendTransactionItems
@ -42,7 +43,7 @@ import com.tangem.features.walletconnect.transaction.ui.common.WcTransactionRequ
import com.tangem.features.walletconnect.transaction.ui.common.WcTransactionRequestItem
import kotlinx.collections.immutable.persistentListOf
@Suppress("LongParameterList")
@Suppress("LongParameterList", "LongMethod")
@Composable
internal fun WcSendTransactionModalBottomSheet(
state: WcSendTransactionItemUM,
@ -103,6 +104,7 @@ internal fun WcSendTransactionModalBottomSheet(
WcSendTransactionItems(
walletName = state.walletName,
networkInfo = state.networkInfo,
feeState = state.feeState,
feeSelectorBlockComponent = feeSelectorBlockComponent,
address = state.address,
)
@ -192,7 +194,7 @@ private class WcSendTransactionStateProvider : CollectionPreviewParameterProvide
),
walletName = "Tangem 2.0",
networkInfo = WcNetworkInfoUM(name = "Ethereum", iconRes = R.drawable.img_eth_22),
networkFee = "~ 0.22 $",
feeState = WcTransactionFeeState.Loading,
address = "0x345FF...34FA",
),
),

View file

@ -25,11 +25,9 @@ import com.tangem.core.ui.components.divider.DividerWithPadding
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.features.send.v2.api.FeeSelectorBlockComponent
import com.tangem.features.walletconnect.connections.entity.VerifiedDAppState
import com.tangem.features.walletconnect.connections.ui.WcAppInfoItem
import com.tangem.features.walletconnect.impl.R
import com.tangem.features.walletconnect.transaction.components.PreviewFeeSelectorBlockComponent
import com.tangem.features.walletconnect.transaction.entity.common.WcNetworkInfoUM
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionAppInfoContentUM
import com.tangem.features.walletconnect.transaction.entity.sign.WcSignTransactionItemUM
@ -38,7 +36,6 @@ import com.tangem.features.walletconnect.transaction.ui.common.*
@Composable
internal fun WcSignTransactionModalBottomSheetContent(
state: WcSignTransactionItemUM,
feeSelectorBlockComponent: FeeSelectorBlockComponent,
onClickTransactionRequest: () -> Unit,
onBack: () -> Unit,
onDismiss: () -> Unit,
@ -87,7 +84,7 @@ internal fun WcSignTransactionModalBottomSheetContent(
)
}
Column(modifier = Modifier.padding(top = 16.dp)) {
WcSignTransactionItems(state, feeSelectorBlockComponent)
WcSignTransactionItems(state)
}
}
},
@ -104,11 +101,7 @@ internal fun WcSignTransactionModalBottomSheetContent(
}
@Composable
private fun WcSignTransactionItems(
state: WcSignTransactionItemUM,
feeSelectorBlockComponent: FeeSelectorBlockComponent,
modifier: Modifier = Modifier,
) {
private fun WcSignTransactionItems(state: WcSignTransactionItemUM, modifier: Modifier = Modifier) {
Column(
modifier = modifier
.clip(RoundedCornerShape(14.dp))
@ -138,7 +131,6 @@ private fun WcSignTransactionItems(
)
}
DividerWithPadding(start = 40.dp, end = 12.dp)
feeSelectorBlockComponent.Content(modifier = Modifier)
}
}
@ -168,7 +160,6 @@ private fun WcSignTransactionBottomSheetPreview(
content = {
WcSignTransactionModalBottomSheetContent(
state = state,
feeSelectorBlockComponent = PreviewFeeSelectorBlockComponent(),
onClickTransactionRequest = {},
onBack = {},
onDismiss = {},