Updated on 2026-08-14
This commit is contained in:
parent
851d9ffea9
commit
9f65e1b80c
18 changed files with 347 additions and 2 deletions
|
|
@ -96,4 +96,10 @@ internal object OnrampDomainModule {
|
||||||
): OnrampSaveTransactionUseCase {
|
): OnrampSaveTransactionUseCase {
|
||||||
return OnrampSaveTransactionUseCase(onrampTransactionRepository)
|
return OnrampSaveTransactionUseCase(onrampTransactionRepository)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideGetOnrampPaymentMethodsUseCase(onrampRepository: OnrampRepository): GetOnrampPaymentMethodsUseCase {
|
||||||
|
return GetOnrampPaymentMethodsUseCase(onrampRepository)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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<List<PaymentMethodDTO>>,
|
||||||
|
) : OnrampPaymentMethodsStore, StringKeyDataStoreDecorator<String, List<PaymentMethodDTO>>(dataStore) {
|
||||||
|
|
||||||
|
override fun provideStringKey(key: String): String = key
|
||||||
|
}
|
||||||
|
|
@ -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<PaymentMethodDTO>?
|
||||||
|
|
||||||
|
suspend fun store(key: String, value: List<PaymentMethodDTO>)
|
||||||
|
|
||||||
|
suspend fun contains(key: String): Boolean
|
||||||
|
}
|
||||||
|
|
@ -1,12 +1,15 @@
|
||||||
package com.tangem.data.onramp
|
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.CountryConverter
|
||||||
import com.tangem.data.onramp.converters.CurrencyConverter
|
import com.tangem.data.onramp.converters.CurrencyConverter
|
||||||
import com.tangem.data.onramp.converters.StatusConverter
|
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.common.response.getOrThrow
|
||||||
import com.tangem.datasource.api.onramp.OnrampApi
|
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.OnrampCountryDTO
|
||||||
import com.tangem.datasource.api.onramp.models.response.model.OnrampCurrencyDTO
|
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.AppPreferencesStore
|
||||||
import com.tangem.datasource.local.preferences.PreferencesKeys
|
import com.tangem.datasource.local.preferences.PreferencesKeys
|
||||||
import com.tangem.datasource.local.preferences.utils.getObject
|
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.OnrampCountry
|
||||||
import com.tangem.domain.onramp.model.OnrampCurrency
|
import com.tangem.domain.onramp.model.OnrampCurrency
|
||||||
import com.tangem.domain.onramp.model.OnrampStatus
|
import com.tangem.domain.onramp.model.OnrampStatus
|
||||||
|
import com.tangem.domain.onramp.model.OnrampPaymentMethod
|
||||||
import com.tangem.domain.onramp.repositories.OnrampRepository
|
import com.tangem.domain.onramp.repositories.OnrampRepository
|
||||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
internal class DefaultOnrampRepository(
|
internal class DefaultOnrampRepository(
|
||||||
private val onrampApi: OnrampApi,
|
private val onrampApi: OnrampApi,
|
||||||
private val dispatchers: CoroutineDispatcherProvider,
|
private val dispatchers: CoroutineDispatcherProvider,
|
||||||
private val appPreferencesStore: AppPreferencesStore,
|
private val appPreferencesStore: AppPreferencesStore,
|
||||||
|
private val paymentMethodsStore: OnrampPaymentMethodsStore,
|
||||||
) : OnrampRepository {
|
) : OnrampRepository {
|
||||||
|
|
||||||
private val currencyConverter = CurrencyConverter()
|
private val currencyConverter = CurrencyConverter()
|
||||||
private val countryConverter = CountryConverter(currencyConverter)
|
private val countryConverter = CountryConverter(currencyConverter)
|
||||||
private val statusConverter = StatusConverter()
|
private val statusConverter = StatusConverter()
|
||||||
|
private val paymentMethodsConverter = PaymentMethodConverter()
|
||||||
|
|
||||||
override suspend fun getCurrencies(): List<OnrampCurrency> = withContext(dispatchers.io) {
|
override suspend fun getCurrencies(): List<OnrampCurrency> = withContext(dispatchers.io) {
|
||||||
onrampApi.getCurrencies()
|
onrampApi.getCurrencies()
|
||||||
|
|
@ -92,4 +99,28 @@ internal class DefaultOnrampRepository(
|
||||||
.getObject<OnrampCountryDTO>(PreferencesKeys.ONRAMP_DEFAULT_COUNTRY)
|
.getObject<OnrampCountryDTO>(PreferencesKeys.ONRAMP_DEFAULT_COUNTRY)
|
||||||
.map { it?.let(countryConverter::convert) }
|
.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<OnrampPaymentMethod> {
|
||||||
|
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"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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<PaymentMethodDTO, OnrampPaymentMethod> {
|
||||||
|
override fun convert(value: PaymentMethodDTO): OnrampPaymentMethod = OnrampPaymentMethod(
|
||||||
|
id = value.id,
|
||||||
|
name = value.name,
|
||||||
|
imageUrl = value.image,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -4,6 +4,7 @@ import com.tangem.data.onramp.DefaultOnrampErrorResolver
|
||||||
import com.tangem.data.onramp.DefaultOnrampRepository
|
import com.tangem.data.onramp.DefaultOnrampRepository
|
||||||
import com.tangem.data.onramp.DefaultOnrampTransactionRepository
|
import com.tangem.data.onramp.DefaultOnrampTransactionRepository
|
||||||
import com.tangem.datasource.api.onramp.OnrampApi
|
import com.tangem.datasource.api.onramp.OnrampApi
|
||||||
|
import com.tangem.datasource.local.onramp.OnrampPaymentMethodsStore
|
||||||
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
||||||
import com.tangem.domain.onramp.repositories.OnrampErrorResolver
|
import com.tangem.domain.onramp.repositories.OnrampErrorResolver
|
||||||
import com.tangem.domain.onramp.repositories.OnrampRepository
|
import com.tangem.domain.onramp.repositories.OnrampRepository
|
||||||
|
|
@ -25,11 +26,13 @@ internal object OnrampDataModule {
|
||||||
onrampApi: OnrampApi,
|
onrampApi: OnrampApi,
|
||||||
dispatchers: CoroutineDispatcherProvider,
|
dispatchers: CoroutineDispatcherProvider,
|
||||||
appPreferencesStore: AppPreferencesStore,
|
appPreferencesStore: AppPreferencesStore,
|
||||||
|
paymentMethodsStore: OnrampPaymentMethodsStore,
|
||||||
): OnrampRepository {
|
): OnrampRepository {
|
||||||
return DefaultOnrampRepository(
|
return DefaultOnrampRepository(
|
||||||
onrampApi = onrampApi,
|
onrampApi = onrampApi,
|
||||||
dispatchers = dispatchers,
|
dispatchers = dispatchers,
|
||||||
appPreferencesStore = appPreferencesStore,
|
appPreferencesStore = appPreferencesStore,
|
||||||
|
paymentMethodsStore = paymentMethodsStore,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
)
|
||||||
|
|
@ -8,6 +8,7 @@ class CheckOnrampAvailabilityUseCase(private val repository: OnrampRepository) {
|
||||||
|
|
||||||
suspend operator fun invoke(): Either<Throwable, OnrampAvailability> {
|
suspend operator fun invoke(): Either<Throwable, OnrampAvailability> {
|
||||||
return Either.catch {
|
return Either.catch {
|
||||||
|
repository.fetchPaymentMethodsIfAbsent()
|
||||||
repository.getDefaultCountrySync()?.let { savedCountry ->
|
repository.getDefaultCountrySync()?.let { savedCountry ->
|
||||||
return@catch if (savedCountry.onrampAvailable) {
|
return@catch if (savedCountry.onrampAvailable) {
|
||||||
val currency = repository.getDefaultCurrencySync() ?: run {
|
val currency = repository.getDefaultCurrencySync() ?: run {
|
||||||
|
|
|
||||||
|
|
@ -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<Throwable, List<OnrampPaymentMethod>> {
|
||||||
|
return Either.catch { repository.getPaymentMethods() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,6 +3,7 @@ package com.tangem.domain.onramp.repositories
|
||||||
import com.tangem.domain.onramp.model.OnrampCountry
|
import com.tangem.domain.onramp.model.OnrampCountry
|
||||||
import com.tangem.domain.onramp.model.OnrampCurrency
|
import com.tangem.domain.onramp.model.OnrampCurrency
|
||||||
import com.tangem.domain.onramp.model.OnrampStatus
|
import com.tangem.domain.onramp.model.OnrampStatus
|
||||||
|
import com.tangem.domain.onramp.model.OnrampPaymentMethod
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
interface OnrampRepository {
|
interface OnrampRepository {
|
||||||
|
|
@ -11,6 +12,7 @@ interface OnrampRepository {
|
||||||
suspend fun getCountries(): List<OnrampCountry>
|
suspend fun getCountries(): List<OnrampCountry>
|
||||||
suspend fun getCountryByIp(): OnrampCountry
|
suspend fun getCountryByIp(): OnrampCountry
|
||||||
suspend fun getStatus(txId: String): OnrampStatus
|
suspend fun getStatus(txId: String): OnrampStatus
|
||||||
|
suspend fun fetchPaymentMethodsIfAbsent()
|
||||||
|
|
||||||
// cache
|
// cache
|
||||||
suspend fun saveDefaultCurrency(currency: OnrampCurrency)
|
suspend fun saveDefaultCurrency(currency: OnrampCurrency)
|
||||||
|
|
@ -19,4 +21,5 @@ interface OnrampRepository {
|
||||||
suspend fun saveDefaultCountry(country: OnrampCountry)
|
suspend fun saveDefaultCountry(country: OnrampCountry)
|
||||||
suspend fun getDefaultCountrySync(): OnrampCountry?
|
suspend fun getDefaultCountrySync(): OnrampCountry?
|
||||||
fun getDefaultCountry(): Flow<OnrampCountry?>
|
fun getDefaultCountry(): Flow<OnrampCountry?>
|
||||||
|
suspend fun getPaymentMethods(): List<OnrampPaymentMethod>
|
||||||
}
|
}
|
||||||
|
|
@ -8,20 +8,23 @@ import com.tangem.core.decompose.model.ParamsContainer
|
||||||
import com.tangem.core.decompose.navigation.Router
|
import com.tangem.core.decompose.navigation.Router
|
||||||
import com.tangem.core.ui.extensions.resourceReference
|
import com.tangem.core.ui.extensions.resourceReference
|
||||||
import com.tangem.domain.onramp.GetOnrampCountryUseCase
|
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.ConfirmResidencyComponent
|
||||||
|
import com.tangem.features.onramp.confirmresidency.entity.ConfirmResidencyBottomSheetConfig
|
||||||
import com.tangem.features.onramp.confirmresidency.entity.ConfirmResidencyUM
|
import com.tangem.features.onramp.confirmresidency.entity.ConfirmResidencyUM
|
||||||
import com.tangem.features.onramp.impl.R
|
import com.tangem.features.onramp.impl.R
|
||||||
import com.tangem.features.onramp.confirmresidency.entity.ConfirmResidencyBottomSheetConfig
|
|
||||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@ComponentScoped
|
@ComponentScoped
|
||||||
internal class ConfirmResidencyModel @Inject constructor(
|
internal class ConfirmResidencyModel @Inject constructor(
|
||||||
override val dispatchers: CoroutineDispatcherProvider,
|
override val dispatchers: CoroutineDispatcherProvider,
|
||||||
private val router: Router,
|
private val router: Router,
|
||||||
|
private val saveDefaultCountryUseCase: OnrampSaveDefaultCountryUseCase,
|
||||||
getOnrampCountryUseCase: GetOnrampCountryUseCase,
|
getOnrampCountryUseCase: GetOnrampCountryUseCase,
|
||||||
paramsContainer: ParamsContainer,
|
paramsContainer: ParamsContainer,
|
||||||
) : Model() {
|
) : Model() {
|
||||||
|
|
@ -54,7 +57,9 @@ internal class ConfirmResidencyModel @Inject constructor(
|
||||||
|
|
||||||
private fun getPrimaryButtonConfig() = if (params.country.onrampAvailable) {
|
private fun getPrimaryButtonConfig() = if (params.country.onrampAvailable) {
|
||||||
ConfirmResidencyUM.ActionButtonConfig(
|
ConfirmResidencyUM.ActionButtonConfig(
|
||||||
onClick = { params.onDismiss(params.country) },
|
onClick = {
|
||||||
|
modelScope.launch { saveDefaultCountryUseCase.invoke(params.country) }
|
||||||
|
},
|
||||||
text = resourceReference(R.string.common_confirm),
|
text = resourceReference(R.string.common_confirm),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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<PaymentMethodUM>,
|
||||||
|
val onDismiss: () -> Unit,
|
||||||
|
)
|
||||||
|
|
||||||
|
interface Factory : ComponentFactory<Params, SelectPaymentMethodComponent>
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
@ -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,
|
||||||
|
)
|
||||||
|
|
@ -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<PaymentMethodUM>,
|
||||||
|
) : TangemBottomSheetConfigContent
|
||||||
|
|
@ -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<PaymentMethodsBottomSheetConfig>(
|
||||||
|
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<PaymentMethodUM>,
|
||||||
|
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,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue