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 799ec969bf..d78bfa694d 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 @@ -83,9 +83,7 @@ internal class DefaultOnrampRepository( private val onrampErrorAdapter = moshi.adapter(ExpressErrorResponse::class.java) private val onrampErrorConverter = OnrampErrorConverter(onrampErrorAdapter) - override suspend fun getCurrencies(): Flow> = withContext(dispatchers.io) { - currenciesStore.get(CURRENCIES_KEY) - } + override fun getCurrencies(): Flow> = currenciesStore.get(CURRENCIES_KEY) override suspend fun fetchCurrencies() = withContext(dispatchers.io) { if (!currenciesStore.getSyncOrNull(CURRENCIES_KEY).isNullOrEmpty()) return@withContext @@ -97,9 +95,7 @@ internal class DefaultOnrampRepository( currenciesStore.store(CURRENCIES_KEY, result) } - override suspend fun getCountries(): Flow> = withContext(dispatchers.io) { - countriesStore.get(COUNTRIES_KEY) - } + override fun getCountries(): Flow> = countriesStore.get(COUNTRIES_KEY) override suspend fun getCountriesSync(): List? { return countriesStore.getSyncOrNull(COUNTRIES_KEY) diff --git a/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampCurrenciesUseCase.kt b/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampCurrenciesUseCase.kt index 33f5ac2f22..4c028a7b02 100644 --- a/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampCurrenciesUseCase.kt +++ b/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampCurrenciesUseCase.kt @@ -13,7 +13,7 @@ class GetOnrampCurrenciesUseCase( private val errorResolver: OnrampErrorResolver, ) { - suspend operator fun invoke(): EitherFlow { + operator fun invoke(): EitherFlow { return onrampRepository.getCurrencies().map { currenciesList -> Either.catch { val (populars, others) = currenciesList.toSet() 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 c5d09a5da7..4ddaca857c 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 @@ -10,8 +10,8 @@ import kotlinx.coroutines.flow.Flow @Suppress("TooManyFunctions") interface OnrampRepository { // api - suspend fun getCurrencies(): Flow> - suspend fun getCountries(): Flow> + fun getCurrencies(): Flow> + fun getCountries(): Flow> suspend fun getCountriesSync(): List? suspend fun getCountryByIp(): OnrampCountry suspend fun getStatus(txId: String): OnrampStatus diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/entity/transformer/UpdateCountryItemsErrorTransformer.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/entity/transformer/UpdateCountryItemsErrorTransformer.kt new file mode 100644 index 0000000000..f6346df096 --- /dev/null +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/entity/transformer/UpdateCountryItemsErrorTransformer.kt @@ -0,0 +1,15 @@ +package com.tangem.features.onramp.selectcountry.entity.transformer + +import com.tangem.features.onramp.selectcountry.entity.CountryListUM +import com.tangem.utils.transformer.Transformer + +internal class UpdateCountryItemsErrorTransformer( + private val onRetry: () -> Unit, +) : Transformer { + override fun transform(prevState: CountryListUM): CountryListUM { + return CountryListUM.Error( + searchBarUM = prevState.searchBarUM, + onRetry = onRetry, + ) + } +} \ No newline at end of file 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 60c6819e3b..d7e2a1c6ad 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 @@ -17,6 +17,7 @@ import com.tangem.features.onramp.selectcountry.SelectCountryComponent import com.tangem.features.onramp.selectcountry.entity.CountryItemState import com.tangem.features.onramp.selectcountry.entity.CountryListUM import com.tangem.features.onramp.selectcountry.entity.CountryListUMController +import com.tangem.features.onramp.selectcountry.entity.transformer.UpdateCountryItemsErrorTransformer import com.tangem.features.onramp.selectcountry.entity.transformer.UpdateCountryItemsLoadingTransformer import com.tangem.features.onramp.selectcountry.entity.transformer.UpdateCountryItemsTransformer import com.tangem.features.onramp.utils.InputManager @@ -26,8 +27,10 @@ import com.tangem.features.onramp.utils.sendOnrampErrorEvent import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.flow.* +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import javax.inject.Inject @@ -44,13 +47,12 @@ internal class OnrampSelectCountryModel @Inject constructor( paramsContainer: ParamsContainer, ) : Model() { - val state: StateFlow get() = countryListUMController.state + val state: StateFlow get() = controller.state private val params: SelectCountryComponent.Params = paramsContainer.require() - private val countryListUMController = CountryListUMController( + private val controller = CountryListUMController( searchBarUM = createSearchBarUM(), loadingItems = loadingItems, ) - private val refreshTrigger = MutableSharedFlow() init { analyticsEventHandler.send(OnrampAnalyticsEvent.SelectResidenceOpened) @@ -58,20 +60,13 @@ internal class OnrampSelectCountryModel @Inject constructor( modelScope.launch { subscribeOnUpdateState() } } - private fun updateCountriesList() { - modelScope.launch { - fetchOnrampCountriesUseCase() - } - } - fun dismiss() { params.onDismiss() } - @OptIn(ExperimentalCoroutinesApi::class) private suspend fun subscribeOnUpdateState() { combine( - flow = refreshTrigger.onStart { emit(Unit) }.flatMapLatest { getOnrampCountriesUseCase() }, + flow = getOnrampCountriesUseCase(), flow2 = getOnrampCountryUseCase(), flow3 = searchManager.query, ) { maybeCountries, maybeCountry, query -> @@ -89,7 +84,7 @@ internal class OnrampSelectCountryModel @Inject constructor( onCountryClick = ::saveCountry, ) } - .onEach(countryListUMController::update) + .onEach(controller::update) .launchIn(modelScope) } @@ -102,23 +97,31 @@ internal class OnrampSelectCountryModel @Inject constructor( } private fun onRetry() { - modelScope.launch { refreshTrigger.emit(Unit) } - countryListUMController.update(UpdateCountryItemsLoadingTransformer(loadingItems)) + controller.update(UpdateCountryItemsLoadingTransformer(loadingItems)) + updateCountriesList() + } + + private fun updateCountriesList() { + modelScope.launch { + fetchOnrampCountriesUseCase().onLeft { + controller.update(UpdateCountryItemsErrorTransformer(onRetry = ::onRetry)) + } + } } private fun onSearchQueryChange(newQuery: String) { - val searchBarUM = countryListUMController.state.value.searchBarUM + val searchBarUM = controller.state.value.searchBarUM if (searchBarUM.query == newQuery) return modelScope.launch { - countryListUMController.update(transformer = UpdateSearchQueryTransformer(newQuery)) + controller.update(transformer = UpdateSearchQueryTransformer(newQuery)) searchManager.update(newQuery) } } private fun onSearchBarActiveChange(isActive: Boolean) { - countryListUMController.update( + controller.update( transformer = UpdateSearchBarActiveStateTransformer( isActive = isActive, placeHolder = resourceReference(id = R.string.common_search), @@ -137,7 +140,7 @@ internal class OnrampSelectCountryModel @Inject constructor( } private companion object { - private const val LOADING_ITEMS_COUNT = 5 + const val LOADING_ITEMS_COUNT = 5 val loadingItems: ImmutableList = MutableList(LOADING_ITEMS_COUNT) { CountryItemState.Loading("Loading #$it") }.toImmutableList() diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcurrency/entity/transformer/UpdateCurrencyItemsErrorTransformer.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcurrency/entity/transformer/UpdateCurrencyItemsErrorTransformer.kt new file mode 100644 index 0000000000..6b89b621fa --- /dev/null +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcurrency/entity/transformer/UpdateCurrencyItemsErrorTransformer.kt @@ -0,0 +1,15 @@ +package com.tangem.features.onramp.selectcurrency.entity.transformer + +import com.tangem.features.onramp.selectcurrency.entity.CurrenciesListUM +import com.tangem.utils.transformer.Transformer + +internal class UpdateCurrencyItemsErrorTransformer( + private val onRetry: () -> Unit, +) : Transformer { + override fun transform(prevState: CurrenciesListUM): CurrenciesListUM { + return CurrenciesListUM.Error( + searchBarUM = prevState.searchBarUM, + onRetry = onRetry, + ) + } +} \ No newline at end of file diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcurrency/model/OnrampSelectCurrencyModel.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcurrency/model/OnrampSelectCurrencyModel.kt index 3ff2d6fc80..127d38cb94 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcurrency/model/OnrampSelectCurrencyModel.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcurrency/model/OnrampSelectCurrencyModel.kt @@ -18,6 +18,7 @@ import com.tangem.features.onramp.selectcurrency.entity.CurrenciesListUM import com.tangem.features.onramp.selectcurrency.entity.CurrenciesSection import com.tangem.features.onramp.selectcurrency.entity.CurrencyItemState import com.tangem.features.onramp.selectcurrency.entity.CurrencyListController +import com.tangem.features.onramp.selectcurrency.entity.transformer.UpdateCurrencyItemsErrorTransformer import com.tangem.features.onramp.selectcurrency.entity.transformer.UpdateCurrencyItemsLoadingTransformer import com.tangem.features.onramp.selectcurrency.entity.transformer.UpdateCurrencyItemsTransformer import com.tangem.features.onramp.utils.InputManager @@ -27,8 +28,10 @@ import com.tangem.features.onramp.utils.sendOnrampErrorEvent import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.flow.* +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import javax.inject.Inject @@ -51,23 +54,15 @@ internal class OnrampSelectCurrencyModel @Inject constructor( currencySearchBarUM = createSearchBarUM(), loadingSections = loadingSections, ) - private val refreshTrigger = MutableSharedFlow() init { updateCurrenciesList() subscribeOnUpdateState() } - private fun updateCurrenciesList() { - modelScope.launch { - fetchOnrampCurrenciesUseCase() - } - } - - @OptIn(ExperimentalCoroutinesApi::class) private fun subscribeOnUpdateState() { combine( - flow = refreshTrigger.onStart { emit(Unit) }.flatMapLatest { getOnrampCurrenciesUseCase() }, + flow = getOnrampCurrenciesUseCase(), flow2 = searchManager.query, ) { maybeCurrencies, query -> maybeCurrencies.onLeft { @@ -97,8 +92,16 @@ internal class OnrampSelectCurrencyModel @Inject constructor( } private fun onRetry() { - modelScope.launch { refreshTrigger.emit(Unit) } controller.update(UpdateCurrencyItemsLoadingTransformer(loadingSections)) + updateCurrenciesList() + } + + private fun updateCurrenciesList() { + modelScope.launch { + fetchOnrampCurrenciesUseCase().onLeft { + controller.update(UpdateCurrencyItemsErrorTransformer(onRetry = ::onRetry)) + } + } } private fun onSearchQueryChange(newQuery: String) {