Updated on 2026-08-14

This commit is contained in:
Tangem 2026-05-21 17:59:40 +05:00
commit a22e77ebe8
669 changed files with 27695 additions and 7905 deletions

View file

@ -1,5 +1,5 @@
package com.tangem.features.swap.v2.api
interface SwapFeatureToggles {
val isSwapRedesignEnabled: Boolean
val isSwapProviderFilterEnabled: Boolean
}

View file

@ -3,10 +3,11 @@ package com.tangem.features.swap.v2.impl
import com.tangem.core.configtoggle.FeatureToggles
import com.tangem.core.configtoggle.feature.FeatureTogglesManager
import com.tangem.features.swap.v2.api.SwapFeatureToggles
import javax.inject.Inject
internal class DefaultSwapFeatureToggles(
internal class DefaultSwapFeatureToggles @Inject constructor(
private val featureToggles: FeatureTogglesManager,
) : SwapFeatureToggles {
override val isSwapRedesignEnabled: Boolean
get() = featureToggles.isFeatureEnabled(FeatureToggles.SWAP_REDESIGN_ENABLED)
override val isSwapProviderFilterEnabled: Boolean =
featureToggles.isFeatureEnabled(FeatureToggles.AND_15009_SWAP_PROVIDER_FILTER_ENABLED)
}

View file

@ -87,6 +87,7 @@ sealed class SwapAmountFieldUM {
val subtitleEllipsisRight: TextEllipsis,
val isClickEnabled: Boolean,
val shouldShowApproximatePrefix: Boolean,
val sendSubtitle: SendSubtitleUM? = null,
) : SwapAmountFieldUM()
}
@ -119,4 +120,11 @@ data class PriceImpact(
type = Type.NONE,
)
}
}
}
@Immutable
data class SendSubtitleUM(
val label: TextReference,
val value: TextReference,
val valueEllipsis: TextEllipsis,
)

View file

@ -60,6 +60,7 @@ internal class SwapAmountFieldConverter(
subtitleEllipsisLeft = subtitles.subtitleEllipsisLeft,
subtitleRight = subtitles.subtitleRight,
subtitleEllipsisRight = subtitles.subtitleEllipsisRight,
sendSubtitle = subtitles.sendSubtitle,
isClickEnabled = true,
shouldShowApproximatePrefix = showApproximatePrefix,
amountField = AmountStateConverter(

View file

@ -58,6 +58,7 @@ internal class SwapAmountUpdateSubtitleConverter(
subtitleEllipsisLeft = subtitles.subtitleEllipsisLeft,
subtitleRight = subtitles.subtitleRight,
subtitleEllipsisRight = subtitles.subtitleEllipsisRight,
sendSubtitle = subtitles.sendSubtitle,
)
}
}

View file

