Updated on 2026-08-14

This commit is contained in:
Tangem 2025-04-30 12:51:57 +03:00
commit 2541461d44
954 changed files with 22834 additions and 21200 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

@ -0,0 +1,48 @@
package com.tangem.features.onramp.deeplink
import com.tangem.common.routing.AppRoute
import com.tangem.common.routing.AppRouter
import com.tangem.features.onramp.success.OnrampSuccessScreenTrigger
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
internal class DefaultOnrampDeepLink @AssistedInject constructor(
private val appRouter: AppRouter,
private val onrampSuccessScreenTrigger: OnrampSuccessScreenTrigger,
@Assisted private val scope: CoroutineScope,
) : OnrampDeepLink() {
override fun onReceive(params: Map<String, String>) {
val txId = params[TX_ID_KEY]
val result = OnrampRedirectResult.getResult(params[RESULT_KEY])
when {
!txId.isNullOrEmpty() -> {
// finish current onramp flow and show onramp success screen
val replaceOnrampScreens = appRouter.stack
.filterNot { it is AppRoute.Onramp }
.toMutableList()
replaceOnrampScreens.add(AppRoute.OnrampSuccess(txId))
appRouter.replaceAll(*replaceOnrampScreens.toTypedArray())
}
result != OnrampRedirectResult.Unknown -> {
scope.launch {
onrampSuccessScreenTrigger.triggerOnrampSuccess(result == OnrampRedirectResult.Success)
}
}
}
}
@AssistedFactory
interface Factory : OnrampDeepLink.Factory {
override fun create(coroutineScope: CoroutineScope): DefaultOnrampDeepLink
}
private companion object {
const val TX_ID_KEY = "tx_id"
const val RESULT_KEY = "result"
}
}

View file

@ -0,0 +1,14 @@
package com.tangem.features.onramp.deeplink
enum class OnrampRedirectResult(val value: String) {
Success("success"),
Cancel("cancel"),
Unknown(""),
;
companion object {
fun getResult(result: String?): OnrampRedirectResult {
return entries.firstOrNull { it.value == result } ?: Unknown
}
}
}

View file

@ -0,0 +1,18 @@
package com.tangem.features.onramp.deeplink.di
import com.tangem.features.onramp.deeplink.DefaultOnrampDeepLink
import com.tangem.features.onramp.deeplink.OnrampDeepLink
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
internal interface OnrampDeeplinkModule {
@Binds
@Singleton
fun bindFactory(impl: DefaultOnrampDeepLink.Factory): OnrampDeepLink.Factory
}

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

