From 2516b9e9b9fc1fc7b0f100205be30b59982f97c9 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 11 Dec 2023 19:07:22 +0300 Subject: [PATCH] Updated on 2026-08-14 --- .../swap/models/states/ProviderState.kt | 31 ++++++++++++++----- .../swap/ui/ChooseProviderBottomSheet.kt | 3 +- .../tangem/feature/swap/ui/ProviderItem.kt | 9 ++++-- .../tangem/feature/swap/ui/StateBuilder.kt | 19 +++++++----- .../feature/swap/viewmodels/SwapViewModel.kt | 17 +++++----- 5 files changed, 53 insertions(+), 26 deletions(-) diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/states/ProviderState.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/states/ProviderState.kt index 84254a5716..265631000e 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/states/ProviderState.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/states/ProviderState.kt @@ -25,7 +25,7 @@ sealed class ProviderState { val subtitle: TextReference, val selectionType: SelectionType, val additionalBadge: AdditionalBadge, - val percentLowerThenBest: Float = 0f, + val percentLowerThenBest: PercentLowerThanBest = PercentLowerThanBest.Empty, override val onProviderClick: (String) -> Unit, ) : ProviderState() @@ -50,18 +50,35 @@ sealed class ProviderState { } } +sealed class PercentLowerThanBest { + data class Value(val value: Float) : PercentLowerThanBest() + object Empty : PercentLowerThanBest() +} + object ProviderPercentDiffComparator : Comparator { override fun compare(o1: ProviderState, o2: ProviderState): Int { if (o1 is ProviderState.Content && o2 !is ProviderState.Content) { - return 1 - } - if (o1 !is ProviderState.Content && o2 is ProviderState.Content) { return -1 } - return if (o1 is ProviderState.Content && o2 is ProviderState.Content) { - o1.percentLowerThenBest.compareTo(o2.percentLowerThenBest) + if (o1 !is ProviderState.Content && o2 is ProviderState.Content) { + return 1 + } + if (o1 is ProviderState.Content && o2 is ProviderState.Content) { + val o1Percent = o1.percentLowerThenBest + val o2Percent = o2.percentLowerThenBest + if (o1Percent is PercentLowerThanBest.Value && o2Percent !is PercentLowerThanBest.Value) { + return -1 + } + if (o1Percent !is PercentLowerThanBest.Value && o2Percent is PercentLowerThanBest.Value) { + return 1 + } + return if (o1Percent is PercentLowerThanBest.Value && o2Percent is PercentLowerThanBest.Value) { + o1Percent.value.compareTo(o2Percent.value) + } else { + 0 + } } else { - 0 + return 0 } } } \ No newline at end of file diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/ChooseProviderBottomSheet.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/ChooseProviderBottomSheet.kt index 2dd33c473f..363085e36c 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/ChooseProviderBottomSheet.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/ChooseProviderBottomSheet.kt @@ -17,6 +17,7 @@ import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.res.TangemTheme import com.tangem.feature.swap.models.states.ChooseProviderBottomSheetConfig +import com.tangem.feature.swap.models.states.PercentLowerThanBest import com.tangem.feature.swap.models.states.ProviderState import com.tangem.feature.swap.presentation.R import kotlinx.collections.immutable.toImmutableList @@ -89,7 +90,7 @@ private fun ChooseProviderBottomSheet_Preview() { iconUrl = "", subtitle = stringReference("1 000 000"), additionalBadge = ProviderState.AdditionalBadge.BestTrade, - percentLowerThenBest = -1.0f, + percentLowerThenBest = PercentLowerThanBest.Value(-1.0f), selectionType = ProviderState.SelectionType.SELECT, onProviderClick = {}, ), diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/ProviderItem.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/ProviderItem.kt index e5fe4ef2c9..51f6936885 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/ProviderItem.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/ProviderItem.kt @@ -24,6 +24,7 @@ import com.tangem.core.ui.components.SpacerH24 import com.tangem.core.ui.extensions.resolveReference import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.res.TangemTheme +import com.tangem.feature.swap.models.states.PercentLowerThanBest import com.tangem.feature.swap.models.states.ProviderState /** @@ -151,8 +152,10 @@ private fun ProviderContentState( maxLines = 1, ) } - if (state.percentLowerThenBest > 0f) { - AnimatedContent(targetState = state.percentLowerThenBest, label = "") { + if (state.percentLowerThenBest is PercentLowerThanBest.Value && + state.percentLowerThenBest.value > 0 + ) { + AnimatedContent(targetState = state.percentLowerThenBest.value, label = "") { Text( text = "-$it%", style = TangemTheme.typography.body2, @@ -404,7 +407,7 @@ private fun ProviderItem_Content_Preview() { iconUrl = "", subtitle = stringReference("1 000 000"), additionalBadge = ProviderState.AdditionalBadge.PermissionRequired, - percentLowerThenBest = -1.0f, + percentLowerThenBest = PercentLowerThanBest.Value(-1.0f), selectionType = ProviderState.SelectionType.SELECT, onProviderClick = {}, ) diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt index bb1842d035..af2f4cb3db 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt @@ -789,7 +789,7 @@ internal class StateBuilder( fun showSelectProviderBottomSheet( uiState: SwapStateHolder, selectedProviderId: String, - pricesLowerBest: Map, + pricesLowerBest: Map, providersStates: Map, unavailableProviders: List, onDismiss: () -> Unit, @@ -820,6 +820,7 @@ internal class StateBuilder( fun updateProvidersBottomSheetContent( uiState: SwapStateHolder, + pricesLowerBest: Map, tokenSwapInfoForProviders: Map, ): SwapStateHolder { val config = uiState.bottomSheetConfig?.content as? ChooseProviderBottomSheetConfig @@ -835,6 +836,9 @@ internal class StateBuilder( .getFormattedCryptoAmount(tokenInfo.cryptoCurrencyStatus.currency) it.copy( subtitle = stringReference(rateString), + percentLowerThenBest = pricesLowerBest[it.id]?.let { percent -> + PercentLowerThanBest.Value(percent) + } ?: PercentLowerThanBest.Empty, ) } else { it @@ -928,7 +932,7 @@ internal class StateBuilder( } private fun Map.Entry.convertToProviderBottomSheetState( - pricesLowerBest: Map, + pricesLowerBest: Map, onProviderSelect: (String) -> Unit, ): ProviderState? { val provider = this.key @@ -1040,7 +1044,7 @@ internal class StateBuilder( subtitle = stringReference(rateString), additionalBadge = badge, selectionType = selectionType, - percentLowerThenBest = ZERO_PERCENT, + percentLowerThenBest = PercentLowerThanBest.Empty, onProviderClick = onProviderClick, ) } @@ -1049,7 +1053,7 @@ internal class StateBuilder( isBestRate: Boolean, state: SwapState.QuotesLoadedState, selectionType: ProviderState.SelectionType, - pricesLowerBest: Map, + pricesLowerBest: Map, onProviderClick: (String) -> Unit, ): ProviderState { val toTokenInfo = state.toTokenInfo @@ -1069,7 +1073,9 @@ internal class StateBuilder( subtitle = stringReference(rateString), additionalBadge = additionalBadge, selectionType = selectionType, - percentLowerThenBest = pricesLowerBest[this] ?: ZERO_PERCENT, + percentLowerThenBest = pricesLowerBest[this.providerId]?.let { percent -> + PercentLowerThanBest.Value(percent) + } ?: PercentLowerThanBest.Value(0f), onProviderClick = onProviderClick, ) } @@ -1103,7 +1109,7 @@ internal class StateBuilder( selectionType = selectionType, subtitle = alertText, additionalBadge = ProviderState.AdditionalBadge.Empty, - percentLowerThenBest = ZERO_PERCENT, + percentLowerThenBest = PercentLowerThanBest.Empty, onProviderClick = onProviderClick, ) } @@ -1148,6 +1154,5 @@ internal class StateBuilder( private const val HUNDRED_PERCENTS = 100 private const val UNKNOWN_AMOUNT_SIGN = "—" private const val MAX_DECIMALS_TO_SHOW = 8 - private const val ZERO_PERCENT = 0f } } \ No newline at end of file diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt index 356dde9be4..2f93839717 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt @@ -5,7 +5,6 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.lifecycle.* import arrow.core.getOrElse -import arrow.core.mapNotNull import com.tangem.common.Provider import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.ui.utils.InputNumberFormatter @@ -289,11 +288,13 @@ internal class SwapViewModel @Inject constructor( if (providersState.isNotEmpty()) { val (provider, state) = updateLoadedQuotes(providersState) setupLoadedState(provider, state, fromToken) + val successStates = providersState + .getLastLoadedSuccessStates() + val pricesLowerBest = getPricesLowerBest(successStates) uiState = stateBuilder.updateProvidersBottomSheetContent( uiState = uiState, - tokenSwapInfoForProviders = providersState - .getLastLoadedSuccessStates() - .entries + pricesLowerBest = pricesLowerBest, + tokenSwapInfoForProviders = successStates.entries .associate { it.key.providerId to it.value.toTokenInfo }, ) } else { @@ -869,21 +870,21 @@ internal class SwapViewModel @Inject constructor( }?.key } - private fun getPricesLowerBest(state: SuccessLoadedSwapData): Map { + private fun getPricesLowerBest(state: SuccessLoadedSwapData): Map { val bestRateEntry = state.maxByOrNull { it.value.toTokenInfo.tokenAmount.value } ?: return emptyMap() val bestRate = bestRateEntry.value.toTokenInfo.tokenAmount.value val hundredPercent = BigDecimal("100") - return state.mapNotNull { + return state.entries.mapNotNull { if (it.key != bestRateEntry.key) { val amount = it.value.toTokenInfo.tokenAmount.value val percentDiff = BigDecimal.ONE.minus( amount.divide(bestRate, RoundingMode.HALF_UP), ).multiply(hundredPercent) - percentDiff.setScale(2, RoundingMode.HALF_UP).toFloat().absoluteValue + it.key.providerId to percentDiff.setScale(2, RoundingMode.HALF_UP).toFloat().absoluteValue } else { null } - } + }.toMap() } private fun createSelectedAppCurrencyFlow(): StateFlow {