@ -6,17 +6,17 @@ import com.tangem.core.ui.format.bigdecimal.crypto
import com.tangem.core.ui.format.bigdecimal.format
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.features.swap.v2.impl.R
import com.tangem.utils.StringsSigns.DOT
import com.tangem.features.swap.v2.impl.amount.entity.SendSubtitleUM
import java.math.BigDecimal
/**
* Computes all subtitle fields for the **From** (primary) field.
*
* | State | subtitleLeft | subtitleRight | ellipsisLeft |
* |--------------------------------|-----------------------------------|-----------------------------------|------------------------|
* | Entering (float), any | "Balance: " (empty param) | "{balance}" masked | OffsetEnd(symbol) |
* | Viewing (fixed), empty | "Balance: " (empty param) | "{balance}" masked (crypto only) | End |
* | Viewing (fixed), not empty | "{balance}" masked | "• Send {displayStr}" masked | OffsetEnd(symbol) |
* | State | subtitleLeft | subtitleRight | sendSubtitle |
* |--------------------------------|-----------------------------------|---------------|-------------------------|
* | Entering (float), any | "Balance: {balance}" masked | EMPTY | null |
* | Viewing (fixed), empty | "Balance: {balance}" masked | EMPTY | null |
* | Viewing (fixed), not empty | "Balance: {balance}" masked | EMPTY | SendSubtitleUM(...) |
*/
internal object SwapFromSubtitleConverter {
@ -35,40 +35,27 @@ internal object SwapFromSubtitleConverter {
crypto(cryptoCurrency = cryptoCurrencyStatus.currency)
} ?: balance
val subtitleLeft: TextReference
val subtitleRight: TextReference
val ellipsisLeft: TextEllipsis
val subtitleLeft = combinedReference(
resourceReference(R.string.common_balance, wrappedList("")),
stringReference(balance).orMaskWithStars(isBalanceHidden),
)
when {
isEntering -> {
subtitleLeft = resourceReference(R.string.common_balance, wrappedList(""))
subtitleRight = combinedReference(stringReference(balance))
.orMaskWithStars(isBalanceHidden)
ellipsisLeft = TextEllipsis.OffsetEnd(symbol.length)
}
!isEntering && isAmountEmpty -> {
subtitleLeft = resourceReference(R.string.common_balance, wrappedList(""))
subtitleRight = combinedReference(stringReference(balance))
.orMaskWithStars(isBalanceHidden)
ellipsisLeft = TextEllipsis.End
}
else -> {
subtitleLeft = stringReference(balance)
.orMaskWithStars(isBalanceHidden)
subtitleRight = combinedReference(
stringReference("$DOT "),
resourceReference(R.string.common_send),
stringReference(" $displayStr"),
).orMaskWithStars(isBalanceHidden)
ellipsisLeft = TextEllipsis.OffsetEnd(symbol.length)
}
val sendSubtitle = if (!isEntering && !isAmountEmpty) {
SendSubtitleUM(
label = resourceReference(R.string.common_send_colon),
value = stringReference(displayStr).orMaskWithStars(isBalanceHidden),
valueEllipsis = TextEllipsis.OffsetEnd(symbol.length),
)
} else {
null
}
return SwapSubtitleResult(
subtitleLeft = subtitleLeft,
subtitleRight = subtitleRight,
subtitleEllipsisLeft = ellipsisLeft,
subtitleRight = TextReference.EMPTY,
subtitleEllipsisLeft = TextEllipsis.OffsetEnd(symbol.length),
subtitleEllipsisRight = TextEllipsis.OffsetEnd(symbol.length),
sendSubtitle = sendSubtitle,
)
}
}

View file

