diff --git a/core/ui/src/main/res/drawable/ic_stack_new_24.xml b/core/ui/src/main/res/drawable/ic_stack_new_24.xml
new file mode 100644
index 0000000000..a0a35fc823
--- /dev/null
+++ b/core/ui/src/main/res/drawable/ic_stack_new_24.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
diff --git a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/SwapAmountBlockComponent.kt b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/SwapAmountBlockComponent.kt
index dbbf511732..5917c12bf3 100644
--- a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/SwapAmountBlockComponent.kt
+++ b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/SwapAmountBlockComponent.kt
@@ -17,6 +17,7 @@ import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.domain.express.models.ExpressProvider
import com.tangem.domain.models.currency.CryptoCurrency
+import com.tangem.domain.settings.usercountry.models.UserCountry
import com.tangem.features.swap.v2.impl.amount.SwapAmountComponentParams.AmountBlockParams
import com.tangem.features.swap.v2.impl.amount.entity.SwapAmountUM
import com.tangem.features.swap.v2.impl.amount.model.SwapAmountModel
@@ -77,6 +78,7 @@ internal class SwapAmountBlockComponent(
providers = amountUM.swapQuotes,
cryptoCurrency = cryptoCurrency,
selectedProvider = selectedProvider,
+ userCountry = model.userCountry,
),
)
},
@@ -95,6 +97,7 @@ internal class SwapAmountBlockComponent(
providers = config.providers,
cryptoCurrency = config.cryptoCurrency,
selectedProvider = config.selectedProvider,
+ userCountry = config.userCountry,
callback = model,
onDismiss = { model.bottomSheetNavigation.dismiss() },
),
@@ -105,5 +108,6 @@ internal class SwapAmountBlockComponent(
val providers: ImmutableList,
val cryptoCurrency: CryptoCurrency,
val selectedProvider: ExpressProvider,
+ val userCountry: UserCountry,
)
}
\ No newline at end of file
diff --git a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/model/SwapAmountModel.kt b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/model/SwapAmountModel.kt
index dfc08a58f3..23c478c056 100644
--- a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/model/SwapAmountModel.kt
+++ b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/model/SwapAmountModel.kt
@@ -17,6 +17,8 @@ import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.express.models.ExpressError
import com.tangem.domain.models.currency.CryptoCurrency
+import com.tangem.domain.settings.usercountry.GetUserCountryUseCase
+import com.tangem.domain.settings.usercountry.models.UserCountry
import com.tangem.domain.swap.models.SwapCurrencies
import com.tangem.domain.swap.models.SwapDirection
import com.tangem.domain.swap.models.SwapDirection.Companion.withSwapDirection
@@ -54,6 +56,7 @@ import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import timber.log.Timber
import java.math.BigDecimal
+import java.util.Locale
import javax.inject.Inject
import kotlin.properties.Delegates
import com.tangem.utils.transformer.update as transformerUpdate
@@ -69,6 +72,7 @@ internal class SwapAmountModel @Inject constructor(
private val swapChooseTokenNetworkListener: SwapChooseTokenNetworkListener,
private val getAllowanceUseCase: GetAllowanceUseCase,
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
+ private val getUserCountryUseCase: GetUserCountryUseCase,
private val appRouter: AppRouter,
private val swapAmountAlertFactory: SwapAmountAlertFactory,
private val swapAlertFactory: SwapAlertFactory,
@@ -89,6 +93,7 @@ internal class SwapAmountModel @Inject constructor(
private var secondaryMaximumAmountBoundary: EnterAmountBoundary? = null
private var secondaryMinimumAmountBoundary: EnterAmountBoundary? = null
+ var userCountry: UserCountry = UserCountry.Other(Locale.getDefault().country)
val bottomSheetNavigation: SlotNavigation = SlotNavigation()
val uiState: StateFlow
@@ -100,6 +105,8 @@ internal class SwapAmountModel @Inject constructor(
init {
modelScope.launch {
appCurrency = getSelectedAppCurrencyUseCase.invokeSync().getOrElse { AppCurrency.Default }
+ userCountry = getUserCountryUseCase.invokeSync().getOrNull()
+ ?: UserCountry.Other(Locale.getDefault().country)
}
configAmountNavigation()
subscribeOnCryptoCurrencyStatusFlow()
diff --git a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/chooseprovider/SwapChooseProviderComponent.kt b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/chooseprovider/SwapChooseProviderComponent.kt
index 744a8a3c91..c04a88654c 100644
--- a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/chooseprovider/SwapChooseProviderComponent.kt
+++ b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/chooseprovider/SwapChooseProviderComponent.kt
@@ -10,6 +10,7 @@ import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
import com.tangem.domain.express.models.ExpressProvider
import com.tangem.domain.models.currency.CryptoCurrency
+import com.tangem.domain.settings.usercountry.models.UserCountry
import com.tangem.features.swap.v2.impl.chooseprovider.model.SwapChooseProviderModel
import com.tangem.features.swap.v2.impl.chooseprovider.ui.SwapChooseProviderBottomSheet
import com.tangem.features.swap.v2.impl.chooseprovider.ui.SwapChooseProviderContent
@@ -41,7 +42,7 @@ internal class SwapChooseProviderComponent(
SwapChooseProviderBottomSheet(config = bottomSheetConfig) {
SwapChooseProviderContent(
- providerList = state.value.providerList,
+ contentUM = state.value,
onProviderClick = model::onProviderClick,
)
}
@@ -51,6 +52,7 @@ internal class SwapChooseProviderComponent(
val cryptoCurrency: CryptoCurrency,
val selectedProvider: ExpressProvider,
val providers: ImmutableList,
+ val userCountry: UserCountry,
val callback: ModelCallback,
val onDismiss: () -> Unit,
)
diff --git a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/chooseprovider/entity/SwapChooseProviderBottomSheetContent.kt b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/chooseprovider/entity/SwapChooseProviderBottomSheetContent.kt
index ad5eb47e18..289afe2a26 100644
--- a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/chooseprovider/entity/SwapChooseProviderBottomSheetContent.kt
+++ b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/chooseprovider/entity/SwapChooseProviderBottomSheetContent.kt
@@ -7,6 +7,7 @@ import kotlinx.collections.immutable.ImmutableList
internal data class SwapChooseProviderBottomSheetContent(
val providerList: ImmutableList,
+ val isApplyFCARestrictions: Boolean,
val selectedProvider: ExpressProvider,
)
diff --git a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/chooseprovider/model/SwapChooseProviderModel.kt b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/chooseprovider/model/SwapChooseProviderModel.kt
index 5b9ce17796..c4bf3d574e 100644
--- a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/chooseprovider/model/SwapChooseProviderModel.kt
+++ b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/chooseprovider/model/SwapChooseProviderModel.kt
@@ -3,10 +3,12 @@ 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.settings.usercountry.models.needApplyFCARestrictions
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
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 kotlinx.collections.immutable.toPersistentList
import kotlinx.coroutines.flow.MutableStateFlow
@@ -21,10 +23,13 @@ internal class SwapChooseProviderModel @Inject constructor(
private val params: SwapChooseProviderComponent.Params = paramsContainer.require()
+ private val needApplyFCARestrictions = params.userCountry.needApplyFCARestrictions()
+
private val swapProviderListItemConverter by lazy(LazyThreadSafetyMode.NONE) {
SwapProviderListItemConverter(
cryptoCurrency = params.cryptoCurrency,
selectedProvider = params.selectedProvider,
+ needApplyFCARestrictions = needApplyFCARestrictions,
)
}
@@ -38,6 +43,7 @@ internal class SwapChooseProviderModel @Inject constructor(
private fun getInitialState(): SwapChooseProviderBottomSheetContent {
return SwapChooseProviderBottomSheetContent(
+ isApplyFCARestrictions = needApplyFCARestrictions && params.selectedProvider.isRestrictedByFCA(),
providerList = swapProviderListItemConverter.convertList(params.providers)
.filterNotNull()
.toPersistentList(),
diff --git a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/chooseprovider/model/converter/SwapProviderListItemConverter.kt b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/chooseprovider/model/converter/SwapProviderListItemConverter.kt
index 75234f816b..e7f45e0726 100644
--- a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/chooseprovider/model/converter/SwapProviderListItemConverter.kt
+++ b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/chooseprovider/model/converter/SwapProviderListItemConverter.kt
@@ -15,11 +15,13 @@ import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.features.swap.v2.impl.R
import com.tangem.features.swap.v2.impl.chooseprovider.entity.SwapProviderListItem
import com.tangem.features.swap.v2.impl.common.entity.SwapQuoteUM
+import com.tangem.features.swap.v2.impl.common.isRestrictedByFCA
import com.tangem.utils.converter.Converter
internal class SwapProviderListItemConverter(
private val cryptoCurrency: CryptoCurrency,
private val selectedProvider: ExpressProvider,
+ private val needApplyFCARestrictions: Boolean,
) : Converter {
override fun convert(value: SwapQuoteUM): SwapProviderListItem? {
val provider = value.provider ?: return null
@@ -66,9 +68,15 @@ internal class SwapProviderListItemConverter(
},
)
}
+ is SwapQuoteUM.Content -> if (needApplyFCARestrictions && value.provider.isRestrictedByFCA()) {
+ ProviderChooseUM.ExtraUM.Action(
+ text = resourceReference(R.string.express_provider_fca_warning_list),
+ )
+ } else {
+ ProviderChooseUM.ExtraUM.Empty
+ }
SwapQuoteUM.Empty,
SwapQuoteUM.Loading,
- is SwapQuoteUM.Content,
-> ProviderChooseUM.ExtraUM.Empty
}
diff --git a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/chooseprovider/ui/SwapChooseProviderBottomSheet.kt b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/chooseprovider/ui/SwapChooseProviderBottomSheet.kt
index 46ab92931b..11d0e32879 100644
--- a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/chooseprovider/ui/SwapChooseProviderBottomSheet.kt
+++ b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/chooseprovider/ui/SwapChooseProviderBottomSheet.kt
@@ -1,6 +1,7 @@
package com.tangem.features.swap.v2.impl.chooseprovider.ui
import android.content.res.Configuration
+import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Icon
@@ -19,6 +20,7 @@ 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.ProviderChooseCrypto
import com.tangem.core.ui.extensions.conditional
import com.tangem.core.ui.extensions.resourceReference
@@ -27,10 +29,9 @@ import com.tangem.core.ui.res.TangemTheme
import com.tangem.core.ui.res.TangemThemePreview
import com.tangem.features.swap.v2.impl.R
import com.tangem.features.swap.v2.impl.chooseprovider.entity.SwapChooseProviderBottomSheetContent
-import com.tangem.features.swap.v2.impl.chooseprovider.entity.SwapProviderListItem
import com.tangem.features.swap.v2.impl.chooseprovider.ui.preview.SwapChooseProviderContentPreview
import com.tangem.features.swap.v2.impl.common.entity.SwapQuoteUM
-import kotlinx.collections.immutable.ImmutableList
+import com.tangem.features.swap.v2.impl.notifications.entity.SwapNotificationUM
@Composable
internal fun SwapChooseProviderBottomSheet(config: TangemBottomSheetConfig, content: @Composable () -> Unit) {
@@ -50,7 +51,7 @@ internal fun SwapChooseProviderBottomSheet(config: TangemBottomSheetConfig, cont
@Composable
internal fun SwapChooseProviderContent(
- providerList: ImmutableList,
+ contentUM: SwapChooseProviderBottomSheetContent,
onProviderClick: (SwapQuoteUM) -> Unit,
modifier: Modifier = Modifier,
) {
@@ -64,7 +65,17 @@ internal fun SwapChooseProviderContent(
color = TangemTheme.colors.text.secondary,
textAlign = TextAlign.Center,
)
- providerList.fastForEachIndexed { index, provider ->
+ AnimatedVisibility(
+ modifier = Modifier.padding(top = 12.dp),
+ visible = contentUM.isApplyFCARestrictions,
+ ) {
+ Notification(
+ config = SwapNotificationUM.Error.FCAWarningList.config,
+ containerColor = TangemTheme.colors.button.disabled,
+ iconTint = TangemTheme.colors.icon.warning,
+ )
+ }
+ contentUM.providerList.fastForEachIndexed { index, provider ->
ProviderChooseCrypto(
providerChooseUM = provider.providerUM,
onClick = { onProviderClick(provider.quote) },
@@ -114,7 +125,11 @@ private fun SwapChooseProviderContent_Preview(
),
) {
SwapChooseProviderContent(
- providerList = params.providerList,
+ contentUM = SwapChooseProviderBottomSheetContent(
+ providerList = params.providerList,
+ isApplyFCARestrictions = true,
+ selectedProvider = SwapChooseProviderContentPreview.provider1,
+ ),
onProviderClick = {},
)
}
diff --git a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/chooseprovider/ui/preview/SwapChooseProviderContentPreview.kt b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/chooseprovider/ui/preview/SwapChooseProviderContentPreview.kt
index b96c7acb4b..dd75bbf62c 100644
--- a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/chooseprovider/ui/preview/SwapChooseProviderContentPreview.kt
+++ b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/chooseprovider/ui/preview/SwapChooseProviderContentPreview.kt
@@ -16,7 +16,7 @@ import java.math.BigDecimal
internal object SwapChooseProviderContentPreview {
- private val provider1 = ExpressProvider(
+ val provider1 = ExpressProvider(
providerId = "changenow",
rateTypes = listOf(ExpressRateType.Float),
name = "ChangeNow",
@@ -88,5 +88,6 @@ internal object SwapChooseProviderContentPreview {
),
),
selectedProvider = provider1,
+ isApplyFCARestrictions = false,
)
}
\ No newline at end of file
diff --git a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/common/SwapProviderUtils.kt b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/common/SwapProviderUtils.kt
new file mode 100644
index 0000000000..6c9e8ece21
--- /dev/null
+++ b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/common/SwapProviderUtils.kt
@@ -0,0 +1,13 @@
+package com.tangem.features.swap.v2.impl.common
+
+import com.tangem.domain.express.models.ExpressProvider
+
+private val FCA_RESTRICTED_PROVIDER_IDS = setOf(
+ "changelly",
+ "changenow",
+ "okx-cross-chain",
+ "okx-on-chain",
+ "simpleswap",
+)
+
+fun ExpressProvider.isRestrictedByFCA() = FCA_RESTRICTED_PROVIDER_IDS.contains(providerId)
\ No newline at end of file