diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/entity/factory/amount/OnrampAmountStateFactory.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/entity/factory/amount/OnrampAmountStateFactory.kt index ff6681a318..ec9ef905d1 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/entity/factory/amount/OnrampAmountStateFactory.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/entity/factory/amount/OnrampAmountStateFactory.kt @@ -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( diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/model/OnrampMainComponentModel.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/model/OnrampMainComponentModel.kt index 8c63935d30..9e382eb0e9 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/model/OnrampMainComponentModel.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/model/OnrampMainComponentModel.kt @@ -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() { diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/ui/OnrampProviderContent.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/ui/OnrampProviderContent.kt index c30e3506ee..381a77989d 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/ui/OnrampProviderContent.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/ui/OnrampProviderContent.kt @@ -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, + ) + } } } diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/SelectProviderComponent.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/SelectProviderComponent.kt index 181a2ed99e..99d4238e86 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/SelectProviderComponent.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/SelectProviderComponent.kt @@ -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, diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/model/SelectProviderModel.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/model/SelectProviderModel.kt index 21a7ba9774..d02e063697 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/model/SelectProviderModel.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/model/SelectProviderModel.kt @@ -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.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.toProvidersListItems(): ImmutableList { + 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() + } } \ No newline at end of file