diff --git a/core/res/src/main/res/values-de/strings.xml b/core/res/src/main/res/values-de/strings.xml
index 65a4990969..8fe310b7d9 100644
--- a/core/res/src/main/res/values-de/strings.xml
+++ b/core/res/src/main/res/values-de/strings.xml
@@ -568,7 +568,7 @@
Keine verfügbaren Anbieter für diese Währung
Bezahlen mit
Du kannst Deine Transaktion beim Drittanbieter %s abschließen.
- Umleitung auf %s …
+ Umleitung auf %s…
Unsere Dienstleistungen sind in diesem Land nicht verfügbar
Änder oder bestätige bitte
Dein Wohnsitz wurde identifiziert als
diff --git a/core/res/src/main/res/values-es/strings.xml b/core/res/src/main/res/values-es/strings.xml
index ee04d97a2f..b77f4a6456 100644
--- a/core/res/src/main/res/values-es/strings.xml
+++ b/core/res/src/main/res/values-es/strings.xml
@@ -858,14 +858,14 @@
Saldos mostrados
Cancelar
Esta operación no está disponible actualmente. Por favor, inténtalo de nuevo más tarde.
- Comprar %s no está disponible en este momento. Por favor revise sus actualizaciones.
+ Comprar %s no está disponible con los proveedores actuales pero estamos trabajando para agregar más opciones.
No tiene fondos para vender. Recargue su cuenta para poder vender fondos desde ella.
No tienes fondos para enviar. Recarga tu cuenta para poder enviar fondos desde ella.
- El servicio de intercambio %s no está disponible en este momento. Por favor consulte nuestras actualizaciones.
+ El servicio de intercambio %s no está compatible con los proveedores actuales pero estamos trabajando para agregar más opciones.
La venta de fondos estará disponible una vez que la(s) transacción(es) pendiente(s) en la red %s se complete
El envío de fondos estará disponible una vez que se completen las transacciones pendientes en la red %s.
- La venta de %s no está disponible en este momento. Por favor consulte nuestras actualizaciones.
- El staking %s no está disponible en este momento. Por favor consulte nuestras actualizaciones.
+ Vender %s no es compatible con los proveedores actuales, pero estamos trabajando para agregar más opciones.
+ El staking de %s no es compatible con los proveedores actuales, pero estamos trabajando para agregar más opciones.
Generar XPUB
Ocultar
Está a punto de ocultar este token de la pantalla principal. Puede volver a agregarlo en cualquier momento a través de la página de gestión de tokens.
diff --git a/core/res/src/main/res/values-fr/strings.xml b/core/res/src/main/res/values-fr/strings.xml
index c9983efdb7..346d3081e5 100644
--- a/core/res/src/main/res/values-fr/strings.xml
+++ b/core/res/src/main/res/values-fr/strings.xml
@@ -850,14 +850,14 @@
Soldes affichés
Annuler
Cette opération est actuellement indisponible. Veuillez réessayer plus tard.
- L\'achat de %s n\'est pas disponible pour le moment. Veuillez vérifier vos mises à jour.
+ L\'achat de %s n\'est pas pris en charge par les fournisseurs actuels mais nous travaillons à ajouter davantage d\'options.
Vous n\'avez pas de fonds à vendre. Renflouez votre compte pour pouvoir vendre des fonds à partir de celui-ci.
Vous n\'avez pas de fonds à envoyer. Renflouez votre compte pour pouvoir envoyer des fonds à partir de celui-ci.
- Le service d\'échange %s n\'est pas disponible pour le moment. Veuillez consulter nos mises à jour.
+ Le service d\'échange %s n\'est pas pris en charge par les fournisseurs actuels mais nous travaillons à ajouter plus d\'options.
La vente de fonds sera disponible une fois que la ou les transactions en attente dans le réseau %s seront terminées
L\'envoi de fonds sera disponible une fois la ou les transactions en attente dans le réseau %s terminées.
- La vente de %s n\'est pas disponible pour le moment. Veuillez consulter nos mises à jour.
- Le staking %s n’est pas disponible pour le moment. Veuillez consulter nos mises à jour.
+ L\'achat de %s n\'est pas pris en charge par les fournisseurs actuels mais nous travaillons à ajouter plus d\'options.
+ Le staking de %s n\'est pas pris en charge par les fournisseurs actuels, mais nous travaillons à ajouter plus d\'options.
Générer XPUB
Masquer
Vous êtes sur le point de masquer ce jeton de l\'écran principal. Vous pouvez le rajouter à tout moment via la page de gestion des jetons.
diff --git a/core/res/src/main/res/values-ja/strings.xml b/core/res/src/main/res/values-ja/strings.xml
index 3d8d8d15d5..f4e7cfccfe 100644
--- a/core/res/src/main/res/values-ja/strings.xml
+++ b/core/res/src/main/res/values-ja/strings.xml
@@ -830,7 +830,7 @@
金額には以下が含まれます: \n • サービス プロバイダーの手数料\n • 取引所からユーザーのアドレスに%1$sを送金するためのネットワーク手数料。 \n\nプロバイダーのスリッページは最大%2$sです
この金額には、サービスプロバイダーの手数料が含まれています。
金額にはサービスプロバイダーの手数料が含まれます。 \n\nプロバイダーのスリッページは最大%s です
- 手数料
+ 情報
すべての分散型取引所は、スマートコントラクトがあなたの許可なくウォレットにアクセスするのを防ぐために承認を必要とします。設計上、スマートコントラクトは承認なしでトークンにアクセスできません。トークンを「ロック解除」することで、あなたは1-inchのスマートコントラクトがトークンを使うことを承認します。ネットワークのマイナーは、このアクションをブロックチェーンに記録するためのガス料金(あなたが支払う)を受け取ります。承認後、トークンを交換することができます。
承認
手数料見積りエラーです。サポートにフィードバックをお送りください。
@@ -846,14 +846,14 @@
残高表示
元に戻す
この操作は現在利用できません。しばらくしてからもう一度お試しください。
- 現在、 %sの買付はご利用いただけません。アップデート情報をご確認ください。
+ %sの買付は、現在のプロバイダーではサポートされていませんが、より多くのオプションを追加できるよう取り組んでいます。
売却できる資金がありません。アカウントに入金して、売却できるようにしてください。
送金する資金がありません。アカウントに入金して、送金できるようにしてください。
- 現在、 %sの交換はご利用いただけません。アップデート情報を確認してください。
+ %sのスワップは、現在のプロバイダーではサポートされていませんが、より多くのオプションを追加できるよう取り組んでいます。
ネットワーク%s内の保留中の取引が完了すると、資金の売却が可能になります。
ネットワーク%s内の保留中の取引が完了すると、送金が可能になります。
- 現在、 %sの売却はご利用いただけません。アップデート情報をご確認ください。
- %s のステーキングは現在ご利用いただけません。最新情報をご確認ください。
+ %sの売却は、現在のプロバイダーではサポートされていませんが、より多くのオプションを追加できるよう取り組んでいます。
+ %sのステーキングは、現在のプロバイダーではサポートされていませんが、より多くのオプションを追加できるよう取り組んでいます。
XPUBを生成する
非表示
このトークンをメイン画面から非表示にします。トークンの管理ページからいつでも再度追加できます。
@@ -946,7 +946,7 @@
%sネットワーク
アドレスがクリップボードにコピーされました
インターネット接続がありません
- 今すぐ10 %オフで購入
+ 今すぐ10 %%オフで購入
1.3万種類以上の暗号資産にアクセス。ワンタップで買付、売却、スワップ、ステーキングが可能です。\nバックアップ用に最大3枚のカードを連携できます。
Tangemウォレットを見る
ウォレット設定
@@ -1019,7 +1019,7 @@
Solanaネットワークが混雑しています。2分以内に取引が完了しない場合は、再度取引を繰り返してください。
Solanaネットワークアラート
Solana ネットワークは 2 日ごとに%1$sのレンタル料を請求します。レンタル料を支払えないアカウントはネットワークから削除されます。アカウントに%2$s以上入金すると、無料で使用できます。
- 現在、一部のネットワークにアクセスできません。しばらくしてからもう一度お試しください。
+ 下にスワイプして更新するか、後でもう一度お試しください。
一部のネットワークにアクセスできません
これはテストネットカードです。取引処理はできませんので、テストおよび開発目的でのみご利用ください。
テスト目的のみ
diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml
index 9a43af9607..76ba8cfddf 100644
--- a/core/res/src/main/res/values-ru/strings.xml
+++ b/core/res/src/main/res/values-ru/strings.xml
@@ -581,7 +581,7 @@
Для данной валюты нет доступных провайдеров
Оплата с
Вы сможете завершить транзакцию через сервис стороннего провайдера, %s
- Переход к %s ...
+ Переход к %s...
Наши сервисы недоступны в данной стране
Настройки
Через
@@ -966,7 +966,7 @@
Нет соединения с интернетом
Получить с 10%% скидкой
Получите доступ к более чем 13 000 криптовалют. Покупайте, продавайте, обменяйте и стейкайте в один клик. Свяжите до трех карт для резервного копирования.
- Откройте Tangem Wallet
+ Откройте Tangem Wallet
Настройки кошелька
Tangem
Используйте %s или отсканируйте карту/кольцо, чтобы разблокировать доступ к вашему кошельку
diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml
index 6978552ae0..6241677828 100644
--- a/core/res/src/main/res/values/strings.xml
+++ b/core/res/src/main/res/values/strings.xml
@@ -294,6 +294,9 @@
Unavailable for this pair
Permission Required
Recommended
+ Bought %s
+ Buying %s
+ Buying %s...
No tokens found. Please try another request
ID: %s
Transaction ID copied
diff --git a/features/onramp/api/src/main/kotlin/com/tangem/features/onramp/component/OnrampSuccessComponent.kt b/features/onramp/api/src/main/kotlin/com/tangem/features/onramp/component/OnrampSuccessComponent.kt
index 70b6e543c4..ceed88f9c5 100644
--- a/features/onramp/api/src/main/kotlin/com/tangem/features/onramp/component/OnrampSuccessComponent.kt
+++ b/features/onramp/api/src/main/kotlin/com/tangem/features/onramp/component/OnrampSuccessComponent.kt
@@ -5,7 +5,7 @@ import com.tangem.core.ui.decompose.ComposableContentComponent
interface OnrampSuccessComponent : ComposableContentComponent {
- data class Params(val txId: String?)
+ data class Params(val txId: String)
interface Factory : ComponentFactory
}
\ No newline at end of file
diff --git a/features/onramp/impl/build.gradle.kts b/features/onramp/impl/build.gradle.kts
index 314c0f9529..c97691d146 100644
--- a/features/onramp/impl/build.gradle.kts
+++ b/features/onramp/impl/build.gradle.kts
@@ -22,6 +22,7 @@ dependencies {
implementation(projects.core.decompose)
implementation(projects.core.ui)
implementation(projects.core.featuretoggles)
+ implementation(projects.core.navigation)
/** Project - Common */
implementation(projects.common.routing)
@@ -42,7 +43,6 @@ dependencies {
/** DI */
implementation(deps.hilt.android)
- implementation(project(":common:ui"))
kapt(deps.hilt.kapt)
/** AndroidX */
diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/success/DefaultOnrampSuccessComponent.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/success/DefaultOnrampSuccessComponent.kt
index 0f5787d3b3..d1b329d10b 100644
--- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/success/DefaultOnrampSuccessComponent.kt
+++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/success/DefaultOnrampSuccessComponent.kt
@@ -1,5 +1,6 @@
package com.tangem.features.onramp.success
+import androidx.activity.compose.BackHandler
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
@@ -8,6 +9,7 @@ import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.decompose.model.getOrCreateModel
import com.tangem.features.onramp.component.OnrampSuccessComponent
import com.tangem.features.onramp.success.model.OnrampSuccessComponentModel
+import com.tangem.features.onramp.success.ui.OnrampSuccessComponentContent
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
@@ -23,7 +25,11 @@ internal class DefaultOnrampSuccessComponent @AssistedInject constructor(
override fun Content(modifier: Modifier) {
val state by model.state.collectAsState()
- // todo onramp [REDACTED_JIRA]
+ BackHandler(onBack = router::pop)
+ OnrampSuccessComponentContent(
+ state = state,
+ onBackClick = router::pop,
+ )
}
@AssistedFactory
diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/success/entity/OnrampSuccessClickIntents.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/success/entity/OnrampSuccessClickIntents.kt
new file mode 100644
index 0000000000..7c7565aef5
--- /dev/null
+++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/success/entity/OnrampSuccessClickIntents.kt
@@ -0,0 +1,5 @@
+package com.tangem.features.onramp.success.entity
+
+interface OnrampSuccessClickIntents {
+ fun goToProviderClick(providerLink: String)
+}
\ No newline at end of file
diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/success/entity/OnrampSuccessComponentUM.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/success/entity/OnrampSuccessComponentUM.kt
index 3f0bea7160..71f80e2f05 100644
--- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/success/entity/OnrampSuccessComponentUM.kt
+++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/success/entity/OnrampSuccessComponentUM.kt
@@ -1,16 +1,22 @@
package com.tangem.features.onramp.success.entity
+import com.tangem.common.ui.expressStatus.state.ExpressStatusUM
+import com.tangem.common.ui.notifications.NotificationUM
+import com.tangem.core.ui.extensions.TextReference
+
sealed class OnrampSuccessComponentUM {
data object Loading : OnrampSuccessComponentUM()
data class Content(
val txId: String,
- val createdAt: Long,
- val providerId: String,
+ val timestamp: Long,
val currencyImageUrl: String,
- val fromAmount: String,
- val toAmount: String,
- val onBackClick: () -> Unit,
+ val fromAmount: TextReference,
+ val toAmount: TextReference,
+ val statusBlock: ExpressStatusUM,
+ val providerName: TextReference,
+ val providerImageUrl: String,
+ val notification: NotificationUM?,
) : OnrampSuccessComponentUM()
}
\ No newline at end of file
diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/success/entity/conterter/SetOnrampSuccessContentConverter.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/success/entity/conterter/SetOnrampSuccessContentConverter.kt
new file mode 100644
index 0000000000..435ced42ba
--- /dev/null
+++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/success/entity/conterter/SetOnrampSuccessContentConverter.kt
@@ -0,0 +1,194 @@
+package com.tangem.features.onramp.success.entity.conterter
+
+import com.tangem.common.ui.expressStatus.state.ExpressLinkUM
+import com.tangem.common.ui.expressStatus.state.ExpressStatusItemState
+import com.tangem.common.ui.expressStatus.state.ExpressStatusItemUM
+import com.tangem.common.ui.expressStatus.state.ExpressStatusUM
+import com.tangem.common.ui.notifications.ExpressNotificationsUM
+import com.tangem.common.ui.notifications.NotificationUM
+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.OnrampStatus
+import com.tangem.domain.onramp.model.cache.OnrampTransaction
+import com.tangem.domain.tokens.model.CryptoCurrency
+import com.tangem.features.onramp.impl.R
+import com.tangem.features.onramp.success.entity.OnrampSuccessComponentUM
+import com.tangem.utils.converter.Converter
+import kotlinx.collections.immutable.persistentListOf
+import org.joda.time.DateTime
+
+internal class SetOnrampSuccessContentConverter(
+ private val cryptoCurrency: CryptoCurrency,
+ private val transaction: OnrampTransaction,
+ private val goToProviderClick: (String) -> Unit,
+) : Converter {
+ override fun convert(value: OnrampStatus): OnrampSuccessComponentUM {
+ return OnrampSuccessComponentUM.Content(
+ txId = value.txId,
+ timestamp = DateTime.parse(value.createdAt).millis,
+ currencyImageUrl = transaction.fromCurrency.image,
+ fromAmount = stringReference(
+ transaction.fromAmount.format {
+ fiat(
+ fiatCurrencyCode = transaction.fromCurrency.name,
+ fiatCurrencySymbol = transaction.fromCurrency.code,
+ )
+ },
+ ),
+ toAmount = stringReference(
+ transaction.toAmount.format {
+ crypto(cryptoCurrency)
+ },
+ ),
+ providerName = stringReference(transaction.providerName),
+ providerImageUrl = transaction.providerImageUrl,
+ statusBlock = convertStatuses(value.status, value.externalTxUrl),
+ notification = getNotification(value.status, value.externalTxUrl),
+ )
+ }
+
+ private fun getNotification(status: OnrampStatus.Status, externalTxUrl: String?): NotificationUM? {
+ if (externalTxUrl == null) return null
+ return when (status) {
+ OnrampStatus.Status.Verifying -> {
+ ExpressNotificationsUM.NeedVerification {
+ goToProviderClick(externalTxUrl)
+ }
+ }
+ OnrampStatus.Status.Failed -> {
+ ExpressNotificationsUM.FailedByProvider {
+ goToProviderClick(externalTxUrl)
+ }
+ }
+ else -> null
+ }
+ }
+
+ private fun convertStatuses(status: OnrampStatus.Status, externalTxUrl: String?): ExpressStatusUM {
+ val statuses = with(status) {
+ persistentListOf(
+ getAwaitingDepositItem(),
+ getPaymentProcessingItem(),
+ getBuyingItem(),
+ getSendingItem(),
+ )
+ }
+
+ return ExpressStatusUM(
+ title = resourceReference(R.string.common_transaction_status),
+ link = getStatusLink(status, externalTxUrl),
+ statuses = statuses,
+ )
+ }
+
+ private fun OnrampStatus.Status.getAwaitingDepositItem() = ExpressStatusItemUM(
+ text = when {
+ order < OnrampStatus.Status.WaitingForPayment.order -> {
+ resourceReference(R.string.express_exchange_status_receiving)
+ }
+ this == OnrampStatus.Status.WaitingForPayment -> {
+ resourceReference(R.string.express_exchange_status_receiving_active)
+ }
+ else -> {
+ resourceReference(R.string.express_exchange_status_received)
+ }
+ },
+ state = getStatusState(OnrampStatus.Status.WaitingForPayment),
+ )
+
+ private fun OnrampStatus.Status.getPaymentProcessingItem() = ExpressStatusItemUM(
+ text = when {
+ order < OnrampStatus.Status.PaymentProcessing.order -> {
+ resourceReference(R.string.express_exchange_status_confirming)
+ }
+ this == OnrampStatus.Status.PaymentProcessing -> {
+ resourceReference(R.string.express_exchange_status_confirming_active)
+ }
+ this == OnrampStatus.Status.Verifying -> {
+ resourceReference(R.string.express_exchange_status_verifying)
+ }
+ this == OnrampStatus.Status.Failed -> {
+ resourceReference(R.string.express_exchange_status_failed)
+ }
+ else -> resourceReference(R.string.express_exchange_status_confirmed)
+ },
+ state = when {
+ order < OnrampStatus.Status.PaymentProcessing.order -> {
+ ExpressStatusItemState.Default
+ }
+ this == OnrampStatus.Status.PaymentProcessing -> {
+ ExpressStatusItemState.Active
+ }
+ this == OnrampStatus.Status.Verifying -> {
+ ExpressStatusItemState.Warning
+ }
+ this == OnrampStatus.Status.Failed -> {
+ ExpressStatusItemState.Error
+ }
+ else -> {
+ ExpressStatusItemState.Done
+ }
+ },
+ )
+
+ private fun OnrampStatus.Status.getBuyingItem() = ExpressStatusItemUM(
+ text = when {
+ order < OnrampStatus.Status.Paid.order -> {
+ resourceReference(R.string.express_status_buying, wrappedList(cryptoCurrency.name))
+ }
+ this == OnrampStatus.Status.Paid -> {
+ resourceReference(R.string.express_status_buying_active, wrappedList(cryptoCurrency.name))
+ }
+ else -> {
+ resourceReference(R.string.express_status_bought, wrappedList(cryptoCurrency.name))
+ }
+ },
+ state = getStatusState(OnrampStatus.Status.Paid),
+ )
+
+ private fun OnrampStatus.Status.getSendingItem() = ExpressStatusItemUM(
+ text = when {
+ order < OnrampStatus.Status.Sending.order -> {
+ resourceReference(R.string.express_exchange_status_sending, wrappedList(cryptoCurrency.name))
+ }
+ this == OnrampStatus.Status.Sending -> {
+ resourceReference(
+ R.string.express_exchange_status_sending_active,
+ wrappedList(cryptoCurrency.name),
+ )
+ }
+ else -> {
+ resourceReference(R.string.express_exchange_status_sent, wrappedList(cryptoCurrency.name))
+ }
+ },
+ state = getStatusState(OnrampStatus.Status.Sending),
+ )
+
+ private fun getStatusLink(status: OnrampStatus.Status, externalTxUrl: String?): ExpressLinkUM {
+ if (externalTxUrl == null) return ExpressLinkUM.Empty
+ return when (status) {
+ OnrampStatus.Status.Verifying,
+ OnrampStatus.Status.Failed,
+ -> {
+ ExpressLinkUM.Content(
+ icon = R.drawable.ic_arrow_top_right_24,
+ text = resourceReference(R.string.common_go_to_provider),
+ onClick = {
+ goToProviderClick(externalTxUrl)
+ },
+ )
+ }
+ else -> ExpressLinkUM.Empty
+ }
+ }
+
+ private fun OnrampStatus.Status.getStatusState(targetState: OnrampStatus.Status) = when {
+ order < targetState.order -> ExpressStatusItemState.Default
+ this == targetState -> ExpressStatusItemState.Active
+ else -> ExpressStatusItemState.Done
+ }
+}
\ No newline at end of file
diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/success/entity/previewdata/OnrampSuccessComponentUMPreviewData.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/success/entity/previewdata/OnrampSuccessComponentUMPreviewData.kt
new file mode 100644
index 0000000000..d7e355ba63
--- /dev/null
+++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/success/entity/previewdata/OnrampSuccessComponentUMPreviewData.kt
@@ -0,0 +1,50 @@
+package com.tangem.features.onramp.success.entity.previewdata
+
+import com.tangem.common.ui.expressStatus.state.ExpressLinkUM
+import com.tangem.common.ui.expressStatus.state.ExpressStatusItemState
+import com.tangem.common.ui.expressStatus.state.ExpressStatusItemUM
+import com.tangem.common.ui.expressStatus.state.ExpressStatusUM
+import com.tangem.core.ui.extensions.resourceReference
+import com.tangem.core.ui.extensions.stringReference
+import com.tangem.features.onramp.impl.R
+import com.tangem.features.onramp.success.entity.OnrampSuccessComponentUM
+import kotlinx.collections.immutable.persistentListOf
+import org.joda.time.DateTime
+
+internal data object OnrampSuccessComponentUMPreviewData {
+
+ val loadingState = OnrampSuccessComponentUM.Loading
+
+ val contentState = OnrampSuccessComponentUM.Content(
+ txId = "b2894851-7b63-4f56-bd75-e408f1dcba31",
+ timestamp = DateTime.parse("2023-09-20T13:45:10.868Z").millis,
+ providerName = stringReference("1Inch"),
+ providerImageUrl = "https://s3.eu-central-1.amazonaws.com/tangem.api/express/1INCH1024.png",
+ fromAmount = stringReference("100 USDT"),
+ toAmount = stringReference("99.99 $"),
+ currencyImageUrl = "",
+ notification = null,
+ statusBlock = ExpressStatusUM(
+ title = resourceReference(R.string.express_exchange_status_title),
+ link = ExpressLinkUM.Empty,
+ statuses = persistentListOf(
+ ExpressStatusItemUM(
+ text = stringReference("Deposit received"),
+ state = ExpressStatusItemState.Done,
+ ),
+ ExpressStatusItemUM(
+ text = stringReference("Confirmed"),
+ state = ExpressStatusItemState.Done,
+ ),
+ ExpressStatusItemUM(
+ text = stringReference("Buying Bitcoin..."),
+ state = ExpressStatusItemState.Active,
+ ),
+ ExpressStatusItemUM(
+ text = stringReference("Sending to you"),
+ state = ExpressStatusItemState.Default,
+ ),
+ ),
+ ),
+ )
+}
\ No newline at end of file
diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/success/model/OnrampSuccessComponentModel.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/success/model/OnrampSuccessComponentModel.kt
index bdda90effd..6e925f143c 100644
--- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/success/model/OnrampSuccessComponentModel.kt
+++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/success/model/OnrampSuccessComponentModel.kt
@@ -1,25 +1,97 @@
package com.tangem.features.onramp.success.model
+import arrow.core.getOrElse
import com.tangem.core.decompose.model.Model
import com.tangem.core.decompose.model.ParamsContainer
+import com.tangem.core.navigation.url.UrlOpener
+import com.tangem.domain.onramp.GetOnrampStatusUseCase
+import com.tangem.domain.onramp.GetOnrampTransactionUseCase
+import com.tangem.domain.onramp.OnrampRemoveTransactionUseCase
+import com.tangem.domain.onramp.model.OnrampStatus
+import com.tangem.domain.onramp.model.cache.OnrampTransaction
+import com.tangem.domain.tokens.GetCryptoCurrencyUseCase
import com.tangem.features.onramp.component.OnrampSuccessComponent
+import com.tangem.features.onramp.success.entity.OnrampSuccessClickIntents
import com.tangem.features.onramp.success.entity.OnrampSuccessComponentUM
+import com.tangem.features.onramp.success.entity.conterter.SetOnrampSuccessContentConverter
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.update
+import kotlinx.coroutines.launch
+import timber.log.Timber
import javax.inject.Inject
+@Suppress("LongParameterList")
internal class OnrampSuccessComponentModel @Inject constructor(
override val dispatchers: CoroutineDispatcherProvider,
+ private val urlOpener: UrlOpener,
+ private val getOnrampTransactionUseCase: GetOnrampTransactionUseCase,
+ private val getOnrampStatusUseCase: GetOnrampStatusUseCase,
+ private val getCryptoCurrencyUseCase: GetCryptoCurrencyUseCase,
+ private val onrampRemoveTransactionUseCase: OnrampRemoveTransactionUseCase,
paramsContainer: ParamsContainer,
-) : Model() {
+) : Model(), OnrampSuccessClickIntents {
- // todo onramp remove in [REDACTED_JIRA]
- @Suppress("UnusedPrivateMember")
private val params: OnrampSuccessComponent.Params = paramsContainer.require()
private val _state: MutableStateFlow = MutableStateFlow(
value = OnrampSuccessComponentUM.Loading,
)
+
val state: StateFlow get() = _state.asStateFlow()
+
+ init {
+ loadData()
+ }
+
+ override fun goToProviderClick(providerLink: String) {
+ urlOpener.openUrl(providerLink)
+ }
+
+ private fun loadData() {
+ modelScope.launch {
+ getOnrampTransactionUseCase(txId = params.txId)
+ .fold(
+ ifLeft = {
+ Timber.e(it.toString())
+ },
+ ifRight = { transaction ->
+ loadTransactionStatus(transaction)
+ },
+ )
+ }
+ }
+
+ private suspend fun loadTransactionStatus(transaction: OnrampTransaction) {
+ val cryptoCurrencies = getCryptoCurrencyUseCase(
+ transaction.userWalletId,
+ transaction.toCurrencyId,
+ ).getOrElse { error("Crypto currency not found") }
+
+ getOnrampStatusUseCase(txId = params.txId)
+ .fold(
+ ifLeft = {
+ Timber.e(it.toString())
+ },
+ ifRight = { status ->
+ _state.update {
+ SetOnrampSuccessContentConverter(
+ cryptoCurrency = cryptoCurrencies,
+ transaction = transaction,
+ goToProviderClick = ::goToProviderClick,
+ ).convert(status)
+ }
+ removeTransactionIfTerminalStatus(status)
+ },
+ )
+ }
+
+ private fun removeTransactionIfTerminalStatus(status: OnrampStatus) {
+ modelScope.launch {
+ if (status.status.isTerminal()) {
+ onrampRemoveTransactionUseCase(status.txId)
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/success/ui/OnrampSuccessComponentContent.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/success/ui/OnrampSuccessComponentContent.kt
new file mode 100644
index 0000000000..e021c732e7
--- /dev/null
+++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/success/ui/OnrampSuccessComponentContent.kt
@@ -0,0 +1,220 @@
+package com.tangem.features.onramp.success.ui
+
+import android.content.res.Configuration
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.*
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.verticalScroll
+import androidx.compose.material3.Scaffold
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.tooling.preview.PreviewParameter
+import androidx.compose.ui.tooling.preview.PreviewParameterProvider
+import androidx.compose.ui.unit.dp
+import coil.compose.SubcomposeAsyncImage
+import coil.request.ImageRequest
+import com.tangem.common.ui.expressStatus.ExpressStatusBlock
+import com.tangem.common.ui.expressStatus.ExpressStatusNotificationBlock
+import com.tangem.core.ui.components.*
+import com.tangem.core.ui.components.appbar.TangemTopAppBar
+import com.tangem.core.ui.components.appbar.models.TopAppBarButtonUM
+import com.tangem.core.ui.components.containers.FooterContainer
+import com.tangem.core.ui.components.transactions.TransactionDoneTitle
+import com.tangem.core.ui.extensions.TextReference
+import com.tangem.core.ui.extensions.resolveReference
+import com.tangem.core.ui.extensions.resourceReference
+import com.tangem.core.ui.extensions.wrappedList
+import com.tangem.core.ui.res.TangemTheme
+import com.tangem.core.ui.res.TangemThemePreview
+import com.tangem.core.ui.utils.DateTimeFormatters
+import com.tangem.core.ui.utils.WindowInsetsZero
+import com.tangem.core.ui.utils.toTimeFormat
+import com.tangem.features.onramp.impl.R
+import com.tangem.features.onramp.success.entity.OnrampSuccessComponentUM
+import com.tangem.features.onramp.success.entity.previewdata.OnrampSuccessComponentUMPreviewData
+
+@Composable
+internal fun OnrampSuccessComponentContent(
+ state: OnrampSuccessComponentUM,
+ onBackClick: () -> Unit,
+ modifier: Modifier = Modifier,
+) {
+ if (state !is OnrampSuccessComponentUM.Content) {
+ Box(modifier.background(TangemTheme.colors.background.secondary))
+ } else {
+ Content(
+ state = state,
+ onBackClick = onBackClick,
+ modifier = modifier,
+ )
+ }
+}
+
+@Composable
+private fun Content(state: OnrampSuccessComponentUM.Content, onBackClick: () -> Unit, modifier: Modifier = Modifier) {
+ Scaffold(
+ modifier = modifier
+ .background(TangemTheme.colors.background.secondary)
+ .systemBarsPadding(),
+ topBar = {
+ TangemTopAppBar(
+ startButton = TopAppBarButtonUM(
+ iconRes = R.drawable.ic_close_24,
+ onIconClicked = onBackClick,
+ ),
+ )
+ },
+ bottomBar = {
+ PrimaryButton(
+ text = stringResource(R.string.common_close),
+ onClick = onBackClick,
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(16.dp),
+ )
+ },
+ contentWindowInsets = WindowInsetsZero,
+ ) { scaffoldPaddings ->
+ Column(
+ modifier = Modifier
+ .background(TangemTheme.colors.background.secondary)
+ .padding(scaffoldPaddings)
+ .fillMaxSize()
+ .verticalScroll(rememberScrollState())
+ .padding(16.dp),
+ ) {
+ TransactionDoneTitle(
+ title = resourceReference(R.string.common_in_progress),
+ subtitle = resourceReference(
+ R.string.send_date_format,
+ wrappedList(
+ state.timestamp.toTimeFormat(DateTimeFormatters.dateFormatter),
+ state.timestamp.toTimeFormat(),
+ ),
+ ),
+ )
+ SpacerH24()
+ AmountBlock(state)
+ SpacerH12()
+ FooterContainer(
+ footer = resourceReference(R.string.onramp_transaction_status_footer_text),
+ ) {
+ ExpressStatusBlock(state.statusBlock)
+ }
+ ExpressStatusNotificationBlock(
+ state.notification,
+ )
+ }
+ }
+}
+
+@Composable
+private fun AmountBlock(state: OnrampSuccessComponentUM.Content) {
+ Column(
+ horizontalAlignment = Alignment.CenterHorizontally,
+ modifier = Modifier
+ .clip(TangemTheme.shapes.roundedCornersXMedium)
+ .background(TangemTheme.colors.background.action)
+ .padding(16.dp),
+ ) {
+ val iconModifier = Modifier.size(size = 40.dp)
+ SubcomposeAsyncImage(
+ modifier = iconModifier,
+ model = ImageRequest.Builder(context = LocalContext.current)
+ .data(state.currencyImageUrl)
+ .crossfade(enable = true)
+ .allowHardware(false)
+ .build(),
+ loading = { CircleShimmer(modifier = iconModifier) },
+ error = { },
+ contentDescription = null,
+ )
+ ResizableText(
+ text = state.fromAmount.resolveReference(),
+ style = TangemTheme.typography.h2,
+ color = TangemTheme.colors.text.primary1,
+ textAlign = TextAlign.Center,
+ maxLines = 1,
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(top = 16.dp),
+ )
+ Text(
+ text = state.toAmount.resolveReference(),
+ style = TangemTheme.typography.caption2,
+ color = TangemTheme.colors.text.tertiary,
+ textAlign = TextAlign.Center,
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(top = 8.dp),
+ )
+ SpacerH12()
+ AmountProviderBlock(
+ state.providerName,
+ state.providerImageUrl,
+ )
+ }
+}
+
+@Composable
+private fun AmountProviderBlock(providerName: TextReference, providerImageUrl: String, modifier: Modifier = Modifier) {
+ Row(
+ modifier = modifier,
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.spacedBy(6.dp),
+ ) {
+ Text(
+ text = stringResource(R.string.common_with),
+ style = TangemTheme.typography.body2,
+ color = TangemTheme.colors.text.tertiary,
+ )
+ SubcomposeAsyncImage(
+ modifier = Modifier.size(size = 16.dp),
+ model = ImageRequest.Builder(context = LocalContext.current)
+ .data(providerImageUrl)
+ .crossfade(enable = true)
+ .allowHardware(false)
+ .build(),
+ loading = { CircleShimmer() },
+ error = { },
+ contentDescription = null,
+ )
+ Text(
+ text = providerName.resolveReference(),
+ style = TangemTheme.typography.body2,
+ color = TangemTheme.colors.text.primary1,
+ )
+ }
+}
+
+// region Preview
+@Preview(showBackground = true, widthDp = 360, heightDp = 720)
+@Preview(showBackground = true, widthDp = 360, heightDp = 720, uiMode = Configuration.UI_MODE_NIGHT_YES)
+@Composable
+private fun OnrampSuccessComponentContent_Preview(
+ @PreviewParameter(OnrampSuccessComponentContentPreviewProvider::class)
+ data: OnrampSuccessComponentUM,
+) {
+ TangemThemePreview {
+ OnrampSuccessComponentContent(
+ state = data,
+ onBackClick = {},
+ )
+ }
+}
+
+private class OnrampSuccessComponentContentPreviewProvider :
+ PreviewParameterProvider {
+ override val values: Sequence
+ get() = sequenceOf(
+ OnrampSuccessComponentUMPreviewData.contentState,
+ )
+}
+// endregion
\ No newline at end of file