diff --git a/app/build.gradle b/app/build.gradle index 1ba0960f0b..d517123715 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -122,9 +122,8 @@ dependencies { // Firebase implementation platform('com.google.firebase:firebase-bom:26.0.0') - implementation 'com.google.firebase:firebase-crashlytics' - implementation 'com.google.firebase:firebase-config-ktx' implementation 'com.google.firebase:firebase-analytics-ktx' + implementation 'com.google.firebase:firebase-crashlytics-ktx' // Analytics implementation 'com.appsflyer:af-android-sdk:6.5.1' diff --git a/app/src/main/java/com/tangem/tap/TapApplication.kt b/app/src/main/java/com/tangem/tap/TapApplication.kt index 22165f40d0..8a15017fe3 100644 --- a/app/src/main/java/com/tangem/tap/TapApplication.kt +++ b/app/src/main/java/com/tangem/tap/TapApplication.kt @@ -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) { diff --git a/app/src/main/java/com/tangem/tap/common/analytics/AmplitudeAnalyticsHandler.kt b/app/src/main/java/com/tangem/tap/common/analytics/AmplitudeAnalyticsHandler.kt deleted file mode 100644 index b68a9a3eb5..0000000000 --- a/app/src/main/java/com/tangem/tap/common/analytics/AmplitudeAnalyticsHandler.kt +++ /dev/null @@ -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 - ) { - client.logEvent(event.event, prepareParams(card, blockchain, params).toJson()) - } - - override fun triggerEvent(event: String, params: Map) { - client.logEvent(event, params.toJson()) - } - - override fun logCardSdkError( - error: TangemSdkError, - actionToLog: Analytics.ActionToLog, - parameters: Map?, - card: Card? - ) { - //TODO - } - - override fun logError(error: Throwable, params: Map) { - //TODO - } - - override fun getOrderEvent(): String { - //TODO - return "" - } - - override fun getOrderParams(order: Storefront.Order): Map { - //TODO - return emptyMap() - } - - private fun Map.toJson(): JSONObject { - val json = JSONObject() - this.map { json.put(it.key, it.value) } - return json - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/analytics/AnalyticsEventHandler.kt b/app/src/main/java/com/tangem/tap/common/analytics/AnalyticsEventHandler.kt new file mode 100644 index 0000000000..d973b4fa2c --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/analytics/AnalyticsEventHandler.kt @@ -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 = emptyMap(), + ) +} + +interface AnalyticsEventHandler : EventHandler { + fun handleAnalyticsEvent( + event: AnalyticsEvent, + params: Map = emptyMap(), + card: Card? = null, + blockchain: String? = null, + ) + + fun prepareParams( + card: Card?, + blockchain: String? = null, + params: Map = emptyMap(), + ): Map { + 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 = emptyMap(), + ) +} + +interface SdkErrorEventHandler : CardSdkErrorEventHandler, BlockchainSdkErrorEventHandler + +interface CardSdkErrorEventHandler { + fun handleCardSdkErrorEvent( + error: TangemSdkError, + action: Analytics.ActionToLog, + params: Map = emptyMap(), + card: Card? = null, + ) +} + +interface BlockchainSdkErrorEventHandler { + fun handleBlockchainSdkErrorEvent( + error: BlockchainError, + action: Analytics.ActionToLog, + params: Map = mapOf(), + card: Card? = null, + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/analytics/AnalyticsEventHandlerBuilder.kt b/app/src/main/java/com/tangem/tap/common/analytics/AnalyticsEventHandlerBuilder.kt new file mode 100644 index 0000000000..e5a2ec3283 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/analytics/AnalyticsEventHandlerBuilder.kt @@ -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() + + 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)) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/analytics/AnalyticsHandler.kt b/app/src/main/java/com/tangem/tap/common/analytics/AnalyticsHandler.kt deleted file mode 100644 index 5386779df4..0000000000 --- a/app/src/main/java/com/tangem/tap/common/analytics/AnalyticsHandler.kt +++ /dev/null @@ -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 = emptyMap() - ) - - abstract fun triggerEvent( - event: String, - params: Map - ) - - abstract fun logCardSdkError( - error: TangemSdkError, - actionToLog: Analytics.ActionToLog, - parameters: Map? = null, - card: Card? = null - ) - - abstract fun logError( - error: Throwable, - params: Map = emptyMap() - ) - - protected fun prepareParams( - card: Card?, - blockchain: String? = null, - params: Map = emptyMap() - ): Map { - 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 -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/analytics/AppsFlyerAnalyticsHandler.kt b/app/src/main/java/com/tangem/tap/common/analytics/AppsFlyerAnalyticsHandler.kt deleted file mode 100644 index 3ca690a971..0000000000 --- a/app/src/main/java/com/tangem/tap/common/analytics/AppsFlyerAnalyticsHandler.kt +++ /dev/null @@ -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 - ) { - AppsFlyerLib.getInstance().logEvent( - context, - event.event, - prepareParams(card, blockchain, params) - ) - } - - override fun logCardSdkError( - error: TangemSdkError, - actionToLog: Analytics.ActionToLog, - parameters: Map?, - card: Card? - ) { - //TODO - } - - override fun logError(error: Throwable, params: Map) { - //TODO - } - - override fun getOrderEvent(): String = AFInAppEventType.PURCHASE - - override fun getOrderParams(order: Storefront.Order): Map { - - 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) { - AppsFlyerLib.getInstance().logEvent(context, event, params) - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/analytics/FirebaseAnalyticsHandler.kt b/app/src/main/java/com/tangem/tap/common/analytics/FirebaseAnalyticsHandler.kt deleted file mode 100644 index e691c2239f..0000000000 --- a/app/src/main/java/com/tangem/tap/common/analytics/FirebaseAnalyticsHandler.kt +++ /dev/null @@ -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 - ) { - 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.toBundle(): Bundle { - return bundleOf(*this.toList().toTypedArray()) - } - - override fun logCardSdkError( - error: TangemSdkError, - actionToLog: Analytics.ActionToLog, - parameters: Map?, - 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) { - 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 { - - 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) { - Firebase.analytics.logEvent(event, params.toBundle()) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/analytics/GlobalAnalyticsHandler.kt b/app/src/main/java/com/tangem/tap/common/analytics/GlobalAnalyticsHandler.kt index 83b77c56e8..cd28857ae7 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/GlobalAnalyticsHandler.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/GlobalAnalyticsHandler.kt @@ -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() { - override fun triggerEvent( +interface GlobalAnalyticsEventHandler : AnalyticsEventHandler, + ShopifyOrderEventHandler, + ErrorEventHandler, + SdkErrorEventHandler + +class GlobalAnalyticsHandler( + private val analyticsHandlers: List, +) : GlobalAnalyticsEventHandler { + + override fun handleEvent(event: String, params: Map) { + analyticsHandlers.forEach { it.handleEvent(event, params) } + } + + override fun handleAnalyticsEvent( event: AnalyticsEvent, + params: Map, card: Card?, blockchain: String?, - params: Map ) { - analyticsHandlers.forEach { it.triggerEvent(event, card, blockchain, params) } + analyticsHandlers.forEach { it.handleAnalyticsEvent(event, params, card, blockchain) } } - override fun triggerEvent(event: String, params: Map) { - analyticsHandlers.forEach { it.triggerEvent(event, params) } + override fun handleShopifyOrderEvent(order: Storefront.Order) { + analyticsHandlers.filterIsInstance().forEach { + it.handleShopifyOrderEvent(order) + } } - override fun logCardSdkError( + override fun handleErrorEvent(error: Throwable, params: Map) { + analyticsHandlers.filterIsInstance().forEach { + it.handleErrorEvent(error, params) + } + } + + override fun handleCardSdkErrorEvent( error: TangemSdkError, - actionToLog: Analytics.ActionToLog, - parameters: Map?, - card: Card? + action: Analytics.ActionToLog, + params: Map, + card: Card?, ) { - analyticsHandlers.forEach { it.logCardSdkError(error, actionToLog, parameters, card) } + analyticsHandlers.filterIsInstance().forEach { + it.handleCardSdkErrorEvent(error, action, params, card) + } } - override fun logError(error: Throwable, params: Map) { - analyticsHandlers.forEach { it.logError(error, params) } + override fun handleBlockchainSdkErrorEvent( + error: BlockchainError, + action: Analytics.ActionToLog, + params: Map, + card: Card?, + ) { + analyticsHandlers.filterIsInstance().forEach { + it.handleBlockchainSdkErrorEvent(error, action, params, card) + } } +} - override fun getOrderEvent(): String { - return "" - } - - override fun getOrderParams(order: Storefront.Order): Map { - 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(), + ) } } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/analytics/handlers/amplitude/AmplitudeAnalyticsHandler.kt b/app/src/main/java/com/tangem/tap/common/analytics/handlers/amplitude/AmplitudeAnalyticsHandler.kt new file mode 100644 index 0000000000..22baff0a2f --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/analytics/handlers/amplitude/AmplitudeAnalyticsHandler.kt @@ -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) { + client.logEvent(event, ParamsJSONObjectConverter().convert(params)) + } + + override fun handleAnalyticsEvent( + event: AnalyticsEvent, + params: Map, + card: Card?, + blockchain: String?, + ) { + handleEvent(event.event, prepareParams(card, blockchain, params)) + } + + class ParamsJSONObjectConverter : Converter, JSONObject> { + override fun convert(value: Map): JSONObject = JSONObject().apply { + value.forEach { this.put(it.key, it.value) } + } + } +} + diff --git a/app/src/main/java/com/tangem/tap/common/analytics/handlers/appsFlyer/AppsFlyerAnalyticsHandler.kt b/app/src/main/java/com/tangem/tap/common/analytics/handlers/appsFlyer/AppsFlyerAnalyticsHandler.kt new file mode 100644 index 0000000000..8b14fc2eba --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/analytics/handlers/appsFlyer/AppsFlyerAnalyticsHandler.kt @@ -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) { + appsFlyerLib.logEvent(context, event, params) + } + + override fun handleAnalyticsEvent( + event: AnalyticsEvent, + params: Map, + 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> { + override fun convert(value: Storefront.Order): Map { + 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 + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/analytics/handlers/firebase/FirebaseAnalyticsHandler.kt b/app/src/main/java/com/tangem/tap/common/analytics/handlers/firebase/FirebaseAnalyticsHandler.kt new file mode 100644 index 0000000000..b2be460eb5 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/analytics/handlers/firebase/FirebaseAnalyticsHandler.kt @@ -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) { + fbAnalytics.logEvent(event, params.toBundle()) + } + + override fun handleAnalyticsEvent( + event: AnalyticsEvent, + params: Map, + 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) { + params.forEach { (key, value) -> fbCrashlytics.setCustomKey(key, value) } + fbCrashlytics.recordException(error) + } + + override fun handleCardSdkErrorEvent( + error: TangemSdkError, + action: Analytics.ActionToLog, + params: Map, + 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, + 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.toBundle(): Bundle { + return bundleOf(*this.toList().toTypedArray()) + } + + companion object { + const val ORDER_EVENT = FirebaseAnalytics.Event.PURCHASE + } + + class OrderToParamsConverter : Converter> { + override fun convert(value: Storefront.Order): Map { + 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 + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/extensions/AnalyticsHandler.kt b/app/src/main/java/com/tangem/tap/common/extensions/AnalyticsHandler.kt deleted file mode 100644 index f2897e2b63..0000000000 --- a/app/src/main/java/com/tangem/tap/common/extensions/AnalyticsHandler.kt +++ /dev/null @@ -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? = 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) - } - } - } - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalAction.kt b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalAction.kt index 4e441f768e..8c50713103 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalAction.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalAction.kt @@ -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() diff --git a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalState.kt b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalState.kt index 17c8ed9f76..55b8d535b3 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalState.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalState.kt @@ -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 diff --git a/app/src/main/java/com/tangem/tap/common/shop/TangemShopService.kt b/app/src/main/java/com/tangem/tap/common/shop/TangemShopService.kt index 6151af3761..c8bd0a5405 100644 --- a/app/src/main/java/com/tangem/tap/common/shop/TangemShopService.kt +++ b/app/src/main/java/com/tangem/tap/common/shop/TangemShopService.kt @@ -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) } } } diff --git a/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt b/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt index 43e318bd82..b4a63f3277 100644 --- a/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt @@ -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? = null, messageRes: Int? = null, ): CompletionResult { - 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 ) { 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 ) } } diff --git a/app/src/main/java/com/tangem/tap/domain/twins/TwinCardsManager.kt b/app/src/main/java/com/tangem/tap/domain/twins/TwinCardsManager.kt index d4313cf946..9d7353fb5f 100644 --- a/app/src/main/java/com/tangem/tap/domain/twins/TwinCardsManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/twins/TwinCardsManager.kt @@ -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 diff --git a/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectManager.kt b/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectManager.kt index 305f4ec978..8bea1d2aeb 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectManager.kt @@ -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 diff --git a/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectSdkHelper.kt b/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectSdkHelper.kt index 78db9b27fc..482cf3f42b 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectSdkHelper.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectSdkHelper.kt @@ -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, ) diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt index 30eebe686a..daf25b5425 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt @@ -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 ?: ""), ), diff --git a/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt b/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt index ceb36bc407..e33abf03e4 100644 --- a/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt @@ -62,7 +62,7 @@ private val homeMiddleware: Middleware = { _, _ -> 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) ) diff --git a/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/SendMiddleware.kt b/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/SendMiddleware.kt index 8a3871a455..4e57c0ea39 100644 --- a/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/SendMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/send/redux/middlewares/SendMiddleware.kt @@ -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, ) diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt index 71506a46da..2825983575 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt @@ -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 diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WarningsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WarningsMiddleware.kt index 52c93db66e..528d4a0f43 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WarningsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WarningsMiddleware.kt @@ -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) } } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/adapters/WarningMessagesAdapter.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/adapters/WarningMessagesAdapter.kt index 14cd39d812..4a5e240442 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/adapters/WarningMessagesAdapter.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/adapters/WarningMessagesAdapter.kt @@ -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() diff --git a/common/src/main/java/com/tangem/common/Converter.kt b/common/src/main/java/com/tangem/common/Converter.kt new file mode 100644 index 0000000000..699f548ac3 --- /dev/null +++ b/common/src/main/java/com/tangem/common/Converter.kt @@ -0,0 +1,8 @@ +package com.tangem.common + +/** +[REDACTED_AUTHOR] + */ +interface Converter { + fun convert(value: I): O +} \ No newline at end of file diff --git a/domain/src/main/java/com/tangem/domain/common/LogConfig.kt b/domain/src/main/java/com/tangem/domain/common/LogConfig.kt index 56c2950141..0325c6910d 100644 --- a/domain/src/main/java/com/tangem/domain/common/LogConfig.kt +++ b/domain/src/main/java/com/tangem/domain/common/LogConfig.kt @@ -7,6 +7,7 @@ object LogConfig { val storeAction: Boolean = BuildConfig.DEBUG val zendesk: Boolean = false val network: NetworkLogConfig = NetworkLogConfig + val analyticsHandlers: AnalyticsHandlersLogConfig = AnalyticsHandlersLogConfig } object NetworkLogConfig { @@ -14,4 +15,10 @@ object NetworkLogConfig { val moonPayService: Boolean = false val tangemTechService: Boolean = BuildConfig.DEBUG val blockchainSdkNetwork: Boolean = BuildConfig.DEBUG +} + +object AnalyticsHandlersLogConfig { + val firebase: Boolean = false + val appsFlyer: Boolean = false + val amplitude: Boolean = false } \ No newline at end of file