Updated on 2026-08-14

This commit is contained in:
Tangem 2025-04-25 19:51:03 +05:00
parent ed25735b31
commit 5a5cfc0fac
16 changed files with 232 additions and 47 deletions

View file

@ -113,6 +113,12 @@ sealed class AnalyticsParam {
data object WalletConnect : TxSentFrom("WalletConnect")
data object Sell : TxSentFrom("Sell")
data class NFT(
override val blockchain: String,
override val token: String,
override val feeType: FeeType,
) : TxSentFrom("NFT"), TxData
}
sealed interface TxData {

View file

@ -379,7 +379,7 @@
<string name="key_invalidated_warning_description">Du hast deine biometrischen Daten aktualisiert, scanne deine Karte oder Ring, um einzutreten</string>
<string name="koinos_insufficient_balance_to_send_koin_description">Dein Guthaben sollte höher sein als der Gebührenwert, um eine Überweisung zu tätigen</string>
<string name="koinos_insufficient_balance_to_send_koin_title">Unzureichende Mittel</string>
<string name="koinos_insufficient_mana_to_send_koin_description">Du hast nicht genug Mana für diese Transaktion. Bitte warte, bis das Mana wieder aufgefüllt ist. Dein Mana-Guthaben beträgt %1$s/%2$s</string>
<string name="koinos_insufficient_mana_to_send_koin_description">Du hast nicht genug Mana für diese Transaktion. Bitte warte, bis das Mana wieder aufgefüllt ist. Dein Managuthaben beträgt %1$s/%2$s</string>
<string name="koinos_insufficient_mana_to_send_koin_title">Nicht genug Mana</string>
<string name="koinos_mana_exceeds_koin_balance_description">Du kannst nur %s übertragen, da das Koinos-Netzwerk ein Mana-Limit vorgibt.</string>
<string name="koinos_mana_exceeds_koin_balance_title">Mana-Limit</string>

View file

@ -375,7 +375,7 @@
<string name="key_invalidated_warning_description">Ha actualizado la biometría, escanee su tarjeta o anillo para entrar</string>
<string name="koinos_insufficient_balance_to_send_koin_description">Su saldo debe ser mayor que el valor de la tarifa para hacer una transferencia</string>
<string name="koinos_insufficient_balance_to_send_koin_title">Saldo insuficiente</string>
<string name="koinos_insufficient_mana_to_send_koin_description">No tiene suficiente Mana para esta transacción. Por favor, espere hasta que el Mana se recargue. Su saldo de Mana es %1$s/%2$s</string>
<string name="koinos_insufficient_mana_to_send_koin_description">No tiene suficiente Mana para esta transacción. Espere hasta que se reponga el maná. Su saldo de maná es %1$s/%2$s</string>
<string name="koinos_insufficient_mana_to_send_koin_title">Mana insuficiente</string>
<string name="koinos_mana_exceeds_koin_balance_description">Solo puede transferir %s debido al límite de Mana impuesto por la red Koinos</string>
<string name="koinos_mana_exceeds_koin_balance_title">Límite de Mana</string>

View file

@ -375,7 +375,7 @@
<string name="key_invalidated_warning_description">Vous avez mis à jour vos données biométriques, scannez votre carte ou bague pour entrer</string>
<string name="koinos_insufficient_balance_to_send_koin_description">Votre solde doit être supérieur à la valeur des frais pour effectuer un transfert</string>
<string name="koinos_insufficient_balance_to_send_koin_title">Solde insuffisant</string>
<string name="koinos_insufficient_mana_to_send_koin_description">Vous n\'avez pas assez de Mana pour cette transaction. Veuillez attendre que le Mana soit reconstitué. Votre solde de Mana est de %1$s/%2$s</string>
<string name="koinos_insufficient_mana_to_send_koin_description">Vous n\'avez pas assez de mana pour cette transaction. Veuillez patienter jusqu\'à ce que le mana soit réapprovisionné. Votre solde de mana est %1$s/%2$s</string>
<string name="koinos_insufficient_mana_to_send_koin_title">Mana insuffisant</string>
<string name="koinos_mana_exceeds_koin_balance_description">Vous ne pouvez transférer que %s en raison de la limite de Mana imposée par le réseau Koinos</string>
<string name="koinos_mana_exceeds_koin_balance_title">Limite de Mana</string>

View file

@ -19,7 +19,6 @@
<string name="common_send">Invia</string>
<string name="common_send_tx_error">Impossibile inviare la transazione</string>
<string name="common_success">Con successo</string>
<string name="common_utxo_validate_withdrawal_message_warning">Due to %1$s limitations only %2$d UTXOs can fit in a single transaction. This means you can only send %3$s or less. You need to reduce the amount.</string>
<string name="details_manage_security_access_code">Codice di accesso</string>
<string name="details_manage_security_access_code_description">Prima di scansionare la carta sarà necessario inserire il codice di accesso corretto</string>
<string name="details_manage_security_long_tap">Mantenimento della carta</string>
@ -36,7 +35,6 @@
<string name="disclaimer_title">Termini del servizio</string>
<string name="eth_gas_required_exceeds_allowance">Not enough funds for the transaction. Please top up your account.</string>
<string name="generic_error">An error occurred</string>
<string name="generic_error_code">An error occurred. Code: %s.</string>
<string name="generic_requires_memo_error">Notifica richiesta</string>
<string name="home_button_scan">Scansiona carta</string>
<string name="initial_message_change_access_code_body">Avvicina per modificare il codice di accesso</string>
@ -44,9 +42,6 @@
<string name="initial_message_scan_header">Avvicina per scansionare</string>
<string name="initial_message_sign_header">Avvicina per firmare</string>
<string name="initial_message_tap_header">Avvicina la carta</string>
<string name="koinos_insufficient_mana_to_send_koin_description">You don\'t have enough Mana for this transaction. Please wait until the Mana is refilled. Your Mana balance is %1$s/%2$s</string>
<string name="no_account_generic">To use the %1$s network, you must pay the account reserve (%2$s %3$s), which locks up and hides that amount indefinitely</string>
<string name="no_account_polkadot">Destination account is not active. Send %s or more to activate the account.</string>
<string name="no_account_send_to_create">Per creare un account, invia fondi a questo indirizzo</string>
<string name="no_trustline_xlm_asset">The destination account does not have a trustline for the asset being sent.</string>
<string name="onboarding_create_wallet_button_create_wallet">Crea portafoglio</string>
@ -55,7 +50,6 @@
<string name="send_error_dust_amount_format">L\'importo minimo è di %s</string>
<string name="send_error_dust_change_format">Il resto minimo è di %s</string>
<string name="send_error_invalid_fee_value">Commissione non valida</string>
<string name="send_error_minimum_balance_format">Minimum balance is %s</string>
<string name="send_error_no_target_account">Il conto totale non è stato creato L\'importo da inviare deve essere %s + commissione o maggiore</string>
<string name="send_error_unknown">Errore sconosciuto</string>
<string name="send_extras_hint_memo">Memo</string>

View file

@ -377,7 +377,7 @@
<string name="key_invalidated_warning_description">生体認証を更新しました。カードまたはリングをスキャンして入ってください。</string>
<string name="koinos_insufficient_balance_to_send_koin_description">送金するには、残高が手数料額より高くなければなりません。</string>
<string name="koinos_insufficient_balance_to_send_koin_title">残高不足</string>
<string name="koinos_insufficient_mana_to_send_koin_description">この取引に必要なManaが不足しています。Manaが補充されるまでお待ちください。あなたのMana残高は%1$s/%2$sです。</string>
<string name="koinos_insufficient_mana_to_send_koin_description">この取引に必要なManaが足りません。Manaが補充されるまでお待ちください。Manaの残高は%1$s / %2$sです。</string>
<string name="koinos_insufficient_mana_to_send_koin_title">Manaが不足しています</string>
<string name="koinos_mana_exceeds_koin_balance_description">KoinosネットワークによるMana制限のため、%s のみ送金できます。</string>
<string name="koinos_mana_exceeds_koin_balance_title">Mana上限</string>
@ -548,6 +548,8 @@
<string name="no_account_polkadot">送信先アカウントが有効ではありません。%s 以上を送信してアカウントを有効にしてください。</string>
<string name="no_account_send_to_create">アカウントを作成するには、このアドレスに資金を送金してください</string>
<string name="no_trustline_xlm_asset">送信先アカウントには、送金されるアセットのトラストラインがありません。</string>
<string name="notification_referral_promo_text">コードを共有すると、販売ごとに5 USDTを獲得できます。お友達は10%割引になります。</string>
<string name="notification_referral_promo_title">友達への紹介で報酬を獲得しよう!</string>
<string name="onboarding_access_code_feature_1_description">すべてのデバイスを保護するには、単一のアクセスコードを設定してください。</string>
<string name="onboarding_access_code_feature_1_title">保護する</string>
<string name="onboarding_access_code_feature_2_description">後で各カードおよびリングに個別のアクセスコードを設定できます。</string>
@ -892,9 +894,9 @@
<string name="staking_notification_restake_text">再ステーキングを使うと、ステーキングを解除することなく、あるバリデータから別のバリデータに資金を移動できます。</string>
<string name="staking_notification_stake_entire_balance_text">残高のすべてをステーキングしようとしています。ステーキング解除や報酬請求にかかるネットワーク手数料をカバーするために、少額を残しておくことをお勧めします。</string>
<string name="staking_notification_ton_activate_account">TONでステーキングを開始するには、まず任意の金額の送金を行ってください。これにより、ウォレットがアクティブになります。</string>
<string name="staking_notification_ton_extra_reserve_info">TONをステーキングまたは出金する場合、入金と出金の両方でステーキング額から0.2 TONの手数料が差し引かれます。</string>
<string name="staking_notification_ton_extra_reserve_info">ネットワーク手数料に加え、取引の全ステップを完了するには最大0.2 TONが必要です。未使用分は取引完了後に返金されます。</string>
<string name="staking_notification_ton_extra_reserve_is_required">この操作を続行するには、ネットワーク手数料に加えて0.2 TONが必要です。残高を補充してください。</string>
<string name="staking_notification_ton_extra_reserve_title">ステーキング手数料</string>
<string name="staking_notification_ton_extra_reserve_title">0.2 TON保留済み</string>
<string name="staking_notification_ton_have_to_unstake_all_text">このアクションは、ネットワークのルールに従って、他のポジションをクローズするか、引き出しステータスに切り替えます。</string>
<string name="staking_notification_ton_have_to_unstake_all_title">ポジション状況</string>
<string name="staking_notification_unlock_text">資金をステーキングから引き出すには、ロックを解除してください。ロック解除には%sかかります。</string>

View file

@ -525,6 +525,9 @@
<string name="no_account_polkadot">Аккаунт получателя не активирован. Отправьте %s или более для активации аккаунта.</string>
<string name="no_account_send_to_create">Для создания аккаунта отправьте средства на этот адрес</string>
<string name="no_trustline_xlm_asset">Аккаунт получателя не содержит трастлайна для отправляемого актива.</string>
<string name="notification_referral_promo_button">Присоединиться</string>
<string name="notification_referral_promo_text">Поделись промокодом — заработай 5 USDT с каждой покупки. Твои друзья получат скидку 10% на карту Tangem!</string>
<string name="notification_referral_promo_title">Получай бонусы за каждого друга!</string>
<string name="onboarding_access_code_feature_1_description">Установите единый код доступа для защиты всех ваших карт или колец</string>
<string name="onboarding_access_code_feature_1_title">Защита</string>
<string name="onboarding_access_code_feature_2_description">Установите индивидуальный код доступа для каждой карты или кольца позже.</string>

View file

@ -381,7 +381,7 @@
<string name="key_invalidated_warning_description">Ви оновили дані біометрії, відскануйте свою картку або кільце для входу</string>
<string name="koinos_insufficient_balance_to_send_koin_description">Ваш баланс повинен перевищувати суму комісії для здійснення переказу</string>
<string name="koinos_insufficient_balance_to_send_koin_title">Недостатньо балансу</string>
<string name="koinos_insufficient_mana_to_send_koin_description">У вас недостатньо Mana для цієї транзакції. Будь ласка, зачекайте, поки Mana буде поповнена. Ваш баланс Mana становить %1$s/%2$s</string>
<string name="koinos_insufficient_mana_to_send_koin_description">У вас недостатньо Мани для цієї транзакції. Будь ласка, зачекайте, поки Мана поповниться. Ваш баланс мани дорівнює %1$s/%2$s</string>
<string name="koinos_insufficient_mana_to_send_koin_title">Недостатньо Mana</string>
<string name="koinos_mana_exceeds_koin_balance_description">Ви можете переказати тільки %s через обмеження Mana, встановлене мережею Koinos</string>
<string name="koinos_mana_exceeds_koin_balance_title">Ліміт Mana</string>

View file

@ -140,7 +140,6 @@
<string name="feedback_subject_support_tangem">Tangem反饋</string>
<string name="feedback_subject_tx_failed">無法發送交易</string>
<string name="generic_error">An error occurred</string>
<string name="generic_error_code">An error occurred. Code: %s.</string>
<string name="generic_requires_memo_error">需要memo</string>
<string name="give_permission_rows_amount">數量 %s</string>
<string name="give_permission_swap_subtitle" formatted="false">要繼續,您需要允許 %1s 智能合約使用您的 %2s</string>
@ -153,12 +152,10 @@
<string name="initial_message_sign_header">點擊簽名</string>
<string name="initial_message_tap_header">點按卡片</string>
<string name="key_invalidated_warning_description">您已更新生物識別登入,掃描您的卡進入</string>
<string name="koinos_insufficient_mana_to_send_koin_description">You don\'t have enough Mana for this transaction. Please wait until the Mana is refilled. Your Mana balance is %1$s/%2$s</string>
<string name="main_manage_tokens">管理代幣</string>
<string name="main_scan_card_warning_view_subtitle">要訪問所有的網路您需要掃描卡片</string>
<string name="main_scan_card_warning_view_title">掃描卡片</string>
<string name="main_tokens">代幣</string>
<string name="no_account_generic">To use the %1$s network, you must pay the account reserve (%2$s %3$s), which locks up and hides that amount indefinitely</string>
<string name="no_account_polkadot">目標帳戶未激活。發送 %s 或更多以激活帳戶</string>
<string name="no_account_send_to_create">要創建帳戶,請將資金發送到此地址</string>
<string name="no_trustline_xlm_asset">目標帳戶沒有用於發送資產的 trustline</string>

View file

@ -546,6 +546,7 @@
<string name="nft_receive_unavailable_asset_warning_message">You haven\'t added this network yet. To start receiving NFTs, add it to the main screen!</string>
<string name="nft_receive_unavailable_asset_warning_title">Network not added</string>
<string name="nft_receive_unavailable_section_title">Not Added</string>
<string name="nft_send">Send NFT</string>
<string name="nft_traits_title">Traits</string>
<string name="nft_wallet_count">%1$d NFTs in %2$d collection</string>
<string name="nft_wallet_receive_nft">Tap here to receive first NFT</string>
@ -555,6 +556,9 @@
<string name="no_account_polkadot">Destination account is not active. Send %s or more to activate the account.</string>
<string name="no_account_send_to_create">To create account send funds to this address</string>
<string name="no_trustline_xlm_asset">The destination account does not have a trustline for the asset being sent.</string>
<string name="notification_referral_promo_button">Join Now</string>
<string name="notification_referral_promo_text">Share your code - earn 5 USDT per sale. Your friend gets 10% OFF.</string>
<string name="notification_referral_promo_title">Get REWARDS for every friend!</string>
<string name="onboarding_access_code_feature_1_description">Set up a single access code to protect all your devices.</string>
<string name="onboarding_access_code_feature_1_title">Protect</string>
<string name="onboarding_access_code_feature_2_description">Set an individual access code for each card or ring later.</string>

View file

@ -11,16 +11,20 @@ import com.arkivanov.decompose.router.stack.childStack
import com.arkivanov.decompose.router.stack.pop
import com.arkivanov.decompose.value.ObserveLifecycleMode
import com.arkivanov.decompose.value.subscribe
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.decompose.context.AppComponentContext
import com.tangem.core.decompose.context.childByContext
import com.tangem.core.decompose.model.getOrCreateModel
import com.tangem.core.decompose.navigation.inner.InnerRouter
import com.tangem.core.ui.decompose.ComposableContentComponent
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.features.nft.component.NFTDetailsBlockComponent
import com.tangem.features.send.v2.api.NFTSendComponent
import com.tangem.features.send.v2.common.CommonSendRoute
import com.tangem.features.send.v2.common.analytics.CommonSendAnalyticEvents
import com.tangem.features.send.v2.common.ui.SendContent
import com.tangem.features.send.v2.common.ui.state.ConfirmUM
import com.tangem.features.send.v2.impl.R
import com.tangem.features.send.v2.sendnft.confirm.NFTSendConfirmComponent
import com.tangem.features.send.v2.sendnft.model.NFTSendModel
import com.tangem.features.send.v2.subcomponents.destination.SendDestinationComponent
@ -40,9 +44,11 @@ internal class DefaultNFTSendComponent @AssistedInject constructor(
@Assisted appComponentContext: AppComponentContext,
@Assisted private val params: NFTSendComponent.Params,
private val nftDetailsBlockComponentFactory: NFTDetailsBlockComponent.Factory,
private val analyticsEventHandler: AnalyticsEventHandler,
) : NFTSendComponent, AppComponentContext by appComponentContext {
private val stackNavigation = StackNavigation<CommonSendRoute>()
private val analyticsCategoryName = CommonSendAnalyticEvents.NFT_SEND_CATEGORY
private val innerRouter = InnerRouter<CommonSendRoute>(
stackNavigation = stackNavigation,
@ -79,15 +85,21 @@ internal class DefaultNFTSendComponent @AssistedInject constructor(
componentScope.launch {
when (val activeComponent = stack.active.instance) {
is NFTSendConfirmComponent -> if (currentRouteFlow.value.isEditMode) {
// analyticsEventHandler.send(SendAnalyticEvents.ConfirmationScreenOpened)
analyticsEventHandler.send(
CommonSendAnalyticEvents.ConfirmationScreenOpened(categoryName = analyticsCategoryName),
)
activeComponent.updateState(model.uiState.value)
}
is SendDestinationComponent -> {
// analyticsEventHandler.send(SendAnalyticEvents.AddressScreenOpened)
analyticsEventHandler.send(
CommonSendAnalyticEvents.AddressScreenOpened(categoryName = analyticsCategoryName),
)
activeComponent.updateState(model.uiState.value.destinationUM)
}
is SendFeeComponent -> {
// analyticsEventHandler.send(SendAnalyticEvents.FeeScreenOpened)
analyticsEventHandler.send(
CommonSendAnalyticEvents.FeeScreenOpened(categoryName = analyticsCategoryName),
)
}
}
currentRouteFlow.emit(stack.active.configuration)
@ -121,7 +133,8 @@ internal class DefaultNFTSendComponent @AssistedInject constructor(
state = model.uiState.value.destinationUM,
currentRoute = currentRouteFlow.filterIsInstance<CommonSendRoute.Destination>(),
isBalanceHidingFlow = model.isBalanceHiddenFlow,
analyticsCategoryName = "", // todo
title = resourceReference(R.string.nft_send),
analyticsCategoryName = analyticsCategoryName,
userWalletId = params.userWalletId,
cryptoCurrency = model.cryptoCurrency,
callback = model,
@ -145,7 +158,7 @@ internal class DefaultNFTSendComponent @AssistedInject constructor(
params = SendFeeComponentParams.FeeParams(
state = model.uiState.value.feeUM,
currentRoute = currentRouteFlow.filterIsInstance<CommonSendRoute.Fee>(),
analyticsCategoryName = "", // todo
analyticsCategoryName = analyticsCategoryName,
userWallet = model.userWallet,
cryptoCurrencyStatus = model.cryptoCurrencyStatus,
feeCryptoCurrencyStatus = model.feeCryptoCurrencyStatus,
@ -167,7 +180,7 @@ internal class DefaultNFTSendComponent @AssistedInject constructor(
nftDetailsBlockComponentFactory = nftDetailsBlockComponentFactory,
params = NFTSendConfirmComponent.Params(
state = model.uiState.value,
analyticsCategoryName = "", // todo
analyticsCategoryName = analyticsCategoryName,
userWallet = model.userWallet,
nftAsset = params.nftAsset,
nftCollectionName = params.nftCollectionName,

View file

@ -0,0 +1,28 @@
package com.tangem.features.send.v2.sendnft.analytics
import com.tangem.core.analytics.models.AnalyticsEvent
import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.core.analytics.models.AnalyticsParam.Key.FEE_TYPE
import com.tangem.core.analytics.models.AnalyticsParam.Key.TOKEN_PARAM
import com.tangem.features.send.v2.common.analytics.CommonSendAnalyticEvents
/**
* Send screen analytics
*/
internal sealed class NFTSendAnalyticEvents(
event: String,
params: Map<String, String> = mapOf(),
) : AnalyticsEvent(category = CommonSendAnalyticEvents.NFT_SEND_CATEGORY, event = event, params = params) {
/** Transaction send screen opened */
data class TransactionScreenOpened(
val token: String,
val feeType: AnalyticsParam.FeeType,
) : NFTSendAnalyticEvents(
event = "NFT Sent Screen Opened",
params = mapOf(
TOKEN_PARAM to token,
FEE_TYPE to feeType.value,
),
)
}

View file

@ -0,0 +1,53 @@
package com.tangem.features.send.v2.sendnft.analytics
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.core.analytics.models.Basic
import com.tangem.core.decompose.di.ModelScoped
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.features.send.v2.sendnft.ui.state.NFTSendUM
import com.tangem.features.send.v2.subcomponents.destination.ui.state.DestinationTextFieldUM
import com.tangem.features.send.v2.subcomponents.destination.ui.state.DestinationUM
import com.tangem.features.send.v2.subcomponents.fee.ui.state.FeeSelectorUM
import com.tangem.features.send.v2.subcomponents.fee.ui.state.FeeUM
import javax.inject.Inject
@ModelScoped
internal class NFTSendAnalyticHelper @Inject constructor(
private val analyticsEventHandler: AnalyticsEventHandler,
) {
fun nftSendSuccessAnalytics(cryptoCurrency: CryptoCurrency, nftSendUM: NFTSendUM) {
val destinationUM = nftSendUM.destinationUM as? DestinationUM.Content
val feeUM = nftSendUM.feeUM as? FeeUM.Content
val feeSelectorUM = feeUM?.feeSelectorUM as? FeeSelectorUM.Content ?: return
val feeType = feeSelectorUM.selectedType.toAnalyticType(feeSelectorUM)
analyticsEventHandler.send(
NFTSendAnalyticEvents.TransactionScreenOpened(
token = cryptoCurrency.symbol,
feeType = feeType,
),
)
analyticsEventHandler.send(
Basic.TransactionSent(
sentFrom = AnalyticsParam.TxSentFrom.NFT(
blockchain = cryptoCurrency.network.name,
token = cryptoCurrency.symbol,
feeType = feeType,
),
memoType = getSendTransactionMemoType(destinationUM?.memoTextField),
),
)
}
private fun getSendTransactionMemoType(
recipientMemo: DestinationTextFieldUM.RecipientMemo?,
): Basic.TransactionSent.MemoType {
val memo = recipientMemo?.value
return when {
memo?.isBlank() == true -> Basic.TransactionSent.MemoType.Empty
memo?.isNotBlank() == true -> Basic.TransactionSent.MemoType.Full
else -> Basic.TransactionSent.MemoType.Null
}
}
}

View file

@ -14,6 +14,11 @@ import com.tangem.core.navigation.url.UrlOpener
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.wrappedList
import com.tangem.datasource.local.nft.converter.NFTSdkAssetConverter
import com.tangem.domain.feedback.GetCardInfoUseCase
import com.tangem.domain.feedback.SaveBlockchainErrorUseCase
import com.tangem.domain.feedback.SendFeedbackEmailUseCase
import com.tangem.domain.feedback.models.BlockchainErrorInfo
import com.tangem.domain.feedback.models.FeedbackEmailType
import com.tangem.domain.settings.IsSendTapHelpEnabledUseCase
import com.tangem.domain.settings.NeverShowTapHelpUseCase
import com.tangem.domain.transaction.usecase.CreateNFTTransferTransactionUseCase
@ -21,12 +26,14 @@ import com.tangem.domain.transaction.usecase.SendTransactionUseCase
import com.tangem.domain.txhistory.usecase.GetExplorerTransactionUrlUseCase
import com.tangem.features.send.v2.common.CommonSendRoute
import com.tangem.features.send.v2.common.SendBalanceUpdater
import com.tangem.features.send.v2.common.SendConfirmAlertFactory
import com.tangem.features.send.v2.common.analytics.CommonSendAnalyticEvents
import com.tangem.features.send.v2.common.analytics.CommonSendAnalyticEvents.SendScreenSource
import com.tangem.features.send.v2.common.ui.state.ConfirmUM
import com.tangem.features.send.v2.common.ui.state.NavigationUM
import com.tangem.features.send.v2.impl.R
import com.tangem.features.send.v2.send.analytics.SendAnalyticEvents
import com.tangem.features.send.v2.send.analytics.SendAnalyticEvents.SendScreenSource
import com.tangem.features.send.v2.send.ui.state.ButtonsUM
import com.tangem.features.send.v2.sendnft.analytics.NFTSendAnalyticHelper
import com.tangem.features.send.v2.sendnft.confirm.NFTSendConfirmComponent
import com.tangem.features.send.v2.sendnft.confirm.model.transformers.NFTSendConfirmInitialStateTransformer
import com.tangem.features.send.v2.sendnft.confirm.model.transformers.NFTSendConfirmSendingStateTransformer
@ -40,6 +47,7 @@ import com.tangem.features.send.v2.subcomponents.fee.ui.state.FeeUM
import com.tangem.features.send.v2.subcomponents.notifications.NotificationsUpdateTrigger
import com.tangem.features.send.v2.subcomponents.notifications.model.NotificationData
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import com.tangem.utils.extensions.stripZeroPlainString
import com.tangem.utils.transformer.update
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
@ -47,7 +55,7 @@ import timber.log.Timber
import java.math.BigDecimal
import javax.inject.Inject
@Suppress("LongParameterList")
@Suppress("LongParameterList", "LargeClass")
@ModelScoped
internal class NFTSendConfirmModel @Inject constructor(
paramsContainer: ParamsContainer,
@ -59,17 +67,23 @@ internal class NFTSendConfirmModel @Inject constructor(
private val createNFTTransferTransactionUseCase: CreateNFTTransferTransactionUseCase,
private val sendTransactionUseCase: SendTransactionUseCase,
private val getExplorerTransactionUrlUseCase: GetExplorerTransactionUrlUseCase,
private val saveBlockchainErrorUseCase: SaveBlockchainErrorUseCase,
private val getCardInfoUseCase: GetCardInfoUseCase,
private val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase,
private val notificationsUpdateTrigger: NotificationsUpdateTrigger,
private val sendFeeCheckReloadTrigger: SendFeeCheckReloadTrigger,
private val sendFeeCheckReloadListener: SendFeeCheckReloadListener,
private val alertFactory: SendConfirmAlertFactory,
private val urlOpener: UrlOpener,
private val shareManager: ShareManager,
private val analyticsEventHandler: AnalyticsEventHandler,
private val nftSendAnalyticHelper: NFTSendAnalyticHelper,
sendBalanceUpdaterFactory: SendBalanceUpdater.Factory,
) : Model(), NFTSendConfirmClickIntents {
private val params: NFTSendConfirmComponent.Params = paramsContainer.require()
private val analyticsCategoryName = params.analyticsCategoryName
private val userWallet = params.userWallet
private val cryptoCurrencyStatus = params.cryptoCurrencyStatus
private val cryptoCurrency = cryptoCurrencyStatus.currency
@ -129,7 +143,12 @@ internal class NFTSendConfirmModel @Inject constructor(
val confirmUM = it.confirmUM as? ConfirmUM.Content
it.copy(confirmUM = confirmUM?.copy(showTapHelp = false) ?: it.confirmUM)
}
// analyticsEventHandler.send(SendAnalyticEvents.ScreenReopened(SendScreenSource.Address))
analyticsEventHandler.send(
CommonSendAnalyticEvents.ScreenReopened(
categoryName = analyticsCategoryName,
source = SendScreenSource.Address,
),
)
router.push(CommonSendRoute.Destination(isEditMode = true))
}
}
@ -141,7 +160,12 @@ internal class NFTSendConfirmModel @Inject constructor(
val confirmUM = it.confirmUM as? ConfirmUM.Content
it.copy(confirmUM = confirmUM?.copy(showTapHelp = false) ?: it.confirmUM)
}
// analyticsEventHandler.send(SendAnalyticEvents.ScreenReopened(SendScreenSource.Fee))
analyticsEventHandler.send(
CommonSendAnalyticEvents.ScreenReopened(
categoryName = analyticsCategoryName,
source = SendScreenSource.Fee,
),
)
router.push(CommonSendRoute.Fee)
}
}
@ -159,18 +183,38 @@ internal class NFTSendConfirmModel @Inject constructor(
override fun onExploreClick() {
val confirmUM = uiState.value.confirmUM as? ConfirmUM.Success ?: return
// analyticsEventHandler.send(SendAnalyticEvents.ExploreButtonClicked)
analyticsEventHandler.send(
CommonSendAnalyticEvents.ExploreButtonClicked(analyticsCategoryName),
)
urlOpener.openUrl(confirmUM.txUrl)
}
override fun onShareClick() {
val confirmUM = uiState.value.confirmUM as? ConfirmUM.Success ?: return
// analyticsEventHandler.send(SendAnalyticEvents.ShareButtonClicked)
analyticsEventHandler.send(
CommonSendAnalyticEvents.ShareButtonClicked(analyticsCategoryName),
)
shareManager.shareText(confirmUM.txUrl)
}
override fun onFailedTxEmailClick(errorMessage: String) {
// TODO()
saveBlockchainErrorUseCase(
error = BlockchainErrorInfo(
errorMessage = errorMessage,
blockchainId = cryptoCurrency.network.id.value,
derivationPath = cryptoCurrency.network.derivationPath.value,
destinationAddress = confirmData.enteredDestination.orEmpty(),
tokenSymbol = null,
amount = params.nftAsset.amount.toString(),
fee = confirmData.fee?.amount?.value?.stripZeroPlainString(),
),
)
val cardInfo = getCardInfoUseCase(userWallet.scanResponse).getOrNull() ?: return
modelScope.launch {
sendFeedbackEmailUseCase(type = FeedbackEmailType.TransactionSendingProblem(cardInfo = cardInfo))
}
}
private fun initialState() {
@ -229,9 +273,9 @@ internal class NFTSendConfirmModel @Inject constructor(
ifLeft = { error ->
Timber.e(error)
_uiState.update(NFTSendConfirmSendingStateTransformer(isSending = false))
// alertFactory.getGenericErrorState {
// onFailedTxEmailClick(error.localizedMessage.orEmpty())
// }
alertFactory.getGenericErrorState {
onFailedTxEmailClick(error.localizedMessage.orEmpty())
}
},
ifRight = { txData ->
sendTransaction(txData)
@ -252,17 +296,22 @@ internal class NFTSendConfirmModel @Inject constructor(
result.fold(
ifLeft = { error ->
Timber.e(error.toString())
// alertFactory.getSendTransactionErrorState(
// error = error,
// popBack = appRouter::pop,
// onFailedTxEmailClick = ::onFailedTxEmailClick,
// )
// analyticsEventHandler.send(SendAnalyticEvents.TransactionError(cryptoCurrency.symbol))
alertFactory.getSendTransactionErrorState(
error = error,
popBack = appRouter::pop,
onFailedTxEmailClick = ::onFailedTxEmailClick,
)
analyticsEventHandler.send(
CommonSendAnalyticEvents.TransactionError(
categoryName = analyticsCategoryName,
token = cryptoCurrency.symbol,
),
)
},
ifRight = {
updateTransactionStatus(txData)
sendBalanceUpdater.scheduleUpdates()
// sendAnalyticHelper.sendSuccessAnalytics(cryptoCurrency, uiState.value)
nftSendAnalyticHelper.nftSendSuccessAnalytics(cryptoCurrency, uiState.value)
},
)
}
@ -307,6 +356,7 @@ internal class NFTSendConfirmModel @Inject constructor(
feeUM = uiState.value.feeUM,
analyticsEventHandler = analyticsEventHandler,
cryptoCurrency = cryptoCurrencyStatus.currency,
analyticsCategoryName = analyticsCategoryName,
).transform(uiState.value.confirmUM),
)
}
@ -331,7 +381,8 @@ internal class NFTSendConfirmModel @Inject constructor(
backIconRes = R.drawable.ic_close_24,
backIconClick = {
analyticsEventHandler.send(
SendAnalyticEvents.CloseButtonClicked(
CommonSendAnalyticEvents.CloseButtonClicked(
categoryName = analyticsCategoryName,
source = SendScreenSource.Confirm,
isFromSummary = true,
isValid = confirmUM.isPrimaryButtonEnabled,

View file

@ -5,8 +5,8 @@ import com.tangem.common.ui.notifications.NotificationUM
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.ui.utils.parseToBigDecimal
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.features.send.v2.common.analytics.CommonSendAnalyticEvents
import com.tangem.features.send.v2.common.ui.state.ConfirmUM
import com.tangem.features.send.v2.send.analytics.SendAnalyticEvents
import com.tangem.features.send.v2.subcomponents.fee.model.checkIfFeeTooHigh
import com.tangem.features.send.v2.subcomponents.fee.ui.state.FeeSelectorUM
import com.tangem.features.send.v2.subcomponents.fee.ui.state.FeeType
@ -18,6 +18,7 @@ internal class NFTSendConfirmationNotificationsTransformer(
private val feeUM: FeeUM,
private val analyticsEventHandler: AnalyticsEventHandler,
private val cryptoCurrency: CryptoCurrency,
private val analyticsCategoryName: String,
) : Transformer<ConfirmUM> {
override fun transform(prevState: ConfirmUM): ConfirmUM {
val state = prevState as? ConfirmUM.Content ?: return prevState
@ -39,7 +40,10 @@ internal class NFTSendConfirmationNotificationsTransformer(
if (feeSelectorUM.selectedType == FeeType.Custom && minimumValue > customValue) {
add(NotificationUM.Warning.FeeTooLow)
analyticsEventHandler.send(
SendAnalyticEvents.NoticeTransactionDelays(cryptoCurrency.symbol),
CommonSendAnalyticEvents.NoticeTransactionDelays(
categoryName = analyticsCategoryName,
token = cryptoCurrency.symbol,
),
)
}
}

View file

@ -13,6 +13,11 @@ import com.tangem.datasource.local.nft.converter.NFTSdkAssetConverter
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.feedback.GetCardInfoUseCase
import com.tangem.domain.feedback.SaveBlockchainErrorUseCase
import com.tangem.domain.feedback.SendFeedbackEmailUseCase
import com.tangem.domain.feedback.models.BlockchainErrorInfo
import com.tangem.domain.feedback.models.FeedbackEmailType
import com.tangem.domain.tokens.GetCryptoCurrenciesUseCase
import com.tangem.domain.tokens.GetCurrencyStatusUpdatesUseCase
import com.tangem.domain.tokens.GetFeePaidCryptoCurrencyStatusSyncUseCase
@ -25,6 +30,7 @@ import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
import com.tangem.features.send.v2.api.NFTSendComponent
import com.tangem.features.send.v2.common.CommonSendRoute
import com.tangem.features.send.v2.common.SendConfirmAlertFactory
import com.tangem.features.send.v2.common.ui.state.ConfirmUM
import com.tangem.features.send.v2.common.ui.state.NavigationUM
import com.tangem.features.send.v2.sendnft.confirm.NFTSendConfirmComponent
@ -58,6 +64,10 @@ internal class NFTSendModel @Inject constructor(
private val getFeePaidCryptoCurrencyStatusSyncUseCase: GetFeePaidCryptoCurrencyStatusSyncUseCase,
private val createNFTTransferTransactionUseCase: CreateNFTTransferTransactionUseCase,
private val getFeeUseCase: GetFeeUseCase,
private val saveBlockchainErrorUseCase: SaveBlockchainErrorUseCase,
private val getCardInfoUseCase: GetCardInfoUseCase,
private val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase,
private val alertFactory: SendConfirmAlertFactory,
) : Model(), SendNFTComponentCallback {
val params: NFTSendComponent.Params = paramsContainer.require()
@ -145,13 +155,33 @@ internal class NFTSendModel @Inject constructor(
)
},
ifLeft = {
// sendConfirmAlertFactory.getGenericErrorState(::onFailedTxEmailClick)
alertFactory.getGenericErrorState(::onFailedTxEmailClick)
return@launch
},
)
}
}
private fun onFailedTxEmailClick(errorMessage: String? = null) {
saveBlockchainErrorUseCase(
error = BlockchainErrorInfo(
errorMessage = errorMessage.orEmpty(),
blockchainId = cryptoCurrency.network.id.value,
derivationPath = cryptoCurrency.network.derivationPath.value,
destinationAddress = "",
tokenSymbol = null,
amount = "",
fee = "",
),
)
val cardInfo = getCardInfoUseCase(userWallet.scanResponse).getOrNull() ?: return
modelScope.launch {
sendFeedbackEmailUseCase(type = FeedbackEmailType.TransactionSendingProblem(cardInfo = cardInfo))
}
}
private fun getCurrenciesStatusUpdates(isSingleWalletWithToken: Boolean) {
getCurrencyStatusUpdatesUseCase(
userWalletId = userWalletId,
@ -171,9 +201,9 @@ internal class NFTSendModel @Inject constructor(
}
},
ifLeft = {
// sendConfirmAlertFactory.getGenericErrorState {
// onFailedTxEmailClick(it.toString())
// }
alertFactory.getGenericErrorState {
onFailedTxEmailClick(it.toString())
}
},
)
}.launchIn(modelScope)