Updated on 2026-08-14

This commit is contained in:
Tangem 2024-12-05 16:11:05 +05:00
parent 4aa09819aa
commit 98fee821fa
9 changed files with 73 additions and 11 deletions

View file

@ -162,6 +162,12 @@ internal object OnrampDomainModule {
return OnrampSaveSelectedPaymentMethod(onrampRepository)
}
@Provides
@Singleton
fun provideOnrampFetchPairsUseCase(onrampRepository: OnrampRepository): OnrampFetchPairsUseCase {
return OnrampFetchPairsUseCase(onrampRepository)
}
@Provides
@Singleton
fun provideGetOnrampRedirectUrlUseCase(

View file

@ -16,4 +16,7 @@ data class OnrampCurrencyDTO(
@Json(name = "precision")
val precision: Int,
@Json(name = "unit")
val unit: String?,
)

View file

@ -11,6 +11,7 @@ internal class CurrencyConverter : TwoWayConverter<OnrampCurrencyDTO, OnrampCurr
code = value.code,
image = value.image,
precision = value.precision,
unit = value.unit ?: value.code,
)
override fun convertBack(value: OnrampCurrency): OnrampCurrencyDTO = OnrampCurrencyDTO(
@ -18,5 +19,6 @@ internal class CurrencyConverter : TwoWayConverter<OnrampCurrencyDTO, OnrampCurr
code = value.code,
image = value.image,
precision = value.precision,
unit = value.unit,
)
}

View file

@ -8,4 +8,5 @@ data class OnrampCurrency(
val code: String,
val image: String,
val precision: Int,
val unit: String,
)

View file

@ -0,0 +1,16 @@
package com.tangem.domain.onramp
import arrow.core.Either
import com.tangem.domain.onramp.repositories.OnrampRepository
import com.tangem.domain.tokens.model.CryptoCurrency
class OnrampFetchPairsUseCase(private val repository: OnrampRepository) {
suspend operator fun invoke(cryptoCurrency: CryptoCurrency): Either<Throwable, Unit> {
return Either.catch {
val country = requireNotNull(repository.getDefaultCountrySync()) { "Country must not be null" }
val currency = requireNotNull(repository.getDefaultCurrencySync()) { "Currency must not be null" }
repository.fetchPairs(currency = currency, country = country, cryptoCurrency = cryptoCurrency)
}
}
}

View file

