Updated on 2026-08-14

This commit is contained in:
Tangem 2025-04-23 13:28:11 +05:00
parent e87d946e40
commit a3a18854c8
48 changed files with 544 additions and 328 deletions

View file

@ -4,10 +4,12 @@ import com.tangem.core.decompose.factory.ComponentFactory
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
import com.tangem.domain.onramp.model.OnrampCountry
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.wallets.models.UserWalletId
internal interface ConfirmResidencyComponent : ComposableBottomSheetComponent {
data class Params(
val userWalletId: UserWalletId,
val cryptoCurrency: CryptoCurrency,
val country: OnrampCountry,
val onDismiss: () -> Unit,

View file

@ -69,6 +69,7 @@ internal class DefaultConfirmResidencyComponent @AssistedInject constructor(
is ConfirmResidencyBottomSheetConfig.SelectCountry -> selectCountryComponentFactory.create(
context = childByContext(componentContext),
params = SelectCountryComponent.Params(
userWalletId = params.userWalletId,
cryptoCurrency = params.cryptoCurrency,
onDismiss = { isCountrySelected ->
// Dismiss country select sheet

View file

@ -54,6 +54,7 @@ internal class DefaultOnrampMainComponent @AssistedInject constructor(
is OnrampMainBottomSheetConfig.ConfirmResidency -> confirmResidencyComponentFactory.create(
context = childByContext(componentContext),
params = ConfirmResidencyComponent.Params(
userWalletId = params.userWalletId,
cryptoCurrency = params.cryptoCurrency,
country = config.country,
onDismiss = {
@ -65,6 +66,7 @@ internal class DefaultOnrampMainComponent @AssistedInject constructor(
is OnrampMainBottomSheetConfig.CurrenciesList -> selectCurrencyComponentFactory.create(
context = childByContext(componentContext),
params = SelectCurrencyComponent.Params(
userWallet = model.userWallet,
cryptoCurrency = params.cryptoCurrency,
onDismiss = model.bottomSheetNavigation::dismiss,
),

View file

@ -57,6 +57,9 @@ internal class OnrampMainComponentModel @Inject constructor(
) : Model(), OnrampIntents {
private val params: OnrampMainComponent.Params = paramsContainer.require()
val userWallet = getWalletsUseCase.invokeSync().first { it.walletId == params.userWalletId }
private val stateFactory = OnrampStateFactory(
currentStateProvider = Provider { _state.value },
cryptoCurrency = params.cryptoCurrency,
@ -68,7 +71,6 @@ internal class OnrampMainComponentModel @Inject constructor(
onrampIntents = this,
cryptoCurrency = params.cryptoCurrency,
)
private val selectedUserWallet = getWalletsUseCase.invokeSync().first { it.walletId == params.userWalletId }
private val _state: MutableStateFlow<OnrampMainComponentUM> = MutableStateFlow(
value = stateFactory.getInitialState(
currency = params.cryptoCurrency.name,
@ -107,7 +109,7 @@ internal class OnrampMainComponentModel @Inject constructor(
private fun checkResidenceCountry() {
modelScope.launch {
checkOnrampAvailabilityUseCase()
checkOnrampAvailabilityUseCase(userWallet)
.onRight(::handleOnrampAvailability)
.onLeft(::handleOnrampError)
}
@ -158,7 +160,7 @@ internal class OnrampMainComponentModel @Inject constructor(
if (!state?.amountBlockState?.amountFieldModel?.fiatValue.isNullOrEmpty()) {
_state.update { amountStateFactory.getAmountSecondaryLoadingState() }
}
fetchPairsUseCase.invoke(params.cryptoCurrency).fold(
fetchPairsUseCase.invoke(userWallet, params.cryptoCurrency).fold(
ifLeft = ::handleOnrampError,
ifRight = { _state.update { amountStateFactory.getAmountSecondaryResetState() } },
)
@ -184,6 +186,7 @@ internal class OnrampMainComponentModel @Inject constructor(
val content = state.value as? OnrampMainComponentUM.Content ?: return@runCatching
if (content.amountBlockState.amountFieldModel.fiatAmount.value.isNullOrZero()) return@runCatching
fetchQuotesUseCase.invoke(
userWallet = userWallet,
amount = content.amountBlockState.amountFieldModel.fiatAmount,
cryptoCurrency = params.cryptoCurrency,
).onLeft(::handleOnrampError)
@ -216,7 +219,7 @@ internal class OnrampMainComponentModel @Inject constructor(
}
override fun onBuyClick(quote: OnrampProviderWithQuote.Data) {
if (isDemoCardUseCase.invoke(selectedUserWallet.cardId)) {
if (isDemoCardUseCase.invoke(userWallet.cardId)) {
showDemoWarning()
} else {
val currentContentState = state.value as? OnrampMainComponentUM.Content ?: return

View file

@ -14,6 +14,7 @@ import com.tangem.core.ui.extensions.wrappedList
import com.tangem.core.ui.message.DialogMessage
import com.tangem.domain.onramp.GetOnrampRedirectUrlUseCase
import com.tangem.domain.onramp.model.error.OnrampError
import com.tangem.domain.wallets.usecase.GetWalletsUseCase
import com.tangem.features.onramp.impl.R
import com.tangem.features.onramp.redirect.OnrampRedirectComponent
import com.tangem.features.onramp.redirect.entity.OnrampRedirectTopBarUM
@ -29,6 +30,7 @@ internal class OnrampRedirectModel @Inject constructor(
override val dispatchers: CoroutineDispatcherProvider,
private val urlOpener: UrlOpener,
private val getOnrampRedirectUrlUseCase: GetOnrampRedirectUrlUseCase,
private val getWalletsUseCase: GetWalletsUseCase,
private val messageSender: UiMessageSender,
private val analyticsEventHandler: AnalyticsEventHandler,
router: Router,
@ -36,6 +38,8 @@ internal class OnrampRedirectModel @Inject constructor(
) : Model() {
private val params: OnrampRedirectComponent.Params = paramsContainer.require()
private val selectedUserWallet = getWalletsUseCase.invokeSync().first { it.walletId == params.userWalletId }
val state = OnrampRedirectUM(
topBarConfig = OnrampRedirectTopBarUM(
title = combinedReference(
@ -62,7 +66,7 @@ internal class OnrampRedirectModel @Inject constructor(
fun getRedirectUrl(isDarkTheme: Boolean) {
modelScope.launch {
getOnrampRedirectUrlUseCase.invoke(
userWalletId = params.userWalletId,
userWallet = selectedUserWallet,
quote = params.onrampProviderWithQuote,
cryptoCurrency = params.cryptoCurrency,
isDarkTheme = isDarkTheme,

View file

@ -61,8 +61,9 @@ internal class DefaultOnrampComponent @AssistedInject constructor(
OnrampChild.Settings -> settingsComponentFactory.create(
context = childByContext(componentContext),
params = OnrampSettingsComponent.Params(
params.cryptoCurrency,
navigation::pop,
userWalletId = params.userWalletId,
cryptoCurrency = params.cryptoCurrency,
onBack = navigation::pop,
),
)
OnrampChild.Main -> onrampMainComponentFactory.create(

View file

@ -3,10 +3,15 @@ package com.tangem.features.onramp.selectcountry
import com.tangem.core.decompose.factory.ComponentFactory
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.wallets.models.UserWalletId
internal interface SelectCountryComponent : ComposableBottomSheetComponent {
data class Params(val cryptoCurrency: CryptoCurrency, val onDismiss: (Boolean) -> Unit)
data class Params(
val userWalletId: UserWalletId,
val cryptoCurrency: CryptoCurrency,
val onDismiss: (Boolean) -> Unit,
)
interface Factory : ComponentFactory<Params, SelectCountryComponent>
}

View file

@ -13,6 +13,7 @@ import com.tangem.domain.onramp.GetOnrampCountryUseCase
import com.tangem.domain.onramp.OnrampSaveDefaultCountryUseCase
import com.tangem.domain.onramp.analytics.OnrampAnalyticsEvent
import com.tangem.domain.onramp.model.OnrampCountry
import com.tangem.domain.wallets.usecase.GetWalletsUseCase
import com.tangem.features.onramp.impl.R
import com.tangem.features.onramp.selectcountry.SelectCountryComponent
import com.tangem.features.onramp.selectcountry.entity.CountryItemState
@ -44,11 +45,15 @@ internal class OnrampSelectCountryModel @Inject constructor(
private val saveDefaultCountryUseCase: OnrampSaveDefaultCountryUseCase,
private val getOnrampCountryUseCase: GetOnrampCountryUseCase,
private val fetchOnrampCountriesUseCase: FetchOnrampCountriesUseCase,
getWalletsUseCase: GetWalletsUseCase,
paramsContainer: ParamsContainer,
) : Model() {
val state: StateFlow<CountryListUM> get() = controller.state
private val params: SelectCountryComponent.Params = paramsContainer.require()
private val userWallet = getWalletsUseCase.invokeSync().first { it.walletId == params.userWalletId }
val state: StateFlow<CountryListUM> get() = controller.state
private val controller = CountryListUMController(
searchBarUM = createSearchBarUM(),
loadingItems = loadingItems,
@ -103,7 +108,7 @@ internal class OnrampSelectCountryModel @Inject constructor(
private fun updateCountriesList() {
modelScope.launch {
fetchOnrampCountriesUseCase().onLeft {
fetchOnrampCountriesUseCase(userWallet).onLeft {
controller.update(UpdateCountryItemsErrorTransformer(onRetry = ::onRetry))
}
}

View file

@ -3,10 +3,15 @@ package com.tangem.features.onramp.selectcurrency
import com.tangem.core.decompose.factory.ComponentFactory
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.wallets.models.UserWallet
internal interface SelectCurrencyComponent : ComposableBottomSheetComponent {
data class Params(val cryptoCurrency: CryptoCurrency, val onDismiss: () -> Unit)
data class Params(
val userWallet: UserWallet,
val cryptoCurrency: CryptoCurrency,
val onDismiss: () -> Unit,
)
interface Factory : ComponentFactory<Params, SelectCurrencyComponent>
}

View file

@ -97,7 +97,7 @@ internal class OnrampSelectCurrencyModel @Inject constructor(
private fun updateCurrenciesList() {
modelScope.launch {
fetchOnrampCurrenciesUseCase().onLeft {
fetchOnrampCurrenciesUseCase(userWallet = params.userWallet).onLeft {
controller.update(UpdateCurrencyItemsErrorTransformer(onRetry = ::onRetry))
}
}

View file

@ -52,7 +52,8 @@ internal class DefaultOnrampSettingsComponent @AssistedInject constructor(
OnrampSettingsConfig.SelectCountry -> selectCountryComponentFactory.create(
context = childByContext(componentContext),
params = SelectCountryComponent.Params(
params.cryptoCurrency,
userWalletId = params.userWalletId,
cryptoCurrency = params.cryptoCurrency,
onDismiss = { model.bottomSheetNavigation.dismiss() },
),
)

View file

@ -3,10 +3,15 @@ package com.tangem.features.onramp.settings
import com.tangem.core.decompose.factory.ComponentFactory
import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.wallets.models.UserWalletId
internal interface OnrampSettingsComponent : ComposableContentComponent {
data class Params(val cryptoCurrency: CryptoCurrency, val onBack: () -> Unit)
data class Params(
val userWalletId: UserWalletId,
val cryptoCurrency: CryptoCurrency,
val onBack: () -> Unit,
)
interface Factory : ComponentFactory<Params, OnrampSettingsComponent>
}

View file

@ -97,7 +97,7 @@ internal class OnrampSuccessComponentModel @Inject constructor(
return
}
getOnrampStatusUseCase(txId = transaction.txId)
getOnrampStatusUseCase(userWallet = userWallet, txId = transaction.txId)
.fold(
ifLeft = { error ->
analyticsEventHandler.sendOnrampErrorEvent(

View file

@ -19,6 +19,7 @@ import com.tangem.domain.tokens.GetTokenListUseCase
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.tokens.model.TokenList
import com.tangem.domain.wallets.usecase.GetWalletsUseCase
import com.tangem.feature.swap.domain.GetAvailablePairsUseCase
import com.tangem.feature.swap.domain.models.domain.LeastTokenInfo
import com.tangem.feature.swap.domain.models.domain.SwapPairLeast
@ -52,11 +53,13 @@ internal class AvailableSwapPairsModel @Inject constructor(
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
private val getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase,
private val getAvailablePairsUseCase: GetAvailablePairsUseCase,
private val getWalletsUseCase: GetWalletsUseCase,
) : Model() {
val state: StateFlow<TokenListUM> = tokenListUMController.state
private var params: AvailableSwapPairsComponent.Params = paramsContainer.require()
private val userWallet = getWalletsUseCase.invokeSync().first { it.walletId == params.userWalletId }
private val tokenListFlow = getTokenListUseCaseFlow()
@ -212,6 +215,7 @@ internal class AvailableSwapPairsModel @Inject constructor(
availablePairsByNetworkFlow.update(networkInfo = networkInfo, state = lceLoading())
getAvailablePairsUseCase(
userWallet = userWallet,
initialCurrency = networkInfo,
currencies = statuses.map(CryptoCurrencyStatus::currency),
)