Updated on 2026-08-14
This commit is contained in:
parent
75e794abdf
commit
342b6a2f50
20 changed files with 254 additions and 60 deletions
|
|
@ -1,7 +1,6 @@
|
|||
package com.tangem.tap.di.domain
|
||||
|
||||
import com.tangem.domain.onramp.GetOnrampCurrenciesUseCase
|
||||
import com.tangem.domain.onramp.OnrampSaveDefaultCurrencyUseCase
|
||||
import com.tangem.domain.onramp.*
|
||||
import com.tangem.domain.onramp.repositories.OnrampRepository
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
|
|
@ -24,4 +23,22 @@ internal object OnrampDomainModule {
|
|||
fun provideOnrampSaveDefaultCurrencyUseCase(onrampRepository: OnrampRepository): OnrampSaveDefaultCurrencyUseCase {
|
||||
return OnrampSaveDefaultCurrencyUseCase(onrampRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideGetOnrampCountriesUseCase(onrampRepository: OnrampRepository): GetOnrampCountriesUseCase {
|
||||
return GetOnrampCountriesUseCase(onrampRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideGetOnrampCountryUseCase(onrampRepository: OnrampRepository): GetOnrampCountryUseCase {
|
||||
return GetOnrampCountryUseCase(onrampRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideOnrampSaveDefaultCountryUseCase(onrampRepository: OnrampRepository): OnrampSaveDefaultCountryUseCase {
|
||||
return OnrampSaveDefaultCountryUseCase(onrampRepository)
|
||||
}
|
||||
}
|
||||
|
|
@ -105,6 +105,8 @@ object PreferencesKeys {
|
|||
|
||||
val ONRAMP_DEFAULT_CURRENCY by lazy { stringPreferencesKey(name = "onrampDefaultCurrency") }
|
||||
|
||||
val ONRAMP_DEFAULT_COUNTRY by lazy { stringPreferencesKey(name = "onrampDefaultCountry") }
|
||||
|
||||
// region Permission
|
||||
fun getShouldShowPermission(permission: String) = booleanPreferencesKey("shouldShowPushPermission_$permission")
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import com.tangem.data.onramp.converters.CountryConverter
|
|||
import com.tangem.data.onramp.converters.CurrencyConverter
|
||||
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.preferences.AppPreferencesStore
|
||||
import com.tangem.datasource.local.preferences.PreferencesKeys
|
||||
|
|
@ -25,7 +26,7 @@ internal class DefaultOnrampRepository(
|
|||
) : OnrampRepository {
|
||||
|
||||
private val currencyConverter = CurrencyConverter()
|
||||
private val countryConverter = CountryConverter()
|
||||
private val countryConverter = CountryConverter(currencyConverter)
|
||||
|
||||
override suspend fun getCurrencies(): List<OnrampCurrency> = withContext(dispatchers.io) {
|
||||
onrampApi.getCurrencies()
|
||||
|
|
@ -39,15 +40,21 @@ internal class DefaultOnrampRepository(
|
|||
.map(countryConverter::convert)
|
||||
}
|
||||
|
||||
override suspend fun saveDefaultCurrency(currency: OnrampCurrency) {
|
||||
override suspend fun getCountryByIp(): OnrampCountry = withContext(dispatchers.io) {
|
||||
onrampApi.getCountryByIp()
|
||||
.getOrThrow()
|
||||
.let(countryConverter::convert)
|
||||
}
|
||||
|
||||
override suspend fun saveDefaultCurrency(currency: OnrampCurrency) = withContext(dispatchers.io) {
|
||||
appPreferencesStore.storeObject<OnrampCurrencyDTO>(
|
||||
key = PreferencesKeys.ONRAMP_DEFAULT_CURRENCY,
|
||||
value = currencyConverter.convertBack(currency),
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun getDefaultCurrencySync(): OnrampCurrency? {
|
||||
return appPreferencesStore
|
||||
override suspend fun getDefaultCurrencySync(): OnrampCurrency? = withContext(dispatchers.io) {
|
||||
appPreferencesStore
|
||||
.getObjectSyncOrNull<OnrampCurrencyDTO>(PreferencesKeys.ONRAMP_DEFAULT_CURRENCY)
|
||||
?.let(currencyConverter::convert)
|
||||
}
|
||||
|
|
@ -57,4 +64,23 @@ internal class DefaultOnrampRepository(
|
|||
.getObject<OnrampCurrencyDTO>(PreferencesKeys.ONRAMP_DEFAULT_CURRENCY)
|
||||
.map { it?.let(currencyConverter::convert) }
|
||||
}
|
||||
|
||||
override suspend fun saveDefaultCountry(country: OnrampCountry) = withContext(dispatchers.io) {
|
||||
appPreferencesStore.storeObject<OnrampCountryDTO>(
|
||||
key = PreferencesKeys.ONRAMP_DEFAULT_COUNTRY,
|
||||
value = countryConverter.convertBack(country),
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun getDefaultCountrySync(): OnrampCountry? = withContext(dispatchers.io) {
|
||||
appPreferencesStore
|
||||
.getObjectSyncOrNull<OnrampCountryDTO>(PreferencesKeys.ONRAMP_DEFAULT_COUNTRY)
|
||||
?.let(countryConverter::convert)
|
||||
}
|
||||
|
||||
override fun getDefaultCountry(): Flow<OnrampCountry?> {
|
||||
return appPreferencesStore
|
||||
.getObject<OnrampCountryDTO>(PreferencesKeys.ONRAMP_DEFAULT_COUNTRY)
|
||||
.map { it?.let(countryConverter::convert) }
|
||||
}
|
||||
}
|
||||
|
|
@ -2,13 +2,14 @@ package com.tangem.data.onramp.converters
|
|||
|
||||
import com.tangem.datasource.api.onramp.models.response.model.OnrampCountryDTO
|
||||
import com.tangem.domain.onramp.model.OnrampCountry
|
||||
import com.tangem.utils.converter.Converter
|
||||
import com.tangem.utils.converter.TwoWayConverter
|
||||
|
||||
internal class CountryConverter : Converter<OnrampCountryDTO, OnrampCountry> {
|
||||
|
||||
private val currencyConverter = CurrencyConverter()
|
||||
internal class CountryConverter(
|
||||
private val currencyConverter: CurrencyConverter,
|
||||
) : TwoWayConverter<OnrampCountryDTO, OnrampCountry> {
|
||||
|
||||
override fun convert(value: OnrampCountryDTO) = OnrampCountry(
|
||||
id = "${value.alpha3}-${value.name}",
|
||||
name = value.name,
|
||||
code = value.code,
|
||||
image = value.image,
|
||||
|
|
@ -17,4 +18,14 @@ internal class CountryConverter : Converter<OnrampCountryDTO, OnrampCountry> {
|
|||
defaultCurrency = currencyConverter.convert(value.defaultCurrency),
|
||||
onrampAvailable = value.onrampAvailable,
|
||||
)
|
||||
|
||||
override fun convertBack(value: OnrampCountry): OnrampCountryDTO = OnrampCountryDTO(
|
||||
name = value.name,
|
||||
code = value.code,
|
||||
image = value.image,
|
||||
alpha3 = value.alpha3,
|
||||
continent = value.continent,
|
||||
defaultCurrency = currencyConverter.convertBack(value.defaultCurrency),
|
||||
onrampAvailable = value.onrampAvailable,
|
||||
)
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.domain.onramp.model
|
||||
|
||||
data class OnrampCountry(
|
||||
val id: String,
|
||||
val name: String,
|
||||
val code: String,
|
||||
val image: String,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
package com.tangem.domain.onramp
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.onramp.model.OnrampCountry
|
||||
import com.tangem.domain.onramp.repositories.OnrampRepository
|
||||
|
||||
class GetOnrampCountriesUseCase(private val onrampRepository: OnrampRepository) {
|
||||
|
||||
suspend operator fun invoke(): Either<Throwable, List<OnrampCountry>> {
|
||||
return Either.catch { onrampRepository.getCountries() }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
package com.tangem.domain.onramp
|
||||
|
||||
import arrow.core.Either
|
||||
import arrow.core.left
|
||||
import arrow.core.right
|
||||
import com.tangem.domain.onramp.model.OnrampCountry
|
||||
import com.tangem.domain.onramp.repositories.OnrampRepository
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
class GetOnrampCountryUseCase(private val repository: OnrampRepository) {
|
||||
|
||||
operator fun invoke(): Flow<Either<Throwable, OnrampCountry?>> {
|
||||
return repository.getDefaultCountry()
|
||||
.map<OnrampCountry?, Either<Throwable, OnrampCountry?>> { it.right() }
|
||||
.catch { emit(it.left()) }
|
||||
}
|
||||
|
||||
suspend fun invokeSync(): Either<Throwable, OnrampCountry> {
|
||||
return Either.catch { repository.getDefaultCountrySync() ?: repository.getCountryByIp() }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package com.tangem.domain.onramp
|
||||
|
||||
import com.tangem.domain.onramp.model.OnrampCountry
|
||||
import com.tangem.domain.onramp.repositories.OnrampRepository
|
||||
|
||||
class OnrampSaveDefaultCountryUseCase(private val repository: OnrampRepository) {
|
||||
|
||||
suspend operator fun invoke(country: OnrampCountry) {
|
||||
repository.saveDefaultCountry(country)
|
||||
}
|
||||
}
|
||||
|
|
@ -3,9 +3,9 @@ package com.tangem.domain.onramp
|
|||
import com.tangem.domain.onramp.model.OnrampCurrency
|
||||
import com.tangem.domain.onramp.repositories.OnrampRepository
|
||||
|
||||
class OnrampSaveDefaultCurrencyUseCase(private val onrampRepository: OnrampRepository) {
|
||||
class OnrampSaveDefaultCurrencyUseCase(private val repository: OnrampRepository) {
|
||||
|
||||
suspend operator fun invoke(currency: OnrampCurrency) {
|
||||
onrampRepository.saveDefaultCurrency(currency)
|
||||
repository.saveDefaultCurrency(currency)
|
||||
}
|
||||
}
|
||||
|
|
@ -7,7 +7,11 @@ import kotlinx.coroutines.flow.Flow
|
|||
interface OnrampRepository {
|
||||
suspend fun getCurrencies(): List<OnrampCurrency>
|
||||
suspend fun getCountries(): List<OnrampCountry>
|
||||
suspend fun getCountryByIp(): OnrampCountry
|
||||
suspend fun saveDefaultCurrency(currency: OnrampCurrency)
|
||||
suspend fun getDefaultCurrencySync(): OnrampCurrency?
|
||||
fun getDefaultCurrency(): Flow<OnrampCurrency?>
|
||||
suspend fun saveDefaultCountry(country: OnrampCountry)
|
||||
suspend fun getDefaultCountrySync(): OnrampCountry?
|
||||
fun getDefaultCountry(): Flow<OnrampCountry?>
|
||||
}
|
||||
|
|
@ -19,13 +19,13 @@ import dagger.assisted.AssistedInject
|
|||
|
||||
internal class DefaultSelectCountryComponent @AssistedInject constructor(
|
||||
@Assisted appComponentContext: AppComponentContext,
|
||||
@Assisted private val params: SelectCountryComponent.Params,
|
||||
@Assisted params: SelectCountryComponent.Params,
|
||||
) : SelectCountryComponent, AppComponentContext by appComponentContext {
|
||||
|
||||
private val model: OnrampSelectCountryModel = getOrCreateModel(params)
|
||||
|
||||
override fun dismiss() {
|
||||
params.onDismiss()
|
||||
model.dismiss()
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ internal data class CountryListUM(val items: ImmutableList<CountriesListItemUM>)
|
|||
}
|
||||
|
||||
/** Get tokens */
|
||||
fun getTokens(): ImmutableList<CountriesListItemUM> {
|
||||
fun getCountries(): ImmutableList<CountriesListItemUM> {
|
||||
if (getSearchBar() == null) return items
|
||||
|
||||
return if (items.size > 1) {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package com.tangem.features.onramp.selectcountry.entity
|
||||
|
||||
import com.tangem.features.onramp.selectcountry.entity.transformer.UpdateCountryItemsTransformer
|
||||
import com.tangem.features.onramp.selectcountry.model.MockedCountriesData
|
||||
import com.tangem.features.onramp.utils.SearchBarUMTransformer
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
|
@ -11,12 +10,14 @@ import kotlinx.coroutines.flow.asStateFlow
|
|||
import kotlinx.coroutines.flow.update
|
||||
import javax.inject.Inject
|
||||
|
||||
private const val LOADING_ITEMS_COUNT = 5
|
||||
|
||||
internal class CountryListUMController @Inject constructor() {
|
||||
|
||||
val state: StateFlow<CountryListUM> get() = _state.asStateFlow()
|
||||
private val _state: MutableStateFlow<CountryListUM> = MutableStateFlow(
|
||||
value = CountryListUM(
|
||||
items = MockedCountriesData.getLoadingItems().map(CountriesListItemUM::Country).toImmutableList(),
|
||||
items = getLoadingItems().map(CountriesListItemUM::Country).toImmutableList(),
|
||||
),
|
||||
)
|
||||
|
||||
|
|
@ -35,7 +36,7 @@ internal class CountryListUMController @Inject constructor() {
|
|||
prevState.copy(
|
||||
items = persistentListOf(
|
||||
updatedSearchBar,
|
||||
*prevState.getTokens().toTypedArray(),
|
||||
*prevState.getCountries().toTypedArray(),
|
||||
),
|
||||
)
|
||||
} else {
|
||||
|
|
@ -48,4 +49,7 @@ internal class CountryListUMController @Inject constructor() {
|
|||
fun getSearchBar(): CountriesListItemUM.SearchBar? {
|
||||
return _state.value.getSearchBar()
|
||||
}
|
||||
|
||||
private fun getLoadingItems(): List<CountryItemState> =
|
||||
MutableList(LOADING_ITEMS_COUNT) { CountryItemState.Loading("Loading #$it") }
|
||||
}
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
package com.tangem.features.onramp.selectcountry.entity.transformer
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.core.ui.components.fields.entity.SearchBarUM
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.domain.onramp.model.OnrampCountry
|
||||
import com.tangem.features.onramp.impl.R
|
||||
import com.tangem.features.onramp.selectcountry.entity.CountriesListItemUM
|
||||
import com.tangem.features.onramp.selectcountry.entity.CountryItemState
|
||||
|
|
@ -10,22 +12,48 @@ import com.tangem.utils.transformer.Transformer
|
|||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
internal class UpdateCountryItemsTransformer(
|
||||
private val countries: List<CountryItemState>,
|
||||
private val maybeCountries: Either<Throwable, List<OnrampCountry>>,
|
||||
private val defaultCountry: OnrampCountry?,
|
||||
private val query: String,
|
||||
private val onQueryChange: (String) -> Unit,
|
||||
private val onActiveChange: (Boolean) -> Unit,
|
||||
private val onCountryClick: (OnrampCountry) -> Unit,
|
||||
) : Transformer<CountryListUM> {
|
||||
|
||||
override fun transform(prevState: CountryListUM): CountryListUM {
|
||||
val searchBarItem = prevState.getSearchBar() ?: createSearchBarItem()
|
||||
|
||||
return prevState.copy(
|
||||
items = (listOfNotNull(searchBarItem) + countries.map(::convertCountry)).toImmutableList(),
|
||||
return maybeCountries.fold(
|
||||
ifLeft = { prevState }, // TODO: [REDACTED_JIRA]
|
||||
ifRight = { countries ->
|
||||
val countriesListItems = countries.filterByQuery().toUiModels()
|
||||
prevState.copy(items = (listOf(searchBarItem) + countriesListItems).toImmutableList())
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
// TODO: Temporarily. Will be refactored after implement domain
|
||||
private fun convertCountry(state: CountryItemState): CountriesListItemUM.Country =
|
||||
CountriesListItemUM.Country(state)
|
||||
private fun List<OnrampCountry>.toUiModels(): List<CountriesListItemUM.Country> {
|
||||
return map { country ->
|
||||
val countryItemState = if (country.onrampAvailable) {
|
||||
CountryItemState.Content(
|
||||
id = country.id,
|
||||
flagUrl = country.image,
|
||||
countryName = country.name,
|
||||
isSelected = defaultCountry?.id?.equals(country.id) == true,
|
||||
onClick = { onCountryClick(country) },
|
||||
)
|
||||
} else {
|
||||
CountryItemState.Unavailable(id = country.id, flagUrl = country.image, countryName = country.name)
|
||||
}
|
||||
CountriesListItemUM.Country(countryItemState)
|
||||
}
|
||||
}
|
||||
|
||||
private fun List<OnrampCountry>.filterByQuery(): List<OnrampCountry> {
|
||||
return filter { country ->
|
||||
country.alpha3.lowercase().contains(query.lowercase()) ||
|
||||
country.name.lowercase().contains(query.lowercase())
|
||||
}
|
||||
}
|
||||
|
||||
private fun createSearchBarItem(): CountriesListItemUM.SearchBar {
|
||||
return CountriesListItemUM.SearchBar(
|
||||
|
|
|
|||
|
|
@ -13,9 +13,6 @@ internal object MockedCountriesData {
|
|||
delay(3_000) // simulate network call
|
||||
emit(getMockedCountries())
|
||||
}
|
||||
fun getLoadingItems(): List<CountryItemState> = MutableList(5) {
|
||||
CountryItemState.Loading("Loading #$it")
|
||||
}
|
||||
|
||||
private fun getMockedCountries(): List<CountryItemState> = MutableList(50) { index ->
|
||||
if (index % 5 == 0) {
|
||||
|
|
|
|||
|
|
@ -2,9 +2,14 @@ package com.tangem.features.onramp.selectcountry.model
|
|||
|
||||
import com.tangem.core.decompose.di.ComponentScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.domain.onramp.GetOnrampCountriesUseCase
|
||||
import com.tangem.domain.onramp.GetOnrampCountryUseCase
|
||||
import com.tangem.domain.onramp.OnrampSaveDefaultCountryUseCase
|
||||
import com.tangem.domain.onramp.model.OnrampCountry
|
||||
import com.tangem.features.onramp.impl.R
|
||||
import com.tangem.features.onramp.selectcountry.entity.CountryItemState
|
||||
import com.tangem.features.onramp.selectcountry.SelectCountryComponent
|
||||
import com.tangem.features.onramp.selectcountry.entity.CountryListUM
|
||||
import com.tangem.features.onramp.selectcountry.entity.CountryListUMController
|
||||
import com.tangem.features.onramp.selectcountry.entity.transformer.UpdateCountryItemsTransformer
|
||||
|
|
@ -17,36 +22,54 @@ import kotlinx.coroutines.launch
|
|||
import javax.inject.Inject
|
||||
|
||||
@ComponentScoped
|
||||
@Suppress("LongParameterList")
|
||||
internal class OnrampSelectCountryModel @Inject constructor(
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val searchManager: SearchManager,
|
||||
private val countryListUMController: CountryListUMController,
|
||||
private val getOnrampCountriesUseCase: GetOnrampCountriesUseCase,
|
||||
private val saveDefaultCountryUseCase: OnrampSaveDefaultCountryUseCase,
|
||||
private val getOnrampCountryUseCase: GetOnrampCountryUseCase,
|
||||
paramsContainer: ParamsContainer,
|
||||
) : Model() {
|
||||
|
||||
val state: StateFlow<CountryListUM> = countryListUMController.state
|
||||
private val params: SelectCountryComponent.Params = paramsContainer.require()
|
||||
|
||||
init {
|
||||
subscribeOnUpdateState()
|
||||
modelScope.launch { subscribeOnUpdateState() }
|
||||
}
|
||||
|
||||
private fun subscribeOnUpdateState() {
|
||||
combine(
|
||||
flow = MockedCountriesData.getCountryItems(),
|
||||
flow2 = searchManager.query,
|
||||
) { countryItems, query ->
|
||||
val filteredCountryItems = countryItems.filterByQuery(query = query)
|
||||
fun dismiss() {
|
||||
params.onDismiss()
|
||||
}
|
||||
|
||||
private suspend fun subscribeOnUpdateState() {
|
||||
combine(
|
||||
flow = flowOf(getOnrampCountriesUseCase.invoke()),
|
||||
flow2 = getOnrampCountryUseCase.invoke(),
|
||||
flow3 = searchManager.query,
|
||||
) { maybeCountries, maybeCountry, query ->
|
||||
UpdateCountryItemsTransformer(
|
||||
countries = filteredCountryItems,
|
||||
maybeCountries = maybeCountries,
|
||||
defaultCountry = maybeCountry.getOrNull(),
|
||||
query = query,
|
||||
onQueryChange = ::onSearchQueryChange,
|
||||
onActiveChange = ::onSearchBarActiveChange,
|
||||
onCountryClick = ::saveCountry,
|
||||
)
|
||||
}
|
||||
.onEach(countryListUMController::update)
|
||||
.flowOn(dispatchers.main)
|
||||
.launchIn(modelScope)
|
||||
}
|
||||
|
||||
private fun saveCountry(country: OnrampCountry) {
|
||||
modelScope.launch {
|
||||
saveDefaultCountryUseCase.invoke(country)
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
private fun onSearchQueryChange(newQuery: String) {
|
||||
val searchBar = countryListUMController.getSearchBar()
|
||||
if (searchBar?.searchBarUM?.query == newQuery) return
|
||||
|
|
@ -66,12 +89,4 @@ internal class OnrampSelectCountryModel @Inject constructor(
|
|||
),
|
||||
)
|
||||
}
|
||||
|
||||
// TODO: Temporarily. Will be refactored after implement domain
|
||||
private fun List<CountryItemState>.filterByQuery(query: String): List<CountryItemState> {
|
||||
return filter {
|
||||
(it as? CountryItemState.Content)?.countryName?.contains(query) == true ||
|
||||
(it as? CountryItemState.Unavailable)?.countryName?.contains(query) == true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -29,7 +29,9 @@ internal fun CountryListItem(state: CountriesListItemUM, modifier: Modifier = Mo
|
|||
when (state) {
|
||||
is CountriesListItemUM.Country -> CountryItem(
|
||||
state = state.state,
|
||||
modifier = modifier.countryClickable(state.state).padding(all = TangemTheme.dimens.spacing16),
|
||||
modifier = modifier
|
||||
.countryClickable(state.state)
|
||||
.padding(all = TangemTheme.dimens.spacing16),
|
||||
)
|
||||
is CountriesListItemUM.SearchBar -> SearchBar(
|
||||
state = state.searchBarUM,
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import androidx.activity.compose.BackHandler
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.arkivanov.decompose.ComponentContext
|
||||
import com.arkivanov.decompose.extensions.compose.jetpack.subscribeAsState
|
||||
import com.arkivanov.decompose.router.slot.childSlot
|
||||
|
|
@ -36,8 +37,9 @@ internal class DefaultOnrampSettingsComponent @AssistedInject constructor(
|
|||
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
val state by model.state.collectAsStateWithLifecycle()
|
||||
BackHandler(onBack = params.onBack)
|
||||
OnrampSettingsContent(modifier = modifier, state = model.state)
|
||||
OnrampSettingsContent(modifier = modifier, state = state)
|
||||
|
||||
val bottomSheet by bottomSheetSlot.subscribeAsState()
|
||||
bottomSheet.child?.instance?.BottomSheet()
|
||||
|
|
|
|||
|
|
@ -1,5 +1,9 @@
|
|||
package com.tangem.features.onramp.settings.entity
|
||||
|
||||
sealed class OnrampSettingsItemUM {
|
||||
data class Residence(val countryName: String, val flagUrl: String, val onClick: () -> Unit) : OnrampSettingsItemUM()
|
||||
data class Residence(
|
||||
val countryName: String = "",
|
||||
val flagUrl: String = "",
|
||||
val onClick: () -> Unit,
|
||||
) : OnrampSettingsItemUM()
|
||||
}
|
||||
|
|
@ -1,34 +1,69 @@
|
|||
package com.tangem.features.onramp.settings.model
|
||||
|
||||
import arrow.core.Either
|
||||
import com.arkivanov.decompose.router.slot.SlotNavigation
|
||||
import com.arkivanov.decompose.router.slot.activate
|
||||
import com.tangem.core.decompose.di.ComponentScoped
|
||||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.domain.onramp.GetOnrampCountryUseCase
|
||||
import com.tangem.domain.onramp.model.OnrampCountry
|
||||
import com.tangem.features.onramp.settings.OnrampSettingsComponent
|
||||
import com.tangem.features.onramp.settings.entity.OnrampSettingsConfig
|
||||
import com.tangem.features.onramp.settings.entity.OnrampSettingsItemUM
|
||||
import com.tangem.features.onramp.settings.entity.OnrampSettingsUM
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.flow.*
|
||||
import javax.inject.Inject
|
||||
|
||||
@ComponentScoped
|
||||
internal class OnrampSettingsModel @Inject constructor(
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val getOnrampCountryUseCase: GetOnrampCountryUseCase,
|
||||
paramsContainer: ParamsContainer,
|
||||
) : Model() {
|
||||
|
||||
private val params: OnrampSettingsComponent.Params = paramsContainer.require()
|
||||
val state: StateFlow<OnrampSettingsUM> get() = _state
|
||||
val bottomSheetNavigation: SlotNavigation<OnrampSettingsConfig> = SlotNavigation()
|
||||
val state = OnrampSettingsUM(
|
||||
onBack = params.onBack,
|
||||
items = listOf(
|
||||
OnrampSettingsItemUM.Residence(
|
||||
countryName = "United States of America",
|
||||
flagUrl = "",
|
||||
onClick = { bottomSheetNavigation.activate(OnrampSettingsConfig.SelectCountry) },
|
||||
),
|
||||
).toImmutableList(),
|
||||
)
|
||||
|
||||
private val params: OnrampSettingsComponent.Params = paramsContainer.require()
|
||||
private val _state: MutableStateFlow<OnrampSettingsUM> = MutableStateFlow(getInitialState())
|
||||
|
||||
init {
|
||||
subscribeOnUpdateState()
|
||||
}
|
||||
|
||||
private fun subscribeOnUpdateState() {
|
||||
getOnrampCountryUseCase.invoke()
|
||||
.onEach(::updateResidenceState)
|
||||
.launchIn(modelScope)
|
||||
}
|
||||
|
||||
private fun updateResidenceState(maybeCountry: Either<Throwable, OnrampCountry?>) {
|
||||
maybeCountry.onRight { country ->
|
||||
_state.update { state ->
|
||||
state.copy(
|
||||
items = listOf(
|
||||
OnrampSettingsItemUM.Residence(
|
||||
countryName = country?.name.orEmpty(),
|
||||
flagUrl = country?.image.orEmpty(),
|
||||
onClick = ::openSelectCountryBottomSheet,
|
||||
),
|
||||
).toImmutableList(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun openSelectCountryBottomSheet() {
|
||||
bottomSheetNavigation.activate(OnrampSettingsConfig.SelectCountry)
|
||||
}
|
||||
|
||||
private fun getInitialState(): OnrampSettingsUM {
|
||||
return OnrampSettingsUM(
|
||||
onBack = params.onBack,
|
||||
items = listOf(OnrampSettingsItemUM.Residence(onClick = ::openSelectCountryBottomSheet)).toImmutableList(),
|
||||
)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue