Updated on 2026-08-14
This commit is contained in:
parent
d0d9fcfef8
commit
d772beda45
11 changed files with 90 additions and 41 deletions
|
|
@ -4,6 +4,7 @@ import com.tangem.common.ui.bottomsheet.permission.state.ApproveType
|
|||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.feature.swap.domain.models.SwapAmount
|
||||
import com.tangem.feature.swap.domain.models.ui.TxFee
|
||||
import java.math.BigDecimal
|
||||
|
||||
data class UiActions(
|
||||
val onSearchEntered: (String) -> Unit,
|
||||
|
|
@ -15,8 +16,8 @@ data class UiActions(
|
|||
val onChangeCardsClicked: () -> Unit,
|
||||
val onBackClicked: () -> Unit,
|
||||
val onMaxAmountSelected: () -> Unit,
|
||||
val onReduceAmount: (SwapAmount) -> Unit,
|
||||
val onLeaveExistentialDeposit: (SwapAmount) -> Unit,
|
||||
val onReduceToAmount: (SwapAmount) -> Unit,
|
||||
val onReduceByAmount: (SwapAmount, reduceBy: BigDecimal) -> Unit,
|
||||
val openPermissionBottomSheet: () -> Unit,
|
||||
val onChangeApproveType: (ApproveType) -> Unit,
|
||||
// region new actions
|
||||
|
|
|
|||
|
|
@ -134,10 +134,11 @@ internal class SwapNotificationsFactory(
|
|||
) {
|
||||
val fromCurrencyStatus = quoteModel.fromTokenInfo.cryptoCurrencyStatus
|
||||
val includeFeeInAmount = quoteModel.preparedSwapConfigState.includeFeeInAmount
|
||||
val amount = quoteModel.fromTokenInfo.tokenAmount
|
||||
val amountToRequest = if (includeFeeInAmount is IncludeFeeInAmount.Included) {
|
||||
includeFeeInAmount.amountSubtractFee
|
||||
} else {
|
||||
quoteModel.fromTokenInfo.tokenAmount
|
||||
amount
|
||||
}
|
||||
val fee = when (val feeState = quoteModel.txFee) {
|
||||
TxFeeState.Empty -> null
|
||||
|
|
@ -154,13 +155,12 @@ internal class SwapNotificationsFactory(
|
|||
addExistentialWarningNotification(
|
||||
existentialDeposit = quoteModel.currencyCheck?.existentialDeposit,
|
||||
feeAmount = fee?.feeValue.orZero(),
|
||||
receivedAmount = amountToRequest.value,
|
||||
sendingAmount = amount.value,
|
||||
cryptoCurrencyStatus = fromCurrencyStatus,
|
||||
onReduceClick = { _, reduceByDiff, _ ->
|
||||
actions.onLeaveExistentialDeposit(
|
||||
amountToRequest.copy(
|
||||
value = amountToRequest.value.minus(reduceByDiff).minus(fee?.feeValue.orZero()),
|
||||
),
|
||||
onReduceClick = { reduceBy, reduceByDiff, _ ->
|
||||
actions.onReduceByAmount(
|
||||
amount.copy(value = amount.value.minus(reduceByDiff)),
|
||||
reduceBy,
|
||||
)
|
||||
},
|
||||
)
|
||||
|
|
@ -170,7 +170,7 @@ internal class SwapNotificationsFactory(
|
|||
cryptoCurrency = fromCurrencyStatus.currency,
|
||||
minAdaValue = quoteModel.minAdaValue,
|
||||
onReduceClick = { reduceTo, _ ->
|
||||
actions.onLeaveExistentialDeposit(amountToRequest.copy(value = reduceTo))
|
||||
actions.onReduceToAmount(amount.copy(value = reduceTo))
|
||||
},
|
||||
)
|
||||
if (!isCardano) {
|
||||
|
|
@ -191,13 +191,13 @@ internal class SwapNotificationsFactory(
|
|||
addReduceAmountNotification(
|
||||
cryptoCurrencyStatus = fromCurrencyStatus,
|
||||
fromAmount = quoteModel.fromTokenInfo.tokenAmount,
|
||||
onReduceAmount = actions.onReduceAmount,
|
||||
onReduceByAmount = actions.onReduceByAmount,
|
||||
)
|
||||
addTransactionLimitErrorNotification(
|
||||
utxoLimit = quoteModel.currencyCheck?.utxoAmountLimit,
|
||||
cryptoCurrency = fromCurrencyStatus.currency,
|
||||
onReduceClick = { reduceTo, _ ->
|
||||
actions.onReduceAmount(amountToRequest.copy(value = reduceTo))
|
||||
actions.onReduceToAmount(amountToRequest.copy(value = reduceTo))
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
@ -294,7 +294,7 @@ internal class SwapNotificationsFactory(
|
|||
private fun MutableList<NotificationUM>.addReduceAmountNotification(
|
||||
cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
fromAmount: SwapAmount,
|
||||
onReduceAmount: (SwapAmount) -> Unit,
|
||||
onReduceByAmount: (SwapAmount, BigDecimal) -> Unit,
|
||||
) {
|
||||
val isTezos = isTezos(cryptoCurrencyStatus.currency.network.id.value)
|
||||
val balance = cryptoCurrencyStatus.value.amount ?: BigDecimal.ZERO
|
||||
|
|
@ -309,7 +309,7 @@ internal class SwapNotificationsFactory(
|
|||
val patchedAmount = fromAmount.copy(
|
||||
value = fromAmount.value - threshold,
|
||||
)
|
||||
onReduceAmount(patchedAmount)
|
||||
onReduceByAmount(patchedAmount, threshold)
|
||||
},
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import com.tangem.feature.swap.domain.models.ui.RequestApproveStateData
|
|||
import com.tangem.feature.swap.domain.models.ui.SwapState
|
||||
import com.tangem.feature.swap.domain.models.ui.TokensDataStateExpress
|
||||
import com.tangem.feature.swap.domain.models.ui.TxFee
|
||||
import java.math.BigDecimal
|
||||
|
||||
data class SwapProcessDataState(
|
||||
// Initial network id
|
||||
|
|
@ -15,6 +16,7 @@ data class SwapProcessDataState(
|
|||
val feePaidCryptoCurrency: CryptoCurrencyStatus? = null,
|
||||
// Amount from input
|
||||
val amount: String? = null,
|
||||
val reduceBalanceBy: BigDecimal = BigDecimal.ZERO,
|
||||
val approveDataModel: RequestApproveStateData? = null,
|
||||
val swapDataModel: SwapDataModel? = null,
|
||||
val selectedFee: TxFee? = null,
|
||||
|
|
|
|||
|
|
@ -25,11 +25,7 @@ import com.tangem.domain.feedback.SaveBlockchainErrorUseCase
|
|||
import com.tangem.domain.feedback.SendFeedbackEmailUseCase
|
||||
import com.tangem.domain.feedback.models.BlockchainErrorInfo
|
||||
import com.tangem.domain.feedback.models.FeedbackEmailType
|
||||
import com.tangem.domain.tokens.GetCryptoCurrencyStatusSyncUseCase
|
||||
import com.tangem.domain.tokens.GetCurrencyStatusUpdatesUseCase
|
||||
import com.tangem.domain.tokens.GetMinimumTransactionAmountSyncUseCase
|
||||
import com.tangem.domain.tokens.GetFeePaidCryptoCurrencyStatusSyncUseCase
|
||||
import com.tangem.domain.tokens.UpdateDelayedNetworkStatusUseCase
|
||||
import com.tangem.domain.tokens.*
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
|
|
@ -144,6 +140,7 @@ internal class SwapViewModel @Inject constructor(
|
|||
// shows currency order (direct - swap initial to selected, reversed = selected to initial)
|
||||
private var isOrderReversed = false
|
||||
private val lastAmount = mutableStateOf(INITIAL_AMOUNT)
|
||||
private val lastReducedBalanceBy = mutableStateOf(BigDecimal.ZERO)
|
||||
private var swapRouter: SwapRouter by Delegates.notNull()
|
||||
|
||||
private val isUserResolvableError: (SwapState) -> Boolean = {
|
||||
|
|
@ -304,6 +301,7 @@ internal class SwapViewModel @Inject constructor(
|
|||
fromToken = fromCurrencyStatus,
|
||||
toToken = toCurrencyStatus,
|
||||
amount = lastAmount.value,
|
||||
reduceBalanceBy = lastReducedBalanceBy.value,
|
||||
toProvidersList = findSwapProviders(fromCurrencyStatus, toCurrencyStatus),
|
||||
)
|
||||
}
|
||||
|
|
@ -321,6 +319,7 @@ internal class SwapViewModel @Inject constructor(
|
|||
fromToken: CryptoCurrencyStatus,
|
||||
toToken: CryptoCurrencyStatus,
|
||||
amount: String,
|
||||
reduceBalanceBy: BigDecimal,
|
||||
toProvidersList: List<SwapProvider>,
|
||||
isSilent: Boolean = false,
|
||||
) {
|
||||
|
|
@ -339,6 +338,7 @@ internal class SwapViewModel @Inject constructor(
|
|||
fromToken = fromToken,
|
||||
toToken = toToken,
|
||||
amount = amount,
|
||||
reduceBalanceBy = reduceBalanceBy,
|
||||
toProvidersList = toProvidersList,
|
||||
),
|
||||
)
|
||||
|
|
@ -354,6 +354,7 @@ internal class SwapViewModel @Inject constructor(
|
|||
toToken = toCurrency,
|
||||
amount = amount,
|
||||
isSilent = isSilent,
|
||||
reduceBalanceBy = dataState.reduceBalanceBy,
|
||||
toProvidersList = findSwapProviders(fromCurrency, toCurrency),
|
||||
)
|
||||
}
|
||||
|
|
@ -363,6 +364,7 @@ internal class SwapViewModel @Inject constructor(
|
|||
fromToken: CryptoCurrencyStatus,
|
||||
toToken: CryptoCurrencyStatus,
|
||||
amount: String,
|
||||
reduceBalanceBy: BigDecimal,
|
||||
toProvidersList: List<SwapProvider>,
|
||||
): PeriodicTask<Map<SwapProvider, SwapState>> {
|
||||
return PeriodicTask(
|
||||
|
|
@ -372,6 +374,7 @@ internal class SwapViewModel @Inject constructor(
|
|||
runCatching(dispatchers.io) {
|
||||
dataState = dataState.copy(
|
||||
amount = amount,
|
||||
reduceBalanceBy = reduceBalanceBy,
|
||||
swapDataModel = null,
|
||||
approveDataModel = null,
|
||||
)
|
||||
|
|
@ -380,6 +383,7 @@ internal class SwapViewModel @Inject constructor(
|
|||
toToken = toToken,
|
||||
providers = toProvidersList,
|
||||
amountToSwap = amount,
|
||||
reduceBalanceBy = reduceBalanceBy,
|
||||
selectedFee = dataState.selectedFee?.feeType ?: FeeType.NORMAL,
|
||||
)
|
||||
}
|
||||
|
|
@ -817,6 +821,7 @@ internal class SwapViewModel @Inject constructor(
|
|||
fromToken = fromToken,
|
||||
toToken = toToken,
|
||||
amount = lastAmount.value,
|
||||
reduceBalanceBy = lastReducedBalanceBy.value,
|
||||
toProvidersList = findSwapProviders(fromToken, toToken),
|
||||
)
|
||||
swapRouter.openScreen(SwapNavScreen.Main)
|
||||
|
|
@ -886,6 +891,7 @@ internal class SwapViewModel @Inject constructor(
|
|||
).getOrNull()
|
||||
val decimals = newFromToken.currency.decimals
|
||||
lastAmount.value = cutAmountWithDecimals(decimals, lastAmount.value)
|
||||
lastReducedBalanceBy.value = BigDecimal.ZERO
|
||||
uiState = stateBuilder.updateSwapAmount(
|
||||
uiState = uiState,
|
||||
amountFormatted = inputNumberFormatter.formatWithThousands(lastAmount.value, decimals),
|
||||
|
|
@ -897,13 +903,18 @@ internal class SwapViewModel @Inject constructor(
|
|||
fromToken = newFromToken,
|
||||
toToken = newToToken,
|
||||
amount = lastAmount.value,
|
||||
reduceBalanceBy = lastReducedBalanceBy.value,
|
||||
toProvidersList = findSwapProviders(newFromToken, newToToken),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun onAmountChanged(value: String) {
|
||||
private fun onAmountChanged(
|
||||
value: String,
|
||||
forceQuotesUpdate: Boolean = false,
|
||||
reduceBalanceBy: BigDecimal = BigDecimal.ZERO,
|
||||
) {
|
||||
viewModelScope.launch {
|
||||
val fromToken = dataState.fromCryptoCurrency
|
||||
val toToken = dataState.toCryptoCurrency
|
||||
|
|
@ -915,6 +926,7 @@ internal class SwapViewModel @Inject constructor(
|
|||
fromToken,
|
||||
).getOrNull()
|
||||
lastAmount.value = cutValue
|
||||
lastReducedBalanceBy.value = reduceBalanceBy
|
||||
uiState = stateBuilder.updateSwapAmount(
|
||||
uiState = uiState,
|
||||
amountFormatted = inputNumberFormatter.formatWithThousands(cutValue, decimals),
|
||||
|
|
@ -928,11 +940,12 @@ internal class SwapViewModel @Inject constructor(
|
|||
isAmountChangedByUser = true
|
||||
}
|
||||
|
||||
amountDebouncer.debounce(viewModelScope, DEBOUNCE_AMOUNT_DELAY) {
|
||||
amountDebouncer.debounce(viewModelScope, DEBOUNCE_AMOUNT_DELAY, forceUpdate = forceQuotesUpdate) {
|
||||
startLoadingQuotes(
|
||||
fromToken = fromToken,
|
||||
toToken = toToken,
|
||||
amount = lastAmount.value,
|
||||
reduceBalanceBy = lastReducedBalanceBy.value,
|
||||
toProvidersList = findSwapProviders(fromToken, toToken),
|
||||
)
|
||||
}
|
||||
|
|
@ -948,12 +961,12 @@ internal class SwapViewModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun onReduceAmountClicked(newAmount: SwapAmount) {
|
||||
onAmountChanged(newAmount.formatToUIRepresentation())
|
||||
}
|
||||
|
||||
private fun onLeaveExistentialDepositClicked(newAmount: SwapAmount) {
|
||||
onAmountChanged(newAmount.formatToUIRepresentation())
|
||||
private fun onReduceAmountClicked(newAmount: SwapAmount, reduceBalanceBy: BigDecimal = BigDecimal.ZERO) {
|
||||
onAmountChanged(
|
||||
value = newAmount.formatToUIRepresentation(),
|
||||
forceQuotesUpdate = true,
|
||||
reduceBalanceBy = reduceBalanceBy,
|
||||
)
|
||||
}
|
||||
|
||||
private fun onAmountSelected(selected: Boolean) {
|
||||
|
|
@ -1014,8 +1027,8 @@ internal class SwapViewModel @Inject constructor(
|
|||
onSearchEntered("")
|
||||
},
|
||||
onMaxAmountSelected = ::onMaxAmountClicked,
|
||||
onReduceAmount = ::onReduceAmountClicked,
|
||||
onLeaveExistentialDeposit = ::onLeaveExistentialDepositClicked,
|
||||
onReduceToAmount = ::onReduceAmountClicked,
|
||||
onReduceByAmount = ::onReduceAmountClicked,
|
||||
openPermissionBottomSheet = {
|
||||
singleTaskScheduler.cancelTask()
|
||||
analyticsEventHandler.send(SwapEvents.ButtonGivePermissionClicked)
|
||||
|
|
@ -1054,6 +1067,7 @@ internal class SwapViewModel @Inject constructor(
|
|||
selectedFee = it.feeType,
|
||||
fromToken = fromToken,
|
||||
amountToSwap = amountToSwap,
|
||||
reduceBalanceBy = dataState.reduceBalanceBy,
|
||||
)
|
||||
setupLoadedState(selectedProvider, updatedState, fromToken)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue