Updated on 2026-08-14
This commit is contained in:
commit
bfd903b43c
595 changed files with 12755 additions and 19837 deletions
|
|
@ -1,7 +1,7 @@
|
|||
package com.tangem.feature.swap.converters
|
||||
|
||||
import com.tangem.common.ui.alerts.TransactionErrorAlertConverter
|
||||
import com.tangem.common.ui.alerts.models.AlertUM
|
||||
import com.tangem.common.ui.alerts.TransactionErrorDialogFactory
|
||||
import com.tangem.core.ui.message.DialogMessage
|
||||
import com.tangem.domain.transaction.error.SendTransactionError
|
||||
import com.tangem.feature.swap.domain.models.ui.SwapTransactionState
|
||||
import com.tangem.feature.swap.models.SwapAlertUM
|
||||
|
|
@ -11,24 +11,25 @@ import com.tangem.utils.converter.Converter
|
|||
internal class SwapTransactionErrorStateConverter(
|
||||
private val onDismiss: () -> Unit,
|
||||
private val onSupportClick: (String) -> Unit,
|
||||
) : Converter<SwapTransactionState.Error, AlertUM?> {
|
||||
override fun convert(value: SwapTransactionState.Error): AlertUM? {
|
||||
private val transactionErrorDialogFactory: TransactionErrorDialogFactory = TransactionErrorDialogFactory(),
|
||||
) : Converter<SwapTransactionState.Error, DialogMessage?> {
|
||||
override fun convert(value: SwapTransactionState.Error): DialogMessage? {
|
||||
return when (value) {
|
||||
is SwapTransactionState.Error.TransactionError -> {
|
||||
when (val error = value.error) {
|
||||
is SendTransactionError.UserCancelledError -> return null
|
||||
null -> SwapAlertUM.GenericError(onDismiss)
|
||||
else -> TransactionErrorAlertConverter(onDismiss, onSupportClick).convert(error)
|
||||
null -> SwapAlertUM.genericError(onDismiss)
|
||||
else -> transactionErrorDialogFactory.create(error, onDismiss, onSupportClick)
|
||||
}
|
||||
}
|
||||
is SwapTransactionState.Error.ExpressError -> {
|
||||
SwapAlertUM.ExpressErrorAlert(
|
||||
SwapAlertUM.expressErrorAlert(
|
||||
message = getExpressErrorMessage(value.error),
|
||||
onConfirmClick = { onSupportClick(value.error.code.toString()) },
|
||||
)
|
||||
}
|
||||
SwapTransactionState.Error.UnknownError -> SwapAlertUM.GenericError(onDismiss)
|
||||
is SwapTransactionState.Error.TangemPayWithdrawalError -> SwapAlertUM.GenericError(
|
||||
SwapTransactionState.Error.UnknownError -> SwapAlertUM.genericError(onDismiss)
|
||||
is SwapTransactionState.Error.TangemPayWithdrawalError -> SwapAlertUM.genericError(
|
||||
onConfirmClick = { onSupportClick(value.txId) },
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,12 +24,22 @@ import com.tangem.core.analytics.models.event.SwapAnalyticsEvent
|
|||
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.ui.UiMessageSender
|
||||
import com.tangem.core.navigation.url.UrlOpener
|
||||
import com.tangem.core.ui.HoldToConfirmButtonFeatureToggles
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.combinedReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.extensions.toWrappedList
|
||||
import com.tangem.core.ui.extensions.wrappedList
|
||||
import com.tangem.core.ui.message.DialogMessage
|
||||
import com.tangem.core.ui.message.EventMessageAction
|
||||
import com.tangem.core.ui.utils.InputNumberFormatter
|
||||
import com.tangem.core.ui.utils.parseBigDecimal
|
||||
import com.tangem.feature.swap.converters.SwapTransactionErrorStateConverter
|
||||
import com.tangem.feature.swap.models.SwapAlertUM
|
||||
import com.tangem.datasource.local.appsflyer.AppsFlyerStore
|
||||
import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles
|
||||
import com.tangem.domain.account.status.model.AccountCryptoCurrencyStatus
|
||||
|
|
@ -162,6 +172,7 @@ internal class SwapModel @Inject constructor(
|
|||
private val getTangemPayCustomerIdUseCase: GetTangemPayCustomerIdUseCase,
|
||||
private val appsFlyerStore: AppsFlyerStore,
|
||||
private val holdToConfirmButtonFeatureToggles: HoldToConfirmButtonFeatureToggles,
|
||||
private val messageSender: UiMessageSender,
|
||||
) : Model() {
|
||||
|
||||
private val params = paramsContainer.require<SwapComponent.Params>()
|
||||
|
|
@ -342,7 +353,8 @@ internal class SwapModel @Inject constructor(
|
|||
}
|
||||
|
||||
if (fromAccountStatus == null) {
|
||||
uiState = stateBuilder.addAlert(uiState = uiState, onDismiss = swapRouter::back)
|
||||
showAlert()
|
||||
swapRouter.back()
|
||||
} else {
|
||||
fromAccountCurrencyStatus = fromAccountStatus
|
||||
toAccountCurrencyStatus = toAccountStatus
|
||||
|
|
@ -360,7 +372,8 @@ internal class SwapModel @Inject constructor(
|
|||
}
|
||||
|
||||
if (fromStatus == null) {
|
||||
uiState = stateBuilder.addAlert(uiState = uiState, onDismiss = swapRouter::back)
|
||||
showAlert()
|
||||
swapRouter.back()
|
||||
} else {
|
||||
initialFromStatus = fromStatus
|
||||
initialToStatus = toStatus
|
||||
|
|
@ -1027,7 +1040,7 @@ internal class SwapModel @Inject constructor(
|
|||
val fee = getSelectedFee()
|
||||
|
||||
if (fee == null && tangemPayInput?.isWithdrawal != true) {
|
||||
makeDefaultAlert(resourceReference(R.string.swapping_fee_estimation_error_text))
|
||||
showAlert(resourceReference(R.string.swapping_fee_estimation_error_text))
|
||||
modelScope.launch {
|
||||
delay(SWAP_IN_PROGRESS_DELAY)
|
||||
startLoadingQuotesFromLastState()
|
||||
|
|
@ -1053,7 +1066,7 @@ internal class SwapModel @Inject constructor(
|
|||
when (swapTransactionState) {
|
||||
is SwapTransactionState.TxSent -> {
|
||||
if (fee == null) {
|
||||
makeDefaultAlert(resourceReference(R.string.swapping_fee_estimation_error_text))
|
||||
showAlert(resourceReference(R.string.swapping_fee_estimation_error_text))
|
||||
return@onSuccess
|
||||
}
|
||||
sendSuccessSwapEvent(
|
||||
|
|
@ -1097,21 +1110,11 @@ internal class SwapModel @Inject constructor(
|
|||
swapRouter.openScreen(SwapNavScreen.Success)
|
||||
}
|
||||
SwapTransactionState.DemoMode -> {
|
||||
uiState = stateBuilder.createDemoModeAlert(
|
||||
uiState = uiState,
|
||||
onDismiss = { uiState = stateBuilder.clearAlert(uiState) },
|
||||
isReverseSwapPossible = isReverseSwapPossible(),
|
||||
)
|
||||
showDemoModeAlert()
|
||||
}
|
||||
is SwapTransactionState.Error -> {
|
||||
startLoadingQuotesFromLastState()
|
||||
uiState = stateBuilder.createErrorTransactionAlert(
|
||||
uiState = uiState,
|
||||
error = swapTransactionState,
|
||||
onDismiss = { uiState = stateBuilder.clearAlert(uiState) },
|
||||
onSupportClick = ::onFailedTxEmailClick,
|
||||
isReverseSwapPossible = isReverseSwapPossible(),
|
||||
)
|
||||
showTransactionErrorAlert(swapTransactionState)
|
||||
}
|
||||
is SwapTransactionState.TangemPayWithdrawalData -> {
|
||||
processTangemPayWithdrawal(swapTransactionState = swapTransactionState)
|
||||
|
|
@ -1120,7 +1123,7 @@ internal class SwapModel @Inject constructor(
|
|||
}.onFailure { error ->
|
||||
Timber.e(error)
|
||||
startLoadingQuotesFromLastState()
|
||||
makeDefaultAlert()
|
||||
showAlert()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1212,7 +1215,7 @@ internal class SwapModel @Inject constructor(
|
|||
}
|
||||
val feeForPermission = when (val fee = approveDataModel.fee) {
|
||||
TxFeeState.Empty -> {
|
||||
makeDefaultAlert(resourceReference(R.string.swapping_fee_estimation_error_text))
|
||||
showAlert(resourceReference(R.string.swapping_fee_estimation_error_text))
|
||||
Timber.e("Fee should not be Empty")
|
||||
return@launch
|
||||
}
|
||||
|
|
@ -1242,29 +1245,19 @@ internal class SwapModel @Inject constructor(
|
|||
startLoadingQuotesFromLastState(isSilent = true)
|
||||
}
|
||||
is SwapTransactionState.Error -> {
|
||||
uiState = stateBuilder.createErrorTransactionAlert(
|
||||
uiState = uiState,
|
||||
error = swapTransactionState,
|
||||
onDismiss = { uiState = stateBuilder.clearAlert(uiState) },
|
||||
onSupportClick = ::onFailedTxEmailClick,
|
||||
isReverseSwapPossible = isReverseSwapPossible(),
|
||||
)
|
||||
showTransactionErrorAlert(swapTransactionState)
|
||||
}
|
||||
SwapTransactionState.DemoMode -> {
|
||||
uiState = stateBuilder.createDemoModeAlert(
|
||||
uiState = uiState,
|
||||
onDismiss = { uiState = stateBuilder.clearAlert(uiState) },
|
||||
isReverseSwapPossible = isReverseSwapPossible(),
|
||||
)
|
||||
showDemoModeAlert()
|
||||
}
|
||||
is SwapTransactionState.TangemPayWithdrawalData -> {
|
||||
processTangemPayWithdrawal(swapTransactionState = swapTransactionState)
|
||||
}
|
||||
}
|
||||
}.onFailure { makeDefaultAlert() }
|
||||
}.onFailure { showAlert() }
|
||||
}.onFailure { error ->
|
||||
Timber.e(error.message.orEmpty())
|
||||
makeDefaultAlert()
|
||||
showAlert()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1654,12 +1647,94 @@ internal class SwapModel @Inject constructor(
|
|||
return inputNumberFormatter.getValidatedNumberWithFixedDecimals(amount, maxDecimals)
|
||||
}
|
||||
|
||||
private fun makeDefaultAlert() {
|
||||
uiState = stateBuilder.addAlert(uiState)
|
||||
private fun showAlert(message: TextReference = resourceReference(R.string.common_unknown_error)) {
|
||||
messageSender.send(SwapAlertUM.genericError(onConfirmClick = { }, message = message))
|
||||
}
|
||||
|
||||
private fun makeDefaultAlert(message: TextReference) {
|
||||
uiState = stateBuilder.addAlert(uiState, message)
|
||||
private fun showDemoModeAlert() {
|
||||
messageSender.send(
|
||||
DialogMessage(
|
||||
title = resourceReference(id = R.string.warning_demo_mode_title),
|
||||
message = resourceReference(id = R.string.warning_demo_mode_message),
|
||||
firstAction = EventMessageAction(
|
||||
title = resourceReference(id = R.string.common_ok),
|
||||
onClick = {},
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun showTransactionErrorAlert(
|
||||
error: SwapTransactionState.Error,
|
||||
onSupportClick: (String) -> Unit = ::onFailedTxEmailClick,
|
||||
) {
|
||||
val errorAlert = SwapTransactionErrorStateConverter(
|
||||
onDismiss = {},
|
||||
onSupportClick = onSupportClick,
|
||||
).convert(error)
|
||||
errorAlert?.let { messageSender.send(it) }
|
||||
}
|
||||
|
||||
private fun onTangemPaySupportClick(txId: String) {
|
||||
modelScope.launch {
|
||||
val metaInfo = getWalletMetaInfoUseCase(userWallet.walletId).getOrNull() ?: return@launch
|
||||
val customerId = getTangemPayCustomerIdUseCase(userWallet.walletId).getOrNull().orEmpty()
|
||||
val email = FeedbackEmailType.Visa.Withdrawal(
|
||||
walletMetaInfo = metaInfo,
|
||||
customerId = customerId,
|
||||
providerName = dataState.selectedProvider?.name.orEmpty(),
|
||||
txId = txId,
|
||||
)
|
||||
sendFeedbackEmailUseCase(email)
|
||||
}
|
||||
}
|
||||
|
||||
private fun showSwapInfoAlert(isPriceImpact: Boolean, token: String, provider: SwapProvider) {
|
||||
messageSender.send(
|
||||
SwapAlertUM.informationAlert(
|
||||
message = buildSwapInfoMessage(isPriceImpact, token, provider),
|
||||
onConfirmClick = {},
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun buildSwapInfoMessage(isPriceImpact: Boolean, token: String, provider: SwapProvider): TextReference {
|
||||
val slippage = provider.slippage?.let { "${it.parseBigDecimal(1)}%" }
|
||||
val messages = buildList {
|
||||
when (provider.type) {
|
||||
ExchangeProviderType.CEX -> {
|
||||
if (slippage != null) {
|
||||
add(
|
||||
resourceReference(
|
||||
id = R.string.swapping_alert_cex_description_with_slippage,
|
||||
formatArgs = wrappedList(token, slippage),
|
||||
),
|
||||
)
|
||||
} else {
|
||||
add(resourceReference(R.string.swapping_alert_cex_description, wrappedList(token)))
|
||||
}
|
||||
}
|
||||
ExchangeProviderType.DEX,
|
||||
ExchangeProviderType.DEX_BRIDGE,
|
||||
-> {
|
||||
if (isPriceImpact) {
|
||||
add(resourceReference(R.string.swapping_high_price_impact_description))
|
||||
add(stringReference("\n\n"))
|
||||
}
|
||||
if (slippage != null) {
|
||||
add(
|
||||
resourceReference(
|
||||
id = R.string.swapping_alert_dex_description_with_slippage,
|
||||
formatArgs = wrappedList(slippage),
|
||||
),
|
||||
)
|
||||
} else {
|
||||
add(resourceReference(R.string.swapping_alert_dex_description, wrappedList(token)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return combinedReference(messages.toWrappedList())
|
||||
}
|
||||
|
||||
@Suppress("LongMethod", "CyclomaticComplexMethod")
|
||||
|
|
@ -1779,14 +1854,7 @@ internal class SwapModel @Inject constructor(
|
|||
val selectedProvider = dataState.selectedProvider ?: return@UiActions
|
||||
val currencySymbol = dataState.toCryptoCurrency?.currency?.symbol ?: return@UiActions
|
||||
val isPriceImpact = uiState.priceImpact is PriceImpact.Value
|
||||
uiState = stateBuilder.createAlert(
|
||||
uiState = uiState,
|
||||
isPriceImpact = isPriceImpact,
|
||||
token = currencySymbol,
|
||||
provider = selectedProvider,
|
||||
isReverseSwapPossible = isReverseSwapPossible(),
|
||||
onDismiss = { uiState = stateBuilder.clearAlert(uiState) },
|
||||
)
|
||||
showSwapInfoAlert(isPriceImpact, currencySymbol, selectedProvider)
|
||||
},
|
||||
onLinkClick = urlOpener::openUrl,
|
||||
onSelectTokenClick = {
|
||||
|
|
@ -2092,31 +2160,12 @@ internal class SwapModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun onTangemPayWithdrawalError(txId: String?) {
|
||||
uiState = stateBuilder.createErrorTransactionAlert(
|
||||
uiState = uiState,
|
||||
showTransactionErrorAlert(
|
||||
error = SwapTransactionState.Error.TangemPayWithdrawalError(txId.orEmpty()),
|
||||
onDismiss = { uiState = stateBuilder.clearAlert(uiState) },
|
||||
onSupportClick = {
|
||||
val customerId = getTangemPayCustomerIdUseCase(userWallet.walletId).getOrNull() ?: "Unknown"
|
||||
onTangemPaySupportClick(customerId = customerId, txId = txId)
|
||||
},
|
||||
isReverseSwapPossible = isReverseSwapPossible(),
|
||||
onSupportClick = ::onTangemPaySupportClick,
|
||||
)
|
||||
}
|
||||
|
||||
private fun onTangemPaySupportClick(customerId: String, txId: String?) {
|
||||
modelScope.launch {
|
||||
val metaInfo = getWalletMetaInfoUseCase(userWallet.walletId).getOrNull() ?: return@launch
|
||||
val email = FeedbackEmailType.Visa.Withdrawal(
|
||||
walletMetaInfo = metaInfo,
|
||||
customerId = customerId,
|
||||
providerName = dataState.selectedProvider?.name.orEmpty(),
|
||||
txId = txId.orEmpty(),
|
||||
)
|
||||
sendFeedbackEmailUseCase(email)
|
||||
}
|
||||
}
|
||||
|
||||
private fun onFailedTxEmailClick(errorMessage: String) {
|
||||
modelScope.launch {
|
||||
val transaction = dataState.swapDataModel?.transaction
|
||||
|
|
|
|||
|
|
@ -1,38 +1,43 @@
|
|||
package com.tangem.feature.swap.models
|
||||
|
||||
import com.tangem.common.ui.alerts.models.AlertUM
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.message.DialogMessage
|
||||
import com.tangem.core.ui.message.EventMessageAction
|
||||
|
||||
sealed class SwapAlertUM : AlertUM {
|
||||
internal object SwapAlertUM {
|
||||
|
||||
data class GenericError(
|
||||
override val onConfirmClick: (() -> Unit),
|
||||
override val message: TextReference = resourceReference(R.string.common_unknown_error),
|
||||
) : SwapAlertUM() {
|
||||
override val title: TextReference? = null
|
||||
override val confirmButtonText: TextReference =
|
||||
resourceReference(id = R.string.common_support)
|
||||
}
|
||||
fun genericError(
|
||||
onConfirmClick: () -> Unit,
|
||||
message: TextReference = resourceReference(R.string.common_unknown_error),
|
||||
): DialogMessage = DialogMessage(
|
||||
title = null,
|
||||
message = message,
|
||||
firstAction = EventMessageAction(
|
||||
title = resourceReference(id = R.string.common_support),
|
||||
onClick = onConfirmClick,
|
||||
),
|
||||
)
|
||||
|
||||
data class ExpressErrorAlert(
|
||||
override val message: TextReference = resourceReference(R.string.common_unknown_error),
|
||||
override val onConfirmClick: (() -> Unit),
|
||||
) : SwapAlertUM() {
|
||||
override val title: TextReference? = null
|
||||
override val confirmButtonText: TextReference =
|
||||
resourceReference(id = R.string.common_support)
|
||||
}
|
||||
fun expressErrorAlert(
|
||||
message: TextReference = resourceReference(R.string.common_unknown_error),
|
||||
onConfirmClick: () -> Unit,
|
||||
): DialogMessage = DialogMessage(
|
||||
title = null,
|
||||
message = message,
|
||||
firstAction = EventMessageAction(
|
||||
title = resourceReference(id = R.string.common_support),
|
||||
onClick = onConfirmClick,
|
||||
),
|
||||
)
|
||||
|
||||
data class InformationAlert(
|
||||
override val message: TextReference,
|
||||
override val onConfirmClick: (() -> Unit),
|
||||
) : SwapAlertUM() {
|
||||
override val title: TextReference = resourceReference(
|
||||
R.string.swapping_alert_title,
|
||||
)
|
||||
override val confirmButtonText: TextReference =
|
||||
resourceReference(id = R.string.common_ok)
|
||||
}
|
||||
fun informationAlert(message: TextReference, onConfirmClick: () -> Unit): DialogMessage = DialogMessage(
|
||||
title = resourceReference(R.string.swapping_alert_title),
|
||||
message = message,
|
||||
firstAction = EventMessageAction(
|
||||
title = resourceReference(id = R.string.common_ok),
|
||||
onClick = onConfirmClick,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -7,14 +7,11 @@ import com.tangem.common.ui.bottomsheet.permission.state.GiveTxPermissionState
|
|||
import com.tangem.common.ui.notifications.NotificationUM
|
||||
import com.tangem.common.ui.swapStoriesScreen.SwapStoriesUM
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.core.ui.event.StateEvent
|
||||
import com.tangem.core.ui.event.consumedEvent
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.feature.swap.domain.models.ui.PriceImpact
|
||||
import com.tangem.feature.swap.models.states.FeeItemState
|
||||
import com.tangem.feature.swap.models.states.ProviderState
|
||||
import com.tangem.feature.swap.models.states.events.SwapEvent
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
|
|
@ -24,7 +21,6 @@ internal data class SwapStateHolder(
|
|||
val blockchainId: String, // not the same as networkId, its local id in app
|
||||
val notifications: ImmutableList<NotificationUM> = persistentListOf(),
|
||||
val isInsufficientFunds: Boolean,
|
||||
val event: StateEvent<SwapEvent> = consumedEvent(),
|
||||
val changeCardsButtonState: ChangeCardsButtonState,
|
||||
val providerState: ProviderState,
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +0,0 @@
|
|||
package com.tangem.feature.swap.models.states.events
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import com.tangem.common.ui.alerts.models.AlertUM
|
||||
|
||||
@Immutable
|
||||
internal sealed class SwapEvent {
|
||||
data class ShowAlert(val alert: AlertUM) : SwapEvent()
|
||||
}
|
||||
|
|
@ -5,21 +5,17 @@ import androidx.compose.ui.text.input.TextFieldValue
|
|||
import com.tangem.common.ui.account.AccountTitleUM
|
||||
import com.tangem.common.ui.account.CryptoPortfolioIconConverter
|
||||
import com.tangem.common.ui.account.toUM
|
||||
import com.tangem.common.ui.alerts.models.AlertDemoModeUM
|
||||
import com.tangem.common.ui.bottomsheet.permission.state.*
|
||||
import com.tangem.common.ui.notifications.NotificationUM
|
||||
import com.tangem.common.ui.swapStoriesScreen.SwapStoriesFactory
|
||||
import com.tangem.common.ui.userwallet.ext.walletInterationIcon
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
|
||||
import com.tangem.core.ui.components.currency.icon.converter.CryptoCurrencyToIconStateConverter
|
||||
import com.tangem.core.ui.event.consumedEvent
|
||||
import com.tangem.core.ui.event.triggeredEvent
|
||||
import com.tangem.core.ui.extensions.*
|
||||
import com.tangem.core.ui.format.bigdecimal.anyDecimals
|
||||
import com.tangem.core.ui.format.bigdecimal.crypto
|
||||
import com.tangem.core.ui.format.bigdecimal.fiat
|
||||
import com.tangem.core.ui.format.bigdecimal.format
|
||||
import com.tangem.core.ui.utils.parseBigDecimal
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.models.account.Account
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
|
|
@ -29,7 +25,6 @@ import com.tangem.domain.models.wallet.UserWallet
|
|||
import com.tangem.domain.models.wallet.isHotWallet
|
||||
import com.tangem.domain.promo.models.StoryContent
|
||||
import com.tangem.domain.transaction.usecase.gasless.IsGaslessFeeSupportedForNetwork
|
||||
import com.tangem.feature.swap.converters.SwapTransactionErrorStateConverter
|
||||
import com.tangem.feature.swap.converters.TokensDataConverter
|
||||
import com.tangem.feature.swap.converters.TokensDataConverterV2
|
||||
import com.tangem.feature.swap.domain.models.ExpressDataError
|
||||
|
|
@ -43,12 +38,10 @@ import com.tangem.feature.swap.model.SwapNotificationsFactory
|
|||
import com.tangem.feature.swap.model.SwapProcessDataState
|
||||
import com.tangem.feature.swap.models.*
|
||||
import com.tangem.feature.swap.models.states.*
|
||||
import com.tangem.feature.swap.models.states.events.SwapEvent
|
||||
import com.tangem.feature.swap.presentation.R
|
||||
import com.tangem.feature.swap.utils.formatToUIRepresentation
|
||||
import com.tangem.utils.Provider
|
||||
import com.tangem.utils.StringsSigns.DASH_SIGN
|
||||
import com.tangem.utils.StringsSigns.PERCENT
|
||||
import com.tangem.utils.StringsSigns.TILDE_SIGN
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
|
@ -972,117 +965,6 @@ internal class StateBuilder(
|
|||
)
|
||||
}
|
||||
|
||||
fun createErrorTransactionAlert(
|
||||
uiState: SwapStateHolder,
|
||||
error: SwapTransactionState.Error,
|
||||
onDismiss: () -> Unit,
|
||||
onSupportClick: (String) -> Unit,
|
||||
isReverseSwapPossible: Boolean,
|
||||
): SwapStateHolder {
|
||||
val errorAlert = SwapTransactionErrorStateConverter(
|
||||
onSupportClick = onSupportClick,
|
||||
onDismiss = onDismiss,
|
||||
).convert(error)
|
||||
return uiState.copy(
|
||||
event = errorAlert?.let {
|
||||
triggeredEvent(
|
||||
data = SwapEvent.ShowAlert(errorAlert),
|
||||
onConsume = onDismiss,
|
||||
)
|
||||
} ?: consumedEvent(),
|
||||
changeCardsButtonState = getChangeCardsButtonState(isReverseSwapPossible),
|
||||
)
|
||||
}
|
||||
|
||||
fun createDemoModeAlert(
|
||||
uiState: SwapStateHolder,
|
||||
onDismiss: () -> Unit,
|
||||
isReverseSwapPossible: Boolean,
|
||||
): SwapStateHolder {
|
||||
return uiState.copy(
|
||||
event = triggeredEvent(
|
||||
data = SwapEvent.ShowAlert(AlertDemoModeUM(onDismiss)),
|
||||
onConsume = onDismiss,
|
||||
),
|
||||
changeCardsButtonState = getChangeCardsButtonState(isReverseSwapPossible),
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
fun createAlert(
|
||||
uiState: SwapStateHolder,
|
||||
isPriceImpact: Boolean,
|
||||
token: String,
|
||||
provider: SwapProvider,
|
||||
onDismiss: () -> Unit,
|
||||
isReverseSwapPossible: Boolean,
|
||||
): SwapStateHolder {
|
||||
val slippage = provider.slippage?.let { "${it.parseBigDecimal(1)}$PERCENT" }
|
||||
val combinedMessage = buildList {
|
||||
when (provider.type) {
|
||||
ExchangeProviderType.CEX -> {
|
||||
if (slippage != null) {
|
||||
add(
|
||||
resourceReference(
|
||||
id = R.string.swapping_alert_cex_description_with_slippage,
|
||||
formatArgs = wrappedList(token, slippage),
|
||||
),
|
||||
)
|
||||
} else {
|
||||
add(resourceReference(R.string.swapping_alert_cex_description, wrappedList(token)))
|
||||
}
|
||||
}
|
||||
ExchangeProviderType.DEX,
|
||||
ExchangeProviderType.DEX_BRIDGE,
|
||||
-> {
|
||||
if (isPriceImpact) {
|
||||
add(resourceReference(R.string.swapping_high_price_impact_description))
|
||||
add(stringReference("\n\n"))
|
||||
}
|
||||
if (slippage != null) {
|
||||
add(
|
||||
resourceReference(
|
||||
id = R.string.swapping_alert_dex_description_with_slippage,
|
||||
formatArgs = wrappedList(slippage),
|
||||
),
|
||||
)
|
||||
} else {
|
||||
add(resourceReference(R.string.swapping_alert_dex_description, wrappedList(token)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return uiState.copy(
|
||||
event = triggeredEvent(
|
||||
SwapEvent.ShowAlert(
|
||||
SwapAlertUM.InformationAlert(
|
||||
message = combinedReference(combinedMessage.toWrappedList()),
|
||||
onConfirmClick = onDismiss,
|
||||
),
|
||||
),
|
||||
onConsume = onDismiss,
|
||||
),
|
||||
changeCardsButtonState = getChangeCardsButtonState(isReverseSwapPossible),
|
||||
)
|
||||
}
|
||||
|
||||
fun addAlert(
|
||||
uiState: SwapStateHolder,
|
||||
message: TextReference = resourceReference(R.string.common_unknown_error),
|
||||
onDismiss: () -> Unit = { clearAlert(uiState) },
|
||||
): SwapStateHolder {
|
||||
return uiState.copy(
|
||||
event = triggeredEvent(
|
||||
SwapEvent.ShowAlert(
|
||||
SwapAlertUM.GenericError(onDismiss, message),
|
||||
),
|
||||
onConsume = onDismiss,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
fun clearAlert(uiState: SwapStateHolder): SwapStateHolder = uiState.copy(event = consumedEvent())
|
||||
|
||||
fun addNotification(uiState: SwapStateHolder, message: TextReference?, onClick: () -> Unit): SwapStateHolder {
|
||||
return uiState.copy(
|
||||
notifications = notificationsFactory.getGeneralErrorStateNotifications(
|
||||
|
|
|
|||
|
|
@ -1,61 +0,0 @@
|
|||
package com.tangem.feature.swap.ui
|
||||
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
|
||||
import com.tangem.common.ui.alerts.models.AlertUM
|
||||
import com.tangem.core.ui.components.BasicDialog
|
||||
import com.tangem.core.ui.components.DialogButtonUM
|
||||
import com.tangem.core.ui.event.EventEffect
|
||||
import com.tangem.core.ui.event.StateEvent
|
||||
import com.tangem.core.ui.extensions.resolveReference
|
||||
import com.tangem.core.ui.extensions.stringResourceSafe
|
||||
import com.tangem.feature.swap.models.states.events.SwapEvent
|
||||
import com.tangem.feature.swap.presentation.R
|
||||
|
||||
@Composable
|
||||
internal fun SwapEventEffect(event: StateEvent<SwapEvent>) {
|
||||
var alertConfig by remember { mutableStateOf<AlertUM?>(value = null) }
|
||||
|
||||
val keyboardController = LocalSoftwareKeyboardController.current
|
||||
LaunchedEffect(key1 = alertConfig) {
|
||||
keyboardController?.hide()
|
||||
}
|
||||
|
||||
alertConfig?.let {
|
||||
SwapAlert(state = it, onDismiss = { alertConfig = null })
|
||||
}
|
||||
|
||||
EventEffect(
|
||||
event = event,
|
||||
onTrigger = { value ->
|
||||
when (value) {
|
||||
is SwapEvent.ShowAlert -> {
|
||||
alertConfig = value.alert
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun SwapAlert(state: AlertUM, onDismiss: () -> Unit) {
|
||||
val confirmButton = DialogButtonUM(
|
||||
title = state.confirmButtonText.resolveReference(),
|
||||
onClick = {
|
||||
state.onConfirmClick?.invoke()
|
||||
onDismiss()
|
||||
},
|
||||
)
|
||||
val dismissButton = DialogButtonUM(
|
||||
title = stringResourceSafe(id = R.string.common_cancel),
|
||||
onClick = onDismiss,
|
||||
)
|
||||
|
||||
BasicDialog(
|
||||
message = state.message.resolveReference(),
|
||||
confirmButton = confirmButton,
|
||||
onDismissDialog = onDismiss,
|
||||
title = state.title?.resolveReference(),
|
||||
dismissButton = dismissButton,
|
||||
)
|
||||
}
|
||||
|
|
@ -117,10 +117,6 @@ internal fun SwapScreenContent(
|
|||
textAlign = TextAlign.Start,
|
||||
)
|
||||
}
|
||||
|
||||
SwapEventEffect(
|
||||
event = state.event,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue