Updated on 2026-08-14

This commit is contained in:
Tangem 2025-08-27 19:04:33 +05:00
commit 484c4138af
7 changed files with 49 additions and 39 deletions

View file

@ -105,10 +105,10 @@ internal class SwapAmountModel @Inject constructor(
private var secondaryMaximumAmountBoundary: EnterAmountBoundary? = null
private var secondaryMinimumAmountBoundary: EnterAmountBoundary? = null
var userCountry: UserCountry = UserCountry.Other(Locale.getDefault().country)
private var userCountry: UserCountry = UserCountry.Other(Locale.getDefault().country)
val bottomSheetNavigation: SlotNavigation<SwapChooseProviderConfig> = SlotNavigation()
var showBestRateAnimation: Boolean = false
private var showBestRateAnimation: Boolean = false
val uiState: StateFlow<SwapAmountUM>
field = MutableStateFlow(params.amountUM)
@ -134,7 +134,10 @@ internal class SwapAmountModel @Inject constructor(
}
fun onStart() {
startLoadingQuotesTask(isSilentReload = false)
quoteTaskScheduler.scheduleTask(
scope = modelScope,
task = loadQuotesTask(),
)
}
fun onStop() {
@ -533,18 +536,17 @@ internal class SwapAmountModel @Inject constructor(
} as? AmountState.Data
val fromAmountValue = fromAmount?.amountTextField?.cryptoAmount?.value.orZero()
if (fromAmount?.amountTextField?.isError == true || fromAmountValue.isNullOrZero()) {
val isAmountScreen = params is SwapAmountComponentParams.AmountParams
val isAmountError = fromAmount?.amountTextField?.isError == true || fromAmountValue.isNullOrZero()
if (isAmountScreen && isAmountError) {
uiState.transformerUpdate(SwapQuoteEmptyStateTransformer)
return
}
val swapGroups = state.swapCurrencies.getGroupWithDirection(state.swapDirection)
uiState.transformerUpdate(SwapQuoteLoadingStateTransformer)
if (!isSilentReload) { uiState.transformerUpdate(SwapQuoteLoadingStateTransformer) }
modelScope.launch {
val quotes = swapGroups.available.filter {
val quotes = state.swapCurrencies.getGroupWithDirection(state.swapDirection).available.filter {
it.currencyStatus.currency.id == toCryptoCurrency.id
}.flatMap {
it.providers
@ -591,7 +593,6 @@ internal class SwapAmountModel @Inject constructor(
needApplyFcaRestrictions = userCountry.needApplyFCARestrictions(),
),
)
feeSelectorReloadTrigger.triggerUpdate()
}
}

View file

@ -34,8 +34,10 @@ internal class SwapAmountSetQuotesTransformer(
val sortedQuotes = quotes.sortedWith(SwapQuotesComparator)
val bestQuote = findBestQuote(quotes) ?: SwapQuoteUM.Empty
val quotesWithDiff = getQuotesWithDiff(sortedQuotes, bestQuote, isSingleProvider)
val selectedQuote = if (isSilentReload && prevState.selectedQuote !is SwapQuoteUM.Loading) {
prevState.selectedQuote
quotesWithDiff.firstOrNull { it.provider?.providerId == prevState.selectedQuote.provider?.providerId }
?: prevState.selectedQuote
} else {
(bestQuote as? SwapQuoteUM.Content)?.copy(
diffPercent = DifferencePercent.Best,
@ -55,7 +57,7 @@ internal class SwapAmountSetQuotesTransformer(
if (updatedState !is SwapAmountUM.Content) return prevState
return updatedState.copy(
isPrimaryButtonEnabled = updatedState.isPrimaryButtonEnabled && quotes.isNotEmpty(),
isPrimaryButtonEnabled = updatedState.isPrimaryButtonEnabled && quotesWithDiff.isNotEmpty(),
swapQuotes = getQuotesWithDiff(sortedQuotes, bestQuote, isSingleProvider),
)
}

View file

@ -45,6 +45,7 @@ internal class SwapAmountValueChangeTransformer(
)
return (updatedState as? SwapAmountUM.Content)?.copy(
isPrimaryButtonEnabled = false,
selectedQuote = if (updatedState.isPrimaryButtonEnabled) {
SwapQuoteUM.Empty
} else {

View file

@ -16,31 +16,34 @@ internal class SwapAmountValueMaxTransformer(
override fun transform(prevState: SwapAmountUM): SwapAmountUM {
if (prevState !is SwapAmountUM.Content) return prevState
return prevState
.copy(selectedQuote = SwapQuoteUM.Loading)
.updateAmount(
onPrimaryAmount = { primaryStatus ->
val updatedState = prevState.updateAmount(
onPrimaryAmount = { primaryStatus ->
copy(
amountField = AmountFieldSetMaxAmountTransformer(
cryptoCurrencyStatus = primaryStatus,
maxAmount = primaryMaximumAmountBoundary,
minAmount = primaryMinimumAmountBoundary,
).transform(prevState.primaryAmount.amountField),
)
},
onSecondaryAmount = { secondaryStatus ->
if (secondaryMaximumAmountBoundary != null) {
copy(
amountField = AmountFieldSetMaxAmountTransformer(
cryptoCurrencyStatus = primaryStatus,
maxAmount = primaryMaximumAmountBoundary,
minAmount = primaryMinimumAmountBoundary,
).transform(prevState.primaryAmount.amountField),
cryptoCurrencyStatus = secondaryStatus,
maxAmount = secondaryMaximumAmountBoundary,
minAmount = secondaryMinimumAmountBoundary,
).transform(prevState.secondaryAmount.amountField),
)
},
onSecondaryAmount = { secondaryStatus ->
if (secondaryMaximumAmountBoundary != null) {
copy(
amountField = AmountFieldSetMaxAmountTransformer(
cryptoCurrencyStatus = secondaryStatus,
maxAmount = secondaryMaximumAmountBoundary,
minAmount = secondaryMinimumAmountBoundary,
).transform(prevState.secondaryAmount.amountField),
)
} else {
this
}
},
)
} else {
this
}
},
)
return (updatedState as? SwapAmountUM.Content)?.copy(
isPrimaryButtonEnabled = false,
selectedQuote = SwapQuoteUM.Loading,
) ?: updatedState
}
}

View file

@ -42,7 +42,7 @@ internal class SwapProviderStateConverter(
val additionalBadge = when {
needApplyFCARestrictions && provider.isRestrictedByFCA() -> AdditionalBadge.FCAWarningList
isNeedBestRateBadge && isBestRate && !needApplyFCARestrictions -> AdditionalBadge.BestTrade
isNeedBestRateBadge && isBestRate -> AdditionalBadge.BestTrade
else -> AdditionalBadge.Empty
}

View file

@ -94,13 +94,15 @@ internal class DefaultSendWithSwapComponent @AssistedInject constructor(
)
activeComponent.updateState(model.uiState.value.destinationUM)
}
is SendWithSwapConfirmComponent -> if (model.currentRoute.value.isEditMode) {
is SendWithSwapConfirmComponent -> {
analyticsEventHandler.send(
CommonSendAnalyticEvents.ConfirmationScreenOpened(
categoryName = model.analyticCategoryName,
),
)
activeComponent.updateState(model.uiState.value)
if (model.currentRoute.value.isEditMode) {
activeComponent.updateState(model.uiState.value)
}
}
}
model.currentRoute.emit(stack.active.configuration)

View file

@ -2,6 +2,7 @@ package com.tangem.features.swap.v2.impl.sendviaswap.analytics
import com.tangem.core.analytics.models.AnalyticsEvent
import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.core.analytics.models.AnalyticsParam.Key.FEE_TYPE
import com.tangem.core.analytics.models.AnalyticsParam.Key.PROVIDER
import com.tangem.core.analytics.models.AnalyticsParam.Key.RECEIVE_BLOCKCHAIN
import com.tangem.core.analytics.models.AnalyticsParam.Key.RECEIVE_TOKEN
@ -24,7 +25,7 @@ internal sealed class SendWithSwapAnalyticEvents(
event = "Send With Swap In Progress Screen Opened",
params = mapOf(
PROVIDER to providerName,
"Commission" to if (feeType is AnalyticsParam.FeeType.Normal) "Market" else "Fast",
FEE_TYPE to if (feeType is AnalyticsParam.FeeType.Normal) "Market" else "Fast",
SEND_TOKEN to fromToken.symbol,
RECEIVE_TOKEN to toToken.symbol,
SEND_BLOCKCHAIN to fromToken.network.name,