diff --git a/app/src/main/java/com/tangem/tap/di/domain/OnrampDomainModule.kt b/app/src/main/java/com/tangem/tap/di/domain/OnrampDomainModule.kt
index f5c4fda538..18f3540843 100644
--- a/app/src/main/java/com/tangem/tap/di/domain/OnrampDomainModule.kt
+++ b/app/src/main/java/com/tangem/tap/di/domain/OnrampDomainModule.kt
@@ -1,11 +1,7 @@
package com.tangem.tap.di.domain
-import com.tangem.domain.onramp.repositories.LegacyTopUpRepository
import com.tangem.domain.onramp.*
-import com.tangem.domain.onramp.repositories.HotCryptoRepository
-import com.tangem.domain.onramp.repositories.OnrampErrorResolver
-import com.tangem.domain.onramp.repositories.OnrampRepository
-import com.tangem.domain.onramp.repositories.OnrampTransactionRepository
+import com.tangem.domain.onramp.repositories.*
import com.tangem.domain.settings.repositories.SettingsRepository
import dagger.Module
import dagger.Provides
@@ -237,4 +233,32 @@ internal object OnrampDomainModule {
fun provideGetLegacyTopUpUrlUseCase(legacyTopUpRepository: LegacyTopUpRepository): GetLegacyTopUpUrlUseCase {
return GetLegacyTopUpUrlUseCase(legacyTopUpRepository)
}
+
+ @Provides
+ @Singleton
+ fun provideGetOnrampAllOffersUseCase(
+ onrampRepository: OnrampRepository,
+ onrampErrorResolver: OnrampErrorResolver,
+ settingsRepository: SettingsRepository,
+ ): GetOnrampAllOffersUseCase {
+ return GetOnrampAllOffersUseCase(
+ onrampRepository = onrampRepository,
+ errorResolver = onrampErrorResolver,
+ settingsRepository = settingsRepository,
+ )
+ }
+
+ @Provides
+ @Singleton
+ fun provideGetOnrampOffersUseCase(
+ onrampRepository: OnrampRepository,
+ onrampErrorResolver: OnrampErrorResolver,
+ onrampTransactionRepository: OnrampTransactionRepository,
+ ): GetOnrampOffersUseCase {
+ return GetOnrampOffersUseCase(
+ onrampRepository = onrampRepository,
+ errorResolver = onrampErrorResolver,
+ onrampTransactionRepository = onrampTransactionRepository,
+ )
+ }
}
\ No newline at end of file
diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml
index 7d747732ea..b475fe441f 100644
--- a/core/res/src/main/res/values/strings.xml
+++ b/core/res/src/main/res/values/strings.xml
@@ -876,7 +876,10 @@
Payment method
Available up to %s
Available from %s
- %d providers
+
+ - %d provider
+ - %d providers
+
Providers
Recently used
Recommended
diff --git a/core/ui/src/main/res/drawable/ic_best_rate_16.xml b/core/ui/src/main/res/drawable/ic_best_rate_16.xml
new file mode 100644
index 0000000000..7e36b66936
--- /dev/null
+++ b/core/ui/src/main/res/drawable/ic_best_rate_16.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/core/ui/src/main/res/drawable/ic_fastest_16.xml b/core/ui/src/main/res/drawable/ic_fastest_16.xml
new file mode 100644
index 0000000000..072444ff1d
--- /dev/null
+++ b/core/ui/src/main/res/drawable/ic_fastest_16.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/domain/onramp/models/src/main/kotlin/com/tangem/domain/onramp/model/OnrampOffer.kt b/domain/onramp/models/src/main/kotlin/com/tangem/domain/onramp/model/OnrampOffer.kt
index e116e55735..56700b01f4 100644
--- a/domain/onramp/models/src/main/kotlin/com/tangem/domain/onramp/model/OnrampOffer.kt
+++ b/domain/onramp/models/src/main/kotlin/com/tangem/domain/onramp/model/OnrampOffer.kt
@@ -1,13 +1,16 @@
package com.tangem.domain.onramp.model
+import java.math.BigDecimal
+
data class OnrampOffersBlock(
val category: OnrampOfferCategory,
val offers: List,
- val isVisible: Boolean = offers.isNotEmpty(),
+ val hasMoreOffers: Boolean,
)
data class OnrampOffer(
val quote: OnrampQuote,
+ val rateDif: BigDecimal?,
val advantages: OnrampOfferAdvantages = OnrampOfferAdvantages.Default,
)
diff --git a/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampAllOffersUseCase.kt b/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampAllOffersUseCase.kt
index 6cc1247867..f2f787e182 100644
--- a/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampAllOffersUseCase.kt
+++ b/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampAllOffersUseCase.kt
@@ -12,6 +12,7 @@ import com.tangem.domain.onramp.model.OnrampQuote
import com.tangem.domain.onramp.model.error.OnrampError
import com.tangem.domain.onramp.repositories.OnrampErrorResolver
import com.tangem.domain.onramp.repositories.OnrampRepository
+import com.tangem.domain.onramp.utils.calculateRateDif
import com.tangem.domain.settings.repositories.SettingsRepository
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.map
@@ -38,6 +39,7 @@ class GetOnrampAllOffersUseCase(
val isGooglePayAvailable = settingsRepository.isGooglePayAvailability()
val overallBestRateQuote = validQuotes.maxByOrNull { it.toAmount.value }
+ val bestRate = overallBestRateQuote?.toAmount?.value
val offersByPaymentMethod = validQuotes.groupBy { it.paymentMethod }
@@ -48,7 +50,8 @@ class GetOnrampAllOffersUseCase(
} else {
OnrampOfferAdvantages.Default
}
- OnrampOffer(quote = quote, advantages = advantages)
+ val rateDif = calculateRateDif(quote.toAmount.value, bestRate)
+ OnrampOffer(quote = quote, rateDif = rateDif, advantages = advantages)
}
val groupBestRateOfferData = methodQuotes.maxByOrNull { it.toAmount.value }
diff --git a/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampOffersUseCase.kt b/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampOffersUseCase.kt
index 29041336a9..1632abd3cc 100644
--- a/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampOffersUseCase.kt
+++ b/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampOffersUseCase.kt
@@ -11,6 +11,7 @@ import com.tangem.domain.onramp.model.error.OnrampError
import com.tangem.domain.onramp.repositories.OnrampErrorResolver
import com.tangem.domain.onramp.repositories.OnrampRepository
import com.tangem.domain.onramp.repositories.OnrampTransactionRepository
+import com.tangem.domain.onramp.utils.calculateRateDif
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map
@@ -43,8 +44,12 @@ class GetOnrampOffersUseCase(
val validQuotes = quotes.filterIsInstance()
if (validQuotes.isEmpty()) return emptyList()
+ val bestRateQuote = validQuotes.maxByOrNull { it.toAmount.value }
+ val bestRate = bestRateQuote?.toAmount?.value
+
val offers = validQuotes.map { quote ->
- OnrampOffer(quote = quote)
+ val rateDif = calculateRateDif(quote.toAmount.value, bestRate)
+ OnrampOffer(quote = quote, rateDif = rateDif)
}
val recentOffer = findRecentOffer(offers, transactions)
@@ -107,6 +112,15 @@ class GetOnrampOffersUseCase(
fastestOffer: OnrampOffer?,
allOffers: List,
): List {
+ val recommendedOffers = buildRecommendedOffers(
+ recentOffer = recentOffer,
+ bestRateOffer = bestRateOffer,
+ fastestOffer = fastestOffer,
+ )
+
+ val shownOffersCount = (if (recentOffer != null) 1 else 0) + recommendedOffers.size
+ val hasMoreOffers = allOffers.size > shownOffersCount
+
return buildList {
if (recentOffer != null) {
add(
@@ -119,23 +133,20 @@ class GetOnrampOffersUseCase(
bestRateOffer,
fastestOffer,
),
+ rateDif = if (bestRateOffer != null) recentOffer.rateDif else null,
),
),
+ hasMoreOffers = false,
),
)
}
- val recommendedOffers = buildRecommendedOffers(
- recentOffer = recentOffer,
- bestRateOffer = bestRateOffer,
- fastestOffer = fastestOffer,
- )
-
if (recommendedOffers.isNotEmpty() && hasOnlyOneMethodAndProvider(allOffers).not()) {
add(
OnrampOffersBlock(
category = OnrampOfferCategory.Recommended,
offers = recommendedOffers,
+ hasMoreOffers = hasMoreOffers,
),
)
}
@@ -167,17 +178,32 @@ class GetOnrampOffersUseCase(
return buildList {
if (isSameOffer(bestRateOffer, fastestOffer)) {
bestRateOffer?.let { offer ->
- add(offer.copy(advantages = OnrampOfferAdvantages.BestRate))
+ add(
+ offer.copy(
+ advantages = OnrampOfferAdvantages.BestRate,
+ rateDif = null,
+ ),
+ )
}
} else {
if (bestRateOffer != null && !isSameOffer(bestRateOffer, recentOffer)) {
- add(bestRateOffer.copy(advantages = OnrampOfferAdvantages.BestRate))
+ add(
+ bestRateOffer.copy(
+ advantages = OnrampOfferAdvantages.BestRate,
+ rateDif = null,
+ ),
+ )
}
if (fastestOffer != null && !isSameOffer(fastestOffer, recentOffer) &&
!isSameOffer(fastestOffer, bestRateOffer)
) {
- add(fastestOffer.copy(advantages = OnrampOfferAdvantages.Fastest))
+ add(
+ fastestOffer.copy(
+ advantages = OnrampOfferAdvantages.Fastest,
+ rateDif = if (bestRateOffer != null) fastestOffer.rateDif else null,
+ ),
+ )
}
}
}
diff --git a/domain/onramp/src/main/java/com/tangem/domain/onramp/utils/OnrampOfferUtils.kt b/domain/onramp/src/main/java/com/tangem/domain/onramp/utils/OnrampOfferUtils.kt
new file mode 100644
index 0000000000..0b3625d494
--- /dev/null
+++ b/domain/onramp/src/main/java/com/tangem/domain/onramp/utils/OnrampOfferUtils.kt
@@ -0,0 +1,8 @@
+package com.tangem.domain.onramp.utils
+
+import java.math.BigDecimal
+
+internal fun calculateRateDif(currentTokenRate: BigDecimal, bestRate: BigDecimal?): BigDecimal? {
+ if (bestRate == null) return null
+ return BigDecimal.ONE - currentTokenRate / bestRate
+}
\ No newline at end of file
diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/alloffers/AllOffersComponent.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/alloffers/AllOffersComponent.kt
new file mode 100644
index 0000000000..7c2de6da52
--- /dev/null
+++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/alloffers/AllOffersComponent.kt
@@ -0,0 +1,17 @@
+package com.tangem.features.onramp.alloffers
+
+import com.tangem.core.decompose.factory.ComponentFactory
+import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
+import com.tangem.domain.models.currency.CryptoCurrency
+import com.tangem.domain.models.wallet.UserWallet
+
+internal interface AllOffersComponent : ComposableBottomSheetComponent {
+
+ data class Params(
+ val userWallet: UserWallet,
+ val cryptoCurrency: CryptoCurrency,
+ val onDismiss: () -> Unit,
+ )
+
+ interface Factory : ComponentFactory
+}
\ No newline at end of file
diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/alloffers/DefaultAllOffersComponent.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/alloffers/DefaultAllOffersComponent.kt
new file mode 100644
index 0000000000..02adaaa504
--- /dev/null
+++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/alloffers/DefaultAllOffersComponent.kt
@@ -0,0 +1,31 @@
+package com.tangem.features.onramp.alloffers
+
+import androidx.compose.runtime.Composable
+import com.tangem.core.decompose.context.AppComponentContext
+import com.tangem.core.decompose.model.getOrCreateModel
+import com.tangem.features.onramp.alloffers.model.AllOffersModel
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+
+internal class DefaultAllOffersComponent @AssistedInject constructor(
+ @Assisted context: AppComponentContext,
+ @Assisted params: AllOffersComponent.Params,
+) : AllOffersComponent, AppComponentContext by context {
+
+ private val model: AllOffersModel = getOrCreateModel(params)
+
+ override fun dismiss() {
+ model.dismiss()
+ }
+
+ @Composable
+ override fun BottomSheet() {
+ // TODO to be continued in [REDACTED_TASK_KEY]
+ }
+
+ @AssistedFactory
+ interface Factory : AllOffersComponent.Factory {
+ override fun create(context: AppComponentContext, params: AllOffersComponent.Params): DefaultAllOffersComponent
+ }
+}
\ No newline at end of file
diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/alloffers/di/AllOffersComponentModelModule.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/alloffers/di/AllOffersComponentModelModule.kt
new file mode 100644
index 0000000000..e709ab73d6
--- /dev/null
+++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/alloffers/di/AllOffersComponentModelModule.kt
@@ -0,0 +1,20 @@
+package com.tangem.features.onramp.alloffers.di
+
+import com.tangem.core.decompose.di.ModelComponent
+import com.tangem.core.decompose.model.Model
+import com.tangem.features.onramp.alloffers.model.AllOffersModel
+import dagger.Binds
+import dagger.Module
+import dagger.hilt.InstallIn
+import dagger.multibindings.ClassKey
+import dagger.multibindings.IntoMap
+
+@Module
+@InstallIn(ModelComponent::class)
+internal interface AllOffersComponentModelModule {
+
+ @Binds
+ @IntoMap
+ @ClassKey(AllOffersModel::class)
+ fun bindAllOffersModel(model: AllOffersModel): Model
+}
\ No newline at end of file
diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/alloffers/di/AllOffersComponentModule.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/alloffers/di/AllOffersComponentModule.kt
new file mode 100644
index 0000000000..3979f343c2
--- /dev/null
+++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/alloffers/di/AllOffersComponentModule.kt
@@ -0,0 +1,18 @@
+package com.tangem.features.onramp.alloffers.di
+
+import com.tangem.features.onramp.alloffers.AllOffersComponent
+import com.tangem.features.onramp.alloffers.DefaultAllOffersComponent
+import dagger.Binds
+import dagger.Module
+import dagger.hilt.InstallIn
+import dagger.hilt.components.SingletonComponent
+import javax.inject.Singleton
+
+@Module
+@InstallIn(SingletonComponent::class)
+internal interface AllOffersComponentModule {
+
+ @Binds
+ @Singleton
+ fun bindAllOffersComponentFactory(factory: DefaultAllOffersComponent.Factory): AllOffersComponent.Factory
+}
\ No newline at end of file
diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/alloffers/model/AllOffersModel.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/alloffers/model/AllOffersModel.kt
new file mode 100644
index 0000000000..3280c17cb9
--- /dev/null
+++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/alloffers/model/AllOffersModel.kt
@@ -0,0 +1,19 @@
+package com.tangem.features.onramp.alloffers.model
+
+import com.tangem.core.decompose.model.Model
+import com.tangem.core.decompose.model.ParamsContainer
+import com.tangem.features.onramp.alloffers.AllOffersComponent
+import com.tangem.utils.coroutines.CoroutineDispatcherProvider
+import javax.inject.Inject
+
+internal class AllOffersModel @Inject constructor(
+ override val dispatchers: CoroutineDispatcherProvider,
+ paramsContainer: ParamsContainer,
+) : Model() {
+
+ private val params: AllOffersComponent.Params = paramsContainer.require()
+
+ fun dismiss() {
+ params.onDismiss()
+ }
+}
\ No newline at end of file
diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/mainv2/DefaultOnrampV2MainComponent.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/mainv2/DefaultOnrampV2MainComponent.kt
index a651416d7f..2487bf37b1 100644
--- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/mainv2/DefaultOnrampV2MainComponent.kt
+++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/mainv2/DefaultOnrampV2MainComponent.kt
@@ -12,6 +12,7 @@ import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.decompose.context.childByContext
import com.tangem.core.decompose.model.getOrCreateModel
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
+import com.tangem.features.onramp.alloffers.AllOffersComponent
import com.tangem.features.onramp.confirmresidency.ConfirmResidencyComponent
import com.tangem.features.onramp.mainv2.entity.OnrampV2MainBottomSheetConfig
import com.tangem.features.onramp.mainv2.model.OnrampV2MainComponentModel
@@ -26,6 +27,7 @@ internal class DefaultOnrampV2MainComponent @AssistedInject constructor(
@Assisted private val params: OnrampV2MainComponent.Params,
private val confirmResidencyComponentFactory: ConfirmResidencyComponent.Factory,
private val selectCurrencyComponentFactory: SelectCurrencyComponent.Factory,
+ private val allOffersComponentFactory: AllOffersComponent.Factory,
) : OnrampV2MainComponent, AppComponentContext by appComponentContext {
private val model: OnrampV2MainComponentModel = getOrCreateModel(params)
@@ -67,6 +69,14 @@ internal class DefaultOnrampV2MainComponent @AssistedInject constructor(
onDismiss = model.bottomSheetNavigation::dismiss,
),
)
+ OnrampV2MainBottomSheetConfig.AllOffers -> allOffersComponentFactory.create(
+ context = childByContext(componentContext),
+ params = AllOffersComponent.Params(
+ userWallet = model.userWallet,
+ cryptoCurrency = params.cryptoCurrency,
+ onDismiss = model.bottomSheetNavigation::dismiss,
+ ),
+ )
}
@AssistedFactory
diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/mainv2/DefaultOnrampV2MainFeatureToggle.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/mainv2/DefaultOnrampV2MainFeatureToggle.kt
index 256bead28d..815fa5060b 100644
--- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/mainv2/DefaultOnrampV2MainFeatureToggle.kt
+++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/mainv2/DefaultOnrampV2MainFeatureToggle.kt
@@ -6,5 +6,5 @@ class DefaultOnrampV2MainFeatureToggle(
private val featureTogglesManager: FeatureTogglesManager,
) : OnrampV2MainFeatureToggle {
override val isOnrampNewMainEnabled: Boolean
- get() = featureTogglesManager.isFeatureEnabled("NEW_ONRAMP_RECEIVE_ENABLED")
+ get() = featureTogglesManager.isFeatureEnabled("NEW_ONRAMP_MAIN_ENABLED")
}
\ No newline at end of file
diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/mainv2/entity/OnrampOfferBlockUM.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/mainv2/entity/OnrampOfferBlockUM.kt
index 583cc962bb..5e41b49346 100644
--- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/mainv2/entity/OnrampOfferBlockUM.kt
+++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/mainv2/entity/OnrampOfferBlockUM.kt
@@ -1,6 +1,7 @@
package com.tangem.features.onramp.mainv2.entity
import androidx.compose.runtime.Immutable
+import com.tangem.core.ui.extensions.TextReference
import com.tangem.domain.onramp.model.OnrampPaymentMethod
import kotlinx.collections.immutable.ImmutableList
@@ -20,22 +21,32 @@ internal sealed interface OnrampOffersBlockUM {
data class Content(
override val isBlockVisible: Boolean,
- val offers: ImmutableList,
+ val recentOffer: OnrampOfferUM?,
+ val recommended: ImmutableList,
+ val onrampAllOffersButtonConfig: OnrampAllOffersButtonConfig?,
) : OnrampOffersBlockUM
}
internal data class OnrampOfferUM(
- val category: OnrampOfferCategory,
- val advantages: OnrampOfferAdvantages,
+ val category: OnrampOfferCategoryUM,
+ val advantages: OnrampOfferAdvantagesUM,
val paymentMethod: OnrampPaymentMethod,
val providerId: String,
val providerName: String,
+ val rate: String,
+ val diff: TextReference?,
+ val onBuyClicked: () -> Unit,
)
-internal enum class OnrampOfferCategory {
+internal enum class OnrampOfferCategoryUM {
RecentlyUsed, Recommended
}
-internal enum class OnrampOfferAdvantages {
+internal enum class OnrampOfferAdvantagesUM {
Default, BestRate, Fastest
-}
\ No newline at end of file
+}
+
+internal data class OnrampAllOffersButtonConfig(
+ val title: TextReference,
+ val onClick: () -> Unit,
+)
\ No newline at end of file
diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/mainv2/entity/OnrampV2MainBottomSheetConfig.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/mainv2/entity/OnrampV2MainBottomSheetConfig.kt
index dcb21bbf8a..d9e6c47a2d 100644
--- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/mainv2/entity/OnrampV2MainBottomSheetConfig.kt
+++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/mainv2/entity/OnrampV2MainBottomSheetConfig.kt
@@ -10,4 +10,7 @@ sealed interface OnrampV2MainBottomSheetConfig {
@Serializable
data object CurrenciesList : OnrampV2MainBottomSheetConfig
+
+ @Serializable
+ data object AllOffers : OnrampV2MainBottomSheetConfig
}
\ No newline at end of file
diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/mainv2/entity/factory/OnrampOffersStateFactory.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/mainv2/entity/factory/OnrampOffersStateFactory.kt
new file mode 100644
index 0000000000..377c5987d4
--- /dev/null
+++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/mainv2/entity/factory/OnrampOffersStateFactory.kt
@@ -0,0 +1,106 @@
+package com.tangem.features.onramp.mainv2.entity.factory
+
+import com.tangem.core.ui.extensions.TextReference
+import com.tangem.core.ui.extensions.stringReference
+import com.tangem.core.ui.format.bigdecimal.crypto
+import com.tangem.core.ui.format.bigdecimal.format
+import com.tangem.core.ui.format.bigdecimal.percent
+import com.tangem.domain.onramp.model.*
+import com.tangem.features.onramp.impl.R
+import com.tangem.features.onramp.main.entity.OnrampIntents
+import com.tangem.features.onramp.mainv2.entity.*
+import com.tangem.utils.Provider
+import com.tangem.utils.StringsSigns.MINUS
+import kotlinx.collections.immutable.toPersistentList
+
+internal class OnrampOffersStateFactory(
+ private val currentStateProvider: Provider,
+ private val onrampIntents: OnrampIntents,
+) {
+
+ fun getOnShowOffersState(offers: List): OnrampV2MainComponentUM {
+ val currentState = currentStateProvider.invoke()
+ return when (currentState) {
+ is OnrampV2MainComponentUM.Content -> {
+ currentState.copy(
+ offersBlockState = mapOnrampOffersBlockToUM(offers),
+ )
+ }
+ is OnrampV2MainComponentUM.InitialLoading -> {
+ currentState
+ }
+ }
+ }
+
+ private fun mapOnrampOffersBlockToUM(offersBlocks: List): OnrampOffersBlockUM.Content {
+ val allOffersUM = mutableListOf()
+ offersBlocks.map { block ->
+ block.offers.forEach { offer ->
+ when (val currentQuote = offer.quote) {
+ is OnrampQuote.AmountError,
+ is OnrampQuote.Error,
+ -> Unit
+ is OnrampQuote.Data -> {
+ allOffersUM.add(
+ OnrampOfferUM(
+ category = mapOfferCategoryDTOtoUM(block.category),
+ advantages = mapOfferAdvantagesDTOtoUM(offer.advantages),
+ paymentMethod = currentQuote.paymentMethod,
+ providerId = currentQuote.provider.id,
+ providerName = currentQuote.provider.info.name,
+ rate = currentQuote.toAmount.value.format {
+ crypto(
+ symbol = currentQuote.toAmount.symbol,
+ decimals = currentQuote.toAmount.decimals,
+ )
+ },
+ diff = offer.rateDif?.let { diff ->
+ stringReference("$MINUS${diff.format { percent() }}")
+ },
+ onBuyClicked = {
+ onrampIntents.onBuyClick(
+ quote = OnrampProviderWithQuote.Data(
+ provider = offer.quote.provider,
+ paymentMethod = currentQuote.paymentMethod,
+ toAmount = currentQuote.toAmount,
+ fromAmount = currentQuote.fromAmount,
+ ),
+ )
+ },
+ ),
+ )
+ }
+ }
+ }
+ }
+
+ return OnrampOffersBlockUM.Content(
+ isBlockVisible = false,
+ recentOffer = allOffersUM.firstOrNull { it.category == OnrampOfferCategoryUM.RecentlyUsed },
+ recommended = allOffersUM.filter { it.category == OnrampOfferCategoryUM.Recommended }.toPersistentList(),
+ onrampAllOffersButtonConfig = if (offersBlocks.any { it.hasMoreOffers }) {
+ OnrampAllOffersButtonConfig(
+ title = TextReference.Res(R.string.onramp_all_offers_button_title),
+ onClick = { onrampIntents.openProviders() },
+ )
+ } else {
+ null
+ },
+ )
+ }
+
+ private fun mapOfferCategoryDTOtoUM(category: OnrampOfferCategory): OnrampOfferCategoryUM {
+ return when (category) {
+ OnrampOfferCategory.Recent -> OnrampOfferCategoryUM.RecentlyUsed
+ OnrampOfferCategory.Recommended -> OnrampOfferCategoryUM.Recommended
+ }
+ }
+
+ private fun mapOfferAdvantagesDTOtoUM(advantages: OnrampOfferAdvantages): OnrampOfferAdvantagesUM {
+ return when (advantages) {
+ OnrampOfferAdvantages.Default -> OnrampOfferAdvantagesUM.Default
+ OnrampOfferAdvantages.BestRate -> OnrampOfferAdvantagesUM.BestRate
+ OnrampOfferAdvantages.Fastest -> OnrampOfferAdvantagesUM.Fastest
+ }
+ }
+}
\ No newline at end of file
diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/mainv2/model/OnrampV2MainComponentModel.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/mainv2/model/OnrampV2MainComponentModel.kt
index 8d6615a675..d83a94d1f0 100644
--- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/mainv2/model/OnrampV2MainComponentModel.kt
+++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/mainv2/model/OnrampV2MainComponentModel.kt
@@ -20,6 +20,7 @@ import com.tangem.features.onramp.main.entity.OnrampLastUpdate
import com.tangem.features.onramp.mainv2.OnrampV2MainComponent
import com.tangem.features.onramp.mainv2.entity.*
import com.tangem.features.onramp.mainv2.entity.factory.OnrampAmountButtonUMStateFactory
+import com.tangem.features.onramp.mainv2.entity.factory.OnrampOffersStateFactory
import com.tangem.features.onramp.mainv2.entity.factory.OnrampV2AmountStateFactory
import com.tangem.features.onramp.mainv2.entity.factory.OnrampV2StateFactory
import com.tangem.features.onramp.utils.sendOnrampErrorEvent
@@ -32,7 +33,7 @@ import kotlinx.coroutines.launch
import timber.log.Timber
import javax.inject.Inject
-@Suppress("LongParameterList")
+@Suppress("LongParameterList", "LargeClass")
internal class OnrampV2MainComponentModel @Inject constructor(
override val dispatchers: CoroutineDispatcherProvider,
private val analyticsEventHandler: AnalyticsEventHandler,
@@ -44,6 +45,7 @@ internal class OnrampV2MainComponentModel @Inject constructor(
private val getOnrampQuotesUseCase: GetOnrampQuotesUseCase,
private val fetchPairsUseCase: OnrampFetchPairsUseCase,
private val amountInputManager: InputManager,
+ private val getOnrampOffersUseCase: GetOnrampOffersUseCase,
paramsContainer: ParamsContainer,
getWalletsUseCase: GetWalletsUseCase,
) : Model(), OnrampIntents {
@@ -58,6 +60,13 @@ internal class OnrampV2MainComponentModel @Inject constructor(
OnrampAmountButtonUMStateFactory()
}
+ private val onrampOffersStateFactory: OnrampOffersStateFactory by lazy(LazyThreadSafetyMode.NONE) {
+ OnrampOffersStateFactory(
+ currentStateProvider = Provider { _state.value },
+ onrampIntents = this,
+ )
+ }
+
private val stateFactory = OnrampV2StateFactory(
currentStateProvider = Provider { _state.value },
cryptoCurrency = params.cryptoCurrency,
@@ -94,6 +103,7 @@ internal class OnrampV2MainComponentModel @Inject constructor(
subscribeToAmountChanges()
subscribeToCountryAndCurrencyUpdates()
subscribeToQuotesUpdate()
+ subscribeOnOffers()
}
override fun onDestroy() {
@@ -117,11 +127,19 @@ internal class OnrampV2MainComponentModel @Inject constructor(
}
override fun onBuyClick(quote: OnrampProviderWithQuote.Data) {
- // TODO in [REDACTED_TASK_KEY] to be continued
+ val currentContentState = state.value as? OnrampV2MainComponentUM.Content ?: return
+ analyticsEventHandler.send(
+ OnrampAnalyticsEvent.OnBuyClick(
+ providerName = quote.provider.info.name,
+ currency = currentContentState.amountBlockState.currencyUM.code,
+ tokenSymbol = params.cryptoCurrency.symbol,
+ ),
+ )
+ params.openRedirectPage(quote)
}
override fun openProviders() {
- // TODO in [REDACTED_TASK_KEY] to be continued
+ bottomSheetNavigation.activate(OnrampV2MainBottomSheetConfig.AllOffers)
}
override fun onRefresh() {
@@ -172,6 +190,20 @@ internal class OnrampV2MainComponentModel @Inject constructor(
router.pop()
}
+ private fun subscribeOnOffers() = modelScope.launch {
+ getOnrampOffersUseCase.invoke(
+ userWalletId = userWallet.walletId,
+ cryptoCurrencyId = params.cryptoCurrency.id,
+ ).collectLatest { maybeOffers ->
+ maybeOffers.fold(
+ ifLeft = ::handleOnrampError,
+ ifRight = { offers ->
+ _state.update { onrampOffersStateFactory.getOnShowOffersState(offers) }
+ },
+ )
+ }
+ }
+
private fun subscribeToAmountChanges() = modelScope.launch {
amountInputManager.query
.filter(String::isNotEmpty)
diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/mainv2/ui/OnrampOffersContent.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/mainv2/ui/OnrampOffersContent.kt
index 6b35933d9e..1fc602096c 100644
--- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/mainv2/ui/OnrampOffersContent.kt
+++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/mainv2/ui/OnrampOffersContent.kt
@@ -1,13 +1,42 @@
package com.tangem.features.onramp.mainv2.ui
+import android.content.res.Configuration
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.tween
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.*
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.HorizontalDivider
+import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.drawWithCache
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.res.vectorResource
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.util.fastForEach
+import coil.compose.SubcomposeAsyncImage
+import coil.request.ImageRequest
+import com.tangem.core.ui.components.*
+import com.tangem.core.ui.components.buttons.common.TangemButtonSize
+import com.tangem.core.ui.extensions.*
import com.tangem.core.ui.res.TangemTheme
+import com.tangem.core.ui.res.TangemThemePreview
+import com.tangem.domain.onramp.model.OnrampPaymentMethod
+import com.tangem.domain.onramp.model.PaymentMethodType
+import com.tangem.features.onramp.impl.R
+import com.tangem.features.onramp.mainv2.entity.OnrampOfferAdvantagesUM
+import com.tangem.features.onramp.mainv2.entity.OnrampOfferCategoryUM
+import com.tangem.features.onramp.mainv2.entity.OnrampOfferUM
import com.tangem.features.onramp.mainv2.entity.OnrampOffersBlockUM
+import kotlinx.collections.immutable.persistentListOf
@Composable
internal fun OnrampOffersContent(state: OnrampOffersBlockUM) {
@@ -23,10 +52,330 @@ internal fun OnrampOffersContent(state: OnrampOffersBlockUM) {
),
label = "Offers block animation",
) {
- Text(
- text = "Some offers",
- style = TangemTheme.typography.head,
+ if (state is OnrampOffersBlockUM.Content) {
+ Column(modifier = Modifier.fillMaxWidth()) {
+ state.recentOffer?.let { recentOffer ->
+ Column {
+ Text(
+ modifier = Modifier.padding(start = 12.dp),
+ text = stringResourceSafe(R.string.onramp_recently_used_title),
+ style = TangemTheme.typography.subtitle2,
+ color = TangemTheme.colors.text.tertiary,
+ )
+
+ SpacerH(8.dp)
+
+ Offer(recentOffer)
+
+ SpacerH(16.dp)
+ }
+ }
+
+ Text(
+ modifier = Modifier.padding(start = 12.dp),
+ text = stringResourceSafe(R.string.onramp_recommended_title),
+ style = TangemTheme.typography.subtitle2,
+ color = TangemTheme.colors.text.tertiary,
+ )
+
+ SpacerH(8.dp)
+
+ state.recommended.fastForEach {
+ Offer(it)
+ SpacerH(8.dp)
+ }
+
+ state.onrampAllOffersButtonConfig?.let {
+ SpacerH(12.dp)
+ SecondaryButton(
+ modifier = Modifier.fillMaxWidth(),
+ text = it.title.resolveReference(),
+ onClick = it.onClick,
+ )
+ }
+ }
+ }
+ }
+}
+
+@Composable
+private fun Offer(onrampOfferUM: OnrampOfferUM, modifier: Modifier = Modifier) {
+ Column(
+ modifier = modifier
+ .fillMaxWidth()
+ .background(
+ color = TangemTheme.colors.background.action,
+ shape = RoundedCornerShape(14.dp),
+ )
+ .padding(12.dp),
+ ) {
+ Row(
+ modifier = Modifier.fillMaxWidth(),
+ verticalAlignment = Alignment.CenterVertically,
+ ) {
+ Column(verticalArrangement = Arrangement.spacedBy(2.dp)) {
+ OfferHeader(advantage = onrampOfferUM.advantages)
+ RateBlock(rate = onrampOfferUM.rate, diff = onrampOfferUM.diff)
+ }
+ SpacerWMax()
+ SecondaryButton(
+ size = TangemButtonSize.RoundedAction,
+ text = stringResourceSafe(R.string.common_buy),
+ onClick = onrampOfferUM.onBuyClicked,
+ )
+ }
+ SpacerH(10.dp)
+ HorizontalDivider(color = TangemTheme.colors.stroke.primary)
+ SpacerH(12.dp)
+ PaymentBlockInOffer(
+ paymentMethod = onrampOfferUM.paymentMethod,
+ providerName = onrampOfferUM.providerName,
)
- // TODO in [REDACTED_TASK_KEY] to be continued
+ }
+}
+
+@Composable
+private fun OfferHeader(advantage: OnrampOfferAdvantagesUM) {
+ when (advantage) {
+ OnrampOfferAdvantagesUM.Default -> {
+ Text(
+ text = stringResourceSafe(R.string.onramp_title_you_get),
+ style = TangemTheme.typography.caption2,
+ color = TangemTheme.colors.text.tertiary,
+ )
+ }
+ OnrampOfferAdvantagesUM.BestRate -> {
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.spacedBy(4.dp),
+ ) {
+ Icon(
+ imageVector = ImageVector.vectorResource(R.drawable.ic_best_rate_16),
+ tint = TangemTheme.colors.icon.accent,
+ contentDescription = null,
+ )
+ Text(
+ text = stringResourceSafe(R.string.express_provider_best_rate),
+ style = TangemTheme.typography.caption1,
+ color = TangemTheme.colors.icon.accent,
+ )
+ }
+ }
+ OnrampOfferAdvantagesUM.Fastest -> {
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.spacedBy(4.dp),
+ ) {
+ Icon(
+ imageVector = ImageVector.vectorResource(R.drawable.ic_fastest_16),
+ tint = TangemTheme.colors.icon.attention,
+ contentDescription = null,
+ )
+ Text(
+ text = stringResourceSafe(R.string.onramp_offer_type_fastet),
+ style = TangemTheme.typography.caption1,
+ color = TangemTheme.colors.icon.attention,
+ )
+ }
+ }
+ }
+}
+
+@Composable
+private fun RateBlock(rate: String, diff: TextReference?) {
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.spacedBy(4.dp),
+ ) {
+ Text(
+ text = rate,
+ style = TangemTheme.typography.subtitle1,
+ color = TangemTheme.colors.text.primary1,
+ )
+ diff?.let {
+ Text(
+ modifier = Modifier
+ .background(
+ color = TangemTheme.colors.text.warning.copy(alpha = 0.1f),
+ shape = RoundedCornerShape(4.dp),
+ )
+ .padding(horizontal = 4.dp),
+ text = it.resolveReference(),
+ style = TangemTheme.typography.caption1,
+ color = TangemTheme.colors.text.warning,
+ )
+ }
+ }
+}
+
+@Composable
+private fun PaymentBlockInOffer(paymentMethod: OnrampPaymentMethod, providerName: String) {
+ Row(verticalAlignment = Alignment.CenterVertically) {
+ Icon(
+ modifier = Modifier.size(16.dp),
+ imageVector = ImageVector.vectorResource(R.drawable.ic_clock_24),
+ tint = TangemTheme.colors.icon.informative,
+ contentDescription = null,
+ )
+
+ SpacerW(2.dp)
+
+ TimingBlock(speed = paymentMethod.type.getProcessingSpeed())
+
+ SpacerW(6.dp)
+
+ DrawDot(color = TangemTheme.colors.text.tertiary)
+
+ SpacerW(6.dp)
+
+ Text(
+ text = providerName,
+ style = TangemTheme.typography.caption2,
+ color = TangemTheme.colors.text.tertiary,
+ )
+
+ SpacerWMax()
+
+ Text(
+ text = stringResourceSafe(R.string.onramp_pay_with),
+ style = TangemTheme.typography.caption2,
+ color = TangemTheme.colors.text.tertiary,
+ )
+
+ SpacerW(4.dp)
+
+ SubcomposeAsyncImage(
+ modifier = Modifier.sizeIn(maxWidth = 38.dp, maxHeight = 16.dp),
+ model = ImageRequest.Builder(context = LocalContext.current)
+ .data(paymentMethod.imageUrl)
+ .crossfade(enable = true)
+ .allowHardware(false)
+ .build(),
+ loading = {
+ TextShimmer(
+ style = TangemTheme.typography.body1,
+ modifier = Modifier.width(40.dp),
+ )
+ },
+ contentDescription = null,
+ )
+ }
+}
+
+@Composable
+private fun TimingBlock(speed: PaymentMethodType.PaymentSpeed) {
+ val timingText = when (speed) {
+ PaymentMethodType.PaymentSpeed.Instant -> {
+ stringResourceSafe(id = R.string.onramp_instant_status)
+ }
+ PaymentMethodType.PaymentSpeed.FewMin -> {
+ stringResourceSafe(
+ id = R.string.onramp_timing_minutes,
+ FEW_MINS_VALUE,
+ )
+ }
+ PaymentMethodType.PaymentSpeed.FewDays -> {
+ pluralStringResourceSafe(
+ id = R.plurals.onramp_timing_days,
+ count = FEW_DAYS_VALUE,
+ FEW_DAYS_VALUE,
+ )
+ }
+ PaymentMethodType.PaymentSpeed.PlentyDays -> {
+ pluralStringResourceSafe(
+ id = R.plurals.onramp_timing_days,
+ count = PLENTY_DAYS_VALUE,
+ PLENTY_DAYS_VALUE,
+ )
+ }
+ PaymentMethodType.PaymentSpeed.Unknown -> ""
+ }
+
+ Text(
+ text = timingText,
+ style = TangemTheme.typography.caption2,
+ color = TangemTheme.colors.text.tertiary,
+ )
+}
+
+@Composable
+fun DrawDot(color: Color) {
+ Spacer(
+ modifier = Modifier
+ .size(4.dp)
+ .drawWithCache {
+ val radius = size.minDimension / 2f
+ onDrawBehind {
+ drawCircle(
+ color = color,
+ radius = radius,
+ )
+ }
+ },
+ )
+}
+
+// will be hardcoded till server will be ready to provide this values
+private const val FEW_MINS_VALUE = "3-5"
+private const val FEW_DAYS_VALUE = 3
+private const val PLENTY_DAYS_VALUE = 5
+
+@Preview(showBackground = true, widthDp = 360)
+@Preview(showBackground = true, widthDp = 360, uiMode = Configuration.UI_MODE_NIGHT_YES)
+@Composable
+private fun OnrampOffersContentPreview() {
+ val state = OnrampOffersBlockUM.Content(
+ isBlockVisible = true,
+ recentOffer = OnrampOfferUM(
+ category = OnrampOfferCategoryUM.RecentlyUsed,
+ advantages = OnrampOfferAdvantagesUM.Default,
+ paymentMethod = OnrampPaymentMethod(
+ id = "card",
+ name = "Card",
+ imageUrl = "https://s3.eu-central-1.amazonaws.com/tangem.api/express/PaymentMethods/visa-mc.png",
+ type = PaymentMethodType.CARD,
+ ),
+ providerId = "providerId3",
+ providerName = "Simplex",
+ rate = "0,00045334 BTC",
+ diff = stringReference("–27%"),
+ onBuyClicked = {},
+ ),
+ recommended = persistentListOf(
+ OnrampOfferUM(
+ category = OnrampOfferCategoryUM.Recommended,
+ advantages = OnrampOfferAdvantagesUM.BestRate,
+ paymentMethod = OnrampPaymentMethod(
+ id = "card",
+ name = "Card",
+ imageUrl = "https://s3.eu-central-1.amazonaws.com/tangem.api/express/PaymentMethods/visa-mc.png",
+ type = PaymentMethodType.CARD,
+ ),
+ providerId = "providerId1",
+ providerName = "Simplex",
+ rate = "0,0245334 BTC",
+ diff = null,
+ onBuyClicked = {},
+ ),
+ OnrampOfferUM(
+ category = OnrampOfferCategoryUM.Recommended,
+ advantages = OnrampOfferAdvantagesUM.Fastest,
+ paymentMethod = OnrampPaymentMethod(
+ id = "card",
+ name = "Card",
+ imageUrl = "https://s3.eu-central-1.amazonaws.com/tangem.api/express/PaymentMethods/visa-mc.png",
+ type = PaymentMethodType.CARD,
+ ),
+ providerId = "providerId2",
+ providerName = "Simplex",
+ rate = "0,00145334 BTC",
+ diff = stringReference("–0.07%"),
+ onBuyClicked = {},
+ ),
+ ),
+ onrampAllOffersButtonConfig = null,
+ )
+ TangemThemePreview {
+ OnrampOffersContent(state)
}
}
\ No newline at end of file
diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/mainv2/ui/OnrampV2AmountContent.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/mainv2/ui/OnrampV2AmountContent.kt
index 284e2e04cc..b0ea37b98b 100644
--- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/mainv2/ui/OnrampV2AmountContent.kt
+++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/mainv2/ui/OnrampV2AmountContent.kt
@@ -1,5 +1,6 @@
package com.tangem.features.onramp.mainv2.ui
+import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.animateContentSize
import androidx.compose.animation.core.tween
import androidx.compose.foundation.background
@@ -51,6 +52,7 @@ internal fun OnrampV2AmountContent(state: OnrampV2MainComponentUM.Content, modif
Column(
modifier = modifier
+ .fillMaxWidth()
.background(
color = TangemTheme.colors.background.action,
shape = RoundedCornerShape(size = TangemTheme.dimens.radius16),
@@ -61,16 +63,14 @@ internal fun OnrampV2AmountContent(state: OnrampV2MainComponentUM.Content, modif
) {
OnrampHeaderTitle()
- SpacerH(12.dp)
-
OnrampAmountField(
amountField = state.amountBlockState.amountFieldModel,
currencyCode = state.amountBlockState.currencyUM.code,
)
- SpacerH(8.dp)
-
- OnrampAmountSecondary(state = state.amountBlockState.secondaryFieldModel)
+ AnimatedVisibility(!state.offersBlockState.isBlockVisible) {
+ OnrampAmountSecondary(state = state.amountBlockState.secondaryFieldModel)
+ }
SpacerH(20.dp)
@@ -115,7 +115,8 @@ private fun OnrampAmountField(amountField: AmountFieldModel, currencyCode: Strin
modifier = Modifier
.focusRequester(requester)
.padding(
- top = TangemTheme.dimens.spacing24,
+ top = TangemTheme.dimens.spacing8,
+ bottom = TangemTheme.dimens.spacing4,
start = TangemTheme.dimens.spacing12,
end = TangemTheme.dimens.spacing12,
)
diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/root/DefaultOnrampComponent.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/root/DefaultOnrampComponent.kt
index e9ee2b3295..b9ff5cb77a 100644
--- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/root/DefaultOnrampComponent.kt
+++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/root/DefaultOnrampComponent.kt
@@ -17,6 +17,8 @@ import com.tangem.core.decompose.context.childByContext
import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.features.onramp.component.OnrampComponent
import com.tangem.features.onramp.main.OnrampMainComponent
+import com.tangem.features.onramp.mainv2.OnrampV2MainComponent
+import com.tangem.features.onramp.mainv2.OnrampV2MainFeatureToggle
import com.tangem.features.onramp.redirect.OnrampRedirectComponent
import com.tangem.features.onramp.root.entity.OnrampChild
import com.tangem.features.onramp.settings.OnrampSettingsComponent
@@ -24,13 +26,15 @@ import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
-@Suppress("UnusedPrivateMember")
+@Suppress("LongParameterList")
internal class DefaultOnrampComponent @AssistedInject constructor(
@Assisted context: AppComponentContext,
@Assisted private val params: OnrampComponent.Params,
private val settingsComponentFactory: OnrampSettingsComponent.Factory,
private val onrampMainComponentFactory: OnrampMainComponent.Factory,
+ private val onrampMainV2ComponentFactory: OnrampV2MainComponent.Factory,
private val onrampRedirectComponentFactory: OnrampRedirectComponent.Factory,
+ private val onrampV2MainFeatureToggle: OnrampV2MainFeatureToggle,
) : OnrampComponent, AppComponentContext by context {
private val navigation = StackNavigation()
@@ -66,24 +70,44 @@ internal class DefaultOnrampComponent @AssistedInject constructor(
onBack = navigation::pop,
),
)
- OnrampChild.Main -> onrampMainComponentFactory.create(
- context = childByContext(componentContext),
- params = OnrampMainComponent.Params(
- userWalletId = params.userWalletId,
- cryptoCurrency = params.cryptoCurrency,
- openSettings = { navigation.push(OnrampChild.Settings) },
- source = params.source,
- openRedirectPage = {
- navigation.push(
- OnrampChild.RedirectPage(
- quote = it,
- cryptoCurrency = params.cryptoCurrency,
- ),
- )
- },
- launchSepa = params.launchSepa,
- ),
- )
+ OnrampChild.Main -> if (onrampV2MainFeatureToggle.isOnrampNewMainEnabled) {
+ onrampMainV2ComponentFactory.create(
+ context = childByContext(componentContext),
+ params = OnrampV2MainComponent.Params(
+ userWalletId = params.userWalletId,
+ cryptoCurrency = params.cryptoCurrency,
+ openSettings = { navigation.push(OnrampChild.Settings) },
+ source = params.source,
+ openRedirectPage = {
+ navigation.push(
+ OnrampChild.RedirectPage(
+ quote = it,
+ cryptoCurrency = params.cryptoCurrency,
+ ),
+ )
+ },
+ ),
+ )
+ } else {
+ onrampMainComponentFactory.create(
+ context = childByContext(componentContext),
+ params = OnrampMainComponent.Params(
+ userWalletId = params.userWalletId,
+ cryptoCurrency = params.cryptoCurrency,
+ openSettings = { navigation.push(OnrampChild.Settings) },
+ source = params.source,
+ openRedirectPage = {
+ navigation.push(
+ OnrampChild.RedirectPage(
+ quote = it,
+ cryptoCurrency = params.cryptoCurrency,
+ ),
+ )
+ },
+ launchSepa = params.launchSepa,
+ ),
+ )
+ }
is OnrampChild.RedirectPage -> onrampRedirectComponentFactory.create(
context = childByContext(componentContext),
params = OnrampRedirectComponent.Params(