Updated on 2026-08-14

This commit is contained in:
Tangem 2024-12-05 14:25:05 +05:00
commit 4aa09819aa
5 changed files with 96 additions and 78 deletions

View file

@ -88,7 +88,10 @@ internal class OnrampAmountStateFactory(
)
}
fun getAmountSecondaryUpdatedState(quoteWithProvider: OnrampProviderWithQuote.Data): OnrampMainComponentUM {
fun getAmountSecondaryUpdatedState(
quoteWithProvider: OnrampProviderWithQuote.Data,
isBestRate: Boolean,
): OnrampMainComponentUM {
val currentState = currentStateProvider()
if (currentState !is OnrampMainComponentUM.Content) return currentState
@ -103,7 +106,7 @@ internal class OnrampAmountStateFactory(
providerBlockState = OnrampProviderBlockUM.Content(
paymentMethod = quoteWithProvider.paymentMethod,
providerName = quoteWithProvider.provider.info.name,
isBestRate = true,
isBestRate = isBestRate,
onClick = onrampIntents::openProviders,
),
buyButtonConfig = currentState.buyButtonConfig.copy(

View file

@ -99,8 +99,8 @@ internal class OnrampMainComponentModel @Inject constructor(
subscribeToQuotesUpdate()
}
fun onProviderSelected(providerWithQuote: OnrampProviderWithQuote.Data) {
_state.update { amountStateFactory.getAmountSecondaryUpdatedState(providerWithQuote) }
fun onProviderSelected(providerWithQuote: OnrampProviderWithQuote.Data, isBestRate: Boolean) {
_state.update { amountStateFactory.getAmountSecondaryUpdatedState(providerWithQuote, isBestRate) }
}
private fun checkResidenceCountry() {

View file

@ -1,5 +1,8 @@
package com.tangem.features.onramp.main.ui
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
@ -68,20 +71,27 @@ private fun OnrampProviderBlock(state: OnrampProviderBlockUM.Content, modifier:
color = TangemTheme.colors.text.tertiary,
)
}
Text(
modifier = Modifier
.background(
color = TangemTheme.colors.icon.accent,
shape = RoundedCornerShape(TangemTheme.dimens.radius4),
)
.padding(
horizontal = TangemTheme.dimens.spacing6,
vertical = TangemTheme.dimens.spacing1,
),
text = stringResource(id = R.string.express_provider_best_rate),
style = TangemTheme.typography.caption1,
color = TangemTheme.colors.text.primary2,
)
AnimatedVisibility(
visible = state.isBestRate,
enter = fadeIn(),
exit = fadeOut(),
label = "Best Rate visibility animation",
) {
Text(
modifier = Modifier
.background(
color = TangemTheme.colors.icon.accent,
shape = RoundedCornerShape(TangemTheme.dimens.radius4),
)
.padding(
horizontal = TangemTheme.dimens.spacing6,
vertical = TangemTheme.dimens.spacing1,
),
text = stringResource(id = R.string.express_provider_best_rate),
style = TangemTheme.typography.caption1,
color = TangemTheme.colors.text.primary2,
)
}
}
}

View file

@ -9,7 +9,7 @@ import com.tangem.domain.tokens.model.CryptoCurrency
internal interface SelectProviderComponent : ComposableBottomSheetComponent {
data class Params(
val onProviderClick: (OnrampProviderWithQuote.Data) -> Unit,
val onProviderClick: (OnrampProviderWithQuote.Data, Boolean) -> Unit,
val onDismiss: () -> Unit,
val selectedPaymentMethod: OnrampPaymentMethod,
val cryptoCurrency: CryptoCurrency,

View file

@ -27,6 +27,7 @@ import com.tangem.features.onramp.providers.entity.ProviderListItemUM
import com.tangem.features.onramp.providers.entity.ProviderListPaymentMethodUM
import com.tangem.features.onramp.providers.entity.ProviderListUM
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
@ -123,64 +124,68 @@ internal class SelectProviderModel @Inject constructor(
}
}
private fun List<OnrampProviderWithQuote>.toProvidersListItems() = sortedByDescending {
(it as? OnrampProviderWithQuote.Data)?.toAmount?.value ?: BigDecimal.ZERO
}.mapIndexed { index, quote ->
when (quote) {
is OnrampProviderWithQuote.Data -> {
val rate = quote.toAmount.value.format {
crypto(symbol = quote.toAmount.symbol, decimals = quote.toAmount.decimals)
}
ProviderListItemUM.Available(
providerId = quote.provider.id,
imageUrl = quote.provider.info.imageLarge,
name = quote.provider.info.name,
rate = rate,
isSelected = index == 0,
onClick = {
analyticsEventHandler.send(
OnrampAnalyticsEvent.OnProviderChosen(
providerName = quote.provider.info.name,
tokenSymbol = params.cryptoCurrency.symbol,
),
)
params.onProviderClick(quote)
params.onDismiss()
},
)
}
is OnrampProviderWithQuote.Unavailable.AvailableFrom -> {
val amount = quote.amount.value.format {
crypto(symbol = quote.amount.symbol, decimals = quote.amount.decimals)
}
ProviderListItemUM.Unavailable(
providerId = quote.provider.id,
imageUrl = quote.provider.info.imageLarge,
name = quote.provider.info.name,
subtitle = resourceReference(R.string.express_provider_min_amount, wrappedList(amount)),
)
}
is OnrampProviderWithQuote.Unavailable.AvailableUpTo -> {
val amount = quote.amount.value.format {
crypto(symbol = quote.amount.symbol, decimals = quote.amount.decimals)
}
ProviderListItemUM.Unavailable(
providerId = quote.provider.id,
imageUrl = quote.provider.info.imageLarge,
name = quote.provider.info.name,
subtitle = resourceReference(R.string.express_provider_max_amount, wrappedList(amount)),
)
}
is OnrampProviderWithQuote.Unavailable.NotSupportedPaymentMethod -> {
ProviderListItemUM.Unavailable(
providerId = quote.provider.id,
imageUrl = quote.provider.info.imageLarge,
name = quote.provider.info.name,
subtitle = stringReference(
"Available with ${quote.availablePaymentMethods.joinToString { it.name }}",
),
)
}
private fun List<OnrampProviderWithQuote>.toProvidersListItems(): ImmutableList<ProviderListItemUM> {
val sortedByRate = sortedByDescending {
(it as? OnrampProviderWithQuote.Data)?.toAmount?.value ?: BigDecimal.ZERO
}
}.toImmutableList()
val bestProvider = sortedByRate.firstOrNull()
return sortedByRate.mapIndexed { index, quote ->
when (quote) {
is OnrampProviderWithQuote.Data -> {
val rate = quote.toAmount.value.format {
crypto(symbol = quote.toAmount.symbol, decimals = quote.toAmount.decimals)
}
ProviderListItemUM.Available(
providerId = quote.provider.id,
imageUrl = quote.provider.info.imageLarge,
name = quote.provider.info.name,
rate = rate,
isSelected = index == 0,
onClick = {
analyticsEventHandler.send(
OnrampAnalyticsEvent.OnProviderChosen(
providerName = quote.provider.info.name,
tokenSymbol = params.cryptoCurrency.symbol,
),
)
params.onProviderClick(quote, bestProvider == quote)
params.onDismiss()
},
)
}
is OnrampProviderWithQuote.Unavailable.AvailableFrom -> {
val amount = quote.amount.value.format {
crypto(symbol = quote.amount.symbol, decimals = quote.amount.decimals)
}
ProviderListItemUM.Unavailable(
providerId = quote.provider.id,
imageUrl = quote.provider.info.imageLarge,
name = quote.provider.info.name,
subtitle = resourceReference(R.string.express_provider_min_amount, wrappedList(amount)),
)
}
is OnrampProviderWithQuote.Unavailable.AvailableUpTo -> {
val amount = quote.amount.value.format {
crypto(symbol = quote.amount.symbol, decimals = quote.amount.decimals)
}
ProviderListItemUM.Unavailable(
providerId = quote.provider.id,
imageUrl = quote.provider.info.imageLarge,
name = quote.provider.info.name,
subtitle = resourceReference(R.string.express_provider_max_amount, wrappedList(amount)),
)
}
is OnrampProviderWithQuote.Unavailable.NotSupportedPaymentMethod -> {
ProviderListItemUM.Unavailable(
providerId = quote.provider.id,
imageUrl = quote.provider.info.imageLarge,
name = quote.provider.info.name,
subtitle = stringReference(
"Available with ${quote.availablePaymentMethods.joinToString { it.name }}",
),
)
}
}
}.toImmutableList()
}
}