Updated on 2026-08-14

This commit is contained in:
Tangem 2025-07-10 11:21:16 +05:00
parent 27cf6b6532
commit 9614d041eb
6 changed files with 75 additions and 11 deletions

View file

@ -21,6 +21,7 @@ import com.tangem.core.decompose.navigation.inner.InnerRouter
import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.features.send.v2.api.FeeSelectorBlockComponent
import com.tangem.features.send.v2.api.SendComponent
import com.tangem.features.send.v2.common.CommonSendRoute
import com.tangem.features.send.v2.common.analytics.CommonSendAnalyticEvents
@ -53,6 +54,7 @@ internal class DefaultSendComponent @AssistedInject constructor(
@Assisted appComponentContext: AppComponentContext,
@Assisted private val params: SendComponent.Params,
private val analyticsEventHandler: AnalyticsEventHandler,
private val feeSelectorComponentFactory: FeeSelectorBlockComponent.Factory,
) : SendComponent, AppComponentContext by appComponentContext {
private val stackNavigation = StackNavigation<CommonSendRoute>()
@ -298,6 +300,7 @@ internal class DefaultSendComponent @AssistedInject constructor(
innerRouter.replaceAll(CommonSendRoute.ConfirmSuccess)
},
),
feeSelectorComponentFactory = feeSelectorComponentFactory,
)
} else {
model.showAlertError()

View file

@ -14,9 +14,11 @@ import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.transaction.error.GetFeeError
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.features.send.v2.api.FeeSelectorBlockComponent
import com.tangem.features.send.v2.api.SendNotificationsComponent
import com.tangem.features.send.v2.api.SendNotificationsComponent.Params.NotificationData
import com.tangem.features.send.v2.api.entity.PredefinedValues
import com.tangem.features.send.v2.api.params.FeeSelectorParams
import com.tangem.features.send.v2.api.subcomponents.destination.SendDestinationComponentParams.DestinationBlockParams
import com.tangem.features.send.v2.common.CommonSendRoute
import com.tangem.features.send.v2.common.ui.state.ConfirmUM
@ -35,6 +37,7 @@ import kotlinx.coroutines.flow.*
internal class SendConfirmComponent(
appComponentContext: AppComponentContext,
params: Params,
private val feeSelectorComponentFactory: FeeSelectorBlockComponent.Factory,
) : ComposableContentComponent, AppComponentContext by appComponentContext {
private val model: SendConfirmModel = getOrCreateModel(params = params)
@ -92,6 +95,18 @@ internal class SendConfirmComponent(
onClick = model::showEditFee,
)
private val feeSelectorBlockComponent = feeSelectorComponentFactory.create(
context = appComponentContext,
params = FeeSelectorParams.FeeSelectorBlockParams(
state = model.uiState.value.feeSelectorUM,
onLoadFee = params.onLoadFee,
cryptoCurrencyStatus = params.cryptoCurrencyStatus,
suggestedFeeState = model.suggestedFeeState,
feeDisplaySource = FeeSelectorParams.FeeDisplaySource.Screen,
),
onResult = model::onFeeResult,
)
private val notificationsComponent = DefaultSendNotificationsComponent(
appComponentContext = child("sendConfirmNotifications"),
params = SendNotificationsComponent.Params(
@ -136,6 +151,7 @@ internal class SendConfirmComponent(
destinationBlockComponent = destinationBlockComponent,
amountBlockComponent = amountBlockComponent,
feeBlockComponent = feeBlockComponent,
feeSelectorBlockComponent = feeSelectorBlockComponent,
notificationsComponent = notificationsComponent,
notificationsUM = notificationState,
)

View file

@ -35,6 +35,9 @@ import com.tangem.domain.txhistory.usecase.GetExplorerTransactionUrlUseCase
import com.tangem.domain.utils.convertToSdkAmount
import com.tangem.domain.wallets.models.requireColdWallet
import com.tangem.features.send.v2.api.SendNotificationsComponent.Params.NotificationData
import com.tangem.features.send.v2.api.callbacks.FeeSelectorModelCallback
import com.tangem.features.send.v2.api.params.FeeSelectorParams
import com.tangem.features.send.v2.api.entity.FeeSelectorUM as FeeSelectorUMRedesigned
import com.tangem.features.send.v2.api.subcomponents.destination.entity.DestinationUM
import com.tangem.features.send.v2.common.CommonSendRoute
import com.tangem.features.send.v2.common.SendBalanceUpdater
@ -92,7 +95,7 @@ internal class SendConfirmModel @Inject constructor(
private val urlOpener: UrlOpener,
private val shareManager: ShareManager,
sendBalanceUpdaterFactory: SendBalanceUpdater.Factory,
) : Model(), SendConfirmClickIntents {
) : Model(), SendConfirmClickIntents, FeeSelectorModelCallback {
private val params: SendConfirmComponent.Params = paramsContainer.require()
@ -115,6 +118,8 @@ internal class SendConfirmModel @Inject constructor(
get() = uiState.value.feeUM as? FeeUM.Content
private val feeSelectorUM
get() = feeUM?.feeSelectorUM as? FeeSelectorUM.Content
private val feeUMV2
get() = uiState.value.feeSelectorUM as? FeeSelectorUMRedesigned.Content
val confirmData: ConfirmData
get() = ConfirmData(
@ -129,6 +134,7 @@ internal class SendConfirmModel @Inject constructor(
private var sendIdleTimer: Long = 0L
private var isAmountSubtractAvailable = false
internal var suggestedFeeState: FeeSelectorParams.SuggestedFeeState = FeeSelectorParams.SuggestedFeeState.None
init {
modelScope.launch {
@ -303,13 +309,22 @@ internal class SendConfirmModel @Inject constructor(
notificationsUpdateTrigger.hasErrorFlow
.onEach { hasError ->
_uiState.update {
val feeUM = it.feeUM as? FeeUM.Content
val feeSelectorUM = feeUM?.feeSelectorUM as? FeeSelectorUM.Content
it.copy(
confirmUM = (it.confirmUM as? ConfirmUM.Content)?.copy(
isPrimaryButtonEnabled = !hasError && feeSelectorUM != null,
) ?: it.confirmUM,
)
if (_uiState.value.isRedesignEnabled) {
val feeUM = it.feeSelectorUM as? FeeSelectorUMRedesigned.Content
it.copy(
confirmUM = (it.confirmUM as? ConfirmUM.Content)?.copy(
isPrimaryButtonEnabled = !hasError && feeUM != null,
) ?: it.confirmUM,
)
} else {
val feeUM = it.feeUM as? FeeUM.Content
val feeSelectorUM = feeUM?.feeSelectorUM as? FeeSelectorUM.Content
it.copy(
confirmUM = (it.confirmUM as? ConfirmUM.Content)?.copy(
isPrimaryButtonEnabled = !hasError && feeSelectorUM != null,
) ?: it.confirmUM,
)
}
}
}
.launchIn(modelScope)
@ -319,9 +334,18 @@ internal class SendConfirmModel @Inject constructor(
val amountValue = amountState?.amountTextField?.cryptoAmount?.value ?: return
val destination = destinationUM?.addressTextField?.actualAddress ?: return
val memo = destinationUM?.memoTextField?.value
val fee = feeSelectorUM?.selectedFee
val isRedesignEnabled = uiState.value.isRedesignEnabled
val fee = if (isRedesignEnabled) {
feeUMV2?.selectedFeeItem?.fee
} else {
feeSelectorUM?.selectedFee
}
val nonce = if (isRedesignEnabled) {
feeUMV2?.nonce
} else {
feeSelectorUM?.nonce
}
val feeValue = fee?.amount?.value ?: return
val nonce = feeSelectorUM?.nonce
val receivingAmount = checkAndCalculateSubtractedAmount(
isAmountSubtractAvailable = isAmountSubtractAvailable,
@ -556,6 +580,12 @@ internal class SendConfirmModel @Inject constructor(
)
}
override fun onFeeResult(feeSelectorUM: FeeSelectorUMRedesigned) {
sendIdleTimer = SystemClock.elapsedRealtime()
_uiState.update { it.copy(feeSelectorUM = feeSelectorUM) }
updateConfirmNotifications()
}
private companion object {
const val CHECK_FEE_UPDATE_DELAY = 10_000L
}

View file

@ -1,6 +1,7 @@
package com.tangem.features.send.v2.send.confirm.ui
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
@ -9,6 +10,7 @@ import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.unit.dp
import com.tangem.common.ui.notifications.NotificationUM
import com.tangem.core.ui.components.SpacerHMax
@ -19,6 +21,7 @@ import com.tangem.core.ui.extensions.wrappedList
import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.utils.DateTimeFormatters
import com.tangem.core.ui.utils.toTimeFormat
import com.tangem.features.send.v2.api.FeeSelectorBlockComponent
import com.tangem.features.send.v2.common.ui.SendingText
import com.tangem.features.send.v2.common.ui.state.ConfirmUM
import com.tangem.features.send.v2.common.ui.tapHelp
@ -40,6 +43,7 @@ internal fun SendConfirmContent(
destinationBlockComponent: DefaultSendDestinationBlockComponent,
amountBlockComponent: SendAmountBlockComponent,
feeBlockComponent: SendFeeBlockComponent,
feeSelectorBlockComponent: FeeSelectorBlockComponent,
notificationsComponent: DefaultSendNotificationsComponent,
notificationsUM: ImmutableList<NotificationUM>,
) {
@ -54,6 +58,7 @@ internal fun SendConfirmContent(
destinationBlockComponent = destinationBlockComponent,
amountBlockComponent = amountBlockComponent,
feeBlockComponent = feeBlockComponent,
feeSelectorBlockComponent = feeSelectorBlockComponent,
)
if (confirmUM != null) {
tapHelp(isDisplay = confirmUM.showTapHelp)
@ -79,18 +84,24 @@ private fun LazyListScope.blocks(
destinationBlockComponent: DefaultSendDestinationBlockComponent,
amountBlockComponent: SendAmountBlockComponent,
feeBlockComponent: SendFeeBlockComponent,
feeSelectorBlockComponent: FeeSelectorBlockComponent,
) {
item(key = BLOCKS_KEY) {
Column(verticalArrangement = Arrangement.spacedBy(12.dp)) {
if (uiState.isRedesignEnabled) {
amountBlockComponent.Content(modifier = Modifier)
destinationBlockComponent.Content(modifier = Modifier)
feeSelectorBlockComponent.Content(
modifier = Modifier
.clip(TangemTheme.shapes.roundedCornersXMedium)
.background(TangemTheme.colors.background.action),
)
} else {
TransactionDoneTitleAnimated(uiState)
destinationBlockComponent.Content(modifier = Modifier)
amountBlockComponent.Content(modifier = Modifier)
feeBlockComponent.Content(modifier = Modifier)
}
feeBlockComponent.Content(modifier = Modifier)
}
}
}

View file

@ -39,6 +39,7 @@ import com.tangem.domain.wallets.models.requireColdWallet
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
import com.tangem.features.send.v2.api.SendComponent
import com.tangem.features.send.v2.api.SendFeatureToggles
import com.tangem.features.send.v2.api.entity.FeeSelectorUM
import com.tangem.features.send.v2.api.entity.PredefinedValues
import com.tangem.features.send.v2.api.subcomponents.destination.SendDestinationComponent
import com.tangem.features.send.v2.api.subcomponents.destination.entity.DestinationUM
@ -395,5 +396,6 @@ internal class SendModel @Inject constructor(
navigationUM = NavigationUM.Empty,
isRedesignEnabled = sendFeatureToggles.isSendRedesignEnabled,
confirmData = null,
feeSelectorUM = FeeSelectorUM.Loading,
)
}

View file

@ -2,6 +2,7 @@ package com.tangem.features.send.v2.send.ui.state
import com.tangem.common.ui.amountScreen.models.AmountState
import com.tangem.common.ui.navigationButtons.NavigationUM
import com.tangem.features.send.v2.api.entity.FeeSelectorUM
import com.tangem.features.send.v2.api.subcomponents.destination.entity.DestinationUM
import com.tangem.features.send.v2.common.ui.state.ConfirmUM
import com.tangem.features.send.v2.send.confirm.model.ConfirmData
@ -11,6 +12,7 @@ internal data class SendUM(
val amountUM: AmountState,
val destinationUM: DestinationUM,
val feeUM: FeeUM,
val feeSelectorUM: FeeSelectorUM,
val confirmUM: ConfirmUM,
val navigationUM: NavigationUM,
val isRedesignEnabled: Boolean,