Updated on 2026-08-14

This commit is contained in:
Tangem 2026-07-01 11:46:25 +03:00
parent 39a107b039
commit 173c414e50
20 changed files with 43 additions and 168 deletions

View file

@ -196,13 +196,9 @@ abstract class BaseTestCase : TestCase(
"DYNAMIC_ADDRESSES_ENABLED" to true, "DYNAMIC_ADDRESSES_ENABLED" to true,
"SOLANA_TX_HISTORY_ENABLED" to true, "SOLANA_TX_HISTORY_ENABLED" to true,
"SOLANA_SCALED_UI_AMOUNT_ENABLED" to true, "SOLANA_SCALED_UI_AMOUNT_ENABLED" to true,
"SWAP_AB_ENABLED" to true,
"AND_15310_ADD_FUNDS_STAGE1" to true, "AND_15310_ADD_FUNDS_STAGE1" to true,
"AND_15009_SWAP_PROVIDER_FILTER_ENABLED" to true,
"AND_15101_TANGEM_PAY_HOT_WALLET_ONBOARDING" to true, "AND_15101_TANGEM_PAY_HOT_WALLET_ONBOARDING" to true,
"AND_15402_ADI_MAIN_SCREEN_DEFAULT_ENABLED" to true, "AND_15402_ADI_MAIN_SCREEN_DEFAULT_ENABLED" to true,
"AND_15103_SWAP_RATE_EXPERIENCE_ENABLED" to true,
"AND_15122_SWAP_PREDEFINED_BUTTONS_ENABLED" to true,
"TWI_1512_HIDE_STORIES_FOR_REFERRAL_ENABLED" to true, "TWI_1512_HIDE_STORIES_FOR_REFERRAL_ENABLED" to true,
// 5.40 // 5.40
"TWI_1377_MANAGE_FUNDS" to true, "TWI_1377_MANAGE_FUNDS" to true,

View file

@ -63,10 +63,6 @@
"name": "AND_15120_SWAP_INTEGRATED_APPROVE", "name": "AND_15120_SWAP_INTEGRATED_APPROVE",
"version": "6.0" "version": "6.0"
}, },
{
"name": "SWAP_AB_ENABLED",
"version": "5.39"
},
{ {
"name": "TWI_1403_PUSH_NOTIFICATION_SETTINGS_ENABLED", "name": "TWI_1403_PUSH_NOTIFICATION_SETTINGS_ENABLED",
"version": "undefined" "version": "undefined"
@ -83,10 +79,6 @@
"name": "TWI_1377_MANAGE_FUNDS", "name": "TWI_1377_MANAGE_FUNDS",
"version": "6.0" "version": "6.0"
}, },
{
"name": "AND_15009_SWAP_PROVIDER_FILTER_ENABLED",
"version": "5.39"
},
{ {
"name": "AND_15101_TANGEM_PAY_HOT_WALLET_ONBOARDING", "name": "AND_15101_TANGEM_PAY_HOT_WALLET_ONBOARDING",
"version": "5.39" "version": "5.39"
@ -95,14 +87,6 @@
"name": "AND_15402_ADI_MAIN_SCREEN_DEFAULT_ENABLED", "name": "AND_15402_ADI_MAIN_SCREEN_DEFAULT_ENABLED",
"version": "5.39" "version": "5.39"
}, },
{
"name": "AND_15103_SWAP_RATE_EXPERIENCE_ENABLED",
"version": "5.39"
},
{
"name": "AND_15122_SWAP_PREDEFINED_BUTTONS_ENABLED",
"version": "5.39"
},
{ {
"name": "TWI_1512_HIDE_STORIES_FOR_REFERRAL_ENABLED", "name": "TWI_1512_HIDE_STORIES_FOR_REFERRAL_ENABLED",
"version": "5.39" "version": "5.39"

View file

@ -46,7 +46,6 @@ internal class FeatureTogglesNamingConventionTest {
"NEW_CARD_SCANNING_ENABLED", "NEW_CARD_SCANNING_ENABLED",
"SOLANA_SCALED_UI_AMOUNT_ENABLED", "SOLANA_SCALED_UI_AMOUNT_ENABLED",
"SOLANA_TX_HISTORY_ENABLED", "SOLANA_TX_HISTORY_ENABLED",
"SWAP_AB_ENABLED",
"VIRTUAL_ACCOUNTS_ENABLED", "VIRTUAL_ACCOUNTS_ENABLED",
"VISA_ONBOARDING_ENABLED", "VISA_ONBOARDING_ENABLED",
"WALLET_CONNECT_BITCOIN_ENABLED", "WALLET_CONNECT_BITCOIN_ENABLED",

View file

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

View file

@ -8,9 +8,6 @@ import javax.inject.Inject
internal class DefaultSwapFeatureToggles @Inject constructor( internal class DefaultSwapFeatureToggles @Inject constructor(
private val featureToggles: FeatureTogglesManager, private val featureToggles: FeatureTogglesManager,
) : SwapFeatureToggles { ) : SwapFeatureToggles {
override val isSwapProviderFilterEnabled: Boolean =
featureToggles.isFeatureEnabled(FeatureToggles.AND_15009_SWAP_PROVIDER_FILTER_ENABLED)
override val isHighFeeWarningEnabled: Boolean = override val isHighFeeWarningEnabled: Boolean =
featureToggles.isFeatureEnabled(FeatureToggles.TWI_1367_HIGH_FEE_WARNING_ENABLED) featureToggles.isFeatureEnabled(FeatureToggles.TWI_1367_HIGH_FEE_WARNING_ENABLED)
} }

View file

@ -9,7 +9,6 @@ import com.tangem.domain.express.models.ExpressError
import com.tangem.domain.express.models.ProviderFilterType import com.tangem.domain.express.models.ProviderFilterType
import com.tangem.domain.express.models.ExpressProviderType import com.tangem.domain.express.models.ExpressProviderType
import com.tangem.domain.settings.usercountry.models.needApplyFCARestrictions 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.SwapChooseProviderComponent
import com.tangem.features.swap.v2.impl.chooseprovider.entity.SwapChooseProviderBottomSheetContent import com.tangem.features.swap.v2.impl.chooseprovider.entity.SwapChooseProviderBottomSheetContent
import com.tangem.features.swap.v2.impl.chooseprovider.model.converter.SwapProviderListItemConverter import com.tangem.features.swap.v2.impl.chooseprovider.model.converter.SwapProviderListItemConverter
@ -27,7 +26,6 @@ import javax.inject.Inject
internal class SwapChooseProviderModel @Inject constructor( internal class SwapChooseProviderModel @Inject constructor(
paramsContainer: ParamsContainer, paramsContainer: ParamsContainer,
override val dispatchers: CoroutineDispatcherProvider, override val dispatchers: CoroutineDispatcherProvider,
private val swapFeatureToggles: SwapFeatureToggles,
private val analyticsEventHandler: AnalyticsEventHandler, private val analyticsEventHandler: AnalyticsEventHandler,
) : Model() { ) : Model() {
@ -80,7 +78,7 @@ internal class SwapChooseProviderModel @Inject constructor(
val hasDex = displayableProviders.any { val hasDex = displayableProviders.any {
it.provider?.type == ExpressProviderType.DEX || it.provider?.type == ExpressProviderType.DEX_BRIDGE it.provider?.type == ExpressProviderType.DEX || it.provider?.type == ExpressProviderType.DEX_BRIDGE
} }
val availableFilters = if (swapFeatureToggles.isSwapProviderFilterEnabled && hasCex && hasDex) { val availableFilters = if (hasCex && hasDex) {
persistentListOf(ProviderFilterType.ALL, ProviderFilterType.CEX, ProviderFilterType.DEX) persistentListOf(ProviderFilterType.ALL, ProviderFilterType.CEX, ProviderFilterType.DEX)
} else { } else {
persistentListOf() persistentListOf()

View file

@ -4,10 +4,6 @@ interface SwapFeatureToggles {
val isYieldSwapEnabled: Boolean val isYieldSwapEnabled: Boolean
val isSwapSwitchToTransferEnabled: Boolean val isSwapSwitchToTransferEnabled: Boolean
val isSwapIntegratedApproveEnabled: Boolean val isSwapIntegratedApproveEnabled: Boolean
val isSwapAbEnabled: Boolean
val isSwapProviderFilterEnabled: Boolean
val isSwapRateExperienceEnabled: Boolean
val isSwapPredefinedButtonsEnabled: Boolean
val isExpressShareButtonEnabled: Boolean val isExpressShareButtonEnabled: Boolean
val isSwapBestDexRateEnabled: Boolean val isSwapBestDexRateEnabled: Boolean
val isHighFeeWarningEnabled: Boolean val isHighFeeWarningEnabled: Boolean

View file

@ -3,17 +3,14 @@ package com.tangem.feature.swap.domain
import com.tangem.core.abtests.manager.ABTestsManager import com.tangem.core.abtests.manager.ABTestsManager
import com.tangem.feature.swap.domain.api.SwapRepository import com.tangem.feature.swap.domain.api.SwapRepository
import com.tangem.feature.swap.domain.models.domain.SwapUIMode import com.tangem.feature.swap.domain.models.domain.SwapUIMode
import com.tangem.features.swap.SwapFeatureToggles
import com.tangem.utils.logging.TangemLogger import com.tangem.utils.logging.TangemLogger
class GetSwapUiModeUseCase( class GetSwapUiModeUseCase(
private val swapFeatureToggles: SwapFeatureToggles,
private val swapRepository: SwapRepository, private val swapRepository: SwapRepository,
private val abTestsManager: ABTestsManager, private val abTestsManager: ABTestsManager,
) { ) {
suspend operator fun invoke(): SwapUIMode { suspend operator fun invoke(): SwapUIMode {
if (!swapFeatureToggles.isSwapAbEnabled) return SwapUIMode.Detailed
swapRepository.getStoredSwapUiMode()?.let { return it } swapRepository.getStoredSwapUiMode()?.let { return it }
val variant = abTestsManager.getValue(KEY_SWAP_FORM_VARIANT, SwapUIMode.Detailed.key) val variant = abTestsManager.getValue(KEY_SWAP_FORM_VARIANT, SwapUIMode.Detailed.key)
TangemLogger.d("Get $variant Swap AB variant from Amplitude as default value") TangemLogger.d("Get $variant Swap AB variant from Amplitude as default value")

View file

@ -18,7 +18,6 @@ import com.tangem.feature.swap.domain.fee.DexSwapFeeCalculator
import com.tangem.feature.swap.domain.fee.PatchEthGasLimitForSwap import com.tangem.feature.swap.domain.fee.PatchEthGasLimitForSwap
import com.tangem.feature.swap.domain.transfer.SwapTransferInteractor import com.tangem.feature.swap.domain.transfer.SwapTransferInteractor
import com.tangem.feature.swap.domain.transfer.SwapTransferInteractorImpl import com.tangem.feature.swap.domain.transfer.SwapTransferInteractorImpl
import com.tangem.features.swap.SwapFeatureToggles
import dagger.Binds import dagger.Binds
import dagger.Module import dagger.Module
import dagger.Provides import dagger.Provides
@ -39,11 +38,9 @@ internal class SwapDomainModule {
@Provides @Provides
@Singleton @Singleton
fun provideGetSwapUiModeUseCase( fun provideGetSwapUiModeUseCase(
swapFeatureToggles: SwapFeatureToggles,
swapRepository: SwapRepository, swapRepository: SwapRepository,
abTestsManager: ABTestsManager, abTestsManager: ABTestsManager,
): GetSwapUiModeUseCase = GetSwapUiModeUseCase( ): GetSwapUiModeUseCase = GetSwapUiModeUseCase(
swapFeatureToggles = swapFeatureToggles,
swapRepository = swapRepository, swapRepository = swapRepository,
abTestsManager = abTestsManager, abTestsManager = abTestsManager,
) )

View file

@ -4,7 +4,6 @@ import com.google.common.truth.Truth.assertThat
import com.tangem.core.abtests.manager.ABTestsManager import com.tangem.core.abtests.manager.ABTestsManager
import com.tangem.feature.swap.domain.api.SwapRepository import com.tangem.feature.swap.domain.api.SwapRepository
import com.tangem.feature.swap.domain.models.domain.SwapUIMode import com.tangem.feature.swap.domain.models.domain.SwapUIMode
import com.tangem.features.swap.SwapFeatureToggles
import io.mockk.coEvery import io.mockk.coEvery
import io.mockk.coVerify import io.mockk.coVerify
import io.mockk.mockk import io.mockk.mockk
@ -13,32 +12,17 @@ import org.junit.jupiter.api.Test
internal class GetSwapUiModeUseCaseTest { internal class GetSwapUiModeUseCaseTest {
private val swapFeatureToggles: SwapFeatureToggles = mockk()
private val swapRepository: SwapRepository = mockk() private val swapRepository: SwapRepository = mockk()
private val abTestsManager: ABTestsManager = mockk() private val abTestsManager: ABTestsManager = mockk()
private val sut = GetSwapUiModeUseCase( private val sut = GetSwapUiModeUseCase(
swapFeatureToggles = swapFeatureToggles,
swapRepository = swapRepository, swapRepository = swapRepository,
abTestsManager = abTestsManager, abTestsManager = abTestsManager,
) )
@Test @Test
fun `GIVEN feature toggle is disabled WHEN invoke THEN returns Detailed without reading repository or AB tests`() = fun `GIVEN repository has Detailed WHEN invoke THEN returns Detailed without reading AB tests`() =
runTest { runTest {
coEvery { swapFeatureToggles.isSwapAbEnabled } returns false
val actual = sut.invoke()
assertThat(actual).isEqualTo(SwapUIMode.Detailed)
coVerify(exactly = 0) { swapRepository.getStoredSwapUiMode() }
coVerify(exactly = 0) { abTestsManager.getValue(any(), any()) }
}
@Test
fun `GIVEN toggle enabled and repository has Detailed WHEN invoke THEN returns Detailed without reading AB tests`() =
runTest {
coEvery { swapFeatureToggles.isSwapAbEnabled } returns true
coEvery { swapRepository.getStoredSwapUiMode() } returns SwapUIMode.Detailed coEvery { swapRepository.getStoredSwapUiMode() } returns SwapUIMode.Detailed
val actual = sut.invoke() val actual = sut.invoke()
@ -48,9 +32,8 @@ internal class GetSwapUiModeUseCaseTest {
} }
@Test @Test
fun `GIVEN toggle enabled and repository has Simple WHEN invoke THEN returns Simple without reading AB tests`() = fun `GIVEN repository has Simple WHEN invoke THEN returns Simple without reading AB tests`() =
runTest { runTest {
coEvery { swapFeatureToggles.isSwapAbEnabled } returns true
coEvery { swapRepository.getStoredSwapUiMode() } returns SwapUIMode.Simple coEvery { swapRepository.getStoredSwapUiMode() } returns SwapUIMode.Simple
val actual = sut.invoke() val actual = sut.invoke()
@ -60,9 +43,8 @@ internal class GetSwapUiModeUseCaseTest {
} }
@Test @Test
fun `GIVEN toggle enabled and repository empty and AB returns detailed WHEN invoke THEN returns Detailed`() = fun `GIVEN repository empty and AB returns detailed WHEN invoke THEN returns Detailed`() =
runTest { runTest {
coEvery { swapFeatureToggles.isSwapAbEnabled } returns true
coEvery { swapRepository.getStoredSwapUiMode() } returns null coEvery { swapRepository.getStoredSwapUiMode() } returns null
coEvery { abTestsManager.getValue("swap_form_variant", "detailed") } returns "detailed" coEvery { abTestsManager.getValue("swap_form_variant", "detailed") } returns "detailed"
@ -73,8 +55,7 @@ internal class GetSwapUiModeUseCaseTest {
} }
@Test @Test
fun `GIVEN toggle enabled and repository empty and AB returns simple WHEN invoke THEN returns Simple`() = runTest { fun `GIVEN repository empty and AB returns simple WHEN invoke THEN returns Simple`() = runTest {
coEvery { swapFeatureToggles.isSwapAbEnabled } returns true
coEvery { swapRepository.getStoredSwapUiMode() } returns null coEvery { swapRepository.getStoredSwapUiMode() } returns null
coEvery { abTestsManager.getValue("swap_form_variant", "detailed") } returns "simple" coEvery { abTestsManager.getValue("swap_form_variant", "detailed") } returns "simple"
@ -85,9 +66,8 @@ internal class GetSwapUiModeUseCaseTest {
} }
@Test @Test
fun `GIVEN toggle enabled and repository empty and AB returns SIMPLE uppercase WHEN invoke THEN returns Simple`() = fun `GIVEN repository empty and AB returns SIMPLE uppercase WHEN invoke THEN returns Simple`() =
runTest { runTest {
coEvery { swapFeatureToggles.isSwapAbEnabled } returns true
coEvery { swapRepository.getStoredSwapUiMode() } returns null coEvery { swapRepository.getStoredSwapUiMode() } returns null
coEvery { abTestsManager.getValue("swap_form_variant", "detailed") } returns "SIMPLE" coEvery { abTestsManager.getValue("swap_form_variant", "detailed") } returns "SIMPLE"
@ -97,9 +77,8 @@ internal class GetSwapUiModeUseCaseTest {
} }
@Test @Test
fun `GIVEN toggle enabled and repository empty and AB returns unknown variant WHEN invoke THEN returns Detailed`() = fun `GIVEN repository empty and AB returns unknown variant WHEN invoke THEN returns Detailed`() =
runTest { runTest {
coEvery { swapFeatureToggles.isSwapAbEnabled } returns true
coEvery { swapRepository.getStoredSwapUiMode() } returns null coEvery { swapRepository.getStoredSwapUiMode() } returns null
coEvery { abTestsManager.getValue("swap_form_variant", "detailed") } returns "something_else" coEvery { abTestsManager.getValue("swap_form_variant", "detailed") } returns "something_else"
@ -109,9 +88,8 @@ internal class GetSwapUiModeUseCaseTest {
} }
@Test @Test
fun `GIVEN toggle enabled and repository empty and AB returns empty string WHEN invoke THEN returns Detailed`() = fun `GIVEN repository empty and AB returns empty string WHEN invoke THEN returns Detailed`() =
runTest { runTest {
coEvery { swapFeatureToggles.isSwapAbEnabled } returns true
coEvery { swapRepository.getStoredSwapUiMode() } returns null coEvery { swapRepository.getStoredSwapUiMode() } returns null
coEvery { abTestsManager.getValue("swap_form_variant", "detailed") } returns "" coEvery { abTestsManager.getValue("swap_form_variant", "detailed") } returns ""

View file

@ -24,25 +24,6 @@ internal class DefaultSwapFeatureToggles @Inject constructor(
toggle = FeatureToggles.AND_15120_SWAP_INTEGRATED_APPROVE, toggle = FeatureToggles.AND_15120_SWAP_INTEGRATED_APPROVE,
) )
override val isSwapAbEnabled: Boolean
get() = featureTogglesManager.isFeatureEnabled(
toggle = FeatureToggles.SWAP_AB_ENABLED,
)
override val isSwapProviderFilterEnabled: Boolean
get() = featureTogglesManager.isFeatureEnabled(
toggle = FeatureToggles.AND_15009_SWAP_PROVIDER_FILTER_ENABLED,
)
override val isSwapRateExperienceEnabled: Boolean
get() = featureTogglesManager.isFeatureEnabled(
toggle = FeatureToggles.AND_15103_SWAP_RATE_EXPERIENCE_ENABLED,
)
override val isSwapPredefinedButtonsEnabled: Boolean
get() = featureTogglesManager.isFeatureEnabled(
toggle = FeatureToggles.AND_15122_SWAP_PREDEFINED_BUTTONS_ENABLED,
)
override val isExpressShareButtonEnabled: Boolean override val isExpressShareButtonEnabled: Boolean
get() = featureTogglesManager.isFeatureEnabled( get() = featureTogglesManager.isFeatureEnabled(
toggle = FeatureToggles.AND_15489_EXPRESS_SHARE_BUTTON_ENABLED, toggle = FeatureToggles.AND_15489_EXPRESS_SHARE_BUTTON_ENABLED,

View file

@ -210,7 +210,6 @@ internal class SwapModel @Inject constructor(
appCurrencyProvider = Provider(selectedAppCurrencyFlow::value), appCurrencyProvider = Provider(selectedAppCurrencyFlow::value),
isAccountsModeProvider = Provider { isAccountsMode }, isAccountsModeProvider = Provider { isAccountsMode },
isGaslessFeeSupportedForNetwork = isGaslessFeeSupportedForNetwork, isGaslessFeeSupportedForNetwork = isGaslessFeeSupportedForNetwork,
swapFeatureToggles = swapFeatureToggles,
appRouter = appRouter, appRouter = appRouter,
) )

View file

@ -36,7 +36,6 @@ internal data class SwapStateHolder(
val predefinedButtons: ImmutableList<PredefinedPercentButtonUM> = persistentListOf(), val predefinedButtons: ImmutableList<PredefinedPercentButtonUM> = persistentListOf(),
val tosState: TosState? = null, val tosState: TosState? = null,
val swapUIMode: SwapUIMode = SwapUIMode.Detailed, val swapUIMode: SwapUIMode = SwapUIMode.Detailed,
val shouldShowAbMenu: Boolean = false,
val transferFooter: TextReference? = null, val transferFooter: TextReference? = null,

View file

@ -52,7 +52,6 @@ import com.tangem.feature.swap.models.states.*
import com.tangem.feature.swap.presentation.R import com.tangem.feature.swap.presentation.R
import com.tangem.feature.swap.utils.formatToUIRepresentation import com.tangem.feature.swap.utils.formatToUIRepresentation
import com.tangem.features.send.api.subcomponents.feeSelector.entity.FeeSelectorUM import com.tangem.features.send.api.subcomponents.feeSelector.entity.FeeSelectorUM
import com.tangem.features.swap.SwapFeatureToggles
import com.tangem.utils.Provider import com.tangem.utils.Provider
import com.tangem.utils.StringsSigns import com.tangem.utils.StringsSigns
import com.tangem.utils.StringsSigns.DASH_SIGN import com.tangem.utils.StringsSigns.DASH_SIGN
@ -73,7 +72,6 @@ internal class StateBuilder(
private val appCurrencyProvider: Provider<AppCurrency>, private val appCurrencyProvider: Provider<AppCurrency>,
private val isAccountsModeProvider: Provider<Boolean>, private val isAccountsModeProvider: Provider<Boolean>,
private val isGaslessFeeSupportedForNetwork: IsGaslessFeeSupportedForNetwork, private val isGaslessFeeSupportedForNetwork: IsGaslessFeeSupportedForNetwork,
private val swapFeatureToggles: SwapFeatureToggles,
private val appRouter: AppRouter, private val appRouter: AppRouter,
) { ) {
private val iconStateConverter by lazy(::CryptoCurrencyToIconStateConverter) private val iconStateConverter by lazy(::CryptoCurrencyToIconStateConverter)
@ -124,7 +122,6 @@ internal class StateBuilder(
onSwapUIModeChange = actions.onSwapUIModeChange, onSwapUIModeChange = actions.onSwapUIModeChange,
onSwapTypeMenuOpened = actions.onSwapTypeMenuOpened, onSwapTypeMenuOpened = actions.onSwapTypeMenuOpened,
onTronBannerShown = actions.onTronBannerShown, onTronBannerShown = actions.onTronBannerShown,
shouldShowAbMenu = swapFeatureToggles.isSwapAbEnabled,
) )
} }
@ -737,16 +734,15 @@ internal class StateBuilder(
/** /**
* Builds the predefined percent buttons once per state update (off the composition path). * Builds the predefined percent buttons once per state update (off the composition path).
* The row is gated by the feature toggle; the MAX button is included only when * The MAX button is included only when [shouldShowMaxAmount] is `true` (e.g. it is dropped for a
* [shouldShowMaxAmount] is `true` (e.g. it is dropped for a native coin swapped within the same * native coin swapped within the same network, where spending the full balance would leave nothing
* network, where spending the full balance would leave nothing for the network fee). * for the network fee).
*/ */
private fun createPredefinedButtons( private fun createPredefinedButtons(
fromToken: CryptoCurrency?, fromToken: CryptoCurrency?,
toCurrency: CryptoCurrency?, toCurrency: CryptoCurrency?,
isTransferMode: Boolean = false, isTransferMode: Boolean = false,
): ImmutableList<PredefinedPercentButtonUM> { ): ImmutableList<PredefinedPercentButtonUM> {
if (!swapFeatureToggles.isSwapPredefinedButtonsEnabled) return persistentListOf()
val shouldShowMaxAmount = shouldShowMaxAmount(fromToken, toCurrency, isTransferMode) val shouldShowMaxAmount = shouldShowMaxAmount(fromToken, toCurrency, isTransferMode)
return PredefinedPercentAmount.entries return PredefinedPercentAmount.entries
.filter { it != PredefinedPercentAmount.MAX || shouldShowMaxAmount } .filter { it != PredefinedPercentAmount.MAX || shouldShowMaxAmount }
@ -1259,7 +1255,7 @@ internal class StateBuilder(
providerType == ExchangeProviderType.DEX.providerName || providerType == ExchangeProviderType.DEX.providerName ||
providerType == ExchangeProviderType.DEX_BRIDGE.providerName providerType == ExchangeProviderType.DEX_BRIDGE.providerName
} }
val availableFilters = if (swapFeatureToggles.isSwapProviderFilterEnabled && hasCex && hasDex) { val availableFilters = if (hasCex && hasDex) {
persistentListOf(ProviderFilterType.ALL, ProviderFilterType.CEX, ProviderFilterType.DEX) persistentListOf(ProviderFilterType.ALL, ProviderFilterType.CEX, ProviderFilterType.DEX)
} else { } else {
persistentListOf() persistentListOf()

View file

@ -85,44 +85,38 @@ private fun SwapTopBar(stateHolder: SwapStateHolder) {
AppBarWithBackButtonAndIcon( AppBarWithBackButtonAndIcon(
text = stringResourceSafe(stateHolder.titleId), text = stringResourceSafe(stateHolder.titleId),
backIconRes = R.drawable.ic_close_24, backIconRes = R.drawable.ic_close_24,
iconRes = if (stateHolder.shouldShowAbMenu) R.drawable.ic_more_vertical_24 else null, iconRes = R.drawable.ic_more_vertical_24,
onIconClick = if (stateHolder.shouldShowAbMenu) { onIconClick = {
{ stateHolder.onSwapTypeMenuOpened()
stateHolder.onSwapTypeMenuOpened() shouldShowModeMenu = true
shouldShowModeMenu = true
}
} else {
null
}, },
onBackClick = stateHolder.onBackClicked, onBackClick = stateHolder.onBackClicked,
) )
if (stateHolder.shouldShowAbMenu) { Box(modifier = Modifier.align(Alignment.TopEnd)) {
Box(modifier = Modifier.align(Alignment.TopEnd)) { TangemDropdownMenu(
TangemDropdownMenu( expanded = shouldShowModeMenu,
expanded = shouldShowModeMenu, modifier = Modifier.background(TangemTheme.colors.background.primary),
modifier = Modifier.background(TangemTheme.colors.background.primary), offset = DpOffset(x = TangemTheme.dimens.spacing20, y = 44.dp),
offset = DpOffset(x = TangemTheme.dimens.spacing20, y = 44.dp), onDismissRequest = { shouldShowModeMenu = false },
onDismissRequest = { shouldShowModeMenu = false }, content = {
content = { SwapUiModeMenuItem(
SwapUiModeMenuItem( title = stringResourceSafe(R.string.swap_simple_mode),
title = stringResourceSafe(R.string.swap_simple_mode), isSelected = stateHolder.swapUIMode == SwapUIMode.Simple,
isSelected = stateHolder.swapUIMode == SwapUIMode.Simple, onClick = {
onClick = { shouldShowModeMenu = false
shouldShowModeMenu = false stateHolder.onSwapUIModeChange(SwapUIMode.Simple)
stateHolder.onSwapUIModeChange(SwapUIMode.Simple) },
}, )
) SwapUiModeMenuItem(
SwapUiModeMenuItem( title = stringResourceSafe(R.string.swap_detailed_mode),
title = stringResourceSafe(R.string.swap_detailed_mode), isSelected = stateHolder.swapUIMode == SwapUIMode.Detailed,
isSelected = stateHolder.swapUIMode == SwapUIMode.Detailed, onClick = {
onClick = { shouldShowModeMenu = false
shouldShowModeMenu = false stateHolder.onSwapUIModeChange(SwapUIMode.Detailed)
stateHolder.onSwapUIModeChange(SwapUIMode.Detailed) },
}, )
) },
}, )
)
}
} }
} }
} }

View file

@ -18,7 +18,6 @@ import com.tangem.feature.swap.models.*
import com.tangem.feature.swap.models.states.ProviderState import com.tangem.feature.swap.models.states.ProviderState
import com.tangem.feature.swap.models.states.SwapNotificationUM import com.tangem.feature.swap.models.states.SwapNotificationUM
import com.tangem.feature.swap.ui.StateBuilder import com.tangem.feature.swap.ui.StateBuilder
import com.tangem.features.swap.SwapFeatureToggles
import com.tangem.utils.Provider import com.tangem.utils.Provider
import io.mockk.every import io.mockk.every
import io.mockk.mockk import io.mockk.mockk
@ -33,7 +32,6 @@ internal class StateBuilderInitialStateTest {
private val appCurrencyProvider: Provider<AppCurrency> = mockk() private val appCurrencyProvider: Provider<AppCurrency> = mockk()
private val isAccountsModeProvider: Provider<Boolean> = mockk() private val isAccountsModeProvider: Provider<Boolean> = mockk()
private val isGaslessFeeSupportedForNetwork: IsGaslessFeeSupportedForNetwork = mockk() private val isGaslessFeeSupportedForNetwork: IsGaslessFeeSupportedForNetwork = mockk()
private val swapFeatureToggles: SwapFeatureToggles = mockk(relaxed = true)
private val appRouter: AppRouter = mockk() private val appRouter: AppRouter = mockk()
private lateinit var sut: StateBuilder private lateinit var sut: StateBuilder
@ -52,7 +50,6 @@ internal class StateBuilderInitialStateTest {
appCurrencyProvider = appCurrencyProvider, appCurrencyProvider = appCurrencyProvider,
isAccountsModeProvider = isAccountsModeProvider, isAccountsModeProvider = isAccountsModeProvider,
isGaslessFeeSupportedForNetwork = isGaslessFeeSupportedForNetwork, isGaslessFeeSupportedForNetwork = isGaslessFeeSupportedForNetwork,
swapFeatureToggles = swapFeatureToggles,
appRouter = appRouter, appRouter = appRouter,
) )
} }

View file

@ -18,7 +18,6 @@ import com.tangem.feature.swap.models.*
import com.tangem.feature.swap.models.states.ProviderState import com.tangem.feature.swap.models.states.ProviderState
import com.tangem.feature.swap.models.states.SwapNotificationUM import com.tangem.feature.swap.models.states.SwapNotificationUM
import com.tangem.feature.swap.ui.StateBuilder import com.tangem.feature.swap.ui.StateBuilder
import com.tangem.features.swap.SwapFeatureToggles
import com.tangem.utils.Provider import com.tangem.utils.Provider
import io.mockk.every import io.mockk.every
import io.mockk.mockk import io.mockk.mockk
@ -33,7 +32,6 @@ internal class StateBuilderPairsTest {
private val appCurrencyProvider: Provider<AppCurrency> = mockk() private val appCurrencyProvider: Provider<AppCurrency> = mockk()
private val isAccountsModeProvider: Provider<Boolean> = mockk() private val isAccountsModeProvider: Provider<Boolean> = mockk()
private val isGaslessFeeSupportedForNetwork: IsGaslessFeeSupportedForNetwork = mockk() private val isGaslessFeeSupportedForNetwork: IsGaslessFeeSupportedForNetwork = mockk()
private val swapFeatureToggles: SwapFeatureToggles = mockk(relaxed = true)
private val appRouter: AppRouter = mockk() private val appRouter: AppRouter = mockk()
private lateinit var sut: StateBuilder private lateinit var sut: StateBuilder
@ -62,7 +60,6 @@ internal class StateBuilderPairsTest {
appCurrencyProvider = appCurrencyProvider, appCurrencyProvider = appCurrencyProvider,
isAccountsModeProvider = isAccountsModeProvider, isAccountsModeProvider = isAccountsModeProvider,
isGaslessFeeSupportedForNetwork = isGaslessFeeSupportedForNetwork, isGaslessFeeSupportedForNetwork = isGaslessFeeSupportedForNetwork,
swapFeatureToggles = swapFeatureToggles,
appRouter = appRouter, appRouter = appRouter,
) )
} }
@ -394,8 +391,7 @@ internal class StateBuilderPairsTest {
inner class PredefinedButtonsVisibility { inner class PredefinedButtonsVisibility {
@Test @Test
fun `GIVEN toggle on and native coin within same network WHEN updateCurrenciesState THEN MAX button is dropped but percents stay`() { fun `GIVEN native coin within same network WHEN updateCurrenciesState THEN MAX button is dropped but percents stay`() {
every { swapFeatureToggles.isSwapPredefinedButtonsEnabled } returns true
val baseState = buildReadyState(coldWallet) val baseState = buildReadyState(coldWallet)
val networkId: Network.ID = mockk(relaxed = true) val networkId: Network.ID = mockk(relaxed = true)
val fromStatus = buildCoinSwapCurrencyStatus(coldWallet, networkId) val fromStatus = buildCoinSwapCurrencyStatus(coldWallet, networkId)
@ -420,8 +416,7 @@ internal class StateBuilderPairsTest {
} }
@Test @Test
fun `GIVEN toggle on and non-coin WHEN updateCurrenciesState THEN all percents including MAX are built`() { fun `GIVEN non-coin WHEN updateCurrenciesState THEN all percents including MAX are built`() {
every { swapFeatureToggles.isSwapPredefinedButtonsEnabled } returns true
val baseState = buildReadyState(coldWallet) val baseState = buildReadyState(coldWallet)
val fromStatus = buildSwapCurrencyStatus(coldWallet) val fromStatus = buildSwapCurrencyStatus(coldWallet)
val toStatus = buildSwapCurrencyStatus(coldWallet) val toStatus = buildSwapCurrencyStatus(coldWallet)
@ -440,24 +435,6 @@ internal class StateBuilderPairsTest {
.inOrder() .inOrder()
} }
@Test
fun `GIVEN toggle off WHEN updateCurrenciesState THEN no predefined buttons are built`() {
every { swapFeatureToggles.isSwapPredefinedButtonsEnabled } returns false
val baseState = buildReadyState(coldWallet)
val fromStatus = buildSwapCurrencyStatus(coldWallet)
val toStatus = buildSwapCurrencyStatus(coldWallet)
val result = sut.updateCurrenciesState(
uiStateHolder = baseState,
emptyAmountState = emptyAmountState,
fromSwapCurrencyStatus = fromStatus,
toSwapCurrencyStatus = toStatus,
shouldResetAmount = false,
)
assertThat(result.predefinedButtons).isEmpty()
}
@Test @Test
fun `WHEN createInitialLoadingState THEN no predefined buttons are built`() { fun `WHEN createInitialLoadingState THEN no predefined buttons are built`() {
val result = sut.createInitialLoadingState() val result = sut.createInitialLoadingState()

View file

@ -25,7 +25,6 @@ import com.tangem.feature.swap.domain.models.ui.*
import com.tangem.feature.swap.models.* import com.tangem.feature.swap.models.*
import com.tangem.feature.swap.models.states.ProviderState import com.tangem.feature.swap.models.states.ProviderState
import com.tangem.feature.swap.ui.StateBuilder import com.tangem.feature.swap.ui.StateBuilder
import com.tangem.features.swap.SwapFeatureToggles
import com.tangem.utils.Provider import com.tangem.utils.Provider
import io.mockk.every import io.mockk.every
import io.mockk.mockk import io.mockk.mockk
@ -59,7 +58,6 @@ internal class StateBuilderSwapButtonTest {
private val appCurrencyProvider: Provider<AppCurrency> = mockk() private val appCurrencyProvider: Provider<AppCurrency> = mockk()
private val isAccountsModeProvider: Provider<Boolean> = mockk() private val isAccountsModeProvider: Provider<Boolean> = mockk()
private val isGaslessFeeSupportedForNetwork: IsGaslessFeeSupportedForNetwork = mockk() private val isGaslessFeeSupportedForNetwork: IsGaslessFeeSupportedForNetwork = mockk()
private val swapFeatureToggles: SwapFeatureToggles = mockk(relaxed = true)
private val appRouter: AppRouter = mockk() private val appRouter: AppRouter = mockk()
private lateinit var sut: StateBuilder private lateinit var sut: StateBuilder
@ -81,7 +79,6 @@ internal class StateBuilderSwapButtonTest {
appCurrencyProvider = appCurrencyProvider, appCurrencyProvider = appCurrencyProvider,
isAccountsModeProvider = isAccountsModeProvider, isAccountsModeProvider = isAccountsModeProvider,
isGaslessFeeSupportedForNetwork = isGaslessFeeSupportedForNetwork, isGaslessFeeSupportedForNetwork = isGaslessFeeSupportedForNetwork,
swapFeatureToggles = swapFeatureToggles,
appRouter = appRouter, appRouter = appRouter,
) )
} }

View file

@ -17,7 +17,6 @@ import com.tangem.feature.swap.models.SwapStateHolder
import com.tangem.feature.swap.models.TransactionCardType import com.tangem.feature.swap.models.TransactionCardType
import com.tangem.feature.swap.models.UiActions import com.tangem.feature.swap.models.UiActions
import com.tangem.feature.swap.ui.StateBuilder import com.tangem.feature.swap.ui.StateBuilder
import com.tangem.features.swap.SwapFeatureToggles
import com.tangem.utils.Provider import com.tangem.utils.Provider
import io.mockk.every import io.mockk.every
import io.mockk.mockk import io.mockk.mockk
@ -34,7 +33,6 @@ internal class StateBuilderUpdateSwapAmountTest {
private val appCurrencyProvider: Provider<AppCurrency> = mockk() private val appCurrencyProvider: Provider<AppCurrency> = mockk()
private val isAccountsModeProvider: Provider<Boolean> = mockk() private val isAccountsModeProvider: Provider<Boolean> = mockk()
private val isGaslessFeeSupportedForNetwork: IsGaslessFeeSupportedForNetwork = mockk() private val isGaslessFeeSupportedForNetwork: IsGaslessFeeSupportedForNetwork = mockk()
private val swapFeatureToggles: SwapFeatureToggles = mockk(relaxed = true)
private val appRouter: AppRouter = mockk() private val appRouter: AppRouter = mockk()
private val appCurrency = AppCurrency.Default private val appCurrency = AppCurrency.Default
@ -58,7 +56,6 @@ internal class StateBuilderUpdateSwapAmountTest {
appCurrencyProvider = appCurrencyProvider, appCurrencyProvider = appCurrencyProvider,
isAccountsModeProvider = isAccountsModeProvider, isAccountsModeProvider = isAccountsModeProvider,
isGaslessFeeSupportedForNetwork = isGaslessFeeSupportedForNetwork, isGaslessFeeSupportedForNetwork = isGaslessFeeSupportedForNetwork,
swapFeatureToggles = swapFeatureToggles,
appRouter = appRouter, appRouter = appRouter,
) )
} }

View file

@ -21,7 +21,6 @@ import com.tangem.common.ui.bottomsheet.receive.mapToAddressModels
import com.tangem.features.rating.RatingComponent import com.tangem.features.rating.RatingComponent
import com.tangem.feature.swap.domain.SwapFeedbackUseCase import com.tangem.feature.swap.domain.SwapFeedbackUseCase
import com.tangem.feature.swap.domain.models.domain.SwapFeedbackParams import com.tangem.feature.swap.domain.models.domain.SwapFeedbackParams
import com.tangem.features.swap.SwapFeatureToggles
import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.analytics.models.AnalyticsParam import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.core.analytics.models.event.OfframpAnalyticsEvent import com.tangem.core.analytics.models.event.OfframpAnalyticsEvent
@ -202,7 +201,6 @@ internal class TokenDetailsModel @Inject constructor(
private val designFeatureToggles: DesignFeatureToggles, private val designFeatureToggles: DesignFeatureToggles,
private val redesignStateController: TokenDetailsStateController, private val redesignStateController: TokenDetailsStateController,
private val swapFeedbackUseCase: SwapFeedbackUseCase, private val swapFeedbackUseCase: SwapFeedbackUseCase,
private val swapFeatureToggles: SwapFeatureToggles,
private val quickTopUpBlockFactory: QuickTopUpBlockFactory, private val quickTopUpBlockFactory: QuickTopUpBlockFactory,
private val getFixedTxHistoryItemsUseCase: GetFixedTxHistoryItemsUseCase, private val getFixedTxHistoryItemsUseCase: GetFixedTxHistoryItemsUseCase,
private val checkOnrampAvailabilityUseCase: CheckOnrampAvailabilityUseCase, private val checkOnrampAvailabilityUseCase: CheckOnrampAvailabilityUseCase,
@ -1182,7 +1180,6 @@ internal class TokenDetailsModel @Inject constructor(
txExternalUrl: String, txExternalUrl: String,
userWalletIdStringValue: String, userWalletIdStringValue: String,
) { ) {
if (!swapFeatureToggles.isSwapRateExperienceEnabled) return
ratingSlotNavigation.activate( ratingSlotNavigation.activate(
RatingComponent.Params( RatingComponent.Params(
onLoadRating = { onLoadRating = {