Updated on 2026-08-14
This commit is contained in:
parent
c8c61bb9d6
commit
4089fe43ac
6 changed files with 127 additions and 41 deletions
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.features.walletconnect.transaction.converter
|
||||
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.walletconnect.model.WcEthMethod
|
||||
import com.tangem.domain.walletconnect.model.WcSolanaMethod
|
||||
import com.tangem.domain.walletconnect.usecase.method.WcMethodContext
|
||||
|
|
@ -12,6 +13,7 @@ import com.tangem.features.walletconnect.transaction.entity.common.WcTransaction
|
|||
import com.tangem.features.walletconnect.transaction.entity.common.WcTransactionRequestInfoUM
|
||||
import com.tangem.features.walletconnect.transaction.entity.send.WcSendTransactionItemUM
|
||||
import com.tangem.features.walletconnect.transaction.entity.send.WcSendTransactionUM
|
||||
import com.tangem.features.walletconnect.utils.WcNotificationsFactory
|
||||
import com.tangem.utils.converter.Converter
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import javax.inject.Inject
|
||||
|
|
@ -20,44 +22,52 @@ internal class WcSendTransactionUMConverter @Inject constructor(
|
|||
private val appInfoContentUMConverter: WcTransactionAppInfoContentUMConverter,
|
||||
private val networkInfoUMConverter: WcNetworkInfoUMConverter,
|
||||
private val requestBlockUMConverter: WcTransactionRequestBlockUMConverter,
|
||||
private val notificationsFactory: WcNotificationsFactory,
|
||||
) : Converter<WcSendTransactionUMConverter.Input, WcSendTransactionUM?> {
|
||||
|
||||
override fun convert(value: Input): WcSendTransactionUM? = when (value.context.method) {
|
||||
is WcEthMethod.SendTransaction,
|
||||
is WcEthMethod.SignTransaction,
|
||||
is WcSolanaMethod.SignAllTransaction,
|
||||
is WcSolanaMethod.SignTransaction,
|
||||
-> WcSendTransactionUM(
|
||||
transaction = WcSendTransactionItemUM(
|
||||
onDismiss = value.actions.onDismiss,
|
||||
onSend = value.actions.onSign,
|
||||
appInfo = appInfoContentUMConverter.convert(
|
||||
WcTransactionAppInfoContentUMConverter.Input(
|
||||
session = value.context.session,
|
||||
onShowVerifiedAlert = value.actions.onShowVerifiedAlert,
|
||||
),
|
||||
),
|
||||
feeState = value.feeState,
|
||||
walletName = value.context.session.wallet.name.takeIf { value.context.session.showWalletInfo },
|
||||
networkInfo = networkInfoUMConverter.convert(value.context.network),
|
||||
estimatedWalletChanges = WcSendReceiveTransactionCheckResultsUM(),
|
||||
isLoading = value.signState.domainStep == WcSignStep.Signing,
|
||||
address = WcAddressConverter.convert(value.context.derivationState),
|
||||
sendEnabled = value.feeSelectorUM is FeeSelectorUM.Content,
|
||||
),
|
||||
feeSelectorUM = value.feeSelectorUM ?: FeeSelectorUM.Loading,
|
||||
transactionRequestInfo = WcTransactionRequestInfoUM(
|
||||
blocks = buildList {
|
||||
addAll(
|
||||
requestBlockUMConverter.convert(
|
||||
WcTransactionRequestBlockUMConverter.Input(value.context.rawSdkRequest),
|
||||
),
|
||||
)
|
||||
}.toImmutableList(),
|
||||
onCopy = value.actions.onCopy,
|
||||
),
|
||||
override fun convert(value: Input): WcSendTransactionUM? {
|
||||
val feeExceedsBalance = notificationsFactory.createFeeExceedsBalance(
|
||||
cryptoCurrencyStatus = value.cryptoCurrencyStatus,
|
||||
feeSelectorUM = value.feeSelectorUM,
|
||||
)
|
||||
else -> null
|
||||
return when (value.context.method) {
|
||||
is WcEthMethod.SendTransaction,
|
||||
is WcEthMethod.SignTransaction,
|
||||
is WcSolanaMethod.SignAllTransaction,
|
||||
is WcSolanaMethod.SignTransaction,
|
||||
-> WcSendTransactionUM(
|
||||
transaction = WcSendTransactionItemUM(
|
||||
onDismiss = value.actions.onDismiss,
|
||||
onSend = value.actions.onSign,
|
||||
appInfo = appInfoContentUMConverter.convert(
|
||||
WcTransactionAppInfoContentUMConverter.Input(
|
||||
session = value.context.session,
|
||||
onShowVerifiedAlert = value.actions.onShowVerifiedAlert,
|
||||
),
|
||||
),
|
||||
feeState = value.feeState,
|
||||
walletName = value.context.session.wallet.name.takeIf { value.context.session.showWalletInfo },
|
||||
networkInfo = networkInfoUMConverter.convert(value.context.network),
|
||||
estimatedWalletChanges = WcSendReceiveTransactionCheckResultsUM(),
|
||||
isLoading = value.signState.domainStep == WcSignStep.Signing,
|
||||
address = WcAddressConverter.convert(value.context.derivationState),
|
||||
sendEnabled = value.feeSelectorUM is FeeSelectorUM.Content && feeExceedsBalance == null,
|
||||
feeExceedsBalanceNotification = feeExceedsBalance,
|
||||
),
|
||||
feeSelectorUM = value.feeSelectorUM ?: FeeSelectorUM.Loading,
|
||||
transactionRequestInfo = WcTransactionRequestInfoUM(
|
||||
blocks = buildList {
|
||||
addAll(
|
||||
requestBlockUMConverter.convert(
|
||||
WcTransactionRequestBlockUMConverter.Input(value.context.rawSdkRequest),
|
||||
),
|
||||
)
|
||||
}.toImmutableList(),
|
||||
onCopy = value.actions.onCopy,
|
||||
),
|
||||
)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
data class Input(
|
||||
|
|
@ -66,5 +76,6 @@ internal class WcSendTransactionUMConverter @Inject constructor(
|
|||
val signState: WcSignState<*>,
|
||||
val actions: WcTransactionActionsUM,
|
||||
val feeSelectorUM: FeeSelectorUM?,
|
||||
val cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
)
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.features.walletconnect.transaction.entity.send
|
||||
|
||||
import com.tangem.common.ui.notifications.NotificationUM
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
|
||||
import com.tangem.features.send.v2.api.entity.FeeSelectorUM
|
||||
import com.tangem.features.walletconnect.transaction.entity.approve.WcSpendAllowanceUM
|
||||
|
|
@ -27,5 +28,6 @@ internal data class WcSendTransactionItemUM(
|
|||
val networkInfo: WcNetworkInfoUM,
|
||||
val address: String?,
|
||||
val sendEnabled: Boolean,
|
||||
val feeExceedsBalanceNotification: NotificationUM.Info?,
|
||||
val isLoading: Boolean = false,
|
||||
) : TangemBottomSheetConfigContent
|
||||
|
|
@ -47,6 +47,7 @@ import com.tangem.features.walletconnect.transaction.entity.common.WcTransaction
|
|||
import com.tangem.features.walletconnect.transaction.entity.send.WcSendTransactionUM
|
||||
import com.tangem.features.walletconnect.transaction.routes.WcTransactionRoutes
|
||||
import com.tangem.features.walletconnect.transaction.ui.blockaid.WcSendAndReceiveBlockAidUiConverter
|
||||
import com.tangem.features.walletconnect.utils.WcNotificationsFactory
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
|
|
@ -69,6 +70,7 @@ internal class WcSendTransactionModel @Inject constructor(
|
|||
private val blockAidUiConverter: WcSendAndReceiveBlockAidUiConverter,
|
||||
private val getFeeUseCase: GetFeeUseCase,
|
||||
private val getNetworkCoinUseCase: GetNetworkCoinStatusUseCase,
|
||||
private val notificationsFactory: WcNotificationsFactory,
|
||||
private val analytics: AnalyticsEventHandler,
|
||||
) : Model(), WcCommonTransactionModel, FeeSelectorModelCallback {
|
||||
|
||||
|
|
@ -159,10 +161,17 @@ internal class WcSendTransactionModel @Inject constructor(
|
|||
* Also handles fee results from FeeSelectorBlockComponent
|
||||
*/
|
||||
fun updateFee(feeSelectorUM: FeeSelectorUM) {
|
||||
val feeExceedsBalance = notificationsFactory.createFeeExceedsBalance(
|
||||
cryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
feeSelectorUM = feeSelectorUM,
|
||||
)
|
||||
_uiState.update {
|
||||
it?.copy(
|
||||
feeSelectorUM = feeSelectorUM,
|
||||
transaction = it.transaction.copy(sendEnabled = feeSelectorUM is FeeSelectorUM.Content),
|
||||
transaction = it.transaction.copy(
|
||||
sendEnabled = feeSelectorUM is FeeSelectorUM.Content && feeExceedsBalance == null,
|
||||
feeExceedsBalanceNotification = feeExceedsBalance,
|
||||
),
|
||||
)
|
||||
}
|
||||
val fee = (feeSelectorUM as? FeeSelectorUM.Content)?.selectedFeeItem?.fee ?: return
|
||||
|
|
@ -227,6 +236,7 @@ internal class WcSendTransactionModel @Inject constructor(
|
|||
signState = signState,
|
||||
actions = actions,
|
||||
feeSelectorUM = uiState.value?.feeSelectorUM,
|
||||
cryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
),
|
||||
)
|
||||
transactionUM = transactionUM?.copy(
|
||||
|
|
|
|||
|
|
@ -18,12 +18,14 @@ 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
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
@Composable
|
||||
internal fun WcSendTransactionItems(
|
||||
walletName: String?,
|
||||
networkInfo: WcNetworkInfoUM,
|
||||
feeState: WcTransactionFeeState,
|
||||
feeSelectorBlockComponent: FeeSelectorBlockComponent?,
|
||||
feeExceedsBalance: Boolean,
|
||||
address: String?,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
|
|
@ -62,7 +64,7 @@ internal fun WcSendTransactionItems(
|
|||
address = address,
|
||||
)
|
||||
}
|
||||
if (feeState != WcTransactionFeeState.None) {
|
||||
if (feeState != WcTransactionFeeState.None && !feeExceedsBalance) {
|
||||
DividerWithPadding(start = 40.dp, end = 12.dp)
|
||||
feeSelectorBlockComponent?.Content(
|
||||
modifier = if (onFeeBlockClicked != null) {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,9 @@ import android.content.res.Configuration
|
|||
import androidx.compose.animation.animateContentSize
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
|
|
@ -14,14 +16,17 @@ import androidx.compose.ui.tooling.preview.Preview
|
|||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.common.ui.notifications.NotificationUM
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
|
||||
import com.tangem.core.ui.components.bottomsheets.modal.TangemModalBottomSheet
|
||||
import com.tangem.core.ui.components.bottomsheets.modal.TangemModalBottomSheetTitle
|
||||
import com.tangem.core.ui.components.bottomsheets.modal.TangemModalBottomSheetWithFooter
|
||||
import com.tangem.core.ui.components.divider.DividerWithPadding
|
||||
import com.tangem.core.ui.components.notifications.Notification
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.features.send.v2.api.FeeSelectorBlockComponent
|
||||
|
|
@ -101,14 +106,22 @@ internal fun WcSendTransactionModalBottomSheet(
|
|||
if (state.estimatedWalletChanges != null) {
|
||||
TransactionCheckResultsItem(state.estimatedWalletChanges, onClickAllowToSpend)
|
||||
}
|
||||
Spacer(Modifier.height(16.dp))
|
||||
WcSendTransactionItems(
|
||||
modifier = Modifier.padding(top = 16.dp),
|
||||
walletName = state.walletName,
|
||||
networkInfo = state.networkInfo,
|
||||
feeState = state.feeState,
|
||||
feeSelectorBlockComponent = feeSelectorBlockComponent,
|
||||
feeExceedsBalance = state.feeExceedsBalanceNotification != null,
|
||||
address = state.address,
|
||||
)
|
||||
if (state.feeExceedsBalanceNotification != null) {
|
||||
Notification(
|
||||
modifier = Modifier.padding(top = 14.dp),
|
||||
config = state.feeExceedsBalanceNotification.config,
|
||||
iconTint = TangemTheme.colors.icon.warning,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -199,9 +212,10 @@ private class WcSendTransactionStateProvider : CollectionPreviewParameterProvide
|
|||
),
|
||||
walletName = "Tangem 2.0 Tangem 2.0 Tangem 2",
|
||||
networkInfo = WcNetworkInfoUM(name = "Optimistic Ethereum Network", iconRes = R.drawable.img_eth_22),
|
||||
feeState = WcTransactionFeeState.Success(null, {}),
|
||||
feeState = WcTransactionFeeState.Success(dAppFee = null, onClick = {}),
|
||||
address = null,
|
||||
sendEnabled = true,
|
||||
feeExceedsBalanceNotification = null,
|
||||
),
|
||||
WcSendTransactionItemUM(
|
||||
onDismiss = {},
|
||||
|
|
@ -237,9 +251,13 @@ private class WcSendTransactionStateProvider : CollectionPreviewParameterProvide
|
|||
),
|
||||
walletName = "Tangem 2.0",
|
||||
networkInfo = WcNetworkInfoUM(name = "Ethereum", iconRes = R.drawable.img_eth_22),
|
||||
feeState = WcTransactionFeeState.Success(null, {}),
|
||||
feeState = WcTransactionFeeState.Success(dAppFee = null, onClick = {}),
|
||||
address = "0xdac17f958d2ee523a2206206994597c13d831ec7",
|
||||
sendEnabled = true,
|
||||
feeExceedsBalanceNotification = NotificationUM.Info(
|
||||
title = stringReference("Insufficient Ethereum"),
|
||||
subtitle = stringReference("Top up your balance to cover the network fee"),
|
||||
),
|
||||
),
|
||||
WcSendTransactionItemUM(
|
||||
onDismiss = {},
|
||||
|
|
@ -278,6 +296,10 @@ private class WcSendTransactionStateProvider : CollectionPreviewParameterProvide
|
|||
feeState = WcTransactionFeeState.None,
|
||||
address = null,
|
||||
sendEnabled = false,
|
||||
feeExceedsBalanceNotification = NotificationUM.Info(
|
||||
title = stringReference("Insufficient Ethereum"),
|
||||
subtitle = stringReference("Top up your balance to cover the network fee"),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
package com.tangem.features.walletconnect.utils
|
||||
|
||||
import com.tangem.blockchain.common.transaction.TransactionFee
|
||||
import com.tangem.common.ui.notifications.NotificationUM
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.features.send.v2.api.entity.FeeSelectorUM
|
||||
import com.tangem.features.send.v2.api.subcomponents.feeSelector.utils.FeeCalculationUtils
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class WcNotificationsFactory @Inject constructor() {
|
||||
|
||||
fun createFeeExceedsBalance(
|
||||
cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
feeSelectorUM: FeeSelectorUM?,
|
||||
): NotificationUM.Info? {
|
||||
// TODO: [REDACTED_TASK_KEY] localization
|
||||
return NotificationUM.Info(
|
||||
title = stringReference("Insufficient ${cryptoCurrencyStatus.currency.name}"),
|
||||
subtitle = stringReference("Top up your balance to cover the network fee"),
|
||||
).takeIf { isFeeExceedsBalance(cryptoCurrencyStatus = cryptoCurrencyStatus, feeSelectorUM = feeSelectorUM) }
|
||||
}
|
||||
|
||||
private fun isFeeExceedsBalance(
|
||||
cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
feeSelectorUM: FeeSelectorUM?,
|
||||
): Boolean {
|
||||
val feeSelectorContent = feeSelectorUM as? FeeSelectorUM.Content ?: return false
|
||||
val lowestFee = when (val fees = feeSelectorContent.fees) {
|
||||
is TransactionFee.Choosable -> fees.minimum
|
||||
is TransactionFee.Single -> fees.normal
|
||||
}
|
||||
|
||||
return FeeCalculationUtils.checkExceedBalance(
|
||||
feeBalance = cryptoCurrencyStatus.value.amount,
|
||||
feeAmount = lowestFee.amount.value,
|
||||
)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue