Updated on 2026-08-14
This commit is contained in:
parent
2f5d6525e2
commit
7d864a96e4
15 changed files with 585 additions and 29 deletions
|
|
@ -568,7 +568,7 @@
|
|||
<string name="onramp_no_available_providers">Keine verfügbaren Anbieter für diese Währung</string>
|
||||
<string name="onramp_pay_with">Bezahlen mit</string>
|
||||
<string name="onramp_redirecting_to_provider_subtitle">Du kannst Deine Transaktion beim Drittanbieter %s abschließen.</string>
|
||||
<string name="onramp_redirecting_to_provider_title">Umleitung auf %s …</string>
|
||||
<string name="onramp_redirecting_to_provider_title">Umleitung auf %s…</string>
|
||||
<string name="onramp_residency_bottomsheet_country_not_supported">Unsere Dienstleistungen sind in diesem Land nicht verfügbar</string>
|
||||
<string name="onramp_residency_bottomsheet_country_subtitle">Änder oder bestätige bitte</string>
|
||||
<string name="onramp_residency_bottomsheet_title">Dein Wohnsitz wurde identifiziert als</string>
|
||||
|
|
|
|||
|
|
@ -858,14 +858,14 @@
|
|||
<string name="toast_balances_shown">Saldos mostrados</string>
|
||||
<string name="toast_undo">Cancelar</string>
|
||||
<string name="token_button_unavailability_generic_description">Esta operación no está disponible actualmente. Por favor, inténtalo de nuevo más tarde.</string>
|
||||
<string name="token_button_unavailability_reason_buy_unavailable">Comprar %s no está disponible en este momento. Por favor revise sus actualizaciones.</string>
|
||||
<string name="token_button_unavailability_reason_buy_unavailable">Comprar %s no está disponible con los proveedores actuales pero estamos trabajando para agregar más opciones.</string>
|
||||
<string name="token_button_unavailability_reason_empty_balance_sell">No tiene fondos para vender. Recargue su cuenta para poder vender fondos desde ella.</string>
|
||||
<string name="token_button_unavailability_reason_empty_balance_send">No tienes fondos para enviar. Recarga tu cuenta para poder enviar fondos desde ella.</string>
|
||||
<string name="token_button_unavailability_reason_not_exchangeable">El servicio de intercambio %s no está disponible en este momento. Por favor consulte nuestras actualizaciones.</string>
|
||||
<string name="token_button_unavailability_reason_not_exchangeable">El servicio de intercambio %s no está compatible con los proveedores actuales pero estamos trabajando para agregar más opciones.</string>
|
||||
<string name="token_button_unavailability_reason_pending_transaction_sell">La venta de fondos estará disponible una vez que la(s) transacción(es) pendiente(s) en la red %s se complete</string>
|
||||
<string name="token_button_unavailability_reason_pending_transaction_send">El envío de fondos estará disponible una vez que se completen las transacciones pendientes en la red %s.</string>
|
||||
<string name="token_button_unavailability_reason_sell_unavailable">La venta de %s no está disponible en este momento. Por favor consulte nuestras actualizaciones.</string>
|
||||
<string name="token_button_unavailability_reason_staking_unavailable">El staking %s no está disponible en este momento. Por favor consulte nuestras actualizaciones.</string>
|
||||
<string name="token_button_unavailability_reason_sell_unavailable">Vender %s no es compatible con los proveedores actuales, pero estamos trabajando para agregar más opciones.</string>
|
||||
<string name="token_button_unavailability_reason_staking_unavailable">El staking de %s no es compatible con los proveedores actuales, pero estamos trabajando para agregar más opciones.</string>
|
||||
<string name="token_details_generate_xpub">Generar XPUB</string>
|
||||
<string name="token_details_hide_alert_hide">Ocultar</string>
|
||||
<string name="token_details_hide_alert_message">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.</string>
|
||||
|
|
|
|||
|
|
@ -850,14 +850,14 @@
|
|||
<string name="toast_balances_shown">Soldes affichés</string>
|
||||
<string name="toast_undo">Annuler</string>
|
||||
<string name="token_button_unavailability_generic_description">Cette opération est actuellement indisponible. Veuillez réessayer plus tard.</string>
|
||||
<string name="token_button_unavailability_reason_buy_unavailable">L\'achat de %s n\'est pas disponible pour le moment. Veuillez vérifier vos mises à jour.</string>
|
||||
<string name="token_button_unavailability_reason_buy_unavailable">L\'achat de %s n\'est pas pris en charge par les fournisseurs actuels mais nous travaillons à ajouter davantage d\'options.</string>
|
||||
<string name="token_button_unavailability_reason_empty_balance_sell">Vous n\'avez pas de fonds à vendre. Renflouez votre compte pour pouvoir vendre des fonds à partir de celui-ci.</string>
|
||||
<string name="token_button_unavailability_reason_empty_balance_send">Vous n\'avez pas de fonds à envoyer. Renflouez votre compte pour pouvoir envoyer des fonds à partir de celui-ci.</string>
|
||||
<string name="token_button_unavailability_reason_not_exchangeable">Le service d\'échange %s n\'est pas disponible pour le moment. Veuillez consulter nos mises à jour.</string>
|
||||
<string name="token_button_unavailability_reason_not_exchangeable">Le service d\'échange %s n\'est pas pris en charge par les fournisseurs actuels mais nous travaillons à ajouter plus d\'options.</string>
|
||||
<string name="token_button_unavailability_reason_pending_transaction_sell">La vente de fonds sera disponible une fois que la ou les transactions en attente dans le réseau %s seront terminées</string>
|
||||
<string name="token_button_unavailability_reason_pending_transaction_send">L\'envoi de fonds sera disponible une fois la ou les transactions en attente dans le réseau %s terminées.</string>
|
||||
<string name="token_button_unavailability_reason_sell_unavailable">La vente de %s n\'est pas disponible pour le moment. Veuillez consulter nos mises à jour.</string>
|
||||
<string name="token_button_unavailability_reason_staking_unavailable">Le staking %s n’est pas disponible pour le moment. Veuillez consulter nos mises à jour.</string>
|
||||
<string name="token_button_unavailability_reason_sell_unavailable">L\'achat de %s n\'est pas pris en charge par les fournisseurs actuels mais nous travaillons à ajouter plus d\'options.</string>
|
||||
<string name="token_button_unavailability_reason_staking_unavailable">Le staking de %s n\'est pas pris en charge par les fournisseurs actuels, mais nous travaillons à ajouter plus d\'options.</string>
|
||||
<string name="token_details_generate_xpub">Générer XPUB</string>
|
||||
<string name="token_details_hide_alert_hide">Masquer</string>
|
||||
<string name="token_details_hide_alert_message">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.</string>
|
||||
|
|
|
|||
|
|
@ -830,7 +830,7 @@
|
|||
<string name="swapping_alert_cex_description_with_slippage">金額には以下が含まれます: \n • サービス プロバイダーの手数料\n • 取引所からユーザーのアドレスに%1$sを送金するためのネットワーク手数料。 \n\nプロバイダーのスリッページは最大%2$sです</string>
|
||||
<string name="swapping_alert_dex_description">この金額には、サービスプロバイダーの手数料が含まれています。</string>
|
||||
<string name="swapping_alert_dex_description_with_slippage">金額にはサービスプロバイダーの手数料が含まれます。 \n\nプロバイダーのスリッページは最大%s です</string>
|
||||
<string name="swapping_alert_title">手数料</string>
|
||||
<string name="swapping_alert_title">情報</string>
|
||||
<string name="swapping_approve_information_text">すべての分散型取引所は、スマートコントラクトがあなたの許可なくウォレットにアクセスするのを防ぐために承認を必要とします。設計上、スマートコントラクトは承認なしでトークンにアクセスできません。トークンを「ロック解除」することで、あなたは1-inchのスマートコントラクトがトークンを使うことを承認します。ネットワークのマイナーは、このアクションをブロックチェーンに記録するためのガス料金(あなたが支払う)を受け取ります。承認後、トークンを交換することができます。</string>
|
||||
<string name="swapping_approve_information_title">承認</string>
|
||||
<string name="swapping_fee_estimation_error_text">手数料見積りエラーです。サポートにフィードバックをお送りください。</string>
|
||||
|
|
@ -846,14 +846,14 @@
|
|||
<string name="toast_balances_shown">残高表示</string>
|
||||
<string name="toast_undo">元に戻す</string>
|
||||
<string name="token_button_unavailability_generic_description">この操作は現在利用できません。しばらくしてからもう一度お試しください。</string>
|
||||
<string name="token_button_unavailability_reason_buy_unavailable">現在、 %sの買付はご利用いただけません。アップデート情報をご確認ください。</string>
|
||||
<string name="token_button_unavailability_reason_buy_unavailable">%sの買付は、現在のプロバイダーではサポートされていませんが、より多くのオプションを追加できるよう取り組んでいます。</string>
|
||||
<string name="token_button_unavailability_reason_empty_balance_sell">売却できる資金がありません。アカウントに入金して、売却できるようにしてください。</string>
|
||||
<string name="token_button_unavailability_reason_empty_balance_send">送金する資金がありません。アカウントに入金して、送金できるようにしてください。</string>
|
||||
<string name="token_button_unavailability_reason_not_exchangeable">現在、 %sの交換はご利用いただけません。アップデート情報を確認してください。</string>
|
||||
<string name="token_button_unavailability_reason_not_exchangeable">%sのスワップは、現在のプロバイダーではサポートされていませんが、より多くのオプションを追加できるよう取り組んでいます。</string>
|
||||
<string name="token_button_unavailability_reason_pending_transaction_sell">ネットワーク%s内の保留中の取引が完了すると、資金の売却が可能になります。</string>
|
||||
<string name="token_button_unavailability_reason_pending_transaction_send">ネットワーク%s内の保留中の取引が完了すると、送金が可能になります。</string>
|
||||
<string name="token_button_unavailability_reason_sell_unavailable">現在、 %sの売却はご利用いただけません。アップデート情報をご確認ください。</string>
|
||||
<string name="token_button_unavailability_reason_staking_unavailable">%s のステーキングは現在ご利用いただけません。最新情報をご確認ください。</string>
|
||||
<string name="token_button_unavailability_reason_sell_unavailable">%sの売却は、現在のプロバイダーではサポートされていませんが、より多くのオプションを追加できるよう取り組んでいます。</string>
|
||||
<string name="token_button_unavailability_reason_staking_unavailable">%sのステーキングは、現在のプロバイダーではサポートされていませんが、より多くのオプションを追加できるよう取り組んでいます。</string>
|
||||
<string name="token_details_generate_xpub">XPUBを生成する</string>
|
||||
<string name="token_details_hide_alert_hide">非表示</string>
|
||||
<string name="token_details_hide_alert_message">このトークンをメイン画面から非表示にします。トークンの管理ページからいつでも再度追加できます。</string>
|
||||
|
|
@ -946,7 +946,7 @@
|
|||
<string name="wallet_network_group_title">%sネットワーク</string>
|
||||
<string name="wallet_notification_address_copied">アドレスがクリップボードにコピーされました</string>
|
||||
<string name="wallet_notification_no_internet">インターネット接続がありません</string>
|
||||
<string name="wallet_promo_banner_button_title">今すぐ10 %オフで購入</string>
|
||||
<string name="wallet_promo_banner_button_title">今すぐ10 %%オフで購入</string>
|
||||
<string name="wallet_promo_banner_description">1.3万種類以上の暗号資産にアクセス。ワンタップで買付、売却、スワップ、ステーキングが可能です。\nバックアップ用に最大3枚のカードを連携できます。</string>
|
||||
<string name="wallet_promo_banner_title">Tangemウォレットを見る</string>
|
||||
<string name="wallet_settings_title">ウォレット設定</string>
|
||||
|
|
@ -1019,7 +1019,7 @@
|
|||
<string name="warning_solana_fee_message">Solanaネットワークが混雑しています。2分以内に取引が完了しない場合は、再度取引を繰り返してください。</string>
|
||||
<string name="warning_solana_fee_title">Solanaネットワークアラート</string>
|
||||
<string name="warning_solana_rent_fee_message">Solana ネットワークは 2 日ごとに%1$sのレンタル料を請求します。レンタル料を支払えないアカウントはネットワークから削除されます。アカウントに%2$s以上入金すると、無料で使用できます。</string>
|
||||
<string name="warning_some_networks_unreachable_message">現在、一部のネットワークにアクセスできません。しばらくしてからもう一度お試しください。</string>
|
||||
<string name="warning_some_networks_unreachable_message">下にスワイプして更新するか、後でもう一度お試しください。</string>
|
||||
<string name="warning_some_networks_unreachable_title">一部のネットワークにアクセスできません</string>
|
||||
<string name="warning_testnet_card_message">これはテストネットカードです。取引処理はできませんので、テストおよび開発目的でのみご利用ください。</string>
|
||||
<string name="warning_testnet_card_title">テスト目的のみ</string>
|
||||
|
|
|
|||
|
|
@ -581,7 +581,7 @@
|
|||
<string name="onramp_no_available_providers">Для данной валюты нет доступных провайдеров</string>
|
||||
<string name="onramp_pay_with">Оплата с</string>
|
||||
<string name="onramp_redirecting_to_provider_subtitle">Вы сможете завершить транзакцию через сервис стороннего провайдера, %s</string>
|
||||
<string name="onramp_redirecting_to_provider_title">Переход к %s ...</string>
|
||||
<string name="onramp_redirecting_to_provider_title">Переход к %s...</string>
|
||||
<string name="onramp_residency_bottomsheet_country_not_supported">Наши сервисы недоступны в данной стране</string>
|
||||
<string name="onramp_settings_title">Настройки</string>
|
||||
<string name="onramp_via">Через</string>
|
||||
|
|
@ -966,7 +966,7 @@
|
|||
<string name="wallet_notification_no_internet">Нет соединения с интернетом</string>
|
||||
<string name="wallet_promo_banner_button_title">Получить с 10%% скидкой</string>
|
||||
<string name="wallet_promo_banner_description">Получите доступ к более чем 13 000 криптовалют. Покупайте, продавайте, обменяйте и стейкайте в один клик. Свяжите до трех карт для резервного копирования. </string>
|
||||
<string name="wallet_promo_banner_title">Откройте Tangem Wallet </string>
|
||||
<string name="wallet_promo_banner_title">Откройте Tangem Wallet</string>
|
||||
<string name="wallet_settings_title">Настройки кошелька</string>
|
||||
<string name="wallet_title">Tangem</string>
|
||||
<string name="warning_access_denied_message">Используйте %s или отсканируйте карту/кольцо, чтобы разблокировать доступ к вашему кошельку</string>
|
||||
|
|
|
|||
|
|
@ -294,6 +294,9 @@
|
|||
<string name="express_provider_not_available">Unavailable for this pair</string>
|
||||
<string name="express_provider_permission_needed">Permission Required</string>
|
||||
<string name="express_provider_recommended">Recommended</string>
|
||||
<string name="express_status_bought">Bought %s</string>
|
||||
<string name="express_status_buying">Buying %s</string>
|
||||
<string name="express_status_buying_active">Buying %s...</string>
|
||||
<string name="express_token_list_empty_search">No tokens found. Please try another request</string>
|
||||
<string name="express_transaction_id">ID: %s</string>
|
||||
<string name="express_transaction_id_copied">Transaction ID copied</string>
|
||||
|
|
|
|||
|
|
@ -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<Params, OnrampSuccessComponent>
|
||||
}
|
||||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
package com.tangem.features.onramp.success.entity
|
||||
|
||||
interface OnrampSuccessClickIntents {
|
||||
fun goToProviderClick(providerLink: String)
|
||||
}
|
||||
|
|
@ -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()
|
||||
}
|
||||
|
|
@ -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<OnrampStatus, OnrampSuccessComponentUM> {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
@ -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,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -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<OnrampSuccessComponentUM> = MutableStateFlow(
|
||||
value = OnrampSuccessComponentUM.Loading,
|
||||
)
|
||||
|
||||
val state: StateFlow<OnrampSuccessComponentUM> 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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<OnrampSuccessComponentUM> {
|
||||
override val values: Sequence<OnrampSuccessComponentUM>
|
||||
get() = sequenceOf(
|
||||
OnrampSuccessComponentUMPreviewData.contentState,
|
||||
)
|
||||
}
|
||||
// endregion
|
||||
Loading…
Add table
Add a link
Reference in a new issue