Updated on 2026-08-14
This commit is contained in:
parent
53f9b9d572
commit
d17d9e35bf
28 changed files with 514 additions and 455 deletions
|
|
@ -5,16 +5,16 @@ import android.content.Context
|
|||
import android.content.pm.PackageManager
|
||||
import coil.ImageLoader
|
||||
import coil.ImageLoaderFactory
|
||||
import com.appsflyer.AppsFlyerLib
|
||||
import com.tangem.Log
|
||||
import com.tangem.LogFormat
|
||||
import com.tangem.blockchain.network.BlockchainSdkRetrofitBuilder
|
||||
import com.tangem.common.json.MoshiJsonConverter
|
||||
import com.tangem.domain.DomainLayer
|
||||
import com.tangem.domain.common.LogConfig
|
||||
import com.tangem.network.common.MoshiConverter
|
||||
import com.tangem.tap.common.AndroidAssetReader
|
||||
import com.tangem.tap.common.AssetReader
|
||||
import com.tangem.tap.common.analytics.GlobalAnalyticsHandler
|
||||
import com.tangem.tap.common.analytics.AnalyticsEventHandlerBuilder
|
||||
import com.tangem.tap.common.feedback.AdditionalFeedbackInfo
|
||||
import com.tangem.tap.common.feedback.FeedbackManager
|
||||
import com.tangem.tap.common.images.createCoilImageLoader
|
||||
|
|
@ -95,15 +95,19 @@ class TapApplication : Application(), ImageLoaderFactory {
|
|||
|
||||
private fun initWithConfigDependency(config: Config) {
|
||||
shopService = TangemShopService(this, config.shopify!!)
|
||||
initAppsFlyer(this, config)
|
||||
initAnalytics(this, config)
|
||||
initFeedbackManager(this, preferencesStorage, config)
|
||||
}
|
||||
|
||||
private fun initAppsFlyer(context: Context, config: Config) {
|
||||
AppsFlyerLib.getInstance().init(config.appsFlyerDevKey, null, context)
|
||||
AppsFlyerLib.getInstance().start(context)
|
||||
val analyticsHandler = GlobalAnalyticsHandler.createDefaultAnalyticHandlers(context)
|
||||
store.dispatch(GlobalAction.SetGlobalAnalyticsHandler(analyticsHandler))
|
||||
private fun initAnalytics(application: Application, config: Config) {
|
||||
val globalAnalyticsHandler = AnalyticsEventHandlerBuilder(
|
||||
application = application,
|
||||
config = config,
|
||||
isDebug = BuildConfig.DEBUG,
|
||||
logConfig = LogConfig.analyticsHandlers,
|
||||
jsonConverter = MoshiJsonConverter.INSTANCE,
|
||||
).default()
|
||||
store.dispatch(GlobalAction.SetGlobalAnalyticsHandler(globalAnalyticsHandler))
|
||||
}
|
||||
|
||||
private fun initFeedbackManager(context: Context, preferencesStorage: PreferencesStorage, config: Config) {
|
||||
|
|
|
|||
|
|
@ -1,56 +0,0 @@
|
|||
package com.tangem.tap.common.analytics
|
||||
|
||||
import com.amplitude.api.Amplitude
|
||||
import com.amplitude.api.AmplitudeClient
|
||||
import com.shopify.buy3.Storefront
|
||||
import com.tangem.common.card.Card
|
||||
import com.tangem.common.core.TangemSdkError
|
||||
import org.json.JSONObject
|
||||
|
||||
class AmplitudeAnalyticsHandler : AnalyticsHandler() {
|
||||
|
||||
private val client: AmplitudeClient = Amplitude.getInstance()
|
||||
|
||||
override fun triggerEvent(
|
||||
event: AnalyticsEvent,
|
||||
card: Card?,
|
||||
blockchain: String?,
|
||||
params: Map<String, String>
|
||||
) {
|
||||
client.logEvent(event.event, prepareParams(card, blockchain, params).toJson())
|
||||
}
|
||||
|
||||
override fun triggerEvent(event: String, params: Map<String, String>) {
|
||||
client.logEvent(event, params.toJson())
|
||||
}
|
||||
|
||||
override fun logCardSdkError(
|
||||
error: TangemSdkError,
|
||||
actionToLog: Analytics.ActionToLog,
|
||||
parameters: Map<AnalyticsParam, String>?,
|
||||
card: Card?
|
||||
) {
|
||||
//TODO
|
||||
}
|
||||
|
||||
override fun logError(error: Throwable, params: Map<String, String>) {
|
||||
//TODO
|
||||
}
|
||||
|
||||
override fun getOrderEvent(): String {
|
||||
//TODO
|
||||
return ""
|
||||
}
|
||||
|
||||
override fun getOrderParams(order: Storefront.Order): Map<String, String> {
|
||||
//TODO
|
||||
return emptyMap()
|
||||
}
|
||||
|
||||
private fun Map<String, String>.toJson(): JSONObject {
|
||||
val json = JSONObject()
|
||||
this.map { json.put(it.key, it.value) }
|
||||
return json
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
package com.tangem.tap.common.analytics
|
||||
|
||||
import com.shopify.buy3.Storefront
|
||||
import com.tangem.blockchain.common.BlockchainError
|
||||
import com.tangem.common.card.Card
|
||||
import com.tangem.common.core.TangemSdkError
|
||||
import com.tangem.tap.common.extensions.filterNotNull
|
||||
|
||||
interface EventHandler {
|
||||
fun handleEvent(
|
||||
event: String,
|
||||
params: Map<String, String> = emptyMap(),
|
||||
)
|
||||
}
|
||||
|
||||
interface AnalyticsEventHandler : EventHandler {
|
||||
fun handleAnalyticsEvent(
|
||||
event: AnalyticsEvent,
|
||||
params: Map<String, String> = emptyMap(),
|
||||
card: Card? = null,
|
||||
blockchain: String? = null,
|
||||
)
|
||||
|
||||
fun prepareParams(
|
||||
card: Card?,
|
||||
blockchain: String? = null,
|
||||
params: Map<String, String> = emptyMap(),
|
||||
): Map<String, String> {
|
||||
return mapOf(
|
||||
AnalyticsParam.FIRMWARE.param to card?.firmwareVersion?.stringValue,
|
||||
AnalyticsParam.BATCH_ID.param to card?.batchId,
|
||||
AnalyticsParam.BLOCKCHAIN.param to blockchain,
|
||||
).filterNotNull() + params
|
||||
}
|
||||
}
|
||||
|
||||
interface ShopifyOrderEventHandler {
|
||||
fun handleShopifyOrderEvent(order: Storefront.Order)
|
||||
}
|
||||
|
||||
interface ErrorEventHandler {
|
||||
fun handleErrorEvent(
|
||||
error: Throwable,
|
||||
params: Map<String, String> = emptyMap(),
|
||||
)
|
||||
}
|
||||
|
||||
interface SdkErrorEventHandler : CardSdkErrorEventHandler, BlockchainSdkErrorEventHandler
|
||||
|
||||
interface CardSdkErrorEventHandler {
|
||||
fun handleCardSdkErrorEvent(
|
||||
error: TangemSdkError,
|
||||
action: Analytics.ActionToLog,
|
||||
params: Map<AnalyticsParam, String> = emptyMap(),
|
||||
card: Card? = null,
|
||||
)
|
||||
}
|
||||
|
||||
interface BlockchainSdkErrorEventHandler {
|
||||
fun handleBlockchainSdkErrorEvent(
|
||||
error: BlockchainError,
|
||||
action: Analytics.ActionToLog,
|
||||
params: Map<AnalyticsParam, String> = mapOf(),
|
||||
card: Card? = null,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
package com.tangem.tap.common.analytics
|
||||
|
||||
import android.app.Application
|
||||
import com.tangem.common.json.MoshiJsonConverter
|
||||
import com.tangem.domain.common.AnalyticsHandlersLogConfig
|
||||
import com.tangem.tap.common.analytics.handlers.amplitude.AmplitudeAnalyticsHandler
|
||||
import com.tangem.tap.common.analytics.handlers.appsFlyer.AppsFlyerAnalyticsHandler
|
||||
import com.tangem.tap.common.analytics.handlers.firebase.FirebaseAnalyticsHandler
|
||||
import com.tangem.tap.domain.configurable.config.Config
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
class AnalyticsEventHandlerBuilder(
|
||||
private val application: Application,
|
||||
private val config: Config,
|
||||
private val isDebug: Boolean,
|
||||
private val logConfig: AnalyticsHandlersLogConfig,
|
||||
private val jsonConverter: MoshiJsonConverter,
|
||||
) {
|
||||
|
||||
private val analyticHandlers = mutableListOf<AnalyticsEventHandler>()
|
||||
|
||||
fun build(): GlobalAnalyticsEventHandler {
|
||||
return GlobalAnalyticsHandler(analyticHandlers.toList())
|
||||
}
|
||||
|
||||
fun default(): GlobalAnalyticsEventHandler {
|
||||
addFirebaseAnalytics()
|
||||
addAppsFlyer()
|
||||
addAmplitude()
|
||||
|
||||
return GlobalAnalyticsHandler(analyticHandlers.toList())
|
||||
}
|
||||
|
||||
fun addFirebaseAnalytics(): AnalyticsEventHandlerBuilder {
|
||||
if (isDebug) {
|
||||
addEventLogger(logConfig.firebase, FirebaseAnalyticsHandler::class.java.simpleName)
|
||||
} else {
|
||||
analyticHandlers.add(FirebaseAnalyticsHandler())
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
fun addAppsFlyer(): AnalyticsEventHandlerBuilder {
|
||||
if (isDebug) {
|
||||
addEventLogger(logConfig.appsFlyer, AppsFlyerAnalyticsHandler::class.java.simpleName)
|
||||
} else {
|
||||
analyticHandlers.add(AppsFlyerAnalyticsHandler(application, config.appsFlyerDevKey))
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
fun addAmplitude(): AnalyticsEventHandlerBuilder {
|
||||
if (isDebug) {
|
||||
addEventLogger(logConfig.amplitude, AmplitudeAnalyticsHandler::class.java.simpleName)
|
||||
} else {
|
||||
analyticHandlers.add(AmplitudeAnalyticsHandler(application, config.amplitudeApiKey))
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
private fun addEventLogger(logsEnabled: Boolean, name: String) {
|
||||
// if (logsEnabled) analyticHandlers.add(AnalyticsLogsPrinter(name, jsonConverter))
|
||||
}
|
||||
}
|
||||
|
|
@ -1,93 +0,0 @@
|
|||
package com.tangem.tap.common.analytics
|
||||
|
||||
import com.shopify.buy3.Storefront
|
||||
import com.tangem.common.card.Card
|
||||
import com.tangem.common.core.TangemSdkError
|
||||
import com.tangem.tap.common.extensions.filterNotNull
|
||||
|
||||
|
||||
abstract class AnalyticsHandler {
|
||||
abstract fun triggerEvent(
|
||||
event: AnalyticsEvent,
|
||||
card: Card? = null,
|
||||
blockchain: String? = null,
|
||||
params: Map<String, String> = emptyMap()
|
||||
)
|
||||
|
||||
abstract fun triggerEvent(
|
||||
event: String,
|
||||
params: Map<String, String>
|
||||
)
|
||||
|
||||
abstract fun logCardSdkError(
|
||||
error: TangemSdkError,
|
||||
actionToLog: Analytics.ActionToLog,
|
||||
parameters: Map<AnalyticsParam, String>? = null,
|
||||
card: Card? = null
|
||||
)
|
||||
|
||||
abstract fun logError(
|
||||
error: Throwable,
|
||||
params: Map<String, String> = emptyMap()
|
||||
)
|
||||
|
||||
protected fun prepareParams(
|
||||
card: Card?,
|
||||
blockchain: String? = null,
|
||||
params: Map<String, String> = emptyMap()
|
||||
): Map<String, String> {
|
||||
return mapOf(
|
||||
AnalyticsParam.FIRMWARE.param to card?.firmwareVersion?.stringValue,
|
||||
AnalyticsParam.BATCH_ID.param to card?.batchId,
|
||||
AnalyticsParam.BLOCKCHAIN.param to blockchain,
|
||||
).filterNotNull() + params
|
||||
}
|
||||
|
||||
fun logWcEvent(event: Analytics.WcAnalyticsEvent) {
|
||||
when (event) {
|
||||
is Analytics.WcAnalyticsEvent.Action -> {
|
||||
triggerEvent(
|
||||
event = AnalyticsEvent.WC_SUCCESS_RESPONSE,
|
||||
params = mapOf(
|
||||
AnalyticsParam.WALLET_CONNECT_ACTION.param to event.action.name
|
||||
)
|
||||
)
|
||||
}
|
||||
is Analytics.WcAnalyticsEvent.Error -> {
|
||||
val params = mapOf(
|
||||
AnalyticsParam.WALLET_CONNECT_ACTION.param to event.action?.name,
|
||||
AnalyticsParam.ERROR_DESCRIPTION.param to event.error.message
|
||||
)
|
||||
.filterNotNull()
|
||||
logError(event.error, params)
|
||||
}
|
||||
is Analytics.WcAnalyticsEvent.InvalidRequest ->
|
||||
triggerEvent(
|
||||
event = AnalyticsEvent.WC_INVALID_REQUEST,
|
||||
params = mapOf(
|
||||
AnalyticsParam.WALLET_CONNECT_REQUEST.param to event.json
|
||||
).filterNotNull()
|
||||
)
|
||||
is Analytics.WcAnalyticsEvent.Session -> {
|
||||
val analyticsEvent = when (event.event) {
|
||||
Analytics.WcSessionEvent.Disconnect -> AnalyticsEvent.WC_SESSION_DISCONNECTED
|
||||
Analytics.WcSessionEvent.Connect -> AnalyticsEvent.WC_NEW_SESSION
|
||||
}
|
||||
triggerEvent(
|
||||
event = analyticsEvent,
|
||||
params = mapOf(
|
||||
AnalyticsParam.WALLET_CONNECT_DAPP_URL.param to event.url
|
||||
).filterNotNull()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun logShopifyOrder(order: Storefront.Order) {
|
||||
triggerEvent(getOrderEvent(), getOrderParams(order))
|
||||
}
|
||||
|
||||
protected abstract fun getOrderEvent(): String
|
||||
|
||||
protected abstract fun getOrderParams(order: Storefront.Order): Map<String, String>
|
||||
}
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
package com.tangem.tap.common.analytics
|
||||
|
||||
import android.content.Context
|
||||
import com.appsflyer.AFInAppEventParameterName
|
||||
import com.appsflyer.AFInAppEventType
|
||||
import com.appsflyer.AppsFlyerLib
|
||||
import com.shopify.buy3.Storefront
|
||||
import com.tangem.common.card.Card
|
||||
import com.tangem.common.core.TangemSdkError
|
||||
|
||||
class AppsFlyerAnalyticsHandler(val context: Context): AnalyticsHandler() {
|
||||
|
||||
override fun triggerEvent(
|
||||
event: AnalyticsEvent,
|
||||
card: Card?,
|
||||
blockchain: String?,
|
||||
params: Map<String, String>
|
||||
) {
|
||||
AppsFlyerLib.getInstance().logEvent(
|
||||
context,
|
||||
event.event,
|
||||
prepareParams(card, blockchain, params)
|
||||
)
|
||||
}
|
||||
|
||||
override fun logCardSdkError(
|
||||
error: TangemSdkError,
|
||||
actionToLog: Analytics.ActionToLog,
|
||||
parameters: Map<AnalyticsParam, String>?,
|
||||
card: Card?
|
||||
) {
|
||||
//TODO
|
||||
}
|
||||
|
||||
override fun logError(error: Throwable, params: Map<String, String>) {
|
||||
//TODO
|
||||
}
|
||||
|
||||
override fun getOrderEvent(): String = AFInAppEventType.PURCHASE
|
||||
|
||||
override fun getOrderParams(order: Storefront.Order): Map<String, String> {
|
||||
|
||||
val sku = order.lineItems.edges.firstOrNull()?.node?.variant?.sku ?: "unknown"
|
||||
|
||||
val discountCode =
|
||||
(order.discountApplications.edges.firstOrNull()?.node as? Storefront.DiscountCodeApplication)?.code
|
||||
|
||||
val discountParams = if (discountCode != null ){
|
||||
mapOf(AFInAppEventParameterName.COUPON_CODE to discountCode)
|
||||
} else {
|
||||
mapOf()
|
||||
}
|
||||
|
||||
return mapOf(
|
||||
AFInAppEventParameterName.CONTENT_ID to sku,
|
||||
AFInAppEventParameterName.REVENUE to order.totalPriceV2.amount,
|
||||
AFInAppEventParameterName.CURRENCY to order.currencyCode.name
|
||||
) + discountParams
|
||||
}
|
||||
|
||||
override fun triggerEvent(event: String, params: Map<String, String>) {
|
||||
AppsFlyerLib.getInstance().logEvent(context, event, params)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,88 +0,0 @@
|
|||
package com.tangem.tap.common.analytics
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.core.os.bundleOf
|
||||
import com.google.firebase.analytics.FirebaseAnalytics
|
||||
import com.google.firebase.analytics.ktx.analytics
|
||||
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||
import com.google.firebase.ktx.Firebase
|
||||
import com.shopify.buy3.Storefront
|
||||
import com.tangem.common.card.Card
|
||||
import com.tangem.common.core.TangemSdkError
|
||||
|
||||
object FirebaseAnalyticsHandler : AnalyticsHandler() {
|
||||
override fun triggerEvent(
|
||||
event: AnalyticsEvent,
|
||||
card: Card?,
|
||||
blockchain: String?,
|
||||
params: Map<String, String>
|
||||
) {
|
||||
val fullParams = prepareParams(card, blockchain, params)
|
||||
Firebase.analytics.logEvent(event.event, fullParams.toBundle())
|
||||
}
|
||||
|
||||
fun logException(name: String, throwable: Throwable) {
|
||||
Firebase.analytics.logEvent(name, bundleOf(
|
||||
"message" to (throwable.message ?: "none"),
|
||||
"cause_message" to (throwable.cause?.message ?: "none"),
|
||||
"stack_trace" to throwable.stackTraceToString()
|
||||
))
|
||||
}
|
||||
|
||||
private fun Map<String, String>.toBundle(): Bundle {
|
||||
return bundleOf(*this.toList().toTypedArray())
|
||||
}
|
||||
|
||||
override fun logCardSdkError(
|
||||
error: TangemSdkError,
|
||||
actionToLog: Analytics.ActionToLog,
|
||||
parameters: Map<AnalyticsParam, String>?,
|
||||
card: Card?,
|
||||
) {
|
||||
if (error is TangemSdkError.UserCancelled) return
|
||||
|
||||
val params = parameters?.toMutableMap() ?: mutableMapOf()
|
||||
if (card != null) params + prepareParams(card)
|
||||
params[AnalyticsParam.ACTION] = actionToLog.key
|
||||
params[AnalyticsParam.ERROR_CODE] = error.code.toString()
|
||||
params[AnalyticsParam.ERROR_DESCRIPTION] = error.javaClass.simpleName
|
||||
params[AnalyticsParam.ERROR_KEY] = "TangemSdkError"
|
||||
|
||||
params.forEach {
|
||||
FirebaseCrashlytics.getInstance().setCustomKey(it.key.param, it.value)
|
||||
}
|
||||
val cardError = TangemSdk.map(error)
|
||||
FirebaseCrashlytics.getInstance().recordException(cardError)
|
||||
}
|
||||
|
||||
override fun logError(error: Throwable, params: Map<String, String>) {
|
||||
params.forEach { (key, value) -> FirebaseCrashlytics.getInstance().setCustomKey(key, value) }
|
||||
FirebaseCrashlytics.getInstance().recordException(error)
|
||||
}
|
||||
|
||||
override fun getOrderEvent(): String = FirebaseAnalytics.Event.PURCHASE
|
||||
|
||||
override fun getOrderParams(order: Storefront.Order): Map<String, String> {
|
||||
|
||||
val sku = order.lineItems.edges.firstOrNull()?.node?.variant?.sku ?: "unknown"
|
||||
|
||||
val discountCode =
|
||||
(order.discountApplications.edges.firstOrNull()?.node as? Storefront.DiscountCodeApplication)?.code
|
||||
|
||||
val discountParams = if (discountCode != null ){
|
||||
mapOf(FirebaseAnalytics.Param.DISCOUNT to discountCode)
|
||||
} else {
|
||||
mapOf()
|
||||
}
|
||||
|
||||
return mapOf(
|
||||
FirebaseAnalytics.Param.ITEM_ID to sku,
|
||||
FirebaseAnalytics.Param.VALUE to order.totalPriceV2.amount,
|
||||
FirebaseAnalytics.Param.CURRENCY to order.currencyCode.name
|
||||
) + discountParams
|
||||
}
|
||||
|
||||
override fun triggerEvent(event: String, params: Map<String, String>) {
|
||||
Firebase.analytics.logEvent(event, params.toBundle())
|
||||
}
|
||||
}
|
||||
|
|
@ -1,77 +1,103 @@
|
|||
package com.tangem.tap.common.analytics
|
||||
|
||||
import android.content.Context
|
||||
import com.amplitude.api.Amplitude
|
||||
import com.appsflyer.AppsFlyerLib
|
||||
import com.shopify.buy3.Storefront
|
||||
import com.tangem.blockchain.common.BlockchainError
|
||||
import com.tangem.common.card.Card
|
||||
import com.tangem.common.core.TangemSdkError
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.tap.common.extensions.filterNotNull
|
||||
|
||||
class GlobalAnalyticsHandler(val analyticsHandlers: List<AnalyticsHandler>) :
|
||||
AnalyticsHandler() {
|
||||
override fun triggerEvent(
|
||||
interface GlobalAnalyticsEventHandler : AnalyticsEventHandler,
|
||||
ShopifyOrderEventHandler,
|
||||
ErrorEventHandler,
|
||||
SdkErrorEventHandler
|
||||
|
||||
class GlobalAnalyticsHandler(
|
||||
private val analyticsHandlers: List<AnalyticsEventHandler>,
|
||||
) : GlobalAnalyticsEventHandler {
|
||||
|
||||
override fun handleEvent(event: String, params: Map<String, String>) {
|
||||
analyticsHandlers.forEach { it.handleEvent(event, params) }
|
||||
}
|
||||
|
||||
override fun handleAnalyticsEvent(
|
||||
event: AnalyticsEvent,
|
||||
params: Map<String, String>,
|
||||
card: Card?,
|
||||
blockchain: String?,
|
||||
params: Map<String, String>
|
||||
) {
|
||||
analyticsHandlers.forEach { it.triggerEvent(event, card, blockchain, params) }
|
||||
analyticsHandlers.forEach { it.handleAnalyticsEvent(event, params, card, blockchain) }
|
||||
}
|
||||
|
||||
override fun triggerEvent(event: String, params: Map<String, String>) {
|
||||
analyticsHandlers.forEach { it.triggerEvent(event, params) }
|
||||
override fun handleShopifyOrderEvent(order: Storefront.Order) {
|
||||
analyticsHandlers.filterIsInstance<ShopifyOrderEventHandler>().forEach {
|
||||
it.handleShopifyOrderEvent(order)
|
||||
}
|
||||
}
|
||||
|
||||
override fun logCardSdkError(
|
||||
override fun handleErrorEvent(error: Throwable, params: Map<String, String>) {
|
||||
analyticsHandlers.filterIsInstance<ErrorEventHandler>().forEach {
|
||||
it.handleErrorEvent(error, params)
|
||||
}
|
||||
}
|
||||
|
||||
override fun handleCardSdkErrorEvent(
|
||||
error: TangemSdkError,
|
||||
actionToLog: Analytics.ActionToLog,
|
||||
parameters: Map<AnalyticsParam, String>?,
|
||||
card: Card?
|
||||
action: Analytics.ActionToLog,
|
||||
params: Map<AnalyticsParam, String>,
|
||||
card: Card?,
|
||||
) {
|
||||
analyticsHandlers.forEach { it.logCardSdkError(error, actionToLog, parameters, card) }
|
||||
analyticsHandlers.filterIsInstance<CardSdkErrorEventHandler>().forEach {
|
||||
it.handleCardSdkErrorEvent(error, action, params, card)
|
||||
}
|
||||
}
|
||||
|
||||
override fun logError(error: Throwable, params: Map<String, String>) {
|
||||
analyticsHandlers.forEach { it.logError(error, params) }
|
||||
override fun handleBlockchainSdkErrorEvent(
|
||||
error: BlockchainError,
|
||||
action: Analytics.ActionToLog,
|
||||
params: Map<AnalyticsParam, String>,
|
||||
card: Card?,
|
||||
) {
|
||||
analyticsHandlers.filterIsInstance<BlockchainSdkErrorEventHandler>().forEach {
|
||||
it.handleBlockchainSdkErrorEvent(error, action, params, card)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getOrderEvent(): String {
|
||||
return ""
|
||||
}
|
||||
|
||||
override fun getOrderParams(order: Storefront.Order): Map<String, String> {
|
||||
return emptyMap()
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun createDefaultAnalyticHandlers(context: Context): GlobalAnalyticsHandler {
|
||||
return GlobalAnalyticsHandler(
|
||||
listOf(
|
||||
FirebaseAnalyticsHandler,
|
||||
AppsFlyerAnalyticsHandler(context),
|
||||
AmplitudeAnalyticsHandler()
|
||||
)
|
||||
fun GlobalAnalyticsEventHandler.logWcEvent(event: Analytics.WcAnalyticsEvent) {
|
||||
when (event) {
|
||||
is Analytics.WcAnalyticsEvent.Action -> {
|
||||
handleAnalyticsEvent(
|
||||
event = AnalyticsEvent.WC_SUCCESS_RESPONSE,
|
||||
params = mapOf(
|
||||
AnalyticsParam.WALLET_CONNECT_ACTION.param to event.action.name,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun initAnalytics(context: Context) {
|
||||
initAppsFlyer(context)
|
||||
initAmplitude(context)
|
||||
is Analytics.WcAnalyticsEvent.Error -> {
|
||||
val params = mapOf(
|
||||
AnalyticsParam.WALLET_CONNECT_ACTION.param to event.action?.name,
|
||||
AnalyticsParam.ERROR_DESCRIPTION.param to event.error.message,
|
||||
).filterNotNull()
|
||||
handleErrorEvent(event.error, params)
|
||||
}
|
||||
|
||||
private fun initAppsFlyer(context: Context) {
|
||||
val devKey = store.state.globalState.configManager?.config?.appsFlyerDevKey ?: return
|
||||
AppsFlyerLib.getInstance().init(devKey, null, context)
|
||||
AppsFlyerLib.getInstance().start(context)
|
||||
|
||||
}
|
||||
|
||||
private fun initAmplitude(context: Context) {
|
||||
val apiKey = store.state.globalState.configManager?.config?.amplitudeApiKey ?: return
|
||||
Amplitude.getInstance()
|
||||
.initialize(context.applicationContext, apiKey)
|
||||
.enableForegroundTracking(context)
|
||||
is Analytics.WcAnalyticsEvent.InvalidRequest ->
|
||||
handleAnalyticsEvent(
|
||||
event = AnalyticsEvent.WC_INVALID_REQUEST,
|
||||
params = mapOf(
|
||||
AnalyticsParam.WALLET_CONNECT_REQUEST.param to event.json,
|
||||
).filterNotNull(),
|
||||
)
|
||||
is Analytics.WcAnalyticsEvent.Session -> {
|
||||
val analyticsEvent = when (event.event) {
|
||||
Analytics.WcSessionEvent.Disconnect -> AnalyticsEvent.WC_SESSION_DISCONNECTED
|
||||
Analytics.WcSessionEvent.Connect -> AnalyticsEvent.WC_NEW_SESSION
|
||||
}
|
||||
handleAnalyticsEvent(
|
||||
event = analyticsEvent,
|
||||
params = mapOf(
|
||||
AnalyticsParam.WALLET_CONNECT_DAPP_URL.param to event.url,
|
||||
).filterNotNull(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
package com.tangem.tap.common.analytics.handlers.amplitude
|
||||
|
||||
import android.app.Application
|
||||
import com.amplitude.api.Amplitude
|
||||
import com.amplitude.api.AmplitudeClient
|
||||
import com.tangem.common.Converter
|
||||
import com.tangem.common.card.Card
|
||||
import com.tangem.tap.common.analytics.AnalyticsEvent
|
||||
import com.tangem.tap.common.analytics.AnalyticsEventHandler
|
||||
import org.json.JSONObject
|
||||
|
||||
class AmplitudeAnalyticsHandler(
|
||||
application: Application,
|
||||
key: String,
|
||||
) : AnalyticsEventHandler {
|
||||
|
||||
private val client: AmplitudeClient = Amplitude.getInstance()
|
||||
|
||||
init {
|
||||
client.initialize(application, key)
|
||||
client.enableForegroundTracking(application)
|
||||
}
|
||||
|
||||
override fun handleEvent(event: String, params: Map<String, String>) {
|
||||
client.logEvent(event, ParamsJSONObjectConverter().convert(params))
|
||||
}
|
||||
|
||||
override fun handleAnalyticsEvent(
|
||||
event: AnalyticsEvent,
|
||||
params: Map<String, String>,
|
||||
card: Card?,
|
||||
blockchain: String?,
|
||||
) {
|
||||
handleEvent(event.event, prepareParams(card, blockchain, params))
|
||||
}
|
||||
|
||||
class ParamsJSONObjectConverter : Converter<Map<String, String>, JSONObject> {
|
||||
override fun convert(value: Map<String, String>): JSONObject = JSONObject().apply {
|
||||
value.forEach { this.put(it.key, it.value) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
package com.tangem.tap.common.analytics.handlers.appsFlyer
|
||||
|
||||
import android.content.Context
|
||||
import com.appsflyer.AFInAppEventParameterName
|
||||
import com.appsflyer.AFInAppEventType
|
||||
import com.appsflyer.AppsFlyerLib
|
||||
import com.shopify.buy3.Storefront
|
||||
import com.tangem.common.Converter
|
||||
import com.tangem.common.card.Card
|
||||
import com.tangem.tap.common.analytics.AnalyticsEvent
|
||||
import com.tangem.tap.common.analytics.AnalyticsEventHandler
|
||||
import com.tangem.tap.common.analytics.ShopifyOrderEventHandler
|
||||
|
||||
class AppsFlyerAnalyticsHandler(
|
||||
private val context: Context,
|
||||
key: String,
|
||||
) : AnalyticsEventHandler, ShopifyOrderEventHandler {
|
||||
|
||||
private val appsFlyerLib: AppsFlyerLib = AppsFlyerLib.getInstance()
|
||||
|
||||
init {
|
||||
appsFlyerLib.init(key, null, context)
|
||||
appsFlyerLib.start(context)
|
||||
}
|
||||
|
||||
override fun handleEvent(event: String, params: Map<String, String>) {
|
||||
appsFlyerLib.logEvent(context, event, params)
|
||||
}
|
||||
|
||||
override fun handleAnalyticsEvent(
|
||||
event: AnalyticsEvent,
|
||||
params: Map<String, String>,
|
||||
card: Card?,
|
||||
blockchain: String?,
|
||||
) {
|
||||
handleEvent(event.event, prepareParams(card, blockchain, params))
|
||||
}
|
||||
|
||||
override fun handleShopifyOrderEvent(order: Storefront.Order) {
|
||||
handleEvent(ORDER_EVENT, OrderToParamsConverter().convert(order))
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val ORDER_EVENT = AFInAppEventType.PURCHASE
|
||||
}
|
||||
|
||||
class OrderToParamsConverter : Converter<Storefront.Order, Map<String, String>> {
|
||||
override fun convert(value: Storefront.Order): Map<String, String> {
|
||||
val sku = value.lineItems.edges.firstOrNull()?.node?.variant?.sku ?: "unknown"
|
||||
|
||||
val discountCode =
|
||||
(value.discountApplications.edges.firstOrNull()?.node as? Storefront.DiscountCodeApplication)?.code
|
||||
|
||||
val discountParams = if (discountCode != null) {
|
||||
mapOf(AFInAppEventParameterName.COUPON_CODE to discountCode)
|
||||
} else {
|
||||
mapOf()
|
||||
}
|
||||
|
||||
return mapOf(
|
||||
AFInAppEventParameterName.CONTENT_ID to sku,
|
||||
AFInAppEventParameterName.REVENUE to value.totalPriceV2.amount,
|
||||
AFInAppEventParameterName.CURRENCY to value.currencyCode.name,
|
||||
) + discountParams
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,127 @@
|
|||
package com.tangem.tap.common.analytics.handlers.firebase
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.core.os.bundleOf
|
||||
import com.google.firebase.analytics.FirebaseAnalytics
|
||||
import com.google.firebase.analytics.ktx.analytics
|
||||
import com.google.firebase.crashlytics.ktx.crashlytics
|
||||
import com.google.firebase.ktx.Firebase
|
||||
import com.shopify.buy3.Storefront
|
||||
import com.tangem.blockchain.common.BlockchainError
|
||||
import com.tangem.blockchain.common.BlockchainSdkError
|
||||
import com.tangem.common.Converter
|
||||
import com.tangem.common.card.Card
|
||||
import com.tangem.common.core.TangemSdkError
|
||||
import com.tangem.tap.common.analytics.Analytics
|
||||
import com.tangem.tap.common.analytics.AnalyticsEvent
|
||||
import com.tangem.tap.common.analytics.AnalyticsEventHandler
|
||||
import com.tangem.tap.common.analytics.AnalyticsParam
|
||||
import com.tangem.tap.common.analytics.ErrorEventHandler
|
||||
import com.tangem.tap.common.analytics.SdkErrorEventHandler
|
||||
import com.tangem.tap.common.analytics.ShopifyOrderEventHandler
|
||||
import com.tangem.tap.common.analytics.TangemSdk
|
||||
import com.tangem.tap.features.demo.DemoTransactionSender
|
||||
|
||||
class FirebaseAnalyticsHandler : AnalyticsEventHandler, ShopifyOrderEventHandler, ErrorEventHandler,
|
||||
SdkErrorEventHandler {
|
||||
|
||||
private val fbAnalytics = Firebase.analytics
|
||||
private val fbCrashlytics = Firebase.crashlytics
|
||||
|
||||
override fun handleEvent(event: String, params: Map<String, String>) {
|
||||
fbAnalytics.logEvent(event, params.toBundle())
|
||||
}
|
||||
|
||||
override fun handleAnalyticsEvent(
|
||||
event: AnalyticsEvent,
|
||||
params: Map<String, String>,
|
||||
card: Card?,
|
||||
blockchain: String?,
|
||||
) {
|
||||
handleEvent(event.event, prepareParams(card, blockchain, params))
|
||||
}
|
||||
|
||||
override fun handleShopifyOrderEvent(order: Storefront.Order) {
|
||||
handleEvent(ORDER_EVENT, OrderToParamsConverter().convert(order))
|
||||
}
|
||||
|
||||
override fun handleErrorEvent(error: Throwable, params: Map<String, String>) {
|
||||
params.forEach { (key, value) -> fbCrashlytics.setCustomKey(key, value) }
|
||||
fbCrashlytics.recordException(error)
|
||||
}
|
||||
|
||||
override fun handleCardSdkErrorEvent(
|
||||
error: TangemSdkError,
|
||||
action: Analytics.ActionToLog,
|
||||
params: Map<AnalyticsParam, String>,
|
||||
card: Card?,
|
||||
) {
|
||||
if (error is TangemSdkError.UserCancelled) return
|
||||
|
||||
val mutableParams = params.toMutableMap()
|
||||
if (card != null) mutableParams + prepareParams(card)
|
||||
|
||||
mutableParams[AnalyticsParam.ACTION] = action.key
|
||||
mutableParams[AnalyticsParam.ERROR_CODE] = error.code.toString()
|
||||
mutableParams[AnalyticsParam.ERROR_DESCRIPTION] = error.javaClass.simpleName
|
||||
mutableParams[AnalyticsParam.ERROR_KEY] = "TangemSdkError"
|
||||
|
||||
mutableParams.forEach { fbCrashlytics.setCustomKey(it.key.param, it.value) }
|
||||
fbCrashlytics.recordException(TangemSdk.map(error))
|
||||
}
|
||||
|
||||
override fun handleBlockchainSdkErrorEvent(
|
||||
error: BlockchainError,
|
||||
action: Analytics.ActionToLog,
|
||||
params: Map<AnalyticsParam, String>,
|
||||
card: Card?,
|
||||
) {
|
||||
val blockchainSdkError = (error as? BlockchainSdkError) ?: return
|
||||
|
||||
if (blockchainSdkError is BlockchainSdkError.WrappedTangemError) {
|
||||
val tangemSdkError = (blockchainSdkError.tangemError as? TangemSdkError) ?: return
|
||||
handleCardSdkErrorEvent(tangemSdkError, action, params, card)
|
||||
return
|
||||
}
|
||||
|
||||
if (blockchainSdkError.customMessage.contains(DemoTransactionSender.ID)) return
|
||||
|
||||
val mutableParams = params.toMutableMap()
|
||||
mutableParams[AnalyticsParam.ACTION] = action.key
|
||||
mutableParams[AnalyticsParam.ERROR_CODE] = error.code.toString()
|
||||
mutableParams[AnalyticsParam.ERROR_DESCRIPTION] = "${error.javaClass.simpleName}: ${error.customMessage}"
|
||||
mutableParams[AnalyticsParam.ERROR_KEY] = "BlockchainSdkError"
|
||||
|
||||
mutableParams.forEach { fbCrashlytics.setCustomKey(it.key.param, it.value) }
|
||||
fbCrashlytics.recordException(error)
|
||||
}
|
||||
|
||||
private fun Map<String, String>.toBundle(): Bundle {
|
||||
return bundleOf(*this.toList().toTypedArray())
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val ORDER_EVENT = FirebaseAnalytics.Event.PURCHASE
|
||||
}
|
||||
|
||||
class OrderToParamsConverter : Converter<Storefront.Order, Map<String, String>> {
|
||||
override fun convert(value: Storefront.Order): Map<String, String> {
|
||||
val sku = value.lineItems.edges.firstOrNull()?.node?.variant?.sku ?: "unknown"
|
||||
|
||||
val discountCode =
|
||||
(value.discountApplications.edges.firstOrNull()?.node as? Storefront.DiscountCodeApplication)?.code
|
||||
|
||||
val discountParams = if (discountCode != null) {
|
||||
mapOf(FirebaseAnalytics.Param.DISCOUNT to discountCode)
|
||||
} else {
|
||||
mapOf()
|
||||
}
|
||||
|
||||
return mapOf(
|
||||
FirebaseAnalytics.Param.ITEM_ID to sku,
|
||||
FirebaseAnalytics.Param.VALUE to value.totalPriceV2.amount,
|
||||
FirebaseAnalytics.Param.CURRENCY to value.currencyCode.name,
|
||||
) + discountParams
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
package com.tangem.tap.common.extensions
|
||||
|
||||
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||
import com.tangem.blockchain.common.BlockchainError
|
||||
import com.tangem.blockchain.common.BlockchainSdkError
|
||||
import com.tangem.common.card.Card
|
||||
import com.tangem.common.core.TangemSdkError
|
||||
import com.tangem.tap.common.analytics.Analytics
|
||||
import com.tangem.tap.common.analytics.AnalyticsHandler
|
||||
import com.tangem.tap.common.analytics.AnalyticsParam
|
||||
import com.tangem.tap.features.demo.DemoTransactionSender
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
fun AnalyticsHandler.logSendTransactionError(
|
||||
error: BlockchainError,
|
||||
action: Analytics.ActionToLog,
|
||||
parameters: Map<AnalyticsParam, String>? = mapOf(),
|
||||
card: Card? = null,
|
||||
) {
|
||||
when (val blockchainSdkError = (error as BlockchainSdkError)) {
|
||||
is BlockchainSdkError.WrappedTangemError -> {
|
||||
val tangemSdkError = (blockchainSdkError.tangemError as? TangemSdkError) ?: return
|
||||
|
||||
logCardSdkError(
|
||||
error = tangemSdkError,
|
||||
actionToLog = action,
|
||||
parameters = parameters,
|
||||
card = card,
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
when {
|
||||
blockchainSdkError.customMessage.contains(DemoTransactionSender.ID) -> return
|
||||
else -> {
|
||||
val params = parameters?.toMutableMap() ?: mutableMapOf()
|
||||
params[AnalyticsParam.ACTION] = action.key
|
||||
params[AnalyticsParam.ERROR_CODE] = error.code.toString()
|
||||
params[AnalyticsParam.ERROR_DESCRIPTION] = "${error.javaClass.simpleName}: ${error.customMessage}"
|
||||
params[AnalyticsParam.ERROR_KEY] = "BlockchainSdkError"
|
||||
|
||||
FirebaseCrashlytics.getInstance().apply {
|
||||
params.forEach { setCustomKey(it.key.param, it.value) }
|
||||
recordException(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@ import com.tangem.blockchain.common.WalletManager
|
|||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.core.TangemError
|
||||
import com.tangem.domain.common.ScanResponse
|
||||
import com.tangem.tap.common.analytics.GlobalAnalyticsHandler
|
||||
import com.tangem.tap.common.analytics.GlobalAnalyticsEventHandler
|
||||
import com.tangem.tap.common.entities.FiatCurrency
|
||||
import com.tangem.tap.common.feedback.FeedbackData
|
||||
import com.tangem.tap.common.feedback.FeedbackManager
|
||||
|
|
@ -75,7 +75,7 @@ sealed class GlobalAction : Action {
|
|||
data class SetConfigManager(val configManager: ConfigManager) : GlobalAction()
|
||||
data class SetWarningManager(val warningManager: WarningMessagesManager) : GlobalAction()
|
||||
data class SetFeedbackManager(val feedbackManager: FeedbackManager) : GlobalAction()
|
||||
data class SetGlobalAnalyticsHandler(val analyticsHandler: GlobalAnalyticsHandler) : GlobalAction()
|
||||
data class SetGlobalAnalyticsHandler(val analyticsHandler: GlobalAnalyticsEventHandler) : GlobalAction()
|
||||
|
||||
data class SendEmail(val feedbackData: FeedbackData) : GlobalAction()
|
||||
data class OpenChat(val feedbackData: FeedbackData) : GlobalAction()
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package com.tangem.tap.common.redux.global
|
||||
|
||||
import com.tangem.domain.common.ScanResponse
|
||||
import com.tangem.tap.common.analytics.GlobalAnalyticsHandler
|
||||
import com.tangem.tap.common.analytics.GlobalAnalyticsEventHandler
|
||||
import com.tangem.tap.common.entities.FiatCurrency
|
||||
import com.tangem.tap.common.feedback.FeedbackManager
|
||||
import com.tangem.tap.common.redux.StateDialog
|
||||
|
|
@ -27,7 +27,7 @@ data class GlobalState(
|
|||
val dialog: StateDialog? = null,
|
||||
val exchangeManager: CurrencyExchangeManager = CurrencyExchangeManager.dummy(),
|
||||
val resources: AndroidResources = AndroidResources(),
|
||||
val analyticsHandler: GlobalAnalyticsHandler? = null,
|
||||
val analyticsHandler: GlobalAnalyticsEventHandler? = null,
|
||||
val userCountryCode: String? = null,
|
||||
) : StateType
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import android.content.Intent
|
|||
import com.google.android.gms.wallet.PaymentData
|
||||
import com.shopify.buy3.Storefront
|
||||
import com.tangem.common.extensions.ifNotNull
|
||||
import com.tangem.tap.common.analytics.GlobalAnalyticsHandler
|
||||
import com.tangem.tap.common.analytics.GlobalAnalyticsEventHandler
|
||||
import com.tangem.tap.common.extensions.filterNotNull
|
||||
import com.tangem.tap.common.shop.data.ProductType
|
||||
import com.tangem.tap.common.shop.data.TangemProduct
|
||||
|
|
@ -196,10 +196,10 @@ class TangemShopService(application: Application, shopifyShop: ShopifyShop) {
|
|||
return checkouts[productType]!!.webUrl
|
||||
}
|
||||
|
||||
suspend fun waitForCheckout(productType: ProductType, analyticsHandler: GlobalAnalyticsHandler?) {
|
||||
suspend fun waitForCheckout(productType: ProductType, analyticsHandler: GlobalAnalyticsEventHandler?) {
|
||||
val result = shopifyService.checkout(true, checkouts[productType]!!.id)
|
||||
result.onSuccess {
|
||||
ifNotNull(analyticsHandler, it.order) { handler, order -> handler.logShopifyOrder(order) }
|
||||
ifNotNull(analyticsHandler, it.order) { handler, order -> handler.handleShopifyOrderEvent(order) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ import com.tangem.operations.pins.SetUserCodeCommand
|
|||
import com.tangem.tap.common.analytics.Analytics
|
||||
import com.tangem.tap.common.analytics.AnalyticsEvent
|
||||
import com.tangem.tap.common.analytics.AnalyticsParam
|
||||
import com.tangem.tap.common.analytics.GlobalAnalyticsHandler
|
||||
import com.tangem.tap.common.analytics.GlobalAnalyticsEventHandler
|
||||
import com.tangem.tap.domain.tasks.CreateWalletAndRescanTask
|
||||
import com.tangem.tap.domain.tasks.product.ResetToFactorySettingsTask
|
||||
import com.tangem.tap.domain.tasks.product.ScanProductTask
|
||||
|
|
@ -44,12 +44,12 @@ import kotlin.coroutines.suspendCoroutine
|
|||
class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Context) {
|
||||
|
||||
suspend fun scanProduct(
|
||||
analyticsHandler: GlobalAnalyticsHandler?,
|
||||
analyticsHandler: GlobalAnalyticsEventHandler?,
|
||||
userTokensRepository: UserTokensRepository,
|
||||
additionalBlockchainsToDerive: Collection<Blockchain>? = null,
|
||||
messageRes: Int? = null,
|
||||
): CompletionResult<ScanResponse> {
|
||||
analyticsHandler?.triggerEvent(AnalyticsEvent.READY_TO_SCAN, null)
|
||||
analyticsHandler?.handleAnalyticsEvent(AnalyticsEvent.READY_TO_SCAN, card = null)
|
||||
|
||||
val message = Message(context.getString(messageRes ?: R.string.initial_message_scan_header))
|
||||
return runTaskAsyncReturnOnMain(
|
||||
|
|
@ -69,30 +69,30 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co
|
|||
}
|
||||
|
||||
private fun sendScanResultsToAnalytics(
|
||||
analyticsHandler: GlobalAnalyticsHandler?,
|
||||
analyticsHandler: GlobalAnalyticsEventHandler?,
|
||||
result: CompletionResult<ScanResponse>
|
||||
) {
|
||||
when (result) {
|
||||
is CompletionResult.Success -> {
|
||||
analyticsHandler?.triggerEvent(
|
||||
analyticsHandler?.handleAnalyticsEvent(
|
||||
event = AnalyticsEvent.CARD_IS_SCANNED,
|
||||
card = result.data.card,
|
||||
blockchain = result.data.walletData?.blockchain
|
||||
)
|
||||
if (DemoHelper.isDemoCard(result.data)) {
|
||||
analyticsHandler?.triggerEvent(
|
||||
analyticsHandler?.handleAnalyticsEvent(
|
||||
event = AnalyticsEvent.DEMO_MODE_ACTIVATED,
|
||||
params = mapOf(AnalyticsParam.CARD_ID.param to result.data.card.cardId),
|
||||
card = result.data.card,
|
||||
blockchain = result.data.walletData?.blockchain,
|
||||
params = mapOf(AnalyticsParam.CARD_ID.param to result.data.card.cardId)
|
||||
blockchain = result.data.walletData?.blockchain
|
||||
)
|
||||
}
|
||||
}
|
||||
is CompletionResult.Failure ->
|
||||
(result.error as? TangemSdkError)?.let { error ->
|
||||
analyticsHandler?.logCardSdkError(
|
||||
analyticsHandler?.handleCardSdkErrorEvent(
|
||||
error = error,
|
||||
actionToLog = Analytics.ActionToLog.Scan
|
||||
action = Analytics.ActionToLog.Scan
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,13 +15,13 @@ import com.tangem.network.common.MoshiConverter
|
|||
import com.tangem.operations.wallet.CreateWalletResponse
|
||||
import com.tangem.tap.common.AssetReader
|
||||
import com.tangem.tap.common.analytics.Analytics
|
||||
import com.tangem.tap.common.analytics.GlobalAnalyticsHandler
|
||||
import com.tangem.tap.common.analytics.GlobalAnalyticsEventHandler
|
||||
import com.tangem.tap.tangemSdkManager
|
||||
|
||||
class TwinCardsManager(
|
||||
private val card: Card,
|
||||
assetReader: AssetReader,
|
||||
val analyticsHandler: GlobalAnalyticsHandler?
|
||||
val analyticsHandler: GlobalAnalyticsEventHandler?
|
||||
) {
|
||||
|
||||
private val currentCardId: String = card.cardId
|
||||
|
|
@ -37,7 +37,7 @@ class TwinCardsManager(
|
|||
is CompletionResult.Success -> currentCardPublicKey = response.data.wallet.publicKey.toHexString()
|
||||
is CompletionResult.Failure -> {
|
||||
(response.error as? TangemSdkError)?.let { error ->
|
||||
analyticsHandler?.logCardSdkError(
|
||||
analyticsHandler?.handleCardSdkErrorEvent(
|
||||
error,
|
||||
Analytics.ActionToLog.CreateWallet,
|
||||
card = card
|
||||
|
|
@ -67,7 +67,7 @@ class TwinCardsManager(
|
|||
}
|
||||
is CompletionResult.Failure -> {
|
||||
(response.error as? TangemSdkError)?.let { error ->
|
||||
analyticsHandler?.logCardSdkError(
|
||||
analyticsHandler?.handleCardSdkErrorEvent(
|
||||
error,
|
||||
Analytics.ActionToLog.CreateWallet,
|
||||
card = card
|
||||
|
|
@ -87,7 +87,7 @@ class TwinCardsManager(
|
|||
is CompletionResult.Success -> Result.Success(response.data)
|
||||
is CompletionResult.Failure -> {
|
||||
(response.error as? TangemSdkError)?.let { error ->
|
||||
analyticsHandler?.logCardSdkError(
|
||||
analyticsHandler?.handleCardSdkErrorEvent(
|
||||
error,
|
||||
Analytics.ActionToLog.WriteIssuerData,
|
||||
card = card
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import com.tangem.common.card.EllipticCurve
|
|||
import com.tangem.common.extensions.guard
|
||||
import com.tangem.domain.common.ScanResponse
|
||||
import com.tangem.tap.common.analytics.Analytics
|
||||
import com.tangem.tap.common.analytics.logWcEvent
|
||||
import com.tangem.tap.common.extensions.dispatchOnMain
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectAction
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ import com.tangem.common.extensions.toHexString
|
|||
import com.tangem.crypto.CryptoUtils
|
||||
import com.tangem.operations.sign.SignHashCommand
|
||||
import com.tangem.tap.common.analytics.Analytics
|
||||
import com.tangem.tap.common.extensions.logSendTransactionError
|
||||
import com.tangem.tap.common.extensions.safeUpdate
|
||||
import com.tangem.tap.common.extensions.toFormattedString
|
||||
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectSession
|
||||
|
|
@ -144,7 +143,7 @@ class WalletConnectSdkHelper {
|
|||
HEX_PREFIX + data.walletManager.wallet.recentTransactions.last().hash
|
||||
}
|
||||
is SimpleResult.Failure -> {
|
||||
store.state.globalState.analyticsHandler?.logSendTransactionError(
|
||||
store.state.globalState.analyticsHandler?.handleBlockchainSdkErrorEvent(
|
||||
result.error,
|
||||
Analytics.ActionToLog.WalletConnectTransaction,
|
||||
)
|
||||
|
|
@ -174,7 +173,7 @@ class WalletConnectSdkHelper {
|
|||
}
|
||||
is CompletionResult.Failure -> {
|
||||
(result.error as? TangemSdkError)?.let { error ->
|
||||
store.state.globalState.analyticsHandler?.logCardSdkError(
|
||||
store.state.globalState.analyticsHandler?.handleCardSdkErrorEvent(
|
||||
error,
|
||||
Analytics.ActionToLog.WalletConnectSign,
|
||||
)
|
||||
|
|
@ -203,7 +202,7 @@ class WalletConnectSdkHelper {
|
|||
}
|
||||
is CompletionResult.Failure -> {
|
||||
(result.error as? TangemSdkError)?.let { error ->
|
||||
store.state.globalState.analyticsHandler?.logCardSdkError(
|
||||
store.state.globalState.analyticsHandler?.handleCardSdkErrorEvent(
|
||||
error,
|
||||
Analytics.ActionToLog.WalletConnectTransaction,
|
||||
)
|
||||
|
|
@ -279,7 +278,7 @@ class WalletConnectSdkHelper {
|
|||
}
|
||||
is CompletionResult.Failure -> {
|
||||
(result.error as? TangemSdkError)?.let { error ->
|
||||
store.state.globalState.analyticsHandler?.logCardSdkError(
|
||||
store.state.globalState.analyticsHandler?.handleCardSdkErrorEvent(
|
||||
error,
|
||||
Analytics.ActionToLog.WalletConnectSign,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ class DetailsMiddleware {
|
|||
}
|
||||
is CompletionResult.Failure -> {
|
||||
(result.error as? TangemSdkError)?.let { error ->
|
||||
store.state.globalState.analyticsHandler?.logCardSdkError(
|
||||
store.state.globalState.analyticsHandler?.handleCardSdkErrorEvent(
|
||||
error,
|
||||
Analytics.ActionToLog.PurgeWallet,
|
||||
card = store.state.detailsState.scanResponse?.card,
|
||||
|
|
@ -159,10 +159,10 @@ class DetailsMiddleware {
|
|||
}
|
||||
is CompletionResult.Failure -> {
|
||||
(result.error as? TangemSdkError)?.let { error ->
|
||||
store.state.globalState.analyticsHandler?.logCardSdkError(
|
||||
store.state.globalState.analyticsHandler?.handleCardSdkErrorEvent(
|
||||
error = error,
|
||||
actionToLog = Analytics.ActionToLog.ChangeSecOptions,
|
||||
parameters = mapOf(
|
||||
action = Analytics.ActionToLog.ChangeSecOptions,
|
||||
params = mapOf(
|
||||
AnalyticsParam.NEW_SECURITY_OPTION to
|
||||
(selectedOption?.name ?: ""),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ private val homeMiddleware: Middleware<AppState> = { _, _ ->
|
|||
store.dispatchOpenUrl(BUY_WALLET_URL)
|
||||
else -> store.dispatch(NavigationAction.NavigateTo(AppScreen.Shop))
|
||||
}
|
||||
store.state.globalState.analyticsHandler?.triggerEvent(
|
||||
store.state.globalState.analyticsHandler?.handleAnalyticsEvent(
|
||||
event = AnalyticsEvent.GET_CARD,
|
||||
params = mapOf(AnalyticsParam.SOURCE.param to GetCardSourceParams.WELCOME.param)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ import com.tangem.tap.common.analytics.AnalyticsParam
|
|||
import com.tangem.tap.common.extensions.dispatchDialogShow
|
||||
import com.tangem.tap.common.extensions.dispatchErrorNotification
|
||||
import com.tangem.tap.common.extensions.dispatchOnMain
|
||||
import com.tangem.tap.common.extensions.logSendTransactionError
|
||||
import com.tangem.tap.common.extensions.safeUpdate
|
||||
import com.tangem.tap.common.extensions.stripZeroPlainString
|
||||
import com.tangem.tap.common.redux.AppDialog
|
||||
|
|
@ -222,7 +221,7 @@ private fun sendTransaction(
|
|||
|
||||
when (sendResult) {
|
||||
is SimpleResult.Success -> {
|
||||
store.state.globalState.analyticsHandler?.triggerEvent(
|
||||
store.state.globalState.analyticsHandler?.handleAnalyticsEvent(
|
||||
event = AnalyticsEvent.TRANSACTION_IS_SENT,
|
||||
card = card,
|
||||
blockchain = walletManager.wallet.blockchain.currency,
|
||||
|
|
@ -252,10 +251,10 @@ private fun sendTransaction(
|
|||
feeAmount = feeAmount,
|
||||
destinationAddress = destinationAddress,
|
||||
)
|
||||
store.state.globalState.analyticsHandler?.logSendTransactionError(
|
||||
store.state.globalState.analyticsHandler?.handleBlockchainSdkErrorEvent(
|
||||
error = sendResult.error,
|
||||
action = Analytics.ActionToLog.SendTransaction,
|
||||
parameters = mapOf(AnalyticsParam.BLOCKCHAIN to walletManager.wallet.blockchain.currency),
|
||||
params = mapOf(AnalyticsParam.BLOCKCHAIN to walletManager.wallet.blockchain.currency),
|
||||
card = card,
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -174,7 +174,7 @@ class WalletMiddleware {
|
|||
}
|
||||
is CompletionResult.Failure -> {
|
||||
(result.error as? TangemSdkError)?.let { error ->
|
||||
store.state.globalState.analyticsHandler?.logCardSdkError(
|
||||
store.state.globalState.analyticsHandler?.handleCardSdkErrorEvent(
|
||||
error,
|
||||
Analytics.ActionToLog.CreateWallet,
|
||||
card = store.state.detailsState.scanResponse?.card
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ class WarningsMiddleware {
|
|||
preferencesStorage.appRatingLaunchObserver.foundWalletWithFunds()
|
||||
}
|
||||
if (preferencesStorage.appRatingLaunchObserver.isReadyToShow()) {
|
||||
store.state.globalState.analyticsHandler?.triggerEvent(AnalyticsEvent.APP_RATING_DISPLAYED)
|
||||
store.state.globalState.analyticsHandler?.handleAnalyticsEvent(AnalyticsEvent.APP_RATING_DISPLAYED)
|
||||
addWarningMessage(WarningMessagesManager.appRatingWarning(), true)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -109,12 +109,12 @@ class WarningMessageVH(val binding: LayoutWarningCardActionBinding) : RecyclerVi
|
|||
binding.btnClose.show()
|
||||
val analyticsHandler = store.state.globalState.analyticsHandler
|
||||
binding.btnClose.setOnClickListener {
|
||||
analyticsHandler?.triggerEvent(AnalyticsEvent.APP_RATING_DISMISS)
|
||||
analyticsHandler?.handleAnalyticsEvent(AnalyticsEvent.APP_RATING_DISMISS)
|
||||
store.dispatch(GlobalAction.HideWarningMessage(warning))
|
||||
store.dispatch(WalletAction.Warnings.AppRating.RemindLater)
|
||||
}
|
||||
binding.btnCanBeBetter.setOnClickListener {
|
||||
analyticsHandler?.triggerEvent(AnalyticsEvent.APP_RATING_NEGATIVE)
|
||||
analyticsHandler?.handleAnalyticsEvent(AnalyticsEvent.APP_RATING_NEGATIVE)
|
||||
store.dispatch(WalletAction.Warnings.AppRating.SetNeverToShow)
|
||||
store.dispatch(GlobalAction.HideWarningMessage(warning))
|
||||
store.dispatch(GlobalAction.SendEmail(RateCanBeBetterEmail()))
|
||||
|
|
@ -122,7 +122,7 @@ class WarningMessageVH(val binding: LayoutWarningCardActionBinding) : RecyclerVi
|
|||
binding.btnReallyCool.setOnClickListener {
|
||||
val activity = binding.root.context.getActivity() ?: return@setOnClickListener
|
||||
|
||||
analyticsHandler?.triggerEvent(AnalyticsEvent.APP_RATING_POSITIVE)
|
||||
analyticsHandler?.handleAnalyticsEvent(AnalyticsEvent.APP_RATING_POSITIVE)
|
||||
store.dispatch(WalletAction.Warnings.AppRating.SetNeverToShow)
|
||||
val reviewManager = ReviewManagerFactory.create(activity)
|
||||
val task = reviewManager.requestReviewFlow()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue