Updated on 2026-08-14

This commit is contained in:
Tangem 2024-12-05 17:46:12 +05:00
parent 98fee821fa
commit 5ee6f98c3e
8 changed files with 88 additions and 32 deletions

View file

@ -60,7 +60,7 @@ internal class OnrampAmountStateFactory(
)
}
fun getAmountSecondaryUpdatedState(quote: OnrampQuote): OnrampMainComponentUM {
fun getAmountSecondaryUpdatedState(quote: OnrampQuote, isBestRate: Boolean): OnrampMainComponentUM {
val currentState = currentStateProvider()
if (currentState !is OnrampMainComponentUM.Content) return currentState
@ -71,7 +71,7 @@ internal class OnrampAmountStateFactory(
amountBlockState = amountState.copy(
secondaryFieldModel = quote.toSecondaryFieldUiModel(amountState),
),
providerBlockState = quote.toProviderBlockState(),
providerBlockState = quote.toProviderBlockState(isBestRate),
buyButtonConfig = currentState.buyButtonConfig.copy(
enabled = quote is OnrampQuote.Data,
onClick = {
@ -118,11 +118,11 @@ internal class OnrampAmountStateFactory(
)
}
private fun OnrampQuote.toProviderBlockState(): OnrampProviderBlockUM {
private fun OnrampQuote.toProviderBlockState(isBestRate: Boolean): OnrampProviderBlockUM {
return OnrampProviderBlockUM.Content(
paymentMethod = paymentMethod,
providerName = provider.info.name,
isBestRate = true,
isBestRate = isBestRate,
onClick = onrampIntents::openProviders,
)
}
@ -136,7 +136,7 @@ internal class OnrampAmountStateFactory(
OnrampAmountSecondaryFieldUM.Content(stringReference(amount))
}
is OnrampQuote.Error.AmountTooBigError -> {
val amount = this.amount.value.format {
val amount = requiredAmount.value.format {
fiat(
fiatCurrencyCode = amountState.amountFieldModel.fiatAmount.currencySymbol,
fiatCurrencySymbol = amountState.amountFieldModel.fiatAmount.currencySymbol,
@ -150,7 +150,7 @@ internal class OnrampAmountStateFactory(
)
}
is OnrampQuote.Error.AmountTooSmallError -> {
val amount = this.amount.value.format {
val amount = requiredAmount.value.format {
fiat(
fiatCurrencyCode = amountState.amountFieldModel.fiatAmount.currencySymbol,
fiatCurrencySymbol = amountState.amountFieldModel.fiatAmount.currencySymbol,

View file

@ -177,7 +177,9 @@ internal class OnrampMainComponentModel @Inject constructor(
private fun subscribeToQuotesUpdate() {
getOnrampQuotesUseCase.invoke()
.onEach { maybeQuotes ->
val quote = maybeQuotes.getOrNull()?.firstOrNull() ?: return@onEach
val quotes = maybeQuotes.getOrNull() ?: return@onEach
val isNoQuotes = quotes.none { it is OnrampQuote.Data }
val quote = quotes.firstOrNull() ?: return@onEach
if (quote is OnrampQuote.Data && lastAmount.value != quote.fromAmount.value) {
lastAmount.value = quote.fromAmount.value
analyticsEventHandler.send(
@ -188,7 +190,7 @@ internal class OnrampMainComponentModel @Inject constructor(
),
)
}
_state.update { amountStateFactory.getAmountSecondaryUpdatedState(quote) }
_state.update { amountStateFactory.getAmountSecondaryUpdatedState(quote, isNoQuotes) }
}
.launchIn(modelScope)
}

View file

@ -32,7 +32,6 @@ import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import timber.log.Timber
import java.math.BigDecimal
import javax.inject.Inject
@Suppress("LongParameterList")
@ -125,11 +124,11 @@ internal class SelectProviderModel @Inject constructor(
}
private fun List<OnrampProviderWithQuote>.toProvidersListItems(): ImmutableList<ProviderListItemUM> {
val sortedByRate = sortedByDescending {
(it as? OnrampProviderWithQuote.Data)?.toAmount?.value ?: BigDecimal.ZERO
}
val bestProvider = sortedByRate.firstOrNull()
return sortedByRate.mapIndexed { index, quote ->
val sorted = sortByRate()
val isQuoteExist = any { it is OnrampProviderWithQuote.Data }
val bestProvider = sorted.firstOrNull().takeIf { isQuoteExist }
return sorted.mapIndexed { index, quote ->
when (quote) {
is OnrampProviderWithQuote.Data -> {
val rate = quote.toAmount.value.format {
@ -154,8 +153,8 @@ internal class SelectProviderModel @Inject constructor(
)
}
is OnrampProviderWithQuote.Unavailable.AvailableFrom -> {
val amount = quote.amount.value.format {
crypto(symbol = quote.amount.symbol, decimals = quote.amount.decimals)
val amount = quote.requiredAmount.value.format {
crypto(symbol = quote.requiredAmount.symbol, decimals = quote.requiredAmount.decimals)
}
ProviderListItemUM.Unavailable(
providerId = quote.provider.id,
@ -165,8 +164,8 @@ internal class SelectProviderModel @Inject constructor(
)
}
is OnrampProviderWithQuote.Unavailable.AvailableUpTo -> {
val amount = quote.amount.value.format {
crypto(symbol = quote.amount.symbol, decimals = quote.amount.decimals)
val amount = quote.requiredAmount.value.format {
crypto(symbol = quote.requiredAmount.symbol, decimals = quote.requiredAmount.decimals)
}
ProviderListItemUM.Unavailable(
providerId = quote.provider.id,
@ -188,4 +187,21 @@ internal class SelectProviderModel @Inject constructor(
}
}.toImmutableList()
}
/**
* Sorting providers by rule:
*
* 1. Highest rate
* 2. Smallest difference between entered amount and required min/max amount
*/
private fun List<OnrampProviderWithQuote>.sortByRate() = sortedByDescending {
when (it) {
is OnrampProviderWithQuote.Data -> it.toAmount.value
// negative difference to sort both when data and unavailable is present
is OnrampProviderWithQuote.Unavailable.AvailableFrom -> it.fromAmount.value - it.requiredAmount.value
is OnrampProviderWithQuote.Unavailable.AvailableUpTo -> it.requiredAmount.value - it.fromAmount.value
is OnrampProviderWithQuote.Unavailable.NotSupportedPaymentMethod -> null
}
}
}