@ -1,20 +1,16 @@
package com.tangem.features.swap.v2.impl.amount.model.converter
import androidx.compose.ui.text.buildAnnotatedString
import com.tangem.common.ui.swap.SwapRateFormatter
import com.tangem.core.ui.extensions.annotatedReference
import com.tangem.core.ui.extensions.appendSpace
import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.format.bigdecimal.anyDecimals
import com.tangem.core.ui.format.bigdecimal.crypto
import com.tangem.core.ui.format.bigdecimal.format
import com.tangem.domain.express.models.ExpressProvider
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.swap.models.SwapDirection
import com.tangem.domain.swap.models.SwapQuoteModel
import com.tangem.features.swap.v2.impl.amount.model.SwapAmountQuoteUtils.calculateRate
import com.tangem.features.swap.v2.impl.common.entity.SwapQuoteUM
import com.tangem.features.swap.v2.impl.common.entity.SwapQuoteUM.Content.DifferencePercent
import com.tangem.utils.StringsSigns
import com.tangem.utils.converter.Converter
import java.math.BigDecimal
@ -29,18 +25,12 @@ internal class SwapQuoteUMConverter(
override fun convert(value: Data): SwapQuoteUM {
val (quote, provider) = value
val rate = calculateRate(
val rateString = SwapRateFormatter.formatRateAnnotated(
from = primaryCurrency,
to = secondaryCurrency,
fromAmount = fromAmount,
toAmount = quote.toTokenAmount,
toAmountDecimals = secondaryCurrency.decimals,
)
val rateString = buildAnnotatedString {
append(BigDecimal.ONE.format { crypto(symbol = primaryCurrency.symbol, decimals = 0).anyDecimals() })
appendSpace()
append(StringsSigns.APPROXIMATE)
appendSpace()
append(rate.format { crypto(secondaryCurrency) })
}
val fromAmountValue = stringReference(
quote.fromTokenAmount?.format { crypto(primaryCurrency) }.orEmpty(),

View file

@ -2,10 +2,12 @@ package com.tangem.features.swap.v2.impl.amount.model.converter
import com.tangem.core.ui.components.atoms.text.TextEllipsis
import com.tangem.core.ui.extensions.TextReference
import com.tangem.features.swap.v2.impl.amount.entity.SendSubtitleUM
internal data class SwapSubtitleResult(
val subtitleLeft: TextReference,
val subtitleRight: TextReference,
val subtitleEllipsisLeft: TextEllipsis,
val subtitleEllipsisRight: TextEllipsis,
val sendSubtitle: SendSubtitleUM? = null,
)

View file

@ -365,23 +365,45 @@ private fun SwapAmountInfoMain(
private fun SwapAmountSubtitle(amountFieldUM: SwapAmountFieldUM) {
SpacerH2()
if (amountFieldUM is SwapAmountFieldUM.Content) {
SpacerH2()
Row(
horizontalArrangement = Arrangement.spacedBy(4.dp),
Column(
verticalArrangement = Arrangement.spacedBy(2.dp),
) {
EllipsisText(
text = amountFieldUM.subtitleLeft.resolveReference(),
style = TangemTheme.typography.caption2,
color = TangemTheme.colors.text.tertiary,
ellipsis = amountFieldUM.subtitleEllipsisLeft,
modifier = Modifier.weight(1f, fill = false),
)
EllipsisText(
text = amountFieldUM.subtitleRight.resolveReference(),
style = TangemTheme.typography.caption2,
color = TangemTheme.colors.text.tertiary,
ellipsis = amountFieldUM.subtitleEllipsisRight,
)
SpacerH2()
Row(
horizontalArrangement = Arrangement.spacedBy(4.dp),
) {
EllipsisText(
text = amountFieldUM.subtitleLeft.resolveReference(),
style = TangemTheme.typography.caption2,
color = TangemTheme.colors.text.tertiary,
ellipsis = amountFieldUM.subtitleEllipsisLeft,
modifier = Modifier.weight(1f, fill = false),
)
EllipsisText(
text = amountFieldUM.subtitleRight.resolveReference(),
style = TangemTheme.typography.caption2,
color = TangemTheme.colors.text.tertiary,
ellipsis = amountFieldUM.subtitleEllipsisRight,
)
}
if (amountFieldUM.sendSubtitle != null) {
Row(
horizontalArrangement = Arrangement.spacedBy(4.dp),
) {
Text(
text = amountFieldUM.sendSubtitle.label.resolveReference(),
style = TangemTheme.typography.caption2,
color = TangemTheme.colors.text.tertiary,
)
EllipsisText(
text = amountFieldUM.sendSubtitle.value.resolveReference(),
style = TangemTheme.typography.caption2,
color = TangemTheme.colors.text.primary1,
ellipsis = amountFieldUM.sendSubtitle.valueEllipsis,
modifier = Modifier.weight(1f, fill = false),
)
}
}
}
} else {
SpacerH2()

View file

@ -16,10 +16,10 @@ import com.tangem.domain.swap.models.SwapAmountType
import com.tangem.domain.swap.models.SwapCurrencies
import com.tangem.domain.swap.models.SwapDirection
import com.tangem.domain.swap.models.SwapRateMode
import com.tangem.features.swap.v2.impl.amount.entity.SendSubtitleUM
import com.tangem.features.swap.v2.impl.amount.entity.SwapAmountFieldUM
import com.tangem.features.swap.v2.impl.amount.entity.SwapAmountUM
import com.tangem.features.swap.v2.impl.common.entity.SwapQuoteUM
import com.tangem.utils.StringsSigns
import kotlinx.collections.immutable.persistentListOf
import java.math.BigDecimal
@ -103,12 +103,17 @@ internal data object SwapAmountContentPreview {
amountType = SwapAmountType.From,
amountField = AmountStatePreviewData.amountState,
title = stringReference("Tether"),
subtitleLeft = stringReference("11 101,123123456 BTC"),
subtitleRight = stringReference(" ${StringsSigns.DOT} 1 212,12 $"),
subtitleLeft = stringReference("Balance: 11 101,123123456 BTC"),
subtitleRight = TextReference.EMPTY,
isClickEnabled = false,
subtitleEllipsisLeft = TextEllipsis.OffsetEnd(3),
subtitleEllipsisRight = TextEllipsis.OffsetEnd(1),
shouldShowApproximatePrefix = false,
sendSubtitle = SendSubtitleUM(
label = stringReference("Send:"),
value = stringReference("1 212,12 BTC"),
valueEllipsis = TextEllipsis.OffsetEnd(3),
),
),
secondaryAmount = SwapAmountFieldUM.Content(
amountType = SwapAmountType.To,

View file

@ -45,6 +45,7 @@ internal class SwapChooseProviderComponent(
SwapChooseProviderContent(
contentUM = state.value,
onProviderClick = model::onProviderClick,
onFilterSelect = model::onFilterSelect,
)
}
}

View file

@ -1,6 +1,7 @@
package com.tangem.features.swap.v2.impl.chooseprovider.entity
import com.tangem.core.ui.components.provider.entity.ProviderChooseUM
import com.tangem.domain.express.models.ProviderFilterType
import com.tangem.domain.express.models.ExpressProvider
import com.tangem.features.swap.v2.impl.common.entity.SwapQuoteUM
import kotlinx.collections.immutable.ImmutableList
@ -9,6 +10,8 @@ internal data class SwapChooseProviderBottomSheetContent(
val providerList: ImmutableList<SwapProviderListItem>,
val isApplyFCARestrictions: Boolean,
val selectedProvider: ExpressProvider,
val selectedFilter: ProviderFilterType,
val availableFilters: ImmutableList<ProviderFilterType>,
)
internal data class SwapProviderListItem(

View file

@ -3,8 +3,11 @@ package com.tangem.features.swap.v2.impl.chooseprovider.model
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.model.ParamsContainer
import com.tangem.domain.express.models.ProviderFilterType
import com.tangem.domain.express.models.ExpressError
import com.tangem.domain.express.models.ExpressProviderType
import com.tangem.domain.settings.usercountry.models.needApplyFCARestrictions
import com.tangem.features.swap.v2.api.SwapFeatureToggles
import com.tangem.features.swap.v2.impl.chooseprovider.SwapChooseProviderComponent
import com.tangem.features.swap.v2.impl.chooseprovider.entity.SwapChooseProviderBottomSheetContent
import com.tangem.features.swap.v2.impl.chooseprovider.model.converter.SwapProviderListItemConverter
@ -12,6 +15,7 @@ import com.tangem.features.swap.v2.impl.common.entity.SwapQuoteUM
import com.tangem.features.swap.v2.impl.common.isRestrictedByFCA
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import com.tangem.utils.extensions.isSingleItem
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toPersistentList
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
@ -21,6 +25,7 @@ import javax.inject.Inject
internal class SwapChooseProviderModel @Inject constructor(
paramsContainer: ParamsContainer,
override val dispatchers: CoroutineDispatcherProvider,
private val swapFeatureToggles: SwapFeatureToggles,
) : Model() {
private val params: SwapChooseProviderComponent.Params = paramsContainer.require()
@ -46,18 +51,53 @@ internal class SwapChooseProviderModel @Inject constructor(
params.onDismiss()
}
fun onFilterSelect(filterType: ProviderFilterType) {
val filteredProviders = getDisplayableProviders(params.providers)
.filter { matchesTypeFilter(it, filterType) }
uiState.value = uiState.value.copy(
providerList = swapProviderListItemConverter.convertList(filteredProviders)
.filterNotNull()
.toPersistentList(),
selectedFilter = filterType,
)
}
private fun getInitialState(): SwapChooseProviderBottomSheetContent {
val filteredProviderList = params.providers.filter { swapQuoteUM ->
val displayableProviders = getDisplayableProviders(params.providers)
val hasCex = displayableProviders.any { it.provider?.type == ExpressProviderType.CEX }
val hasDex = displayableProviders.any {
it.provider?.type == ExpressProviderType.DEX || it.provider?.type == ExpressProviderType.DEX_BRIDGE
}
val availableFilters = if (swapFeatureToggles.isSwapProviderFilterEnabled && hasCex && hasDex) {
persistentListOf(ProviderFilterType.ALL, ProviderFilterType.CEX, ProviderFilterType.DEX)
} else {
persistentListOf()
}
return SwapChooseProviderBottomSheetContent(
isApplyFCARestrictions = isNeedApplyFCARestrictions && params.selectedProvider.isRestrictedByFCA(),
providerList = swapProviderListItemConverter.convertList(displayableProviders)
.filterNotNull()
.toPersistentList(),
selectedProvider = params.selectedProvider,
selectedFilter = ProviderFilterType.ALL,
availableFilters = availableFilters,
)
}
private fun getDisplayableProviders(allProviders: List<SwapQuoteUM>): List<SwapQuoteUM> {
return allProviders.filter { swapQuoteUM ->
swapQuoteUM is SwapQuoteUM.Content ||
swapQuoteUM is SwapQuoteUM.Allowance ||
(swapQuoteUM as? SwapQuoteUM.Error)?.expressError is ExpressError.AmountError
}
return SwapChooseProviderBottomSheetContent(
isApplyFCARestrictions = isNeedApplyFCARestrictions && params.selectedProvider.isRestrictedByFCA(),
providerList = swapProviderListItemConverter.convertList(filteredProviderList)
.filterNotNull()
.toPersistentList(),
selectedProvider = params.selectedProvider,
)
}
private fun matchesTypeFilter(quote: SwapQuoteUM, filterType: ProviderFilterType): Boolean {
val type = quote.provider?.type ?: return filterType == ProviderFilterType.ALL
return when (filterType) {
ProviderFilterType.ALL -> true
ProviderFilterType.CEX -> type == ExpressProviderType.CEX
ProviderFilterType.DEX -> type == ExpressProviderType.DEX || type == ExpressProviderType.DEX_BRIDGE
}
}
}

View file

@ -4,27 +4,36 @@ import android.content.res.Configuration
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import androidx.compose.ui.unit.dp
import androidx.compose.ui.util.fastForEachIndexed
import androidx.compose.ui.util.fastForEach
import com.tangem.core.ui.components.SpacerH12
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
import com.tangem.core.ui.components.bottomsheets.modal.TangemModalBottomSheet
import com.tangem.core.ui.components.bottomsheets.modal.TangemModalBottomSheetTitle
import com.tangem.core.ui.components.notifications.Notification
import com.tangem.core.ui.components.provider.ProviderTypeFilterPicker
import com.tangem.core.ui.components.provider.entity.ProviderChooseUM
import com.tangem.domain.express.models.ProviderFilterType
import com.tangem.core.ui.extensions.conditional
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.selectedBorder
@ -36,6 +45,7 @@ import com.tangem.features.swap.v2.impl.chooseprovider.entity.SwapChooseProvider
import com.tangem.features.swap.v2.impl.chooseprovider.ui.preview.SwapChooseProviderContentPreview
import com.tangem.features.swap.v2.impl.common.entity.SwapQuoteUM
import com.tangem.features.swap.v2.impl.notifications.entity.SwapNotificationUM
import kotlinx.collections.immutable.persistentListOf
private const val DISABLED_COLORS_ALPHA = 0.5f
@ -55,23 +65,38 @@ internal fun SwapChooseProviderBottomSheet(config: TangemBottomSheetConfig, cont
}
}
@Suppress("LongMethod")
@Composable
internal fun SwapChooseProviderContent(
contentUM: SwapChooseProviderBottomSheetContent,
onProviderClick: (SwapQuoteUM) -> Unit,
onFilterSelect: (ProviderFilterType) -> Unit,
modifier: Modifier = Modifier,
) {
val density = LocalDensity.current
var minHeight by remember { mutableStateOf(0.dp) }
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = modifier.padding(horizontal = 12.dp),
modifier = modifier
.padding(horizontal = 12.dp)
.heightIn(min = minHeight)
.onSizeChanged { size ->
with(density) {
val h = size.height.toDp()
if (h > minHeight) minHeight = h
}
},
) {
Text(
text = stringResourceSafe(id = R.string.onramp_choose_provider_title_hint),
style = TangemTheme.typography.caption2,
color = TangemTheme.colors.text.secondary,
textAlign = TextAlign.Center,
modifier = Modifier.padding(bottom = 4.dp),
)
if (contentUM.availableFilters.isNotEmpty()) {
ProviderTypeFilterPicker(
availableFilters = contentUM.availableFilters,
selectedFilter = contentUM.selectedFilter,
onFilterSelect = onFilterSelect,
modifier = Modifier
.padding(horizontal = 4.dp)
.padding(bottom = 12.dp),
)
}
AnimatedVisibility(
modifier = Modifier.padding(top = 12.dp),
visible = contentUM.isApplyFCARestrictions,
@ -83,7 +108,7 @@ internal fun SwapChooseProviderContent(
)
}
SpacerH12()
contentUM.providerList.fastForEachIndexed { index, provider ->
contentUM.providerList.fastForEach { provider ->
SwapProviderItem(
state = provider.swapProviderState,
modifier = Modifier
@ -144,8 +169,15 @@ private fun SwapChooseProviderContent_Preview(
providerList = params.providerList,
isApplyFCARestrictions = true,
selectedProvider = SwapChooseProviderContentPreview.provider1,
selectedFilter = ProviderFilterType.ALL,
availableFilters = persistentListOf(
ProviderFilterType.ALL,
ProviderFilterType.CEX,
ProviderFilterType.DEX,
),
),
onProviderClick = {},
onFilterSelect = {},
)
}
}

View file

@ -4,6 +4,7 @@ import com.tangem.core.ui.components.audits.AuditLabelUM
import com.tangem.core.ui.components.provider.entity.ProviderChooseUM
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringReference
import com.tangem.domain.express.models.ProviderFilterType
import com.tangem.domain.express.models.ExpressProvider
import com.tangem.domain.express.models.ExpressProviderType
import com.tangem.domain.express.models.ExpressRateType
@ -114,5 +115,7 @@ internal object SwapChooseProviderContentPreview {
),
selectedProvider = provider1,
isApplyFCARestrictions = false,
selectedFilter = ProviderFilterType.ALL,
availableFilters = persistentListOf(),
)
}

View file

@ -1,23 +0,0 @@
package com.tangem.features.swap.v2.impl.swap
import com.tangem.core.decompose.navigation.Route
import kotlinx.serialization.Serializable
internal sealed class SwapRoute : Route {
abstract val isEditMode: Boolean
data object Empty : SwapRoute() {
override val isEditMode: Boolean = false
}
@Serializable
data object Confirm : SwapRoute() {
override val isEditMode: Boolean = true
}
@Serializable
data class Amount(
override val isEditMode: Boolean,
) : SwapRoute()
}

View file

@ -0,0 +1,88 @@
package com.tangem.features.swap.v2.impl.amount.model.converter
import com.google.common.truth.Truth.assertThat
import com.tangem.core.ui.extensions.TextReference
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import io.mockk.every
import io.mockk.mockk
import org.junit.Test
import java.math.BigDecimal
internal class SwapFromSubtitleConverterTest {
@Test
fun `GIVEN isEntering true WHEN convert THEN subtitleRight is EMPTY and sendSubtitle is null`() {
val cryptoCurrencyStatus = mockk<CryptoCurrencyStatus>(relaxed = true)
every { cryptoCurrencyStatus.currency.symbol } returns "ETH"
every { cryptoCurrencyStatus.currency.decimals } returns 8
every { cryptoCurrencyStatus.value.amount } returns BigDecimal("1.5")
val result = SwapFromSubtitleConverter.convert(
cryptoCurrencyStatus = cryptoCurrencyStatus,
isBalanceHidden = false,
isEntering = true,
isAmountEmpty = false,
displayAmount = BigDecimal("0.5"),
)
assertThat(result.subtitleRight).isEqualTo(TextReference.EMPTY)
assertThat(result.sendSubtitle).isNull()
}
@Test
fun `GIVEN isEntering false and isAmountEmpty true WHEN convert THEN subtitleRight is EMPTY and sendSubtitle is null`() {
val cryptoCurrencyStatus = mockk<CryptoCurrencyStatus>(relaxed = true)
every { cryptoCurrencyStatus.currency.symbol } returns "ETH"
every { cryptoCurrencyStatus.currency.decimals } returns 8
every { cryptoCurrencyStatus.value.amount } returns BigDecimal("1.5")
val result = SwapFromSubtitleConverter.convert(
cryptoCurrencyStatus = cryptoCurrencyStatus,
isBalanceHidden = false,
isEntering = false,
isAmountEmpty = true,
displayAmount = null,
)
assertThat(result.subtitleRight).isEqualTo(TextReference.EMPTY)
assertThat(result.sendSubtitle).isNull()
}
@Test
fun `GIVEN isEntering false and isAmountEmpty false WHEN convert THEN subtitleRight is EMPTY and sendSubtitle is not null`() {
val cryptoCurrencyStatus = mockk<CryptoCurrencyStatus>(relaxed = true)
every { cryptoCurrencyStatus.currency.symbol } returns "ETH"
every { cryptoCurrencyStatus.currency.decimals } returns 8
every { cryptoCurrencyStatus.value.amount } returns BigDecimal("1.5")
val result = SwapFromSubtitleConverter.convert(
cryptoCurrencyStatus = cryptoCurrencyStatus,
isBalanceHidden = false,
isEntering = false,
isAmountEmpty = false,
displayAmount = BigDecimal("0.5"),
)
assertThat(result.subtitleRight).isEqualTo(TextReference.EMPTY)
assertThat(result.sendSubtitle).isNotNull()
}
@Test
fun `GIVEN isBalanceHidden true and has amount WHEN convert THEN sendSubtitle is not null`() {
val cryptoCurrencyStatus = mockk<CryptoCurrencyStatus>(relaxed = true)
every { cryptoCurrencyStatus.currency.symbol } returns "ETH"
every { cryptoCurrencyStatus.currency.decimals } returns 8
every { cryptoCurrencyStatus.value.amount } returns BigDecimal("1.5")
val result = SwapFromSubtitleConverter.convert(
cryptoCurrencyStatus = cryptoCurrencyStatus,
isBalanceHidden = true,
isEntering = false,
isAmountEmpty = false,
displayAmount = BigDecimal("0.5"),
)
assertThat(result.subtitleRight).isEqualTo(TextReference.EMPTY)
assertThat(result.sendSubtitle).isNotNull()
}
}