From 9f65e1b80c86898aaa7824803178a6ad3be3ca0d Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 20 Nov 2024 14:34:19 +0500 Subject: [PATCH] Updated on 2026-08-14 --- .../tap/di/domain/OnrampDomainModule.kt | 6 + .../tangem/datasource/di/OnrampStoreModule.kt | 21 ++++ .../DefaultOnrampPaymentMethodsStore.kt | 12 ++ .../local/onramp/OnrampPaymentMethodsStore.kt | 12 ++ .../data/onramp/DefaultOnrampRepository.kt | 31 +++++ .../converters/PaymentMethodConverter.kt | 13 ++ .../tangem/data/onramp/di/OnrampDataModule.kt | 3 + .../onramp/model/OnrampPaymentMethod.kt | 10 ++ .../onramp/CheckOnrampAvailabilityUseCase.kt | 1 + .../onramp/GetOnrampPaymentMethodsUseCase.kt | 12 ++ .../onramp/repositories/OnrampRepository.kt | 3 + .../model/ConfirmResidencyModel.kt | 9 +- .../DefaultSelectPaymentMethodComponent.kt | 45 +++++++ .../SelectPaymentMethodComponent.kt | 16 +++ .../di/SelectPaymentMethodComponentModule.kt | 20 +++ .../paymentmethod/entity/PaymentMethodUM.kt | 8 ++ .../entity/PaymentMethodsBottomSheetConfig.kt | 9 ++ .../ui/SelectPaymentMethodBottomSheet.kt | 118 ++++++++++++++++++ 18 files changed, 347 insertions(+), 2 deletions(-) create mode 100644 core/datasource/src/main/java/com/tangem/datasource/di/OnrampStoreModule.kt create mode 100644 core/datasource/src/main/java/com/tangem/datasource/local/onramp/DefaultOnrampPaymentMethodsStore.kt create mode 100644 core/datasource/src/main/java/com/tangem/datasource/local/onramp/OnrampPaymentMethodsStore.kt create mode 100644 data/onramp/src/main/java/com/tangem/data/onramp/converters/PaymentMethodConverter.kt create mode 100644 domain/onramp/models/src/main/kotlin/com/tangem/domain/onramp/model/OnrampPaymentMethod.kt create mode 100644 domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampPaymentMethodsUseCase.kt create mode 100644 features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/paymentmethod/DefaultSelectPaymentMethodComponent.kt create mode 100644 features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/paymentmethod/SelectPaymentMethodComponent.kt create mode 100644 features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/paymentmethod/di/SelectPaymentMethodComponentModule.kt create mode 100644 features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/paymentmethod/entity/PaymentMethodUM.kt create mode 100644 features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/paymentmethod/entity/PaymentMethodsBottomSheetConfig.kt create mode 100644 features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/paymentmethod/ui/SelectPaymentMethodBottomSheet.kt 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 2c276a7117..d21153b84b 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 @@ -96,4 +96,10 @@ internal object OnrampDomainModule { ): OnrampSaveTransactionUseCase { return OnrampSaveTransactionUseCase(onrampTransactionRepository) } + + @Provides + @Singleton + fun provideGetOnrampPaymentMethodsUseCase(onrampRepository: OnrampRepository): GetOnrampPaymentMethodsUseCase { + return GetOnrampPaymentMethodsUseCase(onrampRepository) + } } \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/di/OnrampStoreModule.kt b/core/datasource/src/main/java/com/tangem/datasource/di/OnrampStoreModule.kt new file mode 100644 index 0000000000..8b7fb87fa2 --- /dev/null +++ b/core/datasource/src/main/java/com/tangem/datasource/di/OnrampStoreModule.kt @@ -0,0 +1,21 @@ +package com.tangem.datasource.di + +import com.tangem.datasource.local.datastore.RuntimeDataStore +import com.tangem.datasource.local.onramp.DefaultOnrampPaymentMethodsStore +import com.tangem.datasource.local.onramp.OnrampPaymentMethodsStore +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +internal object OnrampStoreModule { + + @Provides + @Singleton + fun provideOnrampPaymentMethodsStore(): OnrampPaymentMethodsStore { + return DefaultOnrampPaymentMethodsStore(dataStore = RuntimeDataStore()) + } +} \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/onramp/DefaultOnrampPaymentMethodsStore.kt b/core/datasource/src/main/java/com/tangem/datasource/local/onramp/DefaultOnrampPaymentMethodsStore.kt new file mode 100644 index 0000000000..3a4fa1b949 --- /dev/null +++ b/core/datasource/src/main/java/com/tangem/datasource/local/onramp/DefaultOnrampPaymentMethodsStore.kt @@ -0,0 +1,12 @@ +package com.tangem.datasource.local.onramp + +import com.tangem.datasource.api.onramp.models.response.model.PaymentMethodDTO +import com.tangem.datasource.local.datastore.core.StringKeyDataStore +import com.tangem.datasource.local.datastore.core.StringKeyDataStoreDecorator + +internal class DefaultOnrampPaymentMethodsStore( + dataStore: StringKeyDataStore>, +) : OnrampPaymentMethodsStore, StringKeyDataStoreDecorator>(dataStore) { + + override fun provideStringKey(key: String): String = key +} \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/onramp/OnrampPaymentMethodsStore.kt b/core/datasource/src/main/java/com/tangem/datasource/local/onramp/OnrampPaymentMethodsStore.kt new file mode 100644 index 0000000000..a6847ae671 --- /dev/null +++ b/core/datasource/src/main/java/com/tangem/datasource/local/onramp/OnrampPaymentMethodsStore.kt @@ -0,0 +1,12 @@ +package com.tangem.datasource.local.onramp + +import com.tangem.datasource.api.onramp.models.response.model.PaymentMethodDTO + +interface OnrampPaymentMethodsStore { + + suspend fun getSyncOrNull(key: String): List? + + suspend fun store(key: String, value: List) + + suspend fun contains(key: String): Boolean +} \ No newline at end of file diff --git a/data/onramp/src/main/java/com/tangem/data/onramp/DefaultOnrampRepository.kt b/data/onramp/src/main/java/com/tangem/data/onramp/DefaultOnrampRepository.kt index ef6cd4523e..4145803c20 100644 --- a/data/onramp/src/main/java/com/tangem/data/onramp/DefaultOnrampRepository.kt +++ b/data/onramp/src/main/java/com/tangem/data/onramp/DefaultOnrampRepository.kt @@ -1,12 +1,15 @@ package com.tangem.data.onramp +import com.tangem.data.common.api.safeApiCall import com.tangem.data.onramp.converters.CountryConverter import com.tangem.data.onramp.converters.CurrencyConverter import com.tangem.data.onramp.converters.StatusConverter +import com.tangem.data.onramp.converters.PaymentMethodConverter import com.tangem.datasource.api.common.response.getOrThrow import com.tangem.datasource.api.onramp.OnrampApi import com.tangem.datasource.api.onramp.models.response.model.OnrampCountryDTO import com.tangem.datasource.api.onramp.models.response.model.OnrampCurrencyDTO +import com.tangem.datasource.local.onramp.OnrampPaymentMethodsStore import com.tangem.datasource.local.preferences.AppPreferencesStore import com.tangem.datasource.local.preferences.PreferencesKeys import com.tangem.datasource.local.preferences.utils.getObject @@ -15,21 +18,25 @@ import com.tangem.datasource.local.preferences.utils.storeObject import com.tangem.domain.onramp.model.OnrampCountry import com.tangem.domain.onramp.model.OnrampCurrency import com.tangem.domain.onramp.model.OnrampStatus +import com.tangem.domain.onramp.model.OnrampPaymentMethod import com.tangem.domain.onramp.repositories.OnrampRepository import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map import kotlinx.coroutines.withContext +import timber.log.Timber internal class DefaultOnrampRepository( private val onrampApi: OnrampApi, private val dispatchers: CoroutineDispatcherProvider, private val appPreferencesStore: AppPreferencesStore, + private val paymentMethodsStore: OnrampPaymentMethodsStore, ) : OnrampRepository { private val currencyConverter = CurrencyConverter() private val countryConverter = CountryConverter(currencyConverter) private val statusConverter = StatusConverter() + private val paymentMethodsConverter = PaymentMethodConverter() override suspend fun getCurrencies(): List = withContext(dispatchers.io) { onrampApi.getCurrencies() @@ -92,4 +99,28 @@ internal class DefaultOnrampRepository( .getObject(PreferencesKeys.ONRAMP_DEFAULT_COUNTRY) .map { it?.let(countryConverter::convert) } } + + override suspend fun fetchPaymentMethodsIfAbsent() { + if (paymentMethodsStore.contains(PAYMENT_METHODS_KEY)) return + + val response = safeApiCall( + call = { onrampApi.getPaymentMethods().bind() }, + onError = { + Timber.w(it, "Unable to fetch onramp payment methods") + throw it + }, + ) + paymentMethodsStore.store(PAYMENT_METHODS_KEY, response) + } + + override suspend fun getPaymentMethods(): List { + val paymentMethods = requireNotNull(paymentMethodsStore.getSyncOrNull(PAYMENT_METHODS_KEY)) { + "Onramp payment methods is absent in storage" + } + return paymentMethodsConverter.convertList(paymentMethods) + } + + private companion object { + const val PAYMENT_METHODS_KEY = "onramp_payment_methods" + } } \ No newline at end of file diff --git a/data/onramp/src/main/java/com/tangem/data/onramp/converters/PaymentMethodConverter.kt b/data/onramp/src/main/java/com/tangem/data/onramp/converters/PaymentMethodConverter.kt new file mode 100644 index 0000000000..b45273c12e --- /dev/null +++ b/data/onramp/src/main/java/com/tangem/data/onramp/converters/PaymentMethodConverter.kt @@ -0,0 +1,13 @@ +package com.tangem.data.onramp.converters + +import com.tangem.datasource.api.onramp.models.response.model.PaymentMethodDTO +import com.tangem.domain.onramp.model.OnrampPaymentMethod +import com.tangem.utils.converter.Converter + +internal class PaymentMethodConverter : Converter { + override fun convert(value: PaymentMethodDTO): OnrampPaymentMethod = OnrampPaymentMethod( + id = value.id, + name = value.name, + imageUrl = value.image, + ) +} \ No newline at end of file diff --git a/data/onramp/src/main/java/com/tangem/data/onramp/di/OnrampDataModule.kt b/data/onramp/src/main/java/com/tangem/data/onramp/di/OnrampDataModule.kt index fed11e54d0..3731a0773d 100644 --- a/data/onramp/src/main/java/com/tangem/data/onramp/di/OnrampDataModule.kt +++ b/data/onramp/src/main/java/com/tangem/data/onramp/di/OnrampDataModule.kt @@ -4,6 +4,7 @@ import com.tangem.data.onramp.DefaultOnrampErrorResolver import com.tangem.data.onramp.DefaultOnrampRepository import com.tangem.data.onramp.DefaultOnrampTransactionRepository import com.tangem.datasource.api.onramp.OnrampApi +import com.tangem.datasource.local.onramp.OnrampPaymentMethodsStore import com.tangem.datasource.local.preferences.AppPreferencesStore import com.tangem.domain.onramp.repositories.OnrampErrorResolver import com.tangem.domain.onramp.repositories.OnrampRepository @@ -25,11 +26,13 @@ internal object OnrampDataModule { onrampApi: OnrampApi, dispatchers: CoroutineDispatcherProvider, appPreferencesStore: AppPreferencesStore, + paymentMethodsStore: OnrampPaymentMethodsStore, ): OnrampRepository { return DefaultOnrampRepository( onrampApi = onrampApi, dispatchers = dispatchers, appPreferencesStore = appPreferencesStore, + paymentMethodsStore = paymentMethodsStore, ) } diff --git a/domain/onramp/models/src/main/kotlin/com/tangem/domain/onramp/model/OnrampPaymentMethod.kt b/domain/onramp/models/src/main/kotlin/com/tangem/domain/onramp/model/OnrampPaymentMethod.kt new file mode 100644 index 0000000000..0ddf36dbf6 --- /dev/null +++ b/domain/onramp/models/src/main/kotlin/com/tangem/domain/onramp/model/OnrampPaymentMethod.kt @@ -0,0 +1,10 @@ +package com.tangem.domain.onramp.model + +import kotlinx.serialization.Serializable + +@Serializable +data class OnrampPaymentMethod( + val id: String, + val name: String, + val imageUrl: String, +) \ No newline at end of file diff --git a/domain/onramp/src/main/java/com/tangem/domain/onramp/CheckOnrampAvailabilityUseCase.kt b/domain/onramp/src/main/java/com/tangem/domain/onramp/CheckOnrampAvailabilityUseCase.kt index 46af00376b..2e099164d9 100644 --- a/domain/onramp/src/main/java/com/tangem/domain/onramp/CheckOnrampAvailabilityUseCase.kt +++ b/domain/onramp/src/main/java/com/tangem/domain/onramp/CheckOnrampAvailabilityUseCase.kt @@ -8,6 +8,7 @@ class CheckOnrampAvailabilityUseCase(private val repository: OnrampRepository) { suspend operator fun invoke(): Either { return Either.catch { + repository.fetchPaymentMethodsIfAbsent() repository.getDefaultCountrySync()?.let { savedCountry -> return@catch if (savedCountry.onrampAvailable) { val currency = repository.getDefaultCurrencySync() ?: run { diff --git a/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampPaymentMethodsUseCase.kt b/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampPaymentMethodsUseCase.kt new file mode 100644 index 0000000000..898bf3be19 --- /dev/null +++ b/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampPaymentMethodsUseCase.kt @@ -0,0 +1,12 @@ +package com.tangem.domain.onramp + +import arrow.core.Either +import com.tangem.domain.onramp.model.OnrampPaymentMethod +import com.tangem.domain.onramp.repositories.OnrampRepository + +class GetOnrampPaymentMethodsUseCase(private val repository: OnrampRepository) { + + suspend operator fun invoke(): Either> { + return Either.catch { repository.getPaymentMethods() } + } +} \ No newline at end of file diff --git a/domain/onramp/src/main/java/com/tangem/domain/onramp/repositories/OnrampRepository.kt b/domain/onramp/src/main/java/com/tangem/domain/onramp/repositories/OnrampRepository.kt index 7e6dc7df12..1c269c1a75 100644 --- a/domain/onramp/src/main/java/com/tangem/domain/onramp/repositories/OnrampRepository.kt +++ b/domain/onramp/src/main/java/com/tangem/domain/onramp/repositories/OnrampRepository.kt @@ -3,6 +3,7 @@ package com.tangem.domain.onramp.repositories import com.tangem.domain.onramp.model.OnrampCountry import com.tangem.domain.onramp.model.OnrampCurrency import com.tangem.domain.onramp.model.OnrampStatus +import com.tangem.domain.onramp.model.OnrampPaymentMethod import kotlinx.coroutines.flow.Flow interface OnrampRepository { @@ -11,6 +12,7 @@ interface OnrampRepository { suspend fun getCountries(): List suspend fun getCountryByIp(): OnrampCountry suspend fun getStatus(txId: String): OnrampStatus + suspend fun fetchPaymentMethodsIfAbsent() // cache suspend fun saveDefaultCurrency(currency: OnrampCurrency) @@ -19,4 +21,5 @@ interface OnrampRepository { suspend fun saveDefaultCountry(country: OnrampCountry) suspend fun getDefaultCountrySync(): OnrampCountry? fun getDefaultCountry(): Flow + suspend fun getPaymentMethods(): List } \ No newline at end of file diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/confirmresidency/model/ConfirmResidencyModel.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/confirmresidency/model/ConfirmResidencyModel.kt index 25a7058831..d9afb5e94b 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/confirmresidency/model/ConfirmResidencyModel.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/confirmresidency/model/ConfirmResidencyModel.kt @@ -8,20 +8,23 @@ import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.decompose.navigation.Router import com.tangem.core.ui.extensions.resourceReference import com.tangem.domain.onramp.GetOnrampCountryUseCase +import com.tangem.domain.onramp.OnrampSaveDefaultCountryUseCase import com.tangem.features.onramp.confirmresidency.ConfirmResidencyComponent +import com.tangem.features.onramp.confirmresidency.entity.ConfirmResidencyBottomSheetConfig import com.tangem.features.onramp.confirmresidency.entity.ConfirmResidencyUM import com.tangem.features.onramp.impl.R -import com.tangem.features.onramp.confirmresidency.entity.ConfirmResidencyBottomSheetConfig import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.launch import javax.inject.Inject @ComponentScoped internal class ConfirmResidencyModel @Inject constructor( override val dispatchers: CoroutineDispatcherProvider, private val router: Router, + private val saveDefaultCountryUseCase: OnrampSaveDefaultCountryUseCase, getOnrampCountryUseCase: GetOnrampCountryUseCase, paramsContainer: ParamsContainer, ) : Model() { @@ -54,7 +57,9 @@ internal class ConfirmResidencyModel @Inject constructor( private fun getPrimaryButtonConfig() = if (params.country.onrampAvailable) { ConfirmResidencyUM.ActionButtonConfig( - onClick = { params.onDismiss(params.country) }, + onClick = { + modelScope.launch { saveDefaultCountryUseCase.invoke(params.country) } + }, text = resourceReference(R.string.common_confirm), ) } else { diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/paymentmethod/DefaultSelectPaymentMethodComponent.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/paymentmethod/DefaultSelectPaymentMethodComponent.kt new file mode 100644 index 0000000000..75a8748835 --- /dev/null +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/paymentmethod/DefaultSelectPaymentMethodComponent.kt @@ -0,0 +1,45 @@ +package com.tangem.features.onramp.paymentmethod + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import com.tangem.core.decompose.context.AppComponentContext +import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig +import com.tangem.features.onramp.paymentmethod.entity.PaymentMethodsBottomSheetConfig +import com.tangem.features.onramp.paymentmethod.ui.SelectPaymentMethodBottomSheet +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import kotlinx.collections.immutable.toImmutableList + +internal class DefaultSelectPaymentMethodComponent @AssistedInject constructor( + @Assisted context: AppComponentContext, + @Assisted private val params: SelectPaymentMethodComponent.Params, +) : SelectPaymentMethodComponent, AppComponentContext by context { + + override fun dismiss() { + params.onDismiss() + } + + @Composable + override fun BottomSheet() { + val bottomSheetConfig = remember(key1 = this) { + TangemBottomSheetConfig( + isShow = true, + onDismissRequest = ::dismiss, + content = PaymentMethodsBottomSheetConfig( + selectedMethodId = params.selectedMethodId, + paymentMethods = params.paymentMethods.toImmutableList(), + ), + ) + } + SelectPaymentMethodBottomSheet(bottomSheetConfig) + } + + @AssistedFactory + interface Factory : SelectPaymentMethodComponent.Factory { + override fun create( + context: AppComponentContext, + params: SelectPaymentMethodComponent.Params, + ): DefaultSelectPaymentMethodComponent + } +} \ No newline at end of file diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/paymentmethod/SelectPaymentMethodComponent.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/paymentmethod/SelectPaymentMethodComponent.kt new file mode 100644 index 0000000000..8f0090306a --- /dev/null +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/paymentmethod/SelectPaymentMethodComponent.kt @@ -0,0 +1,16 @@ +package com.tangem.features.onramp.paymentmethod + +import com.tangem.core.decompose.factory.ComponentFactory +import com.tangem.core.ui.decompose.ComposableBottomSheetComponent +import com.tangem.features.onramp.paymentmethod.entity.PaymentMethodUM + +internal interface SelectPaymentMethodComponent : ComposableBottomSheetComponent { + + data class Params( + val selectedMethodId: String, + val paymentMethods: List, + 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/paymentmethod/di/SelectPaymentMethodComponentModule.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/paymentmethod/di/SelectPaymentMethodComponentModule.kt new file mode 100644 index 0000000000..48fe4dfaa7 --- /dev/null +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/paymentmethod/di/SelectPaymentMethodComponentModule.kt @@ -0,0 +1,20 @@ +package com.tangem.features.onramp.paymentmethod.di + +import com.tangem.features.onramp.paymentmethod.DefaultSelectPaymentMethodComponent +import com.tangem.features.onramp.paymentmethod.SelectPaymentMethodComponent +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 SelectPaymentMethodComponentModule { + + @Binds + @Singleton + fun bindSelectPaymentMethodComponentFactory( + factory: DefaultSelectPaymentMethodComponent.Factory, + ): SelectPaymentMethodComponent.Factory +} \ No newline at end of file diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/paymentmethod/entity/PaymentMethodUM.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/paymentmethod/entity/PaymentMethodUM.kt new file mode 100644 index 0000000000..08214001de --- /dev/null +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/paymentmethod/entity/PaymentMethodUM.kt @@ -0,0 +1,8 @@ +package com.tangem.features.onramp.paymentmethod.entity + +data class PaymentMethodUM( + val id: String, + val imageUrl: String, + val name: String, + val onSelect: () -> Unit, +) \ No newline at end of file diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/paymentmethod/entity/PaymentMethodsBottomSheetConfig.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/paymentmethod/entity/PaymentMethodsBottomSheetConfig.kt new file mode 100644 index 0000000000..80aeb52757 --- /dev/null +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/paymentmethod/entity/PaymentMethodsBottomSheetConfig.kt @@ -0,0 +1,9 @@ +package com.tangem.features.onramp.paymentmethod.entity + +import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent +import kotlinx.collections.immutable.ImmutableList + +internal data class PaymentMethodsBottomSheetConfig( + val selectedMethodId: String, + val paymentMethods: ImmutableList, +) : TangemBottomSheetConfigContent \ No newline at end of file diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/paymentmethod/ui/SelectPaymentMethodBottomSheet.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/paymentmethod/ui/SelectPaymentMethodBottomSheet.kt new file mode 100644 index 0000000000..75659d6baa --- /dev/null +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/paymentmethod/ui/SelectPaymentMethodBottomSheet.kt @@ -0,0 +1,118 @@ +package com.tangem.features.onramp.paymentmethod.ui + +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import coil.compose.AsyncImage +import com.tangem.core.ui.components.bottomsheets.TangemBottomSheet +import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig +import com.tangem.core.ui.extensions.resourceReference +import com.tangem.core.ui.res.TangemTheme +import com.tangem.features.onramp.impl.R +import com.tangem.features.onramp.paymentmethod.entity.PaymentMethodUM +import com.tangem.features.onramp.paymentmethod.entity.PaymentMethodsBottomSheetConfig +import kotlinx.collections.immutable.ImmutableList + +@Composable +internal fun SelectPaymentMethodBottomSheet(config: TangemBottomSheetConfig) { + TangemBottomSheet( + config = config, + addBottomInsets = true, + containerColor = TangemTheme.colors.background.tertiary, + titleText = resourceReference(R.string.onramp_pay_with), + content = { contentConfig -> + SelectPaymentMethodBottomSheetContent( + modifier = Modifier + .padding(horizontal = TangemTheme.dimens.spacing16) + .padding(top = TangemTheme.dimens.spacing12, bottom = TangemTheme.dimens.spacing24) + .fillMaxWidth() + .wrapContentHeight(), + selectedMethodId = contentConfig.selectedMethodId, + methods = contentConfig.paymentMethods, + ) + }, + ) +} + +@Composable +private fun SelectPaymentMethodBottomSheetContent( + selectedMethodId: String, + methods: ImmutableList, + modifier: Modifier = Modifier, +) { + LazyColumn( + modifier = modifier, + ) { + items( + items = methods, + key = { item -> item.id }, + contentType = { item -> item::class.java }, + itemContent = { item -> + val isSelected = remember(item, selectedMethodId) { + item.id == selectedMethodId + } + val itemModifier = if (isSelected) { + Modifier + .fillMaxWidth() + .border( + width = TangemTheme.dimens.size1, + color = TangemTheme.colors.text.accent, + shape = RoundedCornerShape(TangemTheme.dimens.radius16), + ) + .clip(RoundedCornerShape(TangemTheme.dimens.radius16)) + .clickable(onClick = item.onSelect) + .padding( + start = TangemTheme.dimens.spacing12, + top = TangemTheme.dimens.spacing10, + bottom = TangemTheme.dimens.spacing10, + ) + } else { + Modifier + .fillMaxWidth() + .clip(RoundedCornerShape(TangemTheme.dimens.radius16)) + .clickable(onClick = item.onSelect) + .padding( + start = TangemTheme.dimens.spacing12, + top = TangemTheme.dimens.spacing10, + bottom = TangemTheme.dimens.spacing10, + ) + } + PaymentMethodItem( + modifier = itemModifier, + paymentMethod = item, + isSelected = isSelected, + ) + }, + ) + } +} + +@Composable +private fun PaymentMethodItem(paymentMethod: PaymentMethodUM, isSelected: Boolean, modifier: Modifier = Modifier) { + Row( + modifier = modifier, + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing12), + ) { + AsyncImage( + modifier = Modifier + .size(TangemTheme.dimens.size40), + model = paymentMethod.imageUrl, + contentDescription = null, + ) + Text( + text = paymentMethod.name, + style = TangemTheme.typography.subtitle2, + color = if (isSelected) TangemTheme.colors.text.primary1 else TangemTheme.colors.text.secondary, + ) + } +} \ No newline at end of file