Updated on 2026-08-14
This commit is contained in:
parent
44231e988d
commit
e72c2c87bc
28 changed files with 426 additions and 105 deletions
|
|
@ -72,7 +72,7 @@ internal class OnrampStateFactory(
|
|||
isValuePasted = false,
|
||||
onValuePastedTriggerDismiss = {},
|
||||
),
|
||||
secondaryFieldModel = OnrampAmountSecondaryFieldUM.Loading,
|
||||
secondaryFieldModel = OnrampAmountSecondaryFieldUM.Content(TextReference.EMPTY),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.tangem.features.onramp.main.entity.factory.amount
|
|||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.features.onramp.main.entity.OnrampAmountSecondaryFieldUM
|
||||
import com.tangem.features.onramp.main.entity.OnrampMainComponentUM
|
||||
import com.tangem.utils.Provider
|
||||
|
|
@ -56,7 +57,7 @@ internal class OnrampAmountFieldChangeConverter(
|
|||
return copy(
|
||||
amountBlockState = amountBlockState.copy(
|
||||
amountFieldModel = amountFieldModel,
|
||||
secondaryFieldModel = OnrampAmountSecondaryFieldUM.Loading,
|
||||
secondaryFieldModel = OnrampAmountSecondaryFieldUM.Content(TextReference.EMPTY),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,17 @@
|
|||
package com.tangem.features.onramp.main.entity.factory.amount
|
||||
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.extensions.wrappedList
|
||||
import com.tangem.core.ui.format.bigdecimal.crypto
|
||||
import com.tangem.core.ui.format.bigdecimal.fiat
|
||||
import com.tangem.core.ui.format.bigdecimal.format
|
||||
import com.tangem.domain.onramp.model.OnrampCurrency
|
||||
import com.tangem.domain.onramp.model.OnrampQuote
|
||||
import com.tangem.domain.tokens.model.AmountType
|
||||
import com.tangem.features.onramp.impl.R
|
||||
import com.tangem.features.onramp.main.entity.OnrampAmountBlockUM
|
||||
import com.tangem.features.onramp.main.entity.OnrampAmountSecondaryFieldUM
|
||||
import com.tangem.features.onramp.main.entity.OnrampMainComponentUM
|
||||
import com.tangem.utils.Provider
|
||||
|
||||
|
|
@ -35,4 +45,69 @@ internal class OnrampAmountStateFactory(private val currentStateProvider: Provid
|
|||
),
|
||||
)
|
||||
}
|
||||
|
||||
fun getAmountSecondaryLoadingState(): OnrampMainComponentUM {
|
||||
val currentState = currentStateProvider()
|
||||
if (currentState !is OnrampMainComponentUM.Content) return currentState
|
||||
|
||||
val amountState = currentState.amountBlockState
|
||||
|
||||
return currentState.copy(
|
||||
amountBlockState = amountState.copy(secondaryFieldModel = OnrampAmountSecondaryFieldUM.Loading),
|
||||
)
|
||||
}
|
||||
|
||||
fun getAmountSecondaryUpdatedState(quote: OnrampQuote): OnrampMainComponentUM {
|
||||
val currentState = currentStateProvider()
|
||||
if (currentState !is OnrampMainComponentUM.Content) return currentState
|
||||
|
||||
val amountState = currentState.amountBlockState
|
||||
return currentState.copy(
|
||||
amountBlockState = amountState.copy(
|
||||
secondaryFieldModel = quote.toUiModel(amountState),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun OnrampQuote.toUiModel(amountState: OnrampAmountBlockUM): OnrampAmountSecondaryFieldUM {
|
||||
return when (this) {
|
||||
is OnrampQuote.Content -> {
|
||||
val amount = toAmount.format {
|
||||
crypto(
|
||||
symbol = amountState.amountFieldModel.cryptoAmount.currencySymbol,
|
||||
decimals = amountState.amountFieldModel.cryptoAmount.decimals,
|
||||
)
|
||||
}
|
||||
OnrampAmountSecondaryFieldUM.Content(stringReference(amount))
|
||||
}
|
||||
is OnrampQuote.Error.AmountTooBigError -> {
|
||||
val amount = this.amount.value.format {
|
||||
fiat(
|
||||
fiatCurrencyCode = amountState.amountFieldModel.fiatAmount.currencySymbol,
|
||||
fiatCurrencySymbol = amountState.amountFieldModel.fiatAmount.currencySymbol,
|
||||
)
|
||||
}
|
||||
OnrampAmountSecondaryFieldUM.Error(
|
||||
resourceReference(
|
||||
R.string.onramp_max_amount_restriction,
|
||||
wrappedList(amount),
|
||||
),
|
||||
)
|
||||
}
|
||||
is OnrampQuote.Error.AmountTooSmallError -> {
|
||||
val amount = this.amount.value.format {
|
||||
fiat(
|
||||
fiatCurrencyCode = amountState.amountFieldModel.fiatAmount.currencySymbol,
|
||||
fiatCurrencySymbol = amountState.amountFieldModel.fiatAmount.currencySymbol,
|
||||
)
|
||||
}
|
||||
OnrampAmountSecondaryFieldUM.Error(
|
||||
resourceReference(
|
||||
R.string.onramp_min_amount_restriction,
|
||||
wrappedList(amount),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,9 +5,7 @@ import com.arkivanov.decompose.router.slot.activate
|
|||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.core.decompose.navigation.Router
|
||||
import com.tangem.domain.onramp.CheckOnrampAvailabilityUseCase
|
||||
import com.tangem.domain.onramp.ClearOnrampCacheUseCase
|
||||
import com.tangem.domain.onramp.GetOnrampCurrencyUseCase
|
||||
import com.tangem.domain.onramp.*
|
||||
import com.tangem.domain.onramp.model.OnrampAvailability
|
||||
import com.tangem.domain.onramp.model.OnrampCurrency
|
||||
import com.tangem.features.onramp.main.OnrampMainComponent
|
||||
|
|
@ -16,6 +14,7 @@ import com.tangem.features.onramp.main.entity.OnrampMainBottomSheetConfig
|
|||
import com.tangem.features.onramp.main.entity.OnrampMainComponentUM
|
||||
import com.tangem.features.onramp.main.entity.factory.OnrampStateFactory
|
||||
import com.tangem.features.onramp.main.entity.factory.amount.OnrampAmountStateFactory
|
||||
import com.tangem.features.onramp.utils.InputManager
|
||||
import com.tangem.utils.Provider
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.*
|
||||
|
|
@ -23,12 +22,16 @@ import kotlinx.coroutines.launch
|
|||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
internal class OnrampMainComponentModel @Inject constructor(
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val router: Router,
|
||||
private val checkOnrampAvailabilityUseCase: CheckOnrampAvailabilityUseCase,
|
||||
private val getOnrampCurrencyUseCase: GetOnrampCurrencyUseCase,
|
||||
private val clearOnrampCacheUseCase: ClearOnrampCacheUseCase,
|
||||
private val fetchQuotesUseCase: OnrampFetchQuotesUseCase,
|
||||
private val getOnrampQuotesUseCase: GetOnrampQuotesUseCase,
|
||||
private val amountInputManager: InputManager,
|
||||
paramsContainer: ParamsContainer,
|
||||
) : Model(), OnrampIntents {
|
||||
|
||||
|
|
@ -51,6 +54,7 @@ internal class OnrampMainComponentModel @Inject constructor(
|
|||
|
||||
init {
|
||||
checkResidenceCountry()
|
||||
subscribeToAmountChanges()
|
||||
}
|
||||
|
||||
private fun checkResidenceCountry() {
|
||||
|
|
@ -73,6 +77,7 @@ internal class OnrampMainComponentModel @Inject constructor(
|
|||
private fun handleOnrampAvailable(currency: OnrampCurrency) {
|
||||
_state.update { stateFactory.getReadyState(currency) }
|
||||
subscribeToCurrencyUpdates()
|
||||
subscribeToQuotesUpdate()
|
||||
}
|
||||
|
||||
private fun subscribeToCurrencyUpdates() {
|
||||
|
|
@ -86,8 +91,31 @@ internal class OnrampMainComponentModel @Inject constructor(
|
|||
.launchIn(modelScope)
|
||||
}
|
||||
|
||||
private fun subscribeToAmountChanges() = modelScope.launch {
|
||||
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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun subscribeToQuotesUpdate() {
|
||||
getOnrampQuotesUseCase.invoke()
|
||||
.onEach { maybeQuotes ->
|
||||
val quote = maybeQuotes.getOrNull()?.firstOrNull() ?: return@onEach
|
||||
_state.update { amountStateFactory.getAmountSecondaryUpdatedState(quote) }
|
||||
}
|
||||
.launchIn(modelScope)
|
||||
}
|
||||
|
||||
override fun onAmountValueChanged(value: String) {
|
||||
_state.update { amountStateFactory.getOnAmountValueChange(value) }
|
||||
modelScope.launch { amountInputManager.update(value) }
|
||||
}
|
||||
|
||||
override fun openSettings() {
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import com.tangem.features.onramp.selectcountry.entity.CountryListUM
|
|||
import com.tangem.features.onramp.selectcountry.entity.CountryListUMController
|
||||
import com.tangem.features.onramp.selectcountry.entity.transformer.UpdateCountryItemsLoadingTransformer
|
||||
import com.tangem.features.onramp.selectcountry.entity.transformer.UpdateCountryItemsTransformer
|
||||
import com.tangem.features.onramp.utils.SearchManager
|
||||
import com.tangem.features.onramp.utils.InputManager
|
||||
import com.tangem.features.onramp.utils.UpdateSearchBarActiveStateTransformer
|
||||
import com.tangem.features.onramp.utils.UpdateSearchQueryTransformer
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
|
|
@ -30,7 +30,7 @@ import javax.inject.Inject
|
|||
@ComponentScoped
|
||||
internal class OnrampSelectCountryModel @Inject constructor(
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val searchManager: SearchManager,
|
||||
private val searchManager: InputManager,
|
||||
private val getOnrampCountriesUseCase: GetOnrampCountriesUseCase,
|
||||
private val saveDefaultCountryUseCase: OnrampSaveDefaultCountryUseCase,
|
||||
private val getOnrampCountryUseCase: GetOnrampCountryUseCase,
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ import com.tangem.features.onramp.selectcurrency.entity.CurrencyItemState
|
|||
import com.tangem.features.onramp.selectcurrency.entity.CurrencyListController
|
||||
import com.tangem.features.onramp.selectcurrency.entity.transformer.UpdateCurrencyItemsLoadingTransformer
|
||||
import com.tangem.features.onramp.selectcurrency.entity.transformer.UpdateCurrencyItemsTransformer
|
||||
import com.tangem.features.onramp.utils.SearchManager
|
||||
import com.tangem.features.onramp.utils.InputManager
|
||||
import com.tangem.features.onramp.utils.UpdateSearchBarActiveStateTransformer
|
||||
import com.tangem.features.onramp.utils.UpdateSearchQueryTransformer
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
|
|
@ -31,7 +31,7 @@ import javax.inject.Inject
|
|||
@ComponentScoped
|
||||
internal class OnrampSelectCurrencyModel @Inject constructor(
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val searchManager: SearchManager,
|
||||
private val searchManager: InputManager,
|
||||
private val getOnrampCurrenciesUseCase: GetOnrampCurrenciesUseCase,
|
||||
private val saveDefaultCurrencyUseCase: OnrampSaveDefaultCurrencyUseCase,
|
||||
paramsContainer: ParamsContainer,
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ import com.tangem.features.onramp.swap.availablepairs.entity.transformers.SetLoa
|
|||
import com.tangem.features.onramp.tokenlist.entity.TokenListUM
|
||||
import com.tangem.features.onramp.tokenlist.entity.TokenListUMController
|
||||
import com.tangem.features.onramp.tokenlist.entity.transformer.UpdateTokenItemsTransformer
|
||||
import com.tangem.features.onramp.utils.SearchManager
|
||||
import com.tangem.features.onramp.utils.InputManager
|
||||
import com.tangem.features.onramp.utils.UpdateSearchBarActiveStateTransformer
|
||||
import com.tangem.features.onramp.utils.UpdateSearchQueryTransformer
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
|
|
@ -37,7 +37,7 @@ internal class AvailableSwapPairsModel @Inject constructor(
|
|||
getTokenListUseCase: GetTokenListUseCase,
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val tokenListUMController: TokenListUMController,
|
||||
private val searchManager: SearchManager,
|
||||
private val searchManager: InputManager,
|
||||
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||
private val getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase,
|
||||
private val getAvailablePairsUseCase: GetAvailablePairsUseCase,
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import com.tangem.features.onramp.tokenlist.OnrampTokenListComponent
|
|||
import com.tangem.features.onramp.tokenlist.entity.TokenListUM
|
||||
import com.tangem.features.onramp.tokenlist.entity.TokenListUMController
|
||||
import com.tangem.features.onramp.tokenlist.entity.transformer.UpdateTokenItemsTransformer
|
||||
import com.tangem.features.onramp.utils.SearchManager
|
||||
import com.tangem.features.onramp.utils.InputManager
|
||||
import com.tangem.features.onramp.utils.UpdateSearchBarActiveStateTransformer
|
||||
import com.tangem.features.onramp.utils.UpdateSearchQueryTransformer
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
|
|
@ -33,7 +33,7 @@ internal class OnrampTokenListModel @Inject constructor(
|
|||
paramsContainer: ParamsContainer,
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val tokenListUMController: TokenListUMController,
|
||||
private val searchManager: SearchManager,
|
||||
private val searchManager: InputManager,
|
||||
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||
private val getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase,
|
||||
private val getTokenListUseCase: GetTokenListUseCase,
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import javax.inject.Inject
|
|||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal class SearchManager @Inject constructor() {
|
||||
internal class InputManager @Inject constructor() {
|
||||
|
||||
val query: Flow<String>
|
||||
get() = _query
|
||||
Loading…
Add table
Add a link
Reference in a new issue