Updated on 2026-08-14

This commit is contained in:
Tangem 2025-08-18 19:36:50 +05:00
parent 6f047b8607
commit 694c215bb1
14 changed files with 178 additions and 178 deletions

View file

@ -0,0 +1,70 @@
package com.tangem.features.send.v2.common.ui
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import com.tangem.common.ui.amountScreen.utils.getFiatReference
import com.tangem.core.ui.components.rows.SelectorRowItem
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.extensions.stringResourceSafe
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.features.send.v2.api.entity.FeeSelectorUM
import com.tangem.features.send.v2.impl.R
@Composable
internal fun FeeBlock(feeSelectorUM: FeeSelectorUM) {
if (feeSelectorUM !is FeeSelectorUM.Content) return
val feeExtraInfo = feeSelectorUM.feeExtraInfo
val feeFiatRateUM = feeSelectorUM.feeFiatRateUM
Column(
modifier = Modifier
.fillMaxWidth()
.clip(TangemTheme.shapes.roundedCornersXMedium)
.background(TangemTheme.colors.background.action)
.padding(TangemTheme.dimens.spacing12),
) {
Text(
text = stringResourceSafe(R.string.common_network_fee_title),
style = TangemTheme.typography.subtitle2,
color = TangemTheme.colors.text.tertiary,
)
Box(modifier = Modifier.padding(top = TangemTheme.dimens.spacing8)) {
val feeItemUM = feeSelectorUM.selectedFeeItem
val feeAmount = feeItemUM.fee.amount
SelectorRowItem(
title = feeItemUM.title,
iconRes = feeItemUM.iconRes,
preDot = remember {
stringReference(
feeAmount.value.format {
crypto(
symbol = feeAmount.currencySymbol,
decimals = feeAmount.decimals,
).fee(canBeLower = feeExtraInfo.isFeeApproximate)
},
)
},
postDot = remember {
if (feeExtraInfo.isFeeConvertibleToFiat && feeFiatRateUM != null) {
getFiatReference(feeAmount.value, feeFiatRateUM.rate, feeFiatRateUM.appCurrency)
} else {
null
}
},
ellipsizeOffset = feeAmount.currencySymbol.length,
isSelected = true,
showDivider = false,
showSelectedAppearance = false,
paddingValues = PaddingValues(),
)
}
}
}

View file