@ -42,16 +42,13 @@ internal fun OnrampAmountContent(state: OnrampAmountBlockUM, modifier: Modifier
horizontalAlignment = Alignment.CenterHorizontally,
) {
OnrampCurrencyIcon(currencyUM = state.currencyUM)
OnrampAmountField(
amountField = state.amountFieldModel,
isLoading = state.secondaryFieldModel is OnrampAmountSecondaryFieldUM.Loading,
)
OnrampAmountField(amountField = state.amountFieldModel)
OnrampAmountSecondary(state = state.secondaryFieldModel)
}
}
@Composable
private fun OnrampAmountField(amountField: AmountFieldModel, isLoading: Boolean) {
private fun OnrampAmountField(amountField: AmountFieldModel) {
val decimalFormat = rememberDecimalFormat()
val requester = remember { FocusRequester() }
AmountTextField(
@ -70,7 +67,7 @@ private fun OnrampAmountField(amountField: AmountFieldModel, isLoading: Boolean)
color = TangemTheme.colors.text.primary1,
textAlign = TextAlign.Center,
),
isEnabled = !amountField.isError && !isLoading,
isEnabled = !amountField.isError,
isAutoResize = true,
isValuePasted = amountField.isValuePasted,
onValuePastedTriggerDismiss = amountField.onValuePastedTriggerDismiss,

View file

@ -1,9 +1,10 @@
package com.tangem.features.onramp.redirect.model
import com.tangem.common.routing.AppRoute
import com.tangem.common.routing.AppRouter
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.model.ParamsContainer
import com.tangem.core.decompose.navigation.Router
import com.tangem.core.decompose.ui.UiMessageSender
import com.tangem.core.navigation.url.UrlOpener
import com.tangem.core.ui.components.appbar.models.TopAppBarButtonUM
@ -13,13 +14,18 @@ import com.tangem.core.ui.extensions.stringReference
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.cache.OnrampTransaction
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
import com.tangem.features.onramp.redirect.entity.OnrampRedirectUM
import com.tangem.features.onramp.success.OnrampSuccessScreenListener
import com.tangem.features.onramp.utils.sendOnrampErrorEvent
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import timber.log.Timber
import javax.inject.Inject
@ -31,11 +37,17 @@ internal class OnrampRedirectModel @Inject constructor(
private val getOnrampRedirectUrlUseCase: GetOnrampRedirectUrlUseCase,
private val messageSender: UiMessageSender,
private val analyticsEventHandler: AnalyticsEventHandler,
router: Router,
private val onrampSuccessScreenListener: OnrampSuccessScreenListener,
private val appRouter: AppRouter,
paramsContainer: ParamsContainer,
getWalletsUseCase: GetWalletsUseCase,
) : Model() {
private val params: OnrampRedirectComponent.Params = paramsContainer.require()
private val selectedUserWallet = getWalletsUseCase.invokeSync().first { it.walletId == params.userWalletId }
private var latestOnrampTransaction: OnrampTransaction? = null
val state = OnrampRedirectUM(
topBarConfig = OnrampRedirectTopBarUM(
title = combinedReference(
@ -44,7 +56,7 @@ internal class OnrampRedirectModel @Inject constructor(
),
startButtonUM = TopAppBarButtonUM(
iconRes = R.drawable.ic_close_24,
onIconClicked = router::pop,
onIconClicked = appRouter::pop,
enabled = true,
),
),
@ -59,22 +71,45 @@ internal class OnrampRedirectModel @Inject constructor(
),
)
init {
subscribeToOnrampSuccessListener()
}
fun getRedirectUrl(isDarkTheme: Boolean) {
modelScope.launch {
getOnrampRedirectUrlUseCase.invoke(
userWalletId = params.userWalletId,
userWallet = selectedUserWallet,
quote = params.onrampProviderWithQuote,
cryptoCurrency = params.cryptoCurrency,
isDarkTheme = isDarkTheme,
)
.onLeft(::handleError)
.onRight {
params.onBack()
urlOpener.openUrl(it)
latestOnrampTransaction = it
urlOpener.openUrl(it.redirectUrl)
}
}
}
private fun subscribeToOnrampSuccessListener() {
onrampSuccessScreenListener.onrampSuccessTriggerFlow
.onEach { result ->
val latestTxId = latestOnrampTransaction?.txId
if (latestTxId != null && result) {
// Finish current onramp flow and show onramp success screen
val replaceOnrampScreens = appRouter.stack
.filterNot { it is AppRoute.Onramp }
.toMutableList()
replaceOnrampScreens.add(AppRoute.OnrampSuccess(latestTxId))
appRouter.replaceAll(*replaceOnrampScreens.toTypedArray())
} else {
// Close redirect screen and show last onramp state
params.onBack()
}
}
.launchIn(modelScope)
}
private fun handleError(error: OnrampError) {
Timber.e(error.toString())
analyticsEventHandler.sendOnrampErrorEvent(

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

@ -0,0 +1,26 @@
package com.tangem.features.onramp.success
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import javax.inject.Inject
import javax.inject.Singleton
interface OnrampSuccessScreenListener {
val onrampSuccessTriggerFlow: Flow<Boolean>
}
interface OnrampSuccessScreenTrigger {
suspend fun triggerOnrampSuccess(result: Boolean)
}
@Singleton
internal class DefaultOnrampSuccessScreenTrigger @Inject constructor() :
OnrampSuccessScreenTrigger,
OnrampSuccessScreenListener {
override val onrampSuccessTriggerFlow = MutableSharedFlow<Boolean>()
override suspend fun triggerOnrampSuccess(result: Boolean) {
onrampSuccessTriggerFlow.emit(result)
}
}

View file

@ -2,6 +2,9 @@ package com.tangem.features.onramp.success.di
import com.tangem.features.onramp.component.OnrampSuccessComponent
import com.tangem.features.onramp.success.DefaultOnrampSuccessComponent
import com.tangem.features.onramp.success.DefaultOnrampSuccessScreenTrigger
import com.tangem.features.onramp.success.OnrampSuccessScreenListener
import com.tangem.features.onramp.success.OnrampSuccessScreenTrigger
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
@ -16,4 +19,12 @@ internal interface OnrampSuccessComponentModule {
fun bindOnrampSuccessComponentFactory(
factory: DefaultOnrampSuccessComponent.Factory,
): OnrampSuccessComponent.Factory
@Binds
@Singleton
fun bindOnrampSuccessScreenTrigger(impl: DefaultOnrampSuccessScreenTrigger): OnrampSuccessScreenTrigger
@Binds
@Singleton
fun bindOnrampSuccessScreenListener(impl: DefaultOnrampSuccessScreenTrigger): OnrampSuccessScreenListener
}

View file

@ -2,4 +2,5 @@ package com.tangem.features.onramp.success.entity
interface OnrampSuccessClickIntents {
fun goToProviderClick(providerLink: String)
fun onCopyClick(copiedText: String)
}

View file

@ -25,6 +25,7 @@ internal class SetOnrampSuccessContentConverter(
private val cryptoCurrency: CryptoCurrency,
private val transaction: OnrampTransaction,
private val goToProviderClick: (String) -> Unit,
private val onCopyClick: (String) -> Unit,
) : Converter<OnrampStatus, OnrampSuccessComponentUM> {
override fun convert(value: OnrampStatus): OnrampSuccessComponentUM {
return OnrampSuccessComponentUM.Content(
@ -46,8 +47,12 @@ internal class SetOnrampSuccessContentConverter(
),
providerName = stringReference(transaction.providerName),
providerImageUrl = transaction.providerImageUrl,
statusBlock = convertStatuses(value.status, value.externalTxUrl),
notification = getNotification(value.status, value.externalTxUrl),
statusBlock = convertStatuses(
status = value.status,
externalTxId = value.externalTxId,
externalTxUrl = value.externalTxUrl,
),
notification = getNotification(status = value.status, externalTxUrl = value.externalTxUrl),
)
}
@ -73,7 +78,11 @@ internal class SetOnrampSuccessContentConverter(
null
}
private fun convertStatuses(status: OnrampStatus.Status, externalTxUrl: String?): ExpressStatusUM {
private fun convertStatuses(
status: OnrampStatus.Status,
externalTxId: String?,
externalTxUrl: String?,
): ExpressStatusUM {
val statuses = with(status) {
persistentListOf(
getAwaitingDepositItem(),
@ -85,7 +94,7 @@ internal class SetOnrampSuccessContentConverter(
return ExpressStatusUM(
title = resourceReference(R.string.common_transaction_status),
link = getStatusLink(status, externalTxUrl),
link = getStatusLink(status = status, externalTxId = externalTxId, externalTxUrl = externalTxUrl),
statuses = statuses,
)
}
@ -148,6 +157,10 @@ internal class SetOnrampSuccessContentConverter(
this == OnrampStatus.Status.Paid -> {
resourceReference(R.string.express_status_buying_active, wrappedList(cryptoCurrency.name))
}
this == OnrampStatus.Status.RefundInProgress ||
this == OnrampStatus.Status.Refunded -> {
resourceReference(R.string.express_exchange_status_failed)
}
else -> {
resourceReference(R.string.express_status_bought, wrappedList(cryptoCurrency.name))
}
@ -166,6 +179,12 @@ internal class SetOnrampSuccessContentConverter(
wrappedList(cryptoCurrency.name),
)
}
this == OnrampStatus.Status.RefundInProgress -> {
resourceReference(R.string.express_exchange_status_refunding)
}
this == OnrampStatus.Status.Refunded -> {
resourceReference(R.string.express_exchange_status_refunded)
}
else -> {
resourceReference(R.string.express_exchange_status_sent, wrappedList(cryptoCurrency.name))
}
@ -173,7 +192,11 @@ internal class SetOnrampSuccessContentConverter(
state = getStatusState(OnrampStatus.Status.Sending),
)
private fun getStatusLink(status: OnrampStatus.Status, externalTxUrl: String?): ExpressLinkUM {
private fun getStatusLink(
status: OnrampStatus.Status,
externalTxId: String?,
externalTxUrl: String?,
): ExpressLinkUM {
if (externalTxUrl == null) return ExpressLinkUM.Empty
return when (status) {
OnrampStatus.Status.Verifying,
@ -187,7 +210,15 @@ internal class SetOnrampSuccessContentConverter(
},
)
}
else -> ExpressLinkUM.Empty
else -> if (externalTxId != null) {
ExpressLinkUM.Content(
icon = R.drawable.ic_copy_24,
text = resourceReference(R.string.express_transaction_id, wrappedList(externalTxId)),
onClick = { onCopyClick(externalTxId) },
)
} else {
ExpressLinkUM.Empty
}
}
}

View file

@ -7,6 +7,7 @@ import com.tangem.core.decompose.model.ParamsContainer
import com.tangem.core.decompose.navigation.Router
import com.tangem.core.decompose.ui.UiMessageSender
import com.tangem.core.navigation.url.UrlOpener
import com.tangem.core.ui.clipboard.ClipboardManager
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.wrappedList
import com.tangem.core.ui.message.DialogMessage
@ -46,6 +47,7 @@ internal class OnrampSuccessComponentModel @Inject constructor(
private val getUserWalletUseCase: GetUserWalletUseCase,
private val analyticsEventHandler: AnalyticsEventHandler,
private val messageSender: UiMessageSender,
private val clipboardManager: ClipboardManager,
private val router: Router,
paramsContainer: ParamsContainer,
) : Model(), OnrampSuccessClickIntents {
@ -65,9 +67,13 @@ internal class OnrampSuccessComponentModel @Inject constructor(
urlOpener.openUrl(providerLink)
}
override fun onCopyClick(copiedText: String) {
clipboardManager.setText(text = copiedText, isSensitive = false)
}
private fun loadData() {
modelScope.launch {
getOnrampTransactionUseCase(externalTxId = params.externalTxId)
getOnrampTransactionUseCase(txId = params.txId)
.fold(
ifLeft = { error ->
Timber.e(error.toString())
@ -97,7 +103,7 @@ internal class OnrampSuccessComponentModel @Inject constructor(
return
}
getOnrampStatusUseCase(txId = transaction.txId)
getOnrampStatusUseCase(userWallet = userWallet, txId = transaction.txId)
.fold(
ifLeft = { error ->
analyticsEventHandler.sendOnrampErrorEvent(
@ -124,6 +130,7 @@ internal class OnrampSuccessComponentModel @Inject constructor(
cryptoCurrency = cryptoCurrency,
transaction = transaction,
goToProviderClick = ::goToProviderClick,
onCopyClick = ::onCopyClick,
).convert(status)
}
removeTransactionIfTerminalStatus(

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),
)