diff --git a/core/analytics/models/src/main/java/com/tangem/core/analytics/models/AnalyticsParam.kt b/core/analytics/models/src/main/java/com/tangem/core/analytics/models/AnalyticsParam.kt index 31e79f809c..26da2b1161 100644 --- a/core/analytics/models/src/main/java/com/tangem/core/analytics/models/AnalyticsParam.kt +++ b/core/analytics/models/src/main/java/com/tangem/core/analytics/models/AnalyticsParam.kt @@ -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 { diff --git a/core/res/src/main/res/values-de/strings.xml b/core/res/src/main/res/values-de/strings.xml index 67aa4da4df..cecd9a6bbb 100644 --- a/core/res/src/main/res/values-de/strings.xml +++ b/core/res/src/main/res/values-de/strings.xml @@ -379,7 +379,7 @@ Du hast deine biometrischen Daten aktualisiert, scanne deine Karte oder Ring, um einzutreten Dein Guthaben sollte höher sein als der Gebührenwert, um eine Überweisung zu tätigen Unzureichende Mittel - 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 + 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 Nicht genug Mana Du kannst nur %s übertragen, da das Koinos-Netzwerk ein Mana-Limit vorgibt. Mana-Limit diff --git a/core/res/src/main/res/values-es/strings.xml b/core/res/src/main/res/values-es/strings.xml index 8d8cd1ccfe..128949fd13 100644 --- a/core/res/src/main/res/values-es/strings.xml +++ b/core/res/src/main/res/values-es/strings.xml @@ -375,7 +375,7 @@ Ha actualizado la biometría, escanee su tarjeta o anillo para entrar Su saldo debe ser mayor que el valor de la tarifa para hacer una transferencia Saldo insuficiente - 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 + No tiene suficiente Mana para esta transacción. Espere hasta que se reponga el maná. Su saldo de maná es %1$s/%2$s Mana insuficiente Solo puede transferir %s debido al límite de Mana impuesto por la red Koinos Límite de Mana diff --git a/core/res/src/main/res/values-fr/strings.xml b/core/res/src/main/res/values-fr/strings.xml index e7209c6305..9d695df7c1 100644 --- a/core/res/src/main/res/values-fr/strings.xml +++ b/core/res/src/main/res/values-fr/strings.xml @@ -375,7 +375,7 @@ Vous avez mis à jour vos données biométriques, scannez votre carte ou bague pour entrer Votre solde doit être supérieur à la valeur des frais pour effectuer un transfert Solde insuffisant - 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 + 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 Mana insuffisant Vous ne pouvez transférer que %s en raison de la limite de Mana imposée par le réseau Koinos Limite de Mana diff --git a/core/res/src/main/res/values-it/strings.xml b/core/res/src/main/res/values-it/strings.xml index 001ae1f84d..7132029cfe 100644 --- a/core/res/src/main/res/values-it/strings.xml +++ b/core/res/src/main/res/values-it/strings.xml @@ -19,7 +19,6 @@ Invia Impossibile inviare la transazione Con successo - 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. Codice di accesso Prima di scansionare la carta sarà necessario inserire il codice di accesso corretto Mantenimento della carta @@ -36,7 +35,6 @@ Termini del servizio Not enough funds for the transaction. Please top up your account. An error occurred - An error occurred. Code: %s. Notifica richiesta Scansiona carta Avvicina per modificare il codice di accesso @@ -44,9 +42,6 @@ Avvicina per scansionare Avvicina per firmare Avvicina la carta - You don\'t have enough Mana for this transaction. Please wait until the Mana is refilled. Your Mana balance is %1$s/%2$s - To use the %1$s network, you must pay the account reserve (%2$s %3$s), which locks up and hides that amount indefinitely - Destination account is not active. Send %s or more to activate the account. Per creare un account, invia fondi a questo indirizzo The destination account does not have a trustline for the asset being sent. Crea portafoglio @@ -55,7 +50,6 @@ L\'importo minimo è di %s Il resto minimo è di %s Commissione non valida - Minimum balance is %s Il conto totale non è stato creato L\'importo da inviare deve essere %s + commissione o maggiore Errore sconosciuto Memo diff --git a/core/res/src/main/res/values-ja/strings.xml b/core/res/src/main/res/values-ja/strings.xml index ec498830f5..e41ea53407 100644 --- a/core/res/src/main/res/values-ja/strings.xml +++ b/core/res/src/main/res/values-ja/strings.xml @@ -377,7 +377,7 @@ 生体認証を更新しました。カードまたはリングをスキャンして入ってください。 送金するには、残高が手数料額より高くなければなりません。 残高不足 - この取引に必要なManaが不足しています。Manaが補充されるまでお待ちください。あなたのMana残高は%1$s/%2$sです。 + この取引に必要なManaが足りません。Manaが補充されるまでお待ちください。Manaの残高は%1$s / %2$sです。 Manaが不足しています KoinosネットワークによるMana制限のため、%s のみ送金できます。 Mana上限 @@ -548,6 +548,8 @@ 送信先アカウントが有効ではありません。%s 以上を送信してアカウントを有効にしてください。 アカウントを作成するには、このアドレスに資金を送金してください 送信先アカウントには、送金されるアセットのトラストラインがありません。 + コードを共有すると、販売ごとに5 USDTを獲得できます。お友達は10%割引になります。 + 友達への紹介で報酬を獲得しよう! すべてのデバイスを保護するには、単一のアクセスコードを設定してください。 保護する 後で各カードおよびリングに個別のアクセスコードを設定できます。 @@ -892,9 +894,9 @@ 再ステーキングを使うと、ステーキングを解除することなく、あるバリデータから別のバリデータに資金を移動できます。 残高のすべてをステーキングしようとしています。ステーキング解除や報酬請求にかかるネットワーク手数料をカバーするために、少額を残しておくことをお勧めします。 TONでステーキングを開始するには、まず任意の金額の送金を行ってください。これにより、ウォレットがアクティブになります。 - TONをステーキングまたは出金する場合、入金と出金の両方でステーキング額から0.2 TONの手数料が差し引かれます。 + ネットワーク手数料に加え、取引の全ステップを完了するには最大0.2 TONが必要です。未使用分は取引完了後に返金されます。 この操作を続行するには、ネットワーク手数料に加えて0.2 TONが必要です。残高を補充してください。 - ステーキング手数料 + 0.2 TON保留済み このアクションは、ネットワークのルールに従って、他のポジションをクローズするか、引き出しステータスに切り替えます。 ポジション状況 資金をステーキングから引き出すには、ロックを解除してください。ロック解除には%sかかります。 diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml index 401b2fea2a..c599f5bead 100644 --- a/core/res/src/main/res/values-ru/strings.xml +++ b/core/res/src/main/res/values-ru/strings.xml @@ -525,6 +525,9 @@ Аккаунт получателя не активирован. Отправьте %s или более для активации аккаунта. Для создания аккаунта отправьте средства на этот адрес Аккаунт получателя не содержит трастлайна для отправляемого актива. + Присоединиться + Поделись промокодом — заработай 5 USDT с каждой покупки. Твои друзья получат скидку 10% на карту Tangem! + Получай бонусы за каждого друга! Установите единый код доступа для защиты всех ваших карт или колец Защита Установите индивидуальный код доступа для каждой карты или кольца позже. diff --git a/core/res/src/main/res/values-uk-rUA/strings.xml b/core/res/src/main/res/values-uk-rUA/strings.xml index 1a942a7a26..130fc7559d 100644 --- a/core/res/src/main/res/values-uk-rUA/strings.xml +++ b/core/res/src/main/res/values-uk-rUA/strings.xml @@ -381,7 +381,7 @@ Ви оновили дані біометрії, відскануйте свою картку або кільце для входу Ваш баланс повинен перевищувати суму комісії для здійснення переказу Недостатньо балансу - У вас недостатньо Mana для цієї транзакції. Будь ласка, зачекайте, поки Mana буде поповнена. Ваш баланс Mana становить %1$s/%2$s + У вас недостатньо Мани для цієї транзакції. Будь ласка, зачекайте, поки Мана поповниться. Ваш баланс мани дорівнює %1$s/%2$s Недостатньо Mana Ви можете переказати тільки %s через обмеження Mana, встановлене мережею Koinos Ліміт Mana diff --git a/core/res/src/main/res/values-zh-rTW/strings.xml b/core/res/src/main/res/values-zh-rTW/strings.xml index 78849a3497..e1f37d9840 100644 --- a/core/res/src/main/res/values-zh-rTW/strings.xml +++ b/core/res/src/main/res/values-zh-rTW/strings.xml @@ -140,7 +140,6 @@ Tangem反饋 無法發送交易 An error occurred - An error occurred. Code: %s. 需要memo 數量 %s 要繼續,您需要允許 %1s 智能合約使用您的 %2s @@ -153,12 +152,10 @@ 點擊簽名 點按卡片 您已更新生物識別登入,掃描您的卡進入 - You don\'t have enough Mana for this transaction. Please wait until the Mana is refilled. Your Mana balance is %1$s/%2$s 管理代幣 要訪問所有的網路您需要掃描卡片 掃描卡片 代幣 - To use the %1$s network, you must pay the account reserve (%2$s %3$s), which locks up and hides that amount indefinitely 目標帳戶未激活。發送 %s 或更多以激活帳戶 要創建帳戶,請將資金發送到此地址 目標帳戶沒有用於發送資產的 trustline diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index 81f172e609..d374882e15 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -546,6 +546,7 @@ You haven\'t added this network yet. To start receiving NFTs, add it to the main screen! Network not added Not Added + Send NFT Traits %1$d NFTs in %2$d collection Tap here to receive first NFT @@ -555,6 +556,9 @@ Destination account is not active. Send %s or more to activate the account. To create account send funds to this address The destination account does not have a trustline for the asset being sent. + Join Now + Share your code - earn 5 USDT per sale. Your friend gets 10% OFF. + Get REWARDS for every friend! Set up a single access code to protect all your devices. Protect Set an individual access code for each card or ring later. diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/confirm/model/SendConfirmAlertFactory.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/common/SendConfirmAlertFactory.kt similarity index 97% rename from features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/confirm/model/SendConfirmAlertFactory.kt rename to features/send-v2/impl/src/main/java/com/tangem/features/send/v2/common/SendConfirmAlertFactory.kt index 7eb09a280d..147ce18f67 100644 --- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/confirm/model/SendConfirmAlertFactory.kt +++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/common/SendConfirmAlertFactory.kt @@ -1,4 +1,4 @@ -package com.tangem.features.send.v2.send.confirm.model +package com.tangem.features.send.v2.common import com.tangem.common.ui.alerts.TransactionErrorAlertConverter import com.tangem.common.ui.alerts.models.AlertDemoModeUM diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/common/analytics/CommonSendAnalyticEvents.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/common/analytics/CommonSendAnalyticEvents.kt new file mode 100644 index 0000000000..a392ca4da3 --- /dev/null +++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/common/analytics/CommonSendAnalyticEvents.kt @@ -0,0 +1,109 @@ +package com.tangem.features.send.v2.common.analytics + +import com.tangem.core.analytics.models.AnalyticsEvent +import com.tangem.core.analytics.models.AnalyticsParam.Key.SOURCE +import com.tangem.core.analytics.models.AnalyticsParam.Key.TOKEN_PARAM + +/** + * Send screen analytics + */ +internal sealed class CommonSendAnalyticEvents( + category: String, + event: String, + params: Map = mapOf(), +) : AnalyticsEvent(category = category, event = event, params = params) { + + /** Recipient address screen opened */ + data class AddressScreenOpened( + val categoryName: String, + ) : CommonSendAnalyticEvents(category = categoryName, event = "Address Screen Opened") + + /** Amount screen opened */ + data class AmountScreenOpened( + val categoryName: String, + ) : CommonSendAnalyticEvents(category = categoryName, event = "Amount Screen Opened") + + /** Fee screen opened */ + data class FeeScreenOpened( + val categoryName: String, + ) : CommonSendAnalyticEvents(category = categoryName, event = "Fee Screen Opened") + + /** Confirmation screen opened */ + data class ConfirmationScreenOpened( + val categoryName: String, + ) : CommonSendAnalyticEvents(category = categoryName, event = "Confirm Screen Opened") + + /** If transaction delays notification is present */ + data class NoticeTransactionDelays( + val categoryName: String, + val token: String, + ) : CommonSendAnalyticEvents( + category = categoryName, + event = "Notice - Transaction Delays Are Possible", + params = mapOf(TOKEN_PARAM to token), + ) + + /** If error occurs during send transactions */ + data class TransactionError( + val categoryName: String, + val token: String, + ) : CommonSendAnalyticEvents( + category = categoryName, + event = "Error - Transaction Rejected", + params = mapOf(TOKEN_PARAM to token), + ) + + /** Close button clicked */ + data class CloseButtonClicked( + val categoryName: String, + val source: SendScreenSource, + val isFromSummary: Boolean, + val isValid: Boolean, + ) : CommonSendAnalyticEvents( + category = categoryName, + event = "Button - Close", + params = mapOf( + SOURCE to source.name, + "FromSummary" to if (isFromSummary) "Yes" else "No", + "isValid" to if (isValid) "Yes" else "No", + ), + ) + + /** Share button clicked */ + data class ShareButtonClicked( + val categoryName: String, + ) : CommonSendAnalyticEvents( + category = categoryName, + event = "Button - Share", + ) + + /** Expore button clicked */ + data class ExploreButtonClicked( + val categoryName: String, + ) : CommonSendAnalyticEvents( + category = categoryName, + event = "Button - Explore", + ) + + /** Screen reopened from confirmation screen */ + data class ScreenReopened( + val categoryName: String, + val source: SendScreenSource, + ) : CommonSendAnalyticEvents( + category = categoryName, + event = "Screen Reopened", + params = mapOf(SOURCE to source.name), + ) + + companion object { + const val SEND_CATEGORY = "Token / Send" + const val NFT_SEND_CATEGORY = "NFT" + } + + internal enum class SendScreenSource { + Address, + Amount, + Fee, + Confirm, + } +} \ No newline at end of file diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/DefaultSendComponent.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/DefaultSendComponent.kt index d94ae93e49..af8eb70adc 100644 --- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/DefaultSendComponent.kt +++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/DefaultSendComponent.kt @@ -18,13 +18,15 @@ 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.send.v2.api.SendComponent import com.tangem.features.send.v2.common.CommonSendRoute import com.tangem.features.send.v2.common.PredefinedValues +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.SendContent 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.send.analytics.SendAnalyticEvents.SendScreenSource +import com.tangem.features.send.v2.impl.R import com.tangem.features.send.v2.send.confirm.SendConfirmComponent import com.tangem.features.send.v2.send.model.SendModel import com.tangem.features.send.v2.subcomponents.amount.SendAmountComponent @@ -48,6 +50,7 @@ internal class DefaultSendComponent @AssistedInject constructor( ) : SendComponent, AppComponentContext by appComponentContext { private val stackNavigation = StackNavigation() + private val analyticCategoryName = CommonSendAnalyticEvents.SEND_CATEGORY private val innerRouter = InnerRouter( stackNavigation = stackNavigation, @@ -88,19 +91,27 @@ internal class DefaultSendComponent @AssistedInject constructor( componentScope.launch { when (val activeComponent = stack.active.instance) { is SendConfirmComponent -> if (currentRoute.value.isEditMode) { - analyticsEventHandler.send(SendAnalyticEvents.ConfirmationScreenOpened) + analyticsEventHandler.send( + CommonSendAnalyticEvents.ConfirmationScreenOpened(categoryName = analyticCategoryName), + ) activeComponent.updateState(model.uiState.value) } is SendAmountComponent -> { - analyticsEventHandler.send(SendAnalyticEvents.AmountScreenOpened) + analyticsEventHandler.send( + CommonSendAnalyticEvents.AmountScreenOpened(categoryName = analyticCategoryName), + ) activeComponent.updateState(model.uiState.value.amountUM) } is SendDestinationComponent -> { - analyticsEventHandler.send(SendAnalyticEvents.AddressScreenOpened) + analyticsEventHandler.send( + CommonSendAnalyticEvents.AddressScreenOpened(categoryName = analyticCategoryName), + ) activeComponent.updateState(model.uiState.value.destinationUM) } is SendFeeComponent -> { - analyticsEventHandler.send(SendAnalyticEvents.FeeScreenOpened) + analyticsEventHandler.send( + CommonSendAnalyticEvents.FeeScreenOpened(categoryName = analyticCategoryName), + ) } } currentRoute.emit(stack.active.configuration) @@ -135,7 +146,8 @@ internal class DefaultSendComponent @AssistedInject constructor( state = model.uiState.value.destinationUM, currentRoute = currentRoute.filterIsInstance(), isBalanceHidingFlow = model.isBalanceHiddenFlow, - analyticsCategoryName = SendAnalyticEvents.SEND_CATEGORY, + analyticsCategoryName = analyticCategoryName, + title = resourceReference(R.string.send_recipient_label), userWalletId = params.userWalletId, cryptoCurrency = params.currency, callback = model, @@ -156,7 +168,7 @@ internal class DefaultSendComponent @AssistedInject constructor( state = model.uiState.value.amountUM, currentRoute = currentRoute.filterIsInstance(), isBalanceHidingFlow = model.isBalanceHiddenFlow, - analyticsCategoryName = SendAnalyticEvents.SEND_CATEGORY, + analyticsCategoryName = analyticCategoryName, userWallet = model.userWallet, appCurrency = model.appCurrency, cryptoCurrencyStatus = model.cryptoCurrencyStatus, @@ -167,7 +179,8 @@ internal class DefaultSendComponent @AssistedInject constructor( onChildBack() } else { analyticsEventHandler.send( - SendAnalyticEvents.CloseButtonClicked( + CommonSendAnalyticEvents.CloseButtonClicked( + categoryName = analyticCategoryName, source = SendScreenSource.Amount, isFromSummary = false, isValid = model.uiState.value.amountUM.isPrimaryButtonEnabled, @@ -196,7 +209,7 @@ internal class DefaultSendComponent @AssistedInject constructor( params = SendFeeComponentParams.FeeParams( state = model.uiState.value.feeUM, currentRoute = currentRoute.filterIsInstance(), - analyticsCategoryName = SendAnalyticEvents.SEND_CATEGORY, + analyticsCategoryName = analyticCategoryName, userWallet = model.userWallet, cryptoCurrencyStatus = model.cryptoCurrencyStatus, feeCryptoCurrencyStatus = model.feeCryptoCurrencyStatus, @@ -235,7 +248,7 @@ internal class DefaultSendComponent @AssistedInject constructor( userWallet = model.userWallet, currentRoute = currentRoute, isBalanceHidingFlow = model.isBalanceHiddenFlow, - analyticsCategoryName = SendAnalyticEvents.SEND_CATEGORY, + analyticsCategoryName = analyticCategoryName, cryptoCurrencyStatus = model.cryptoCurrencyStatus, feeCryptoCurrencyStatus = model.feeCryptoCurrencyStatus, appCurrency = model.appCurrency, diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/analytics/SendAnalyticEvents.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/analytics/SendAnalyticEvents.kt index aca97719f1..90e33cdec8 100644 --- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/analytics/SendAnalyticEvents.kt +++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/analytics/SendAnalyticEvents.kt @@ -3,8 +3,8 @@ package com.tangem.features.send.v2.send.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.SOURCE import com.tangem.core.analytics.models.AnalyticsParam.Key.TOKEN_PARAM +import com.tangem.features.send.v2.common.analytics.CommonSendAnalyticEvents /** * Send screen analytics @@ -12,19 +12,7 @@ import com.tangem.core.analytics.models.AnalyticsParam.Key.TOKEN_PARAM internal sealed class SendAnalyticEvents( event: String, params: Map = mapOf(), -) : AnalyticsEvent(category = SEND_CATEGORY, event = event, params = params) { - - /** Recipient address screen opened */ - data object AddressScreenOpened : SendAnalyticEvents(event = "Address Screen Opened") - - /** Amount screen opened */ - data object AmountScreenOpened : SendAnalyticEvents(event = "Amount Screen Opened") - - /** Fee screen opened */ - data object FeeScreenOpened : SendAnalyticEvents(event = "Fee Screen Opened") - - /** Confirmation screen opened */ - data object ConfirmationScreenOpened : SendAnalyticEvents(event = "Confirm Screen Opened") +) : AnalyticsEvent(category = CommonSendAnalyticEvents.SEND_CATEGORY, event = event, params = params) { /** Transaction send screen opened */ data class TransactionScreenOpened( @@ -37,55 +25,4 @@ internal sealed class SendAnalyticEvents( FEE_TYPE to feeType.value, ), ) - - /** If transaction delays notification is present */ - data class NoticeTransactionDelays( - val token: String, - ) : SendAnalyticEvents( - event = "Notice - Transaction Delays Are Possible", - params = mapOf(TOKEN_PARAM to token), - ) - - /** If error occurs during send transactions */ - data class TransactionError(val token: String) : SendAnalyticEvents( - event = "Error - Transaction Rejected", - params = mapOf(TOKEN_PARAM to token), - ) - - /** Close button clicked */ - data class CloseButtonClicked( - val source: SendScreenSource, - val isFromSummary: Boolean, - val isValid: Boolean, - ) : SendAnalyticEvents( - event = "Button - Close", - params = mapOf( - SOURCE to source.name, - "FromSummary" to if (isFromSummary) "Yes" else "No", - "isValid" to if (isValid) "Yes" else "No", - ), - ) - - /** Share button clicked */ - data object ShareButtonClicked : SendAnalyticEvents(event = "Button - Share") - - /** Expore button clicked */ - data object ExploreButtonClicked : SendAnalyticEvents(event = "Button - Explore") - - /** Screen reopened from confirmation screen */ - data class ScreenReopened(val source: SendScreenSource) : SendAnalyticEvents( - event = "Screen Reopened", - params = mapOf(SOURCE to source.name), - ) - - companion object { - const val SEND_CATEGORY = "Token / Send" - } - - internal enum class SendScreenSource { - Address, - Amount, - Fee, - Confirm, - } } \ No newline at end of file diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/confirm/model/SendConfirmModel.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/confirm/model/SendConfirmModel.kt index 0cdba71372..51a5163719 100644 --- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/confirm/model/SendConfirmModel.kt +++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/confirm/model/SendConfirmModel.kt @@ -32,11 +32,12 @@ import com.tangem.domain.txhistory.usecase.GetExplorerTransactionUrlUseCase import com.tangem.domain.utils.convertToSdkAmount 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.analytics.SendAnalyticHelper import com.tangem.features.send.v2.send.confirm.SendConfirmComponent import com.tangem.features.send.v2.send.confirm.model.transformers.SendConfirmInitialStateTransformer @@ -93,6 +94,7 @@ internal class SendConfirmModel @Inject constructor( private val params: SendConfirmComponent.Params = paramsContainer.require() + private val analyticsCategoryName = params.analyticsCategoryName private val userWallet = params.userWallet private val appCurrency = params.appCurrency private val cryptoCurrencyStatus = params.cryptoCurrencyStatus @@ -165,7 +167,12 @@ internal class SendConfirmModel @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)) } } @@ -177,7 +184,12 @@ internal class SendConfirmModel @Inject constructor( val confirmUM = it.confirmUM as? ConfirmUM.Content it.copy(confirmUM = confirmUM?.copy(showTapHelp = false) ?: it.confirmUM) } - analyticsEventHandler.send(SendAnalyticEvents.ScreenReopened(SendScreenSource.Amount)) + analyticsEventHandler.send( + CommonSendAnalyticEvents.ScreenReopened( + categoryName = analyticsCategoryName, + source = SendScreenSource.Amount, + ), + ) router.push(CommonSendRoute.Amount(isEditMode = true)) } } @@ -189,7 +201,12 @@ internal class SendConfirmModel @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) } } @@ -207,13 +224,13 @@ internal class SendConfirmModel @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) } @@ -347,7 +364,12 @@ internal class SendConfirmModel @Inject constructor( popBack = appRouter::pop, onFailedTxEmailClick = ::onFailedTxEmailClick, ) - analyticsEventHandler.send(SendAnalyticEvents.TransactionError(cryptoCurrency.symbol)) + analyticsEventHandler.send( + CommonSendAnalyticEvents.TransactionError( + categoryName = analyticsCategoryName, + token = cryptoCurrency.symbol, + ), + ) }, ifRight = { updateTransactionStatus(txData) @@ -419,6 +441,7 @@ internal class SendConfirmModel @Inject constructor( analyticsEventHandler = analyticsEventHandler, cryptoCurrency = cryptoCurrencyStatus.currency, appCurrency = appCurrency, + analyticsCategoryName = params.analyticsCategoryName, ).transform(uiState.value.confirmUM), ) } @@ -445,7 +468,8 @@ internal class SendConfirmModel @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, diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/confirm/model/transformers/SendConfirmationNotificationsTransformer.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/confirm/model/transformers/SendConfirmationNotificationsTransformer.kt index 853e5bcdb5..dc73d36994 100644 --- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/confirm/model/transformers/SendConfirmationNotificationsTransformer.kt +++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/confirm/model/transformers/SendConfirmationNotificationsTransformer.kt @@ -14,9 +14,9 @@ import com.tangem.core.ui.format.bigdecimal.format import com.tangem.core.ui.utils.parseToBigDecimal import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.tokens.model.CryptoCurrency -import com.tangem.features.send.v2.impl.R -import com.tangem.features.send.v2.send.analytics.SendAnalyticEvents +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.impl.R 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 @@ -30,6 +30,7 @@ internal class SendConfirmationNotificationsTransformer( private val analyticsEventHandler: AnalyticsEventHandler, private val cryptoCurrency: CryptoCurrency, private val appCurrency: AppCurrency, + private val analyticsCategoryName: String, ) : Transformer { override fun transform(prevState: ConfirmUM): ConfirmUM { val state = prevState as? ConfirmUM.Content ?: return prevState @@ -52,7 +53,10 @@ internal class SendConfirmationNotificationsTransformer( if (feeSelectorUM.selectedType == FeeType.Custom && minimumValue > customValue) { add(NotificationUM.Warning.FeeTooLow) analyticsEventHandler.send( - SendAnalyticEvents.NoticeTransactionDelays(cryptoCurrency.symbol), + CommonSendAnalyticEvents.NoticeTransactionDelays( + categoryName = analyticsCategoryName, + token = cryptoCurrency.symbol, + ), ) } } diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/model/SendModel.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/model/SendModel.kt index c153cbe90e..ea1ca3146c 100644 --- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/model/SendModel.kt +++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/send/model/SendModel.kt @@ -37,7 +37,7 @@ import com.tangem.features.send.v2.common.PredefinedValues 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.send.confirm.SendConfirmComponent -import com.tangem.features.send.v2.send.confirm.model.SendConfirmAlertFactory +import com.tangem.features.send.v2.common.SendConfirmAlertFactory import com.tangem.features.send.v2.send.ui.state.SendUM import com.tangem.features.send.v2.subcomponents.amount.SendAmountComponent import com.tangem.features.send.v2.subcomponents.amount.SendAmountUpdateQRTrigger diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/sendnft/DefaultNFTSendComponent.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/sendnft/DefaultNFTSendComponent.kt index 4b65d6d5ae..7fc4f402c2 100644 --- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/sendnft/DefaultNFTSendComponent.kt +++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/sendnft/DefaultNFTSendComponent.kt @@ -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() + private val analyticsCategoryName = CommonSendAnalyticEvents.NFT_SEND_CATEGORY private val innerRouter = InnerRouter( 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(), 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(), - 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, diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/sendnft/analytics/NFTSendAnalyticEvents.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/sendnft/analytics/NFTSendAnalyticEvents.kt new file mode 100644 index 0000000000..ec215b0478 --- /dev/null +++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/sendnft/analytics/NFTSendAnalyticEvents.kt @@ -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 = 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, + ), + ) +} \ No newline at end of file diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/sendnft/analytics/NFTSendAnalyticHelper.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/sendnft/analytics/NFTSendAnalyticHelper.kt new file mode 100644 index 0000000000..da36ab5006 --- /dev/null +++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/sendnft/analytics/NFTSendAnalyticHelper.kt @@ -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 + } + } +} \ No newline at end of file diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/sendnft/confirm/model/NFTSendConfirmModel.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/sendnft/confirm/model/NFTSendConfirmModel.kt index 19424360b9..0e89448a8f 100644 --- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/sendnft/confirm/model/NFTSendConfirmModel.kt +++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/sendnft/confirm/model/NFTSendConfirmModel.kt @@ -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, diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/sendnft/confirm/model/transformers/NFTSendConfirmationNotificationsTransformer.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/sendnft/confirm/model/transformers/NFTSendConfirmationNotificationsTransformer.kt index af93239501..f5b2ba2744 100644 --- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/sendnft/confirm/model/transformers/NFTSendConfirmationNotificationsTransformer.kt +++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/sendnft/confirm/model/transformers/NFTSendConfirmationNotificationsTransformer.kt @@ -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 { 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, + ), ) } } diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/sendnft/model/NFTSendModel.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/sendnft/model/NFTSendModel.kt index 71fb3be509..8146fab729 100644 --- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/sendnft/model/NFTSendModel.kt +++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/sendnft/model/NFTSendModel.kt @@ -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) diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/destination/SendDestinationComponentParams.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/destination/SendDestinationComponentParams.kt index ecd05eba6d..f22aacd83c 100644 --- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/destination/SendDestinationComponentParams.kt +++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/destination/SendDestinationComponentParams.kt @@ -1,5 +1,6 @@ package com.tangem.features.send.v2.subcomponents.destination +import com.tangem.core.ui.extensions.TextReference import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.wallets.models.UserWalletId import com.tangem.features.send.v2.common.CommonSendRoute @@ -21,6 +22,7 @@ internal sealed class SendDestinationComponentParams { override val analyticsCategoryName: String, override val cryptoCurrency: CryptoCurrency, override val userWalletId: UserWalletId, + val title: TextReference, val isBalanceHidingFlow: StateFlow, val currentRoute: Flow, val callback: ModelCallback, diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/destination/model/SendDestinationModel.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/destination/model/SendDestinationModel.kt index b2e71ae80a..16dbe408d7 100644 --- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/destination/model/SendDestinationModel.kt +++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/destination/model/SendDestinationModel.kt @@ -22,10 +22,10 @@ import com.tangem.domain.txhistory.usecase.GetFixedTxHistoryItemsUseCase import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.usecase.GetWalletsUseCase import com.tangem.features.send.v2.common.PredefinedValues +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.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.subcomponents.destination.SendDestinationComponentParams import com.tangem.features.send.v2.subcomponents.destination.SendDestinationComponentParams.DestinationBlockParams @@ -289,7 +289,7 @@ internal class SendDestinationModel @Inject constructor( ).onEach { (state, route) -> params.callback.onNavigationResult( NavigationUM.Content( - title = resourceReference(R.string.send_recipient_label), + title = params.title, subtitle = null, backIconRes = if (route.isEditMode) { R.drawable.ic_back_24 @@ -299,7 +299,8 @@ internal class SendDestinationModel @Inject constructor( backIconClick = { if (!route.isEditMode) { analyticsEventHandler.send( - SendAnalyticEvents.CloseButtonClicked( + CommonSendAnalyticEvents.CloseButtonClicked( + categoryName = params.analyticsCategoryName, source = SendScreenSource.Address, isFromSummary = false, isValid = state.isPrimaryButtonEnabled,