@ -12,10 +12,6 @@ import com.tangem.domain.tokens.model.AmountType
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.tokens.model.convertToAmount
import com.tangem.features.onramp.main.entity.*
import com.tangem.features.onramp.main.entity.OnrampAmountBlockUM
import com.tangem.features.onramp.main.entity.OnrampAmountSecondaryFieldUM
import com.tangem.features.onramp.main.entity.OnrampCurrencyUM
import com.tangem.features.onramp.main.entity.OnrampMainComponentUM
import com.tangem.utils.Provider
import java.math.BigDecimal
@ -77,7 +73,7 @@ internal class OnrampStateFactory(
}
private fun BigDecimal.convertToFiatAmount(currency: OnrampCurrency): Amount = Amount(
currencySymbol = currency.name,
currencySymbol = currency.unit,
value = this,
decimals = currency.precision,
type = AmountType.FiatType(currency.code),

View file

@ -39,7 +39,7 @@ internal class OnrampAmountStateFactory(
),
amountFieldModel = amountState.amountFieldModel.copy(
fiatAmount = amountState.amountFieldModel.fiatAmount.copy(
currencySymbol = currency.code,
currencySymbol = currency.unit,
decimals = currency.precision,
type = AmountType.FiatType(currency.code),
),
@ -65,6 +65,8 @@ internal class OnrampAmountStateFactory(
if (currentState !is OnrampMainComponentUM.Content) return currentState
val amountState = currentState.amountBlockState
if (amountState.amountFieldModel.fiatValue.isEmpty()) return currentState
return currentState.copy(
amountBlockState = amountState.copy(
secondaryFieldModel = quote.toSecondaryFieldUiModel(amountState),

View file

@ -33,6 +33,9 @@ import com.tangem.features.onramp.main.entity.factory.amount.OnrampAmountStateFa
import com.tangem.features.onramp.utils.InputManager
import com.tangem.utils.Provider
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import com.tangem.utils.coroutines.PeriodicTask
import com.tangem.utils.coroutines.SingleTaskScheduler
import com.tangem.utils.isNullOrZero
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import timber.log.Timber
@ -50,6 +53,7 @@ internal class OnrampMainComponentModel @Inject constructor(
private val clearOnrampCacheUseCase: ClearOnrampCacheUseCase,
private val fetchQuotesUseCase: OnrampFetchQuotesUseCase,
private val getOnrampQuotesUseCase: GetOnrampQuotesUseCase,
private val fetchPairsUseCase: OnrampFetchPairsUseCase,
private val amountInputManager: InputManager,
private val messageSender: UiMessageSender,
getWalletsUseCase: GetWalletsUseCase,
@ -73,6 +77,7 @@ internal class OnrampMainComponentModel @Inject constructor(
onClose = router::pop,
),
)
private val quotesTaskScheduler = SingleTaskScheduler<Unit>()
val state: StateFlow<OnrampMainComponentUM> get() = _state.asStateFlow()
val bottomSheetNavigation: SlotNavigation<OnrampMainBottomSheetConfig> = SlotNavigation()
@ -126,6 +131,7 @@ internal class OnrampMainComponentModel @Inject constructor(
val currency = maybeCurrency.getOrNull()
if (currency != null) {
_state.update { amountStateFactory.getUpdatedCurrencyState(currency) }
updatePairsAndQuotes()
}
}
.launchIn(modelScope)
@ -135,15 +141,39 @@ internal class OnrampMainComponentModel @Inject constructor(
amountInputManager.query
.filter(String::isNotEmpty)
.collectLatest { _ ->
val content = state.value as? OnrampMainComponentUM.Content ?: return@collectLatest
_state.update { amountStateFactory.getAmountSecondaryLoadingState() }
fetchQuotesUseCase.invoke(
amount = content.amountBlockState.amountFieldModel.fiatAmount,
cryptoCurrency = params.cryptoCurrency,
)
startLoadingQuotes()
}
}
private suspend fun updatePairsAndQuotes() {
fetchPairsUseCase.invoke(params.cryptoCurrency)
startLoadingQuotes()
}
private fun startLoadingQuotes() {
quotesTaskScheduler.cancelTask()
quotesTaskScheduler.scheduleTask(scope = modelScope, task = loadQuotesTask())
}
private fun loadQuotesTask(): PeriodicTask<Unit> {
return PeriodicTask(
delay = UPDATE_DELAY,
task = {
runCatching {
val content = state.value as? OnrampMainComponentUM.Content ?: return@runCatching
if (content.amountBlockState.amountFieldModel.fiatAmount.value.isNullOrZero()) return@runCatching
fetchQuotesUseCase.invoke(
amount = content.amountBlockState.amountFieldModel.fiatAmount,
cryptoCurrency = params.cryptoCurrency,
)
}
},
onSuccess = {},
onError = {},
)
}
private fun subscribeToQuotesUpdate() {
getOnrampQuotesUseCase.invoke()
.onEach { maybeQuotes ->
@ -205,6 +235,7 @@ internal class OnrampMainComponentModel @Inject constructor(
override fun onDestroy() {
modelScope.launch { clearOnrampCacheUseCase.invoke() }
quotesTaskScheduler.cancelTask()
super.onDestroy()
}
@ -236,4 +267,8 @@ internal class OnrampMainComponentModel @Inject constructor(
},
)
}
private companion object {
const val UPDATE_DELAY = 10_000L
}
}

View file

@ -60,6 +60,7 @@ private fun OnrampAmountField(amountField: AmountFieldModel) {
visualTransformation = AmountVisualTransformation(
decimals = amountField.fiatAmount.decimals,
symbol = amountField.fiatAmount.currencySymbol,
currencyCode = amountField.fiatAmount.currencySymbol,
decimalFormat = decimalFormat,
),
onValueChange = amountField.onValueChange,