@ -18,8 +18,6 @@ import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.res.TangemTheme
import com.tangem.features.send.v2.common.CommonSendRoute
import com.tangem.features.send.v2.send.confirm.SendConfirmComponent
import com.tangem.features.send.v2.send.success.SendConfirmSuccessComponent
@Composable
internal fun SendContent(
@ -38,9 +36,9 @@ internal fun SendContent(
Children(
stack = stackState,
animation = stackAnimation { child ->
when (child.instance) {
is SendConfirmSuccessComponent -> fade(minAlpha = 1.0f)
is SendConfirmComponent -> fade()
when (child.configuration) {
is CommonSendRoute.ConfirmSuccess -> fade(minAlpha = 1.0f)
is CommonSendRoute.Confirm -> fade()
else -> slide()
}
},

View file

@ -115,7 +115,6 @@ private fun FeeTitle(feeDisplaySource: FeeSelectorParams.FeeDisplaySource, onDis
}
}
@Suppress("LongMethod", "CyclomaticComplexMethod")
@Composable
private fun FeeSelectorItems(
state: FeeSelectorUM.Content,
@ -144,110 +143,6 @@ private fun FeeSelectorItems(
.selectedBorder(isSelected = isSelected)
.clickableSingle(onClick = { feeSelectorIntents.onFeeItemSelected(item) })
when (item) {
is FeeItem.Suggested -> RegularFeeItemContent(
modifier = itemModifier,
title = item.title,
iconRes = R.drawable.ic_star_mini_24,
iconBackgroundColor = iconBackgroundColor,
iconTint = iconTint,
preDot = stringReference(
item.fee.amount.value.format {
crypto(
symbol = item.fee.amount.currencySymbol,
decimals = item.fee.amount.decimals,
).fee(canBeLower = state.feeExtraInfo.isFeeApproximate)
},
),
postDot = if (feeFiatRateUM != null) {
getFiatReference(
value = item.fee.amount.value,
rate = feeFiatRateUM.rate,
appCurrency = feeFiatRateUM.appCurrency,
)
} else {
null
},
ellipsizeOffset = item.fee.amount.currencySymbol.length,
showDivider = !isSelected && !lastItem,
)
is FeeItem.Slow -> RegularFeeItemContent(
modifier = itemModifier,
title = resourceReference(R.string.common_fee_selector_option_slow),
iconRes = R.drawable.ic_tortoise_24,
iconBackgroundColor = iconBackgroundColor,
iconTint = iconTint,
preDot = stringReference(
item.fee.amount.value.format {
crypto(
symbol = item.fee.amount.currencySymbol,
decimals = item.fee.amount.decimals,
).fee(canBeLower = state.feeExtraInfo.isFeeApproximate)
},
),
postDot = if (feeFiatRateUM != null) {
getFiatReference(
value = item.fee.amount.value,
rate = feeFiatRateUM.rate,
appCurrency = feeFiatRateUM.appCurrency,
)
} else {
null
},
ellipsizeOffset = item.fee.amount.currencySymbol.length,
showDivider = !isSelected && !lastItem,
)
is FeeItem.Market -> RegularFeeItemContent(
modifier = itemModifier,
title = resourceReference(R.string.common_fee_selector_option_market),
iconRes = R.drawable.ic_bird_24,
iconBackgroundColor = iconBackgroundColor,
iconTint = iconTint,
preDot = stringReference(
item.fee.amount.value.format {
crypto(
symbol = item.fee.amount.currencySymbol,
decimals = item.fee.amount.decimals,
).fee(canBeLower = state.feeExtraInfo.isFeeApproximate)
},
),
postDot = if (feeFiatRateUM != null) {
getFiatReference(
value = item.fee.amount.value,
rate = feeFiatRateUM.rate,
appCurrency = feeFiatRateUM.appCurrency,
)
} else {
null
},
ellipsizeOffset = item.fee.amount.currencySymbol.length,
showDivider = !isSelected && !lastItem,
)
is FeeItem.Fast -> RegularFeeItemContent(
modifier = itemModifier,
title = resourceReference(R.string.common_fee_selector_option_fast),
iconRes = R.drawable.ic_hare_24,
iconBackgroundColor = iconBackgroundColor,
iconTint = iconTint,
preDot = stringReference(
item.fee.amount.value.format {
crypto(
symbol = item.fee.amount.currencySymbol,
decimals = item.fee.amount.decimals,
).fee(canBeLower = state.feeExtraInfo.isFeeApproximate)
},
),
postDot = if (feeFiatRateUM != null) {
getFiatReference(
value = item.fee.amount.value,
rate = feeFiatRateUM.rate,
appCurrency = feeFiatRateUM.appCurrency,
)
} else {
null
},
ellipsizeOffset = item.fee.amount.currencySymbol.length,
showDivider = !isSelected && !lastItem,
)
is FeeItem.Custom -> CustomFeeBlock(
modifier = itemModifier,
customFee = item,
@ -257,6 +152,32 @@ private fun FeeSelectorItems(
onValueChange = feeSelectorIntents::onCustomFeeValueChange,
nonce = state.feeNonce,
)
else -> RegularFeeItemContent(
modifier = itemModifier,
title = item.title,
iconRes = item.iconRes,
iconBackgroundColor = iconBackgroundColor,
iconTint = iconTint,
preDot = stringReference(
item.fee.amount.value.format {
crypto(
symbol = item.fee.amount.currencySymbol,
decimals = item.fee.amount.decimals,
).fee(canBeLower = state.feeExtraInfo.isFeeApproximate)
},
),
postDot = if (feeFiatRateUM != null) {
getFiatReference(
value = item.fee.amount.value,
rate = feeFiatRateUM.rate,
appCurrency = feeFiatRateUM.appCurrency,
)
} else {
null
},
ellipsizeOffset = item.fee.amount.currencySymbol.length,
showDivider = !isSelected && !lastItem,
)
}
}
}
@ -491,7 +412,14 @@ private class FeeSelectorUMContentProvider : CollectionPreviewParameterProvider<
fee = Fee.Common(Amount(value = BigDecimal("0.1"), blockchain = Blockchain.Ethereum)),
),
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.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,
),

View file

@ -38,7 +38,6 @@ import com.tangem.features.send.v2.subcomponents.amount.SendAmountComponent
import com.tangem.features.send.v2.subcomponents.amount.SendAmountComponentParams
import com.tangem.features.send.v2.subcomponents.destination.DefaultSendDestinationBlockComponent
import com.tangem.features.send.v2.subcomponents.destination.DefaultSendDestinationComponent
import com.tangem.features.send.v2.subcomponents.fee.SendFeeBlockComponent
import com.tangem.features.send.v2.subcomponents.fee.SendFeeComponent
import com.tangem.features.send.v2.subcomponents.fee.SendFeeComponentParams
import dagger.assisted.Assisted
@ -254,7 +253,6 @@ internal class DefaultSendComponent @AssistedInject constructor(
val destinationAddress = (state.destinationUM as? DestinationUM.Content)?.addressTextField?.value
val txUrl = (state.confirmUM as? ConfirmUM.Success)?.txUrl
val cryptoCurrencyStatus = model.cryptoCurrencyStatusFlow.value
val feeCryptoCurrencyStatus = model.feeCryptoCurrencyStatusFlow.value
if (sendAmount == null ||
destinationAddress == null ||
@ -279,29 +277,10 @@ internal class DefaultSendComponent @AssistedInject constructor(
onClick = {},
)
val feeBlockComponent = SendFeeBlockComponent(
appComponentContext = child("sendConfirmFeeBlock"),
params = SendFeeComponentParams.FeeBlockParams(
state = model.uiState.value.feeUM,
analyticsCategoryName = model.analyticCategoryName,
userWallet = model.userWallet,
cryptoCurrencyStatus = cryptoCurrencyStatus,
feeCryptoCurrencyStatus = feeCryptoCurrencyStatus,
appCurrency = model.appCurrency,
sendAmount = sendAmount,
destinationAddress = destinationAddress,
blockClickEnableFlow = MutableStateFlow(true),
onLoadFee = model::loadFee,
),
onResult = { },
onClick = {},
)
return SendConfirmSuccessComponent(
appComponentContext = factoryContext,
params = SendConfirmSuccessComponent.Params(
sendUMFlow = model.uiState,
feeBlockComponent = feeBlockComponent,
destinationBlockComponent = destinationBlockComponent,
analyticsCategoryName = model.analyticCategoryName,
currentRoute = model.currentRoute,

View file

@ -12,7 +12,6 @@ import com.tangem.features.send.v2.common.CommonSendRoute
import com.tangem.features.send.v2.send.success.model.SendConfirmSuccessModel
import com.tangem.features.send.v2.send.success.ui.SendConfirmSuccessContent
import com.tangem.features.send.v2.send.ui.state.SendUM
import com.tangem.features.send.v2.subcomponents.fee.SendFeeBlockComponent
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow
@ -23,7 +22,6 @@ internal class SendConfirmSuccessComponent(
private val model: SendConfirmSuccessModel = getOrCreateModel(params = params)
private val destinationBlockComponent: SendDestinationBlockComponent = params.destinationBlockComponent
private val feeBlockComponent: SendFeeBlockComponent = params.feeBlockComponent
@Composable
override fun Content(modifier: Modifier) {
@ -31,14 +29,12 @@ internal class SendConfirmSuccessComponent(
SendConfirmSuccessContent(
sendUM = state,
destinationBlockComponent = destinationBlockComponent,
feeBlockComponent = feeBlockComponent,
)
}
data class Params(
val sendUMFlow: StateFlow<SendUM>,
val destinationBlockComponent: SendDestinationBlockComponent,
val feeBlockComponent: SendFeeBlockComponent,
val analyticsCategoryName: String,
val currentRoute: Flow<CommonSendRoute>,
val txUrl: String,

View file

@ -21,18 +21,14 @@ import com.tangem.core.ui.utils.DateTimeFormatters
import com.tangem.core.ui.utils.toPx
import com.tangem.core.ui.utils.toTimeFormat
import com.tangem.features.send.v2.api.subcomponents.destination.SendDestinationBlockComponent
import com.tangem.features.send.v2.common.ui.FeeBlock
import com.tangem.features.send.v2.common.ui.state.ConfirmUM
import com.tangem.features.send.v2.impl.R
import com.tangem.features.send.v2.send.ui.state.SendUM
import com.tangem.features.send.v2.subcomponents.fee.SendFeeBlockComponent
import kotlinx.coroutines.delay
@Composable
internal fun SendConfirmSuccessContent(
sendUM: SendUM,
destinationBlockComponent: SendDestinationBlockComponent,
feeBlockComponent: SendFeeBlockComponent,
) {
internal fun SendConfirmSuccessContent(sendUM: SendUM, destinationBlockComponent: SendDestinationBlockComponent) {
var visible by remember { mutableStateOf(false) }
LaunchedEffect(Unit) {
@ -84,7 +80,7 @@ internal fun SendConfirmSuccessContent(
onClick = {},
)
destinationBlockComponent.Content(modifier = Modifier)
feeBlockComponent.Content(modifier = Modifier)
FeeBlock(feeSelectorUM = sendUM.feeSelectorUM)
Spacer(Modifier.height(60.dp))
}
BottomFade(Modifier.align(Alignment.BottomCenter), TangemTheme.colors.background.tertiary)

View file

@ -6,6 +6,7 @@ import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
@ -14,6 +15,7 @@ import com.tangem.blockchain.common.transaction.TransactionFee
import com.tangem.common.ui.amountScreen.utils.getFiatReference
import com.tangem.core.ui.components.RectangleShimmer
import com.tangem.core.ui.components.rows.SelectorRowItem
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.format.bigdecimal.BigDecimalFormatConstants.EMPTY_BALANCE_SIGN
@ -62,20 +64,24 @@ internal fun FeeBlock(feeUM: FeeUM, isClickEnabled: Boolean, onClick: () -> Unit
R.string.common_fee_selector_option_market to R.drawable.ic_bird_24
}
SelectorRowItem(
titleRes = title,
title = resourceReference(title),
iconRes = icon,
preDot = stringReference(
feeAmount?.value.format {
crypto(
symbol = feeAmount?.currencySymbol.orEmpty(),
decimals = feeAmount?.decimals ?: 0,
).fee(canBeLower = feeUM.isFeeApproximate)
},
),
postDot = if (feeUM.isFeeConvertibleToFiat) {
getFiatReference(feeAmount?.value, feeUM.rate, feeUM.appCurrency)
} else {
null
preDot = remember {
stringReference(
feeAmount?.value.format {
crypto(
symbol = feeAmount?.currencySymbol.orEmpty(),
decimals = feeAmount?.decimals ?: 0,
).fee(canBeLower = feeUM.isFeeApproximate)
},
)
},
postDot = remember {
if (feeUM.isFeeConvertibleToFiat) {
getFiatReference(feeAmount?.value, feeUM.rate, feeUM.appCurrency)
} else {
null
}
},
ellipsizeOffset = feeAmount?.currencySymbol?.length,
isSelected = true,

View file

@ -16,6 +16,7 @@ import com.tangem.common.ui.amountScreen.utils.getFiatReference
import com.tangem.core.ui.components.RectangleShimmer
import com.tangem.core.ui.components.SpacerWMax
import com.tangem.core.ui.components.rows.SelectorRowItem
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.format.bigdecimal.BigDecimalFormatConstants.EMPTY_BALANCE_SIGN
import com.tangem.core.ui.format.bigdecimal.crypto
@ -52,7 +53,7 @@ internal fun SendSpeedSelectorItem(
.clickable { onSelect() },
) {
SelectorRowItem(
titleRes = titleRes,
title = resourceReference(titleRes),
iconRes = iconRes,
onSelect = onSelect,
modifier = modifier,