Updated on 2026-08-14

This commit is contained in:
Tangem 2025-11-14 16:52:26 +04:00
parent 7975a65e30
commit 361b6c05b6
4 changed files with 55 additions and 48 deletions

View file

@ -223,19 +223,7 @@ internal class SwapModel @Inject constructor(
initTokens(isInitiallyReversed)
}
} else {
val fromStatus = if (tangemPayInput != null) {
getTangemPayCurrencyStatusUseCase(
currency = initialCurrencyFrom,
cryptoAmount = tangemPayInput.cryptoAmount,
fiatAmount = tangemPayInput.fiatAmount,
depositAddress = tangemPayInput.depositAddress,
)
} else {
getSingleCryptoCurrencyStatusUseCase.invokeMultiWalletSync(
userWalletId = userWalletId,
cryptoCurrencyId = initialCurrencyFrom.id,
).getOrNull()
}
val fromStatus = getFromStatus()
val toStatus = initialCurrencyTo?.let {
getSingleCryptoCurrencyStatusUseCase.invokeMultiWalletSync(
userWalletId = userWalletId,
@ -567,7 +555,6 @@ internal class SwapModel @Inject constructor(
selectedFeeType = dataState.selectedFee?.feeType ?: FeeType.NORMAL,
isReverseSwapPossible = isReverseSwapPossible(),
needApplyFCARestrictions = userCountry.needApplyFCARestrictions(),
isForTangemPaySwap = tangemPayInput != null,
)
if (uiState.notifications.any { it is SwapNotificationUM.Error.UnableToCoverFeeWarning }) {
analyticsEventHandler.send(
@ -587,7 +574,6 @@ internal class SwapModel @Inject constructor(
toTokenStatus = toTokenStatus,
isReverseSwapPossible = isReverseSwapPossible(),
toAccount = dataState.toAccount,
isForTangemPaySwap = tangemPayInput != null,
)
}
is SwapState.SwapError -> {
@ -602,7 +588,6 @@ internal class SwapModel @Inject constructor(
isReverseSwapPossible = isReverseSwapPossible(),
needApplyFCARestrictions = userCountry.needApplyFCARestrictions(),
toAccount = dataState.toAccount,
isForTangemPaySwap = tangemPayInput != null,
)
sendErrorAnalyticsEvent(state.error, provider)
}
@ -776,9 +761,11 @@ internal class SwapModel @Inject constructor(
swapRouter.openScreen(SwapNavScreen.Success)
}
SwapTransactionState.DemoMode -> {
uiState = stateBuilder.createDemoModeAlert(uiState) {
uiState = stateBuilder.clearAlert(uiState)
}
uiState = stateBuilder.createDemoModeAlert(
uiState = uiState,
onDismiss = { uiState = stateBuilder.clearAlert(uiState) },
isReverseSwapPossible = isReverseSwapPossible(),
)
}
is SwapTransactionState.Error -> {
startLoadingQuotesFromLastState()
@ -787,6 +774,7 @@ internal class SwapModel @Inject constructor(
error = it,
onDismiss = { uiState = stateBuilder.clearAlert(uiState) },
onSupportClick = ::onFailedTxEmailClick,
isReverseSwapPossible = isReverseSwapPossible(),
)
}
}
@ -867,12 +855,15 @@ internal class SwapModel @Inject constructor(
error = it,
onDismiss = { uiState = stateBuilder.clearAlert(uiState) },
onSupportClick = ::onFailedTxEmailClick,
isReverseSwapPossible = isReverseSwapPossible(),
)
}
SwapTransactionState.DemoMode -> {
uiState = stateBuilder.createDemoModeAlert(uiState) {
uiState = stateBuilder.clearAlert(uiState)
}
uiState = stateBuilder.createDemoModeAlert(
uiState = uiState,
onDismiss = { uiState = stateBuilder.clearAlert(uiState) },
isReverseSwapPossible = isReverseSwapPossible(),
)
}
}
}.onFailure { makeDefaultAlert() }
@ -1354,9 +1345,9 @@ internal class SwapModel @Inject constructor(
isPriceImpact = isPriceImpact,
token = currencySymbol,
provider = selectedProvider,
) {
uiState = stateBuilder.clearAlert(uiState)
}
isReverseSwapPossible = isReverseSwapPossible(),
onDismiss = { uiState = stateBuilder.clearAlert(uiState) },
)
},
onLinkClick = urlOpener::openUrl,
onSelectTokenClick = {
@ -1499,6 +1490,7 @@ internal class SwapModel @Inject constructor(
}
private fun isReverseSwapPossible(): Boolean {
if (tangemPayInput != null) return false
val from = dataState.fromCryptoCurrency ?: return false
val to = dataState.toCryptoCurrency ?: return false
@ -1611,6 +1603,22 @@ internal class SwapModel @Inject constructor(
)
}
private suspend fun getFromStatus(): CryptoCurrencyStatus? {
return if (tangemPayInput != null) {
getTangemPayCurrencyStatusUseCase(
currency = initialCurrencyFrom,
cryptoAmount = tangemPayInput.cryptoAmount,
fiatAmount = tangemPayInput.fiatAmount,
depositAddress = tangemPayInput.depositAddress,
)
} else {
getSingleCryptoCurrencyStatusUseCase.invokeMultiWalletSync(
userWalletId = userWalletId,
cryptoCurrencyId = initialCurrencyFrom.id,
).getOrNull()
}
}
private companion object {
const val INITIAL_AMOUNT = ""
const val UPDATE_DELAY = 10000L

View file

@ -25,7 +25,7 @@ internal data class SwapStateHolder(
val notifications: ImmutableList<NotificationUM> = persistentListOf(),
val isInsufficientFunds: Boolean,
val event: StateEvent<SwapEvent> = consumedEvent(),
val changeCardsButtonState: ChangeCardsButtonState = ChangeCardsButtonState.ENABLED,
val changeCardsButtonState: ChangeCardsButtonState,
val providerState: ProviderState,
val fee: FeeItemState = FeeItemState.Empty,

View file

@ -277,7 +277,6 @@ internal class StateBuilder(
selectedFeeType: FeeType,
isReverseSwapPossible: Boolean,
needApplyFCARestrictions: Boolean,
isForTangemPaySwap: Boolean,
): SwapStateHolder {
if (uiStateHolder.sendCardData !is SwapCardState.SwapCardData) return uiStateHolder
if (uiStateHolder.receiveCardData !is SwapCardState.SwapCardData) return uiStateHolder
@ -370,11 +369,7 @@ internal class StateBuilder(
enabled = getSwapButtonEnabled(notifications),
onClick = actions.onSwapClick,
),
changeCardsButtonState = if (isReverseSwapPossible && !isForTangemPaySwap) {
ChangeCardsButtonState.ENABLED
} else {
ChangeCardsButtonState.DISABLED
},
changeCardsButtonState = getChangeCardsButtonState(isReverseSwapPossible),
providerState = swapProvider.convertToContentClickableProviderState(
isBestRate = bestRatedProviderId == swapProvider.providerId,
fromTokenInfo = quoteModel.fromTokenInfo,
@ -443,7 +438,6 @@ internal class StateBuilder(
expressDataError: ExpressDataError,
isReverseSwapPossible: Boolean,
needApplyFCARestrictions: Boolean,
isForTangemPaySwap: Boolean,
): SwapStateHolder {
if (uiStateHolder.sendCardData !is SwapCardState.SwapCardData) return uiStateHolder
if (uiStateHolder.receiveCardData !is SwapCardState.SwapCardData) return uiStateHolder
@ -502,11 +496,7 @@ internal class StateBuilder(
enabled = false,
onClick = actions.onSwapClick,
),
changeCardsButtonState = if (isReverseSwapPossible && !isForTangemPaySwap) {
ChangeCardsButtonState.ENABLED
} else {
ChangeCardsButtonState.DISABLED
},
changeCardsButtonState = getChangeCardsButtonState(isReverseSwapPossible),
providerState = providerState,
priceImpact = PriceImpact.Empty(),
tosState = createTosState(swapProvider),
@ -561,7 +551,6 @@ internal class StateBuilder(
toTokenStatus: CryptoCurrencyStatus?,
toAccount: Account.CryptoPortfolio?,
isReverseSwapPossible: Boolean,
isForTangemPaySwap: Boolean,
): SwapStateHolder {
if (uiStateHolder.sendCardData !is SwapCardState.SwapCardData) return uiStateHolder
if (uiStateHolder.receiveCardData !is SwapCardState.SwapCardData) return uiStateHolder
@ -604,11 +593,7 @@ internal class StateBuilder(
enabled = false,
onClick = { },
),
changeCardsButtonState = if (isReverseSwapPossible && !isForTangemPaySwap) {
ChangeCardsButtonState.ENABLED
} else {
ChangeCardsButtonState.DISABLED
},
changeCardsButtonState = getChangeCardsButtonState(isReverseSwapPossible),
providerState = ProviderState.Empty(),
priceImpact = PriceImpact.Empty(),
)
@ -873,6 +858,7 @@ internal class StateBuilder(
error: SwapTransactionState.Error,
onDismiss: () -> Unit,
onSupportClick: (String) -> Unit,
isReverseSwapPossible: Boolean,
): SwapStateHolder {
val errorAlert = SwapTransactionErrorStateConverter(
onSupportClick = onSupportClick,
@ -885,26 +871,32 @@ internal class StateBuilder(
onConsume = onDismiss,
)
} ?: consumedEvent(),
changeCardsButtonState = ChangeCardsButtonState.ENABLED,
changeCardsButtonState = getChangeCardsButtonState(isReverseSwapPossible),
)
}
fun createDemoModeAlert(uiState: SwapStateHolder, onDismiss: () -> Unit): SwapStateHolder {
fun createDemoModeAlert(
uiState: SwapStateHolder,
onDismiss: () -> Unit,
isReverseSwapPossible: Boolean,
): SwapStateHolder {
return uiState.copy(
event = triggeredEvent(
data = SwapEvent.ShowAlert(AlertDemoModeUM(onDismiss)),
onConsume = onDismiss,
),
changeCardsButtonState = ChangeCardsButtonState.ENABLED,
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 {
@ -951,7 +943,7 @@ internal class StateBuilder(
),
onConsume = onDismiss,
),
changeCardsButtonState = ChangeCardsButtonState.ENABLED,
changeCardsButtonState = getChangeCardsButtonState(isReverseSwapPossible),
)
}
@ -1396,6 +1388,12 @@ internal class StateBuilder(
}
}
private fun getChangeCardsButtonState(isReverseSwapPossible: Boolean) = if (isReverseSwapPossible) {
ChangeCardsButtonState.ENABLED
} else {
ChangeCardsButtonState.DISABLED
}
private companion object {
private const val RU_LOCALE = "ru"
private const val EN_LOCALE = "en"

View file

@ -461,6 +461,7 @@ private val state = SwapStateHolder(
onClick = {},
),
),
changeCardsButtonState = ChangeCardsButtonState.ENABLED,
)
@Preview(widthDp = 360, showBackground = true)