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 b485886c06..29cd227fdd 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,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) + } } \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesKeys.kt b/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesKeys.kt index 60946f6ff4..a049a7db22 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesKeys.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/local/preferences/PreferencesKeys.kt @@ -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") 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 55fcfc1077..31afbf4c67 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 @@ -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 = 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( 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(PreferencesKeys.ONRAMP_DEFAULT_CURRENCY) ?.let(currencyConverter::convert) } @@ -57,4 +64,23 @@ internal class DefaultOnrampRepository( .getObject(PreferencesKeys.ONRAMP_DEFAULT_CURRENCY) .map { it?.let(currencyConverter::convert) } } + + override suspend fun saveDefaultCountry(country: OnrampCountry) = withContext(dispatchers.io) { + appPreferencesStore.storeObject( + key = PreferencesKeys.ONRAMP_DEFAULT_COUNTRY, + value = countryConverter.convertBack(country), + ) + } + + override suspend fun getDefaultCountrySync(): OnrampCountry? = withContext(dispatchers.io) { + appPreferencesStore + .getObjectSyncOrNull(PreferencesKeys.ONRAMP_DEFAULT_COUNTRY) + ?.let(countryConverter::convert) + } + + override fun getDefaultCountry(): Flow { + return appPreferencesStore + .getObject(PreferencesKeys.ONRAMP_DEFAULT_COUNTRY) + .map { it?.let(countryConverter::convert) } + } } \ No newline at end of file diff --git a/data/onramp/src/main/java/com/tangem/data/onramp/converters/CountryConverter.kt b/data/onramp/src/main/java/com/tangem/data/onramp/converters/CountryConverter.kt index 6d1c21f2d8..97099c62b1 100644 --- a/data/onramp/src/main/java/com/tangem/data/onramp/converters/CountryConverter.kt +++ b/data/onramp/src/main/java/com/tangem/data/onramp/converters/CountryConverter.kt @@ -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 { - - private val currencyConverter = CurrencyConverter() +internal class CountryConverter( + private val currencyConverter: CurrencyConverter, +) : TwoWayConverter { 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 { 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, + ) } \ No newline at end of file diff --git a/domain/onramp/models/src/main/kotlin/com/tangem/domain/onramp/model/OnrampCountry.kt b/domain/onramp/models/src/main/kotlin/com/tangem/domain/onramp/model/OnrampCountry.kt index fb718b7cc1..1a3a9b69dc 100644 --- a/domain/onramp/models/src/main/kotlin/com/tangem/domain/onramp/model/OnrampCountry.kt +++ b/domain/onramp/models/src/main/kotlin/com/tangem/domain/onramp/model/OnrampCountry.kt @@ -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, diff --git a/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampCountriesUseCase.kt b/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampCountriesUseCase.kt new file mode 100644 index 0000000000..bbf1323710 --- /dev/null +++ b/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampCountriesUseCase.kt @@ -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> { + return Either.catch { onrampRepository.getCountries() } + } +} \ No newline at end of file diff --git a/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampCountryUseCase.kt b/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampCountryUseCase.kt new file mode 100644 index 0000000000..209324027a --- /dev/null +++ b/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampCountryUseCase.kt @@ -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> { + return repository.getDefaultCountry() + .map> { it.right() } + .catch { emit(it.left()) } + } + + suspend fun invokeSync(): Either { + return Either.catch { repository.getDefaultCountrySync() ?: repository.getCountryByIp() } + } +} \ No newline at end of file diff --git a/domain/onramp/src/main/java/com/tangem/domain/onramp/OnrampSaveDefaultCountryUseCase.kt b/domain/onramp/src/main/java/com/tangem/domain/onramp/OnrampSaveDefaultCountryUseCase.kt new file mode 100644 index 0000000000..e939cfee5f --- /dev/null +++ b/domain/onramp/src/main/java/com/tangem/domain/onramp/OnrampSaveDefaultCountryUseCase.kt @@ -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) + } +} \ No newline at end of file diff --git a/domain/onramp/src/main/java/com/tangem/domain/onramp/OnrampSaveDefaultCurrencyUseCase.kt b/domain/onramp/src/main/java/com/tangem/domain/onramp/OnrampSaveDefaultCurrencyUseCase.kt index e30213f5ab..6362609fbf 100644 --- a/domain/onramp/src/main/java/com/tangem/domain/onramp/OnrampSaveDefaultCurrencyUseCase.kt +++ b/domain/onramp/src/main/java/com/tangem/domain/onramp/OnrampSaveDefaultCurrencyUseCase.kt @@ -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) } } \ 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 73c41ce3db..85b4e27f69 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 @@ -7,7 +7,11 @@ import kotlinx.coroutines.flow.Flow interface OnrampRepository { suspend fun getCurrencies(): List suspend fun getCountries(): List + suspend fun getCountryByIp(): OnrampCountry suspend fun saveDefaultCurrency(currency: OnrampCurrency) suspend fun getDefaultCurrencySync(): OnrampCurrency? fun getDefaultCurrency(): Flow + suspend fun saveDefaultCountry(country: OnrampCountry) + suspend fun getDefaultCountrySync(): OnrampCountry? + fun getDefaultCountry(): Flow } \ No newline at end of file diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/DefaultSelectCountryComponent.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/DefaultSelectCountryComponent.kt index 60c7d65ff5..35fc452dc8 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/DefaultSelectCountryComponent.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/DefaultSelectCountryComponent.kt @@ -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 diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/entity/CountryListUM.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/entity/CountryListUM.kt index f1e6365c95..6006c973c8 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/entity/CountryListUM.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/entity/CountryListUM.kt @@ -11,7 +11,7 @@ internal data class CountryListUM(val items: ImmutableList) } /** Get tokens */ - fun getTokens(): ImmutableList { + fun getCountries(): ImmutableList { if (getSearchBar() == null) return items return if (items.size > 1) { diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/entity/CountryListUMController.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/entity/CountryListUMController.kt index 5956d4128d..88015101bb 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/entity/CountryListUMController.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/entity/CountryListUMController.kt @@ -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 get() = _state.asStateFlow() private val _state: MutableStateFlow = 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 = + MutableList(LOADING_ITEMS_COUNT) { CountryItemState.Loading("Loading #$it") } } \ No newline at end of file diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/entity/transformer/UpdateCountryItemsTransformer.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/entity/transformer/UpdateCountryItemsTransformer.kt index 9b8e8b9f73..5489a9910c 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/entity/transformer/UpdateCountryItemsTransformer.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/entity/transformer/UpdateCountryItemsTransformer.kt @@ -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, + private val maybeCountries: Either>, + private val defaultCountry: OnrampCountry?, + private val query: String, private val onQueryChange: (String) -> Unit, private val onActiveChange: (Boolean) -> Unit, + private val onCountryClick: (OnrampCountry) -> Unit, ) : Transformer { 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.toUiModels(): List { + 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.filterByQuery(): List { + return filter { country -> + country.alpha3.lowercase().contains(query.lowercase()) || + country.name.lowercase().contains(query.lowercase()) + } + } private fun createSearchBarItem(): CountriesListItemUM.SearchBar { return CountriesListItemUM.SearchBar( diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/model/MockedCountriesData.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/model/MockedCountriesData.kt index 0c9622c58a..59c6d5d7c0 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/model/MockedCountriesData.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/model/MockedCountriesData.kt @@ -13,9 +13,6 @@ internal object MockedCountriesData { delay(3_000) // simulate network call emit(getMockedCountries()) } - fun getLoadingItems(): List = MutableList(5) { - CountryItemState.Loading("Loading #$it") - } private fun getMockedCountries(): List = MutableList(50) { index -> if (index % 5 == 0) { diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/model/OnrampSelectCountryModel.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/model/OnrampSelectCountryModel.kt index 4dd57e776f..8c4915a779 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/model/OnrampSelectCountryModel.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/model/OnrampSelectCountryModel.kt @@ -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 = 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.filterByQuery(query: String): List { - return filter { - (it as? CountryItemState.Content)?.countryName?.contains(query) == true || - (it as? CountryItemState.Unavailable)?.countryName?.contains(query) == true - } - } } \ No newline at end of file diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/ui/CountryListItem.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/ui/CountryListItem.kt index 1b285b7b66..7bc00833a0 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/ui/CountryListItem.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/ui/CountryListItem.kt @@ -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, diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/settings/DefaultOnrampSettingsComponent.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/settings/DefaultOnrampSettingsComponent.kt index 2fff47ec00..efec6676c4 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/settings/DefaultOnrampSettingsComponent.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/settings/DefaultOnrampSettingsComponent.kt @@ -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() diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/settings/entity/OnrampSettingsItemUM.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/settings/entity/OnrampSettingsItemUM.kt index f957739a26..9bd7ad60a1 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/settings/entity/OnrampSettingsItemUM.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/settings/entity/OnrampSettingsItemUM.kt @@ -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() } \ No newline at end of file diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/settings/model/OnrampSettingsModel.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/settings/model/OnrampSettingsModel.kt index edff4909ee..0f41e6f6ca 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/settings/model/OnrampSettingsModel.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/settings/model/OnrampSettingsModel.kt @@ -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 get() = _state val bottomSheetNavigation: SlotNavigation = 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 = MutableStateFlow(getInitialState()) + + init { + subscribeOnUpdateState() + } + + private fun subscribeOnUpdateState() { + getOnrampCountryUseCase.invoke() + .onEach(::updateResidenceState) + .launchIn(modelScope) + } + + private fun updateResidenceState(maybeCountry: Either) { + 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(), + ) + } } \ No newline at end of file