From b5a54b0e29f8827a510b745d52d9ac7786acebe6 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 3 Dec 2024 20:17:14 +0500 Subject: [PATCH] Updated on 2026-08-14 --- .../data/onramp/DefaultOnrampRepository.kt | 2 +- .../onramp/model/OnrampRedirectError.kt | 8 +++ .../onramp/GetOnrampRedirectUrlUseCase.kt | 5 +- .../onramp/main/OnrampMainComponent.kt | 2 + .../main/model/OnrampMainComponentModel.kt | 66 ++++++++++++++++--- .../redirect/model/OnrampRedirectModel.kt | 35 +++++++++- .../onramp/root/DefaultOnrampComponent.kt | 1 + 7 files changed, 105 insertions(+), 14 deletions(-) create mode 100644 domain/onramp/models/src/main/kotlin/com/tangem/domain/onramp/model/OnrampRedirectError.kt 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 aa7e56fae3..b8034ca4a2 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 @@ -305,7 +305,7 @@ internal class DefaultOnrampRepository( toAmount = quote.toAmount.value, ) } else { - error("Express signature invalid") + throw OnrampRedirectError.VerificationFailed } } catch (e: Exception) { Timber.e(e) diff --git a/domain/onramp/models/src/main/kotlin/com/tangem/domain/onramp/model/OnrampRedirectError.kt b/domain/onramp/models/src/main/kotlin/com/tangem/domain/onramp/model/OnrampRedirectError.kt new file mode 100644 index 0000000000..c8733be36a --- /dev/null +++ b/domain/onramp/models/src/main/kotlin/com/tangem/domain/onramp/model/OnrampRedirectError.kt @@ -0,0 +1,8 @@ +package com.tangem.domain.onramp.model + +sealed class OnrampRedirectError : Throwable() { + + data class DataError(override val cause: Throwable?) : OnrampRedirectError() + + data object VerificationFailed : OnrampRedirectError() +} \ No newline at end of file diff --git a/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampRedirectUrlUseCase.kt b/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampRedirectUrlUseCase.kt index 3c7762b989..8d179444fd 100644 --- a/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampRedirectUrlUseCase.kt +++ b/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampRedirectUrlUseCase.kt @@ -2,6 +2,7 @@ package com.tangem.domain.onramp import arrow.core.Either import com.tangem.domain.onramp.model.OnrampProviderWithQuote +import com.tangem.domain.onramp.model.OnrampRedirectError import com.tangem.domain.onramp.repositories.OnrampRepository import com.tangem.domain.onramp.repositories.OnrampTransactionRepository import com.tangem.domain.tokens.model.CryptoCurrency @@ -16,7 +17,7 @@ class GetOnrampRedirectUrlUseCase( userWalletId: UserWalletId, quote: OnrampProviderWithQuote.Data, cryptoCurrency: CryptoCurrency, - ): Either { + ): Either { return Either.catch { val transaction = repository.getOnrampData( userWalletId = userWalletId, @@ -25,6 +26,8 @@ class GetOnrampRedirectUrlUseCase( ) transactionRepository.storeTransaction(transaction) transaction.redirectUrl + }.mapLeft { throwable -> + if (throwable is OnrampRedirectError) throwable else OnrampRedirectError.DataError(throwable) } } } \ No newline at end of file diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/OnrampMainComponent.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/OnrampMainComponent.kt index 8bce587855..0c888514f5 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/OnrampMainComponent.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/OnrampMainComponent.kt @@ -5,10 +5,12 @@ import com.tangem.core.ui.decompose.ComposableContentComponent import com.tangem.domain.onramp.model.OnrampProviderWithQuote import com.tangem.domain.onramp.model.OnrampSource import com.tangem.domain.tokens.model.CryptoCurrency +import com.tangem.domain.wallets.models.UserWalletId internal interface OnrampMainComponent : ComposableContentComponent { data class Params( + val userWalletId: UserWalletId, val cryptoCurrency: CryptoCurrency, val source: OnrampSource, val openSettings: () -> Unit, diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/model/OnrampMainComponentModel.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/model/OnrampMainComponentModel.kt index 7b74e90295..b99613f1ad 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/model/OnrampMainComponentModel.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/model/OnrampMainComponentModel.kt @@ -1,16 +1,26 @@ package com.tangem.features.onramp.main.model +import androidx.compose.ui.res.stringResource import com.arkivanov.decompose.router.slot.SlotNavigation import com.arkivanov.decompose.router.slot.activate +import com.tangem.common.ui.alerts.models.AlertDemoModeUM 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.ui.components.BasicDialog +import com.tangem.core.ui.components.DialogButtonUM +import com.tangem.core.ui.extensions.resolveReference +import com.tangem.core.ui.message.ContentMessage +import com.tangem.domain.demo.IsDemoCardUseCase import com.tangem.domain.onramp.* import com.tangem.domain.onramp.analytics.OnrampAnalyticsEvent import com.tangem.domain.onramp.model.OnrampAvailability import com.tangem.domain.onramp.model.OnrampCurrency import com.tangem.domain.onramp.model.OnrampProviderWithQuote +import com.tangem.domain.wallets.usecase.GetWalletsUseCase +import com.tangem.features.onramp.impl.R import com.tangem.features.onramp.main.OnrampMainComponent import com.tangem.features.onramp.main.entity.OnrampIntents import com.tangem.features.onramp.main.entity.OnrampMainBottomSheetConfig @@ -31,12 +41,15 @@ internal class OnrampMainComponentModel @Inject constructor( override val dispatchers: CoroutineDispatcherProvider, private val analyticsEventHandler: AnalyticsEventHandler, private val router: Router, + private val isDemoCardUseCase: IsDemoCardUseCase, private val checkOnrampAvailabilityUseCase: CheckOnrampAvailabilityUseCase, private val getOnrampCurrencyUseCase: GetOnrampCurrencyUseCase, private val clearOnrampCacheUseCase: ClearOnrampCacheUseCase, private val fetchQuotesUseCase: OnrampFetchQuotesUseCase, private val getOnrampQuotesUseCase: GetOnrampQuotesUseCase, private val amountInputManager: InputManager, + private val messageSender: UiMessageSender, + getWalletsUseCase: GetWalletsUseCase, paramsContainer: ParamsContainer, ) : Model(), OnrampIntents { @@ -50,7 +63,7 @@ internal class OnrampMainComponentModel @Inject constructor( currentStateProvider = Provider { _state.value }, onrampIntents = this, ) - + private val selectedUserWallet = getWalletsUseCase.invokeSync().first { it.walletId == params.userWalletId } private val _state: MutableStateFlow = MutableStateFlow( value = stateFactory.getInitialState( currency = params.cryptoCurrency.name, @@ -145,15 +158,19 @@ internal class OnrampMainComponentModel @Inject constructor( } override fun onBuyClick(quote: OnrampProviderWithQuote.Data) { - val currentContentState = state.value as? OnrampMainComponentUM.Content ?: return - analyticsEventHandler.send( - OnrampAnalyticsEvent.OnBuyClick( - providerName = quote.provider.info.name, - currency = currentContentState.amountBlockState.currencyUM.code, - cryptoCurrency = params.cryptoCurrency.name, - ), - ) - params.openRedirectPage(quote) + if (isDemoCardUseCase.invoke(selectedUserWallet.cardId)) { + showDemoWarning() + } else { + val currentContentState = state.value as? OnrampMainComponentUM.Content ?: return + analyticsEventHandler.send( + OnrampAnalyticsEvent.OnBuyClick( + providerName = quote.provider.info.name, + currency = currentContentState.amountBlockState.currencyUM.code, + cryptoCurrency = params.cryptoCurrency.name, + ), + ) + params.openRedirectPage(quote) + } } override fun openCurrenciesList() { @@ -175,4 +192,33 @@ internal class OnrampMainComponentModel @Inject constructor( modelScope.launch { clearOnrampCacheUseCase.invoke() } super.onDestroy() } + + private fun showDemoWarning() { + val alertUM = AlertDemoModeUM(onConfirmClick = {}) + + messageSender.send( + message = ContentMessage { onDismiss -> + val confirmButton = DialogButtonUM( + title = alertUM.confirmButtonText.resolveReference(), + onClick = { + alertUM.onConfirmClick() + onDismiss() + }, + ) + + val dismissButton = DialogButtonUM( + title = stringResource(id = R.string.common_cancel), + onClick = onDismiss, + ) + + BasicDialog( + message = alertUM.message.resolveReference(), + confirmButton = confirmButton, + onDismissDialog = onDismiss, + title = alertUM.title.resolveReference(), + dismissButton = dismissButton, + ) + }, + ) + } } \ No newline at end of file diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/redirect/model/OnrampRedirectModel.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/redirect/model/OnrampRedirectModel.kt index 8d7b3dc545..e75051640c 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/redirect/model/OnrampRedirectModel.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/redirect/model/OnrampRedirectModel.kt @@ -1,14 +1,19 @@ package com.tangem.features.onramp.redirect.model +import androidx.compose.ui.res.stringResource 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.BasicDialog +import com.tangem.core.ui.components.DialogButtonUM import com.tangem.core.ui.components.appbar.models.TopAppBarButtonUM import com.tangem.core.ui.extensions.combinedReference 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.message.ContentMessage import com.tangem.domain.onramp.GetOnrampRedirectUrlUseCase import com.tangem.features.onramp.impl.R import com.tangem.features.onramp.redirect.OnrampRedirectComponent @@ -23,6 +28,7 @@ internal class OnrampRedirectModel @Inject constructor( override val dispatchers: CoroutineDispatcherProvider, private val urlOpener: UrlOpener, private val getOnrampRedirectUrlUseCase: GetOnrampRedirectUrlUseCase, + private val messageSender: UiMessageSender, router: Router, paramsContainer: ParamsContainer, ) : Model() { @@ -62,8 +68,33 @@ internal class OnrampRedirectModel @Inject constructor( quote = params.onrampProviderWithQuote, cryptoCurrency = params.cryptoCurrency, ) - .onLeft { Timber.e(it) } - .onRight { urlOpener.openUrl(it) } + .onLeft(::handleError) + .onRight { + params.onBack() + urlOpener.openUrl(it) + } } } + + private fun handleError(throwable: Throwable) { + Timber.e(throwable) + + val contentMessage = ContentMessage { onDismiss -> + BasicDialog( + message = stringResource(id = R.string.common_unknown_error), + confirmButton = DialogButtonUM( + title = stringResource(id = R.string.common_ok), + onClick = { + params.onBack() + onDismiss() + }, + ), + onDismissDialog = { + params.onBack() + onDismiss() + }, + ) + } + messageSender.send(contentMessage) + } } \ No newline at end of file diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/root/DefaultOnrampComponent.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/root/DefaultOnrampComponent.kt index 826a86e2dc..6e86c98f9a 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/root/DefaultOnrampComponent.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/root/DefaultOnrampComponent.kt @@ -65,6 +65,7 @@ internal class DefaultOnrampComponent @AssistedInject constructor( OnrampChild.Main -> onrampMainComponentFactory.create( context = childByContext(componentContext), params = OnrampMainComponent.Params( + userWalletId = params.userWalletId, cryptoCurrency = params.cryptoCurrency, openSettings = { navigation.push(OnrampChild.Settings) }, source = params.source,