From 5899667c14e5310a7445d5394d54de6d1059c2ab Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 27 Oct 2022 18:36:42 +0500 Subject: [PATCH 01/47] Updated on 2026-08-14 --- .../java/com/tangem/tap/TapApplication.kt | 20 ++++- ...GlobalAnalyticsHandler.kt => Analytics.kt} | 87 +++++++------------ .../analytics/AnalyticsHandlersFactory.kt | 23 +++++ .../common/analytics/AnalyticsInterfaces.kt | 3 - .../analytics/GlobalAnalyticsEventHandler.kt | 18 ++++ .../GlobalAnalyticsEventHandlerBuilder.kt | 79 ----------------- .../common/analytics/api/EventHandlerApi.kt | 41 +++++---- .../amplitude/AmplitudeAnalyticsHandler.kt | 17 +++- .../handlers/amplitude/AmplitudeLogClient.kt | 5 +- .../appsFlyer/AppsFlyerAnalyticsHandler.kt | 18 +++- .../handlers/appsFlyer/AppsFlyerLogClient.kt | 5 +- .../firebase/FirebaseAnalyticsHandler.kt | 31 +++++-- .../handlers/firebase/FirebaseLogClient.kt | 5 +- .../tap/common/redux/global/GlobalState.kt | 4 +- .../tap/common/shop/TangemShopService.kt | 2 +- .../com/tangem/tap/domain/TangemSdkManager.kt | 2 +- .../tap/domain/twins/TwinCardsManager.kt | 6 +- .../walletconnect/WalletConnectSdkHelper.kt | 8 +- .../details/redux/DetailsMiddleware.kt | 4 +- .../redux/OnboardingSaltPayMiddleware.kt | 16 ++-- .../send/redux/middlewares/SendMiddleware.kt | 2 +- .../redux/middlewares/WalletMiddleware.kt | 2 +- 22 files changed, 204 insertions(+), 194 deletions(-) rename app/src/main/java/com/tangem/tap/common/analytics/{GlobalAnalyticsHandler.kt => Analytics.kt} (60%) create mode 100644 app/src/main/java/com/tangem/tap/common/analytics/AnalyticsHandlersFactory.kt delete mode 100644 app/src/main/java/com/tangem/tap/common/analytics/AnalyticsInterfaces.kt create mode 100644 app/src/main/java/com/tangem/tap/common/analytics/GlobalAnalyticsEventHandler.kt delete mode 100644 app/src/main/java/com/tangem/tap/common/analytics/GlobalAnalyticsEventHandlerBuilder.kt diff --git a/app/src/main/java/com/tangem/tap/TapApplication.kt b/app/src/main/java/com/tangem/tap/TapApplication.kt index c0d6e566b4..1913ac6e16 100644 --- a/app/src/main/java/com/tangem/tap/TapApplication.kt +++ b/app/src/main/java/com/tangem/tap/TapApplication.kt @@ -14,7 +14,12 @@ 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.GlobalAnalyticsEventHandlerBuilder +import com.tangem.tap.common.analytics.Analytics +import com.tangem.tap.common.analytics.AnalyticsHandlersFactory +import com.tangem.tap.common.analytics.api.AnalyticsHandlerBuilder +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.common.feedback.AdditionalFeedbackInfo import com.tangem.tap.common.feedback.FeedbackManager import com.tangem.tap.common.images.createCoilImageLoader @@ -102,14 +107,21 @@ class TapApplication : Application(), ImageLoaderFactory { } private fun initAnalytics(application: Application, config: Config) { - val globalAnalyticsHandler = GlobalAnalyticsEventHandlerBuilder( + val factory = AnalyticsHandlersFactory() + factory.addBuilder(AmplitudeAnalyticsHandler.Builder()) + factory.addBuilder(AppsFlyerAnalyticsHandler.Builder()) + factory.addBuilder(FirebaseAnalyticsHandler.Builder()) + + val buildData = AnalyticsHandlerBuilder.Data( application = application, config = config, isDebug = BuildConfig.DEBUG, logConfig = LogConfig.analyticsHandlers, jsonConverter = MoshiJsonConverter.INSTANCE, - ).default() - store.dispatch(GlobalAction.SetGlobalAnalyticsHandler(globalAnalyticsHandler)) + ) + factory.build(buildData).forEach { + Analytics.addHandler(it.id(), it) + } } private fun initFeedbackManager(context: Context, preferencesStorage: PreferencesStorage, config: Config) { diff --git a/app/src/main/java/com/tangem/tap/common/analytics/GlobalAnalyticsHandler.kt b/app/src/main/java/com/tangem/tap/common/analytics/Analytics.kt similarity index 60% rename from app/src/main/java/com/tangem/tap/common/analytics/GlobalAnalyticsHandler.kt rename to app/src/main/java/com/tangem/tap/common/analytics/Analytics.kt index d1bef7d01b..9eaee82a3a 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/GlobalAnalyticsHandler.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/Analytics.kt @@ -7,68 +7,43 @@ import com.tangem.common.core.TangemSdkError import com.tangem.tap.common.analytics.api.AnalyticsEventHandler import com.tangem.tap.common.analytics.api.BlockchainSdkErrorEventHandler import com.tangem.tap.common.analytics.api.CardSdkErrorEventHandler -import com.tangem.tap.common.analytics.api.ErrorEventHandler import com.tangem.tap.common.analytics.api.ErrorEventLogger -import com.tangem.tap.common.analytics.api.SdkErrorEventHandler import com.tangem.tap.common.analytics.api.ShopifyOrderEventHandler import com.tangem.tap.common.analytics.events.AnalyticsEvent import com.tangem.tap.common.extensions.filterNotNull -interface GlobalAnalyticsEventHandler : AnalyticsEventHandler, - ErrorEventHandler, - SdkErrorEventHandler, - ShopifyOrderEventHandler { +/** +[REDACTED_AUTHOR] + */ +object Analytics : GlobalAnalyticsEventHandler { - fun attachToAllEvents(key: String, value: String) + private val handlers = mutableMapOf() - companion object { - fun stub(): GlobalAnalyticsEventHandler { - return object : GlobalAnalyticsEventHandler { - override fun attachToAllEvents(key: String, value: String) {} - override fun handleEvent(event: String, params: Map) {} - override fun handleErrorEvent(error: Throwable, params: Map) {} - override fun handleCardSdkErrorEvent( - error: TangemSdkError, - action: AnalyticsAnOld.ActionToLog, - params: Map, - card: Card?, - ) { - } - - override fun handleBlockchainSdkErrorEvent( - error: BlockchainError, - action: AnalyticsAnOld.ActionToLog, - params: Map, - card: Card?, - ) { - } - - override fun handleShopifyOrderEvent(order: Storefront.Order) {} - } - } - } -} - -class GlobalAnalyticsHandler( - private val analyticsHandlers: List, -) : GlobalAnalyticsEventHandler { + private val analyticsHandlers: List + get() = handlers.values.toList() private val attachToAllEventsParams: MutableMap = mutableMapOf() + override fun id(): String = analyticsHandlers.joinToString(", ") { it.id() } + + override fun addHandler(name: String, handler: AnalyticsEventHandler) { + handlers[name] = handler + } + + override fun removeHandler(name: String): AnalyticsEventHandler? { + return handlers.remove(name) + } + override fun attachToAllEvents(key: String, value: String) { attachToAllEventsParams[key] = value } - override fun handleEvent(event: String, params: Map) { - analyticsHandlers.forEach { it.handleEvent(event, params) } + override fun send(event: String, params: Map) { + analyticsHandlers.forEach { it.send(event, params) } } - override fun handleAnalyticsEvent( - event: AnalyticsEvent, - card: Card?, - blockchain: String?, - ) { - analyticsHandlers.forEach { it.handleAnalyticsEvent(event, card, blockchain) } + override fun send(event: AnalyticsEvent, card: Card?, blockchain: String?) { + analyticsHandlers.forEach { it.send(event, card, blockchain) } } override fun handleAnalyticsEvent( @@ -77,40 +52,42 @@ class GlobalAnalyticsHandler( card: Card?, blockchain: String?, ) { - analyticsHandlers.forEach { it.handleAnalyticsEvent(event, params, card, blockchain) } + analyticsHandlers.forEach { + it.handleAnalyticsEvent(event, params, card, blockchain) + } } - override fun handleErrorEvent(error: Throwable, params: Map) { + override fun send(error: Throwable, params: Map) { analyticsHandlers.filterIsInstance().forEach { it.logErrorEvent(error, params) } } - override fun handleCardSdkErrorEvent( + override fun send( error: TangemSdkError, action: AnalyticsAnOld.ActionToLog, params: Map, card: Card?, ) { analyticsHandlers.filterIsInstance().forEach { - it.handleCardSdkErrorEvent(error, action, params, card) + it.send(error, action, params, card) } } - override fun handleBlockchainSdkErrorEvent( + override fun send( error: BlockchainError, action: AnalyticsAnOld.ActionToLog, params: Map, card: Card?, ) { analyticsHandlers.filterIsInstance().forEach { - it.handleBlockchainSdkErrorEvent(error, action, params, card) + it.send(error, action, params, card) } } - override fun handleShopifyOrderEvent(order: Storefront.Order) { + override fun send(order: Storefront.Order) { analyticsHandlers.filterIsInstance().forEach { - it.handleShopifyOrderEvent(order) + it.send(order) } } @@ -136,7 +113,7 @@ fun GlobalAnalyticsEventHandler.logWcEvent(event: AnalyticsAnOld.WcAnalyticsEven AnalyticsParamAnOld.WALLET_CONNECT_ACTION.param to event.action?.name, AnalyticsParamAnOld.ERROR_DESCRIPTION.param to event.error.message, ).filterNotNull() - handleErrorEvent(event.error, params) + send(event.error, params) } is AnalyticsAnOld.WcAnalyticsEvent.InvalidRequest -> handleAnalyticsEvent( diff --git a/app/src/main/java/com/tangem/tap/common/analytics/AnalyticsHandlersFactory.kt b/app/src/main/java/com/tangem/tap/common/analytics/AnalyticsHandlersFactory.kt new file mode 100644 index 0000000000..a287f6fac2 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/analytics/AnalyticsHandlersFactory.kt @@ -0,0 +1,23 @@ +package com.tangem.tap.common.analytics + +import com.tangem.tap.common.analytics.api.AnalyticsEventHandler +import com.tangem.tap.common.analytics.api.AnalyticsHandlerBuilder + +/** +[REDACTED_AUTHOR] + */ +class AnalyticsHandlersFactory { + + private val builders = mutableListOf() + + fun addBuilder(builder: AnalyticsHandlerBuilder) { + builders.add(builder) + } + + fun build(data: AnalyticsHandlerBuilder.Data): List { + val handlers = builders.mapNotNull { it.build(data) } + builders.clear() + + return handlers + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/analytics/AnalyticsInterfaces.kt b/app/src/main/java/com/tangem/tap/common/analytics/AnalyticsInterfaces.kt deleted file mode 100644 index 6fd6fc7dc8..0000000000 --- a/app/src/main/java/com/tangem/tap/common/analytics/AnalyticsInterfaces.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.tangem.tap.common.analytics - - diff --git a/app/src/main/java/com/tangem/tap/common/analytics/GlobalAnalyticsEventHandler.kt b/app/src/main/java/com/tangem/tap/common/analytics/GlobalAnalyticsEventHandler.kt new file mode 100644 index 0000000000..139ffa5582 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/analytics/GlobalAnalyticsEventHandler.kt @@ -0,0 +1,18 @@ +package com.tangem.tap.common.analytics + +import com.tangem.tap.common.analytics.api.AnalyticsEventHandler +import com.tangem.tap.common.analytics.api.ErrorEventHandler +import com.tangem.tap.common.analytics.api.SdkErrorEventHandler +import com.tangem.tap.common.analytics.api.ShopifyOrderEventHandler + +interface GlobalAnalyticsEventHandler : AnalyticsEventHandler, + ErrorEventHandler, + SdkErrorEventHandler, + ShopifyOrderEventHandler { + + fun addHandler(name: String, handler: AnalyticsEventHandler) + + fun removeHandler(name: String): AnalyticsEventHandler? + + fun attachToAllEvents(key: String, value: String) +} diff --git a/app/src/main/java/com/tangem/tap/common/analytics/GlobalAnalyticsEventHandlerBuilder.kt b/app/src/main/java/com/tangem/tap/common/analytics/GlobalAnalyticsEventHandlerBuilder.kt deleted file mode 100644 index 8e2b439e08..0000000000 --- a/app/src/main/java/com/tangem/tap/common/analytics/GlobalAnalyticsEventHandlerBuilder.kt +++ /dev/null @@ -1,79 +0,0 @@ -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.api.AnalyticsEventHandler -import com.tangem.tap.common.analytics.handlers.amplitude.AmplitudeAnalyticsHandler -import com.tangem.tap.common.analytics.handlers.amplitude.AmplitudeClient -import com.tangem.tap.common.analytics.handlers.amplitude.AmplitudeLogClient -import com.tangem.tap.common.analytics.handlers.appsFlyer.AppsFlyerAnalyticsHandler -import com.tangem.tap.common.analytics.handlers.appsFlyer.AppsFlyerClient -import com.tangem.tap.common.analytics.handlers.appsFlyer.AppsFlyerLogClient -import com.tangem.tap.common.analytics.handlers.firebase.FirebaseAnalyticsHandler -import com.tangem.tap.common.analytics.handlers.firebase.FirebaseClient -import com.tangem.tap.common.analytics.handlers.firebase.FirebaseLogClient -import com.tangem.tap.domain.configurable.config.Config - -/** -[REDACTED_AUTHOR] - */ -class GlobalAnalyticsEventHandlerBuilder( - val application: Application, - val config: Config, - val isDebug: Boolean, - val logConfig: AnalyticsHandlersLogConfig, - 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(): GlobalAnalyticsEventHandlerBuilder { - if (isDebug) { - if (logConfig.firebase) FirebaseLogClient(createLogger("FirebaseAnalyticsHandler")) else null - } else { - FirebaseClient() - }?.let { - analyticHandlers.add(FirebaseAnalyticsHandler(it)) - } - return this - } - - fun addAppsFlyer(): GlobalAnalyticsEventHandlerBuilder { - if (isDebug) { - if (logConfig.appsFlyer) AppsFlyerLogClient(createLogger("AppsFlyerAnalyticsHandler")) else null - } else { - AppsFlyerClient(application, config.appsFlyerDevKey) - }?.let { - analyticHandlers.add(AppsFlyerAnalyticsHandler(it)) - } - return this - } - - fun addAmplitude(): GlobalAnalyticsEventHandlerBuilder { - if (isDebug) { - if (logConfig.firebase) AmplitudeLogClient(createLogger("AmplitudeAnalyticsHandler")) else null - } else { - AmplitudeClient(application, config.amplitudeApiKey) - }?.let { - analyticHandlers.add(AmplitudeAnalyticsHandler(it)) - } - return this - } - - private fun createLogger(name: String): AnalyticsEventsLogger { - return AnalyticsEventsLogger(name, jsonConverter) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/analytics/api/EventHandlerApi.kt b/app/src/main/java/com/tangem/tap/common/analytics/api/EventHandlerApi.kt index 08e1609e3c..ea77e75dfd 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/api/EventHandlerApi.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/api/EventHandlerApi.kt @@ -1,31 +1,30 @@ package com.tangem.tap.common.analytics.api +import android.app.Application 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.common.json.MoshiJsonConverter +import com.tangem.domain.common.AnalyticsHandlersLogConfig import com.tangem.tap.common.analytics.AnalyticsAnOld import com.tangem.tap.common.analytics.AnalyticsEventAnOld import com.tangem.tap.common.analytics.AnalyticsParamAnOld import com.tangem.tap.common.analytics.events.AnalyticsEvent import com.tangem.tap.common.analytics.events.AnalyticsParam import com.tangem.tap.common.extensions.filterNotNull +import com.tangem.tap.domain.configurable.config.Config /** [REDACTED_AUTHOR] */ interface AnalyticsEventHandler { - fun handleEvent( - event: String, - params: Map = emptyMap(), - ) + fun id(): String - fun handleAnalyticsEvent( - event: AnalyticsEvent, - card: Card? = null, - blockchain: String? = null, - ) { - handleEvent( + fun send(event: String, params: Map = emptyMap()) + + fun send(event: AnalyticsEvent, card: Card? = null, blockchain: String? = null) { + send( event = prepareEventString(event.category, event.event), params = prepareParams(card, blockchain, event.params), ) @@ -38,7 +37,7 @@ interface AnalyticsEventHandler { card: Card? = null, blockchain: String? = null, ) { - handleEvent(event.event, prepareParams(card, blockchain, params)) + send(event.event, prepareParams(card, blockchain, params)) } fun prepareParams( @@ -57,7 +56,7 @@ interface AnalyticsEventHandler { } interface ErrorEventHandler { - fun handleErrorEvent( + fun send( error: Throwable, params: Map = emptyMap(), ) @@ -66,7 +65,7 @@ interface ErrorEventHandler { interface SdkErrorEventHandler : CardSdkErrorEventHandler, BlockchainSdkErrorEventHandler interface CardSdkErrorEventHandler { - fun handleCardSdkErrorEvent( + fun send( error: TangemSdkError, action: AnalyticsAnOld.ActionToLog, params: Map = emptyMap(), @@ -75,7 +74,7 @@ interface CardSdkErrorEventHandler { } interface BlockchainSdkErrorEventHandler { - fun handleBlockchainSdkErrorEvent( + fun send( error: BlockchainError, action: AnalyticsAnOld.ActionToLog, params: Map = mapOf(), @@ -84,5 +83,17 @@ interface BlockchainSdkErrorEventHandler { } interface ShopifyOrderEventHandler { - fun handleShopifyOrderEvent(order: Storefront.Order) + fun send(order: Storefront.Order) } + +interface AnalyticsHandlerBuilder { + fun build(data: Data): AnalyticsEventHandler? + + data class Data( + val application: Application, + val config: Config, + val isDebug: Boolean, + val logConfig: AnalyticsHandlersLogConfig, + val jsonConverter: MoshiJsonConverter, + ) +} \ 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 index 27132a1f61..5a03cc2f36 100644 --- 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 @@ -1,12 +1,27 @@ package com.tangem.tap.common.analytics.handlers.amplitude import com.tangem.tap.common.analytics.api.AnalyticsEventHandler +import com.tangem.tap.common.analytics.api.AnalyticsHandlerBuilder class AmplitudeAnalyticsHandler( private val client: AmplitudeAnalyticsClient, ) : AnalyticsEventHandler { - override fun handleEvent(event: String, params: Map) { + override fun id(): String = ID + + override fun send(event: String, params: Map) { client.logEvent(event, params) } + + companion object { + const val ID = "Amplitude" + } + + class Builder : AnalyticsHandlerBuilder { + override fun build(data: AnalyticsHandlerBuilder.Data): AnalyticsEventHandler? = when { + !data.isDebug -> AmplitudeClient(data.application, data.config.amplitudeApiKey) + data.isDebug && data.logConfig.appsFlyer -> AmplitudeLogClient(data.jsonConverter) + else -> null + }?.let { AmplitudeAnalyticsHandler(it) } + } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/analytics/handlers/amplitude/AmplitudeLogClient.kt b/app/src/main/java/com/tangem/tap/common/analytics/handlers/amplitude/AmplitudeLogClient.kt index b800259b5f..f60d2edfcf 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/handlers/amplitude/AmplitudeLogClient.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/handlers/amplitude/AmplitudeLogClient.kt @@ -1,14 +1,17 @@ package com.tangem.tap.common.analytics.handlers.amplitude +import com.tangem.common.json.MoshiJsonConverter import com.tangem.tap.common.analytics.AnalyticsEventsLogger /** [REDACTED_AUTHOR] */ internal class AmplitudeLogClient( - private val logger: AnalyticsEventsLogger, + jsonConverter: MoshiJsonConverter, ) : AmplitudeAnalyticsClient { + private val logger: AnalyticsEventsLogger = AnalyticsEventsLogger(AmplitudeAnalyticsHandler.ID, jsonConverter) + override fun logEvent(event: String, params: Map) { logger.logEvent(event, params) } 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 index 0acfb1dc2f..008b6189b9 100644 --- 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 @@ -5,22 +5,34 @@ import com.appsflyer.AFInAppEventType import com.shopify.buy3.Storefront import com.tangem.common.Converter import com.tangem.tap.common.analytics.api.AnalyticsEventHandler +import com.tangem.tap.common.analytics.api.AnalyticsHandlerBuilder import com.tangem.tap.common.analytics.api.ShopifyOrderEventHandler class AppsFlyerAnalyticsHandler( private val client: AppsFlyerAnalyticsClient, ) : AnalyticsEventHandler, ShopifyOrderEventHandler { - override fun handleEvent(event: String, params: Map) { + override fun id(): String = ID + + override fun send(event: String, params: Map) { client.logEvent(event, params) } - override fun handleShopifyOrderEvent(order: Storefront.Order) { - handleEvent(ORDER_EVENT, OrderToParamsConverter().convert(order)) + override fun send(order: Storefront.Order) { + send(ORDER_EVENT, OrderToParamsConverter().convert(order)) } companion object { const val ORDER_EVENT = AFInAppEventType.PURCHASE + const val ID = "AppsFlyer" + } + + class Builder : AnalyticsHandlerBuilder { + override fun build(data: AnalyticsHandlerBuilder.Data): AnalyticsEventHandler? = when { + !data.isDebug -> AppsFlyerClient(data.application, data.config.appsFlyerDevKey) + data.isDebug && data.logConfig.appsFlyer -> AppsFlyerLogClient(data.jsonConverter) + else -> null + }?.let { AppsFlyerAnalyticsHandler(it) } } } diff --git a/app/src/main/java/com/tangem/tap/common/analytics/handlers/appsFlyer/AppsFlyerLogClient.kt b/app/src/main/java/com/tangem/tap/common/analytics/handlers/appsFlyer/AppsFlyerLogClient.kt index 0d3737a161..8e87061b2c 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/handlers/appsFlyer/AppsFlyerLogClient.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/handlers/appsFlyer/AppsFlyerLogClient.kt @@ -1,14 +1,17 @@ package com.tangem.tap.common.analytics.handlers.appsFlyer +import com.tangem.common.json.MoshiJsonConverter import com.tangem.tap.common.analytics.AnalyticsEventsLogger /** [REDACTED_AUTHOR] */ internal class AppsFlyerLogClient( - private val logger: AnalyticsEventsLogger, + jsonConverter: MoshiJsonConverter, ) : AppsFlyerAnalyticsClient { + private val logger = AnalyticsEventsLogger(AppsFlyerAnalyticsHandler.ID, jsonConverter) + override fun logEvent(event: String, params: Map) { logger.logEvent(event, params) } 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 index 3ab6326670..65ef31ac8e 100644 --- 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 @@ -9,6 +9,7 @@ import com.tangem.common.core.TangemSdkError import com.tangem.tap.common.analytics.AnalyticsAnOld import com.tangem.tap.common.analytics.AnalyticsParamAnOld import com.tangem.tap.common.analytics.api.AnalyticsEventHandler +import com.tangem.tap.common.analytics.api.AnalyticsHandlerBuilder import com.tangem.tap.common.analytics.api.ErrorEventHandler import com.tangem.tap.common.analytics.api.SdkErrorEventHandler import com.tangem.tap.common.analytics.api.ShopifyOrderEventHandler @@ -19,15 +20,17 @@ class FirebaseAnalyticsHandler( private val client: FirebaseAnalyticsClient, ) : AnalyticsEventHandler, ErrorEventHandler, SdkErrorEventHandler, ShopifyOrderEventHandler { - override fun handleEvent(event: String, params: Map) { + override fun id(): String = ID + + override fun send(event: String, params: Map) { client.logEvent(event, params) } - override fun handleErrorEvent(error: Throwable, params: Map) { + override fun send(error: Throwable, params: Map) { client.logErrorEvent(error, params) } - override fun handleCardSdkErrorEvent( + override fun send( error: TangemSdkError, action: AnalyticsAnOld.ActionToLog, params: Map, @@ -36,11 +39,11 @@ class FirebaseAnalyticsHandler( val model = CardSdkErrorConverter.Model(error, action, params, prepareParams(card)) val converter = CardSdkErrorConverter() converter.convert(model)?.let { - handleErrorEvent(it.throwable, it.params) + send(it.throwable, it.params) } } - override fun handleBlockchainSdkErrorEvent( + override fun send( error: BlockchainError, action: AnalyticsAnOld.ActionToLog, params: Map, @@ -50,12 +53,24 @@ class FirebaseAnalyticsHandler( val model = BlockchainSdkErrorConverter.Model(error, action, params, prepareParams(card)) val converter = BlockchainSdkErrorConverter(CardSdkErrorConverter()) converter.convert(model)?.let { - handleErrorEvent(it.throwable, it.params) + send(it.throwable, it.params) } } - override fun handleShopifyOrderEvent(order: Storefront.Order) { - handleEvent(FirebaseClient.ORDER_EVENT, OrderToParamsConverter().convert(order)) + override fun send(order: Storefront.Order) { + send(FirebaseClient.ORDER_EVENT, OrderToParamsConverter().convert(order)) + } + + companion object { + const val ID = "Firebase" + } + + class Builder : AnalyticsHandlerBuilder { + override fun build(data: AnalyticsHandlerBuilder.Data): AnalyticsEventHandler? = when { + !data.isDebug -> FirebaseClient() + data.isDebug && data.logConfig.firebase -> FirebaseLogClient(data.jsonConverter) + else -> null + }?.let { FirebaseAnalyticsHandler(it) } } } diff --git a/app/src/main/java/com/tangem/tap/common/analytics/handlers/firebase/FirebaseLogClient.kt b/app/src/main/java/com/tangem/tap/common/analytics/handlers/firebase/FirebaseLogClient.kt index ccacc09f9e..e460f9dbf9 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/handlers/firebase/FirebaseLogClient.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/handlers/firebase/FirebaseLogClient.kt @@ -1,14 +1,17 @@ package com.tangem.tap.common.analytics.handlers.firebase +import com.tangem.common.json.MoshiJsonConverter import com.tangem.tap.common.analytics.AnalyticsEventsLogger /** [REDACTED_AUTHOR] */ internal class FirebaseLogClient( - private val logger: AnalyticsEventsLogger, + jsonConverter: MoshiJsonConverter, ) : FirebaseAnalyticsClient { + private val logger: AnalyticsEventsLogger = AnalyticsEventsLogger(FirebaseAnalyticsHandler.ID, jsonConverter) + override fun logEvent(event: String, params: Map) { logger.logEvent(event, params) } 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 a02172db23..b31226d6da 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,6 +1,7 @@ package com.tangem.tap.common.redux.global import com.tangem.domain.common.ScanResponse +import com.tangem.tap.common.analytics.Analytics import com.tangem.tap.common.analytics.GlobalAnalyticsEventHandler import com.tangem.tap.common.entities.FiatCurrency import com.tangem.tap.common.feedback.FeedbackManager @@ -27,11 +28,10 @@ data class GlobalState( val dialog: StateDialog? = null, val exchangeManager: CurrencyExchangeManager = CurrencyExchangeManager.dummy(), val resources: AndroidResources = AndroidResources(), - val analyticsHandler: GlobalAnalyticsEventHandler = GlobalAnalyticsEventHandler.stub(), + val analyticsHandler: GlobalAnalyticsEventHandler = Analytics, val userCountryCode: String? = null, ) : StateType - data class AndroidResources( val strings: RString = RString(), ) { 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 c8bd0a5405..d26f38e508 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 @@ -199,7 +199,7 @@ class TangemShopService(application: Application, shopifyShop: ShopifyShop) { suspend fun waitForCheckout(productType: ProductType, analyticsHandler: GlobalAnalyticsEventHandler?) { val result = shopifyService.checkout(true, checkouts[productType]!!.id) result.onSuccess { - ifNotNull(analyticsHandler, it.order) { handler, order -> handler.handleShopifyOrderEvent(order) } + ifNotNull(analyticsHandler, it.order) { handler, order -> handler.send(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 296b47185b..94bf9fcaec 100644 --- a/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt @@ -91,7 +91,7 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co } is CompletionResult.Failure -> (result.error as? TangemSdkError)?.let { error -> - analyticsHandler?.handleCardSdkErrorEvent( + analyticsHandler?.send( error = error, action = AnalyticsAnOld.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 feb58ca6f0..7a39dc917d 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 @@ -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?.handleCardSdkErrorEvent( + analyticsHandler?.send( error, AnalyticsAnOld.ActionToLog.CreateWallet, card = card @@ -67,7 +67,7 @@ class TwinCardsManager( } is CompletionResult.Failure -> { (response.error as? TangemSdkError)?.let { error -> - analyticsHandler?.handleCardSdkErrorEvent( + analyticsHandler?.send( error, AnalyticsAnOld.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?.handleCardSdkErrorEvent( + analyticsHandler?.send( error, AnalyticsAnOld.ActionToLog.WriteIssuerData, card = card 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 f90eb7cbb9..c09bfcbfe9 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 @@ -143,7 +143,7 @@ class WalletConnectSdkHelper { HEX_PREFIX + data.walletManager.wallet.recentTransactions.last().hash } is SimpleResult.Failure -> { - store.state.globalState.analyticsHandler?.handleBlockchainSdkErrorEvent( + store.state.globalState.analyticsHandler?.send( result.error, AnalyticsAnOld.ActionToLog.WalletConnectTransaction, ) @@ -173,7 +173,7 @@ class WalletConnectSdkHelper { } is CompletionResult.Failure -> { (result.error as? TangemSdkError)?.let { error -> - store.state.globalState.analyticsHandler?.handleCardSdkErrorEvent( + store.state.globalState.analyticsHandler?.send( error, AnalyticsAnOld.ActionToLog.WalletConnectSign, ) @@ -202,7 +202,7 @@ class WalletConnectSdkHelper { } is CompletionResult.Failure -> { (result.error as? TangemSdkError)?.let { error -> - store.state.globalState.analyticsHandler?.handleCardSdkErrorEvent( + store.state.globalState.analyticsHandler?.send( error, AnalyticsAnOld.ActionToLog.WalletConnectTransaction, ) @@ -278,7 +278,7 @@ class WalletConnectSdkHelper { } is CompletionResult.Failure -> { (result.error as? TangemSdkError)?.let { error -> - store.state.globalState.analyticsHandler?.handleCardSdkErrorEvent( + store.state.globalState.analyticsHandler?.send( error, AnalyticsAnOld.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 309c2900d3..719e666a32 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 @@ -110,7 +110,7 @@ class DetailsMiddleware { } is CompletionResult.Failure -> { (result.error as? TangemSdkError)?.let { error -> - store.state.globalState.analyticsHandler?.handleCardSdkErrorEvent( + store.state.globalState.analyticsHandler?.send( error, AnalyticsAnOld.ActionToLog.PurgeWallet, card = store.state.detailsState.scanResponse?.card, @@ -154,7 +154,7 @@ class DetailsMiddleware { } is CompletionResult.Failure -> { (result.error as? TangemSdkError)?.let { error -> - store.state.globalState.analyticsHandler?.handleCardSdkErrorEvent( + store.state.globalState.analyticsHandler?.send( error = error, action = AnalyticsAnOld.ActionToLog.ChangeSecOptions, params = mapOf( diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayMiddleware.kt index b969f87719..fdd09a7dd8 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayMiddleware.kt @@ -77,7 +77,7 @@ private fun handleOnboardingSaltPayAction(anyAction: Action, appState: () -> App } } is OnboardingSaltPayAction.RegisterCard -> { - analyticsHandler.handleAnalyticsEvent(Onboarding.ButtonConnect()) + analyticsHandler.send(Onboarding.ButtonConnect()) handleInProgress = true val state = getState() @@ -151,7 +151,7 @@ private fun handleOnboardingSaltPayAction(anyAction: Action, appState: () -> App is OnboardingSaltPayAction.TrySetPin -> { try { assertPinValid(action.pin, getState().pinLength) - analyticsHandler.handleAnalyticsEvent(Onboarding.PinCodeSet()) + analyticsHandler.send(Onboarding.PinCodeSet()) store.dispatch(OnboardingSaltPayAction.SetPin(action.pin)) store.dispatch(OnboardingSaltPayAction.SetStep(SaltPayActivationStep.CardRegistration)) } catch (error: SaltPayActivationError) { @@ -159,7 +159,7 @@ private fun handleOnboardingSaltPayAction(anyAction: Action, appState: () -> App } } is OnboardingSaltPayAction.Claim -> { - analyticsHandler.handleAnalyticsEvent(Onboarding.ButtonClaim()) + analyticsHandler.send(Onboarding.ButtonClaim()) val state = getState() handleInProgress = true @@ -192,7 +192,7 @@ private fun handleOnboardingSaltPayAction(anyAction: Action, appState: () -> App } handleInProgress = false - analyticsHandler.handleAnalyticsEvent(Onboarding.ClaimWasSuccessfully()) + analyticsHandler.send(Onboarding.ClaimWasSuccessfully()) dispatchOnMain(OnboardingSaltPayAction.SetStep(SaltPayActivationStep.ClaimInProgress)) dispatchOnMain(OnboardingSaltPayAction.RefreshClaim) } @@ -242,10 +242,10 @@ private fun handleOnboardingSaltPayAction(anyAction: Action, appState: () -> App private fun handleAnalytics(analyticsHandler: GlobalAnalyticsEventHandler, step: SaltPayActivationStep) { when (step) { - SaltPayActivationStep.KycStart -> analyticsHandler.handleAnalyticsEvent(Onboarding.KYCStarted()) - SaltPayActivationStep.KycWaiting -> analyticsHandler.handleAnalyticsEvent(Onboarding.KYCInProgress()) - SaltPayActivationStep.KycReject -> analyticsHandler.handleAnalyticsEvent(Onboarding.KYCRejected()) - SaltPayActivationStep.Claim -> analyticsHandler.handleAnalyticsEvent(Onboarding.ClaimScreenOpened()) + SaltPayActivationStep.KycStart -> analyticsHandler.send(Onboarding.KYCStarted()) + SaltPayActivationStep.KycWaiting -> analyticsHandler.send(Onboarding.KYCInProgress()) + SaltPayActivationStep.KycReject -> analyticsHandler.send(Onboarding.KYCRejected()) + SaltPayActivationStep.Claim -> analyticsHandler.send(Onboarding.ClaimScreenOpened()) else -> {} } } 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 22cd5ad13a..49bbefe866 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 @@ -250,7 +250,7 @@ private fun sendTransaction( feeAmount = feeAmount, destinationAddress = destinationAddress, ) - store.state.globalState.analyticsHandler?.handleBlockchainSdkErrorEvent( + store.state.globalState.analyticsHandler?.send( error = sendResult.error, action = AnalyticsAnOld.ActionToLog.SendTransaction, params = mapOf(AnalyticsParamAnOld.BLOCKCHAIN to walletManager.wallet.blockchain.currency), 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 ca2323f38e..5e34717f5d 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 @@ -186,7 +186,7 @@ class WalletMiddleware { } is CompletionResult.Failure -> { (result.error as? TangemSdkError)?.let { error -> - store.state.globalState.analyticsHandler?.handleCardSdkErrorEvent( + store.state.globalState.analyticsHandler?.send( error, AnalyticsAnOld.ActionToLog.CreateWallet, card = store.state.detailsState.scanResponse?.card From f5bad316181c7cd0bc851a6a8071f7e0244fe0ee Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 28 Oct 2022 12:02:07 +0500 Subject: [PATCH 02/47] Updated on 2026-08-14 --- .../tap/common/redux/global/GlobalAction.kt | 2 -- .../common/redux/global/GlobalMidlleware.kt | 1 - .../tap/common/redux/global/GlobalReducer.kt | 1 - .../tap/common/redux/global/GlobalState.kt | 3 --- .../tap/common/shop/TangemShopService.kt | 7 +++--- .../com/tangem/tap/domain/TangemSdkManager.kt | 14 +++++------ .../tap/domain/twins/TwinCardsManager.kt | 9 ++++---- .../walletconnect/WalletConnectManager.kt | 13 ++++++----- .../walletconnect/WalletConnectSdkHelper.kt | 21 ++++------------- .../details/redux/DetailsMiddleware.kt | 5 ++-- .../tap/features/home/redux/HomeMiddleware.kt | 5 ++-- .../twins/redux/TwinCardsMiddleware.kt | 1 - .../redux/OnboardingSaltPayMiddleware.kt | 23 +++++++++---------- .../send/redux/middlewares/SendMiddleware.kt | 5 ++-- .../tap/features/shop/redux/ShopMiddleware.kt | 7 +----- .../redux/middlewares/WalletMiddleware.kt | 3 ++- .../redux/middlewares/WarningsMiddleware.kt | 3 ++- .../ui/adapters/WarningMessagesAdapter.kt | 8 +++---- 18 files changed, 54 insertions(+), 77 deletions(-) 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 b226be3401..c1e6d85f11 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,6 @@ 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.GlobalAnalyticsEventHandler import com.tangem.tap.common.entities.FiatCurrency import com.tangem.tap.common.feedback.FeedbackData import com.tangem.tap.common.feedback.FeedbackManager @@ -89,7 +88,6 @@ 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: GlobalAnalyticsEventHandler) : GlobalAction() data class SendEmail(val feedbackData: FeedbackData) : GlobalAction() data class OpenChat(val feedbackData: FeedbackData, val zendeskConfig: ZendeskConfig? = null) : GlobalAction() diff --git a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMidlleware.kt b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMidlleware.kt index a805bbd798..bd346b13a6 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMidlleware.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMidlleware.kt @@ -163,7 +163,6 @@ private fun handleAction(action: Action, appState: () -> AppState?, dispatch: Di is GlobalAction.ScanCard -> { scope.launch { val result = tangemSdkManager.scanProduct( - store.state.globalState.analyticsHandler, userTokensRepository, action.additionalBlockchainsToDerive, action.messageResId, diff --git a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalReducer.kt b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalReducer.kt index b0cefc6d9e..820506ab18 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalReducer.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalReducer.kt @@ -48,7 +48,6 @@ fun globalReducer(action: Action, state: AppState): GlobalState { globalState.copy(configManager = action.configManager) } is GlobalAction.SetWarningManager -> globalState.copy(warningManager = action.warningManager) - is GlobalAction.SetGlobalAnalyticsHandler -> globalState.copy(analyticsHandler = action.analyticsHandler) is GlobalAction.UpdateWalletSignedHashes -> { val card = globalState.scanResponse?.card ?: return globalState val wallet = card.wallet(action.walletPublicKey) ?: return globalState 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 b31226d6da..11c84ed856 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,8 +1,6 @@ package com.tangem.tap.common.redux.global import com.tangem.domain.common.ScanResponse -import com.tangem.tap.common.analytics.Analytics -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 @@ -28,7 +26,6 @@ data class GlobalState( val dialog: StateDialog? = null, val exchangeManager: CurrencyExchangeManager = CurrencyExchangeManager.dummy(), val resources: AndroidResources = AndroidResources(), - val analyticsHandler: GlobalAnalyticsEventHandler = Analytics, 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 d26f38e508..87dacd7bc1 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 @@ -4,8 +4,7 @@ import android.app.Application 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.GlobalAnalyticsEventHandler +import com.tangem.tap.common.analytics.Analytics 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 +195,10 @@ class TangemShopService(application: Application, shopifyShop: ShopifyShop) { return checkouts[productType]!!.webUrl } - suspend fun waitForCheckout(productType: ProductType, analyticsHandler: GlobalAnalyticsEventHandler?) { + suspend fun waitForCheckout(productType: ProductType) { val result = shopifyService.checkout(true, checkouts[productType]!!.id) result.onSuccess { - ifNotNull(analyticsHandler, it.order) { handler, order -> handler.send(order) } + it.order?.let { Analytics.send(it) } } } 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 94bf9fcaec..55ec76e903 100644 --- a/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt @@ -26,10 +26,10 @@ import com.tangem.operations.derivation.DeriveMultipleWalletPublicKeysTask import com.tangem.operations.pins.CheckUserCodesCommand import com.tangem.operations.pins.CheckUserCodesResponse import com.tangem.operations.pins.SetUserCodeCommand +import com.tangem.tap.common.analytics.Analytics import com.tangem.tap.common.analytics.AnalyticsAnOld import com.tangem.tap.common.analytics.AnalyticsEventAnOld import com.tangem.tap.common.analytics.AnalyticsParamAnOld -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 @@ -45,18 +45,17 @@ import kotlin.coroutines.suspendCoroutine class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Context) { suspend fun scanProduct( - analyticsHandler: GlobalAnalyticsEventHandler?, userTokensRepository: UserTokensRepository, additionalBlockchainsToDerive: Collection? = null, messageRes: Int? = null, ): CompletionResult { - analyticsHandler?.handleAnalyticsEvent(AnalyticsEventAnOld.READY_TO_SCAN, card = null) + Analytics.handleAnalyticsEvent(AnalyticsEventAnOld.READY_TO_SCAN, card = null) val message = Message(context.getString(messageRes ?: R.string.initial_message_scan_header)) return runTaskAsyncReturnOnMain( runnable = ScanProductTask(null, userTokensRepository, additionalBlockchainsToDerive), cardId = null, initialMessage = message, - ).also { sendScanResultsToAnalytics(analyticsHandler, it) } + ).also { sendScanResultsToAnalytics(it) } } suspend fun createProductWallet( @@ -70,18 +69,17 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co } private fun sendScanResultsToAnalytics( - analyticsHandler: GlobalAnalyticsEventHandler?, result: CompletionResult, ) { when (result) { is CompletionResult.Success -> { - analyticsHandler?.handleAnalyticsEvent( + Analytics.handleAnalyticsEvent( event = AnalyticsEventAnOld.CARD_IS_SCANNED, card = result.data.card, blockchain = result.data.walletData?.blockchain, ) if (DemoHelper.isDemoCard(result.data)) { - analyticsHandler?.handleAnalyticsEvent( + Analytics.handleAnalyticsEvent( event = AnalyticsEventAnOld.DEMO_MODE_ACTIVATED, params = mapOf(AnalyticsParamAnOld.CARD_ID.param to result.data.card.cardId), card = result.data.card, @@ -91,7 +89,7 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co } is CompletionResult.Failure -> (result.error as? TangemSdkError)?.let { error -> - analyticsHandler?.send( + Analytics.send( error = error, action = AnalyticsAnOld.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 7a39dc917d..fc80f3c5b0 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 @@ -14,14 +14,13 @@ import com.tangem.domain.common.ScanResponse 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.AnalyticsAnOld -import com.tangem.tap.common.analytics.GlobalAnalyticsEventHandler import com.tangem.tap.tangemSdkManager class TwinCardsManager( private val card: Card, assetReader: AssetReader, - val analyticsHandler: GlobalAnalyticsEventHandler? ) { private val currentCardId: String = card.cardId @@ -37,7 +36,7 @@ class TwinCardsManager( is CompletionResult.Success -> currentCardPublicKey = response.data.wallet.publicKey.toHexString() is CompletionResult.Failure -> { (response.error as? TangemSdkError)?.let { error -> - analyticsHandler?.send( + Analytics.send( error, AnalyticsAnOld.ActionToLog.CreateWallet, card = card @@ -67,7 +66,7 @@ class TwinCardsManager( } is CompletionResult.Failure -> { (response.error as? TangemSdkError)?.let { error -> - analyticsHandler?.send( + Analytics.send( error, AnalyticsAnOld.ActionToLog.CreateWallet, card = card @@ -87,7 +86,7 @@ class TwinCardsManager( is CompletionResult.Success -> Result.Success(response.data) is CompletionResult.Failure -> { (response.error as? TangemSdkError)?.let { error -> - analyticsHandler?.send( + Analytics.send( error, AnalyticsAnOld.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 6bd6cddada..f9ed7f61a5 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 @@ -4,6 +4,7 @@ import com.tangem.blockchain.common.Blockchain 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.AnalyticsAnOld import com.tangem.tap.common.analytics.logWcEvent import com.tangem.tap.common.extensions.dispatchOnMain @@ -223,7 +224,7 @@ class WalletConnectManager { } private fun onSessionClosed(session: WCSession) { - store.state.globalState.analyticsHandler?.logWcEvent( + Analytics.logWcEvent( AnalyticsAnOld.WcAnalyticsEvent.Session( AnalyticsAnOld.WcSessionEvent.Disconnect, sessions[session]?.peerMeta?.url ) @@ -372,7 +373,7 @@ class WalletConnectManager { ), ) } - store.state.globalState.analyticsHandler?.logWcEvent( + Analytics.logWcEvent( AnalyticsAnOld.WcAnalyticsEvent.Session( AnalyticsAnOld.WcSessionEvent.Connect, peer.url, ), @@ -387,7 +388,7 @@ class WalletConnectManager { } client.onEthSendTransaction = { id: Long, transaction: WCEthereumTransaction -> Timber.d("onEthSendTransaction: $transaction") - store.state.globalState.analyticsHandler?.logWcEvent( + Analytics.logWcEvent( AnalyticsAnOld.WcAnalyticsEvent.Action( AnalyticsAnOld.WcAction.SendTransaction ) @@ -405,7 +406,7 @@ class WalletConnectManager { } client.onEthSignTransaction = { id: Long, transaction: WCEthereumTransaction -> Timber.d("onEthSignTransaction: $transaction") - store.state.globalState.analyticsHandler?.logWcEvent( + Analytics.logWcEvent( AnalyticsAnOld.WcAnalyticsEvent.Action( AnalyticsAnOld.WcAction.SignTransaction ) @@ -423,7 +424,7 @@ class WalletConnectManager { } client.onEthSign = { id: Long, message: WCEthereumSignMessage -> Timber.d("onEthSign: $message") - store.state.globalState.analyticsHandler?.logWcEvent( + Analytics.logWcEvent( AnalyticsAnOld.WcAnalyticsEvent.Action( AnalyticsAnOld.WcAction.PersonalSign ) @@ -499,7 +500,7 @@ class WalletConnectManager { val message = EthSignHelper.tryToParseEthTypedMessage(request) if (message != null) { Timber.d("onEthSign_v4: $message") - store.state.globalState.analyticsHandler?.logWcEvent( + Analytics.logWcEvent( AnalyticsAnOld.WcAnalyticsEvent.Action( AnalyticsAnOld.WcAction.PersonalSign ) 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 c09bfcbfe9..36e8fc2a1d 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 @@ -24,6 +24,7 @@ import com.tangem.common.extensions.toDecompressedPublicKey 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.analytics.AnalyticsAnOld import com.tangem.tap.common.extensions.safeUpdate import com.tangem.tap.common.extensions.toFormattedString @@ -143,10 +144,7 @@ class WalletConnectSdkHelper { HEX_PREFIX + data.walletManager.wallet.recentTransactions.last().hash } is SimpleResult.Failure -> { - store.state.globalState.analyticsHandler?.send( - result.error, - AnalyticsAnOld.ActionToLog.WalletConnectTransaction, - ) + Analytics.send(result.error, AnalyticsAnOld.ActionToLog.WalletConnectTransaction) Timber.e(result.error as BlockchainSdkError) null } @@ -173,10 +171,7 @@ class WalletConnectSdkHelper { } is CompletionResult.Failure -> { (result.error as? TangemSdkError)?.let { error -> - store.state.globalState.analyticsHandler?.send( - error, - AnalyticsAnOld.ActionToLog.WalletConnectSign, - ) + Analytics.send(error, AnalyticsAnOld.ActionToLog.WalletConnectSign) } Timber.e(result.error.customMessage) null @@ -202,10 +197,7 @@ class WalletConnectSdkHelper { } is CompletionResult.Failure -> { (result.error as? TangemSdkError)?.let { error -> - store.state.globalState.analyticsHandler?.send( - error, - AnalyticsAnOld.ActionToLog.WalletConnectTransaction, - ) + Analytics.send(error, AnalyticsAnOld.ActionToLog.WalletConnectTransaction) } Timber.e(result.error.customMessage) null @@ -278,10 +270,7 @@ class WalletConnectSdkHelper { } is CompletionResult.Failure -> { (result.error as? TangemSdkError)?.let { error -> - store.state.globalState.analyticsHandler?.send( - error, - AnalyticsAnOld.ActionToLog.WalletConnectSign, - ) + Analytics.send(error, AnalyticsAnOld.ActionToLog.WalletConnectSign) } Timber.e(result.error.customMessage) null 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 719e666a32..6df912853f 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 @@ -3,6 +3,7 @@ package com.tangem.tap.features.details.redux import com.tangem.common.CompletionResult import com.tangem.common.core.TangemSdkError import com.tangem.domain.common.TapWorkarounds.isTangemTwins +import com.tangem.tap.common.analytics.Analytics import com.tangem.tap.common.analytics.AnalyticsAnOld import com.tangem.tap.common.analytics.AnalyticsParamAnOld import com.tangem.tap.common.extensions.dispatchNotification @@ -110,7 +111,7 @@ class DetailsMiddleware { } is CompletionResult.Failure -> { (result.error as? TangemSdkError)?.let { error -> - store.state.globalState.analyticsHandler?.send( + Analytics.send( error, AnalyticsAnOld.ActionToLog.PurgeWallet, card = store.state.detailsState.scanResponse?.card, @@ -154,7 +155,7 @@ class DetailsMiddleware { } is CompletionResult.Failure -> { (result.error as? TangemSdkError)?.let { error -> - store.state.globalState.analyticsHandler?.send( + Analytics.send( error = error, action = AnalyticsAnOld.ActionToLog.ChangeSecOptions, params = mapOf( 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 e7be6e2145..8df39141c7 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 @@ -6,6 +6,7 @@ import com.tangem.domain.common.ScanResponse import com.tangem.domain.common.extensions.withIOContext import com.tangem.domain.common.extensions.withMainContext import com.tangem.tap.DELAY_SDK_DIALOG_CLOSE +import com.tangem.tap.common.analytics.Analytics import com.tangem.tap.common.analytics.AnalyticsEventAnOld import com.tangem.tap.common.analytics.AnalyticsParamAnOld import com.tangem.tap.common.analytics.GetCardSourceParamsAnOld @@ -102,7 +103,7 @@ private fun handleHomeAction(appState: () -> AppState?, action: Action, dispatch RUSSIA_COUNTRY_CODE, BELARUS_COUNTRY_CODE -> store.dispatchOpenUrl(BUY_WALLET_URL) else -> store.dispatch(NavigationAction.NavigateTo(AppScreen.Shop)) } - store.state.globalState.analyticsHandler?.handleAnalyticsEvent( + Analytics.handleAnalyticsEvent( event = AnalyticsEventAnOld.GET_CARD, params = mapOf(AnalyticsParamAnOld.SOURCE.param to GetCardSourceParamsAnOld.WELCOME.param), ) @@ -149,7 +150,7 @@ private fun onScanSuccess(scanResponse: ScanResponse) { val tapWalletManager = globalState.tapWalletManager tapWalletManager.updateConfigManager(scanResponse) - globalState.analyticsHandler.attachToAllEvents(AnalyticsParam.BatchId, scanResponse.card.batchId) + Analytics.attachToAllEvents(AnalyticsParam.BatchId, scanResponse.card.batchId) store.dispatch(TwinCardsAction.IfTwinsPrepareState(scanResponse)) diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt index 47dd842d1d..35f7e1d7bd 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt @@ -139,7 +139,6 @@ private fun handle(action: Action, dispatch: DispatchFunction) { val manager = TwinCardsManager( card = getScanResponse().card, assetReader = action.reader, - analyticsHandler = store.state.globalState.analyticsHandler ) store.dispatch(TwinCardsAction.CardsManager.Set(manager)) diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayMiddleware.kt index fdd09a7dd8..d5442968ca 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayMiddleware.kt @@ -10,7 +10,7 @@ import com.tangem.domain.common.extensions.successOr import com.tangem.domain.common.extensions.withMainContext import com.tangem.network.api.paymentology.KYCStatus import com.tangem.network.api.paymentology.RegistrationResponse -import com.tangem.tap.common.analytics.GlobalAnalyticsEventHandler +import com.tangem.tap.common.analytics.Analytics import com.tangem.tap.common.analytics.events.Onboarding import com.tangem.tap.common.extensions.dispatchOnMain import com.tangem.tap.common.extensions.isPositive @@ -59,7 +59,6 @@ private fun handleOnboardingSaltPayAction(anyAction: Action, appState: () -> App fun getAppState(): AppState = appState()!! fun getOnboardingWalletState(): OnboardingWalletState = getAppState().onboardingWalletState fun getState(): OnboardingSaltPayState = getOnboardingWalletState().onboardingSaltPayState!! - val analyticsHandler = getAppState().globalState.analyticsHandler when (action) { is OnboardingSaltPayAction.Update -> { @@ -77,7 +76,7 @@ private fun handleOnboardingSaltPayAction(anyAction: Action, appState: () -> App } } is OnboardingSaltPayAction.RegisterCard -> { - analyticsHandler.send(Onboarding.ButtonConnect()) + Analytics.send(Onboarding.ButtonConnect()) handleInProgress = true val state = getState() @@ -151,7 +150,7 @@ private fun handleOnboardingSaltPayAction(anyAction: Action, appState: () -> App is OnboardingSaltPayAction.TrySetPin -> { try { assertPinValid(action.pin, getState().pinLength) - analyticsHandler.send(Onboarding.PinCodeSet()) + Analytics.send(Onboarding.PinCodeSet()) store.dispatch(OnboardingSaltPayAction.SetPin(action.pin)) store.dispatch(OnboardingSaltPayAction.SetStep(SaltPayActivationStep.CardRegistration)) } catch (error: SaltPayActivationError) { @@ -159,7 +158,7 @@ private fun handleOnboardingSaltPayAction(anyAction: Action, appState: () -> App } } is OnboardingSaltPayAction.Claim -> { - analyticsHandler.send(Onboarding.ButtonClaim()) + Analytics.send(Onboarding.ButtonClaim()) val state = getState() handleInProgress = true @@ -192,7 +191,7 @@ private fun handleOnboardingSaltPayAction(anyAction: Action, appState: () -> App } handleInProgress = false - analyticsHandler.send(Onboarding.ClaimWasSuccessfully()) + Analytics.send(Onboarding.ClaimWasSuccessfully()) dispatchOnMain(OnboardingSaltPayAction.SetStep(SaltPayActivationStep.ClaimInProgress)) dispatchOnMain(OnboardingSaltPayAction.RefreshClaim) } @@ -233,19 +232,19 @@ private fun handleOnboardingSaltPayAction(anyAction: Action, appState: () -> App } } } - is OnboardingSaltPayAction.SetStep -> handleAnalytics(analyticsHandler, action.newStep) + is OnboardingSaltPayAction.SetStep -> handleAnalytics(action.newStep) else -> { /* do nothing, only reduce */ } } } -private fun handleAnalytics(analyticsHandler: GlobalAnalyticsEventHandler, step: SaltPayActivationStep) { +private fun handleAnalytics(step: SaltPayActivationStep) { when (step) { - SaltPayActivationStep.KycStart -> analyticsHandler.send(Onboarding.KYCStarted()) - SaltPayActivationStep.KycWaiting -> analyticsHandler.send(Onboarding.KYCInProgress()) - SaltPayActivationStep.KycReject -> analyticsHandler.send(Onboarding.KYCRejected()) - SaltPayActivationStep.Claim -> analyticsHandler.send(Onboarding.ClaimScreenOpened()) + SaltPayActivationStep.KycStart -> Analytics.send(Onboarding.KYCStarted()) + SaltPayActivationStep.KycWaiting -> Analytics.send(Onboarding.KYCInProgress()) + SaltPayActivationStep.KycReject -> Analytics.send(Onboarding.KYCRejected()) + SaltPayActivationStep.Claim -> Analytics.send(Onboarding.ClaimScreenOpened()) else -> {} } } 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 49bbefe866..1e886dd335 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 @@ -17,6 +17,7 @@ import com.tangem.common.services.Result import com.tangem.domain.common.TapWorkarounds.isStart2Coin import com.tangem.domain.common.extensions.withMainContext import com.tangem.tap.DELAY_SDK_DIALOG_CLOSE +import com.tangem.tap.common.analytics.Analytics import com.tangem.tap.common.analytics.AnalyticsAnOld import com.tangem.tap.common.analytics.AnalyticsEventAnOld import com.tangem.tap.common.analytics.AnalyticsParamAnOld @@ -221,7 +222,7 @@ private fun sendTransaction( when (sendResult) { is SimpleResult.Success -> { - store.state.globalState.analyticsHandler?.handleAnalyticsEvent( + Analytics.handleAnalyticsEvent( event = AnalyticsEventAnOld.TRANSACTION_IS_SENT, card = card, blockchain = walletManager.wallet.blockchain.currency, @@ -250,7 +251,7 @@ private fun sendTransaction( feeAmount = feeAmount, destinationAddress = destinationAddress, ) - store.state.globalState.analyticsHandler?.send( + Analytics.send( error = sendResult.error, action = AnalyticsAnOld.ActionToLog.SendTransaction, params = mapOf(AnalyticsParamAnOld.BLOCKCHAIN to walletManager.wallet.blockchain.currency), diff --git a/app/src/main/java/com/tangem/tap/features/shop/redux/ShopMiddleware.kt b/app/src/main/java/com/tangem/tap/features/shop/redux/ShopMiddleware.kt index ceba9a5217..f7f126c05f 100644 --- a/app/src/main/java/com/tangem/tap/features/shop/redux/ShopMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/shop/redux/ShopMiddleware.kt @@ -119,13 +119,8 @@ private fun handle(action: Action) { is ShopAction.FinishSuccessfulOrder -> { scope.launch { - shopService.waitForCheckout( - productType = shopState.selectedProduct, - analyticsHandler = store.state.globalState.analyticsHandler - ) + shopService.waitForCheckout(shopState.selectedProduct) } } - } - } \ No newline at end of file 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 5e34717f5d..157c8786b4 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 @@ -11,6 +11,7 @@ import com.tangem.common.services.Result import com.tangem.domain.common.extensions.withMainContext import com.tangem.operations.attestation.Attestation import com.tangem.operations.attestation.OnlineCardVerifier +import com.tangem.tap.common.analytics.Analytics import com.tangem.tap.common.analytics.AnalyticsAnOld import com.tangem.tap.common.extensions.copyToClipboard import com.tangem.tap.common.extensions.dispatchDebugErrorNotification @@ -186,7 +187,7 @@ class WalletMiddleware { } is CompletionResult.Failure -> { (result.error as? TangemSdkError)?.let { error -> - store.state.globalState.analyticsHandler?.send( + Analytics.send( error, AnalyticsAnOld.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 8bf72ef3c7..4a30816169 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 @@ -8,6 +8,7 @@ import com.tangem.common.card.Card import com.tangem.common.card.FirmwareVersion import com.tangem.domain.common.ScanResponse import com.tangem.domain.common.TapWorkarounds.isTestCard +import com.tangem.tap.common.analytics.Analytics import com.tangem.tap.common.analytics.AnalyticsEventAnOld import com.tangem.tap.common.extensions.dispatchOnMain import com.tangem.tap.common.extensions.isGreaterThan @@ -81,7 +82,7 @@ class WarningsMiddleware { preferencesStorage.appRatingLaunchObserver.foundWalletWithFunds() } if (preferencesStorage.appRatingLaunchObserver.isReadyToShow()) { - store.state.globalState.analyticsHandler?.handleAnalyticsEvent(AnalyticsEventAnOld.APP_RATING_DISPLAYED) + Analytics.handleAnalyticsEvent(AnalyticsEventAnOld.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 57e8e81f77..6a38cb2622 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 @@ -7,6 +7,7 @@ import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView import com.google.android.play.core.review.ReviewManagerFactory +import com.tangem.tap.common.analytics.Analytics import com.tangem.tap.common.analytics.AnalyticsEventAnOld import com.tangem.tap.common.extensions.getActivity import com.tangem.tap.common.extensions.getColor @@ -107,14 +108,13 @@ class WarningMessageVH(val binding: LayoutWarningCardActionBinding) : RecyclerVi binding.groupControlsTemporary.hide() binding.groupControlsRating.show() binding.btnClose.show() - val analyticsHandler = store.state.globalState.analyticsHandler binding.btnClose.setOnClickListener { - analyticsHandler?.handleAnalyticsEvent(AnalyticsEventAnOld.APP_RATING_DISMISS) + Analytics.handleAnalyticsEvent(AnalyticsEventAnOld.APP_RATING_DISMISS) store.dispatch(GlobalAction.HideWarningMessage(warning)) store.dispatch(WalletAction.Warnings.AppRating.RemindLater) } binding.btnCanBeBetter.setOnClickListener { - analyticsHandler?.handleAnalyticsEvent(AnalyticsEventAnOld.APP_RATING_NEGATIVE) + Analytics.handleAnalyticsEvent(AnalyticsEventAnOld.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?.handleAnalyticsEvent(AnalyticsEventAnOld.APP_RATING_POSITIVE) + Analytics.handleAnalyticsEvent(AnalyticsEventAnOld.APP_RATING_POSITIVE) store.dispatch(WalletAction.Warnings.AppRating.SetNeverToShow) val reviewManager = ReviewManagerFactory.create(activity) val task = reviewManager.requestReviewFlow() From 2c19b748b0a0a3df33bfeffd8cc4b4c5aa96d704 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 28 Oct 2022 12:27:15 +0500 Subject: [PATCH 03/47] Updated on 2026-08-14 --- .../tap/features/home/redux/HomeMiddleware.kt | 2 +- .../features/onboarding/OnboardingHelper.kt | 4 +- .../features/onboarding/OnboardingManager.kt | 22 ++++++--- .../products/note/OnboardingNoteFragment.kt | 1 + .../note/redux/OnboardingNoteAction.kt | 1 + .../note/redux/OnboardingNoteMiddleware.kt | 8 ++++ .../OnboardingOtherCardsFragment.kt | 1 + .../redux/OnboardingOtherCardsAction.kt | 1 + .../redux/OnboardingOtherCardsMiddleware.kt | 10 +++- .../twins/redux/TwinCardsMiddleware.kt | 23 ++++++--- .../wallet/redux/OnboardingWalletAction.kt | 1 - .../redux/OnboardingWalletMiddleware.kt | 30 +++++++----- .../saltPay/redux/OnboardingSaltPayAction.kt | 12 ++--- .../redux/OnboardingSaltPayMiddleware.kt | 47 ++++++++++++++----- .../saltPay/redux/OnboardingSaltPayReducer.kt | 2 +- .../wallet/ui/OnboardingWalletFragment.kt | 3 +- .../tap/persistence/UsedCardsPrefStorage.kt | 18 +++---- 17 files changed, 127 insertions(+), 59 deletions(-) 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 8df39141c7..5f77bee19f 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 @@ -166,7 +166,7 @@ private fun onScanSuccess(scanResponse: ScanResponse) { val isOnboardingCase = result.data if (isOnboardingCase) { store.dispatch(GlobalAction.Onboarding.Start(scanResponse, canSkipBackup = false)) - store.dispatch(OnboardingSaltPayAction.Init.SetDependencies(manager, config)) + store.dispatch(OnboardingSaltPayAction.SetDependencies(manager, config)) store.dispatch(OnboardingSaltPayAction.Update) navigateTo(AppScreen.OnboardingWallet) } else { diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingHelper.kt b/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingHelper.kt index f2227fcc32..48d1e70e68 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingHelper.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingHelper.kt @@ -19,10 +19,10 @@ class OnboardingHelper { if (!response.twinsIsTwinned()) { true } else { - cardInfoStorage.activationIsStarted(response.card.cardId) + cardInfoStorage.isActivationStarted(response.card.cardId) } } - response.card.hasWallets() -> cardInfoStorage.activationIsStarted(response.card.cardId) + response.card.hasWallets() -> cardInfoStorage.isActivationStarted(response.card.cardId) else -> true } } diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingManager.kt b/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingManager.kt index 8284efcd3d..853044464b 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingManager.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingManager.kt @@ -67,8 +67,10 @@ class OnboardingManager( } } - return balance.copy(currency = Currency.Blockchain( - walletManager.wallet.blockchain, walletManager.wallet.publicKey.derivationPath?.rawPath) + return balance.copy( + currency = Currency.Blockchain( + walletManager.wallet.blockchain, walletManager.wallet.publicKey.derivationPath?.rawPath, + ), ) } @@ -79,6 +81,14 @@ class OnboardingManager( fun activationFinished(cardId: String) { usedCardsPrefStorage.activationFinished(cardId) } + + fun isActivationFinished(cardId: String): Boolean { + return usedCardsPrefStorage.isActivationFinished(cardId) + } + + fun isActivationStarted(cardId: String): Boolean { + return usedCardsPrefStorage.isActivationStarted(cardId) + } } data class OnboardingWalletBalance( @@ -98,23 +108,23 @@ data class OnboardingWalletBalance( companion object { fun error(error: TapError): OnboardingWalletBalance = OnboardingWalletBalance( state = ProgressState.Error, - error = error + error = error, ) fun criticalError(error: TapError): OnboardingWalletBalance = OnboardingWalletBalance( state = ProgressState.Error, - criticalError = error + criticalError = error, ) fun loading(value: BigDecimal = BigDecimal.ZERO): OnboardingWalletBalance = OnboardingWalletBalance( value, - state = ProgressState.Loading + state = ProgressState.Loading, ) fun done(value: BigDecimal, hasTransactions: Boolean): OnboardingWalletBalance = OnboardingWalletBalance( value, hasIncomingTransaction = hasTransactions, - state = ProgressState.Done + state = ProgressState.Done, ) } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/OnboardingNoteFragment.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/OnboardingNoteFragment.kt index a54a27bd28..865726f3dc 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/OnboardingNoteFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/OnboardingNoteFragment.kt @@ -41,6 +41,7 @@ class OnboardingNoteFragment : BaseOnboardingFragment() { binding.toolbar.setTitle(R.string.onboarding_title) btnRefreshBalanceWidget = RefreshBalanceWidget(mainBinding.onboardingTopContainer.onboardingWalletContainer) + store.dispatch(OnboardingNoteAction.Init) store.dispatch(OnboardingNoteAction.LoadCardArtwork) store.dispatch(OnboardingNoteAction.DetermineStepOfScreen) } diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteAction.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteAction.kt index 5b377fd072..8e7046f114 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteAction.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteAction.kt @@ -10,6 +10,7 @@ import org.rekotlin.Action */ sealed class OnboardingNoteAction : Action { // from user, ui + object Init : OnboardingNoteAction() object LoadCardArtwork : OnboardingNoteAction() object CreateWallet : OnboardingNoteAction() object TopUp : OnboardingNoteAction() diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteMiddleware.kt index d990941bd5..a71a55f30a 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteMiddleware.kt @@ -4,6 +4,8 @@ import com.tangem.common.CompletionResult import com.tangem.common.extensions.guard import com.tangem.domain.common.extensions.withMainContext import com.tangem.tap.DELAY_SDK_DIALOG_CLOSE +import com.tangem.tap.common.analytics.Analytics +import com.tangem.tap.common.analytics.events.Onboarding import com.tangem.tap.common.extensions.dispatchDialogShow import com.tangem.tap.common.extensions.dispatchErrorNotification import com.tangem.tap.common.extensions.dispatchOpenUrl @@ -58,6 +60,11 @@ private fun handleNoteAction(appState: () -> AppState?, action: Action, dispatch val noteState = store.state.onboardingNoteState when (action) { + is OnboardingNoteAction.Init -> { + if (!onboardingManager.isActivationStarted(card.cardId)) { + Analytics.send(Onboarding.Started()) + } + } is OnboardingNoteAction.LoadCardArtwork -> { scope.launch { val artworkUrl = onboardingManager.loadArtworkUrl() @@ -78,6 +85,7 @@ private fun handleNoteAction(appState: () -> AppState?, action: Action, dispatch store.dispatch(OnboardingNoteAction.Balance.Update) } OnboardingNoteStep.Done -> { + Analytics.send(Onboarding.Finished()) onboardingManager.activationFinished(card.cardId) postUi(DELAY_SDK_DIALOG_CLOSE) { store.dispatch(OnboardingNoteAction.Confetti.Show) } } diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/OnboardingOtherCardsFragment.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/OnboardingOtherCardsFragment.kt index 0ed23143da..960062acab 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/OnboardingOtherCardsFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/OnboardingOtherCardsFragment.kt @@ -33,6 +33,7 @@ class OnboardingOtherCardsFragment : BaseOnboardingFragment { + if (!onboardingManager.isActivationStarted(card.cardId)) { + Analytics.send(Onboarding.Started()) + } + } is OnboardingOtherCardsAction.LoadCardArtwork -> { scope.launch { val artworkUrl = onboardingManager.loadArtworkUrl() @@ -60,6 +67,7 @@ private fun handleOtherCardsAction(action: Action, dispatch: DispatchFunction) { } is OnboardingOtherCardsAction.SetStepOfScreen -> { if (action.step == OnboardingOtherCardsStep.Done) { + Analytics.send(Onboarding.Finished()) onboardingManager.activationFinished(card.cardId) postUi(200) { store.dispatch(OnboardingOtherCardsAction.Confetti.Show) } } @@ -71,7 +79,7 @@ private fun handleOtherCardsAction(action: Action, dispatch: DispatchFunction) { when (result) { is CompletionResult.Success -> { val updatedResponse = onboardingManager.scanResponse.copy( - card = result.data.card + card = result.data.card, ) onboardingManager.scanResponse = updatedResponse onboardingManager.activationStarted(updatedResponse.card.cardId) diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt index 35f7e1d7bd..864549e54d 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt @@ -6,6 +6,8 @@ import com.tangem.common.extensions.guard import com.tangem.domain.common.ScanResponse import com.tangem.domain.common.extensions.withMainContext import com.tangem.tap.DELAY_SDK_DIALOG_CLOSE +import com.tangem.tap.common.analytics.Analytics +import com.tangem.tap.common.analytics.events.Onboarding import com.tangem.tap.common.extensions.dispatchDialogShow import com.tangem.tap.common.extensions.dispatchErrorNotification import com.tangem.tap.common.extensions.dispatchOpenUrl @@ -76,6 +78,7 @@ private fun handle(action: Action, dispatch: DispatchFunction) { fun finishCardActivation() { if (twinCardsState.mode == CreateTwinWalletMode.CreateWallet) { + Analytics.send(Onboarding.Finished()) onboardingManager?.activationFinished(getScanResponse().card.cardId) twinCardsState.pairCardId?.let { onboardingManager?.activationFinished(it) } } @@ -85,11 +88,18 @@ private fun handle(action: Action, dispatch: DispatchFunction) { is TwinCardsAction.Init -> { if (twinCardsState.currentStep == TwinCardsStep.WelcomeOnly) return + val scanResponse = getScanResponse() + onboardingManager?.apply { + if (!isActivationStarted(scanResponse.card.cardId)) { + Analytics.send(Onboarding.Started()) + } + } + when (twinCardsState.mode) { CreateTwinWalletMode.CreateWallet -> { if (preferencesStorage.wasTwinsOnboardingShown()) { val step = when { - !getScanResponse().twinsIsTwinned() -> TwinCardsStep.CreateFirstWallet + !scanResponse.twinsIsTwinned() -> TwinCardsStep.CreateFirstWallet twinCardsState.walletBalance.balanceIsToppedUp() -> TwinCardsStep.Done else -> TwinCardsStep.TopUpWallet } @@ -105,8 +115,8 @@ private fun handle(action: Action, dispatch: DispatchFunction) { } is TwinCardsAction.Wallet.HandleOnBackPressed -> { val shouldReturnCardBack = twinCardsState.mode == CreateTwinWalletMode.CreateWallet - && twinCardsState.currentStep != TwinCardsStep.TopUpWallet - && twinCardsState.currentStep != TwinCardsStep.Done + && twinCardsState.currentStep != TwinCardsStep.TopUpWallet + && twinCardsState.currentStep != TwinCardsStep.Done if (twinCardsState.showAlert) { val onInterruptPrompt = { @@ -163,7 +173,7 @@ private fun handle(action: Action, dispatch: DispatchFunction) { val result = manager.createSecondWallet( action.initialMessage, action.preparingMessage, - action.creatingWalletMessage + action.creatingWalletMessage, ) when (result) { is CompletionResult.Success -> { @@ -221,11 +231,11 @@ private fun handle(action: Action, dispatch: DispatchFunction) { val balanceIsLoading = twinCardsState.walletBalance.copy( currency = Currency.Blockchain( walletManager.wallet.blockchain, - walletManager.wallet.publicKey.derivationPath?.rawPath + walletManager.wallet.publicKey.derivationPath?.rawPath, ), state = ProgressState.Loading, error = null, - criticalError = null + criticalError = null, ) store.dispatch(TwinCardsAction.Balance.Set(balanceIsLoading)) @@ -239,7 +249,6 @@ private fun handle(action: Action, dispatch: DispatchFunction) { store.dispatch(TwinCardsAction.Balance.SetNonCriticalError(loadedBalance.error)) } } - } is TwinCardsAction.Balance.Set -> { if (action.balance.balanceIsToppedUp()) { diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletAction.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletAction.kt index 0de2a90471..728e86280e 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletAction.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletAction.kt @@ -7,7 +7,6 @@ import org.rekotlin.Action sealed class OnboardingWalletAction : Action { object Init : OnboardingWalletAction() - object StartSaltPayCardActivation : OnboardingWalletAction() object GetToCreateWalletStep : OnboardingWalletAction() object GetToSaltPayStep : OnboardingWalletAction() object CreateWallet : OnboardingWalletAction() diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt index 48e9c32f2f..ebdae723ea 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt @@ -3,10 +3,14 @@ package com.tangem.tap.features.onboarding.products.wallet.redux import com.tangem.blockchain.common.Blockchain import com.tangem.common.CompletionResult import com.tangem.common.card.Card +import com.tangem.common.extensions.ifNotNull import com.tangem.domain.common.ScanResponse +import com.tangem.domain.common.TapWorkarounds.isSaltPay import com.tangem.domain.common.extensions.withMainContext import com.tangem.operations.backup.BackupService import com.tangem.tap.backupService +import com.tangem.tap.common.analytics.Analytics +import com.tangem.tap.common.analytics.events.Onboarding import com.tangem.tap.common.extensions.dispatchDialogShow import com.tangem.tap.common.extensions.dispatchOnMain import com.tangem.tap.common.extensions.primaryCardIsSaltPay @@ -61,6 +65,12 @@ private fun handleWalletAction(action: Action, state: () -> AppState?, dispatch: when (action) { OnboardingWalletAction.Init -> { + ifNotNull(onboardingManager, card) { manager, card -> + if (!card.isSaltPay && !manager.isActivationStarted(card.cardId)) { + Analytics.send(Onboarding.Started()) + } + } + when { card == null -> { // it's possible when found unfinished backup for standard Wallet cards @@ -87,13 +97,6 @@ private fun handleWalletAction(action: Action, state: () -> AppState?, dispatch: } } } - is OnboardingWalletAction.StartSaltPayCardActivation -> { - // we need to do this because the standard activation happens in the OnboardingWalletAction.CreateWallet - // step which is omitted for SaltPay cards - if (onboardingWalletState.isSaltPay && scanResponse != null) { - startCardActivation(scanResponse) - } - } is OnboardingWalletAction.LoadArtwork -> { scope.launch { val artwork = onboardingManager?.loadArtworkUrl() @@ -148,9 +151,6 @@ private fun handleWalletAction(action: Action, state: () -> AppState?, dispatch: } else { val backupState = store.state.onboardingWalletState.backupState val updatedScanResponse = updateScanResponseAfterBackup(scanResponse, backupState) - if (onboardingWalletState.isSaltPay) { - finishCardActivation(backupState, scanResponse.card) - } scope.launch { globalState.tapWalletManager.onCardScanned(updatedScanResponse) } store.dispatchOnMain(NavigationAction.NavigateTo(AppScreen.Wallet)) } @@ -313,6 +313,7 @@ private fun handleBackupAction(appState: () -> AppState?, action: BackupAction) } is BackupAction.FinishBackup -> { if (!onboardingWalletState.isSaltPay) { + Analytics.send(Onboarding.Finished()) finishCardActivation(backupState, card) } } @@ -320,7 +321,10 @@ private fun handleBackupAction(appState: () -> AppState?, action: BackupAction) backupService.discardSavedBackup() } is BackupAction.DiscardSavedBackup -> { - backupService.primaryCardId?.let { finishCardsActivationForDiscardedUnfinishedBackup(it) } + backupService.primaryCardId?.let { + Analytics.send(Onboarding.Finished()) + finishCardsActivationForDiscardedUnfinishedBackup(it) + } backupService.discardSavedBackup() } is BackupAction.CheckForUnfinishedBackup -> { @@ -351,7 +355,7 @@ private fun startCardActivation(scanResponse: ScanResponse) { * Standard Wallet cards finish activation at BackupAction.FinishBackup * SaltPay cards finish activation at OnboardingWalletAction.FinishOnboarding */ -private fun finishCardActivation(backupState: BackupState, card: Card?) { +internal fun finishCardActivation(backupState: BackupState, card: Card?) { (listOf(backupState.primaryCardId, card?.cardId) + backupState.backupCardIds) .distinct().filterNotNull() .forEach { cardId -> @@ -377,7 +381,7 @@ private fun initSaltPayOnBackupFinishedIfNeeded( if (scanResponse == null) throw IllegalArgumentException() val (manager, config) = OnboardingSaltPayState.initDependency(scanResponse) - store.dispatchOnMain(OnboardingSaltPayAction.Init.SetDependencies(manager, config)) + store.dispatchOnMain(OnboardingSaltPayAction.SetDependencies(manager, config)) store.dispatchOnMain(OnboardingSaltPayAction.Update) } } diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayAction.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayAction.kt index 009f2350ad..a2194e9568 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayAction.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayAction.kt @@ -10,12 +10,12 @@ import java.math.BigDecimal [REDACTED_AUTHOR] */ sealed class OnboardingSaltPayAction : Action { - sealed class Init : OnboardingSaltPayAction() { - data class SetDependencies( - val registrationManager: SaltPayActivationManager, - val saltPayConfig: SaltPayConfig, - ) : Init() - } + object Init : OnboardingSaltPayAction() + + data class SetDependencies( + val registrationManager: SaltPayActivationManager, + val saltPayConfig: SaltPayConfig, + ) : OnboardingSaltPayAction() data class SetInProgress(val isInProgress: Boolean) : OnboardingSaltPayAction() data class SetClaimRefreshInProgress(val isInProgress: Boolean) : OnboardingSaltPayAction() diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayMiddleware.kt index d5442968ca..ea6bec2c95 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayMiddleware.kt @@ -12,13 +12,16 @@ import com.tangem.network.api.paymentology.KYCStatus import com.tangem.network.api.paymentology.RegistrationResponse import com.tangem.tap.common.analytics.Analytics import com.tangem.tap.common.analytics.events.Onboarding +import com.tangem.tap.common.extensions.dispatchDebugErrorNotification import com.tangem.tap.common.extensions.dispatchOnMain import com.tangem.tap.common.extensions.isPositive import com.tangem.tap.common.redux.AppState import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.domain.TangemSigner import com.tangem.tap.features.demo.DemoHelper +import com.tangem.tap.features.onboarding.OnboardingManager import com.tangem.tap.features.onboarding.products.wallet.redux.OnboardingWalletState +import com.tangem.tap.features.onboarding.products.wallet.redux.finishCardActivation import com.tangem.tap.features.onboarding.products.wallet.saltPay.AllSymbolsTheSameFilter import com.tangem.tap.features.onboarding.products.wallet.saltPay.SaltPayActivationManager import com.tangem.tap.features.onboarding.products.wallet.saltPay.SaltPayExceptionHandler @@ -58,9 +61,23 @@ private fun handleOnboardingSaltPayAction(anyAction: Action, appState: () -> App fun getAppState(): AppState = appState()!! fun getOnboardingWalletState(): OnboardingWalletState = getAppState().onboardingWalletState + fun getOnboardingManager(): OnboardingManager? = getAppState().globalState.onboardingState.onboardingManager fun getState(): OnboardingSaltPayState = getOnboardingWalletState().onboardingSaltPayState!! when (action) { + is OnboardingSaltPayAction.Init -> { + if (getOnboardingWalletState().isSaltPay) return + val onboardingManager = getOnboardingManager().guard { + // onboardingManager may be null if it's started from standard Wallet unfinished backup + return + } + + val card = onboardingManager.scanResponse.card + if (!onboardingManager.isActivationStarted(card.cardId)) { + Analytics.send(Onboarding.Started()) + onboardingManager.activationStarted(card.cardId) + } + } is OnboardingSaltPayAction.Update -> { handleInProgress = true @@ -232,23 +249,31 @@ private fun handleOnboardingSaltPayAction(anyAction: Action, appState: () -> App } } } - is OnboardingSaltPayAction.SetStep -> handleAnalytics(action.newStep) + is OnboardingSaltPayAction.SetStep -> { + when (action.newStep) { + SaltPayActivationStep.KycStart -> Analytics.send(Onboarding.KYCStarted()) + SaltPayActivationStep.KycWaiting -> Analytics.send(Onboarding.KYCInProgress()) + SaltPayActivationStep.KycReject -> Analytics.send(Onboarding.KYCRejected()) + SaltPayActivationStep.Claim -> Analytics.send(Onboarding.ClaimScreenOpened()) + SaltPayActivationStep.ClaimSuccess, SaltPayActivationStep.Success -> { + Analytics.send(Onboarding.Finished()) + val onboardingManager = getOnboardingManager().guard { + // Null is possible if it is started from a standard pending backup and in this case + // it is impossible to get here + store.dispatchDebugErrorNotification("OnboardingManager can't be NULL") + return + } + finishCardActivation(getOnboardingWalletState().backupState, onboardingManager.scanResponse.card) + } + else -> {} + } + } else -> { /* do nothing, only reduce */ } } } -private fun handleAnalytics(step: SaltPayActivationStep) { - when (step) { - SaltPayActivationStep.KycStart -> Analytics.send(Onboarding.KYCStarted()) - SaltPayActivationStep.KycWaiting -> Analytics.send(Onboarding.KYCInProgress()) - SaltPayActivationStep.KycReject -> Analytics.send(Onboarding.KYCRejected()) - SaltPayActivationStep.Claim -> Analytics.send(Onboarding.ClaimScreenOpened()) - else -> {} - } -} - suspend fun SaltPayActivationManager.update( currentStep: SaltPayActivationStep, currentAmountToClaim: Amount?, diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayReducer.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayReducer.kt index 264829c157..71570fd52e 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayReducer.kt @@ -17,7 +17,7 @@ class OnboardingSaltPayReducer { private fun internalReduce(anyAction: Action, onboardingWalletState: OnboardingWalletState): OnboardingWalletState { val action = anyAction as? OnboardingSaltPayAction ?: return onboardingWalletState - if (onboardingWalletState.onboardingSaltPayState == null && action is OnboardingSaltPayAction.Init.SetDependencies) { + if (onboardingWalletState.onboardingSaltPayState == null && action is OnboardingSaltPayAction.SetDependencies) { return onboardingWalletState.copy( onboardingSaltPayState = OnboardingSaltPayState( saltPayManager = action.registrationManager, diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/OnboardingWalletFragment.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/OnboardingWalletFragment.kt index 47b6beb3aa..e016d5fe8d 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/OnboardingWalletFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/OnboardingWalletFragment.kt @@ -32,6 +32,7 @@ import com.tangem.tap.features.onboarding.products.wallet.redux.BackupStep import com.tangem.tap.features.onboarding.products.wallet.redux.OnboardingWalletAction import com.tangem.tap.features.onboarding.products.wallet.redux.OnboardingWalletState import com.tangem.tap.features.onboarding.products.wallet.redux.OnboardingWalletStep +import com.tangem.tap.features.onboarding.products.wallet.saltPay.redux.OnboardingSaltPayAction import com.tangem.tap.features.onboarding.products.wallet.saltPay.ui.OnboardingSaltPayView import com.tangem.tap.features.onboarding.products.wallet.ui.dialogs.AccessCodeDialog import com.tangem.tap.store @@ -81,7 +82,7 @@ class OnboardingWalletFragment : BaseFragment(R.layout.fragment_onboarding_walle addBackPressHandler(this) store.dispatch(OnboardingWalletAction.Init) - store.dispatch(OnboardingWalletAction.StartSaltPayCardActivation) + store.dispatch(OnboardingSaltPayAction.Init) store.dispatch(OnboardingWalletAction.LoadArtwork) } diff --git a/app/src/main/java/com/tangem/tap/persistence/UsedCardsPrefStorage.kt b/app/src/main/java/com/tangem/tap/persistence/UsedCardsPrefStorage.kt index 5d7f241fb8..fb7f6a75e1 100644 --- a/app/src/main/java/com/tangem/tap/persistence/UsedCardsPrefStorage.kt +++ b/app/src/main/java/com/tangem/tap/persistence/UsedCardsPrefStorage.kt @@ -11,7 +11,7 @@ import timber.log.Timber */ class UsedCardsPrefStorage( private val preferences: SharedPreferences, - private val jsonConverter: MoshiJsonConverter + private val jsonConverter: MoshiJsonConverter, ) { internal fun migrate() { @@ -43,14 +43,6 @@ class UsedCardsPrefStorage( save(foundItem, restoredList) } - fun isActivationFinished(cardId: String): Boolean { - return !(findCardInfo(cardId)?.isActivationStarted ?: true) - } - - fun activationIsStarted(cardId: String): Boolean { - return findCardInfo(cardId)?.isActivationStarted ?: false - } - fun activationFinished(cardId: String) { val restoredList = restore() val foundItem = findCardInfo(cardId, restoredList)?.copy(isActivationStarted = false) @@ -59,6 +51,14 @@ class UsedCardsPrefStorage( save(foundItem, restoredList) } + fun isActivationFinished(cardId: String): Boolean { + return !(findCardInfo(cardId)?.isActivationStarted ?: true) + } + + fun isActivationStarted(cardId: String): Boolean { + return findCardInfo(cardId)?.isActivationStarted ?: false + } + private fun findCardInfo(cardId: String, list: MutableList? = null): UsedCardInfo? { val findInList = list ?: restore() return findInList.firstOrNull { it.cardId == cardId } From cc4292319d29cfaaf42efd86f03ebf31046db052 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 28 Oct 2022 18:02:29 +0500 Subject: [PATCH 04/47] Updated on 2026-08-14 --- .../note/redux/OnboardingNoteMiddleware.kt | 5 +++++ .../redux/OnboardingOtherCardsMiddleware.kt | 15 +++++++++++---- .../products/twins/redux/TwinCardsMiddleware.kt | 7 ++++++- .../wallet/redux/OnboardingWalletMiddleware.kt | 3 +++ 4 files changed, 25 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteMiddleware.kt index a71a55f30a..f55bf9668a 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteMiddleware.kt @@ -81,6 +81,9 @@ private fun handleNoteAction(appState: () -> AppState?, action: Action, dispatch } is OnboardingNoteAction.SetStepOfScreen -> { when (action.step) { + OnboardingNoteStep.CreateWallet -> { + Analytics.send(Onboarding.CreateWallet.ScreenOpened()) + } OnboardingNoteStep.TopUpWallet -> { store.dispatch(OnboardingNoteAction.Balance.Update) } @@ -92,11 +95,13 @@ private fun handleNoteAction(appState: () -> AppState?, action: Action, dispatch } } is OnboardingNoteAction.CreateWallet -> { + Analytics.send(Onboarding.CreateWallet.ButtonCreateWallet()) scope.launch { val result = tangemSdkManager.createProductWallet(scanResponse) withMainContext { when (result) { is CompletionResult.Success -> { + Analytics.send(Onboarding.CreateWallet.WalletCreatedSuccessfully()) val updatedResponse = scanResponse.copy(card = result.data.card) onboardingManager.scanResponse = updatedResponse onboardingManager.activationStarted(updatedResponse.card.cardId) diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/redux/OnboardingOtherCardsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/redux/OnboardingOtherCardsMiddleware.kt index efb2226659..ff988cc8d5 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/redux/OnboardingOtherCardsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/redux/OnboardingOtherCardsMiddleware.kt @@ -66,18 +66,25 @@ private fun handleOtherCardsAction(action: Action, dispatch: DispatchFunction) { store.dispatch((OnboardingOtherCardsAction.SetStepOfScreen(step))) } is OnboardingOtherCardsAction.SetStepOfScreen -> { - if (action.step == OnboardingOtherCardsStep.Done) { - Analytics.send(Onboarding.Finished()) - onboardingManager.activationFinished(card.cardId) - postUi(200) { store.dispatch(OnboardingOtherCardsAction.Confetti.Show) } + when (action.step) { + OnboardingOtherCardsStep.CreateWallet -> { + Analytics.send(Onboarding.CreateWallet.ScreenOpened()) + } + OnboardingOtherCardsStep.Done -> { + Analytics.send(Onboarding.Finished()) + onboardingManager.activationFinished(card.cardId) + postUi(200) { store.dispatch(OnboardingOtherCardsAction.Confetti.Show) } + } } } is OnboardingOtherCardsAction.CreateWallet -> { + Analytics.send(Onboarding.CreateWallet.ButtonCreateWallet()) scope.launch { val result = tangemSdkManager.createProductWallet(onboardingManager.scanResponse) withMainContext { when (result) { is CompletionResult.Success -> { + Analytics.send(Onboarding.CreateWallet.WalletCreatedSuccessfully()) val updatedResponse = onboardingManager.scanResponse.copy( card = result.data.card, ) diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt index 864549e54d..9865fc9c06 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt @@ -99,7 +99,10 @@ private fun handle(action: Action, dispatch: DispatchFunction) { CreateTwinWalletMode.CreateWallet -> { if (preferencesStorage.wasTwinsOnboardingShown()) { val step = when { - !scanResponse.twinsIsTwinned() -> TwinCardsStep.CreateFirstWallet + !scanResponse.twinsIsTwinned() -> { + Analytics.send(Onboarding.CreateWallet.ScreenOpened()) + TwinCardsStep.CreateFirstWallet + } twinCardsState.walletBalance.balanceIsToppedUp() -> TwinCardsStep.Done else -> TwinCardsStep.TopUpWallet } @@ -146,6 +149,7 @@ private fun handle(action: Action, dispatch: DispatchFunction) { } } is TwinCardsAction.Wallet.LaunchFirstStep -> { + Analytics.send(Onboarding.CreateWallet.ButtonCreateWallet()) val manager = TwinCardsManager( card = getScanResponse().card, assetReader = action.reader, @@ -155,6 +159,7 @@ private fun handle(action: Action, dispatch: DispatchFunction) { scope.launch { when (val result = manager.createFirstWallet(action.initialMessage)) { is CompletionResult.Success -> { + Analytics.send(Onboarding.CreateWallet.WalletCreatedSuccessfully()) startCardActivation(result.data.cardId) delay(DELAY_SDK_DIALOG_CLOSE) withMainContext { diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt index 4e34f48b54..ab507c9a6e 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt @@ -94,6 +94,7 @@ private fun handleWalletAction(action: Action, state: () -> AppState?, dispatch: } else -> { store.dispatch(OnboardingWalletAction.GetToCreateWalletStep) + Analytics.send(Onboarding.CreateWallet.ScreenOpened()) } } } @@ -109,12 +110,14 @@ private fun handleWalletAction(action: Action, state: () -> AppState?, dispatch: } } is OnboardingWalletAction.CreateWallet -> { + Analytics.send(Onboarding.CreateWallet.ButtonCreateWallet()) scope.launch { scanResponse ?: return@launch val result = tangemSdkManager.createProductWallet(scanResponse) withMainContext { when (result) { is CompletionResult.Success -> { + Analytics.send(Onboarding.CreateWallet.WalletCreatedSuccessfully()) //here we must use updated scanResponse after createWallet & derivation val updatedResponse = globalState.onboardingState.onboardingManager.scanResponse.copy( card = result.data.card, From d963d65f2ec591cc717e533e1f8e318257009dcf Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 28 Oct 2022 19:49:32 +0500 Subject: [PATCH 05/47] Updated on 2026-08-14 --- .../tap/common/analytics/events/Onboarding.kt | 20 +++++++++---------- .../redux/OnboardingWalletMiddleware.kt | 9 +++++++++ 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/common/analytics/events/Onboarding.kt b/app/src/main/java/com/tangem/tap/common/analytics/events/Onboarding.kt index b65408b7d5..5634c25afa 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/events/Onboarding.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/events/Onboarding.kt @@ -34,9 +34,9 @@ sealed class Onboarding( class AccessCodeEntered : Backup("Access Code Entered") class AccessCodeReEntered : Backup("Access Code Re-entered") - class Finished(cardsCount: String) : Backup( + class Finished(cardsCount: Int) : Backup( event = "Backup Finished", - params = mapOf("Cards count" to cardsCount), + params = mapOf("Cards count" to "$cardsCount"), ) } @@ -65,12 +65,12 @@ sealed class Onboarding( class SetupFinished : Twins("Twin Setup Finished") } - class PinCodeSet: Onboarding("Onboarding", "PIN code set") - class ButtonConnect: Onboarding("Onboarding", "Button - Connect") - class KYCStarted: Onboarding("Onboarding", "KYC started") - class KYCInProgress: Onboarding("Onboarding", "KYC in progress") - class KYCRejected: Onboarding("Onboarding", "KYC rejected") - class ClaimScreenOpened: Onboarding("Onboarding", "Claim screen opened") - class ButtonClaim: Onboarding("Onboarding", "Button - Claim") - class ClaimWasSuccessfully: Onboarding("Onboarding", "Claim was successfully") + class PinCodeSet : Onboarding("Onboarding", "PIN code set") + class ButtonConnect : Onboarding("Onboarding", "Button - Connect") + class KYCStarted : Onboarding("Onboarding", "KYC started") + class KYCInProgress : Onboarding("Onboarding", "KYC in progress") + class KYCRejected : Onboarding("Onboarding", "KYC rejected") + class ClaimScreenOpened : Onboarding("Onboarding", "Claim screen opened") + class ButtonClaim : Onboarding("Onboarding", "Button - Claim") + class ClaimWasSuccessfully : Onboarding("Onboarding", "Claim was successfully") } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt index ab507c9a6e..e468e440f5 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt @@ -169,6 +169,7 @@ private fun handleWalletAction(action: Action, state: () -> AppState?, dispatch: if (onboardingWalletState.isSaltPay) { BackupAction.StartBackup } else { + Analytics.send(Onboarding.Backup.ScreenOpened()) BackupAction.IntroduceBackup } } else { @@ -224,6 +225,7 @@ private fun handleBackupAction(appState: () -> AppState?, action: BackupAction) when (action) { is BackupAction.StartBackup -> { + Analytics.send(Onboarding.Backup.Started()) backupService.discardSavedBackup() val primaryCard = scanResponse?.primaryCard if (primaryCard != null) { @@ -269,7 +271,11 @@ private fun handleBackupAction(appState: () -> AppState?, action: BackupAction) store.dispatchOnMain(GlobalAction.ShowDialog(BackupDialog.AddMoreBackupCards)) } } + is BackupAction.ShowEnterAccessCodeScreen -> { + Analytics.send(Onboarding.Backup.SettingAccessCodeStarted()) + } is BackupAction.CheckAccessCode -> { + Analytics.send(Onboarding.Backup.AccessCodeEntered()) if (action.accessCode.length < 4) { store.dispatch(BackupAction.SetAccessCodeError(AccessCodeError.CodeTooShort)) } else { @@ -278,6 +284,7 @@ private fun handleBackupAction(appState: () -> AppState?, action: BackupAction) } } is BackupAction.SaveAccessCodeConfirmation -> { + Analytics.send(Onboarding.Backup.AccessCodeReEntered()) if (action.accessCodeConfirmation == backupState.accessCode) { store.dispatch(BackupAction.SetAccessCodeError(null)) backupService.setAccessCode(action.accessCodeConfirmation) @@ -315,6 +322,7 @@ private fun handleBackupAction(appState: () -> AppState?, action: BackupAction) } } is BackupAction.FinishBackup -> { + Analytics.send(Onboarding.Backup.Finished(backupState.backupCardsNumber)) if (!onboardingWalletState.isSaltPay) { Analytics.send(Onboarding.Finished()) finishCardActivation(backupState, card) @@ -340,6 +348,7 @@ private fun handleBackupAction(appState: () -> AppState?, action: BackupAction) store.dispatch(NavigationAction.NavigateTo(AppScreen.OnboardingWallet)) } is BackupAction.DismissBackup -> { + Analytics.send(Onboarding.Backup.Skipped()) if (onboardingWalletState.isSaltPay) throw UnsupportedOperationException() store.dispatch(BackupAction.FinishBackup) } From 7d0835f28c7c6bdf702733ad646ba36d004aec69 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 28 Oct 2022 23:15:07 +0500 Subject: [PATCH 06/47] Updated on 2026-08-14 --- .../domain/tasks/product/ScanProductTask.kt | 4 +- .../features/onboarding/OnboardingHelper.kt | 5 +- .../tap/persistence/PreferencesStorage.kt | 5 - .../tap/persistence/UsedCardsPrefStorage.kt | 97 ++++++++++++++----- 4 files changed, 78 insertions(+), 33 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt b/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt index 252d3585e6..a5d9fc3932 100644 --- a/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt +++ b/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt @@ -162,9 +162,9 @@ private class ScanWalletProcessor( session: CardSession, callback: (result: CompletionResult) -> Unit, ) { - val activationIsFinished = preferencesStorage.usedCardsPrefStorage.isActivationFinished(card.cardId) + val activationInProgress = preferencesStorage.usedCardsPrefStorage.isActivationInProgress(card.cardId) - if (card.backupStatus == Card.BackupStatus.NoBackup && !activationIsFinished && card.wallets.isNotEmpty()) { + if (card.backupStatus == Card.BackupStatus.NoBackup && activationInProgress && card.wallets.isNotEmpty()) { StartPrimaryCardLinkingTask().run(session) { linkingResult -> when (linkingResult) { is CompletionResult.Success -> { diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingHelper.kt b/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingHelper.kt index f2227fcc32..2917a052fe 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingHelper.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingHelper.kt @@ -14,15 +14,16 @@ class OnboardingHelper { fun isOnboardingCase(response: ScanResponse): Boolean { val cardInfoStorage = preferencesStorage.usedCardsPrefStorage + val cardId = response.card.cardId return when { response.isTangemTwins() -> { if (!response.twinsIsTwinned()) { true } else { - cardInfoStorage.activationIsStarted(response.card.cardId) + cardInfoStorage.isActivationInProgress(cardId) } } - response.card.hasWallets() -> cardInfoStorage.activationIsStarted(response.card.cardId) + response.card.hasWallets() -> cardInfoStorage.isActivationInProgress(cardId) else -> true } } diff --git a/app/src/main/java/com/tangem/tap/persistence/PreferencesStorage.kt b/app/src/main/java/com/tangem/tap/persistence/PreferencesStorage.kt index 723af0df99..40e4cd1bd2 100644 --- a/app/src/main/java/com/tangem/tap/persistence/PreferencesStorage.kt +++ b/app/src/main/java/com/tangem/tap/persistence/PreferencesStorage.kt @@ -33,11 +33,6 @@ class PreferencesStorage(applicationContext: Application) { fun getCountOfLaunches(): Int = preferences.getInt(APP_LAUNCH_COUNT_KEY, 1) - @Deprecated("Use UsedCardsPrefStorage instead") - fun wasCardScannedBefore(cardId: String): Boolean { - return usedCardsPrefStorage.wasScanned(cardId) - } - fun saveDisclaimerAccepted() { preferences.edit { putBoolean(DISCLAIMER_ACCEPTED_KEY, true) } } diff --git a/app/src/main/java/com/tangem/tap/persistence/UsedCardsPrefStorage.kt b/app/src/main/java/com/tangem/tap/persistence/UsedCardsPrefStorage.kt index 5d7f241fb8..f814eb7e16 100644 --- a/app/src/main/java/com/tangem/tap/persistence/UsedCardsPrefStorage.kt +++ b/app/src/main/java/com/tangem/tap/persistence/UsedCardsPrefStorage.kt @@ -11,16 +11,16 @@ import timber.log.Timber */ class UsedCardsPrefStorage( private val preferences: SharedPreferences, - private val jsonConverter: MoshiJsonConverter + private val jsonConverter: MoshiJsonConverter, ) { - internal fun migrate() { - val scannedIds = preferences.getString(SCANNED_CARDS_IDS_KEY, null) ?: return + private val migrationList = mutableListOf( + UserCardInfoToV2(this), + ) - val usedCardsInfo = scannedIds.split(",").map { UsedCardInfo(it.trim(), true) } - if (save(usedCardsInfo.toMutableList())) { - preferences.edit { this.remove(SCANNED_CARDS_IDS_KEY) } - } + internal fun migrate() { + migrationList.forEach { it.migrate() } + migrationList.clear() } fun scanned(cardId: String) { @@ -43,20 +43,28 @@ class UsedCardsPrefStorage( save(foundItem, restoredList) } - fun isActivationFinished(cardId: String): Boolean { - return !(findCardInfo(cardId)?.isActivationStarted ?: true) + fun activationFinished(cardId: String) { + val restoredList = restore() + var foundItem = findCardInfo(cardId, restoredList) ?: UsedCardInfo(cardId) + foundItem = foundItem.copy( + isActivationStarted = true, + isActivationFinished = true, + ) + + save(foundItem, restoredList) } - fun activationIsStarted(cardId: String): Boolean { + fun isActivationStarted(cardId: String): Boolean { return findCardInfo(cardId)?.isActivationStarted ?: false } - fun activationFinished(cardId: String) { - val restoredList = restore() - val foundItem = findCardInfo(cardId, restoredList)?.copy(isActivationStarted = false) - ?: UsedCardInfo(cardId, isActivationStarted = false) + fun isActivationFinished(cardId: String): Boolean { + return findCardInfo(cardId)?.isActivationFinished ?: false + } - save(foundItem, restoredList) + fun isActivationInProgress(cardId: String): Boolean { + val cardInfo = findCardInfo(cardId) ?: return false + return cardInfo.isActivationStarted && !cardInfo.isActivationFinished } private fun findCardInfo(cardId: String, list: MutableList? = null): UsedCardInfo? { @@ -74,7 +82,7 @@ class UsedCardsPrefStorage( private fun save(list: MutableList): Boolean { return try { val json = jsonConverter.toJson(list) - preferences.edit { putString(USED_CARDS_INFO, json) } + preferences.edit { putString(USED_CARDS_INFO_V2, json) } true } catch (ex: Exception) { Timber.e(ex) @@ -83,23 +91,64 @@ class UsedCardsPrefStorage( } private fun restore(): MutableList { - val json = preferences.getString(USED_CARDS_INFO, null) ?: return mutableListOf() + val json = preferences.getString(USED_CARDS_INFO_V2, null) ?: return mutableListOf() return try { jsonConverter.fromJson(json, jsonConverter.typedList(UsedCardInfo::class.java))!! } catch (ex: Exception) { - preferences.edit(true) { remove(USED_CARDS_INFO) } + preferences.edit(true) { remove(USED_CARDS_INFO_V2) } mutableListOf() } } companion object { + private const val USED_CARDS_INFO_V2 = "usedCardsInfo_v2" private const val USED_CARDS_INFO = "usedCardsInfo" - private const val SCANNED_CARDS_IDS_KEY = "scannedCardIds" } + + private class UserCardInfoToV2( + private val storage: UsedCardsPrefStorage, + ) : Migration { + override fun migrate() { + val restoredCardsInfo = restore() + if (restoredCardsInfo.isEmpty()) return + + val newCardsInfo = restoredCardsInfo.map { cardInfo -> + UsedCardInfo( + cardId = cardInfo.cardId, + isScanned = cardInfo.isScanned, + isActivationStarted = true, + isActivationFinished = !cardInfo.isActivationStarted, + ) + }.toMutableList() + storage.save(newCardsInfo) + } + + private fun restore(): MutableList { + val json = storage.preferences.getString(USED_CARDS_INFO, null) ?: return mutableListOf() + return try { + storage.jsonConverter.fromJson(json, storage.jsonConverter.typedList(UsedCardInfoOld::class.java))!! + } catch (ex: Exception) { + mutableListOf() + } finally { + storage.preferences.edit(true) { remove(USED_CARDS_INFO) } + } + } + } + + private data class UsedCardInfo( + val cardId: String, + val isScanned: Boolean = false, + val isActivationStarted: Boolean = false, + val isActivationFinished: Boolean = false, + ) + + private data class UsedCardInfoOld( + val cardId: String, + val isScanned: Boolean = false, + val isActivationStarted: Boolean = false, + ) } -private data class UsedCardInfo( - val cardId: String, - val isScanned: Boolean = false, - val isActivationStarted: Boolean = false, -) \ No newline at end of file +private interface Migration { + fun migrate() +} \ No newline at end of file From a71116a0aa5312c44b3c38a914d98be67deccbdb Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 28 Oct 2022 23:15:23 +0500 Subject: [PATCH 07/47] Updated on 2026-08-14 --- app/src/main/assets/tangem-app-config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/assets/tangem-app-config b/app/src/main/assets/tangem-app-config index c8f577f2ab..cf6ea50867 160000 --- a/app/src/main/assets/tangem-app-config +++ b/app/src/main/assets/tangem-app-config @@ -1 +1 @@ -Subproject commit c8f577f2ab48e0d6c49f79b6cff21eabe67cd63e +Subproject commit cf6ea50867477f97655da9da47ff94987e8f3354 From 7b90bb0848dd1bcabb6210d90562016312055916 Mon Sep 17 00:00:00 2001 From: Tangem Date: Sat, 29 Oct 2022 00:22:43 +0500 Subject: [PATCH 08/47] Updated on 2026-08-14 --- .../java/com/tangem/tap/persistence/PreferencesStorage.kt | 8 -------- 1 file changed, 8 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/persistence/PreferencesStorage.kt b/app/src/main/java/com/tangem/tap/persistence/PreferencesStorage.kt index 2250427b09..32ff1aeb79 100644 --- a/app/src/main/java/com/tangem/tap/persistence/PreferencesStorage.kt +++ b/app/src/main/java/com/tangem/tap/persistence/PreferencesStorage.kt @@ -33,14 +33,6 @@ class PreferencesStorage(applicationContext: Application) { fun getCountOfLaunches(): Int = preferences.getInt(APP_LAUNCH_COUNT_KEY, 1) - fun saveDisclaimerAccepted() { - preferences.edit { putBoolean(DISCLAIMER_ACCEPTED_KEY, true) } - } - - fun wasDisclaimerAccepted(): Boolean { - return preferences.getBoolean(DISCLAIMER_ACCEPTED_KEY, false) - } - fun saveTwinsOnboardingShown() { preferences.edit { putBoolean(TWINS_ONBOARDING_SHOWN_KEY, true) } } From 9f031964463ec2d4d4a8e9d6851bbc13469524ab Mon Sep 17 00:00:00 2001 From: Tangem Date: Sun, 30 Oct 2022 20:41:30 +0500 Subject: [PATCH 09/47] Updated on 2026-08-14 --- .../features/onboarding/products/wallet/ui/BackupAnimator.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/BackupAnimator.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/BackupAnimator.kt index d57205ce46..66f90f159c 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/BackupAnimator.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/BackupAnimator.kt @@ -68,7 +68,7 @@ class WalletBackupAnimator( when (backupCardsCounts) { 0 -> { when (currentStep) { - STEP_CREATE_WALLET -> { + UNDEFINED, STEP_CREATE_WALLET -> { cardsWidget.toFolded(false) { cardsWidget.toFan() } FIRST_BACKUP.animateAlpha(0.6f, 0) From 936112008744895f8e42d6e696a824b589c61906 Mon Sep 17 00:00:00 2001 From: Tangem Date: Sun, 30 Oct 2022 20:43:03 +0500 Subject: [PATCH 10/47] Updated on 2026-08-14 --- .../wallet/saltPay/redux/OnboardingSaltPayMiddleware.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayMiddleware.kt index 90c9d33f06..f550b730ac 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayMiddleware.kt @@ -66,7 +66,7 @@ private fun handleOnboardingSaltPayAction(anyAction: Action, appState: () -> App when (action) { is OnboardingSaltPayAction.Init -> { - if (getOnboardingWalletState().isSaltPay) return + if (!getOnboardingWalletState().isSaltPay) return val onboardingManager = getOnboardingManager().guard { // onboardingManager may be null if it's started from standard Wallet unfinished backup return @@ -289,7 +289,7 @@ suspend fun SaltPayActivationManager.update( return Result.Failure(ex) } - checkGasIfNeeded(this, newStep).successOr { return it } + // checkGasIfNeeded(this, newStep).successOr { return it } Timber.d("update: success: %s", newStep) return Result.Success(newStep) From 085ffaf2c5d0be5d5b8be04613eb719d4da0df72 Mon Sep 17 00:00:00 2001 From: Tangem Date: Sun, 30 Oct 2022 20:43:48 +0500 Subject: [PATCH 11/47] Updated on 2026-08-14 --- .../tap/domain/tasks/product/ScanProductTask.kt | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt b/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt index a5d9fc3932..459191b260 100644 --- a/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt +++ b/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt @@ -73,7 +73,7 @@ class ScanProductTask( // it need because processorResult.data.card doesn't contains attestation result // and CardWallet.derivedKeys val processorScanResponseWithNewCard = processorResult.data.copy( - card = scanTaskResult.data + card = scanTaskResult.data, ) callback(CompletionResult.Success(processorScanResponseWithNewCard)) } @@ -96,7 +96,7 @@ private class ScanNoteProcessor : ProductCommandProcessor { override fun proceed( card: Card, session: CardSession, - callback: (result: CompletionResult) -> Unit + callback: (result: CompletionResult) -> Unit, ) { callback( CompletionResult.Success( @@ -145,7 +145,7 @@ private class ScanWalletProcessor( is CompletionResult.Success -> { PreflightReadTask( readMode = PreflightReadMode.FullCardRead, - cardId = card.cardId + cardId = card.cardId, ).run(session) { readResult -> when (readResult) { is CompletionResult.Success -> startLinkingForBackupIfNeeded(card, session, callback) @@ -157,6 +157,7 @@ private class ScanWalletProcessor( } } } + private fun startLinkingForBackupIfNeeded( card: Card, session: CardSession, @@ -164,7 +165,9 @@ private class ScanWalletProcessor( ) { val activationInProgress = preferencesStorage.usedCardsPrefStorage.isActivationInProgress(card.cardId) - if (card.backupStatus == Card.BackupStatus.NoBackup && activationInProgress && card.wallets.isNotEmpty()) { + if ((card.backupStatus == Card.BackupStatus.NoBackup && card.wallets.isNotEmpty()) + && (activationInProgress || card.isSaltPay) + ) { StartPrimaryCardLinkingTask().run(session) { linkingResult -> when (linkingResult) { is CompletionResult.Success -> { @@ -180,6 +183,7 @@ private class ScanWalletProcessor( deriveKeysIfNeeded(card, session, callback) } } + private fun deriveKeysIfNeeded( card: Card, session: CardSession, @@ -251,7 +255,7 @@ private class ScanWalletProcessor( Blockchain.RSK, Blockchain.Fantom, Blockchain.FantomTestnet, Blockchain.Avalanche, Blockchain.AvalancheTestnet, - ).map { BlockchainNetwork(it, card) } + ).map { BlockchainNetwork(it, card) }, ) } return blockchainsToDerive.distinct() From 41703c9f113ac0545b5bb5aeb19c42450cce72d5 Mon Sep 17 00:00:00 2001 From: Tangem Date: Sun, 30 Oct 2022 20:44:26 +0500 Subject: [PATCH 12/47] Updated on 2026-08-14 --- .../analytics/handlers/amplitude/AmplitudeAnalyticsHandler.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index 5a03cc2f36..06f77c15b3 100644 --- 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 @@ -20,7 +20,7 @@ class AmplitudeAnalyticsHandler( class Builder : AnalyticsHandlerBuilder { override fun build(data: AnalyticsHandlerBuilder.Data): AnalyticsEventHandler? = when { !data.isDebug -> AmplitudeClient(data.application, data.config.amplitudeApiKey) - data.isDebug && data.logConfig.appsFlyer -> AmplitudeLogClient(data.jsonConverter) + data.isDebug && data.logConfig.amplitude -> AmplitudeLogClient(data.jsonConverter) else -> null }?.let { AmplitudeAnalyticsHandler(it) } } From 08b9e7f8f4fc8362f548cc4201bba699b7fcad72 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 31 Oct 2022 11:27:31 +0500 Subject: [PATCH 13/47] Updated on 2026-08-14 --- .../onboarding/products/note/OnboardingNoteFragment.kt | 7 ++++++- .../products/note/redux/OnboardingNoteMiddleware.kt | 1 - .../products/otherCards/OnboardingOtherCardsFragment.kt | 7 ++++++- .../otherCards/redux/OnboardingOtherCardsMiddleware.kt | 1 - .../onboarding/products/twins/redux/TwinCardsMiddleware.kt | 1 - .../onboarding/products/twins/ui/TwinsCardsFragment.kt | 3 +++ .../products/wallet/redux/OnboardingWalletMiddleware.kt | 1 - .../wallet/saltPay/redux/OnboardingSaltPayMiddleware.kt | 3 --- .../products/wallet/saltPay/ui/OnboardingSaltPayView.kt | 4 ++++ .../products/wallet/ui/OnboardingWalletFragment.kt | 7 ++++++- 10 files changed, 25 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/OnboardingNoteFragment.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/OnboardingNoteFragment.kt index 865726f3dc..82d575fafe 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/OnboardingNoteFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/OnboardingNoteFragment.kt @@ -9,6 +9,8 @@ import androidx.core.view.isVisible import androidx.transition.TransitionManager import coil.load import com.tangem.blockchain.common.Blockchain +import com.tangem.tap.common.analytics.Analytics +import com.tangem.tap.common.analytics.events.Onboarding import com.tangem.tap.common.extensions.getDrawableCompat import com.tangem.tap.common.extensions.stripZeroPlainString import com.tangem.tap.common.redux.navigation.ShareElement @@ -109,7 +111,10 @@ class OnboardingNoteFragment : BaseOnboardingFragment() { private fun setupCreateWalletState(state: OnboardingNoteState) = with(mainBinding.onboardingActionContainer) { btnMainAction.setText(R.string.onboarding_create_wallet_button_create_wallet) - btnMainAction.setOnClickListener { store.dispatch(OnboardingNoteAction.CreateWallet) } + btnMainAction.setOnClickListener { + Analytics.send(Onboarding.CreateWallet.ButtonCreateWallet()) + store.dispatch(OnboardingNoteAction.CreateWallet) + } btnAlternativeAction.setText(R.string.onboarding_button_what_does_it_mean) btnAlternativeAction.setOnClickListener { } diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteMiddleware.kt index f55bf9668a..6e1d907be1 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteMiddleware.kt @@ -95,7 +95,6 @@ private fun handleNoteAction(appState: () -> AppState?, action: Action, dispatch } } is OnboardingNoteAction.CreateWallet -> { - Analytics.send(Onboarding.CreateWallet.ButtonCreateWallet()) scope.launch { val result = tangemSdkManager.createProductWallet(scanResponse) withMainContext { diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/OnboardingOtherCardsFragment.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/OnboardingOtherCardsFragment.kt index 960062acab..f01eb6fbcd 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/OnboardingOtherCardsFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/OnboardingOtherCardsFragment.kt @@ -8,6 +8,8 @@ import androidx.constraintlayout.widget.ConstraintSet import androidx.core.view.isVisible import androidx.transition.TransitionManager import coil.load +import com.tangem.tap.common.analytics.Analytics +import com.tangem.tap.common.analytics.events.Onboarding import com.tangem.tap.common.extensions.getDrawableCompat import com.tangem.tap.common.redux.navigation.ShareElement import com.tangem.tap.common.transitions.InternalNoteLayoutTransition @@ -69,7 +71,10 @@ class OnboardingOtherCardsFragment : BaseOnboardingFragment { - Analytics.send(Onboarding.CreateWallet.ButtonCreateWallet()) scope.launch { val result = tangemSdkManager.createProductWallet(onboardingManager.scanResponse) withMainContext { diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt index 9865fc9c06..a872bfef97 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt @@ -149,7 +149,6 @@ private fun handle(action: Action, dispatch: DispatchFunction) { } } is TwinCardsAction.Wallet.LaunchFirstStep -> { - Analytics.send(Onboarding.CreateWallet.ButtonCreateWallet()) val manager = TwinCardsManager( card = getScanResponse().card, assetReader = action.reader, diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/ui/TwinsCardsFragment.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/ui/TwinsCardsFragment.kt index d4c6826a3c..450e9ecd50 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/ui/TwinsCardsFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/ui/TwinsCardsFragment.kt @@ -16,6 +16,8 @@ import com.tangem.common.extensions.VoidCallback import com.tangem.domain.common.TwinCardNumber import com.tangem.tangem_sdk_new.ui.widget.leapfrogWidget.LeapfrogWidget import com.tangem.tap.common.AndroidAssetReader +import com.tangem.tap.common.analytics.Analytics +import com.tangem.tap.common.analytics.events.Onboarding import com.tangem.tap.common.extensions.beginDelayedTransition import com.tangem.tap.common.extensions.getDrawableCompat import com.tangem.tap.common.extensions.hide @@ -238,6 +240,7 @@ class TwinsCardsFragment : BaseOnboardingFragment() { btnMainAction.text = getString(R.string.twins_recreate_button_format, twinIndexNumber) btnMainAction.setOnClickListener { + Analytics.send(Onboarding.CreateWallet.ButtonCreateWallet()) store.dispatch( TwinCardsAction.Wallet.LaunchFirstStep( Message(getString(R.string.twins_recreate_title_format, twinIndexNumber)), diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt index e468e440f5..dfe53282ed 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt @@ -110,7 +110,6 @@ private fun handleWalletAction(action: Action, state: () -> AppState?, dispatch: } } is OnboardingWalletAction.CreateWallet -> { - Analytics.send(Onboarding.CreateWallet.ButtonCreateWallet()) scope.launch { scanResponse ?: return@launch val result = tangemSdkManager.createProductWallet(scanResponse) diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayMiddleware.kt index f550b730ac..69f3e0a674 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayMiddleware.kt @@ -93,8 +93,6 @@ private fun handleOnboardingSaltPayAction(anyAction: Action, appState: () -> App } } is OnboardingSaltPayAction.RegisterCard -> { - Analytics.send(Onboarding.ButtonConnect()) - handleInProgress = true val state = getState() @@ -175,7 +173,6 @@ private fun handleOnboardingSaltPayAction(anyAction: Action, appState: () -> App } } is OnboardingSaltPayAction.Claim -> { - Analytics.send(Onboarding.ButtonClaim()) val state = getState() handleInProgress = true diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/ui/OnboardingSaltPayView.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/ui/OnboardingSaltPayView.kt index 90321f426a..dc934546aa 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/ui/OnboardingSaltPayView.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/ui/OnboardingSaltPayView.kt @@ -14,6 +14,8 @@ import coil.size.Scale import com.google.android.material.appbar.MaterialToolbar import com.google.android.material.button.MaterialButton import com.tangem.common.extensions.guard +import com.tangem.tap.common.analytics.Analytics +import com.tangem.tap.common.analytics.events.Onboarding import com.tangem.tap.common.compose.PinCodeWidget import com.tangem.tap.common.extensions.configureSettings import com.tangem.tap.common.extensions.dispatchDebugErrorNotification @@ -178,6 +180,7 @@ internal class OnboardingSaltPayView( showOnlyView(connectCard.root) { progressButton = SaltPayProgressButton(connectCard.root) connectCard.btnConnect.setOnClickListener { + Analytics.send(Onboarding.ButtonConnect()) store.dispatch(OnboardingSaltPayAction.RegisterCard) } } @@ -286,6 +289,7 @@ internal class OnboardingSaltPayView( btnMain.text = getText(R.string.onboarding_button_claim) btnMain.isEnabled btnMain.setOnClickListener { + Analytics.send(Onboarding.ButtonClaim()) store.dispatch(OnboardingSaltPayAction.Claim) } progressButton = SaltPayProgressButton(actionContainer.root) diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/OnboardingWalletFragment.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/OnboardingWalletFragment.kt index e016d5fe8d..59b784620f 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/OnboardingWalletFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/ui/OnboardingWalletFragment.kt @@ -19,6 +19,8 @@ import com.tangem.common.CardIdFormatter import com.tangem.common.core.CardIdDisplayFormat import com.tangem.tangem_sdk_new.ui.widget.leapfrogWidget.LeapfrogWidget import com.tangem.tangem_sdk_new.ui.widget.leapfrogWidget.PropertyCalculator +import com.tangem.tap.common.analytics.Analytics +import com.tangem.tap.common.analytics.events.Onboarding import com.tangem.tap.common.extensions.hide import com.tangem.tap.common.extensions.inflate import com.tangem.tap.common.extensions.show @@ -171,7 +173,10 @@ class OnboardingWalletFragment : BaseFragment(R.layout.fragment_onboarding_walle private fun setupCreateWalletState() = with(binding) { layoutButtonsCommon.btnWalletMainAction.setText(R.string.onboarding_create_wallet_button_create_wallet) - layoutButtonsCommon.btnWalletMainAction.setOnClickListener { store.dispatch(OnboardingWalletAction.CreateWallet) } + layoutButtonsCommon.btnWalletMainAction.setOnClickListener { + Analytics.send(Onboarding.CreateWallet.ButtonCreateWallet()) + store.dispatch(OnboardingWalletAction.CreateWallet) + } layoutButtonsCommon.btnWalletAlternativeAction.hide() toolbar.title = getText(R.string.onboarding_getting_started) From 03eeebd2806f7da4df18ad2374e114f2e42b0fba Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 31 Oct 2022 12:05:13 +0500 Subject: [PATCH 14/47] Updated on 2026-08-14 --- .../com/tangem/tap/features/home/HomeFragment.kt | 14 ++++++++++++-- .../tap/features/home/redux/HomeMiddleware.kt | 2 ++ .../features/wallet/ui/dialogs/ScanFailsDialog.kt | 3 +++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/features/home/HomeFragment.kt b/app/src/main/java/com/tangem/tap/features/home/HomeFragment.kt index 839c7a3828..313471aa5d 100644 --- a/app/src/main/java/com/tangem/tap/features/home/HomeFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/home/HomeFragment.kt @@ -11,6 +11,8 @@ import androidx.compose.ui.platform.ComposeView import androidx.core.view.WindowInsetsControllerCompat import androidx.fragment.app.Fragment import com.google.accompanist.appcompattheme.AppCompatTheme +import com.tangem.tap.common.analytics.Analytics +import com.tangem.tap.common.analytics.events.IntroductionProcess import com.tangem.tap.common.redux.navigation.AppScreen import com.tangem.tap.common.redux.navigation.NavigationAction import com.tangem.tap.features.home.compose.StoriesScreen @@ -27,6 +29,7 @@ class HomeFragment : Fragment(), StoreSubscriber { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + Analytics.send(IntroductionProcess.ScreenOpened()) store.dispatch(HomeAction.Init) } @@ -78,9 +81,16 @@ class HomeFragment : Fragment(), StoreSubscriber { private fun ScreenContent() { StoriesScreen( homeState, - onScanButtonClick = { store.dispatch(HomeAction.ReadCard) }, - onShopButtonClick = { store.dispatch(HomeAction.GoToShop(store.state.globalState.userCountryCode)) }, + onScanButtonClick = { + Analytics.send(IntroductionProcess.ButtonScanCard()) + store.dispatch(HomeAction.ReadCard) + }, + onShopButtonClick = { + Analytics.send(IntroductionProcess.ButtonBuyCards()) + store.dispatch(HomeAction.GoToShop(store.state.globalState.userCountryCode)) + }, onSearchTokensClick = { + Analytics.send(IntroductionProcess.ButtonTokensList()) store.dispatch(NavigationAction.NavigateTo(AppScreen.AddTokens)) store.dispatch(TokensAction.AllowToAddTokens(false)) store.dispatch(TokensAction.LoadCurrencies()) 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 5a4e3d2ca2..460c05f0a2 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 @@ -14,6 +14,7 @@ import com.tangem.tap.common.analytics.AnalyticsEventAnOld import com.tangem.tap.common.analytics.AnalyticsParamAnOld import com.tangem.tap.common.analytics.GetCardSourceParamsAnOld import com.tangem.tap.common.analytics.events.AnalyticsParam +import com.tangem.tap.common.analytics.events.IntroductionProcess import com.tangem.tap.common.entities.IndeterminateProgressButton import com.tangem.tap.common.extensions.dispatchDialogShow import com.tangem.tap.common.extensions.dispatchOpenUrl @@ -161,6 +162,7 @@ private fun showDisclaimerIfNeed(scanResponse: ScanResponse, nextHandler: (ScanR } private fun onScanSuccess(scanResponse: ScanResponse) { + Analytics.send(IntroductionProcess.CardWasScanned()) val globalState = store.state.globalState val tapWalletManager = globalState.tapWalletManager tapWalletManager.updateConfigManager(scanResponse) diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/dialogs/ScanFailsDialog.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/dialogs/ScanFailsDialog.kt index 91afcc3819..d3bc64fa17 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/dialogs/ScanFailsDialog.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/dialogs/ScanFailsDialog.kt @@ -2,6 +2,8 @@ package com.tangem.tap.features.wallet.ui.dialogs import android.content.Context import androidx.appcompat.app.AlertDialog +import com.tangem.tap.common.analytics.Analytics +import com.tangem.tap.common.analytics.events.IntroductionProcess import com.tangem.tap.common.extensions.dispatchDialogHide import com.tangem.tap.common.feedback.ScanFailsEmail import com.tangem.tap.common.redux.global.GlobalAction @@ -19,6 +21,7 @@ class ScanFailsDialog { setTitle(context.getString(R.string.common_warning)) setMessage(R.string.alert_troubleshooting_scan_card_title) setPositiveButton(R.string.alert_button_request_support) { _, _ -> + Analytics.send(IntroductionProcess.ButtonRequestSupport()) store.dispatch(GlobalAction.SendEmail(ScanFailsEmail())) } setNeutralButton(R.string.alert_troubleshooting_scan_card_ok) { _, _ -> } From 1d5360126656ad9d84ed65566c1b1af5181025c2 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 31 Oct 2022 12:30:11 +0500 Subject: [PATCH 15/47] Updated on 2026-08-14 --- .../tap/common/extensions/WalletManager.kt | 5 ++--- .../note/redux/OnboardingNoteMiddleware.kt | 17 +++++++++++++++-- .../products/twins/redux/TwinCardsMiddleware.kt | 4 ++-- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/common/extensions/WalletManager.kt b/app/src/main/java/com/tangem/tap/common/extensions/WalletManager.kt index 15d02907bf..cda489f536 100644 --- a/app/src/main/java/com/tangem/tap/common/extensions/WalletManager.kt +++ b/app/src/main/java/com/tangem/tap/common/extensions/WalletManager.kt @@ -55,11 +55,10 @@ suspend fun WalletManager.safeUpdate(): Result = try { } } -fun WalletManager?.getToUpUrl(): String? { +fun WalletManager.getTopUpUrl(): String? { val globalState = store.state.globalState - val wallet = this?.wallet ?: return null - val defaultAddress = wallet.address + return globalState.exchangeManager.getUrl( action = CurrencyExchangeManager.Action.Buy, blockchain = wallet.blockchain, diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteMiddleware.kt index 6e1d907be1..ef0c5a743a 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteMiddleware.kt @@ -5,12 +5,14 @@ import com.tangem.common.extensions.guard import com.tangem.domain.common.extensions.withMainContext import com.tangem.tap.DELAY_SDK_DIALOG_CLOSE import com.tangem.tap.common.analytics.Analytics +import com.tangem.tap.common.analytics.events.AnalyticsParam import com.tangem.tap.common.analytics.events.Onboarding +import com.tangem.tap.common.extensions.dispatchDebugErrorNotification import com.tangem.tap.common.extensions.dispatchDialogShow import com.tangem.tap.common.extensions.dispatchErrorNotification import com.tangem.tap.common.extensions.dispatchOpenUrl import com.tangem.tap.common.extensions.getAddressData -import com.tangem.tap.common.extensions.getToUpUrl +import com.tangem.tap.common.extensions.getTopUpUrl import com.tangem.tap.common.extensions.onCardScanned import com.tangem.tap.common.postUi import com.tangem.tap.common.redux.AppDialog @@ -85,6 +87,7 @@ private fun handleNoteAction(appState: () -> AppState?, action: Action, dispatch Analytics.send(Onboarding.CreateWallet.ScreenOpened()) } OnboardingNoteStep.TopUpWallet -> { + Analytics.send(Onboarding.Topup.ScreenOpened()) store.dispatch(OnboardingNoteAction.Balance.Update) } OnboardingNoteStep.Done -> { @@ -159,11 +162,21 @@ private fun handleNoteAction(appState: () -> AppState?, action: Action, dispatch is OnboardingNoteAction.ShowAddressInfoDialog -> { val addressData = noteState.walletManager?.getAddressData() ?: return + Analytics.send(Onboarding.Topup.ButtonShowWalletAddress()) val appDialog = AppDialog.AddressInfoDialog(noteState.walletBalance.currency, addressData) store.dispatchDialogShow(appDialog) } is OnboardingNoteAction.TopUp -> { - val topUpUrl = noteState.walletManager?.getToUpUrl() ?: return + val walletManager = noteState.walletManager.guard { + store.dispatchDebugErrorNotification("NPE: WalletManager") + return + } + + val blockchain = walletManager.wallet.blockchain + val currencyType = AnalyticsParam.CurrencyType.Blockchain(blockchain) + Analytics.send(Onboarding.Topup.ButtonBuyCrypto(currencyType)) + + val topUpUrl = walletManager.getTopUpUrl() ?: return store.dispatchOpenUrl(topUpUrl) } OnboardingNoteAction.Done -> { diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt index a872bfef97..83514174a1 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt @@ -12,7 +12,7 @@ import com.tangem.tap.common.extensions.dispatchDialogShow import com.tangem.tap.common.extensions.dispatchErrorNotification import com.tangem.tap.common.extensions.dispatchOpenUrl import com.tangem.tap.common.extensions.getAddressData -import com.tangem.tap.common.extensions.getToUpUrl +import com.tangem.tap.common.extensions.getTopUpUrl import com.tangem.tap.common.extensions.onCardScanned import com.tangem.tap.common.postUi import com.tangem.tap.common.redux.AppDialog @@ -268,7 +268,7 @@ private fun handle(action: Action, dispatch: DispatchFunction) { store.dispatchDialogShow(appDialog) } is TwinCardsAction.TopUp -> { - val topUpUrl = twinCardsState.walletManager?.getToUpUrl() ?: return + val topUpUrl = twinCardsState.walletManager?.getTopUpUrl() ?: return store.dispatchOpenUrl(topUpUrl) } TwinCardsAction.Done -> { From 67ad64b128a598313bd884542de69ebdf545b0e7 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 31 Oct 2022 12:44:29 +0500 Subject: [PATCH 16/47] Updated on 2026-08-14 --- .../products/twins/redux/TwinCardsMiddleware.kt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt index 83514174a1..bf3cb1296c 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt @@ -139,8 +139,10 @@ private fun handle(action: Action, dispatch: DispatchFunction) { } is TwinCardsAction.SetStepOfScreen -> { when (action.step) { - TwinCardsStep.WelcomeOnly -> preferencesStorage.saveTwinsOnboardingShown() - TwinCardsStep.Welcome -> preferencesStorage.saveTwinsOnboardingShown() + TwinCardsStep.WelcomeOnly, TwinCardsStep.Welcome -> { + Analytics.send(Onboarding.Twins.ScreenOpened()) + preferencesStorage.saveTwinsOnboardingShown() + } TwinCardsStep.TopUpWallet -> store.dispatch(TwinCardsAction.Balance.Update) TwinCardsStep.Done -> { finishCardActivation() @@ -149,6 +151,7 @@ private fun handle(action: Action, dispatch: DispatchFunction) { } } is TwinCardsAction.Wallet.LaunchFirstStep -> { + Analytics.send(Onboarding.Twins.SetupStarted()) val manager = TwinCardsManager( card = getScanResponse().card, assetReader = action.reader, @@ -199,6 +202,7 @@ private fun handle(action: Action, dispatch: DispatchFunction) { scope.launch { when (val result = manager.complete(action.message)) { is Result.Success -> { + Analytics.send(Onboarding.Twins.SetupFinished()) updateScanResponse(result.data) delay(DELAY_SDK_DIALOG_CLOSE) withMainContext { From 8f61c0b19f91cc65edfbec1672c9dfaad46aaf1c Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 31 Oct 2022 15:45:44 +0500 Subject: [PATCH 17/47] Updated on 2026-08-14 --- .../common/analytics/events/AnalyticsParam.kt | 9 ---- .../tap/common/analytics/events/Settings.kt | 6 ++- .../details/ui/details/DetailsFragment.kt | 4 +- .../details/ui/details/DetailsScreen.kt | 8 +-- .../details/ui/details/DetailsScreenState.kt | 50 +++++++++++-------- .../details/ui/details/DetailsViewModel.kt | 14 ++++-- .../walletconnect/WalletConnectViewModel.kt | 8 ++- 7 files changed, 59 insertions(+), 40 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/common/analytics/events/AnalyticsParam.kt b/app/src/main/java/com/tangem/tap/common/analytics/events/AnalyticsParam.kt index 8c69239429..cca03e068f 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/events/AnalyticsParam.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/events/AnalyticsParam.kt @@ -41,15 +41,6 @@ sealed class AnalyticsParam { object LongTap : SecurityMode("Long Tap") } - sealed class SocialNetwork(val value: String) { - object Facebook : SocialNetwork("Facebook") - object Instagram : SocialNetwork("Instagram") - object Youtube : SocialNetwork("Youtube") - object Twitter : SocialNetwork("Twitter") - object LinkedIn : SocialNetwork("LinkedIn") - object GitHub : SocialNetwork("GitHub") - } - companion object Key { const val Blockchain = "blockchain" const val BatchId = "batch_id" diff --git a/app/src/main/java/com/tangem/tap/common/analytics/events/Settings.kt b/app/src/main/java/com/tangem/tap/common/analytics/events/Settings.kt index 56893d2f31..fff6794867 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/events/Settings.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/events/Settings.kt @@ -1,5 +1,7 @@ package com.tangem.tap.common.analytics.events +import com.tangem.tap.features.details.ui.details.SocialNetwork + /** [REDACTED_AUTHOR] */ @@ -18,9 +20,9 @@ sealed class Settings( class ButtonAppSettings : Settings(event = "Button - App Settings") class ButtonCreateBackup : Settings(event = "Button - Create Backup") - sealed class ButtonSocialNetwork(network: AnalyticsParam.SocialNetwork) : Settings( + class ButtonSocialNetwork(network: SocialNetwork) : Settings( event = "Button - Social Network", - params = mapOf("Network" to network.value), + params = mapOf("Network" to network.id), ) sealed class CardSettings( diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsFragment.kt b/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsFragment.kt index 6674371319..2c206736e5 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsFragment.kt @@ -10,6 +10,8 @@ import androidx.compose.ui.platform.ComposeView import androidx.fragment.app.Fragment import androidx.transition.TransitionInflater import com.google.accompanist.appcompattheme.AppCompatTheme +import com.tangem.tap.common.analytics.Analytics +import com.tangem.tap.common.analytics.events.Settings import com.tangem.tap.common.redux.navigation.NavigationAction import com.tangem.tap.features.details.redux.DetailsState import com.tangem.tap.store @@ -24,7 +26,7 @@ class DetailsFragment : Fragment(), StoreSubscriber { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - + Analytics.send(Settings.ScreenOpened()) val inflater = TransitionInflater.from(requireContext()) enterTransition = inflater.inflateTransition(android.R.transition.fade) exitTransition = inflater.inflateTransition(android.R.transition.fade) diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsScreen.kt b/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsScreen.kt index e0b4f1f186..47946d1e73 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsScreen.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsScreen.kt @@ -162,8 +162,8 @@ fun DetailsItem( @Composable fun TangemSocialAccounts( - links: List, - onSocialNetworkClick: (String) -> Unit, + links: List, + onSocialNetworkClick: (SocialNetworkLink) -> Unit, modifier: Modifier = Modifier, ) { LazyRow( @@ -171,11 +171,11 @@ fun TangemSocialAccounts( ) { items(links) { Icon( - painter = painterResource(id = it.iconRes), + painter = painterResource(id = it.network.iconRes), contentDescription = "", modifier = modifier .padding(8.dp) - .clickable { onSocialNetworkClick(it.url) }, + .clickable { onSocialNetworkClick(it) }, tint = colorResource(id = R.color.icon_informative), ) } diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsScreenState.kt b/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsScreenState.kt index 1962a53261..a92efc7e2b 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsScreenState.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsScreenState.kt @@ -4,11 +4,11 @@ import com.tangem.wallet.R data class DetailsScreenState( val elements: List, - val tangemLinks: List, + val tangemLinks: List, val tangemVersion: String, val appCurrency: String, val onItemsClick: (SettingsElement) -> Unit, - val onSocialNetworkClick: (String) -> Unit, + val onSocialNetworkClick: (SocialNetworkLink) -> Unit, ) { val appNameRes: Int = R.string.app_name } @@ -30,28 +30,38 @@ enum class SettingsElement( ; } -data class TangemLink( - val iconRes: Int, +data class SocialNetworkLink( + val network: SocialNetwork, val url: String, ) +sealed class SocialNetwork(val id: String, val iconRes: Int) { + object Telegram : SocialNetwork("Telegram", R.drawable.ic_telegram) + object Twitter : SocialNetwork("Twitter", R.drawable.ic_twitter) + object Facebook : SocialNetwork("Facebook", R.drawable.ic_facebook) + object Instagram : SocialNetwork("Instagram", R.drawable.ic_instagram) + object GitHub : SocialNetwork("GitHub", R.drawable.ic_github) + object Youtube : SocialNetwork("Youtube", R.drawable.ic_youtube) + object LinkedIn : SocialNetwork("LinkedIn", R.drawable.ic_linkedin) +} + object TangemSocialAccounts { - val accountsEn: List = listOf( - TangemLink(R.drawable.ic_telegram, "https://t.me/TangemCards"), - TangemLink(R.drawable.ic_twitter, "https://twitter.com/tangem"), - TangemLink(R.drawable.ic_facebook, "https://m.facebook.com/TangemCards/"), - TangemLink(R.drawable.ic_instagram, "https://instagram.com/tangemcards"), - TangemLink(R.drawable.ic_github, "https://github.com/tangem"), - TangemLink(R.drawable.ic_youtube, "https://youtube.com/channel/UCFGwLS7yggzVkP6ozte0m1w"), - TangemLink(R.drawable.ic_linkedin, "https://www.linkedin.com/company/tangem"), + val accountsEn: List = listOf( + SocialNetworkLink(SocialNetwork.Telegram, "https://t.me/TangemCards"), + SocialNetworkLink(SocialNetwork.Twitter, "https://twitter.com/tangem"), + SocialNetworkLink(SocialNetwork.Facebook, "https://m.facebook.com/TangemCards/"), + SocialNetworkLink(SocialNetwork.Instagram, "https://instagram.com/tangemcards"), + SocialNetworkLink(SocialNetwork.GitHub, "https://github.com/tangem"), + SocialNetworkLink(SocialNetwork.Youtube, "https://youtube.com/channel/UCFGwLS7yggzVkP6ozte0m1w"), + SocialNetworkLink(SocialNetwork.LinkedIn, "https://www.linkedin.com/company/tangem"), ) - val accountsRu: List = listOf( - TangemLink(R.drawable.ic_telegram, "https://t.me/tangem_ru"), - TangemLink(R.drawable.ic_twitter, "https://twitter.com/tangem"), - TangemLink(R.drawable.ic_facebook, "https://m.facebook.com/TangemCards/"), - TangemLink(R.drawable.ic_instagram, "https://instagram.com/tangemcards"), - TangemLink(R.drawable.ic_github, "https://github.com/tangem"), - TangemLink(R.drawable.ic_youtube, "https://youtube.com/channel/UCFGwLS7yggzVkP6ozte0m1w"), - TangemLink(R.drawable.ic_linkedin, "https://www.linkedin.com/company/tangem"), + val accountsRu: List = listOf( + SocialNetworkLink(SocialNetwork.Telegram, "https://t.me/tangem_ru"), + SocialNetworkLink(SocialNetwork.Twitter, "https://twitter.com/tangem"), + SocialNetworkLink(SocialNetwork.Facebook, "https://m.facebook.com/TangemCards/"), + SocialNetworkLink(SocialNetwork.Instagram, "https://instagram.com/tangemcards"), + SocialNetworkLink(SocialNetwork.GitHub, "https://github.com/tangem"), + SocialNetworkLink(SocialNetwork.Youtube, "https://youtube.com/channel/UCFGwLS7yggzVkP6ozte0m1w"), + SocialNetworkLink(SocialNetwork.LinkedIn, "https://www.linkedin.com/company/tangem"), ) } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsViewModel.kt b/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsViewModel.kt index 1de39fa063..c48aeab31d 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsViewModel.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsViewModel.kt @@ -2,6 +2,8 @@ package com.tangem.tap.features.details.ui.details import com.tangem.domain.common.TapWorkarounds.isSaltPay import com.tangem.domain.common.TapWorkarounds.isStart2Coin +import com.tangem.tap.common.analytics.Analytics +import com.tangem.tap.common.analytics.events.Settings import com.tangem.tap.common.feedback.FeedbackEmail import com.tangem.tap.common.feedback.SupportInfo import com.tangem.tap.common.redux.AppState @@ -51,8 +53,9 @@ class DetailsViewModel(private val store: Store) { ) } - private fun handleSocialNetworkClick(url: String) { - store.dispatch(NavigationAction.OpenUrl(url)) + private fun handleSocialNetworkClick(link: SocialNetworkLink) { + Analytics.send(Settings.ButtonSocialNetwork(link.network)) + store.dispatch(NavigationAction.OpenUrl(link.url)) } private fun handleClickingSettingsItem(item: SettingsElement) { @@ -61,21 +64,26 @@ class DetailsViewModel(private val store: Store) { store.dispatch(NavigationAction.NavigateTo(AppScreen.WalletConnectSessions)) } SettingsElement.Chat -> { + Analytics.send(Settings.ButtonChat()) store.dispatch(GlobalAction.OpenChat(SupportInfo())) } SettingsElement.SendFeedback -> { + Analytics.send(Settings.ButtonSendFeedback()) store.dispatch(GlobalAction.SendEmail(FeedbackEmail())) } SettingsElement.CardSettings -> { + Analytics.send(Settings.ButtonCardSettings()) store.dispatch(NavigationAction.NavigateTo(AppScreen.CardSettings)) } SettingsElement.AppCurrency -> { store.dispatch(WalletAction.AppCurrencyAction.ChooseAppCurrency) } SettingsElement.AppSettings -> { + Analytics.send(Settings.ButtonAppSettings()) store.dispatch(NavigationAction.NavigateTo(AppScreen.AppSettings)) //TODO: To be available later } SettingsElement.LinkMoreCards -> { + Analytics.send(Settings.ButtonCreateBackup()) store.dispatch(DetailsAction.CreateBackup) } SettingsElement.TermsOfService -> { @@ -90,7 +98,7 @@ class DetailsViewModel(private val store: Store) { } } - private fun getSocialLinks(): List { + private fun getSocialLinks(): List { val locale = LocaleRegionProvider().getRegion() return if (locale.lowercase() == RUSSIA_COUNTRY_CODE) { TangemSocialAccounts.accountsRu diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectViewModel.kt b/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectViewModel.kt index 6bbde4c1ae..9f4c8dd659 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectViewModel.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectViewModel.kt @@ -1,5 +1,7 @@ package com.tangem.tap.features.details.ui.walletconnect +import com.tangem.tap.common.analytics.Analytics +import com.tangem.tap.common.analytics.events.Settings import com.tangem.tap.common.redux.AppState import com.tangem.tap.features.details.redux.walletconnect.WalletConnectAction import com.tangem.tap.features.details.redux.walletconnect.WalletConnectSession @@ -12,7 +14,10 @@ class WalletConnectViewModel(private val store: Store) { state.sessions.map { wcSession -> WcSessionForScreen.fromSession(wcSession) }, isLoading = state.loading, onRemoveSession = { sessionUri -> onRemoveSession(sessionUri, state.sessions) }, - onAddSession = { copiedUri -> store.dispatch(WalletConnectAction.StartWalletConnect(copiedUri)) }, + onAddSession = { copiedUri -> + Analytics.send(Settings.ButtonStartWalletConnectSession()) + store.dispatch(WalletConnectAction.StartWalletConnect(copiedUri)) + }, ) } @@ -20,6 +25,7 @@ class WalletConnectViewModel(private val store: Store) { sessions .firstOrNull { it.session.toUri() == sessionUri } ?.let { baseSession -> + Analytics.send(Settings.ButtonStopWalletConnectSession()) store.dispatch(WalletConnectAction.DisconnectSession(baseSession.session)) } } From 1b2c087d0858b0c973bdac26963a9b85ae8f57fc Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 31 Oct 2022 15:49:34 +0500 Subject: [PATCH 18/47] Updated on 2026-08-14 --- .../ui/walletconnect/WalletConnectScreen.kt | 14 ++++++++++++-- .../ui/walletconnect/WalletConnectViewModel.kt | 8 +------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectScreen.kt b/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectScreen.kt index 168bd4a024..499f31ddcf 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectScreen.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectScreen.kt @@ -30,6 +30,8 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import com.tangem.tap.common.analytics.Analytics +import com.tangem.tap.common.analytics.events.Settings import com.tangem.tap.common.compose.TangemTypography import com.tangem.tap.common.extensions.getFromClipboard import com.tangem.tap.features.details.ui.common.SettingsScreensScaffold @@ -53,7 +55,12 @@ fun WalletConnectScreen( }, fab = { if (!state.isLoading) { - AddSessionFab(onAddSession = { state.onAddSession(context.getFromClipboard()?.toString()) }) + AddSessionFab( + onAddSession = { + Analytics.send(Settings.ButtonStartWalletConnectSession()) + state.onAddSession(context.getFromClipboard()?.toString()) + }, + ) } }, titleRes = R.string.wallet_connect_title, @@ -147,7 +154,10 @@ private fun WalletConnectSessions( modifier = modifier.weight(1f), ) IconButton( - onClick = { state.onRemoveSession(session.sessionId) }, + onClick = { + Analytics.send(Settings.ButtonStopWalletConnectSession()) + state.onRemoveSession(session.sessionId) + }, ) { Icon( painter = painterResource(id = R.drawable.ic_cross_rounded_24), diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectViewModel.kt b/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectViewModel.kt index 9f4c8dd659..6bbde4c1ae 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectViewModel.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/walletconnect/WalletConnectViewModel.kt @@ -1,7 +1,5 @@ package com.tangem.tap.features.details.ui.walletconnect -import com.tangem.tap.common.analytics.Analytics -import com.tangem.tap.common.analytics.events.Settings import com.tangem.tap.common.redux.AppState import com.tangem.tap.features.details.redux.walletconnect.WalletConnectAction import com.tangem.tap.features.details.redux.walletconnect.WalletConnectSession @@ -14,10 +12,7 @@ class WalletConnectViewModel(private val store: Store) { state.sessions.map { wcSession -> WcSessionForScreen.fromSession(wcSession) }, isLoading = state.loading, onRemoveSession = { sessionUri -> onRemoveSession(sessionUri, state.sessions) }, - onAddSession = { copiedUri -> - Analytics.send(Settings.ButtonStartWalletConnectSession()) - store.dispatch(WalletConnectAction.StartWalletConnect(copiedUri)) - }, + onAddSession = { copiedUri -> store.dispatch(WalletConnectAction.StartWalletConnect(copiedUri)) }, ) } @@ -25,7 +20,6 @@ class WalletConnectViewModel(private val store: Store) { sessions .firstOrNull { it.session.toUri() == sessionUri } ?.let { baseSession -> - Analytics.send(Settings.ButtonStopWalletConnectSession()) store.dispatch(WalletConnectAction.DisconnectSession(baseSession.session)) } } From e4ff41dc503e7fc84792d8354e144456e8a8d364 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 31 Oct 2022 20:25:53 +0500 Subject: [PATCH 19/47] Updated on 2026-08-14 --- .../tap/common/analytics/events/AnalyticsParam.kt | 10 ++++++++++ .../tangem/tap/common/analytics/events/Settings.kt | 4 ++-- .../tap/features/details/redux/DetailsMiddleware.kt | 12 +++++++++++- .../details/ui/cardsettings/CardSettingsViewModel.kt | 6 ++++++ 4 files changed, 29 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/common/analytics/events/AnalyticsParam.kt b/app/src/main/java/com/tangem/tap/common/analytics/events/AnalyticsParam.kt index cca03e068f..5e3f8a81c5 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/events/AnalyticsParam.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/events/AnalyticsParam.kt @@ -1,5 +1,7 @@ package com.tangem.tap.common.analytics.events +import com.tangem.tap.features.details.redux.SecurityOption + sealed class AnalyticsParam { sealed class CurrencyType(val value: String) { @@ -39,6 +41,14 @@ sealed class AnalyticsParam { object AccessCode : SecurityMode("Access Code") object Passcode : SecurityMode("Passcode") object LongTap : SecurityMode("Long Tap") + + companion object { + fun from(option: SecurityOption): SecurityMode = when(option){ + SecurityOption.AccessCode -> AccessCode + SecurityOption.PassCode -> Passcode + SecurityOption.LongTap -> LongTap + } + } } companion object Key { diff --git a/app/src/main/java/com/tangem/tap/common/analytics/events/Settings.kt b/app/src/main/java/com/tangem/tap/common/analytics/events/Settings.kt index fff6794867..b24d6ef042 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/events/Settings.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/events/Settings.kt @@ -35,12 +35,12 @@ sealed class Settings( class UserCodeChanged : CardSettings("User Code Changed") class ButtonChangeSecurityMode : CardSettings("Button - Change Security Mode") - sealed class ButtonChangeUserCode(type: AnalyticsParam.UserCode) : CardSettings( + class ButtonChangeUserCode(type: AnalyticsParam.UserCode) : CardSettings( event = "Button - Change User Code", params = mapOf("Type" to type.value), ) - sealed class SecurityModeChanged(mode: AnalyticsParam.SecurityMode) : CardSettings( + class SecurityModeChanged(mode: AnalyticsParam.SecurityMode) : CardSettings( event = "Security Mode Changed", params = mapOf("Mode" to mode.value), ) 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 6df912853f..13caeece31 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 @@ -6,6 +6,8 @@ import com.tangem.domain.common.TapWorkarounds.isTangemTwins import com.tangem.tap.common.analytics.Analytics import com.tangem.tap.common.analytics.AnalyticsAnOld import com.tangem.tap.common.analytics.AnalyticsParamAnOld +import com.tangem.tap.common.analytics.events.AnalyticsParam +import com.tangem.tap.common.analytics.events.Settings import com.tangem.tap.common.extensions.dispatchNotification import com.tangem.tap.common.extensions.dispatchOnMain import com.tangem.tap.common.redux.AppState @@ -107,6 +109,7 @@ class DetailsMiddleware { val result = tangemSdkManager.resetToFactorySettings(card) when (result) { is CompletionResult.Success -> { + Analytics.send(Settings.CardSettings.FactoryResetFinished()) store.dispatchOnMain(NavigationAction.PopBackTo(AppScreen.Home)) } is CompletionResult.Failure -> { @@ -133,6 +136,10 @@ class DetailsMiddleware { is DetailsAction.ManageSecurity.OpenSecurity -> { store.dispatch(NavigationAction.NavigateTo(AppScreen.DetailsSecurity)) } + is DetailsAction.ManageSecurity.SelectOption -> { + val modeParam = AnalyticsParam.SecurityMode.from(action.option) + Analytics.send(Settings.CardSettings.SecurityModeChanged(modeParam)) + } is DetailsAction.ManageSecurity.SaveChanges -> { val cardId = store.state.detailsState.scanResponse?.card?.cardId val selectedOption = @@ -176,7 +183,10 @@ class DetailsMiddleware { is DetailsAction.ManageSecurity.ChangeAccessCode -> { val card = store.state.detailsState.cardSettingsState?.card ?: return scope.launch { - tangemSdkManager.setAccessCode(card.cardId) + when(tangemSdkManager.setAccessCode(card.cardId)){ + is CompletionResult.Success -> Analytics.send(Settings.CardSettings.UserCodeChanged()) + is CompletionResult.Failure -> {} + } } } else -> { /* no-op */ diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/CardSettingsViewModel.kt b/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/CardSettingsViewModel.kt index b238ffe8f2..44f5cdb8d2 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/CardSettingsViewModel.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/CardSettingsViewModel.kt @@ -2,6 +2,9 @@ package com.tangem.tap.features.details.ui.cardsettings import com.tangem.domain.common.TapWorkarounds.isTangemTwins import com.tangem.domain.common.getTwinCardIdForUser +import com.tangem.tap.common.analytics.Analytics +import com.tangem.tap.common.analytics.events.AnalyticsParam +import com.tangem.tap.common.analytics.events.Settings import com.tangem.tap.common.redux.AppState import com.tangem.tap.features.details.redux.CardSettingsState import com.tangem.tap.features.details.redux.DetailsAction @@ -59,12 +62,15 @@ class CardSettingsViewModel(private val store: Store) { private fun handleClickingItem(item: CardInfo) { when (item) { is CardInfo.ChangeAccessCode -> { + Analytics.send(Settings.CardSettings.ButtonChangeUserCode(AnalyticsParam.UserCode.AccessCode)) store.dispatch(DetailsAction.ManageSecurity.ChangeAccessCode) } is CardInfo.ResetToFactorySettings -> { + Analytics.send(Settings.CardSettings.ButtonFactoryReset()) store.dispatch(DetailsAction.ResetToFactory.Start) } is CardInfo.SecurityMode -> { + Analytics.send(Settings.CardSettings.ButtonChangeSecurityMode()) store.dispatch(DetailsAction.ManageSecurity.OpenSecurity) } else -> {} From d7b674ea892ebbf31114df58d944ee1c723b86c6 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 1 Nov 2022 14:07:13 +0500 Subject: [PATCH 20/47] Updated on 2026-08-14 --- .../common/analytics/events/AnalyticsParam.kt | 4 +- .../common/analytics/events/ManageTokens.kt | 46 ++++++++-- .../addCustomToken/AddCustomTokenFragment.kt | 28 +++--- .../features/tokens/redux/TokensMiddleware.kt | 4 + .../features/tokens/ui/AddTokensFragment.kt | 54 ++++++----- .../tokens/ui/compose/CurrenciesScreen.kt | 91 +++++++++++++------ 6 files changed, 159 insertions(+), 68 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/common/analytics/events/AnalyticsParam.kt b/app/src/main/java/com/tangem/tap/common/analytics/events/AnalyticsParam.kt index 5e3f8a81c5..9996f479b7 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/events/AnalyticsParam.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/events/AnalyticsParam.kt @@ -10,7 +10,7 @@ sealed class AnalyticsParam { class Token(token: com.tangem.blockchain.common.Token) : CurrencyType(token.symbol) } - // Multicurrency or CurrencyType + // MultiCurrency or CurrencyType sealed class CardCurrency(val value: String) { object MultiCurrency : CardCurrency("Multicurrency") class SingleCurrency(type: CurrencyType) : CardCurrency(type.value) @@ -43,7 +43,7 @@ sealed class AnalyticsParam { object LongTap : SecurityMode("Long Tap") companion object { - fun from(option: SecurityOption): SecurityMode = when(option){ + fun from(option: SecurityOption): SecurityMode = when (option) { SecurityOption.AccessCode -> AccessCode SecurityOption.PassCode -> Passcode SecurityOption.LongTap -> LongTap diff --git a/app/src/main/java/com/tangem/tap/common/analytics/events/ManageTokens.kt b/app/src/main/java/com/tangem/tap/common/analytics/events/ManageTokens.kt index e5e3fdb96a..9f3ec194b7 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/events/ManageTokens.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/events/ManageTokens.kt @@ -1,5 +1,9 @@ package com.tangem.tap.common.analytics.events +import com.tangem.domain.common.extensions.toNetworkId +import com.tangem.domain.features.addCustomToken.CustomCurrency +import com.tangem.tap.common.extensions.filterNotNull + /** [REDACTED_AUTHOR] */ @@ -10,7 +14,18 @@ sealed class ManageTokens( class ScreenOpened : ManageTokens("Manage Tokens Screen Opened") class TokenSearched : ManageTokens("Token Searched") - class TokenSwitcherChanged : ManageTokens("Token Switcher Changed") + + class TokenSwitcherChanged( + type: AnalyticsParam.CurrencyType, + state: AnalyticsParam.OnOffState, + ) : ManageTokens( + "Token Switcher Changed", + params = mapOf( + "Token" to type.value, + "State" to state.value, + ), + ) + class ButtonSaveChanges : ManageTokens("Button - Save Changes") class ButtonCustomToken : ManageTokens("Button - Custom Token") @@ -21,13 +36,28 @@ sealed class ManageTokens( class ScreenOpened : ManageTokens("Custom Token Screen Opened") - class TokenWasAdded(symbol: String, network: String, address: String) : ManageTokens( + class TokenWasAdded(customCurrency: CustomCurrency) : ManageTokens( event = "Custom Token Was Added", - params = mapOf( - "Symbol" to symbol, - "Network" to network, - "Address" to address, - ), - ) + params = convertToParam(customCurrency), + ) { + companion object { + private fun convertToParam(customCurrency: CustomCurrency): Map = with(customCurrency) { + return when (this) { + is CustomCurrency.CustomBlockchain -> mapOf( + "Network" to network.toNetworkId(), + "Symbol" to network.currency, + "DerivationPath" to derivationPath?.rawPath, + ).filterNotNull() + is CustomCurrency.CustomToken -> mapOf( + "Network" to network.toNetworkId(), + "Symbol" to token.symbol, + "DerivationPath" to derivationPath?.rawPath, + "Token" to token.id, + "Address" to token.contractAddress, + ).filterNotNull() + } + } + } + } } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/addCustomToken/AddCustomTokenFragment.kt b/app/src/main/java/com/tangem/tap/features/tokens/addCustomToken/AddCustomTokenFragment.kt index 2192fd0477..3954882be5 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/addCustomToken/AddCustomTokenFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/addCustomToken/AddCustomTokenFragment.kt @@ -13,6 +13,8 @@ import androidx.compose.ui.platform.ComposeView import com.google.accompanist.appcompattheme.AppCompatTheme import com.tangem.domain.features.addCustomToken.redux.AddCustomTokenState import com.tangem.domain.redux.domainStore +import com.tangem.tap.common.analytics.Analytics +import com.tangem.tap.common.analytics.events.ManageTokens import com.tangem.tap.common.compose.ClosePopupTrigger import com.tangem.tap.features.BaseStoreFragment import com.tangem.tap.features.FragmentOnBackPressedHandler @@ -28,6 +30,11 @@ class AddCustomTokenFragment : BaseStoreFragment(R.layout.view_compose_fragment) private var state: MutableState = mutableStateOf(domainStore.state.addCustomTokensState) + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + Analytics.send(ManageTokens.CustomToken.ScreenOpened()) + } + override fun subscribeToStore() { domainStore.subscribe(this) { state -> state.skipRepeats { oldState, newState -> @@ -45,30 +52,29 @@ class AddCustomTokenFragment : BaseStoreFragment(R.layout.view_compose_fragment) override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - requireActivity().window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); - view.findViewById(R.id.toolbar)?.let { - it.setTitle(R.string.add_custom_token_title) - } + requireActivity().window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE) + view.findViewById(R.id.toolbar)?.setTitle(R.string.add_custom_token_title) val closePopupTrigger = initClosingPopupTriggerEvent() view.findViewById(R.id.view_compose)?.setContent { AppCompatTheme(requireContext()) { - Box(modifier = Modifier - .fillMaxSize() + Box( + modifier = Modifier + .fillMaxSize(), ) { AddCustomTokenScreen(state, closePopupTrigger) } } } - - } private fun initClosingPopupTriggerEvent(): ClosePopupTrigger = ClosePopupTrigger().apply { onCloseComplete = ::handleOnBackPressed - addBackPressHandler(object : FragmentOnBackPressedHandler { - override fun handleOnBackPressed() = close() - }) + addBackPressHandler( + object : FragmentOnBackPressedHandler { + override fun handleOnBackPressed() = close() + }, + ) } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensMiddleware.kt b/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensMiddleware.kt index 9817b4db49..7bf90e4bfd 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/redux/TokensMiddleware.kt @@ -21,6 +21,8 @@ import com.tangem.domain.redux.domainStore import com.tangem.operations.derivation.ExtendedPublicKeysMap import com.tangem.tap.DELAY_SDK_DIALOG_CLOSE import com.tangem.tap.assetReader +import com.tangem.tap.common.analytics.Analytics +import com.tangem.tap.common.analytics.events.ManageTokens import com.tangem.tap.common.extensions.dispatchDebugErrorNotification import com.tangem.tap.common.extensions.dispatchOnMain import com.tangem.tap.common.redux.AppState @@ -52,6 +54,7 @@ class TokensMiddleware { handleAddingCustomToken(action) } is TokensAction.SetSearchInput -> { + Analytics.send(ManageTokens.TokenSearched()) handleLoadCurrencies( scanResponse = store.state.globalState.scanResponse, newSearchInput = action.searchInput @@ -345,6 +348,7 @@ class TokensMiddleware { store.dispatchOnMain(NavigationAction.PopBackTo()) } + Analytics.send(ManageTokens.CustomToken.TokenWasAdded(customCurrency)) val currency = Currency.fromCustomCurrency(customCurrency) val isNeedToDerive = isNeedToDerive(scanResponse, currency) val currencyList = listOf(currency) diff --git a/app/src/main/java/com/tangem/tap/features/tokens/ui/AddTokensFragment.kt b/app/src/main/java/com/tangem/tap/features/tokens/ui/AddTokensFragment.kt index 9a9052115c..36b1f82337 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/ui/AddTokensFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/ui/AddTokensFragment.kt @@ -15,6 +15,8 @@ import androidx.transition.TransitionInflater import by.kirich1409.viewbindingdelegate.viewBinding import com.google.accompanist.appcompattheme.AppCompatTheme import com.tangem.blockchain.common.Blockchain +import com.tangem.tap.common.analytics.Analytics +import com.tangem.tap.common.analytics.events.ManageTokens import com.tangem.tap.common.extensions.copyToClipboard import com.tangem.tap.common.extensions.dispatchNotification import com.tangem.tap.common.extensions.dispatchOnMain @@ -48,12 +50,17 @@ class AddTokensFragment : Fragment(R.layout.fragment_add_tokens), override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setHasOptionsMenu(true) - activity?.onBackPressedDispatcher?.addCallback(this, object : OnBackPressedCallback(true) { - override fun handleOnBackPressed() { - store.dispatch(NavigationAction.PopBackTo()) - store.dispatch(TokensAction.ResetState) - } - }) + Analytics.send(ManageTokens.ScreenOpened()) + + activity?.onBackPressedDispatcher?.addCallback( + this, + object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + store.dispatch(NavigationAction.PopBackTo()) + store.dispatch(TokensAction.ResetState) + } + }, + ) val inflater = TransitionInflater.from(requireContext()) enterTransition = inflater.inflateTransition(R.transition.slide_right) exitTransition = inflater.inflateTransition(R.transition.fade) @@ -80,6 +87,7 @@ class AddTokensFragment : Fragment(R.layout.fragment_add_tokens), toolbar.setNavigationOnClickListener { activity?.onBackPressed() } val onSaveChanges = { tokens: List, blockchains: List -> + Analytics.send(ManageTokens.ButtonSaveChanges()) store.dispatch(TokensAction.SaveChanges(tokens, blockchains)) } val onNetworkItemClicked = { contractAddress: ContractAddress -> @@ -88,11 +96,11 @@ class AddTokensFragment : Fragment(R.layout.fragment_add_tokens), } val onLoadMore = { - store.dispatch( - TokensAction.LoadMore( - scanResponse = store.state.globalState.scanResponse - ) - ) + store.dispatch( + TokensAction.LoadMore( + scanResponse = store.state.globalState.scanResponse, + ), + ) } cvCurrencies.setContent { @@ -101,7 +109,7 @@ class AddTokensFragment : Fragment(R.layout.fragment_add_tokens), tokensState = tokensState, onSaveChanges = onSaveChanges, onNetworkItemClicked = onNetworkItemClicked, - onLoadMore = onLoadMore + onLoadMore = onLoadMore, ) } } @@ -119,6 +127,7 @@ class AddTokensFragment : Fragment(R.layout.fragment_add_tokens), return when (item.itemId) { R.id.menu_search -> true R.id.menu_navigate_add_custom_token -> { + Analytics.send(ManageTokens.ButtonCustomToken()) store.dispatch(TokensAction.PrepareAndNavigateToAddCustomToken) true } @@ -154,15 +163,18 @@ class AddTokensFragment : Fragment(R.layout.fragment_add_tokens), } fun SearchView.inputtedTextAsFlow(): Flow = callbackFlow { - val watcher = setOnQueryTextListener(object : SearchView.OnQueryTextListener { - override fun onQueryTextSubmit(query: String?): Boolean { - return false - } + val watcher = + setOnQueryTextListener( + object : SearchView.OnQueryTextListener { + override fun onQueryTextSubmit(query: String?): Boolean { + return false + } - override fun onQueryTextChange(newText: String?): Boolean { - trySend(newText ?: "") - return false - } - }) + override fun onQueryTextChange(newText: String?): Boolean { + trySend(newText ?: "") + return false + } + }, + ) awaitClose { (watcher) } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/CurrenciesScreen.kt b/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/CurrenciesScreen.kt index 49886cbf86..7cf23fb44c 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/CurrenciesScreen.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/ui/compose/CurrenciesScreen.kt @@ -8,8 +8,16 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding -import androidx.compose.material.* -import androidx.compose.runtime.* +import androidx.compose.material.CircularProgressIndicator +import androidx.compose.material.ExtendedFloatingActionButton +import androidx.compose.material.FabPosition +import androidx.compose.material.Scaffold +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color @@ -20,6 +28,9 @@ import androidx.compose.ui.unit.dp import com.tangem.blockchain.common.Blockchain import com.tangem.domain.common.TapWorkarounds.useOldStyleDerivation import com.tangem.domain.common.extensions.fromNetworkId +import com.tangem.tap.common.analytics.Analytics +import com.tangem.tap.common.analytics.events.AnalyticsParam +import com.tangem.tap.common.analytics.events.ManageTokens import com.tangem.tap.common.compose.Keyboard import com.tangem.tap.common.compose.extensions.addAndNotify import com.tangem.tap.common.compose.extensions.removeAndNotify @@ -41,7 +52,7 @@ fun CurrenciesScreen( tokensState: MutableState = mutableStateOf(store.state.tokensState), onSaveChanges: (List, List) -> Unit, onNetworkItemClicked: (ContractAddress) -> Unit, - onLoadMore: () -> Unit + onLoadMore: () -> Unit, ) { val tokensAddedOnMainScreen = remember { tokensState.value.addedTokens } val blockchainsAddedOnMainScreen = remember { tokensState.value.addedBlockchains } @@ -82,21 +93,21 @@ fun CurrenciesScreen( AnimatedVisibility( visible = tokensState.value.loadCoinsState == LoadCoinsState.LOADING, enter = fadeIn(), - exit = fadeOut() + exit = fadeOut(), ) { Box( contentAlignment = Alignment.Center, - modifier = Modifier.fillMaxSize() + modifier = Modifier.fillMaxSize(), ) { CircularProgressIndicator( - color = Color(0xFF1ACE80) + color = Color(0xFF1ACE80), ) } } AnimatedVisibility( visible = tokensState.value.loadCoinsState == LoadCoinsState.LOADED, enter = fadeIn(animationSpec = tween(1000)), - exit = fadeOut(animationSpec = tween(1000)) + exit = fadeOut(animationSpec = tween(1000)), ) { Column { val showHeader = tokensState.value.scanResponse?.card?.useOldStyleDerivation == true @@ -110,7 +121,7 @@ fun CurrenciesScreen( onAddCurrencyToggleClick(currency, token) }, onNetworkItemClicked = onNetworkItemClicked, - onLoadMore = onLoadMore + onLoadMore = onLoadMore, ) } } @@ -122,29 +133,39 @@ private fun toggleBlockchain( blockchain: Blockchain, blockchainsAddedOnMainScreen: List, addedBlockchainsState: MutableState>, - addedTokens: List + addedTokens: List, ) { val isTryingToRemove = addedBlockchainsState.value.contains(blockchain) val isAddedOnMainScreen = blockchainsAddedOnMainScreen.contains(blockchain) val isTokenWithSameBlockchainFound = addedTokens.any { it.blockchain == blockchain } + val analyticsCurrencyTypeParam = AnalyticsParam.CurrencyType.Blockchain(blockchain) if (isTryingToRemove) { if (isTokenWithSameBlockchainFound) { - store.dispatchDialogShow(WalletDialog.TokensAreLinkedDialog( - currencyTitle = blockchain.name, - currencySymbol = blockchain.currency - )) + store.dispatchDialogShow( + WalletDialog.TokensAreLinkedDialog( + currencyTitle = blockchain.name, + currencySymbol = blockchain.currency, + ), + ) } else { if (isAddedOnMainScreen) { - store.dispatchDialogShow(WalletDialog.RemoveWalletDialog( - currencyTitle = blockchain.name, - onOk = { addedBlockchainsState.removeAndNotify(blockchain) } - )) + store.dispatchDialogShow( + WalletDialog.RemoveWalletDialog( + currencyTitle = blockchain.name, + onOk = { + analyticsCurrencyTypeParam.sendOn() + addedBlockchainsState.removeAndNotify(blockchain) + }, + ), + ) } else { + analyticsCurrencyTypeParam.sendOff() addedBlockchainsState.removeAndNotify(blockchain) } } } else { + analyticsCurrencyTypeParam.sendOn() addedBlockchainsState.addAndNotify(blockchain) } } @@ -158,28 +179,46 @@ private fun toggleToken( val isTryingToRemove = addedTokensState.value.contains(token) val isAddedOnMainScreen = tokensAddedOnMainScreen.contains(token) val isUnsupportedToken = !tokensState.canHandleToken(token) + val analyticsCurrencyTypeParam = AnalyticsParam.CurrencyType.Token(token.token) if (isTryingToRemove) { if (isAddedOnMainScreen) { - store.dispatchDialogShow(WalletDialog.RemoveWalletDialog( - currencyTitle = token.token.name, - onOk = { addedTokensState.removeAndNotify(token) } - )) + store.dispatchDialogShow( + WalletDialog.RemoveWalletDialog( + currencyTitle = token.token.name, + onOk = { + analyticsCurrencyTypeParam.sendOff() + addedTokensState.removeAndNotify(token) + }, + ), + ) } else { + analyticsCurrencyTypeParam.sendOff() addedTokensState.removeAndNotify(token) } } else { if (isUnsupportedToken) { - store.dispatchDialogShow(AppDialog.SimpleOkDialogRes( - headerId = R.string.common_warning, - messageId = R.string.alert_manage_tokens_unsupported_message, - )) + store.dispatchDialogShow( + AppDialog.SimpleOkDialogRes( + headerId = R.string.common_warning, + messageId = R.string.alert_manage_tokens_unsupported_message, + ), + ) } else { + analyticsCurrencyTypeParam.sendOn() addedTokensState.addAndNotify(token) } } } +private fun AnalyticsParam.CurrencyType.sendOn() { + Analytics.send(ManageTokens.TokenSwitcherChanged(this, AnalyticsParam.OnOffState.On)) +} + +private fun AnalyticsParam.CurrencyType.sendOff() { + Analytics.send(ManageTokens.TokenSwitcherChanged(this, AnalyticsParam.OnOffState.Off)) +} + @Composable fun SaveChangesButton(keyboardState: Keyboard, onSaveChanges: () -> Unit) { @@ -198,6 +237,6 @@ fun SaveChangesButton(keyboardState: Keyboard, onSaveChanges: () -> Unit) { onClick = onSaveChanges, backgroundColor = colorResource(id = R.color.accent), contentColor = Color.White, - modifier = Modifier.padding(bottom = padding.dp) + modifier = Modifier.padding(bottom = padding.dp), ) } \ No newline at end of file From 7aa118cec40934fbf46e8bc58427e569d6df7d0f Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 1 Nov 2022 14:21:12 +0500 Subject: [PATCH 21/47] Updated on 2026-08-14 --- .../tangem/tap/common/analytics/events/ManageTokens.kt | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/common/analytics/events/ManageTokens.kt b/app/src/main/java/com/tangem/tap/common/analytics/events/ManageTokens.kt index 9f3ec194b7..77cfc78626 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/events/ManageTokens.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/events/ManageTokens.kt @@ -44,15 +44,13 @@ sealed class ManageTokens( private fun convertToParam(customCurrency: CustomCurrency): Map = with(customCurrency) { return when (this) { is CustomCurrency.CustomBlockchain -> mapOf( - "Network" to network.toNetworkId(), - "Symbol" to network.currency, + "Token" to network.currency, "DerivationPath" to derivationPath?.rawPath, ).filterNotNull() is CustomCurrency.CustomToken -> mapOf( - "Network" to network.toNetworkId(), - "Symbol" to token.symbol, + "Token" to token.symbol, "DerivationPath" to derivationPath?.rawPath, - "Token" to token.id, + "NetworkId" to network.toNetworkId(), "Address" to token.contractAddress, ).filterNotNull() } From a63f4797fe4cd999b236f0d902227e069956c1f2 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 1 Nov 2022 14:29:00 +0500 Subject: [PATCH 22/47] Updated on 2026-08-14 --- .../tangem/tap/features/details/redux/DetailsMiddleware.kt | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) 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 13caeece31..23edb2035c 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 @@ -136,10 +136,6 @@ class DetailsMiddleware { is DetailsAction.ManageSecurity.OpenSecurity -> { store.dispatch(NavigationAction.NavigateTo(AppScreen.DetailsSecurity)) } - is DetailsAction.ManageSecurity.SelectOption -> { - val modeParam = AnalyticsParam.SecurityMode.from(action.option) - Analytics.send(Settings.CardSettings.SecurityModeChanged(modeParam)) - } is DetailsAction.ManageSecurity.SaveChanges -> { val cardId = store.state.detailsState.scanResponse?.card?.cardId val selectedOption = @@ -155,6 +151,8 @@ class DetailsMiddleware { when (result) { is CompletionResult.Success -> { selectedOption?.let { + val paramValue = AnalyticsParam.SecurityMode.from(it) + Analytics.send(Settings.CardSettings.SecurityModeChanged(paramValue)) store.dispatch(GlobalAction.UpdateSecurityOptions(it)) } store.dispatch(NavigationAction.PopBackTo()) From 37648e0d92c35212ae385e880401c50b2c5e6b2e Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 1 Nov 2022 17:02:08 +0500 Subject: [PATCH 23/47] Updated on 2026-08-14 --- .../tangem/tap/common/analytics/events/ManageTokens.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/common/analytics/events/ManageTokens.kt b/app/src/main/java/com/tangem/tap/common/analytics/events/ManageTokens.kt index 77cfc78626..f944f58d24 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/events/ManageTokens.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/events/ManageTokens.kt @@ -45,13 +45,13 @@ sealed class ManageTokens( return when (this) { is CustomCurrency.CustomBlockchain -> mapOf( "Token" to network.currency, - "DerivationPath" to derivationPath?.rawPath, + "Derivation Path" to derivationPath?.rawPath, ).filterNotNull() is CustomCurrency.CustomToken -> mapOf( "Token" to token.symbol, - "DerivationPath" to derivationPath?.rawPath, - "NetworkId" to network.toNetworkId(), - "Address" to token.contractAddress, + "Derivation Path" to derivationPath?.rawPath, + "Network Id" to network.toNetworkId(), + "Contract Address" to token.contractAddress, ).filterNotNull() } } From 8a4a0d77e9bc4b97b05eab4ea973a873618d9e23 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 1 Nov 2022 17:10:55 +0500 Subject: [PATCH 24/47] Updated on 2026-08-14 --- .../java/com/tangem/tap/common/extensions/UI.kt | 3 ++- .../tap/features/wallet/ui/WalletFragment.kt | 3 +++ .../features/wallet/ui/adapters/WalletAdapter.kt | 14 ++++++++------ .../features/wallet/ui/wallet/MultiWalletView.kt | 3 +++ 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/common/extensions/UI.kt b/app/src/main/java/com/tangem/tap/common/extensions/UI.kt index 4be902ebf7..9e58542ecb 100644 --- a/app/src/main/java/com/tangem/tap/common/extensions/UI.kt +++ b/app/src/main/java/com/tangem/tap/common/extensions/UI.kt @@ -19,6 +19,7 @@ import android.view.inputmethod.InputMethodManager import androidx.annotation.ColorInt import androidx.annotation.ColorRes import androidx.annotation.DrawableRes +import androidx.annotation.PluralsRes import androidx.annotation.StringRes import androidx.core.content.ContextCompat import androidx.core.view.isVisible @@ -57,7 +58,7 @@ fun View.getString(@StringRes id: Int, vararg formatArgs: String): String { return context.getString(id, *formatArgs) } -fun View.getQuantityString(@StringRes id: Int, quantity: Int): String { +fun View.getQuantityString(@PluralsRes id: Int, quantity: Int): String { return context.resources.getQuantityString(id, quantity, quantity) } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt index 87a31563fa..a3d82b0de2 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt @@ -16,6 +16,8 @@ import coil.load import coil.size.Scale import com.tangem.domain.common.TapWorkarounds.isSaltPay import com.tangem.tap.MainActivity +import com.tangem.tap.common.analytics.Analytics +import com.tangem.tap.common.analytics.events.Portfolio import com.tangem.tap.common.extensions.show import com.tangem.tap.common.recyclerView.SpaceItemDecoration import com.tangem.tap.common.redux.global.GlobalAction @@ -152,6 +154,7 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber(DiffUtilCallback) { +class WalletAdapter : ListAdapter(DiffUtilCallback) { override fun getItemId(position: Int): Long { return currentList[position].currencyData.currencySymbol?.hashCode()?.toLong() ?: 0 @@ -30,7 +31,7 @@ class WalletAdapter fun submitList( list: List, primaryBlockchain: Blockchain?, - primaryToken: Token? = null + primaryToken: Token? = null, ) { // We used this method to sort the list of currencies. Sorting is disabled for now. super.submitList(list) @@ -38,7 +39,7 @@ class WalletAdapter override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): WalletsViewHolder { val layout = ItemCurrencyWalletBinding.inflate( - LayoutInflater.from(parent.context), parent, false + LayoutInflater.from(parent.context), parent, false, ) return WalletsViewHolder(layout) } @@ -49,11 +50,11 @@ class WalletAdapter object DiffUtilCallback : DiffUtil.ItemCallback() { override fun areContentsTheSame( - oldItem: WalletData, newItem: WalletData + oldItem: WalletData, newItem: WalletData, ) = oldItem == newItem override fun areItemsTheSame( - oldItem: WalletData, newItem: WalletData + oldItem: WalletData, newItem: WalletData, ) = oldItem == newItem } @@ -112,6 +113,7 @@ class WalletAdapter if (wallet.walletAddresses != null) { cardWallet.setOnClickListener { + Analytics.send(Portfolio.TokenTapped()) store.dispatch(WalletAction.MultiWallet.SelectWallet(wallet)) } } else { diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt index 9d4fe68894..891dba9126 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt @@ -6,6 +6,8 @@ import androidx.recyclerview.widget.LinearLayoutManager import com.tangem.common.card.Card import com.tangem.domain.common.TapWorkarounds.derivationStyle import com.tangem.domain.common.TapWorkarounds.isTestCard +import com.tangem.tap.common.analytics.Analytics +import com.tangem.tap.common.analytics.events.Portfolio import com.tangem.tap.common.extensions.animateVisibility import com.tangem.tap.common.extensions.formatAmountAsSpannedString import com.tangem.tap.common.extensions.getQuantityString @@ -85,6 +87,7 @@ class MultiWalletView : WalletView() { binding.btnAddToken.setOnClickListener { val card = store.state.globalState.scanResponse!!.card + Analytics.send(Portfolio.ButtonManageTokens()) store.dispatch( TokensAction.LoadCurrencies( supportedBlockchains = CurrenciesRepository.getBlockchains( From d57d48e68164f8c37ceade0e1ebee386421b3bb9 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 1 Nov 2022 18:03:12 +0500 Subject: [PATCH 25/47] Updated on 2026-08-14 --- .../tangem/tap/common/analytics/events/AnalyticsParam.kt | 1 + .../com/tangem/tap/common/analytics/events/MainScreen.kt | 2 +- .../wallet/redux/middlewares/AppCurrencyMiddleware.kt | 4 ++++ .../com/tangem/tap/features/wallet/ui/WalletFragment.kt | 6 ++++-- .../features/wallet/ui/adapters/WarningMessagesAdapter.kt | 5 +++++ .../tangem/tap/features/wallet/ui/wallet/MultiWalletView.kt | 3 +++ 6 files changed, 18 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/common/analytics/events/AnalyticsParam.kt b/app/src/main/java/com/tangem/tap/common/analytics/events/AnalyticsParam.kt index 9996f479b7..17b2a3484b 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/events/AnalyticsParam.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/events/AnalyticsParam.kt @@ -8,6 +8,7 @@ sealed class AnalyticsParam { class Currency(currency: com.tangem.tap.features.wallet.models.Currency) : CurrencyType(currency.currencySymbol) class Blockchain(blockchain: com.tangem.blockchain.common.Blockchain) : CurrencyType(blockchain.currency) class Token(token: com.tangem.blockchain.common.Token) : CurrencyType(token.symbol) + class FiatCurrency(fiatCurrency: com.tangem.tap.common.entities.FiatCurrency): CurrencyType(fiatCurrency.symbol) } // MultiCurrency or CurrencyType diff --git a/app/src/main/java/com/tangem/tap/common/analytics/events/MainScreen.kt b/app/src/main/java/com/tangem/tap/common/analytics/events/MainScreen.kt index c6825718b7..e19202bf4f 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/events/MainScreen.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/events/MainScreen.kt @@ -19,7 +19,7 @@ sealed class MainScreen( params = mapOf("Currency Type" to currencyType.value), ) - sealed class NoticeRateAppButton(result: AnalyticsParam.RateApp) : MainScreen( + class NoticeRateAppButton(result: AnalyticsParam.RateApp) : MainScreen( event = "Notice - Rate The App Button Tapped", params = mapOf("Result" to result.value), ) diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/AppCurrencyMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/AppCurrencyMiddleware.kt index f1fb6371cc..40613f791e 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/AppCurrencyMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/AppCurrencyMiddleware.kt @@ -3,6 +3,9 @@ package com.tangem.tap.features.wallet.redux.middlewares import com.tangem.common.services.Result import com.tangem.network.api.tangemTech.CurrenciesResponse import com.tangem.network.api.tangemTech.TangemTechService +import com.tangem.tap.common.analytics.Analytics +import com.tangem.tap.common.analytics.events.AnalyticsParam +import com.tangem.tap.common.analytics.events.MainScreen import com.tangem.tap.common.entities.FiatCurrency import com.tangem.tap.common.extensions.dispatchDialogShow import com.tangem.tap.common.redux.global.GlobalAction @@ -61,6 +64,7 @@ class AppCurrencyMiddleware( } private fun selectCurrency(action: WalletAction.AppCurrencyAction.SelectAppCurrency) { + Analytics.send(MainScreen.MainCurrencyChanged(AnalyticsParam.CurrencyType.FiatCurrency(action.fiatCurrency))) tapWalletManager.rates.clear() fiatCurrenciesPrefStorage.saveAppCurrency(action.fiatCurrency) store.dispatch(GlobalAction.ChangeAppCurrency(action.fiatCurrency)) diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt index a3d82b0de2..97fba31222 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt @@ -17,6 +17,7 @@ import coil.size.Scale import com.tangem.domain.common.TapWorkarounds.isSaltPay import com.tangem.tap.MainActivity import com.tangem.tap.common.analytics.Analytics +import com.tangem.tap.common.analytics.events.MainScreen import com.tangem.tap.common.analytics.events.Portfolio import com.tangem.tap.common.extensions.show import com.tangem.tap.common.recyclerView.SpaceItemDecoration @@ -54,6 +55,8 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber Date: Tue, 1 Nov 2022 19:14:20 +0500 Subject: [PATCH 26/47] Updated on 2026-08-14 --- .../tap/common/analytics/events/Token.kt | 32 +++++++++-- .../middlewares/MultiWalletMiddleware.kt | 2 + .../middlewares/TradeCryptoMiddleware.kt | 39 ++++++++----- .../middlewares/WalletDialogsMiddleware.kt | 12 +++- .../redux/middlewares/WalletMiddleware.kt | 2 + .../wallet/ui/WalletDetailsFragment.kt | 56 +++++++++++-------- 6 files changed, 98 insertions(+), 45 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/common/analytics/events/Token.kt b/app/src/main/java/com/tangem/tap/common/analytics/events/Token.kt index afe5da529a..b0c9a0db1d 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/events/Token.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/events/Token.kt @@ -1,5 +1,7 @@ package com.tangem.tap.common.analytics.events +import com.tangem.tap.common.analytics.events.AnalyticsParam.CurrencyType + /** [REDACTED_AUTHOR] */ @@ -12,10 +14,30 @@ sealed class Token( class Refreshed : Token("Token", "Refreshed") class ButtonRemoveToken : Token("Token", "Button - Remove Token") class ButtonExplore : Token("Token", "Button - Explore") - class ButtonBuy(token: String) : Token("Token", "Button - Buy", mapOf("Token" to token)) - class ButtonSell(token: String) : Token("Token", "Button - Sell", mapOf("Token" to token)) - class ButtonExchange(token: String) : Token("Token", "Button - Exchange", mapOf("Token" to token)) - class ButtonSend(token: String) : Token("Token", "Button - Send", mapOf("Token" to token)) + + class ButtonBuy(type: CurrencyType) : Token( + category = "Token", + event = "Button - Buy", + params = mapOf("Token" to type.value), + ) + + class ButtonSell(type: CurrencyType) : Token( + category = "Token", + event = "Button - Sell", + params = mapOf("Token" to type.value), + ) + + class ButtonExchange(type: CurrencyType) : Token( + category = "Token", + event = "Button - Exchange", + params = mapOf("Token" to type.value), + ) + + class ButtonSend(type: CurrencyType) : Token( + category = "Token", + event = "Button - Send", + params = mapOf("Token" to type.value), + ) sealed class Recieve( event: String, @@ -37,7 +59,7 @@ sealed class Token( class ButtonQRCode : Send("Button - QR Code") class ButtonSwapCurrency : Send("Button - Swap Currency") - class TransactionSent(token: AnalyticsParam.CurrencyType) : Send( + class TransactionSent(token: CurrencyType) : Send( event = "Transaction Sent", params = mapOf("Token" to token.value), ) diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt index ba68023190..3433d447d5 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt @@ -5,6 +5,7 @@ import com.tangem.blockchain.common.Token import com.tangem.blockchain.common.WalletManager import com.tangem.common.extensions.guard import com.tangem.domain.common.extensions.withMainContext +import com.tangem.tap.common.analytics.Analytics import com.tangem.tap.common.extensions.dispatchDialogShow import com.tangem.tap.common.extensions.dispatchErrorNotification import com.tangem.tap.common.extensions.safeUpdate @@ -109,6 +110,7 @@ class MultiWalletMiddleware { WalletDialog.RemoveWalletDialog( currencyTitle = currency.currencyName, onOk = { + Analytics.send(com.tangem.tap.common.analytics.events.Token.ButtonRemoveToken()) store.dispatch( WalletAction.MultiWallet.RemoveWallet( currency = currency, diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt index 319c940a52..182c75c9bd 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt @@ -2,6 +2,9 @@ package com.tangem.tap.features.wallet.redux.middlewares import com.tangem.blockchain.blockchains.ethereum.EthereumWalletManager import com.tangem.blockchain.common.AmountType +import com.tangem.tap.common.analytics.Analytics +import com.tangem.tap.common.analytics.events.AnalyticsParam +import com.tangem.tap.common.analytics.events.Token import com.tangem.tap.common.extensions.dispatchDebugErrorNotification import com.tangem.tap.common.extensions.dispatchOnMain import com.tangem.tap.common.redux.AppState @@ -19,7 +22,6 @@ import com.tangem.tap.scope import com.tangem.tap.store import kotlinx.coroutines.launch - class TradeCryptoMiddleware { fun handle(state: () -> AppState?, action: WalletAction.TradeCryptoAction) { if (DemoHelper.tryHandle(state, action)) return @@ -50,6 +52,7 @@ class TradeCryptoMiddleware { val exchangeManager = store.state.globalState.exchangeManager val appCurrency = store.state.globalState.appCurrency val currency = selectedWalletData.currency + Analytics.send(Token.ButtonBuy(AnalyticsParam.CurrencyType.Currency(currency))) if (currency is Currency.Token && currency.blockchain.isTestnet()) { val walletManager = store.state.walletState.getWalletManager(currency) @@ -62,7 +65,7 @@ class TradeCryptoMiddleware { exchangeManager.buyErc20TestnetTokens( card = card, walletManager = walletManager, - token = currency.token + token = currency.token, ) } return @@ -73,7 +76,7 @@ class TradeCryptoMiddleware { blockchain = currency.blockchain, cryptoCurrencyName = currency.currencySymbol, fiatCurrencyName = appCurrency.code, - walletAddress = addresses[0].address + walletAddress = addresses[0].address, )?.let { store.dispatchOnMain(NavigationAction.OpenUrl(it)) } } @@ -85,29 +88,37 @@ class TradeCryptoMiddleware { if (addresses.isEmpty()) return val currency = selectedWalletData.currency + Analytics.send(Token.ButtonSell(AnalyticsParam.CurrencyType.Currency(currency))) + store.state.globalState.exchangeManager.getUrl( action = CurrencyExchangeManager.Action.Sell, blockchain = currency.blockchain, cryptoCurrencyName = currency.currencySymbol, fiatCurrencyName = appCurrency.code, - walletAddress = addresses[0].address + walletAddress = addresses[0].address, )?.let { store.dispatchOnMain(NavigationAction.OpenUrl(it)) } } private fun preconfigureAndOpenSendScreen(action: WalletAction.TradeCryptoAction.SendCrypto) { val selectedWalletData = store.state.walletState.getSelectedWalletData() ?: return + Analytics.send(Token.ButtonSend(AnalyticsParam.CurrencyType.Currency(selectedWalletData.currency))) + val walletManager = store.state.walletState.getWalletManager(selectedWalletData.currency) - store.dispatchOnMain(PrepareSendScreen( - coinAmount = walletManager?.wallet?.amounts?.get(AmountType.Coin), - coinRate = selectedWalletData.fiatRate, - walletManager = walletManager - )) - store.dispatchOnMain(SendAction.SendSpecificTransaction( - sendAmount = action.amount, - destinationAddress = action.destinationAddress, - transactionId = action.transactionId - )) + store.dispatchOnMain( + PrepareSendScreen( + coinAmount = walletManager?.wallet?.amounts?.get(AmountType.Coin), + coinRate = selectedWalletData.fiatRate, + walletManager = walletManager, + ), + ) + store.dispatchOnMain( + SendAction.SendSpecificTransaction( + sendAmount = action.amount, + destinationAddress = action.destinationAddress, + transactionId = action.transactionId, + ), + ) store.dispatchOnMain(NavigationAction.NavigateTo(AppScreen.Send)) } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletDialogsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletDialogsMiddleware.kt index d53809be9c..64d2122fa2 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletDialogsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletDialogsMiddleware.kt @@ -1,5 +1,8 @@ package com.tangem.tap.features.wallet.redux.middlewares +import com.tangem.tap.common.analytics.Analytics +import com.tangem.tap.common.analytics.events.AnalyticsParam +import com.tangem.tap.common.analytics.events.Token import com.tangem.tap.common.extensions.dispatchDialogHide import com.tangem.tap.common.extensions.dispatchDialogShow import com.tangem.tap.common.redux.AppDialog @@ -14,6 +17,9 @@ class WalletDialogsMiddleware { store.dispatchDialogShow(WalletDialog.SignedHashesMultiWalletDialog) } is WalletAction.DialogAction.ChooseTradeActionDialog -> { + store.state.walletState.getSelectedWalletData()?.let { + Analytics.send(Token.ButtonExchange(AnalyticsParam.CurrencyType.Currency(it.currency))) + } store.dispatchDialogShow(WalletDialog.ChooseTradeActionDialog) } is WalletAction.DialogAction.QrCode -> { @@ -21,14 +27,14 @@ class WalletDialogsMiddleware { AppDialog.AddressInfoDialog( currency = action.currency, addressData = action.selectedAddress, - ) + ), ) } is WalletAction.DialogAction.ChooseCurrency -> { store.dispatchDialogShow( WalletDialog.SelectAmountToSendDialog( - amounts = action.amounts - ) + amounts = action.amounts, + ), ) } is WalletAction.DialogAction.RussianCardholdersWarningDialog -> { 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 157c8786b4..a4f353a6f7 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 @@ -13,6 +13,7 @@ import com.tangem.operations.attestation.Attestation import com.tangem.operations.attestation.OnlineCardVerifier import com.tangem.tap.common.analytics.Analytics import com.tangem.tap.common.analytics.AnalyticsAnOld +import com.tangem.tap.common.analytics.events.Token import com.tangem.tap.common.extensions.copyToClipboard import com.tangem.tap.common.extensions.dispatchDebugErrorNotification import com.tangem.tap.common.extensions.dispatchOnMain @@ -247,6 +248,7 @@ class WalletMiddleware { action.context.shareText(action.address) } is WalletAction.ExploreAddress -> { + Analytics.send(Token.ButtonExplore()) store.dispatchOpenUrl(action.exploreUrl) } is WalletAction.Send -> { diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt index 281d4b3938..9d3dfca291 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletDetailsFragment.kt @@ -19,6 +19,9 @@ import com.tangem.domain.common.TapWorkarounds.derivationStyle import com.tangem.tangem_sdk_new.extensions.dpToPx import com.tangem.tap.common.SnackbarHandler import com.tangem.tap.common.TestActions +import com.tangem.tap.common.analytics.Analytics +import com.tangem.tap.common.analytics.events.DetailsScreen +import com.tangem.tap.common.analytics.events.Token import com.tangem.tap.common.extensions.appendIfNotNull import com.tangem.tap.common.extensions.beginDelayedTransition import com.tangem.tap.common.extensions.fitChipsByGroupWidth @@ -59,12 +62,17 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setHasOptionsMenu(true) - activity?.onBackPressedDispatcher?.addCallback(this, object : OnBackPressedCallback(true) { - override fun handleOnBackPressed() { - store.dispatch(WalletAction.MultiWallet.SelectWallet(null)) - store.dispatch(NavigationAction.PopBackTo()) - } - }) + + Analytics.send(DetailsScreen.ScreenOpened()) + activity?.onBackPressedDispatcher?.addCallback( + this, + object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + store.dispatch(WalletAction.MultiWallet.SelectWallet(null)) + store.dispatch(NavigationAction.PopBackTo()) + } + }, + ) val inflater = TransitionInflater.from(requireContext()) enterTransition = inflater.inflateTransition(R.transition.slide_right) exitTransition = inflater.inflateTransition(R.transition.fade) @@ -125,7 +133,7 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), view?.findViewById(R.id.l_balance)?.let { view -> TestActions.initFor( view = view, - actions = TestWallet.solanaRentExemptWarning() + actions = TestWallet.solanaRentExemptWarning(), ) } } @@ -149,13 +157,15 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), binding.srlWalletDetails.setOnRefreshListener { if (selectedWallet.currencyData.status != BalanceStatus.Loading) { - store.dispatch(WalletAction.LoadWallet( - blockchain = BlockchainNetwork( - selectedWallet.currency.blockchain, - selectedWallet.currency.derivationPath, - emptyList() - ) - ) + Analytics.send(Token.Refreshed()) + store.dispatch( + WalletAction.LoadWallet( + blockchain = BlockchainNetwork( + selectedWallet.currency.blockchain, + selectedWallet.currency.derivationPath, + emptyList(), + ), + ), ) } } @@ -183,7 +193,7 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), tvCurrencyTitle.text = currencyData.currency tvCurrencySubtitle.text = tvCurrencySubtitle.getString( R.string.wallet_currency_subtitle, - currency.blockchain.fullName + currency.blockchain.fullName, ) } @@ -225,7 +235,6 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), ) } - private fun showPendingTransactionsIfPresent(pendingTransactions: List) { pendingTransactionAdapter.submitList(pendingTransactions) binding.rvPendingTransaction.show(pendingTransactions.isNotEmpty()) @@ -256,8 +265,8 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), store.dispatch( WalletAction.ExploreAddress( state.walletAddresses.selectedAddress.exploreUrl, - requireContext() - ) + requireContext(), + ), ) } ivQrCode.setImageBitmap(state.walletAddresses.selectedAddress.shareUrl.toQrCode()) @@ -272,7 +281,7 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), binding.srlWalletDetails.isRefreshing = false (activity as? SnackbarHandler)?.showSnackbar( text = R.string.wallet_notification_no_internet, - buttonTitle = R.string.common_retry + buttonTitle = R.string.common_retry, ) { store.dispatch(WalletAction.LoadData) } } } else { @@ -292,7 +301,8 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), lBalance.tvStatus.setLoadingStatus(R.string.wallet_balance_loading) } BalanceStatus.VerifiedOnline, BalanceStatus.SameCurrencyTransactionInProgress, - BalanceStatus.TransactionInProgress -> { + BalanceStatus.TransactionInProgress, + -> { lBalanceError.root.hide() lBalance.root.show() lBalance.groupBalance.show() @@ -315,7 +325,7 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), lBalance.tvError.show() lBalance.tvError.setWarningStatus( R.string.wallet_balance_blockchain_unreachable, - data.errorMessage + data.errorMessage, ) } BalanceStatus.NoAccount -> { @@ -325,7 +335,7 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), lBalanceError.tvErrorDescriptions.text = getString( R.string.wallet_error_no_account_subtitle_format, - data.amountToCreateAccount, data.currencySymbol + data.amountToCreateAccount, data.currencySymbol, ) } } @@ -364,7 +374,7 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), private fun TextView.setStatus( text: String, @ColorRes color: Int, - @DrawableRes drawable: Int? + @DrawableRes drawable: Int?, ) { this.text = text setTextColor(getColor(color)) From bb19d52b2d9e2b3fc8b8a5c2ca1e0cad14ab6ccd Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 1 Nov 2022 20:43:38 +0500 Subject: [PATCH 27/47] Updated on 2026-08-14 --- .../onboarding/AddressInfoBottomSheetDialog.kt | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/AddressInfoBottomSheetDialog.kt b/app/src/main/java/com/tangem/tap/features/onboarding/AddressInfoBottomSheetDialog.kt index 50faf24376..4635716436 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/AddressInfoBottomSheetDialog.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/AddressInfoBottomSheetDialog.kt @@ -5,6 +5,8 @@ import android.os.Bundle import android.view.LayoutInflater import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetDialog +import com.tangem.tap.common.analytics.Analytics +import com.tangem.tap.common.analytics.events.Token import com.tangem.tap.common.extensions.copyToClipboard import com.tangem.tap.common.extensions.dispatchDialogHide import com.tangem.tap.common.extensions.dispatchShare @@ -21,7 +23,7 @@ import com.tangem.wallet.databinding.DialogOnboardingAddressInfoBinding */ class AddressInfoBottomSheetDialog( private val stateDialog: AppDialog.AddressInfoDialog, - context: Context + context: Context, ) : BottomSheetDialog(context) { var binding: DialogOnboardingAddressInfoBinding? = null @@ -40,6 +42,7 @@ class AddressInfoBottomSheetDialog( override fun show() { super.show() + Analytics.send(Token.Recieve.ScreenOpened()) showData(data = stateDialog.addressData) } @@ -51,10 +54,12 @@ class AddressInfoBottomSheetDialog( imvQrCode.setImageBitmap(data.qrCode) tvAddress.text = data.address btnFlCopyAddress.setOnClickListener { + Analytics.send(Token.Recieve.ButtonCopyAddress()) context.copyToClipboard(data.address) store.dispatchToastNotification(R.string.copy_toast_msg) } btnFlShare.setOnClickListener { + Analytics.send(Token.Recieve.ButtonShareAddress()) store.dispatchShare(data.shareUrl) } tvReceiveMessage.text = getQRReceiveMessage(tvReceiveMessage.context, stateDialog.currency) @@ -67,7 +72,7 @@ fun getQRReceiveMessage(context: Context, currency: Currency): String { context.getString( R.string.address_qr_code_message_format, currency.blockchain.fullName, - currency.currencySymbol + currency.currencySymbol, ) } is Currency.Token -> { @@ -75,7 +80,7 @@ fun getQRReceiveMessage(context: Context, currency: Currency): String { R.string.address_qr_code_message_token_format, currency.token.name, currency.currencySymbol, - currency.blockchain.fullName + currency.blockchain.fullName, ) } } From 9a9d7efe656e277f3d634245529f58fcf980026c Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 1 Nov 2022 20:49:56 +0500 Subject: [PATCH 28/47] Updated on 2026-08-14 --- .../main/java/com/tangem/tap/common/DialogManager.kt | 3 +-- .../wallet/redux/middlewares/TradeCryptoMiddleware.kt | 10 +++++++--- .../RussianCardholdersWarningBottomSheetDialog.kt | 3 +++ 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/common/DialogManager.kt b/app/src/main/java/com/tangem/tap/common/DialogManager.kt index 5ae8d9ce04..ed8d4542b9 100644 --- a/app/src/main/java/com/tangem/tap/common/DialogManager.kt +++ b/app/src/main/java/com/tangem/tap/common/DialogManager.kt @@ -152,8 +152,7 @@ class DialogManager : StoreSubscriber { primaryButtonRes = state.dialog.primaryButtonRes, primaryButtonAction = state.dialog.onOk, ) - is WalletDialog.RussianCardholdersWarningDialog -> - RussianCardholdersWarningBottomSheetDialog(context) + is WalletDialog.RussianCardholdersWarningDialog -> RussianCardholdersWarningBottomSheetDialog(context) else -> null } dialog?.show() diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt index 182c75c9bd..8a951b246c 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt @@ -7,6 +7,7 @@ import com.tangem.tap.common.analytics.events.AnalyticsParam import com.tangem.tap.common.analytics.events.Token import com.tangem.tap.common.extensions.dispatchDebugErrorNotification import com.tangem.tap.common.extensions.dispatchOnMain +import com.tangem.tap.common.extensions.dispatchOpenUrl import com.tangem.tap.common.redux.AppState import com.tangem.tap.common.redux.navigation.AppScreen import com.tangem.tap.common.redux.navigation.NavigationAction @@ -77,7 +78,10 @@ class TradeCryptoMiddleware { cryptoCurrencyName = currency.currencySymbol, fiatCurrencyName = appCurrency.code, walletAddress = addresses[0].address, - )?.let { store.dispatchOnMain(NavigationAction.OpenUrl(it)) } + )?.let { + store.dispatchOpenUrl(it) + Analytics.send(Token.Topup.ScreenOpened()) + } } private fun proceedSellAction() { @@ -96,7 +100,7 @@ class TradeCryptoMiddleware { cryptoCurrencyName = currency.currencySymbol, fiatCurrencyName = appCurrency.code, walletAddress = addresses[0].address, - )?.let { store.dispatchOnMain(NavigationAction.OpenUrl(it)) } + )?.let { store.dispatchOpenUrl(it) } } private fun preconfigureAndOpenSendScreen(action: WalletAction.TradeCryptoAction.SendCrypto) { @@ -127,6 +131,6 @@ class TradeCryptoMiddleware { store.state.globalState.exchangeManager.getSellCryptoReceiptUrl( action = CurrencyExchangeManager.Action.Sell, transactionId = transactionId, - )?.let { store.dispatchOnMain(NavigationAction.OpenUrl(it)) } + )?.let { store.dispatchOpenUrl(it) } } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/dialogs/RussianCardholdersWarningBottomSheetDialog.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/dialogs/RussianCardholdersWarningBottomSheetDialog.kt index a41dce9228..526b991006 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/dialogs/RussianCardholdersWarningBottomSheetDialog.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/dialogs/RussianCardholdersWarningBottomSheetDialog.kt @@ -4,6 +4,8 @@ import android.content.Context import android.os.Bundle import android.view.LayoutInflater import com.google.android.material.bottomsheet.BottomSheetDialog +import com.tangem.tap.common.analytics.Analytics +import com.tangem.tap.common.analytics.events.Token import com.tangem.tap.common.extensions.dispatchDialogHide import com.tangem.tap.common.redux.navigation.NavigationAction import com.tangem.tap.features.wallet.redux.WalletAction @@ -16,6 +18,7 @@ class RussianCardholdersWarningBottomSheetDialog(context: Context) : BottomSheet override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + Analytics.send(Token.Topup.P2PScreenOpened()) binding = DialogRussiansCardholdersWarningBinding .inflate(LayoutInflater.from(context)) .also { setContentView(it.root) } From e761c047d1f0249d7a891f488aa1cf115c2caeca Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 1 Nov 2022 20:51:04 +0500 Subject: [PATCH 29/47] Updated on 2026-08-14 --- .../wallet/redux/middlewares/TradeCryptoMiddleware.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt index 8a951b246c..a18c14fae9 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt @@ -100,7 +100,10 @@ class TradeCryptoMiddleware { cryptoCurrencyName = currency.currencySymbol, fiatCurrencyName = appCurrency.code, walletAddress = addresses[0].address, - )?.let { store.dispatchOpenUrl(it) } + )?.let { + store.dispatchOpenUrl(it) + Analytics.send(Token.Withdraw.ScreenOpened()) + } } private fun preconfigureAndOpenSendScreen(action: WalletAction.TradeCryptoAction.SendCrypto) { From bd3ecd6e1ad773cffc94ad662c31174d5b3579b4 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 1 Nov 2022 21:02:14 +0500 Subject: [PATCH 30/47] Updated on 2026-08-14 --- .../common/analytics/events/AnalyticsParam.kt | 3 +- .../tap/common/analytics/events/Token.kt | 4 +- .../send/redux/middlewares/SendMiddleware.kt | 3 ++ .../tap/features/send/ui/SendFragment.kt | 40 ++++++++++++++++--- 4 files changed, 42 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/common/analytics/events/AnalyticsParam.kt b/app/src/main/java/com/tangem/tap/common/analytics/events/AnalyticsParam.kt index 17b2a3484b..08cc1d9e5b 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/events/AnalyticsParam.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/events/AnalyticsParam.kt @@ -8,7 +8,8 @@ sealed class AnalyticsParam { class Currency(currency: com.tangem.tap.features.wallet.models.Currency) : CurrencyType(currency.currencySymbol) class Blockchain(blockchain: com.tangem.blockchain.common.Blockchain) : CurrencyType(blockchain.currency) class Token(token: com.tangem.blockchain.common.Token) : CurrencyType(token.symbol) - class FiatCurrency(fiatCurrency: com.tangem.tap.common.entities.FiatCurrency): CurrencyType(fiatCurrency.symbol) + class FiatCurrency(fiatCurrency: com.tangem.tap.common.entities.FiatCurrency) : CurrencyType(fiatCurrency.symbol) + class Amount(amount: com.tangem.blockchain.common.Amount) : CurrencyType(amount.currencySymbol) } // MultiCurrency or CurrencyType diff --git a/app/src/main/java/com/tangem/tap/common/analytics/events/Token.kt b/app/src/main/java/com/tangem/tap/common/analytics/events/Token.kt index b0c9a0db1d..7648552745 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/events/Token.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/events/Token.kt @@ -59,9 +59,9 @@ sealed class Token( class ButtonQRCode : Send("Button - QR Code") class ButtonSwapCurrency : Send("Button - Swap Currency") - class TransactionSent(token: CurrencyType) : Send( + class TransactionSent(type: CurrencyType) : Send( event = "Transaction Sent", - params = mapOf("Token" to token.value), + params = mapOf("Token" to type.value), ) } 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 1e886dd335..c45924449f 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 @@ -21,6 +21,8 @@ import com.tangem.tap.common.analytics.Analytics import com.tangem.tap.common.analytics.AnalyticsAnOld import com.tangem.tap.common.analytics.AnalyticsEventAnOld import com.tangem.tap.common.analytics.AnalyticsParamAnOld +import com.tangem.tap.common.analytics.events.AnalyticsParam +import com.tangem.tap.common.analytics.events.Token import com.tangem.tap.common.extensions.dispatchDialogShow import com.tangem.tap.common.extensions.dispatchErrorNotification import com.tangem.tap.common.extensions.dispatchOnMain @@ -222,6 +224,7 @@ private fun sendTransaction( when (sendResult) { is SimpleResult.Success -> { + Analytics.send(Token.Send.TransactionSent(AnalyticsParam.CurrencyType.Amount(amountToSend))) Analytics.handleAnalyticsEvent( event = AnalyticsEventAnOld.TRANSACTION_IS_SENT, card = card, diff --git a/app/src/main/java/com/tangem/tap/features/send/ui/SendFragment.kt b/app/src/main/java/com/tangem/tap/features/send/ui/SendFragment.kt index 4837aa7449..9fe57ae5bd 100644 --- a/app/src/main/java/com/tangem/tap/features/send/ui/SendFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/send/ui/SendFragment.kt @@ -16,6 +16,8 @@ import com.google.android.material.textfield.TextInputEditText import com.tangem.Message import com.tangem.tangem_sdk_new.extensions.hideSoftKeyboard import com.tangem.tap.common.KeyboardObserver +import com.tangem.tap.common.analytics.Analytics +import com.tangem.tap.common.analytics.events.Token import com.tangem.tap.common.entities.FiatCurrency import com.tangem.tap.common.extensions.getFromClipboard import com.tangem.tap.common.extensions.setOnImeActionListener @@ -28,10 +30,25 @@ import com.tangem.tap.common.toggleWidget.IndeterminateProgressButtonWidget import com.tangem.tap.common.toggleWidget.ViewStateWidget import com.tangem.tap.features.BaseStoreFragment import com.tangem.tap.features.addBackPressHandler -import com.tangem.tap.features.send.redux.* -import com.tangem.tap.features.send.redux.AddressPayIdActionUi.* -import com.tangem.tap.features.send.redux.AmountActionUi.* -import com.tangem.tap.features.send.redux.FeeActionUi.* +import com.tangem.tap.features.send.redux.AddressPayIdActionUi +import com.tangem.tap.features.send.redux.AddressPayIdActionUi.CheckClipboard +import com.tangem.tap.features.send.redux.AddressPayIdActionUi.PasteAddressPayId +import com.tangem.tap.features.send.redux.AddressPayIdActionUi.SetTruncateHandler +import com.tangem.tap.features.send.redux.AddressPayIdActionUi.TruncateOrRestore +import com.tangem.tap.features.send.redux.AmountAction +import com.tangem.tap.features.send.redux.AmountActionUi +import com.tangem.tap.features.send.redux.AmountActionUi.CheckAmountToSend +import com.tangem.tap.features.send.redux.AmountActionUi.SetMainCurrency +import com.tangem.tap.features.send.redux.AmountActionUi.SetMaxAmount +import com.tangem.tap.features.send.redux.AmountActionUi.ToggleMainCurrency +import com.tangem.tap.features.send.redux.FeeActionUi.ChangeIncludeFee +import com.tangem.tap.features.send.redux.FeeActionUi.ChangeSelectedFee +import com.tangem.tap.features.send.redux.FeeActionUi.ToggleControlsVisibility +import com.tangem.tap.features.send.redux.ReceiptAction +import com.tangem.tap.features.send.redux.ReleaseSendState +import com.tangem.tap.features.send.redux.SendAction +import com.tangem.tap.features.send.redux.SendActionUi +import com.tangem.tap.features.send.redux.TransactionExtrasAction import com.tangem.tap.features.send.redux.states.FeeType import com.tangem.tap.features.send.redux.states.MainCurrencyType import com.tangem.tap.features.send.ui.stateSubscribers.SendStateSubscriber @@ -43,7 +60,12 @@ import com.tangem.wallet.R import com.tangem.wallet.databinding.FragmentSendBinding import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.channels.awaitClose -import kotlinx.coroutines.flow.* +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.callbackFlow +import kotlinx.coroutines.flow.debounce +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach import java.text.DecimalFormatSymbols /** @@ -61,6 +83,11 @@ class SendFragment : BaseStoreFragment(R.layout.fragment_send) { val binding: FragmentSendBinding by viewBinding(FragmentSendBinding::bind) + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + Analytics.send(Token.Send.ScreenOpened()) + } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) addBackPressHandler(this) @@ -101,10 +128,12 @@ class SendFragment : BaseStoreFragment(R.layout.fragment_send) { .launchIn(mainScope) imvPaste.setOnClickListener { + Analytics.send(Token.Send.ButtonPaste()) store.dispatch(PasteAddressPayId(requireContext().getFromClipboard()?.toString() ?: "")) store.dispatch(TruncateOrRestore(!etAddressOrPayId.isFocused)) } imvQrCode.setOnClickListener { + Analytics.send(Token.Send.ButtonQRCode()) startActivityForResult( Intent(requireContext(), ScanQrCodeActivity::class.java), ScanQrCodeActivity.SCAN_QR_REQUEST_CODE @@ -165,6 +194,7 @@ class SendFragment : BaseStoreFragment(R.layout.fragment_send) { store.dispatch(AmountAction.SetDecimalSeparator(decimalSeparator)) binding.lSendAmount.tvAmountCurrency.setOnClickListener { + Analytics.send(Token.Send.ButtonSwapCurrency()) store.dispatch(ToggleMainCurrency) store.dispatch(ReceiptAction.RefreshReceipt) store.dispatch(SendAction.ChangeSendButtonState(store.state.sendState.getButtonState())) From c204af29737419436c6da74d78c90c1271236685 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 2 Nov 2022 11:56:53 +0500 Subject: [PATCH 31/47] Updated on 2026-08-14 --- .../tangem/tap/common/analytics/Analytics.kt | 5 ++- .../common/analytics/api/EventHandlerApi.kt | 3 +- .../tap/common/analytics/events/Shop.kt | 34 +++++++++++++-- .../appsFlyer/AppsFlyerAnalyticsHandler.kt | 34 +++------------ .../firebase/FirebaseAnalyticsHandler.kt | 31 +++----------- .../tap/common/shop/TangemShopService.kt | 41 +++++++++---------- .../tap/features/shop/ui/ShopFragment.kt | 4 ++ 7 files changed, 72 insertions(+), 80 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/common/analytics/Analytics.kt b/app/src/main/java/com/tangem/tap/common/analytics/Analytics.kt index 9eaee82a3a..386213f341 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/Analytics.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/Analytics.kt @@ -11,6 +11,7 @@ import com.tangem.tap.common.analytics.api.ErrorEventLogger import com.tangem.tap.common.analytics.api.ShopifyOrderEventHandler import com.tangem.tap.common.analytics.events.AnalyticsEvent import com.tangem.tap.common.extensions.filterNotNull +import com.tangem.tap.common.shop.data.ProductType /** [REDACTED_AUTHOR] @@ -85,9 +86,9 @@ object Analytics : GlobalAnalyticsEventHandler { } } - override fun send(order: Storefront.Order) { + override fun send(order: Storefront.Order, productType: ProductType) { analyticsHandlers.filterIsInstance().forEach { - it.send(order) + it.send(order, productType) } } diff --git a/app/src/main/java/com/tangem/tap/common/analytics/api/EventHandlerApi.kt b/app/src/main/java/com/tangem/tap/common/analytics/api/EventHandlerApi.kt index ea77e75dfd..5eda855ec2 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/api/EventHandlerApi.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/api/EventHandlerApi.kt @@ -13,6 +13,7 @@ import com.tangem.tap.common.analytics.AnalyticsParamAnOld import com.tangem.tap.common.analytics.events.AnalyticsEvent import com.tangem.tap.common.analytics.events.AnalyticsParam import com.tangem.tap.common.extensions.filterNotNull +import com.tangem.tap.common.shop.data.ProductType import com.tangem.tap.domain.configurable.config.Config /** @@ -83,7 +84,7 @@ interface BlockchainSdkErrorEventHandler { } interface ShopifyOrderEventHandler { - fun send(order: Storefront.Order) + fun send(order: Storefront.Order, productType: ProductType) } interface AnalyticsHandlerBuilder { diff --git a/app/src/main/java/com/tangem/tap/common/analytics/events/Shop.kt b/app/src/main/java/com/tangem/tap/common/analytics/events/Shop.kt index c09bf89ab3..90fdf6e08f 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/events/Shop.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/events/Shop.kt @@ -1,5 +1,10 @@ package com.tangem.tap.common.analytics.events +import com.shopify.buy3.Storefront +import com.tangem.common.Converter +import com.tangem.tap.common.extensions.filterNotNull +import com.tangem.tap.common.shop.data.ProductType + /** [REDACTED_AUTHOR] */ @@ -10,13 +15,36 @@ sealed class Shop( class ScreenOpened : IntroductionProcess("Shop Screen Opened") - class Purchased(productSku: String) : Shop( + class Purchased(params: Map) : Shop( event = "Purchased", - params = mapOf("SKU" to productSku), + params = params, ) class Redirected(partnerName: String) : Shop( event = "Redirected", params = mapOf("Partner" to partnerName), ) -} \ No newline at end of file +} + +class OrderToParamsConverter : Converter, Map> { + override fun convert(value: Pair): Map { + val order = value.first + val productType = value.second + + val code = (order.discountApplications.edges.firstOrNull()?.node as? Storefront.DiscountCodeApplication)?.code + val sku = order.lineItems.edges.firstOrNull()?.node?.variant?.sku ?: productType.sku + + val count = when (productType) { + ProductType.WALLET_2_CARDS -> "2" + ProductType.WALLET_3_CARDS -> "3" + } + val amount = "${order.totalPriceV2.amount} ${order.totalPriceV2.currencyCode.name}" + + return mapOf( + "Coupon Code" to code, + "SKU" to sku, + "Count" to count, + "Amount" to amount, + ).filterNotNull() + } +} 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 index 008b6189b9..8264b4c501 100644 --- 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 @@ -1,12 +1,12 @@ package com.tangem.tap.common.analytics.handlers.appsFlyer -import com.appsflyer.AFInAppEventParameterName -import com.appsflyer.AFInAppEventType import com.shopify.buy3.Storefront -import com.tangem.common.Converter import com.tangem.tap.common.analytics.api.AnalyticsEventHandler import com.tangem.tap.common.analytics.api.AnalyticsHandlerBuilder import com.tangem.tap.common.analytics.api.ShopifyOrderEventHandler +import com.tangem.tap.common.analytics.events.OrderToParamsConverter +import com.tangem.tap.common.analytics.events.Shop +import com.tangem.tap.common.shop.data.ProductType class AppsFlyerAnalyticsHandler( private val client: AppsFlyerAnalyticsClient, @@ -18,12 +18,12 @@ class AppsFlyerAnalyticsHandler( client.logEvent(event, params) } - override fun send(order: Storefront.Order) { - send(ORDER_EVENT, OrderToParamsConverter().convert(order)) + override fun send(order: Storefront.Order, productType: ProductType) { + val eventParams = OrderToParamsConverter().convert(order to productType) + send(Shop.Purchased(eventParams)) } companion object { - const val ORDER_EVENT = AFInAppEventType.PURCHASE const val ID = "AppsFlyer" } @@ -34,26 +34,4 @@ class AppsFlyerAnalyticsHandler( else -> null }?.let { AppsFlyerAnalyticsHandler(it) } } -} - -private 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 index 65ef31ac8e..1c79942d4f 100644 --- 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 @@ -1,9 +1,7 @@ package com.tangem.tap.common.analytics.handlers.firebase -import com.google.firebase.analytics.FirebaseAnalytics import com.shopify.buy3.Storefront import com.tangem.blockchain.common.BlockchainError -import com.tangem.common.Converter import com.tangem.common.card.Card import com.tangem.common.core.TangemSdkError import com.tangem.tap.common.analytics.AnalyticsAnOld @@ -15,6 +13,9 @@ import com.tangem.tap.common.analytics.api.SdkErrorEventHandler import com.tangem.tap.common.analytics.api.ShopifyOrderEventHandler import com.tangem.tap.common.analytics.converters.BlockchainSdkErrorConverter import com.tangem.tap.common.analytics.converters.CardSdkErrorConverter +import com.tangem.tap.common.analytics.events.OrderToParamsConverter +import com.tangem.tap.common.analytics.events.Shop +import com.tangem.tap.common.shop.data.ProductType class FirebaseAnalyticsHandler( private val client: FirebaseAnalyticsClient, @@ -57,8 +58,9 @@ class FirebaseAnalyticsHandler( } } - override fun send(order: Storefront.Order) { - send(FirebaseClient.ORDER_EVENT, OrderToParamsConverter().convert(order)) + override fun send(order: Storefront.Order, productType: ProductType) { + val eventParams = OrderToParamsConverter().convert(order to productType) + send(Shop.Purchased(eventParams)) } companion object { @@ -72,25 +74,4 @@ class FirebaseAnalyticsHandler( else -> null }?.let { FirebaseAnalyticsHandler(it) } } -} - -private 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/shop/TangemShopService.kt b/app/src/main/java/com/tangem/tap/common/shop/TangemShopService.kt index 87dacd7bc1..3d2c060786 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 @@ -22,7 +22,6 @@ class TangemShopService(application: Application, shopifyShop: ShopifyShop) { private val shopifyService = ShopifyService(application, shopifyShop) - private val checkouts = mutableMapOf() private val variants = mutableMapOf() @@ -40,24 +39,27 @@ class TangemShopService(application: Application, shopifyShop: ShopifyShop) { variants.putAll(availableVariants) if (variants.size < SKUS_TO_DISPLAY.size) { - return Result.failure(Exception( - "Shopify: products are missing, " + - "\nproducts available: ${variants.keys.map { it.sku }}")) + return Result.failure( + Exception( + "Shopify: products are missing, " + + "\nproducts available: ${variants.keys.map { it.sku }}", + ), + ) } val twoCardsProduct = TangemProduct( type = ProductType.WALLET_2_CARDS, totalSum = TotalSum( finalValue = variants[ProductType.WALLET_2_CARDS]?.priceV2?.format(), - beforeDiscount = variants[ProductType.WALLET_2_CARDS]?.compareAtPriceV2?.format() - ) + beforeDiscount = variants[ProductType.WALLET_2_CARDS]?.compareAtPriceV2?.format(), + ), ) val threeCardsProduct = TangemProduct( type = ProductType.WALLET_3_CARDS, totalSum = TotalSum( finalValue = variants[ProductType.WALLET_3_CARDS]?.priceV2?.format(), - beforeDiscount = variants[ProductType.WALLET_3_CARDS]?.compareAtPriceV2?.format() - ) + beforeDiscount = variants[ProductType.WALLET_3_CARDS]?.compareAtPriceV2?.format(), + ), ) createCheckouts() return Result.success(listOf(twoCardsProduct, threeCardsProduct)) @@ -85,7 +87,7 @@ class TangemShopService(application: Application, shopifyShop: ShopifyShop) { val totalPrice = checkouts[productType]!!.totalPriceV2.amount googlePayService.payWithGooglePay( totalPriceCents = totalPrice, currencyCode = checkouts[productType]!!.currencyCode.name, - merchantID = shopifyService.shop.merchantID + merchantID = shopifyService.shop.merchantID, ) } @@ -104,7 +106,7 @@ class TangemShopService(application: Application, shopifyShop: ShopifyShop) { suspend fun handleGooglePayResult( resultCode: Int, data: Intent?, - productType: ProductType + productType: ProductType, ): Result { val result = googlePayService.handleResponseFromGooglePay(resultCode, data) result.onSuccess { @@ -119,7 +121,7 @@ class TangemShopService(application: Application, shopifyShop: ShopifyShop) { private suspend fun completeTokenizedPayment( paymentData: PaymentData, - productType: ProductType + productType: ProductType, ): Result { val checkout = checkouts[productType]!! val googlePayResponse = @@ -140,19 +142,18 @@ class TangemShopService(application: Application, shopifyShop: ShopifyShop) { phone = addressGPay.phoneNumber } - val payment = Storefront.TokenizedPaymentInputV3( amount, idempotencyKey, address, paymentData.toJson(), - Storefront.PaymentTokenType.GOOGLE_PAY + Storefront.PaymentTokenType.GOOGLE_PAY, ) .setTest(true) return shopifyService.completeWithTokenizedPayment( payment = payment, - checkoutID = checkout.id + checkoutID = checkout.id, ) } @@ -181,12 +182,12 @@ class TangemShopService(application: Application, shopifyShop: ShopifyShop) { productType, TotalSum( finalValue = it.totalPriceV2.format(), - beforeDiscount = variants[productType]!!.compareAtPriceV2.format() + beforeDiscount = variants[productType]!!.compareAtPriceV2.format(), ), - appliedDiscount = it.getAppliedDiscount() - ) + appliedDiscount = it.getAppliedDiscount(), + ), - ) + ) } return Result.failure(result.exceptionOrNull()!!) } @@ -197,9 +198,7 @@ class TangemShopService(application: Application, shopifyShop: ShopifyShop) { suspend fun waitForCheckout(productType: ProductType) { val result = shopifyService.checkout(true, checkouts[productType]!!.id) - result.onSuccess { - it.order?.let { Analytics.send(it) } - } + result.onSuccess { checkout -> checkout.order?.let { Analytics.send(it, productType) } } } companion object { diff --git a/app/src/main/java/com/tangem/tap/features/shop/ui/ShopFragment.kt b/app/src/main/java/com/tangem/tap/features/shop/ui/ShopFragment.kt index 51fe6cb54c..338561267b 100644 --- a/app/src/main/java/com/tangem/tap/features/shop/ui/ShopFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/shop/ui/ShopFragment.kt @@ -12,6 +12,8 @@ import androidx.activity.OnBackPressedCallback import by.kirich1409.viewbindingdelegate.viewBinding import com.tangem.tap.common.GlobalLayoutStateHandler import com.tangem.tap.common.KeyboardObserver +import com.tangem.tap.common.analytics.Analytics +import com.tangem.tap.common.analytics.events.Shop import com.tangem.tap.common.extensions.show import com.tangem.tap.common.redux.navigation.NavigationAction import com.tangem.tap.common.shop.data.ProductType @@ -41,6 +43,8 @@ class ShopFragment : BaseStoreFragment(R.layout.fragment_shop), StoreSubscriber< override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + Analytics.send(Shop.ScreenOpened()) + activity?.onBackPressedDispatcher?.addCallback(this, object : OnBackPressedCallback(true) { override fun handleOnBackPressed() { store.dispatch(NavigationAction.PopBackTo()) From 48343b3c604483811203a922494e278f81db8221 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 2 Nov 2022 12:30:20 +0500 Subject: [PATCH 32/47] Updated on 2026-08-14 --- .../tangem/tap/domain/walletconnect/WalletConnectManager.kt | 3 +++ 1 file changed, 3 insertions(+) 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 f9ed7f61a5..31e16004cd 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 @@ -6,6 +6,7 @@ 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.AnalyticsAnOld +import com.tangem.tap.common.analytics.events.WalletConnect import com.tangem.tap.common.analytics.logWcEvent import com.tangem.tap.common.extensions.dispatchOnMain import com.tangem.tap.common.redux.global.GlobalAction @@ -224,6 +225,7 @@ class WalletConnectManager { } private fun onSessionClosed(session: WCSession) { + Analytics.send(WalletConnect.SessionDisconnected()) Analytics.logWcEvent( AnalyticsAnOld.WcAnalyticsEvent.Session( AnalyticsAnOld.WcSessionEvent.Disconnect, sessions[session]?.peerMeta?.url @@ -373,6 +375,7 @@ class WalletConnectManager { ), ) } + Analytics.send(WalletConnect.NewSessionEstablished()) Analytics.logWcEvent( AnalyticsAnOld.WcAnalyticsEvent.Session( AnalyticsAnOld.WcSessionEvent.Connect, peer.url, From dec6afa96a4adfbcfb8fa08fafb7a9731d909854 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 2 Nov 2022 14:57:52 +0500 Subject: [PATCH 33/47] Updated on 2026-08-14 --- .../java/com/tangem/tap/common/analytics/events/Token.kt | 7 ++++++- .../wallet/redux/middlewares/MultiWalletMiddleware.kt | 4 +++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/common/analytics/events/Token.kt b/app/src/main/java/com/tangem/tap/common/analytics/events/Token.kt index 7648552745..9da6abe399 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/events/Token.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/events/Token.kt @@ -12,9 +12,14 @@ sealed class Token( ) : AnalyticsEvent(category, event, params) { class Refreshed : Token("Token", "Refreshed") - class ButtonRemoveToken : Token("Token", "Button - Remove Token") class ButtonExplore : Token("Token", "Button - Explore") + class ButtonRemoveToken(type: CurrencyType) : Token( + "Token", + "Button - Remove Token", + params = mapOf("Token" to type.value), + ) + class ButtonBuy(type: CurrencyType) : Token( category = "Token", event = "Button - Buy", diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt index 3433d447d5..3fe4e1b3d0 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt @@ -6,6 +6,8 @@ import com.tangem.blockchain.common.WalletManager import com.tangem.common.extensions.guard import com.tangem.domain.common.extensions.withMainContext import com.tangem.tap.common.analytics.Analytics +import com.tangem.tap.common.analytics.events.AnalyticsParam +import com.tangem.tap.common.analytics.events.Token.ButtonRemoveToken import com.tangem.tap.common.extensions.dispatchDialogShow import com.tangem.tap.common.extensions.dispatchErrorNotification import com.tangem.tap.common.extensions.safeUpdate @@ -110,7 +112,7 @@ class MultiWalletMiddleware { WalletDialog.RemoveWalletDialog( currencyTitle = currency.currencyName, onOk = { - Analytics.send(com.tangem.tap.common.analytics.events.Token.ButtonRemoveToken()) + Analytics.send(ButtonRemoveToken(AnalyticsParam.CurrencyType.Currency(currency))) store.dispatch( WalletAction.MultiWallet.RemoveWallet( currency = currency, From c2b57b28b0506ce12bce12741bf46d3a3cca0d87 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 2 Nov 2022 17:52:24 +0500 Subject: [PATCH 34/47] Updated on 2026-08-14 --- .../converters/ShopOrderToEventConverter.kt | 27 ++++++++++++++ .../tap/common/analytics/events/Shop.kt | 37 ++++--------------- .../appsFlyer/AppsFlyerAnalyticsHandler.kt | 8 ++-- .../firebase/FirebaseAnalyticsHandler.kt | 8 ++-- 4 files changed, 43 insertions(+), 37 deletions(-) create mode 100644 app/src/main/java/com/tangem/tap/common/analytics/converters/ShopOrderToEventConverter.kt diff --git a/app/src/main/java/com/tangem/tap/common/analytics/converters/ShopOrderToEventConverter.kt b/app/src/main/java/com/tangem/tap/common/analytics/converters/ShopOrderToEventConverter.kt new file mode 100644 index 0000000000..ddbd1683bd --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/analytics/converters/ShopOrderToEventConverter.kt @@ -0,0 +1,27 @@ +package com.tangem.tap.common.analytics.converters + +import com.shopify.buy3.Storefront +import com.tangem.common.Converter +import com.tangem.tap.common.analytics.events.Shop +import com.tangem.tap.common.shop.data.ProductType + +/** +[REDACTED_AUTHOR] + */ +class ShopOrderToEventConverter : Converter, Shop.Purchased> { + + override fun convert(value: Pair): Shop.Purchased { + val order = value.first + val productType = value.second + + val sku = order.lineItems.edges.firstOrNull()?.node?.variant?.sku ?: productType.sku + val count = when (productType) { + ProductType.WALLET_2_CARDS -> "2" + ProductType.WALLET_3_CARDS -> "3" + } + val amount = "${order.totalPriceV2.amount} ${order.totalPriceV2.currencyCode.name}" + val code = (order.discountApplications.edges.firstOrNull()?.node as? Storefront.DiscountCodeApplication)?.code + + return Shop.Purchased(sku, count, amount, code) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/analytics/events/Shop.kt b/app/src/main/java/com/tangem/tap/common/analytics/events/Shop.kt index 90fdf6e08f..9634f2929b 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/events/Shop.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/events/Shop.kt @@ -1,9 +1,6 @@ package com.tangem.tap.common.analytics.events -import com.shopify.buy3.Storefront -import com.tangem.common.Converter import com.tangem.tap.common.extensions.filterNotNull -import com.tangem.tap.common.shop.data.ProductType /** [REDACTED_AUTHOR] @@ -15,36 +12,18 @@ sealed class Shop( class ScreenOpened : IntroductionProcess("Shop Screen Opened") - class Purchased(params: Map) : Shop( + class Purchased(sku: String, count: String, amount: String, couponCode: String?) : Shop( event = "Purchased", - params = params, + params = mapOf( + "SKU" to sku, + "Count" to count, + "Amount" to amount, + "Coupon Code" to couponCode, + ).filterNotNull(), ) class Redirected(partnerName: String) : Shop( event = "Redirected", params = mapOf("Partner" to partnerName), ) -} - -class OrderToParamsConverter : Converter, Map> { - override fun convert(value: Pair): Map { - val order = value.first - val productType = value.second - - val code = (order.discountApplications.edges.firstOrNull()?.node as? Storefront.DiscountCodeApplication)?.code - val sku = order.lineItems.edges.firstOrNull()?.node?.variant?.sku ?: productType.sku - - val count = when (productType) { - ProductType.WALLET_2_CARDS -> "2" - ProductType.WALLET_3_CARDS -> "3" - } - val amount = "${order.totalPriceV2.amount} ${order.totalPriceV2.currencyCode.name}" - - return mapOf( - "Coupon Code" to code, - "SKU" to sku, - "Count" to count, - "Amount" to amount, - ).filterNotNull() - } -} +} \ No newline at end of file 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 index 8264b4c501..fe23cfd753 100644 --- 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 @@ -4,8 +4,7 @@ import com.shopify.buy3.Storefront import com.tangem.tap.common.analytics.api.AnalyticsEventHandler import com.tangem.tap.common.analytics.api.AnalyticsHandlerBuilder import com.tangem.tap.common.analytics.api.ShopifyOrderEventHandler -import com.tangem.tap.common.analytics.events.OrderToParamsConverter -import com.tangem.tap.common.analytics.events.Shop +import com.tangem.tap.common.analytics.converters.ShopOrderToEventConverter import com.tangem.tap.common.shop.data.ProductType class AppsFlyerAnalyticsHandler( @@ -19,8 +18,9 @@ class AppsFlyerAnalyticsHandler( } override fun send(order: Storefront.Order, productType: ProductType) { - val eventParams = OrderToParamsConverter().convert(order to productType) - send(Shop.Purchased(eventParams)) + //TODO: make sending this event through filters + val event = ShopOrderToEventConverter().convert(order to productType) + send(event) } companion object { 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 index 1c79942d4f..f2abc8ca76 100644 --- 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 @@ -13,8 +13,7 @@ import com.tangem.tap.common.analytics.api.SdkErrorEventHandler import com.tangem.tap.common.analytics.api.ShopifyOrderEventHandler import com.tangem.tap.common.analytics.converters.BlockchainSdkErrorConverter import com.tangem.tap.common.analytics.converters.CardSdkErrorConverter -import com.tangem.tap.common.analytics.events.OrderToParamsConverter -import com.tangem.tap.common.analytics.events.Shop +import com.tangem.tap.common.analytics.converters.ShopOrderToEventConverter import com.tangem.tap.common.shop.data.ProductType class FirebaseAnalyticsHandler( @@ -59,8 +58,9 @@ class FirebaseAnalyticsHandler( } override fun send(order: Storefront.Order, productType: ProductType) { - val eventParams = OrderToParamsConverter().convert(order to productType) - send(Shop.Purchased(eventParams)) + //TODO: make sending this event through filters + val event = ShopOrderToEventConverter().convert(order to productType) + send(event) } companion object { From 9c3cd6f2d3df061a26a931bdd0fabd2bb22d2878 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 2 Nov 2022 19:26:45 +0500 Subject: [PATCH 35/47] Updated on 2026-08-14 --- .../java/com/tangem/tap/TapApplication.kt | 4 +++ .../tangem/tap/common/analytics/Analytics.kt | 30 ++++++++++++------- .../analytics/GlobalAnalyticsEventHandler.kt | 9 ++++-- .../common/analytics/api/EventFilterApi.kt | 12 ++++++++ .../common/analytics/api/EventHandlerApi.kt | 6 ---- .../filters/ShopPurchasedEventFilter.kt | 25 ++++++++++++++++ .../appsFlyer/AppsFlyerAnalyticsHandler.kt | 12 +------- .../firebase/FirebaseAnalyticsHandler.kt | 12 +------- .../tap/common/shop/TangemShopService.kt | 8 ++++- 9 files changed, 76 insertions(+), 42 deletions(-) create mode 100644 app/src/main/java/com/tangem/tap/common/analytics/api/EventFilterApi.kt create mode 100644 app/src/main/java/com/tangem/tap/common/analytics/filters/ShopPurchasedEventFilter.kt diff --git a/app/src/main/java/com/tangem/tap/TapApplication.kt b/app/src/main/java/com/tangem/tap/TapApplication.kt index 1913ac6e16..5417042486 100644 --- a/app/src/main/java/com/tangem/tap/TapApplication.kt +++ b/app/src/main/java/com/tangem/tap/TapApplication.kt @@ -17,6 +17,7 @@ import com.tangem.tap.common.AssetReader import com.tangem.tap.common.analytics.Analytics import com.tangem.tap.common.analytics.AnalyticsHandlersFactory import com.tangem.tap.common.analytics.api.AnalyticsHandlerBuilder +import com.tangem.tap.common.analytics.filters.ShopPurchasedEventFilter 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 @@ -122,6 +123,9 @@ class TapApplication : Application(), ImageLoaderFactory { factory.build(buildData).forEach { Analytics.addHandler(it.id(), it) } + listOf( + ShopPurchasedEventFilter(), + ).forEach { Analytics.addFilter(it) } } private fun initFeedbackManager(context: Context, preferencesStorage: PreferencesStorage, config: Config) { diff --git a/app/src/main/java/com/tangem/tap/common/analytics/Analytics.kt b/app/src/main/java/com/tangem/tap/common/analytics/Analytics.kt index 386213f341..57617de12b 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/Analytics.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/Analytics.kt @@ -1,23 +1,22 @@ 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.analytics.api.AnalyticsEventFilter import com.tangem.tap.common.analytics.api.AnalyticsEventHandler import com.tangem.tap.common.analytics.api.BlockchainSdkErrorEventHandler import com.tangem.tap.common.analytics.api.CardSdkErrorEventHandler import com.tangem.tap.common.analytics.api.ErrorEventLogger -import com.tangem.tap.common.analytics.api.ShopifyOrderEventHandler import com.tangem.tap.common.analytics.events.AnalyticsEvent import com.tangem.tap.common.extensions.filterNotNull -import com.tangem.tap.common.shop.data.ProductType /** [REDACTED_AUTHOR] */ object Analytics : GlobalAnalyticsEventHandler { + private val eventFilters = mutableListOf() private val handlers = mutableMapOf() private val analyticsHandlers: List @@ -35,6 +34,14 @@ object Analytics : GlobalAnalyticsEventHandler { return handlers.remove(name) } + override fun addFilter(filter: AnalyticsEventFilter) { + eventFilters.add(filter) + } + + override fun removeFilter(filter: AnalyticsEventFilter) { + eventFilters.remove(filter) + } + override fun attachToAllEvents(key: String, value: String) { attachToAllEventsParams[key] = value } @@ -44,7 +51,16 @@ object Analytics : GlobalAnalyticsEventHandler { } override fun send(event: AnalyticsEvent, card: Card?, blockchain: String?) { - analyticsHandlers.forEach { it.send(event, card, blockchain) } + val eventFilter = eventFilters.firstOrNull { it.canBeAppliedTo(event) } + + when { + eventFilter == null -> analyticsHandlers.forEach { it.send(event, card, blockchain) } + eventFilter.canBeSent(event) -> { + analyticsHandlers + .filter { eventFilter.canBeConsumedBy(it, event) } + .forEach { it.send(event) } + } + } } override fun handleAnalyticsEvent( @@ -86,12 +102,6 @@ object Analytics : GlobalAnalyticsEventHandler { } } - override fun send(order: Storefront.Order, productType: ProductType) { - analyticsHandlers.filterIsInstance().forEach { - it.send(order, productType) - } - } - override fun prepareParams(card: Card?, blockchain: String?, params: Map): Map { return super.prepareParams(card, blockchain, params).toMutableMap().apply { putAll(attachToAllEventsParams) diff --git a/app/src/main/java/com/tangem/tap/common/analytics/GlobalAnalyticsEventHandler.kt b/app/src/main/java/com/tangem/tap/common/analytics/GlobalAnalyticsEventHandler.kt index 139ffa5582..287f991527 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/GlobalAnalyticsEventHandler.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/GlobalAnalyticsEventHandler.kt @@ -1,18 +1,21 @@ package com.tangem.tap.common.analytics +import com.tangem.tap.common.analytics.api.AnalyticsEventFilter import com.tangem.tap.common.analytics.api.AnalyticsEventHandler import com.tangem.tap.common.analytics.api.ErrorEventHandler import com.tangem.tap.common.analytics.api.SdkErrorEventHandler -import com.tangem.tap.common.analytics.api.ShopifyOrderEventHandler interface GlobalAnalyticsEventHandler : AnalyticsEventHandler, ErrorEventHandler, - SdkErrorEventHandler, - ShopifyOrderEventHandler { + SdkErrorEventHandler { fun addHandler(name: String, handler: AnalyticsEventHandler) fun removeHandler(name: String): AnalyticsEventHandler? + fun addFilter(filter: AnalyticsEventFilter) + + fun removeFilter(filter: AnalyticsEventFilter) + fun attachToAllEvents(key: String, value: String) } diff --git a/app/src/main/java/com/tangem/tap/common/analytics/api/EventFilterApi.kt b/app/src/main/java/com/tangem/tap/common/analytics/api/EventFilterApi.kt new file mode 100644 index 0000000000..a4e93fa75b --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/analytics/api/EventFilterApi.kt @@ -0,0 +1,12 @@ +package com.tangem.tap.common.analytics.api + +import com.tangem.tap.common.analytics.events.AnalyticsEvent + +/** +[REDACTED_AUTHOR] + */ +interface AnalyticsEventFilter { + fun canBeAppliedTo(event: AnalyticsEvent): Boolean + fun canBeSent(event: AnalyticsEvent): Boolean + fun canBeConsumedBy(handler: AnalyticsEventHandler, event: AnalyticsEvent): Boolean +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/analytics/api/EventHandlerApi.kt b/app/src/main/java/com/tangem/tap/common/analytics/api/EventHandlerApi.kt index 5eda855ec2..494747287e 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/api/EventHandlerApi.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/api/EventHandlerApi.kt @@ -1,7 +1,6 @@ package com.tangem.tap.common.analytics.api import android.app.Application -import com.shopify.buy3.Storefront import com.tangem.blockchain.common.BlockchainError import com.tangem.common.card.Card import com.tangem.common.core.TangemSdkError @@ -13,7 +12,6 @@ import com.tangem.tap.common.analytics.AnalyticsParamAnOld import com.tangem.tap.common.analytics.events.AnalyticsEvent import com.tangem.tap.common.analytics.events.AnalyticsParam import com.tangem.tap.common.extensions.filterNotNull -import com.tangem.tap.common.shop.data.ProductType import com.tangem.tap.domain.configurable.config.Config /** @@ -83,10 +81,6 @@ interface BlockchainSdkErrorEventHandler { ) } -interface ShopifyOrderEventHandler { - fun send(order: Storefront.Order, productType: ProductType) -} - interface AnalyticsHandlerBuilder { fun build(data: Data): AnalyticsEventHandler? diff --git a/app/src/main/java/com/tangem/tap/common/analytics/filters/ShopPurchasedEventFilter.kt b/app/src/main/java/com/tangem/tap/common/analytics/filters/ShopPurchasedEventFilter.kt new file mode 100644 index 0000000000..5267782ddc --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/analytics/filters/ShopPurchasedEventFilter.kt @@ -0,0 +1,25 @@ +package com.tangem.tap.common.analytics.filters + +import com.tangem.tap.common.analytics.api.AnalyticsEventFilter +import com.tangem.tap.common.analytics.api.AnalyticsEventHandler +import com.tangem.tap.common.analytics.events.AnalyticsEvent +import com.tangem.tap.common.analytics.events.Shop +import com.tangem.tap.common.analytics.handlers.appsFlyer.AppsFlyerAnalyticsHandler +import com.tangem.tap.common.analytics.handlers.firebase.FirebaseAnalyticsHandler + +/** +[REDACTED_AUTHOR] + */ +class ShopPurchasedEventFilter : AnalyticsEventFilter { + + override fun canBeAppliedTo(event: AnalyticsEvent): Boolean = event is Shop.Purchased + + override fun canBeSent(event: AnalyticsEvent): Boolean = true + + override fun canBeConsumedBy(handler: AnalyticsEventHandler, event: AnalyticsEvent): Boolean { + return when (handler) { + is AppsFlyerAnalyticsHandler, is FirebaseAnalyticsHandler -> true + else -> false + } + } +} \ No newline at end of file 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 index fe23cfd753..b91da358d6 100644 --- 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 @@ -1,15 +1,11 @@ package com.tangem.tap.common.analytics.handlers.appsFlyer -import com.shopify.buy3.Storefront import com.tangem.tap.common.analytics.api.AnalyticsEventHandler import com.tangem.tap.common.analytics.api.AnalyticsHandlerBuilder -import com.tangem.tap.common.analytics.api.ShopifyOrderEventHandler -import com.tangem.tap.common.analytics.converters.ShopOrderToEventConverter -import com.tangem.tap.common.shop.data.ProductType class AppsFlyerAnalyticsHandler( private val client: AppsFlyerAnalyticsClient, -) : AnalyticsEventHandler, ShopifyOrderEventHandler { +) : AnalyticsEventHandler { override fun id(): String = ID @@ -17,12 +13,6 @@ class AppsFlyerAnalyticsHandler( client.logEvent(event, params) } - override fun send(order: Storefront.Order, productType: ProductType) { - //TODO: make sending this event through filters - val event = ShopOrderToEventConverter().convert(order to productType) - send(event) - } - companion object { const val ID = "AppsFlyer" } 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 index f2abc8ca76..9a4a8bf839 100644 --- 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 @@ -1,6 +1,5 @@ package com.tangem.tap.common.analytics.handlers.firebase -import com.shopify.buy3.Storefront import com.tangem.blockchain.common.BlockchainError import com.tangem.common.card.Card import com.tangem.common.core.TangemSdkError @@ -10,15 +9,12 @@ import com.tangem.tap.common.analytics.api.AnalyticsEventHandler import com.tangem.tap.common.analytics.api.AnalyticsHandlerBuilder import com.tangem.tap.common.analytics.api.ErrorEventHandler import com.tangem.tap.common.analytics.api.SdkErrorEventHandler -import com.tangem.tap.common.analytics.api.ShopifyOrderEventHandler import com.tangem.tap.common.analytics.converters.BlockchainSdkErrorConverter import com.tangem.tap.common.analytics.converters.CardSdkErrorConverter -import com.tangem.tap.common.analytics.converters.ShopOrderToEventConverter -import com.tangem.tap.common.shop.data.ProductType class FirebaseAnalyticsHandler( private val client: FirebaseAnalyticsClient, -) : AnalyticsEventHandler, ErrorEventHandler, SdkErrorEventHandler, ShopifyOrderEventHandler { +) : AnalyticsEventHandler, ErrorEventHandler, SdkErrorEventHandler { override fun id(): String = ID @@ -57,12 +53,6 @@ class FirebaseAnalyticsHandler( } } - override fun send(order: Storefront.Order, productType: ProductType) { - //TODO: make sending this event through filters - val event = ShopOrderToEventConverter().convert(order to productType) - send(event) - } - companion object { const val ID = "Firebase" } 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 3d2c060786..271886dea1 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,6 +5,7 @@ import android.content.Intent import com.google.android.gms.wallet.PaymentData import com.shopify.buy3.Storefront import com.tangem.tap.common.analytics.Analytics +import com.tangem.tap.common.analytics.converters.ShopOrderToEventConverter import com.tangem.tap.common.extensions.filterNotNull import com.tangem.tap.common.shop.data.ProductType import com.tangem.tap.common.shop.data.TangemProduct @@ -198,7 +199,12 @@ class TangemShopService(application: Application, shopifyShop: ShopifyShop) { suspend fun waitForCheckout(productType: ProductType) { val result = shopifyService.checkout(true, checkouts[productType]!!.id) - result.onSuccess { checkout -> checkout.order?.let { Analytics.send(it, productType) } } + result.onSuccess { checkout -> + checkout.order?.let { + val event = ShopOrderToEventConverter().convert(it to productType) + Analytics.send(event) + } + } } companion object { From bd0adfea6ffc5d403816862ed99b391900d3f55b Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 2 Nov 2022 21:24:22 +0500 Subject: [PATCH 36/47] Updated on 2026-08-14 --- .../onboarding/products/twins/redux/TwinCardsMiddleware.kt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt index bf3cb1296c..aa6de330d6 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsMiddleware.kt @@ -1,5 +1,6 @@ package com.tangem.tap.features.onboarding.products.twins.redux +import com.tangem.blockchain.common.Blockchain import com.tangem.blockchain.extensions.Result import com.tangem.common.CompletionResult import com.tangem.common.extensions.guard @@ -7,6 +8,7 @@ import com.tangem.domain.common.ScanResponse import com.tangem.domain.common.extensions.withMainContext import com.tangem.tap.DELAY_SDK_DIALOG_CLOSE import com.tangem.tap.common.analytics.Analytics +import com.tangem.tap.common.analytics.events.AnalyticsParam import com.tangem.tap.common.analytics.events.Onboarding import com.tangem.tap.common.extensions.dispatchDialogShow import com.tangem.tap.common.extensions.dispatchErrorNotification @@ -273,6 +275,10 @@ private fun handle(action: Action, dispatch: DispatchFunction) { } is TwinCardsAction.TopUp -> { val topUpUrl = twinCardsState.walletManager?.getTopUpUrl() ?: return + + val currencyType = AnalyticsParam.CurrencyType.Blockchain(Blockchain.Bitcoin) + Analytics.send(Onboarding.Topup.ButtonBuyCrypto(currencyType)) + store.dispatchOpenUrl(topUpUrl) } TwinCardsAction.Done -> { From 7d7b6106a0673e93a8d9c02866b72aeebe450de3 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 2 Nov 2022 21:48:54 +0500 Subject: [PATCH 37/47] Updated on 2026-08-14 --- .../java/com/tangem/tap/TapApplication.kt | 2 + .../converters/BasicSignInEventConverter.kt | 38 +++++++++++++++++++ .../converters/ParamCardCurrencyConverter.kt | 31 +++++++++++++++ .../common/analytics/events/AnalyticsEvent.kt | 1 + .../tap/common/analytics/events/Basic.kt | 2 +- .../analytics/filters/BasicSignInFilter.kt | 27 +++++++++++++ .../redux/reducers/TotalBalanceOperations.kt | 27 +++++++++---- .../tap/features/wallet/ui/WalletFragment.kt | 14 +++++++ 8 files changed, 134 insertions(+), 8 deletions(-) create mode 100644 app/src/main/java/com/tangem/tap/common/analytics/converters/BasicSignInEventConverter.kt create mode 100644 app/src/main/java/com/tangem/tap/common/analytics/converters/ParamCardCurrencyConverter.kt create mode 100644 app/src/main/java/com/tangem/tap/common/analytics/filters/BasicSignInFilter.kt diff --git a/app/src/main/java/com/tangem/tap/TapApplication.kt b/app/src/main/java/com/tangem/tap/TapApplication.kt index 5417042486..36fcd97572 100644 --- a/app/src/main/java/com/tangem/tap/TapApplication.kt +++ b/app/src/main/java/com/tangem/tap/TapApplication.kt @@ -17,6 +17,7 @@ import com.tangem.tap.common.AssetReader import com.tangem.tap.common.analytics.Analytics import com.tangem.tap.common.analytics.AnalyticsHandlersFactory import com.tangem.tap.common.analytics.api.AnalyticsHandlerBuilder +import com.tangem.tap.common.analytics.filters.BasicSignInFilter import com.tangem.tap.common.analytics.filters.ShopPurchasedEventFilter import com.tangem.tap.common.analytics.handlers.amplitude.AmplitudeAnalyticsHandler import com.tangem.tap.common.analytics.handlers.appsFlyer.AppsFlyerAnalyticsHandler @@ -125,6 +126,7 @@ class TapApplication : Application(), ImageLoaderFactory { } listOf( ShopPurchasedEventFilter(), + BasicSignInFilter(), ).forEach { Analytics.addFilter(it) } } diff --git a/app/src/main/java/com/tangem/tap/common/analytics/converters/BasicSignInEventConverter.kt b/app/src/main/java/com/tangem/tap/common/analytics/converters/BasicSignInEventConverter.kt new file mode 100644 index 0000000000..e3d07461d0 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/analytics/converters/BasicSignInEventConverter.kt @@ -0,0 +1,38 @@ +package com.tangem.tap.common.analytics.converters + +import com.tangem.common.Converter +import com.tangem.common.extensions.isZero +import com.tangem.domain.common.ScanResponse +import com.tangem.tap.common.analytics.events.AnalyticsParam +import com.tangem.tap.common.analytics.events.Basic +import com.tangem.tap.domain.tokens.UserWalletId +import com.tangem.tap.features.wallet.redux.ProgressState +import java.math.BigDecimal + +/** +[REDACTED_AUTHOR] + */ +class BasicSignInEventConverter( + private val scanResponse: ScanResponse, + private val progressState: ProgressState, + private val totalCryptoAmount: BigDecimal, +) : Converter { + + override fun convert(value: Any?): Basic.SignedIn? { + if (progressState == ProgressState.Loading || progressState == ProgressState.Refreshing) return null + val cardCurrency = ParamCardCurrencyConverter().convert(scanResponse) ?: return null + + val cardState = when { + totalCryptoAmount.isZero() -> AnalyticsParam.CardState.Empty + else -> AnalyticsParam.CardState.Full + } + + return Basic.SignedIn( + state = cardState, + currency = cardCurrency, + batch = scanResponse.card.batchId, + ).apply { + filterData = UserWalletId(scanResponse.card.wallets.first().publicKey).stringValue + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/analytics/converters/ParamCardCurrencyConverter.kt b/app/src/main/java/com/tangem/tap/common/analytics/converters/ParamCardCurrencyConverter.kt new file mode 100644 index 0000000000..e64b751f4f --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/analytics/converters/ParamCardCurrencyConverter.kt @@ -0,0 +1,31 @@ +package com.tangem.tap.common.analytics.converters + +import com.tangem.blockchain.common.Blockchain +import com.tangem.common.Converter +import com.tangem.domain.common.SaltPayWorkaround +import com.tangem.domain.common.ScanResponse +import com.tangem.domain.common.TapWorkarounds.getTangemNoteBlockchain +import com.tangem.tap.common.analytics.events.AnalyticsParam +import com.tangem.tap.domain.extensions.isMultiwalletAllowed + +/** +[REDACTED_AUTHOR] + */ +class ParamCardCurrencyConverter : Converter { + + override fun convert(value: ScanResponse): AnalyticsParam.CardCurrency? { + if (value.card.isMultiwalletAllowed) return AnalyticsParam.CardCurrency.MultiCurrency + + val type = when { + value.isTangemNote() -> { + value.card.getTangemNoteBlockchain()?.let { AnalyticsParam.CurrencyType.Blockchain(it) } + } + value.isTangemTwins() -> AnalyticsParam.CurrencyType.Blockchain(Blockchain.Bitcoin) + value.isSaltPay() -> AnalyticsParam.CurrencyType.Token(SaltPayWorkaround.tokenFrom(Blockchain.SaltPay)) + value.getPrimaryToken() != null -> AnalyticsParam.CurrencyType.Token(value.getPrimaryToken()!!) + else -> null + } ?: return null + + return AnalyticsParam.CardCurrency.SingleCurrency(type) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/analytics/events/AnalyticsEvent.kt b/app/src/main/java/com/tangem/tap/common/analytics/events/AnalyticsEvent.kt index 0451fdd68c..8e5cf0e942 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/events/AnalyticsEvent.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/events/AnalyticsEvent.kt @@ -7,4 +7,5 @@ sealed class AnalyticsEvent( val category: String, val event: String, val params: Map = mapOf(), + var filterData: Any? = null, ) \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/analytics/events/Basic.kt b/app/src/main/java/com/tangem/tap/common/analytics/events/Basic.kt index bb37145672..cba32f8061 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/events/Basic.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/events/Basic.kt @@ -8,7 +8,7 @@ sealed class Basic( params: Map = mapOf(), ) : AnalyticsEvent("Basic", event, params) { - sealed class SignedIn( + class SignedIn( state: AnalyticsParam.CardState, currency: AnalyticsParam.CardCurrency, batch: String, diff --git a/app/src/main/java/com/tangem/tap/common/analytics/filters/BasicSignInFilter.kt b/app/src/main/java/com/tangem/tap/common/analytics/filters/BasicSignInFilter.kt new file mode 100644 index 0000000000..c885cf7ae6 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/analytics/filters/BasicSignInFilter.kt @@ -0,0 +1,27 @@ +package com.tangem.tap.common.analytics.filters + +import com.tangem.tap.common.analytics.api.AnalyticsEventFilter +import com.tangem.tap.common.analytics.api.AnalyticsEventHandler +import com.tangem.tap.common.analytics.events.AnalyticsEvent +import com.tangem.tap.common.analytics.events.Basic + +/** +[REDACTED_AUTHOR] + */ +class BasicSignInFilter : AnalyticsEventFilter { + + private val alreadySignedIn = mutableSetOf() + + override fun canBeAppliedTo(event: AnalyticsEvent): Boolean = event is Basic.SignedIn + + override fun canBeSent(event: AnalyticsEvent): Boolean { + val userWalletId = event.filterData as? String ?: return false + + val canBeSent = !alreadySignedIn.contains(userWalletId) + alreadySignedIn.add(userWalletId) + + return canBeSent + } + + override fun canBeConsumedBy(handler: AnalyticsEventHandler, event: AnalyticsEvent): Boolean = true +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/TotalBalanceOperations.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/TotalBalanceOperations.kt index 15e44ea361..79470dae62 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/TotalBalanceOperations.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/TotalBalanceOperations.kt @@ -17,6 +17,12 @@ fun List.calculateTotalFiatAmount(): BigDecimal { .reduce(BigDecimal::plus) } +fun List.calculateTotalCryptoAmount(): BigDecimal { + return this + .map { it.currencyData.amount ?: BigDecimal.ZERO } + .reduce(BigDecimal::plus) +} + private fun List.mapToProgressState(): List { return this.map { wallet -> if (wallet.fiatRate == null) ProgressState.Error @@ -25,12 +31,15 @@ private fun List.mapToProgressState(): List { BalanceStatus.VerifiedOnline, BalanceStatus.SameCurrencyTransactionInProgress, BalanceStatus.TransactionInProgress, - BalanceStatus.NoAccount -> ProgressState.Done + BalanceStatus.NoAccount, + -> ProgressState.Done BalanceStatus.Unreachable, BalanceStatus.EmptyCard, - BalanceStatus.UnknownBlockchain -> ProgressState.Error + BalanceStatus.UnknownBlockchain, + -> ProgressState.Error BalanceStatus.Loading, - null -> ProgressState.Loading + null, + -> ProgressState.Loading } } } @@ -41,20 +50,24 @@ private infix fun ProgressState.or(newState: ProgressState): ProgressState { ProgressState.Loading, ProgressState.Refreshing, ProgressState.Error, - ProgressState.Done -> this + ProgressState.Done, + -> this } ProgressState.Done, - ProgressState.Error -> when (newState) { + ProgressState.Error, + -> when (newState) { ProgressState.Loading, ProgressState.Refreshing, - ProgressState.Error -> newState + ProgressState.Error, + -> newState ProgressState.Done -> this } ProgressState.Refreshing -> when (newState) { ProgressState.Loading -> this ProgressState.Refreshing, ProgressState.Error, - ProgressState.Done -> newState + ProgressState.Done, + -> newState } } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt index 97fba31222..b44dcebc1d 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt @@ -17,6 +17,7 @@ import coil.size.Scale import com.tangem.domain.common.TapWorkarounds.isSaltPay import com.tangem.tap.MainActivity import com.tangem.tap.common.analytics.Analytics +import com.tangem.tap.common.analytics.converters.BasicSignInEventConverter import com.tangem.tap.common.analytics.events.MainScreen import com.tangem.tap.common.analytics.events.Portfolio import com.tangem.tap.common.extensions.show @@ -33,6 +34,7 @@ import com.tangem.tap.features.wallet.redux.ErrorType import com.tangem.tap.features.wallet.redux.ProgressState import com.tangem.tap.features.wallet.redux.WalletAction import com.tangem.tap.features.wallet.redux.WalletState +import com.tangem.tap.features.wallet.redux.reducers.calculateTotalCryptoAmount import com.tangem.tap.features.wallet.ui.adapters.WarningMessagesAdapter import com.tangem.tap.features.wallet.ui.wallet.MultiWalletView import com.tangem.tap.features.wallet.ui.wallet.SaltPaySingleWalletView @@ -119,6 +121,7 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber Date: Thu, 3 Nov 2022 17:42:20 +0500 Subject: [PATCH 38/47] Updated on 2026-08-14 --- app/src/main/assets/tangem-app-config | 2 +- .../common/analytics/converters/BasicSignInEventConverter.kt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/assets/tangem-app-config b/app/src/main/assets/tangem-app-config index a1658496e7..cf6ea50867 160000 --- a/app/src/main/assets/tangem-app-config +++ b/app/src/main/assets/tangem-app-config @@ -1 +1 @@ -Subproject commit a1658496e777b611fc990ef2bc1a1a1fd48bc1e6 +Subproject commit cf6ea50867477f97655da9da47ff94987e8f3354 diff --git a/app/src/main/java/com/tangem/tap/common/analytics/converters/BasicSignInEventConverter.kt b/app/src/main/java/com/tangem/tap/common/analytics/converters/BasicSignInEventConverter.kt index e3d07461d0..083fd47f08 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/converters/BasicSignInEventConverter.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/converters/BasicSignInEventConverter.kt @@ -5,7 +5,7 @@ import com.tangem.common.extensions.isZero import com.tangem.domain.common.ScanResponse import com.tangem.tap.common.analytics.events.AnalyticsParam import com.tangem.tap.common.analytics.events.Basic -import com.tangem.tap.domain.tokens.UserWalletId +import com.tangem.tap.domain.extensions.getUserWalletId import com.tangem.tap.features.wallet.redux.ProgressState import java.math.BigDecimal @@ -32,7 +32,7 @@ class BasicSignInEventConverter( currency = cardCurrency, batch = scanResponse.card.batchId, ).apply { - filterData = UserWalletId(scanResponse.card.wallets.first().publicKey).stringValue + filterData = scanResponse.card.getUserWalletId() } } } \ No newline at end of file From d2d725c4e9927ce8e6b7b9f1334b460cf54ba31e Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 3 Nov 2022 17:45:42 +0500 Subject: [PATCH 39/47] Updated on 2026-08-14 --- .../java/com/tangem/tap/TapApplication.kt | 2 + .../converters/BasicEventConverter.kt | 76 +++++++++++++++++++ .../converters/BasicSignInEventConverter.kt | 38 ---------- .../common/analytics/events/AnalyticsParam.kt | 7 +- .../tap/common/analytics/events/Basic.kt | 2 +- .../analytics/filters/BasicTopUpFilter.kt | 50 ++++++++++++ .../tap/features/wallet/ui/WalletFragment.kt | 10 +-- .../tap/persistence/PreferencesStorage.kt | 2 + .../tap/persistence/ToppedUpWalletStorage.kt | 57 ++++++++++++++ 9 files changed, 195 insertions(+), 49 deletions(-) create mode 100644 app/src/main/java/com/tangem/tap/common/analytics/converters/BasicEventConverter.kt delete mode 100644 app/src/main/java/com/tangem/tap/common/analytics/converters/BasicSignInEventConverter.kt create mode 100644 app/src/main/java/com/tangem/tap/common/analytics/filters/BasicTopUpFilter.kt create mode 100644 app/src/main/java/com/tangem/tap/persistence/ToppedUpWalletStorage.kt diff --git a/app/src/main/java/com/tangem/tap/TapApplication.kt b/app/src/main/java/com/tangem/tap/TapApplication.kt index 36fcd97572..be1837114f 100644 --- a/app/src/main/java/com/tangem/tap/TapApplication.kt +++ b/app/src/main/java/com/tangem/tap/TapApplication.kt @@ -18,6 +18,7 @@ import com.tangem.tap.common.analytics.Analytics import com.tangem.tap.common.analytics.AnalyticsHandlersFactory import com.tangem.tap.common.analytics.api.AnalyticsHandlerBuilder import com.tangem.tap.common.analytics.filters.BasicSignInFilter +import com.tangem.tap.common.analytics.filters.BasicTopUpFilter import com.tangem.tap.common.analytics.filters.ShopPurchasedEventFilter import com.tangem.tap.common.analytics.handlers.amplitude.AmplitudeAnalyticsHandler import com.tangem.tap.common.analytics.handlers.appsFlyer.AppsFlyerAnalyticsHandler @@ -127,6 +128,7 @@ class TapApplication : Application(), ImageLoaderFactory { listOf( ShopPurchasedEventFilter(), BasicSignInFilter(), + BasicTopUpFilter(preferencesStorage.toppedUpWalletStorage), ).forEach { Analytics.addFilter(it) } } diff --git a/app/src/main/java/com/tangem/tap/common/analytics/converters/BasicEventConverter.kt b/app/src/main/java/com/tangem/tap/common/analytics/converters/BasicEventConverter.kt new file mode 100644 index 0000000000..3950f458bc --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/analytics/converters/BasicEventConverter.kt @@ -0,0 +1,76 @@ +package com.tangem.tap.common.analytics.converters + +import com.tangem.common.Converter +import com.tangem.common.extensions.isZero +import com.tangem.domain.common.ScanResponse +import com.tangem.tap.common.analytics.events.AnalyticsParam +import com.tangem.tap.common.analytics.events.Basic +import com.tangem.tap.common.analytics.filters.BasicTopUpFilter +import com.tangem.tap.domain.extensions.getUserWalletId +import com.tangem.tap.domain.extensions.isMultiwalletAllowed +import com.tangem.tap.features.wallet.redux.ProgressState +import com.tangem.tap.features.wallet.redux.WalletData +import com.tangem.tap.features.wallet.redux.WalletState +import com.tangem.tap.features.wallet.redux.reducers.calculateTotalCryptoAmount + +/** +[REDACTED_AUTHOR] + */ +class BasicSignInEventConverter( + private val scanResponse: ScanResponse, +) : Converter { + + override fun convert(value: WalletState): Basic.SignedIn? { + if (!statesIsReadyToCreateEvent(scanResponse, value)) return null + val cardCurrency = ParamCardCurrencyConverter().convert(scanResponse) ?: return null + + return Basic.SignedIn( + state = AnalyticsParam.CardBalanceState.from(value.walletsData), + currency = cardCurrency, + batch = scanResponse.card.batchId, + ).apply { + filterData = scanResponse.card.getUserWalletId() + } + } +} + +class BasicTopUpEventConverter( + private val scanResponse: ScanResponse, +) : Converter { + + override fun convert(value: WalletState): Basic.ToppedUp? { + if (!statesIsReadyToCreateEvent(scanResponse, value)) return null + val cardCurrency = ParamCardCurrencyConverter().convert(scanResponse) ?: return null + + val data = BasicTopUpFilter.Data( + walletId = scanResponse.card.getUserWalletId(), + cardBalanceState = AnalyticsParam.CardBalanceState.from(value.walletsData), + ) + + return Basic.ToppedUp(cardCurrency).apply { filterData = data } + } +} + +private fun AnalyticsParam.CardBalanceState.Companion.from(walletsData: List): AnalyticsParam.CardBalanceState { + val totalCryptoAmount = walletsData.calculateTotalCryptoAmount() + return when { + totalCryptoAmount.isZero() -> AnalyticsParam.CardBalanceState.Empty + else -> AnalyticsParam.CardBalanceState.Full + } +} + +private fun statesIsReadyToCreateEvent(scanResponse: ScanResponse, state: WalletState): Boolean { + if (scanResponse.card.isMultiwalletAllowed && state.missingDerivations.isNotEmpty()) return false + if (state.walletsData.isEmpty()) return false + + val totalBalanceState = state.totalBalance?.state ?: return false + if (totalBalanceState == ProgressState.Loading || totalBalanceState == ProgressState.Refreshing) return false + + val balancesCount = state.walletsData.map { + if (it.currencyData.amount == null) 0 else 1 + }.reduce { acc, i -> acc + i } + + if (balancesCount != state.wallets.size) return false + + return true +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/analytics/converters/BasicSignInEventConverter.kt b/app/src/main/java/com/tangem/tap/common/analytics/converters/BasicSignInEventConverter.kt deleted file mode 100644 index 083fd47f08..0000000000 --- a/app/src/main/java/com/tangem/tap/common/analytics/converters/BasicSignInEventConverter.kt +++ /dev/null @@ -1,38 +0,0 @@ -package com.tangem.tap.common.analytics.converters - -import com.tangem.common.Converter -import com.tangem.common.extensions.isZero -import com.tangem.domain.common.ScanResponse -import com.tangem.tap.common.analytics.events.AnalyticsParam -import com.tangem.tap.common.analytics.events.Basic -import com.tangem.tap.domain.extensions.getUserWalletId -import com.tangem.tap.features.wallet.redux.ProgressState -import java.math.BigDecimal - -/** -[REDACTED_AUTHOR] - */ -class BasicSignInEventConverter( - private val scanResponse: ScanResponse, - private val progressState: ProgressState, - private val totalCryptoAmount: BigDecimal, -) : Converter { - - override fun convert(value: Any?): Basic.SignedIn? { - if (progressState == ProgressState.Loading || progressState == ProgressState.Refreshing) return null - val cardCurrency = ParamCardCurrencyConverter().convert(scanResponse) ?: return null - - val cardState = when { - totalCryptoAmount.isZero() -> AnalyticsParam.CardState.Empty - else -> AnalyticsParam.CardState.Full - } - - return Basic.SignedIn( - state = cardState, - currency = cardCurrency, - batch = scanResponse.card.batchId, - ).apply { - filterData = scanResponse.card.getUserWalletId() - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/analytics/events/AnalyticsParam.kt b/app/src/main/java/com/tangem/tap/common/analytics/events/AnalyticsParam.kt index 08cc1d9e5b..71e6eb6c09 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/events/AnalyticsParam.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/events/AnalyticsParam.kt @@ -18,9 +18,10 @@ sealed class AnalyticsParam { class SingleCurrency(type: CurrencyType) : CardCurrency(type.value) } - sealed class CardState(val value: String) { - object Empty : CardState("Empty") - object Full : CardState("Full") + sealed class CardBalanceState(val value: String) { + object Empty : CardBalanceState("Empty") + object Full : CardBalanceState("Full") + companion object } sealed class RateApp(val value: String) { diff --git a/app/src/main/java/com/tangem/tap/common/analytics/events/Basic.kt b/app/src/main/java/com/tangem/tap/common/analytics/events/Basic.kt index cba32f8061..f1e3927530 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/events/Basic.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/events/Basic.kt @@ -9,7 +9,7 @@ sealed class Basic( ) : AnalyticsEvent("Basic", event, params) { class SignedIn( - state: AnalyticsParam.CardState, + state: AnalyticsParam.CardBalanceState, currency: AnalyticsParam.CardCurrency, batch: String, ) : Basic( diff --git a/app/src/main/java/com/tangem/tap/common/analytics/filters/BasicTopUpFilter.kt b/app/src/main/java/com/tangem/tap/common/analytics/filters/BasicTopUpFilter.kt new file mode 100644 index 0000000000..5b0638231e --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/analytics/filters/BasicTopUpFilter.kt @@ -0,0 +1,50 @@ +package com.tangem.tap.common.analytics.filters + +import com.tangem.common.extensions.guard +import com.tangem.tap.common.analytics.api.AnalyticsEventFilter +import com.tangem.tap.common.analytics.api.AnalyticsEventHandler +import com.tangem.tap.common.analytics.events.AnalyticsEvent +import com.tangem.tap.common.analytics.events.AnalyticsParam +import com.tangem.tap.common.analytics.events.Basic +import com.tangem.tap.persistence.ToppedUpWalletStorage + +/** +[REDACTED_AUTHOR] + */ +class BasicTopUpFilter( + private val topupWalletStorage: ToppedUpWalletStorage, +) : AnalyticsEventFilter { + + override fun canBeAppliedTo(event: AnalyticsEvent): Boolean = event is Basic.ToppedUp + + override fun canBeSent(event: AnalyticsEvent): Boolean { + val data = event.filterData as? Data ?: return false + + val walletInfo = topupWalletStorage.restore(data.walletId).guard { + val newWalletInfo = Data( + walletId = data.walletId, + cardBalanceState = data.cardBalanceState, + ) + topupWalletStorage.save(newWalletInfo) + return false + } + + if (walletInfo.isToppedUp) return false + + return if (!walletInfo.isToppedUp && data.isToppedUp) { + topupWalletStorage.save(walletInfo.copy(cardBalanceState = AnalyticsParam.CardBalanceState.Full)) + true + } else { + false + } + } + + override fun canBeConsumedBy(handler: AnalyticsEventHandler, event: AnalyticsEvent): Boolean = true + + data class Data( + val walletId: String, + val cardBalanceState: AnalyticsParam.CardBalanceState, + ) { + val isToppedUp: Boolean = cardBalanceState == AnalyticsParam.CardBalanceState.Full + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt index b44dcebc1d..544d94e6ca 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt @@ -18,6 +18,7 @@ import com.tangem.domain.common.TapWorkarounds.isSaltPay import com.tangem.tap.MainActivity import com.tangem.tap.common.analytics.Analytics import com.tangem.tap.common.analytics.converters.BasicSignInEventConverter +import com.tangem.tap.common.analytics.converters.BasicTopUpEventConverter import com.tangem.tap.common.analytics.events.MainScreen import com.tangem.tap.common.analytics.events.Portfolio import com.tangem.tap.common.extensions.show @@ -34,7 +35,6 @@ import com.tangem.tap.features.wallet.redux.ErrorType import com.tangem.tap.features.wallet.redux.ProgressState import com.tangem.tap.features.wallet.redux.WalletAction import com.tangem.tap.features.wallet.redux.WalletState -import com.tangem.tap.features.wallet.redux.reducers.calculateTotalCryptoAmount import com.tangem.tap.features.wallet.ui.adapters.WarningMessagesAdapter import com.tangem.tap.features.wallet.ui.wallet.MultiWalletView import com.tangem.tap.features.wallet.ui.wallet.SaltPaySingleWalletView @@ -231,13 +231,9 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber = mutableSetOf() + + init { + walletList.addAll(restore()) + } + + fun save(userWalletInfo: BasicTopUpFilter.Data): Boolean { + walletList.removeAll { it.walletId == userWalletInfo.walletId } + walletList.add(userWalletInfo) + return save(walletList) + } + + fun restore(walletId: String): BasicTopUpFilter.Data? { + return walletList.firstOrNull { it.walletId == walletId } + } + + private fun save(userWallets: MutableSet): Boolean { + return try { + val json = jsonConverter.toJson(userWallets) + preferences.edit(true) { putString(KEY, json) } + true + } catch (ex: Exception) { + Timber.e(ex) + false + } + } + + private fun restore(): MutableSet { + val json = preferences.getString(KEY, null) ?: return mutableSetOf() + return try { + jsonConverter.fromJson(json, jsonConverter.typedList(BasicTopUpFilter.Data::class.java))!! + } catch (ex: Exception) { + preferences.edit(true) { remove(KEY) } + mutableSetOf() + } + } + + companion object { + private const val KEY = "userWalletsInfo" + } +} \ No newline at end of file From 431852f30c12e5f97ae3ea7539bf3e3cc5c7dc97 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 8 Nov 2022 14:53:46 +0500 Subject: [PATCH 40/47] Updated on 2026-08-14 --- .../tangem/tap/common/analytics/Analytics.kt | 60 ++++++++++++++----- 1 file changed, 44 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/common/analytics/Analytics.kt b/app/src/main/java/com/tangem/tap/common/analytics/Analytics.kt index 57617de12b..6e773bceab 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/Analytics.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/Analytics.kt @@ -3,6 +3,7 @@ package com.tangem.tap.common.analytics import com.tangem.blockchain.common.BlockchainError import com.tangem.common.card.Card import com.tangem.common.core.TangemSdkError +import com.tangem.domain.common.FeatureCoroutineExceptionHandler import com.tangem.tap.common.analytics.api.AnalyticsEventFilter import com.tangem.tap.common.analytics.api.AnalyticsEventHandler import com.tangem.tap.common.analytics.api.BlockchainSdkErrorEventHandler @@ -10,12 +11,20 @@ import com.tangem.tap.common.analytics.api.CardSdkErrorEventHandler import com.tangem.tap.common.analytics.api.ErrorEventLogger import com.tangem.tap.common.analytics.events.AnalyticsEvent import com.tangem.tap.common.extensions.filterNotNull +import kotlinx.coroutines.CoroutineName +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.asCoroutineDispatcher +import kotlinx.coroutines.launch +import java.util.concurrent.Executors /** [REDACTED_AUTHOR] */ object Analytics : GlobalAnalyticsEventHandler { + internal val analyticsScope: CoroutineScope by lazy { createScope() } + private val eventFilters = mutableListOf() private val handlers = mutableMapOf() @@ -47,18 +56,22 @@ object Analytics : GlobalAnalyticsEventHandler { } override fun send(event: String, params: Map) { - analyticsHandlers.forEach { it.send(event, params) } + analyticsScope.launch { + analyticsHandlers.forEach { it.send(event, params) } + } } override fun send(event: AnalyticsEvent, card: Card?, blockchain: String?) { - val eventFilter = eventFilters.firstOrNull { it.canBeAppliedTo(event) } + analyticsScope.launch { + val eventFilter = eventFilters.firstOrNull { it.canBeAppliedTo(event) } - when { - eventFilter == null -> analyticsHandlers.forEach { it.send(event, card, blockchain) } - eventFilter.canBeSent(event) -> { - analyticsHandlers - .filter { eventFilter.canBeConsumedBy(it, event) } - .forEach { it.send(event) } + when { + eventFilter == null -> analyticsHandlers.forEach { it.send(event, card, blockchain) } + eventFilter.canBeSent(event) -> { + analyticsHandlers + .filter { eventFilter.canBeConsumedBy(it, event) } + .forEach { it.send(event) } + } } } } @@ -69,14 +82,18 @@ object Analytics : GlobalAnalyticsEventHandler { card: Card?, blockchain: String?, ) { - analyticsHandlers.forEach { - it.handleAnalyticsEvent(event, params, card, blockchain) + analyticsScope.launch { + analyticsHandlers.forEach { + it.handleAnalyticsEvent(event, params, card, blockchain) + } } } override fun send(error: Throwable, params: Map) { - analyticsHandlers.filterIsInstance().forEach { - it.logErrorEvent(error, params) + analyticsScope.launch { + analyticsHandlers.filterIsInstance().forEach { + it.logErrorEvent(error, params) + } } } @@ -86,8 +103,10 @@ object Analytics : GlobalAnalyticsEventHandler { params: Map, card: Card?, ) { - analyticsHandlers.filterIsInstance().forEach { - it.send(error, action, params, card) + analyticsScope.launch { + analyticsHandlers.filterIsInstance().forEach { + it.send(error, action, params, card) + } } } @@ -97,8 +116,10 @@ object Analytics : GlobalAnalyticsEventHandler { params: Map, card: Card?, ) { - analyticsHandlers.filterIsInstance().forEach { - it.send(error, action, params, card) + analyticsScope.launch { + analyticsHandlers.filterIsInstance().forEach { + it.send(error, action, params, card) + } } } @@ -107,6 +128,13 @@ object Analytics : GlobalAnalyticsEventHandler { putAll(attachToAllEventsParams) } } + + private fun createScope(): CoroutineScope { + val name = "Analytics" + val dispatcher = Executors.newFixedThreadPool(1).asCoroutineDispatcher() + val exceptionHandler = FeatureCoroutineExceptionHandler.create(name) + return CoroutineScope(Job() + dispatcher + CoroutineName(name) + exceptionHandler) + } } fun GlobalAnalyticsEventHandler.logWcEvent(event: AnalyticsAnOld.WcAnalyticsEvent) { From de93d0f3503a9fd2c3dc6ed1f755a1ffeba07693 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 8 Nov 2022 18:26:18 +0500 Subject: [PATCH 41/47] Updated on 2026-08-14 --- app/src/main/assets/tangem-app-config | 2 +- .../tangem/tap/common/analytics/Analytics.kt | 67 +++++++++++++------ .../analytics/GlobalAnalyticsEventHandler.kt | 21 ------ .../analytics/api/ErrorEventHandlerApi.kt | 37 ++++++++++ .../common/analytics/api/EventFilterApi.kt | 7 +- .../common/analytics/api/EventHandlerApi.kt | 41 +----------- .../analytics/api/ParamsInterceptorApi.kt | 17 +++++ .../common/analytics/events/AnalyticsParam.kt | 4 +- .../tap/common/analytics/events/Basic.kt | 2 +- .../analytics/filters/BasicSignInFilter.kt | 2 +- .../analytics/filters/BasicTopUpFilter.kt | 2 +- .../filters/ShopPurchasedEventFilter.kt | 2 +- .../BatchIdParamsInterceptor.kt | 21 ++++++ .../tap/features/home/redux/HomeMiddleware.kt | 4 +- 14 files changed, 140 insertions(+), 89 deletions(-) delete mode 100644 app/src/main/java/com/tangem/tap/common/analytics/GlobalAnalyticsEventHandler.kt create mode 100644 app/src/main/java/com/tangem/tap/common/analytics/api/ErrorEventHandlerApi.kt create mode 100644 app/src/main/java/com/tangem/tap/common/analytics/api/ParamsInterceptorApi.kt create mode 100644 app/src/main/java/com/tangem/tap/common/analytics/paramsInterceptor/BatchIdParamsInterceptor.kt diff --git a/app/src/main/assets/tangem-app-config b/app/src/main/assets/tangem-app-config index cf6ea50867..a1658496e7 160000 --- a/app/src/main/assets/tangem-app-config +++ b/app/src/main/assets/tangem-app-config @@ -1 +1 @@ -Subproject commit cf6ea50867477f97655da9da47ff94987e8f3354 +Subproject commit a1658496e777b611fc990ef2bc1a1a1fd48bc1e6 diff --git a/app/src/main/java/com/tangem/tap/common/analytics/Analytics.kt b/app/src/main/java/com/tangem/tap/common/analytics/Analytics.kt index 6e773bceab..3950438219 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/Analytics.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/Analytics.kt @@ -6,9 +6,15 @@ import com.tangem.common.core.TangemSdkError import com.tangem.domain.common.FeatureCoroutineExceptionHandler import com.tangem.tap.common.analytics.api.AnalyticsEventFilter import com.tangem.tap.common.analytics.api.AnalyticsEventHandler +import com.tangem.tap.common.analytics.api.AnalyticsFilterHolder +import com.tangem.tap.common.analytics.api.AnalyticsHandlerHolder import com.tangem.tap.common.analytics.api.BlockchainSdkErrorEventHandler import com.tangem.tap.common.analytics.api.CardSdkErrorEventHandler +import com.tangem.tap.common.analytics.api.ErrorEventHandler import com.tangem.tap.common.analytics.api.ErrorEventLogger +import com.tangem.tap.common.analytics.api.ParamsInterceptor +import com.tangem.tap.common.analytics.api.ParamsInterceptorHolder +import com.tangem.tap.common.analytics.api.SdkErrorEventHandler import com.tangem.tap.common.analytics.events.AnalyticsEvent import com.tangem.tap.common.extensions.filterNotNull import kotlinx.coroutines.CoroutineName @@ -21,18 +27,27 @@ import java.util.concurrent.Executors /** [REDACTED_AUTHOR] */ +interface GlobalAnalyticsEventHandler : AnalyticsEventHandler, + ErrorEventHandler, + SdkErrorEventHandler, + AnalyticsHandlerHolder, + AnalyticsFilterHolder, + ParamsInterceptorHolder { + + fun send(event: AnalyticsEvent, card: Card? = null, blockchain: String? = null) +} + object Analytics : GlobalAnalyticsEventHandler { - internal val analyticsScope: CoroutineScope by lazy { createScope() } + private val analyticsScope: CoroutineScope by lazy { createScope() } - private val eventFilters = mutableListOf() private val handlers = mutableMapOf() + private val analyticsFilters = mutableSetOf() + private val paramsInterceptors = mutableMapOf() private val analyticsHandlers: List get() = handlers.values.toList() - private val attachToAllEventsParams: MutableMap = mutableMapOf() - override fun id(): String = analyticsHandlers.joinToString(", ") { it.id() } override fun addHandler(name: String, handler: AnalyticsEventHandler) { @@ -44,33 +59,39 @@ object Analytics : GlobalAnalyticsEventHandler { } override fun addFilter(filter: AnalyticsEventFilter) { - eventFilters.add(filter) + analyticsFilters.add(filter) } - override fun removeFilter(filter: AnalyticsEventFilter) { - eventFilters.remove(filter) + override fun removeFilter(filter: AnalyticsEventFilter): Boolean { + return analyticsFilters.remove(filter) } - override fun attachToAllEvents(key: String, value: String) { - attachToAllEventsParams[key] = value + override fun addParamsInterceptor(interceptor: ParamsInterceptor) { + paramsInterceptors[interceptor.id()] = interceptor + } + + override fun removeParamsInterceptor(interceptor: ParamsInterceptor): ParamsInterceptor? { + return paramsInterceptors.remove(interceptor.id()) } override fun send(event: String, params: Map) { analyticsScope.launch { - analyticsHandlers.forEach { it.send(event, params) } + analyticsHandlers.forEach { it.send(event, params.interceptParams()) } } } override fun send(event: AnalyticsEvent, card: Card?, blockchain: String?) { analyticsScope.launch { - val eventFilter = eventFilters.firstOrNull { it.canBeAppliedTo(event) } + val eventString = prepareEventString(event.category, event.event) + val eventParams = prepareParams(card, blockchain, event.interceptParams()) + val eventFilter = analyticsFilters.firstOrNull { it.canBeAppliedTo(event) } when { - eventFilter == null -> analyticsHandlers.forEach { it.send(event, card, blockchain) } + eventFilter == null -> analyticsHandlers.forEach { it.send(eventString, eventParams) } eventFilter.canBeSent(event) -> { analyticsHandlers - .filter { eventFilter.canBeConsumedBy(it, event) } - .forEach { it.send(event) } + .filter { handler -> eventFilter.canBeConsumedByHandler(handler, event) } + .forEach { it.send(eventString, eventParams) } } } } @@ -84,7 +105,7 @@ object Analytics : GlobalAnalyticsEventHandler { ) { analyticsScope.launch { analyticsHandlers.forEach { - it.handleAnalyticsEvent(event, params, card, blockchain) + it.handleAnalyticsEvent(event, params.interceptParams(), card, blockchain) } } } @@ -123,17 +144,21 @@ object Analytics : GlobalAnalyticsEventHandler { } } - override fun prepareParams(card: Card?, blockchain: String?, params: Map): Map { - return super.prepareParams(card, blockchain, params).toMutableMap().apply { - putAll(attachToAllEventsParams) - } + private fun AnalyticsEvent.interceptParams(): Map = params.interceptParams() + + private fun Map.interceptParams(): Map { + return this.toMutableMap().apply { interceptParams() } + } + + private fun MutableMap.interceptParams() { + paramsInterceptors.values.forEach { it.intercept(this) } } private fun createScope(): CoroutineScope { val name = "Analytics" val dispatcher = Executors.newFixedThreadPool(1).asCoroutineDispatcher() - val exceptionHandler = FeatureCoroutineExceptionHandler.create(name) - return CoroutineScope(Job() + dispatcher + CoroutineName(name) + exceptionHandler) + val exHandler = FeatureCoroutineExceptionHandler.create(name) + return CoroutineScope(Job() + dispatcher + CoroutineName(name) + exHandler) } } diff --git a/app/src/main/java/com/tangem/tap/common/analytics/GlobalAnalyticsEventHandler.kt b/app/src/main/java/com/tangem/tap/common/analytics/GlobalAnalyticsEventHandler.kt deleted file mode 100644 index 287f991527..0000000000 --- a/app/src/main/java/com/tangem/tap/common/analytics/GlobalAnalyticsEventHandler.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.tangem.tap.common.analytics - -import com.tangem.tap.common.analytics.api.AnalyticsEventFilter -import com.tangem.tap.common.analytics.api.AnalyticsEventHandler -import com.tangem.tap.common.analytics.api.ErrorEventHandler -import com.tangem.tap.common.analytics.api.SdkErrorEventHandler - -interface GlobalAnalyticsEventHandler : AnalyticsEventHandler, - ErrorEventHandler, - SdkErrorEventHandler { - - fun addHandler(name: String, handler: AnalyticsEventHandler) - - fun removeHandler(name: String): AnalyticsEventHandler? - - fun addFilter(filter: AnalyticsEventFilter) - - fun removeFilter(filter: AnalyticsEventFilter) - - fun attachToAllEvents(key: String, value: String) -} diff --git a/app/src/main/java/com/tangem/tap/common/analytics/api/ErrorEventHandlerApi.kt b/app/src/main/java/com/tangem/tap/common/analytics/api/ErrorEventHandlerApi.kt new file mode 100644 index 0000000000..3279075ea4 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/analytics/api/ErrorEventHandlerApi.kt @@ -0,0 +1,37 @@ +package com.tangem.tap.common.analytics.api + +import com.tangem.blockchain.common.BlockchainError +import com.tangem.common.card.Card +import com.tangem.common.core.TangemSdkError +import com.tangem.tap.common.analytics.AnalyticsAnOld +import com.tangem.tap.common.analytics.AnalyticsParamAnOld + +/** +[REDACTED_AUTHOR] + */ +interface ErrorEventHandler { + fun send( + error: Throwable, + params: Map = emptyMap(), + ) +} + +interface SdkErrorEventHandler : CardSdkErrorEventHandler, BlockchainSdkErrorEventHandler + +interface CardSdkErrorEventHandler { + fun send( + error: TangemSdkError, + action: AnalyticsAnOld.ActionToLog, + params: Map = emptyMap(), + card: Card? = null, + ) +} + +interface BlockchainSdkErrorEventHandler { + fun send( + error: BlockchainError, + action: AnalyticsAnOld.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/api/EventFilterApi.kt b/app/src/main/java/com/tangem/tap/common/analytics/api/EventFilterApi.kt index a4e93fa75b..c86313164b 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/api/EventFilterApi.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/api/EventFilterApi.kt @@ -8,5 +8,10 @@ import com.tangem.tap.common.analytics.events.AnalyticsEvent interface AnalyticsEventFilter { fun canBeAppliedTo(event: AnalyticsEvent): Boolean fun canBeSent(event: AnalyticsEvent): Boolean - fun canBeConsumedBy(handler: AnalyticsEventHandler, event: AnalyticsEvent): Boolean + fun canBeConsumedByHandler(handler: AnalyticsEventHandler, event: AnalyticsEvent): Boolean +} + +interface AnalyticsFilterHolder { + fun addFilter(filter: AnalyticsEventFilter) + fun removeFilter(filter: AnalyticsEventFilter): Boolean } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/analytics/api/EventHandlerApi.kt b/app/src/main/java/com/tangem/tap/common/analytics/api/EventHandlerApi.kt index 494747287e..5095d83dfa 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/api/EventHandlerApi.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/api/EventHandlerApi.kt @@ -1,15 +1,10 @@ package com.tangem.tap.common.analytics.api import android.app.Application -import com.tangem.blockchain.common.BlockchainError import com.tangem.common.card.Card -import com.tangem.common.core.TangemSdkError import com.tangem.common.json.MoshiJsonConverter import com.tangem.domain.common.AnalyticsHandlersLogConfig -import com.tangem.tap.common.analytics.AnalyticsAnOld import com.tangem.tap.common.analytics.AnalyticsEventAnOld -import com.tangem.tap.common.analytics.AnalyticsParamAnOld -import com.tangem.tap.common.analytics.events.AnalyticsEvent import com.tangem.tap.common.analytics.events.AnalyticsParam import com.tangem.tap.common.extensions.filterNotNull import com.tangem.tap.domain.configurable.config.Config @@ -22,13 +17,6 @@ interface AnalyticsEventHandler { fun send(event: String, params: Map = emptyMap()) - fun send(event: AnalyticsEvent, card: Card? = null, blockchain: String? = null) { - send( - event = prepareEventString(event.category, event.event), - params = prepareParams(card, blockchain, event.params), - ) - } - @Deprecated("Migrate to AnalyticsEvent") fun handleAnalyticsEvent( event: AnalyticsEventAnOld, @@ -45,7 +33,6 @@ interface AnalyticsEventHandler { params: Map = emptyMap(), ): Map = mapOf( AnalyticsParam.Firmware to card?.firmwareVersion?.stringValue, - AnalyticsParam.BatchId to card?.batchId, AnalyticsParam.Blockchain to blockchain, ).filterNotNull() + params @@ -54,31 +41,9 @@ interface AnalyticsEventHandler { } } -interface ErrorEventHandler { - fun send( - error: Throwable, - params: Map = emptyMap(), - ) -} - -interface SdkErrorEventHandler : CardSdkErrorEventHandler, BlockchainSdkErrorEventHandler - -interface CardSdkErrorEventHandler { - fun send( - error: TangemSdkError, - action: AnalyticsAnOld.ActionToLog, - params: Map = emptyMap(), - card: Card? = null, - ) -} - -interface BlockchainSdkErrorEventHandler { - fun send( - error: BlockchainError, - action: AnalyticsAnOld.ActionToLog, - params: Map = mapOf(), - card: Card? = null, - ) +interface AnalyticsHandlerHolder { + fun addHandler(name: String, handler: AnalyticsEventHandler) + fun removeHandler(name: String): AnalyticsEventHandler? } interface AnalyticsHandlerBuilder { diff --git a/app/src/main/java/com/tangem/tap/common/analytics/api/ParamsInterceptorApi.kt b/app/src/main/java/com/tangem/tap/common/analytics/api/ParamsInterceptorApi.kt new file mode 100644 index 0000000000..245ef32da5 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/analytics/api/ParamsInterceptorApi.kt @@ -0,0 +1,17 @@ +package com.tangem.tap.common.analytics.api + +import com.tangem.tap.common.analytics.events.AnalyticsEvent + +/** +[REDACTED_AUTHOR] + */ +interface ParamsInterceptor { + fun id(): String + fun canBeAppliedTo(event: AnalyticsEvent): Boolean + fun intercept(params: MutableMap) +} + +interface ParamsInterceptorHolder { + fun addParamsInterceptor(interceptor: ParamsInterceptor) + fun removeParamsInterceptor(interceptor: ParamsInterceptor): ParamsInterceptor? +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/analytics/events/AnalyticsParam.kt b/app/src/main/java/com/tangem/tap/common/analytics/events/AnalyticsParam.kt index 71e6eb6c09..0d76d1dd08 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/events/AnalyticsParam.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/events/AnalyticsParam.kt @@ -55,8 +55,10 @@ sealed class AnalyticsParam { } companion object Key { + const val BatchId = "Batch" + + // old keys const val Blockchain = "blockchain" - const val BatchId = "batch_id" const val Firmware = "firmware" } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/analytics/events/Basic.kt b/app/src/main/java/com/tangem/tap/common/analytics/events/Basic.kt index f1e3927530..229093235d 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/events/Basic.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/events/Basic.kt @@ -17,7 +17,7 @@ sealed class Basic( params = mapOf( "State" to state.value, "Currency" to currency.value, - "Batch" to batch, + AnalyticsParam.BatchId to batch, ), ) diff --git a/app/src/main/java/com/tangem/tap/common/analytics/filters/BasicSignInFilter.kt b/app/src/main/java/com/tangem/tap/common/analytics/filters/BasicSignInFilter.kt index c885cf7ae6..372f2787a3 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/filters/BasicSignInFilter.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/filters/BasicSignInFilter.kt @@ -23,5 +23,5 @@ class BasicSignInFilter : AnalyticsEventFilter { return canBeSent } - override fun canBeConsumedBy(handler: AnalyticsEventHandler, event: AnalyticsEvent): Boolean = true + override fun canBeConsumedByHandler(handler: AnalyticsEventHandler, event: AnalyticsEvent): Boolean = true } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/analytics/filters/BasicTopUpFilter.kt b/app/src/main/java/com/tangem/tap/common/analytics/filters/BasicTopUpFilter.kt index 5b0638231e..fea71037d9 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/filters/BasicTopUpFilter.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/filters/BasicTopUpFilter.kt @@ -39,7 +39,7 @@ class BasicTopUpFilter( } } - override fun canBeConsumedBy(handler: AnalyticsEventHandler, event: AnalyticsEvent): Boolean = true + override fun canBeConsumedByHandler(handler: AnalyticsEventHandler, event: AnalyticsEvent): Boolean = true data class Data( val walletId: String, diff --git a/app/src/main/java/com/tangem/tap/common/analytics/filters/ShopPurchasedEventFilter.kt b/app/src/main/java/com/tangem/tap/common/analytics/filters/ShopPurchasedEventFilter.kt index 5267782ddc..945dbefab4 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/filters/ShopPurchasedEventFilter.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/filters/ShopPurchasedEventFilter.kt @@ -16,7 +16,7 @@ class ShopPurchasedEventFilter : AnalyticsEventFilter { override fun canBeSent(event: AnalyticsEvent): Boolean = true - override fun canBeConsumedBy(handler: AnalyticsEventHandler, event: AnalyticsEvent): Boolean { + override fun canBeConsumedByHandler(handler: AnalyticsEventHandler, event: AnalyticsEvent): Boolean { return when (handler) { is AppsFlyerAnalyticsHandler, is FirebaseAnalyticsHandler -> true else -> false diff --git a/app/src/main/java/com/tangem/tap/common/analytics/paramsInterceptor/BatchIdParamsInterceptor.kt b/app/src/main/java/com/tangem/tap/common/analytics/paramsInterceptor/BatchIdParamsInterceptor.kt new file mode 100644 index 0000000000..ffe48cf198 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/analytics/paramsInterceptor/BatchIdParamsInterceptor.kt @@ -0,0 +1,21 @@ +package com.tangem.tap.common.analytics.paramsInterceptor + +import com.tangem.tap.common.analytics.api.ParamsInterceptor +import com.tangem.tap.common.analytics.events.AnalyticsEvent +import com.tangem.tap.common.analytics.events.AnalyticsParam + +/** +[REDACTED_AUTHOR] + */ +class BatchIdParamsInterceptor( + val batchId: String, +) : ParamsInterceptor { + + override fun id(): String = this::class.java.simpleName + + override fun canBeAppliedTo(event: AnalyticsEvent): Boolean = true + + override fun intercept(params: MutableMap) { + params[AnalyticsParam.BatchId] = batchId + } +} \ No newline at end of file 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 0148a2cbf7..16d6ee9efd 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 @@ -13,8 +13,8 @@ import com.tangem.tap.common.analytics.Analytics import com.tangem.tap.common.analytics.AnalyticsEventAnOld import com.tangem.tap.common.analytics.AnalyticsParamAnOld import com.tangem.tap.common.analytics.GetCardSourceParamsAnOld -import com.tangem.tap.common.analytics.events.AnalyticsParam import com.tangem.tap.common.analytics.events.IntroductionProcess +import com.tangem.tap.common.analytics.paramsInterceptor.BatchIdParamsInterceptor import com.tangem.tap.common.entities.IndeterminateProgressButton import com.tangem.tap.common.extensions.dispatchDialogShow import com.tangem.tap.common.extensions.dispatchOpenUrl @@ -165,7 +165,7 @@ private fun onScanSuccess(scanResponse: ScanResponse) { val tapWalletManager = globalState.tapWalletManager tapWalletManager.updateConfigManager(scanResponse) - Analytics.attachToAllEvents(AnalyticsParam.BatchId, scanResponse.card.batchId) + Analytics.addParamsInterceptor(BatchIdParamsInterceptor(scanResponse.card.batchId)) store.dispatch(TwinCardsAction.IfTwinsPrepareState(scanResponse)) From fec0f149526f4e4818bf7036a482fc7a5b02ce48 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 8 Nov 2022 18:37:46 +0500 Subject: [PATCH 42/47] Updated on 2026-08-14 --- .../com/tangem/tap/common/analytics/Analytics.kt | 4 ++-- .../tap/common/analytics/api/EventFilterApi.kt | 13 +++++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/common/analytics/Analytics.kt b/app/src/main/java/com/tangem/tap/common/analytics/Analytics.kt index 3950438219..276ef9059f 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/Analytics.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/Analytics.kt @@ -87,11 +87,11 @@ object Analytics : GlobalAnalyticsEventHandler { val eventFilter = analyticsFilters.firstOrNull { it.canBeAppliedTo(event) } when { - eventFilter == null -> analyticsHandlers.forEach { it.send(eventString, eventParams) } + eventFilter == null -> analyticsHandlers.forEach { handler -> handler.send(eventString, eventParams) } eventFilter.canBeSent(event) -> { analyticsHandlers .filter { handler -> eventFilter.canBeConsumedByHandler(handler, event) } - .forEach { it.send(eventString, eventParams) } + .forEach { handler -> handler.send(eventString, eventParams) } } } } diff --git a/app/src/main/java/com/tangem/tap/common/analytics/api/EventFilterApi.kt b/app/src/main/java/com/tangem/tap/common/analytics/api/EventFilterApi.kt index c86313164b..eb0f9587ce 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/api/EventFilterApi.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/api/EventFilterApi.kt @@ -4,10 +4,23 @@ import com.tangem.tap.common.analytics.events.AnalyticsEvent /** [REDACTED_AUTHOR] + * The filter is used to separate events to send and determine which handler it can be processed with. */ interface AnalyticsEventFilter { + /** + * Recognizes the event and checks if the given filter can be applied to the event. + */ fun canBeAppliedTo(event: AnalyticsEvent): Boolean + + /** + * An internal filter check that, on external or internal conditions, recognizes the possibility of + * sending an event. + */ fun canBeSent(event: AnalyticsEvent): Boolean + + /** + * Performs a check to see if the event can be dispatched by a specific handler + */ fun canBeConsumedByHandler(handler: AnalyticsEventHandler, event: AnalyticsEvent): Boolean } From 5030c571c5f297b2f963f1bc54517e3f3e6e7625 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 9 Nov 2022 06:08:40 +0500 Subject: [PATCH 43/47] Updated on 2026-08-14 --- .../java/com/tangem/tap/TapApplication.kt | 23 ++- .../tangem/tap/common/analytics/Analytics.kt | 145 +++--------------- .../common/analytics/AnalyticsEventAnOld.kt | 71 --------- .../tap/common/analytics/AnalyticsFactory.kt | 37 +++++ .../analytics/AnalyticsHandlersFactory.kt | 23 --- .../analytics/api/ErrorEventHandlerApi.kt | 37 ----- .../common/analytics/api/EventFilterApi.kt | 2 +- .../common/analytics/api/EventHandlerApi.kt | 43 ++---- .../converters/AnalyticsErrorConverter.kt | 70 +++++++++ .../converters/SdkErrorConverters.kt | 88 ----------- .../common/analytics/events/AnalyticsEvent.kt | 3 +- .../common/analytics/events/AnalyticsParam.kt | 13 +- .../tap/common/analytics/events/Basic.kt | 8 +- .../tap/common/analytics/events/Settings.kt | 15 +- .../tap/common/analytics/events/Token.kt | 9 +- .../common/analytics/events/WalletConnect.kt | 6 +- .../analytics/filters/BasicSignInFilter.kt | 4 +- .../analytics/filters/BasicTopUpFilter.kt | 4 +- .../filters/ShopPurchasedEventFilter.kt | 4 +- .../amplitude/AmplitudeAnalyticsHandler.kt | 6 +- .../appsFlyer/AppsFlyerAnalyticsHandler.kt | 6 +- .../firebase/FirebaseAnalyticsHandler.kt | 59 +++---- .../com/tangem/tap/domain/TangemSdkManager.kt | 32 +--- .../tap/domain/twins/TwinCardsManager.kt | 44 +----- .../walletconnect/WalletConnectManager.kt | 52 +++---- .../walletconnect/WalletConnectSdkHelper.kt | 41 ++--- .../details/redux/DetailsMiddleware.kt | 28 +--- .../tap/features/home/redux/HomeMiddleware.kt | 7 - .../send/redux/middlewares/SendMiddleware.kt | 20 +-- .../redux/middlewares/WalletMiddleware.kt | 12 +- .../redux/middlewares/WarningsMiddleware.kt | 34 ++-- .../ui/adapters/WarningMessagesAdapter.kt | 10 +- 32 files changed, 298 insertions(+), 658 deletions(-) delete mode 100644 app/src/main/java/com/tangem/tap/common/analytics/AnalyticsEventAnOld.kt create mode 100644 app/src/main/java/com/tangem/tap/common/analytics/AnalyticsFactory.kt delete mode 100644 app/src/main/java/com/tangem/tap/common/analytics/AnalyticsHandlersFactory.kt delete mode 100644 app/src/main/java/com/tangem/tap/common/analytics/api/ErrorEventHandlerApi.kt create mode 100644 app/src/main/java/com/tangem/tap/common/analytics/converters/AnalyticsErrorConverter.kt delete mode 100644 app/src/main/java/com/tangem/tap/common/analytics/converters/SdkErrorConverters.kt diff --git a/app/src/main/java/com/tangem/tap/TapApplication.kt b/app/src/main/java/com/tangem/tap/TapApplication.kt index be1837114f..568ca4af60 100644 --- a/app/src/main/java/com/tangem/tap/TapApplication.kt +++ b/app/src/main/java/com/tangem/tap/TapApplication.kt @@ -15,7 +15,7 @@ import com.tangem.network.common.MoshiConverter import com.tangem.tap.common.AndroidAssetReader import com.tangem.tap.common.AssetReader import com.tangem.tap.common.analytics.Analytics -import com.tangem.tap.common.analytics.AnalyticsHandlersFactory +import com.tangem.tap.common.analytics.AnalyticsFactory import com.tangem.tap.common.analytics.api.AnalyticsHandlerBuilder import com.tangem.tap.common.analytics.filters.BasicSignInFilter import com.tangem.tap.common.analytics.filters.BasicTopUpFilter @@ -110,10 +110,14 @@ class TapApplication : Application(), ImageLoaderFactory { } private fun initAnalytics(application: Application, config: Config) { - val factory = AnalyticsHandlersFactory() - factory.addBuilder(AmplitudeAnalyticsHandler.Builder()) - factory.addBuilder(AppsFlyerAnalyticsHandler.Builder()) - factory.addBuilder(FirebaseAnalyticsHandler.Builder()) + val factory = AnalyticsFactory() + factory.addHandlerBuilder(AmplitudeAnalyticsHandler.Builder()) + factory.addHandlerBuilder(AppsFlyerAnalyticsHandler.Builder()) + factory.addHandlerBuilder(FirebaseAnalyticsHandler.Builder()) + + factory.addFilter(ShopPurchasedEventFilter()) + factory.addFilter(BasicSignInFilter()) + factory.addFilter(BasicTopUpFilter(preferencesStorage.toppedUpWalletStorage)) val buildData = AnalyticsHandlerBuilder.Data( application = application, @@ -122,14 +126,7 @@ class TapApplication : Application(), ImageLoaderFactory { logConfig = LogConfig.analyticsHandlers, jsonConverter = MoshiJsonConverter.INSTANCE, ) - factory.build(buildData).forEach { - Analytics.addHandler(it.id(), it) - } - listOf( - ShopPurchasedEventFilter(), - BasicSignInFilter(), - BasicTopUpFilter(preferencesStorage.toppedUpWalletStorage), - ).forEach { Analytics.addFilter(it) } + factory.build(Analytics, buildData) } private fun initFeedbackManager(context: Context, preferencesStorage: PreferencesStorage, config: Config) { diff --git a/app/src/main/java/com/tangem/tap/common/analytics/Analytics.kt b/app/src/main/java/com/tangem/tap/common/analytics/Analytics.kt index 276ef9059f..03cb8437bb 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/Analytics.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/Analytics.kt @@ -1,22 +1,14 @@ package com.tangem.tap.common.analytics -import com.tangem.blockchain.common.BlockchainError -import com.tangem.common.card.Card -import com.tangem.common.core.TangemSdkError import com.tangem.domain.common.FeatureCoroutineExceptionHandler import com.tangem.tap.common.analytics.api.AnalyticsEventFilter import com.tangem.tap.common.analytics.api.AnalyticsEventHandler import com.tangem.tap.common.analytics.api.AnalyticsFilterHolder +import com.tangem.tap.common.analytics.api.AnalyticsHandler import com.tangem.tap.common.analytics.api.AnalyticsHandlerHolder -import com.tangem.tap.common.analytics.api.BlockchainSdkErrorEventHandler -import com.tangem.tap.common.analytics.api.CardSdkErrorEventHandler -import com.tangem.tap.common.analytics.api.ErrorEventHandler -import com.tangem.tap.common.analytics.api.ErrorEventLogger import com.tangem.tap.common.analytics.api.ParamsInterceptor import com.tangem.tap.common.analytics.api.ParamsInterceptorHolder -import com.tangem.tap.common.analytics.api.SdkErrorEventHandler import com.tangem.tap.common.analytics.events.AnalyticsEvent -import com.tangem.tap.common.extensions.filterNotNull import kotlinx.coroutines.CoroutineName import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job @@ -28,33 +20,26 @@ import java.util.concurrent.Executors [REDACTED_AUTHOR] */ interface GlobalAnalyticsEventHandler : AnalyticsEventHandler, - ErrorEventHandler, - SdkErrorEventHandler, AnalyticsHandlerHolder, AnalyticsFilterHolder, - ParamsInterceptorHolder { - - fun send(event: AnalyticsEvent, card: Card? = null, blockchain: String? = null) -} + ParamsInterceptorHolder object Analytics : GlobalAnalyticsEventHandler { private val analyticsScope: CoroutineScope by lazy { createScope() } - private val handlers = mutableMapOf() - private val analyticsFilters = mutableSetOf() + private val handlers = mutableMapOf() private val paramsInterceptors = mutableMapOf() + private val analyticsFilters = mutableSetOf() - private val analyticsHandlers: List + private val analyticsHandlers: List get() = handlers.values.toList() - override fun id(): String = analyticsHandlers.joinToString(", ") { it.id() } - - override fun addHandler(name: String, handler: AnalyticsEventHandler) { + override fun addHandler(name: String, handler: AnalyticsHandler) { handlers[name] = handler } - override fun removeHandler(name: String): AnalyticsEventHandler? { + override fun removeHandler(name: String): AnalyticsHandler? { return handlers.remove(name) } @@ -74,84 +59,29 @@ object Analytics : GlobalAnalyticsEventHandler { return paramsInterceptors.remove(interceptor.id()) } - override fun send(event: String, params: Map) { + override fun send(event: AnalyticsEvent) { analyticsScope.launch { - analyticsHandlers.forEach { it.send(event, params.interceptParams()) } - } - } - - override fun send(event: AnalyticsEvent, card: Card?, blockchain: String?) { - analyticsScope.launch { - val eventString = prepareEventString(event.category, event.event) - val eventParams = prepareParams(card, blockchain, event.interceptParams()) - + event.params = applyParamsInterceptors(event) val eventFilter = analyticsFilters.firstOrNull { it.canBeAppliedTo(event) } + when { - eventFilter == null -> analyticsHandlers.forEach { handler -> handler.send(eventString, eventParams) } + eventFilter == null -> analyticsHandlers.forEach { handler -> handler.send(event) } eventFilter.canBeSent(event) -> { analyticsHandlers .filter { handler -> eventFilter.canBeConsumedByHandler(handler, event) } - .forEach { handler -> handler.send(eventString, eventParams) } + .forEach { handler -> handler.send(event) } } } } } - override fun handleAnalyticsEvent( - event: AnalyticsEventAnOld, - params: Map, - card: Card?, - blockchain: String?, - ) { - analyticsScope.launch { - analyticsHandlers.forEach { - it.handleAnalyticsEvent(event, params.interceptParams(), card, blockchain) - } - } - } + private fun applyParamsInterceptors(event: AnalyticsEvent): MutableMap { + val interceptedParams = event.params.toMutableMap() + paramsInterceptors.values + .filter { it.canBeAppliedTo(event) } + .forEach { it.intercept(interceptedParams) } - override fun send(error: Throwable, params: Map) { - analyticsScope.launch { - analyticsHandlers.filterIsInstance().forEach { - it.logErrorEvent(error, params) - } - } - } - - override fun send( - error: TangemSdkError, - action: AnalyticsAnOld.ActionToLog, - params: Map, - card: Card?, - ) { - analyticsScope.launch { - analyticsHandlers.filterIsInstance().forEach { - it.send(error, action, params, card) - } - } - } - - override fun send( - error: BlockchainError, - action: AnalyticsAnOld.ActionToLog, - params: Map, - card: Card?, - ) { - analyticsScope.launch { - analyticsHandlers.filterIsInstance().forEach { - it.send(error, action, params, card) - } - } - } - - private fun AnalyticsEvent.interceptParams(): Map = params.interceptParams() - - private fun Map.interceptParams(): Map { - return this.toMutableMap().apply { interceptParams() } - } - - private fun MutableMap.interceptParams() { - paramsInterceptors.values.forEach { it.intercept(this) } + return interceptedParams } private fun createScope(): CoroutineScope { @@ -160,43 +90,4 @@ object Analytics : GlobalAnalyticsEventHandler { val exHandler = FeatureCoroutineExceptionHandler.create(name) return CoroutineScope(Job() + dispatcher + CoroutineName(name) + exHandler) } -} - -fun GlobalAnalyticsEventHandler.logWcEvent(event: AnalyticsAnOld.WcAnalyticsEvent) { - when (event) { - is AnalyticsAnOld.WcAnalyticsEvent.Action -> { - handleAnalyticsEvent( - event = AnalyticsEventAnOld.WC_SUCCESS_RESPONSE, - params = mapOf( - AnalyticsParamAnOld.WALLET_CONNECT_ACTION.param to event.action.name, - ), - ) - } - is AnalyticsAnOld.WcAnalyticsEvent.Error -> { - val params = mapOf( - AnalyticsParamAnOld.WALLET_CONNECT_ACTION.param to event.action?.name, - AnalyticsParamAnOld.ERROR_DESCRIPTION.param to event.error.message, - ).filterNotNull() - send(event.error, params) - } - is AnalyticsAnOld.WcAnalyticsEvent.InvalidRequest -> - handleAnalyticsEvent( - event = AnalyticsEventAnOld.WC_INVALID_REQUEST, - params = mapOf( - AnalyticsParamAnOld.WALLET_CONNECT_REQUEST.param to event.json, - ).filterNotNull(), - ) - is AnalyticsAnOld.WcAnalyticsEvent.Session -> { - val analyticsEvent = when (event.event) { - AnalyticsAnOld.WcSessionEvent.Disconnect -> AnalyticsEventAnOld.WC_SESSION_DISCONNECTED - AnalyticsAnOld.WcSessionEvent.Connect -> AnalyticsEventAnOld.WC_NEW_SESSION - } - handleAnalyticsEvent( - event = analyticsEvent, - params = mapOf( - AnalyticsParamAnOld.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/AnalyticsEventAnOld.kt b/app/src/main/java/com/tangem/tap/common/analytics/AnalyticsEventAnOld.kt deleted file mode 100644 index 41cc0d9b96..0000000000 --- a/app/src/main/java/com/tangem/tap/common/analytics/AnalyticsEventAnOld.kt +++ /dev/null @@ -1,71 +0,0 @@ -package com.tangem.tap.common.analytics - -enum class AnalyticsEventAnOld(val event: String) { - CARD_IS_SCANNED("card_is_scanned"), - TRANSACTION_IS_SENT("transaction_is_sent"), - READY_TO_SCAN("ready_to_scan"), - DEMO_MODE_ACTIVATED("demo_mode_activated"), - - APP_RATING_DISPLAYED("rate_app_warning_displayed"), - APP_RATING_DISMISS("dismiss_rate_app_warning"), - APP_RATING_NEGATIVE("negative_rate_app_feedback"), - APP_RATING_POSITIVE("positive_rate_app_feedback"), - - WC_SUCCESS_RESPONSE("wallet_connect_success_response"), - WC_INVALID_REQUEST("wallet_connect_invalid_request"), - WC_NEW_SESSION("wallet_connect_new_session"), - WC_SESSION_DISCONNECTED("wallet_connect_session_disconnected"), - - GET_CARD("get_card"), -} - -enum class AnalyticsParamAnOld(val param: String) { - BLOCKCHAIN("blockchain"), - CARD_ID("cardId"), - BATCH_ID("batch_id"), - FIRMWARE("firmware"), - ACTION("action"), - ERROR_DESCRIPTION("error_description"), - ERROR_CODE("error_code"), - NEW_SECURITY_OPTION("new_security_option"), - ERROR_KEY("Tangem SDK error key"), - - WALLET_CONNECT_ACTION("wallet_connect_action"), - WALLET_CONNECT_REQUEST("wallet_connect_request"), - WALLET_CONNECT_DAPP_URL("wallet_connect_dapp_url"), - - SOURCE("source"), -} - -enum class GetCardSourceParamsAnOld(val param: String) { - WELCOME("welcome"), - ONBOARDING_BUY_MORE("wallet_onboaring_buy_more_cards"), - ONBOARDING("wallet_onboarding") -} - -object AnalyticsAnOld { - enum class ActionToLog(val key: String) { - Scan("tap_scan_task"), - SendTransaction("send_transaction"), - WalletConnectSign("wallet_connect_personal_sign"), - WalletConnectTransaction("wallet_connect_tx_sign"), - ReadPinSettings("read_pin_settings"), - ChangeSecOptions("change_sec_options"), - CreateWallet("create_wallet"), - PurgeWallet("purge_wallet"), - WriteIssuerData("write_issuer_data"), - } - - enum class WcSessionEvent { Disconnect, Connect } - - enum class WcAction { PersonalSign, SignTransaction, SendTransaction } - - sealed class WcAnalyticsEvent { - data class Error(val error: Throwable, val action: WcAction?) : - WcAnalyticsEvent() - - data class Session(val event: WcSessionEvent, val url: String?) : WcAnalyticsEvent() - data class Action(val action: WcAction) : WcAnalyticsEvent() - data class InvalidRequest(val json: String?) : WcAnalyticsEvent() - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/analytics/AnalyticsFactory.kt b/app/src/main/java/com/tangem/tap/common/analytics/AnalyticsFactory.kt new file mode 100644 index 0000000000..8936adfc3c --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/analytics/AnalyticsFactory.kt @@ -0,0 +1,37 @@ +package com.tangem.tap.common.analytics + +import com.tangem.tap.common.analytics.api.AnalyticsEventFilter +import com.tangem.tap.common.analytics.api.AnalyticsHandlerBuilder +import com.tangem.tap.common.analytics.api.ParamsInterceptor + +/** +[REDACTED_AUTHOR] + */ +class AnalyticsFactory { + + private val builders = mutableListOf() + private val filters = mutableListOf() + private val interceptors = mutableListOf() + + fun addHandlerBuilder(builder: AnalyticsHandlerBuilder) { + builders.add(builder) + } + + fun addFilter(filter: AnalyticsEventFilter) { + filters.add(filter) + } + + fun addParamsInterceptor(interceptor: ParamsInterceptor) { + interceptors.add(interceptor) + } + + fun build(analytics: Analytics, data: AnalyticsHandlerBuilder.Data) { + builders.mapNotNull { it.build(data) }.forEach { analytics.addHandler(it.id(), it) } + filters.forEach { analytics.addFilter(it) } + interceptors.forEach { analytics.addParamsInterceptor(it) } + + builders.clear() + filters.clear() + interceptors.clear() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/analytics/AnalyticsHandlersFactory.kt b/app/src/main/java/com/tangem/tap/common/analytics/AnalyticsHandlersFactory.kt deleted file mode 100644 index a287f6fac2..0000000000 --- a/app/src/main/java/com/tangem/tap/common/analytics/AnalyticsHandlersFactory.kt +++ /dev/null @@ -1,23 +0,0 @@ -package com.tangem.tap.common.analytics - -import com.tangem.tap.common.analytics.api.AnalyticsEventHandler -import com.tangem.tap.common.analytics.api.AnalyticsHandlerBuilder - -/** -[REDACTED_AUTHOR] - */ -class AnalyticsHandlersFactory { - - private val builders = mutableListOf() - - fun addBuilder(builder: AnalyticsHandlerBuilder) { - builders.add(builder) - } - - fun build(data: AnalyticsHandlerBuilder.Data): List { - val handlers = builders.mapNotNull { it.build(data) } - builders.clear() - - return handlers - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/analytics/api/ErrorEventHandlerApi.kt b/app/src/main/java/com/tangem/tap/common/analytics/api/ErrorEventHandlerApi.kt deleted file mode 100644 index 3279075ea4..0000000000 --- a/app/src/main/java/com/tangem/tap/common/analytics/api/ErrorEventHandlerApi.kt +++ /dev/null @@ -1,37 +0,0 @@ -package com.tangem.tap.common.analytics.api - -import com.tangem.blockchain.common.BlockchainError -import com.tangem.common.card.Card -import com.tangem.common.core.TangemSdkError -import com.tangem.tap.common.analytics.AnalyticsAnOld -import com.tangem.tap.common.analytics.AnalyticsParamAnOld - -/** -[REDACTED_AUTHOR] - */ -interface ErrorEventHandler { - fun send( - error: Throwable, - params: Map = emptyMap(), - ) -} - -interface SdkErrorEventHandler : CardSdkErrorEventHandler, BlockchainSdkErrorEventHandler - -interface CardSdkErrorEventHandler { - fun send( - error: TangemSdkError, - action: AnalyticsAnOld.ActionToLog, - params: Map = emptyMap(), - card: Card? = null, - ) -} - -interface BlockchainSdkErrorEventHandler { - fun send( - error: BlockchainError, - action: AnalyticsAnOld.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/api/EventFilterApi.kt b/app/src/main/java/com/tangem/tap/common/analytics/api/EventFilterApi.kt index eb0f9587ce..04d6dbbb01 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/api/EventFilterApi.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/api/EventFilterApi.kt @@ -21,7 +21,7 @@ interface AnalyticsEventFilter { /** * Performs a check to see if the event can be dispatched by a specific handler */ - fun canBeConsumedByHandler(handler: AnalyticsEventHandler, event: AnalyticsEvent): Boolean + fun canBeConsumedByHandler(handler: AnalyticsHandler, event: AnalyticsEvent): Boolean } interface AnalyticsFilterHolder { diff --git a/app/src/main/java/com/tangem/tap/common/analytics/api/EventHandlerApi.kt b/app/src/main/java/com/tangem/tap/common/analytics/api/EventHandlerApi.kt index 5095d83dfa..344402f7f1 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/api/EventHandlerApi.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/api/EventHandlerApi.kt @@ -1,53 +1,44 @@ package com.tangem.tap.common.analytics.api import android.app.Application -import com.tangem.common.card.Card import com.tangem.common.json.MoshiJsonConverter import com.tangem.domain.common.AnalyticsHandlersLogConfig -import com.tangem.tap.common.analytics.AnalyticsEventAnOld -import com.tangem.tap.common.analytics.events.AnalyticsParam -import com.tangem.tap.common.extensions.filterNotNull +import com.tangem.tap.common.analytics.events.AnalyticsEvent import com.tangem.tap.domain.configurable.config.Config /** [REDACTED_AUTHOR] */ interface AnalyticsEventHandler { + fun send(event: AnalyticsEvent) +} + +interface AnalyticsHandler : AnalyticsEventHandler { fun id(): String fun send(event: String, params: Map = emptyMap()) - @Deprecated("Migrate to AnalyticsEvent") - fun handleAnalyticsEvent( - event: AnalyticsEventAnOld, - params: Map = emptyMap(), - card: Card? = null, - blockchain: String? = null, - ) { - send(event.event, prepareParams(card, blockchain, params)) + override fun send(event: AnalyticsEvent) { + send(prepareEventString(event), event.params) } - fun prepareParams( - card: Card? = null, - blockchain: String? = null, - params: Map = emptyMap(), - ): Map = mapOf( - AnalyticsParam.Firmware to card?.firmwareVersion?.stringValue, - AnalyticsParam.Blockchain to blockchain, - ).filterNotNull() + params + fun prepareEventString(event: AnalyticsEvent): String = "[${event.category}] ${event.event}" +} - fun prepareEventString(category: String, event: String): String { - return "[$category] $event" - } +interface ErrorEventHandler { + fun send( + error: Throwable, + params: Map = emptyMap(), + ) } interface AnalyticsHandlerHolder { - fun addHandler(name: String, handler: AnalyticsEventHandler) - fun removeHandler(name: String): AnalyticsEventHandler? + fun addHandler(name: String, handler: AnalyticsHandler) + fun removeHandler(name: String): AnalyticsHandler? } interface AnalyticsHandlerBuilder { - fun build(data: Data): AnalyticsEventHandler? + fun build(data: Data): AnalyticsHandler? data class Data( val application: Application, diff --git a/app/src/main/java/com/tangem/tap/common/analytics/converters/AnalyticsErrorConverter.kt b/app/src/main/java/com/tangem/tap/common/analytics/converters/AnalyticsErrorConverter.kt new file mode 100644 index 0000000000..b6fab47d07 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/analytics/converters/AnalyticsErrorConverter.kt @@ -0,0 +1,70 @@ +package com.tangem.tap.common.analytics.converters + +import com.tangem.blockchain.common.BlockchainSdkError +import com.tangem.common.Converter +import com.tangem.common.core.TangemSdkError +import com.tangem.tap.common.analytics.events.AnalyticsParam +import com.tangem.tap.features.demo.DemoTransactionSender + +/** +[REDACTED_AUTHOR] + */ +class AnalyticsErrorConverter : Converter> { + fun canBeHandled(error: Throwable): Boolean { + return when (error) { + is TangemSdkError.UserCancelled -> false + is BlockchainSdkError -> !error.customMessage.contains(DemoTransactionSender.ID) + else -> true + } + } + + override fun convert(value: Throwable): Map { + return when (value) { + is BlockchainSdkError -> BlockchainSdkErrorConverter(CardSdkErrorConverter()).convert(value) + is TangemSdkError -> CardSdkErrorConverter().convert(value) + else -> ThrowableErrorConverter().convert(value) + } + } +} + +private class ThrowableErrorConverter : Converter> { + override fun convert(value: Throwable): Map { + val unknown = "unknown" + return mapOf( + AnalyticsParam.ErrorKey to AnalyticsParam.Error.App.value, + AnalyticsParam.ErrorDescription to (value.message ?: value.cause?.message ?: unknown), + ) + } +} + +class CardSdkErrorConverter : Converter> { + + override fun convert(value: TangemSdkError): Map { + if (value is TangemSdkError.UserCancelled) return emptyMap() + + return mapOf( + AnalyticsParam.ErrorKey to AnalyticsParam.Error.CardSdk.value, + AnalyticsParam.ErrorCode to value.code.toString(), + AnalyticsParam.ErrorDescription to value.toString(), + ) + } +} + +private class BlockchainSdkErrorConverter( + private val cardSdkErrorConverter: CardSdkErrorConverter, +) : Converter> { + + override fun convert(value: BlockchainSdkError): Map { + if (value.customMessage.contains(DemoTransactionSender.ID)) return emptyMap() + + if (value is BlockchainSdkError.WrappedTangemError) { + return (value.tangemError as? TangemSdkError)?.let { cardSdkErrorConverter.convert(it) } ?: emptyMap() + } + + return mapOf( + AnalyticsParam.ErrorKey to AnalyticsParam.Error.BlockchainSdk.value, + AnalyticsParam.ErrorCode to value.code.toString(), + AnalyticsParam.ErrorDescription to "${value.javaClass.simpleName}: ${value.customMessage}", + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/analytics/converters/SdkErrorConverters.kt b/app/src/main/java/com/tangem/tap/common/analytics/converters/SdkErrorConverters.kt deleted file mode 100644 index 5229df8174..0000000000 --- a/app/src/main/java/com/tangem/tap/common/analytics/converters/SdkErrorConverters.kt +++ /dev/null @@ -1,88 +0,0 @@ -package com.tangem.tap.common.analytics.converters - -import com.tangem.blockchain.common.BlockchainError -import com.tangem.blockchain.common.BlockchainSdkError -import com.tangem.common.Converter -import com.tangem.common.core.TangemSdkError -import com.tangem.tap.common.analytics.AnalyticsAnOld -import com.tangem.tap.common.analytics.AnalyticsParamAnOld -import com.tangem.tap.common.analytics.TangemSdk -import com.tangem.tap.features.demo.DemoTransactionSender - -/** -[REDACTED_AUTHOR] - */ -internal data class ErrorEvent( - val throwable: Throwable, - val params: Map, -) - -internal class CardSdkErrorConverter : Converter { - - override fun convert(value: Model): ErrorEvent? { - if (value.error is TangemSdkError.UserCancelled) return null - - val mutableParams = value.params.convertToParamValue().toMutableMap().apply { - putAll(value.cardParams) - } - mutableParams[AnalyticsParamAnOld.ACTION.param] = value.action.key - mutableParams[AnalyticsParamAnOld.ERROR_CODE.param] = value.error.code.toString() - mutableParams[AnalyticsParamAnOld.ERROR_DESCRIPTION.param] = value.error.javaClass.simpleName - mutableParams[AnalyticsParamAnOld.ERROR_KEY.param] = "TangemSdkError" - - return ErrorEvent(TangemSdk.map(value.error), mutableParams) - } - - internal data class Model( - val error: TangemSdkError, - val action: AnalyticsAnOld.ActionToLog, - val params: Map, - val cardParams: Map, - ) -} - -internal class BlockchainSdkErrorConverter( - private val cardSdkErrorConverter: CardSdkErrorConverter, -) : Converter { - - override fun convert(value: Model): ErrorEvent? { - val error = (value.error as? BlockchainSdkError) ?: return null - - if (error is BlockchainSdkError.WrappedTangemError) { - val tangemSdkError = (error.tangemError as? TangemSdkError) ?: return null - - val cardSdkModel = CardSdkErrorConverter.Model( - error = tangemSdkError, - action = value.action, - params = value.params, - cardParams = value.cardParams, - ) - return cardSdkErrorConverter.convert(cardSdkModel) - } - - if (error.customMessage.contains(DemoTransactionSender.ID)) return null - - val mutableParams = value.params.convertToParamValue().toMutableMap() - mutableParams[AnalyticsParamAnOld.ACTION.param] = value.action.key - mutableParams[AnalyticsParamAnOld.ERROR_CODE.param] = error.code.toString() - mutableParams[AnalyticsParamAnOld.ERROR_DESCRIPTION.param] = "${error.javaClass.simpleName}: ${error.customMessage}" - mutableParams[AnalyticsParamAnOld.ERROR_KEY.param] = "BlockchainSdkError" - - return ErrorEvent(value.error, mutableParams) - } - - data class Model( - val error: BlockchainError, - val action: AnalyticsAnOld.ActionToLog, - val params: Map, - val cardParams: Map, - ) -} - -internal fun Map.convertToParamValue(): Map { - return mutableMapOf().also { newMap -> - this.forEach { - newMap[it.key.param] = it.value - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/analytics/events/AnalyticsEvent.kt b/app/src/main/java/com/tangem/tap/common/analytics/events/AnalyticsEvent.kt index 8e5cf0e942..b2db44fe52 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/events/AnalyticsEvent.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/events/AnalyticsEvent.kt @@ -6,6 +6,7 @@ package com.tangem.tap.common.analytics.events sealed class AnalyticsEvent( val category: String, val event: String, - val params: Map = mapOf(), + var params: Map = mapOf(), + val error: Throwable? = null, var filterData: Any? = null, ) \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/analytics/events/AnalyticsParam.kt b/app/src/main/java/com/tangem/tap/common/analytics/events/AnalyticsParam.kt index 0d76d1dd08..bad36d3f0d 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/events/AnalyticsParam.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/events/AnalyticsParam.kt @@ -54,11 +54,16 @@ sealed class AnalyticsParam { } } + sealed class Error(val value: String) { + object App : Error("App Error") + object CardSdk : Error("Card Sdk Error") + object BlockchainSdk : Error("Blockchain Sdk Error") + } + companion object Key { const val BatchId = "Batch" - - // old keys - const val Blockchain = "blockchain" - const val Firmware = "firmware" + const val ErrorDescription = "Error Description" + const val ErrorCode = "Error Code" + const val ErrorKey = "Error Key" } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/analytics/events/Basic.kt b/app/src/main/java/com/tangem/tap/common/analytics/events/Basic.kt index 229093235d..80afe6d3f8 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/events/Basic.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/events/Basic.kt @@ -6,7 +6,8 @@ package com.tangem.tap.common.analytics.events sealed class Basic( event: String, params: Map = mapOf(), -) : AnalyticsEvent("Basic", event, params) { + error: Throwable? = null, +) : AnalyticsEvent("Basic", event, params, error) { class SignedIn( state: AnalyticsParam.CardBalanceState, @@ -25,4 +26,9 @@ sealed class Basic( event = "Topped up", params = mapOf("Currency" to currency.value), ) + + class ScanError(error: Throwable) : Basic( + event = "Scan", + error = error, + ) } diff --git a/app/src/main/java/com/tangem/tap/common/analytics/events/Settings.kt b/app/src/main/java/com/tangem/tap/common/analytics/events/Settings.kt index b24d6ef042..38725048a7 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/events/Settings.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/events/Settings.kt @@ -9,7 +9,8 @@ sealed class Settings( category: String = "Settings", event: String, params: Map = mapOf(), -) : AnalyticsEvent(category, event, params) { + error: Throwable? = null, +) : AnalyticsEvent(category, event, params, error) { class ScreenOpened : Settings(event = "Settings Screen Opened") class ButtonChat : Settings(event = "Button - Chat") @@ -28,10 +29,15 @@ sealed class Settings( sealed class CardSettings( event: String, params: Map = mapOf(), - ) : Settings("Settings / Card Settings", event, params) { + error: Throwable? = null, + ) : Settings("Settings / Card Settings", event, params, error) { class ButtonFactoryReset : CardSettings("Button - Factory Reset") - class FactoryResetFinished : CardSettings("Factory Reset Finished") + class FactoryResetFinished(error: Throwable? = null) : CardSettings( + event = "Factory Reset Finished", + error = error, + ) + class UserCodeChanged : CardSettings("User Code Changed") class ButtonChangeSecurityMode : CardSettings("Button - Change Security Mode") @@ -40,9 +46,10 @@ sealed class Settings( params = mapOf("Type" to type.value), ) - class SecurityModeChanged(mode: AnalyticsParam.SecurityMode) : CardSettings( + class SecurityModeChanged(mode: AnalyticsParam.SecurityMode, error: Throwable? = null) : CardSettings( event = "Security Mode Changed", params = mapOf("Mode" to mode.value), + error = error, ) } diff --git a/app/src/main/java/com/tangem/tap/common/analytics/events/Token.kt b/app/src/main/java/com/tangem/tap/common/analytics/events/Token.kt index 9da6abe399..7445e31f33 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/events/Token.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/events/Token.kt @@ -9,7 +9,8 @@ sealed class Token( category: String, event: String, params: Map = mapOf(), -) : AnalyticsEvent(category, event, params) { + error: Throwable? = null, +) : AnalyticsEvent(category, event, params, error) { class Refreshed : Token("Token", "Refreshed") class ButtonExplore : Token("Token", "Button - Explore") @@ -57,16 +58,18 @@ sealed class Token( sealed class Send( event: String, params: Map = mapOf(), - ) : Token("Token / Send", event, params) { + error: Throwable? = null, + ) : Token("Token / Send", event, params, error) { class ScreenOpened : Send("Send Screen Opened") class ButtonPaste : Send("Button - Paste") class ButtonQRCode : Send("Button - QR Code") class ButtonSwapCurrency : Send("Button - Swap Currency") - class TransactionSent(type: CurrencyType) : Send( + class TransactionSent(type: CurrencyType, error: Throwable? = null) : Send( event = "Transaction Sent", params = mapOf("Token" to type.value), + error = error, ) } diff --git a/app/src/main/java/com/tangem/tap/common/analytics/events/WalletConnect.kt b/app/src/main/java/com/tangem/tap/common/analytics/events/WalletConnect.kt index 624145c63d..1ff587b2aa 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/events/WalletConnect.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/events/WalletConnect.kt @@ -6,9 +6,13 @@ package com.tangem.tap.common.analytics.events sealed class WalletConnect( event: String, params: Map = mapOf(), -) : AnalyticsEvent("Wallet Connect", event, params) { + error: Throwable? = null, +) : AnalyticsEvent("Wallet Connect", event, params, error) { class NewSessionEstablished : WalletConnect("New Session Established") class SessionDisconnected : WalletConnect("Session Disconnected") class RequestSigned : WalletConnect("Request Signed") + + class SignError(error: Throwable) : WalletConnect("Sign", error = error) + class TransactionError(error: Throwable) : WalletConnect("Transaction", error = error) } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/analytics/filters/BasicSignInFilter.kt b/app/src/main/java/com/tangem/tap/common/analytics/filters/BasicSignInFilter.kt index 372f2787a3..a582ea34f1 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/filters/BasicSignInFilter.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/filters/BasicSignInFilter.kt @@ -1,7 +1,7 @@ package com.tangem.tap.common.analytics.filters import com.tangem.tap.common.analytics.api.AnalyticsEventFilter -import com.tangem.tap.common.analytics.api.AnalyticsEventHandler +import com.tangem.tap.common.analytics.api.AnalyticsHandler import com.tangem.tap.common.analytics.events.AnalyticsEvent import com.tangem.tap.common.analytics.events.Basic @@ -23,5 +23,5 @@ class BasicSignInFilter : AnalyticsEventFilter { return canBeSent } - override fun canBeConsumedByHandler(handler: AnalyticsEventHandler, event: AnalyticsEvent): Boolean = true + override fun canBeConsumedByHandler(handler: AnalyticsHandler, event: AnalyticsEvent): Boolean = true } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/analytics/filters/BasicTopUpFilter.kt b/app/src/main/java/com/tangem/tap/common/analytics/filters/BasicTopUpFilter.kt index fea71037d9..be780ccd2d 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/filters/BasicTopUpFilter.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/filters/BasicTopUpFilter.kt @@ -2,7 +2,7 @@ package com.tangem.tap.common.analytics.filters import com.tangem.common.extensions.guard import com.tangem.tap.common.analytics.api.AnalyticsEventFilter -import com.tangem.tap.common.analytics.api.AnalyticsEventHandler +import com.tangem.tap.common.analytics.api.AnalyticsHandler import com.tangem.tap.common.analytics.events.AnalyticsEvent import com.tangem.tap.common.analytics.events.AnalyticsParam import com.tangem.tap.common.analytics.events.Basic @@ -39,7 +39,7 @@ class BasicTopUpFilter( } } - override fun canBeConsumedByHandler(handler: AnalyticsEventHandler, event: AnalyticsEvent): Boolean = true + override fun canBeConsumedByHandler(handler: AnalyticsHandler, event: AnalyticsEvent): Boolean = true data class Data( val walletId: String, diff --git a/app/src/main/java/com/tangem/tap/common/analytics/filters/ShopPurchasedEventFilter.kt b/app/src/main/java/com/tangem/tap/common/analytics/filters/ShopPurchasedEventFilter.kt index 945dbefab4..dffa123240 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/filters/ShopPurchasedEventFilter.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/filters/ShopPurchasedEventFilter.kt @@ -1,7 +1,7 @@ package com.tangem.tap.common.analytics.filters import com.tangem.tap.common.analytics.api.AnalyticsEventFilter -import com.tangem.tap.common.analytics.api.AnalyticsEventHandler +import com.tangem.tap.common.analytics.api.AnalyticsHandler import com.tangem.tap.common.analytics.events.AnalyticsEvent import com.tangem.tap.common.analytics.events.Shop import com.tangem.tap.common.analytics.handlers.appsFlyer.AppsFlyerAnalyticsHandler @@ -16,7 +16,7 @@ class ShopPurchasedEventFilter : AnalyticsEventFilter { override fun canBeSent(event: AnalyticsEvent): Boolean = true - override fun canBeConsumedByHandler(handler: AnalyticsEventHandler, event: AnalyticsEvent): Boolean { + override fun canBeConsumedByHandler(handler: AnalyticsHandler, event: AnalyticsEvent): Boolean { return when (handler) { is AppsFlyerAnalyticsHandler, is FirebaseAnalyticsHandler -> true else -> false 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 index 06f77c15b3..c76fe21d38 100644 --- 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 @@ -1,11 +1,11 @@ package com.tangem.tap.common.analytics.handlers.amplitude -import com.tangem.tap.common.analytics.api.AnalyticsEventHandler +import com.tangem.tap.common.analytics.api.AnalyticsHandler import com.tangem.tap.common.analytics.api.AnalyticsHandlerBuilder class AmplitudeAnalyticsHandler( private val client: AmplitudeAnalyticsClient, -) : AnalyticsEventHandler { +) : AnalyticsHandler { override fun id(): String = ID @@ -18,7 +18,7 @@ class AmplitudeAnalyticsHandler( } class Builder : AnalyticsHandlerBuilder { - override fun build(data: AnalyticsHandlerBuilder.Data): AnalyticsEventHandler? = when { + override fun build(data: AnalyticsHandlerBuilder.Data): AnalyticsHandler? = when { !data.isDebug -> AmplitudeClient(data.application, data.config.amplitudeApiKey) data.isDebug && data.logConfig.amplitude -> AmplitudeLogClient(data.jsonConverter) else -> null 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 index b91da358d6..c3968d9d72 100644 --- 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 @@ -1,11 +1,11 @@ package com.tangem.tap.common.analytics.handlers.appsFlyer -import com.tangem.tap.common.analytics.api.AnalyticsEventHandler +import com.tangem.tap.common.analytics.api.AnalyticsHandler import com.tangem.tap.common.analytics.api.AnalyticsHandlerBuilder class AppsFlyerAnalyticsHandler( private val client: AppsFlyerAnalyticsClient, -) : AnalyticsEventHandler { +) : AnalyticsHandler { override fun id(): String = ID @@ -18,7 +18,7 @@ class AppsFlyerAnalyticsHandler( } class Builder : AnalyticsHandlerBuilder { - override fun build(data: AnalyticsHandlerBuilder.Data): AnalyticsEventHandler? = when { + override fun build(data: AnalyticsHandlerBuilder.Data): AnalyticsHandler? = when { !data.isDebug -> AppsFlyerClient(data.application, data.config.appsFlyerDevKey) data.isDebug && data.logConfig.appsFlyer -> AppsFlyerLogClient(data.jsonConverter) else -> null 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 index 9a4a8bf839..109e61d0a5 100644 --- 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 @@ -1,20 +1,14 @@ package com.tangem.tap.common.analytics.handlers.firebase -import com.tangem.blockchain.common.BlockchainError -import com.tangem.common.card.Card -import com.tangem.common.core.TangemSdkError -import com.tangem.tap.common.analytics.AnalyticsAnOld -import com.tangem.tap.common.analytics.AnalyticsParamAnOld -import com.tangem.tap.common.analytics.api.AnalyticsEventHandler +import com.tangem.tap.common.analytics.api.AnalyticsHandler import com.tangem.tap.common.analytics.api.AnalyticsHandlerBuilder import com.tangem.tap.common.analytics.api.ErrorEventHandler -import com.tangem.tap.common.analytics.api.SdkErrorEventHandler -import com.tangem.tap.common.analytics.converters.BlockchainSdkErrorConverter -import com.tangem.tap.common.analytics.converters.CardSdkErrorConverter +import com.tangem.tap.common.analytics.converters.AnalyticsErrorConverter +import com.tangem.tap.common.analytics.events.AnalyticsEvent class FirebaseAnalyticsHandler( private val client: FirebaseAnalyticsClient, -) : AnalyticsEventHandler, ErrorEventHandler, SdkErrorEventHandler { +) : AnalyticsHandler, ErrorEventHandler { override fun id(): String = ID @@ -22,43 +16,32 @@ class FirebaseAnalyticsHandler( client.logEvent(event, params) } + override fun send(event: AnalyticsEvent) { + when (event.error) { + null -> super.send(event) + else -> { + val errorConverter = AnalyticsErrorConverter() + if (!errorConverter.canBeHandled(event.error)) return + + val errorParams = errorConverter.convert(event.error).toMutableMap() + errorParams["Category"] = event.category + errorParams["Event"] = event.event + errorParams.putAll(event.params) + send(event.error, errorParams) + } + } + } + override fun send(error: Throwable, params: Map) { client.logErrorEvent(error, params) } - override fun send( - error: TangemSdkError, - action: AnalyticsAnOld.ActionToLog, - params: Map, - card: Card?, - ) { - val model = CardSdkErrorConverter.Model(error, action, params, prepareParams(card)) - val converter = CardSdkErrorConverter() - converter.convert(model)?.let { - send(it.throwable, it.params) - } - } - - override fun send( - error: BlockchainError, - action: AnalyticsAnOld.ActionToLog, - params: Map, - card: Card?, - ) { - - val model = BlockchainSdkErrorConverter.Model(error, action, params, prepareParams(card)) - val converter = BlockchainSdkErrorConverter(CardSdkErrorConverter()) - converter.convert(model)?.let { - send(it.throwable, it.params) - } - } - companion object { const val ID = "Firebase" } class Builder : AnalyticsHandlerBuilder { - override fun build(data: AnalyticsHandlerBuilder.Data): AnalyticsEventHandler? = when { + override fun build(data: AnalyticsHandlerBuilder.Data): AnalyticsHandler? = when { !data.isDebug -> FirebaseClient() data.isDebug && data.logConfig.firebase -> FirebaseLogClient(data.jsonConverter) else -> null 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 194d6d5815..7d6db12a26 100644 --- a/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt @@ -27,14 +27,11 @@ import com.tangem.operations.pins.CheckUserCodesCommand import com.tangem.operations.pins.CheckUserCodesResponse import com.tangem.operations.pins.SetUserCodeCommand import com.tangem.tap.common.analytics.Analytics -import com.tangem.tap.common.analytics.AnalyticsAnOld -import com.tangem.tap.common.analytics.AnalyticsEventAnOld -import com.tangem.tap.common.analytics.AnalyticsParamAnOld +import com.tangem.tap.common.analytics.events.Basic import com.tangem.tap.domain.tasks.CreateWalletAndRescanTask import com.tangem.tap.domain.tasks.product.ResetToFactorySettingsTask import com.tangem.tap.domain.tasks.product.ScanProductTask import com.tangem.tap.domain.tokens.UserTokensRepository -import com.tangem.tap.features.demo.DemoHelper import com.tangem.wallet.R import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.isActive @@ -49,8 +46,6 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co additionalBlockchainsToDerive: Collection? = null, messageRes: Int? = null, ): CompletionResult { - Analytics.handleAnalyticsEvent(AnalyticsEventAnOld.READY_TO_SCAN, card = null) - val message = Message(context.getString(messageRes ?: R.string.initial_message_scan_header)) return runTaskAsyncReturnOnMain( runnable = ScanProductTask(null, userTokensRepository, additionalBlockchainsToDerive), @@ -71,29 +66,10 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co private fun sendScanResultsToAnalytics( result: CompletionResult, ) { - when (result) { - is CompletionResult.Success -> { - Analytics.handleAnalyticsEvent( - event = AnalyticsEventAnOld.CARD_IS_SCANNED, - card = result.data.card, - blockchain = result.data.walletData?.blockchain, - ) - if (DemoHelper.isDemoCard(result.data)) { - Analytics.handleAnalyticsEvent( - event = AnalyticsEventAnOld.DEMO_MODE_ACTIVATED, - params = mapOf(AnalyticsParamAnOld.CARD_ID.param to result.data.card.cardId), - card = result.data.card, - blockchain = result.data.walletData?.blockchain, - ) - } + if (result is CompletionResult.Failure) { + (result.error as? TangemSdkError)?.let { error -> + Analytics.send(Basic.ScanError(error)) } - is CompletionResult.Failure -> - (result.error as? TangemSdkError)?.let { error -> - Analytics.send( - error = error, - action = AnalyticsAnOld.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 fc80f3c5b0..c1f7001ebc 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 @@ -7,19 +7,16 @@ import com.tangem.blockchain.extensions.Result import com.tangem.common.CompletionResult import com.tangem.common.KeyPair import com.tangem.common.card.Card -import com.tangem.common.core.TangemSdkError import com.tangem.common.extensions.hexToBytes import com.tangem.common.extensions.toHexString import com.tangem.domain.common.ScanResponse 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.AnalyticsAnOld import com.tangem.tap.tangemSdkManager class TwinCardsManager( - private val card: Card, + card: Card, assetReader: AssetReader, ) { @@ -34,15 +31,7 @@ class TwinCardsManager( val response = tangemSdkManager.runTaskAsync(CreateFirstTwinWalletTask(), currentCardId, message) when (response) { is CompletionResult.Success -> currentCardPublicKey = response.data.wallet.publicKey.toHexString() - is CompletionResult.Failure -> { - (response.error as? TangemSdkError)?.let { error -> - Analytics.send( - error, - AnalyticsAnOld.ActionToLog.CreateWallet, - card = card - ) - } - } + is CompletionResult.Failure -> {} } return response } @@ -57,22 +46,14 @@ class TwinCardsManager( firstCardId = currentCardId, issuerKeys = issuerKeyPair, preparingMessage = preparingMessage, - creatingWalletMessage = creatingWalletMessage + creatingWalletMessage = creatingWalletMessage, ) val response = tangemSdkManager.runTaskAsync(task, null, initialMessage) when (response) { is CompletionResult.Success -> { secondCardPublicKey = response.data.wallet.publicKey.toHexString() } - is CompletionResult.Failure -> { - (response.error as? TangemSdkError)?.let { error -> - Analytics.send( - error, - AnalyticsAnOld.ActionToLog.CreateWallet, - card = card - ) - } - } + is CompletionResult.Failure -> {} } return response } @@ -80,20 +61,11 @@ class TwinCardsManager( suspend fun complete(message: Message): Result { val response = tangemSdkManager.runTaskAsync( FinalizeTwinTask(secondCardPublicKey!!.hexToBytes(), issuerKeyPair), - currentCardId, message + currentCardId, message, ) return when (response) { is CompletionResult.Success -> Result.Success(response.data) - is CompletionResult.Failure -> { - (response.error as? TangemSdkError)?.let { error -> - Analytics.send( - error, - AnalyticsAnOld.ActionToLog.WriteIssuerData, - card = card - ) - } - Result.fromTangemSdkError(response.error) - } + is CompletionResult.Failure -> Result.fromTangemSdkError(response.error) } } @@ -102,13 +74,13 @@ class TwinCardsManager( val issuer = getIssuers(reader).first { it.publicKey == publicKey } return KeyPair( publicKey = issuer.publicKey.hexToBytes(), - privateKey = issuer.privateKey.hexToBytes() + privateKey = issuer.privateKey.hexToBytes(), ) } private fun getAdapter(): JsonAdapter> { return MoshiConverter.defaultMoshi().adapter( - Types.newParameterizedType(List::class.java, Issuer::class.java) + Types.newParameterizedType(List::class.java, Issuer::class.java), ) } 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 31e16004cd..8b66d5ce12 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,9 +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.AnalyticsAnOld import com.tangem.tap.common.analytics.events.WalletConnect -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.domain.TapError @@ -226,11 +224,6 @@ class WalletConnectManager { private fun onSessionClosed(session: WCSession) { Analytics.send(WalletConnect.SessionDisconnected()) - Analytics.logWcEvent( - AnalyticsAnOld.WcAnalyticsEvent.Session( - AnalyticsAnOld.WcSessionEvent.Disconnect, sessions[session]?.peerMeta?.url - ) - ) sessions.remove(session) walletConnectRepository.removeSession(session) store.dispatchOnMain(WalletConnectAction.RemoveSession(session)) @@ -376,11 +369,6 @@ class WalletConnectManager { ) } Analytics.send(WalletConnect.NewSessionEstablished()) - Analytics.logWcEvent( - AnalyticsAnOld.WcAnalyticsEvent.Session( - AnalyticsAnOld.WcSessionEvent.Connect, peer.url, - ), - ) } } } @@ -391,11 +379,11 @@ class WalletConnectManager { } client.onEthSendTransaction = { id: Long, transaction: WCEthereumTransaction -> Timber.d("onEthSendTransaction: $transaction") - Analytics.logWcEvent( - AnalyticsAnOld.WcAnalyticsEvent.Action( - AnalyticsAnOld.WcAction.SendTransaction - ) - ) + // Analytics.logWcEvent( + // AnalyticsAnOld.WcAnalyticsEvent.Action( + // AnalyticsAnOld.WcAction.SendTransaction + // ) + // ) sessions[client.session]?.toWalletConnectSession()?.let { sessionData -> store.dispatchOnMain( WalletConnectAction.HandleTransactionRequest( @@ -409,11 +397,11 @@ class WalletConnectManager { } client.onEthSignTransaction = { id: Long, transaction: WCEthereumTransaction -> Timber.d("onEthSignTransaction: $transaction") - Analytics.logWcEvent( - AnalyticsAnOld.WcAnalyticsEvent.Action( - AnalyticsAnOld.WcAction.SignTransaction - ) - ) + // Analytics.logWcEvent( + // AnalyticsAnOld.WcAnalyticsEvent.Action( + // AnalyticsAnOld.WcAction.SignTransaction + // ) + // ) sessions[client.session]?.toWalletConnectSession()?.let { sessionData -> store.dispatchOnMain( WalletConnectAction.HandleTransactionRequest( @@ -427,11 +415,11 @@ class WalletConnectManager { } client.onEthSign = { id: Long, message: WCEthereumSignMessage -> Timber.d("onEthSign: $message") - Analytics.logWcEvent( - AnalyticsAnOld.WcAnalyticsEvent.Action( - AnalyticsAnOld.WcAction.PersonalSign - ) - ) + // Analytics.logWcEvent( + // AnalyticsAnOld.WcAnalyticsEvent.Action( + // AnalyticsAnOld.WcAction.PersonalSign + // ) + // ) sessions[client.session]?.toWalletConnectSession()?.let { sessionData -> store.dispatchOnMain( WalletConnectAction.HandlePersonalSignRequest( @@ -503,11 +491,11 @@ class WalletConnectManager { val message = EthSignHelper.tryToParseEthTypedMessage(request) if (message != null) { Timber.d("onEthSign_v4: $message") - Analytics.logWcEvent( - AnalyticsAnOld.WcAnalyticsEvent.Action( - AnalyticsAnOld.WcAction.PersonalSign - ) - ) + // Analytics.logWcEvent( + // AnalyticsAnOld.WcAnalyticsEvent.Action( + // AnalyticsAnOld.WcAction.PersonalSign + // ) + // ) sessions[client.session]?.toWalletConnectSession()?.let { sessionData -> store.dispatchOnMain( WalletConnectAction.HandlePersonalSignRequest( 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 36e8fc2a1d..a95fd872e9 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,7 @@ 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.analytics.AnalyticsAnOld +import com.tangem.tap.common.analytics.events.WalletConnect import com.tangem.tap.common.extensions.safeUpdate import com.tangem.tap.common.extensions.toFormattedString import com.tangem.tap.features.details.redux.walletconnect.WalletConnectSession @@ -88,8 +88,8 @@ class WalletConnectSdkHelper { extras = EthereumTransactionExtras( data = transaction.data.removePrefix(HEX_PREFIX).hexToBytes(), gasLimit = gas.toBigInteger(), - nonce = transaction.nonce?.hexToBigDecimal()?.toBigInteger() - ) + nonce = transaction.nonce?.hexToBigDecimal()?.toBigInteger(), + ), ) val dialogData = TransactionRequestDialogData( dAppName = session.peerMeta.name, @@ -101,7 +101,7 @@ class WalletConnectSdkHelper { isEnoughFundsToSend = (balance - total) >= BigDecimal.ZERO, session = session.session, id = id, - type = type + type = type, ) return WcTransactionData( type = type, @@ -109,7 +109,7 @@ class WalletConnectSdkHelper { session = session, id = id, walletManager = walletManager, - dialogData = dialogData + dialogData = dialogData, ) } @@ -123,7 +123,7 @@ class WalletConnectSdkHelper { val blockchain = session.wallet.getBlockchainForSession() return factory.makeWalletManager( blockchain = blockchain, - publicKey = publicKey + publicKey = publicKey, ) } @@ -137,14 +137,14 @@ class WalletConnectSdkHelper { private suspend fun sendTransaction(data: WcTransactionData): String? { val result = (data.walletManager as TransactionSender).send( transactionData = data.transaction, - signer = CommonSigner(tangemSdk) + signer = CommonSigner(tangemSdk), ) return when (result) { SimpleResult.Success -> { HEX_PREFIX + data.walletManager.wallet.recentTransactions.last().hash } is SimpleResult.Failure -> { - Analytics.send(result.error, AnalyticsAnOld.ActionToLog.WalletConnectTransaction) + (result.error as? TangemSdkError)?.let { Analytics.send(WalletConnect.TransactionError(it)) } Timber.e(result.error as BlockchainSdkError) null } @@ -156,13 +156,13 @@ class WalletConnectSdkHelper { transactionData = data.transaction, nonce = null, blockchain = data.walletManager.wallet.blockchain, - gasLimit = null + gasLimit = null, ) ?: return null val command = SignHashCommand( hash = dataToSign.hash, walletPublicKey = data.walletManager.wallet.publicKey.seedKey, - derivationPath = data.walletManager.wallet.publicKey.derivationPath + derivationPath = data.walletManager.wallet.publicKey.derivationPath, ) val result = tangemSdkManager.runTaskAsync(command, initialMessage = Message()) return when (result) { @@ -170,9 +170,7 @@ class WalletConnectSdkHelper { HEX_PREFIX + result.data } is CompletionResult.Failure -> { - (result.error as? TangemSdkError)?.let { error -> - Analytics.send(error, AnalyticsAnOld.ActionToLog.WalletConnectSign) - } + (result.error as? TangemSdkError)?.let { Analytics.send(WalletConnect.SignError(it)) } Timber.e(result.error.customMessage) null } @@ -183,7 +181,7 @@ class WalletConnectSdkHelper { val command = SignHashCommand( hash = data, walletPublicKey = session.wallet.walletPublicKey ?: return null, - derivationPath = session.wallet.derivationPath + derivationPath = session.wallet.derivationPath, ) val result = tangemSdkManager.runTaskAsync(command, initialMessage = Message()) return when (result) { @@ -192,13 +190,11 @@ class WalletConnectSdkHelper { ?: session.wallet.walletPublicKey.toDecompressedPublicKey() getBnbResultString( key.toHexString(), - result.data.signature.toHexString() + result.data.signature.toHexString(), ) } is CompletionResult.Failure -> { - (result.error as? TangemSdkError)?.let { error -> - Analytics.send(error, AnalyticsAnOld.ActionToLog.WalletConnectTransaction) - } + (result.error as? TangemSdkError)?.let { Analytics.send(WalletConnect.TransactionError(it)) } Timber.e(result.error.customMessage) null } @@ -223,18 +219,17 @@ class WalletConnectSdkHelper { val prefixData = (ETH_MESSAGE_PREFIX + messageData.size.toString()).toByteArray() val hashToSign = (prefixData + messageData).toKeccak() - val dialogData = PersonalSignDialogData( dAppName = session.peerMeta.name, message = messageString, session = session.session, - id = id + id = id, ) return WcPersonalSignData( hash = hashToSign, session = session, id = id, - dialogData = dialogData + dialogData = dialogData, ) } @@ -269,9 +264,7 @@ class WalletConnectSdkHelper { ) } is CompletionResult.Failure -> { - (result.error as? TangemSdkError)?.let { error -> - Analytics.send(error, AnalyticsAnOld.ActionToLog.WalletConnectSign) - } + (result.error as? TangemSdkError)?.let { Analytics.send(WalletConnect.SignError(it)) } Timber.e(result.error.customMessage) null } 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 835a392ee2..b316098ff4 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 @@ -4,8 +4,6 @@ import com.tangem.common.CompletionResult import com.tangem.common.core.TangemSdkError import com.tangem.domain.common.TapWorkarounds.isTangemTwins import com.tangem.tap.common.analytics.Analytics -import com.tangem.tap.common.analytics.AnalyticsAnOld -import com.tangem.tap.common.analytics.AnalyticsParamAnOld import com.tangem.tap.common.analytics.events.AnalyticsParam import com.tangem.tap.common.analytics.events.Settings import com.tangem.tap.common.extensions.dispatchDialogShow @@ -129,11 +127,7 @@ class DetailsMiddleware { } is CompletionResult.Failure -> { (result.error as? TangemSdkError)?.let { error -> - Analytics.send( - error, - AnalyticsAnOld.ActionToLog.PurgeWallet, - card = store.state.detailsState.scanResponse?.card, - ) + Analytics.send(Settings.CardSettings.FactoryResetFinished(error)) } } } @@ -160,30 +154,20 @@ class DetailsMiddleware { SecurityOption.LongTap -> tangemSdkManager.setLongTap(cardId) SecurityOption.PassCode -> tangemSdkManager.setPasscode(cardId) SecurityOption.AccessCode -> tangemSdkManager.setAccessCode(cardId) - else -> null + else -> return@launch } withContext(Dispatchers.Main) { + val paramValue = AnalyticsParam.SecurityMode.from(selectedOption) when (result) { is CompletionResult.Success -> { - selectedOption?.let { - val paramValue = AnalyticsParam.SecurityMode.from(it) - Analytics.send(Settings.CardSettings.SecurityModeChanged(paramValue)) - store.dispatch(GlobalAction.UpdateSecurityOptions(it)) - } + Analytics.send(Settings.CardSettings.SecurityModeChanged(paramValue)) + store.dispatch(GlobalAction.UpdateSecurityOptions(selectedOption)) store.dispatch(NavigationAction.PopBackTo()) store.dispatch(DetailsAction.ManageSecurity.SaveChanges.Success) } is CompletionResult.Failure -> { (result.error as? TangemSdkError)?.let { error -> - Analytics.send( - error = error, - action = AnalyticsAnOld.ActionToLog.ChangeSecOptions, - params = mapOf( - AnalyticsParamAnOld.NEW_SECURITY_OPTION to - (selectedOption?.name ?: ""), - ), - card = store.state.detailsState.scanResponse?.card, - ) + Analytics.send(Settings.CardSettings.SecurityModeChanged(paramValue, error)) } store.dispatch(DetailsAction.ManageSecurity.SaveChanges.Failure) } 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 16d6ee9efd..c3c0145ec8 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 @@ -10,9 +10,6 @@ import com.tangem.operations.backup.BackupService import com.tangem.tap.DELAY_SDK_DIALOG_CLOSE import com.tangem.tap.backupService import com.tangem.tap.common.analytics.Analytics -import com.tangem.tap.common.analytics.AnalyticsEventAnOld -import com.tangem.tap.common.analytics.AnalyticsParamAnOld -import com.tangem.tap.common.analytics.GetCardSourceParamsAnOld import com.tangem.tap.common.analytics.events.IntroductionProcess import com.tangem.tap.common.analytics.paramsInterceptor.BatchIdParamsInterceptor import com.tangem.tap.common.entities.IndeterminateProgressButton @@ -107,10 +104,6 @@ private fun handleHomeAction(appState: () -> AppState?, action: Action, dispatch RUSSIA_COUNTRY_CODE, BELARUS_COUNTRY_CODE -> store.dispatchOpenUrl(BUY_WALLET_URL) else -> store.dispatch(NavigationAction.NavigateTo(AppScreen.Shop)) } - Analytics.handleAnalyticsEvent( - event = AnalyticsEventAnOld.GET_CARD, - params = mapOf(AnalyticsParamAnOld.SOURCE.param to GetCardSourceParamsAnOld.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 c45924449f..da468c2636 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 @@ -18,9 +18,6 @@ import com.tangem.domain.common.TapWorkarounds.isStart2Coin import com.tangem.domain.common.extensions.withMainContext import com.tangem.tap.DELAY_SDK_DIALOG_CLOSE import com.tangem.tap.common.analytics.Analytics -import com.tangem.tap.common.analytics.AnalyticsAnOld -import com.tangem.tap.common.analytics.AnalyticsEventAnOld -import com.tangem.tap.common.analytics.AnalyticsParamAnOld import com.tangem.tap.common.analytics.events.AnalyticsParam import com.tangem.tap.common.analytics.events.Token import com.tangem.tap.common.extensions.dispatchDialogShow @@ -222,14 +219,10 @@ private fun sendTransaction( dispatch(SendAction.ChangeSendButtonState(ButtonState.ENABLED)) tangemSdk.config.linkedTerminal = isLinkedTerminal + val currencyType = AnalyticsParam.CurrencyType.Amount(amountToSend) when (sendResult) { is SimpleResult.Success -> { - Analytics.send(Token.Send.TransactionSent(AnalyticsParam.CurrencyType.Amount(amountToSend))) - Analytics.handleAnalyticsEvent( - event = AnalyticsEventAnOld.TRANSACTION_IS_SENT, - card = card, - blockchain = walletManager.wallet.blockchain.currency, - ) + Analytics.send(Token.Send.TransactionSent(currencyType)) dispatch(SendAction.SendSuccess) if (externalTransactionData != null) { @@ -254,15 +247,10 @@ private fun sendTransaction( feeAmount = feeAmount, destinationAddress = destinationAddress, ) - Analytics.send( - error = sendResult.error, - action = AnalyticsAnOld.ActionToLog.SendTransaction, - params = mapOf(AnalyticsParamAnOld.BLOCKCHAIN to walletManager.wallet.blockchain.currency), - card = card, - ) - val error = (sendResult.error as? BlockchainSdkError) ?: return@withMainContext + Analytics.send(Token.Send.TransactionSent(currencyType, error)) + when (error) { is BlockchainSdkError.WrappedTangemError -> { val tangemSdkError = (error.tangemError as? TangemSdkError) ?: return@withMainContext 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 78c837ba71..07d6994a7a 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 @@ -5,14 +5,12 @@ import com.tangem.blockchain.common.Amount import com.tangem.blockchain.common.AmountType import com.tangem.blockchain.common.WalletManager import com.tangem.common.CompletionResult -import com.tangem.common.core.TangemSdkError import com.tangem.common.extensions.isZero import com.tangem.common.services.Result import com.tangem.domain.common.extensions.withMainContext import com.tangem.operations.attestation.Attestation import com.tangem.operations.attestation.OnlineCardVerifier import com.tangem.tap.common.analytics.Analytics -import com.tangem.tap.common.analytics.AnalyticsAnOld import com.tangem.tap.common.analytics.events.Token import com.tangem.tap.common.extensions.copyToClipboard import com.tangem.tap.common.extensions.dispatchDebugErrorNotification @@ -189,15 +187,7 @@ class WalletMiddleware { globalState.scanResponse?.copy(card = result.data) scanNoteResponse?.let { store.onCardScanned(scanNoteResponse) } } - is CompletionResult.Failure -> { - (result.error as? TangemSdkError)?.let { error -> - Analytics.send( - error, - AnalyticsAnOld.ActionToLog.CreateWallet, - card = store.state.detailsState.scanResponse?.card, - ) - } - } + is CompletionResult.Failure -> {} } } } 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 4a30816169..112c3a0afb 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 @@ -8,8 +8,6 @@ import com.tangem.common.card.Card import com.tangem.common.card.FirmwareVersion import com.tangem.domain.common.ScanResponse import com.tangem.domain.common.TapWorkarounds.isTestCard -import com.tangem.tap.common.analytics.Analytics -import com.tangem.tap.common.analytics.AnalyticsEventAnOld import com.tangem.tap.common.extensions.dispatchOnMain import com.tangem.tap.common.extensions.isGreaterThan import com.tangem.tap.common.redux.global.GlobalState @@ -55,14 +53,10 @@ class WarningsMiddleware { if (action.remainingSignatures != null && action.remainingSignatures <= WarningMessagesManager.REMAINING_SIGNATURES_WARNING ) { - store.state.globalState.warningManager - ?.removeWarnings( - messageRes = R.string.warning_low_signatures_format - ) + store.state.globalState.warningManager?.removeWarnings(R.string.warning_low_signatures_format) addWarningMessage( - warning = - WarningMessagesManager.remainingSignaturesNotEnough(action.remainingSignatures), - autoUpdate = true + warning = WarningMessagesManager.remainingSignaturesNotEnough(action.remainingSignatures), + autoUpdate = true, ) } } @@ -70,7 +64,8 @@ class WarningsMiddleware { is WalletAction.Warnings.CheckHashesCount, is WalletAction.Warnings.CheckHashesCount.ConfirmHashesCount, is WalletAction.Warnings.CheckHashesCount.NeedToCheckHashesCountOnline, - is WalletAction.Warnings.Set -> Unit + is WalletAction.Warnings.Set, + -> Unit } } @@ -82,7 +77,6 @@ class WarningsMiddleware { preferencesStorage.appRatingLaunchObserver.foundWalletWithFunds() } if (preferencesStorage.appRatingLaunchObserver.isReadyToShow()) { - Analytics.handleAnalyticsEvent(AnalyticsEventAnOld.APP_RATING_DISPLAYED) addWarningMessage(WarningMessagesManager.appRatingWarning(), true) } } @@ -119,11 +113,7 @@ class WarningsMiddleware { if (remainingSignatures != null && remainingSignatures <= WarningMessagesManager.REMAINING_SIGNATURES_WARNING ) { - addWarningMessage( - WarningMessagesManager.remainingSignaturesNotEnough( - remainingSignatures - ) - ) + addWarningMessage(WarningMessagesManager.remainingSignaturesNotEnough(remainingSignatures)) } } @@ -179,15 +169,9 @@ class WarningsMiddleware { } is SimpleResult.Failure -> if (result.error is BlockchainSdkError.SignatureCountNotMatched) { - addWarningMessage( - WarningMessagesManager.alreadySignedHashesWarning(), - true - ) + addWarningMessage(WarningMessagesManager.alreadySignedHashesWarning(), true) } else if (signedHashes > 0) { - addWarningMessage( - WarningMessagesManager.alreadySignedHashesWarning(), - true - ) + addWarningMessage(WarningMessagesManager.alreadySignedHashesWarning(), true) } null -> Unit } @@ -208,7 +192,7 @@ class WarningsMiddleware { val warningManager = store.state.globalState.warningManager ?: return emptyList() return warningManager.getWarnings( WarningMessage.Location.MainScreen, - store.state.walletState.blockchains + store.state.walletState.blockchains, ) } } \ No newline at end of file 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 90abb0d255..dd3bcee91c 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 @@ -8,7 +8,6 @@ import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView import com.google.android.play.core.review.ReviewManagerFactory import com.tangem.tap.common.analytics.Analytics -import com.tangem.tap.common.analytics.AnalyticsEventAnOld import com.tangem.tap.common.analytics.events.AnalyticsParam import com.tangem.tap.common.analytics.events.MainScreen import com.tangem.tap.common.extensions.getActivity @@ -29,7 +28,7 @@ class WarningMessagesAdapter : ListAdapter(Dif override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): WarningMessageVH { val binding = LayoutWarningCardActionBinding.inflate( - LayoutInflater.from(parent.context), parent, false + LayoutInflater.from(parent.context), parent, false, ) return WarningMessageVH(binding) } @@ -63,7 +62,7 @@ class WarningMessageVH(val binding: LayoutWarningCardActionBinding) : RecyclerVi tvMessage.text = getString( resId = warning.messageResId, default = warning.message, - formatArgs = warning.messageFormatArg + formatArgs = warning.messageFormatArg, ) } @@ -101,7 +100,7 @@ class WarningMessageVH(val binding: LayoutWarningCardActionBinding) : RecyclerVi } } val buttonTitle = binding.root.getString( - warning.buttonTextId ?: R.string.how_to_got_it_button + warning.buttonTextId ?: R.string.how_to_got_it_button, ) binding.btnGotIt.setOnClickListener(buttonAction) binding.btnGotIt.text = buttonTitle @@ -112,13 +111,11 @@ class WarningMessageVH(val binding: LayoutWarningCardActionBinding) : RecyclerVi binding.btnClose.show() binding.btnClose.setOnClickListener { Analytics.send(MainScreen.NoticeRateAppButton(AnalyticsParam.RateApp.Closed)) - Analytics.handleAnalyticsEvent(AnalyticsEventAnOld.APP_RATING_DISMISS) store.dispatch(GlobalAction.HideWarningMessage(warning)) store.dispatch(WalletAction.Warnings.AppRating.RemindLater) } binding.btnCanBeBetter.setOnClickListener { Analytics.send(MainScreen.NoticeRateAppButton(AnalyticsParam.RateApp.Disliked)) - Analytics.handleAnalyticsEvent(AnalyticsEventAnOld.APP_RATING_NEGATIVE) store.dispatch(WalletAction.Warnings.AppRating.SetNeverToShow) store.dispatch(GlobalAction.HideWarningMessage(warning)) store.dispatch(GlobalAction.SendEmail(RateCanBeBetterEmail())) @@ -127,7 +124,6 @@ class WarningMessageVH(val binding: LayoutWarningCardActionBinding) : RecyclerVi val activity = binding.root.context.getActivity() ?: return@setOnClickListener Analytics.send(MainScreen.NoticeRateAppButton(AnalyticsParam.RateApp.Liked)) - Analytics.handleAnalyticsEvent(AnalyticsEventAnOld.APP_RATING_POSITIVE) store.dispatch(WalletAction.Warnings.AppRating.SetNeverToShow) val reviewManager = ReviewManagerFactory.create(activity) val task = reviewManager.requestReviewFlow() From ec62375be4a1108b58d8368b554065e930d20c68 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 14 Nov 2022 22:36:50 +0500 Subject: [PATCH 44/47] Updated on 2026-08-14 --- .../main/java/com/tangem/tap/common/analytics/Analytics.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/common/analytics/Analytics.kt b/app/src/main/java/com/tangem/tap/common/analytics/Analytics.kt index 03cb8437bb..8a6ee52f27 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/Analytics.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/Analytics.kt @@ -11,7 +11,7 @@ import com.tangem.tap.common.analytics.api.ParamsInterceptorHolder import com.tangem.tap.common.analytics.events.AnalyticsEvent import kotlinx.coroutines.CoroutineName import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Job +import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.asCoroutineDispatcher import kotlinx.coroutines.launch import java.util.concurrent.Executors @@ -88,6 +88,6 @@ object Analytics : GlobalAnalyticsEventHandler { val name = "Analytics" val dispatcher = Executors.newFixedThreadPool(1).asCoroutineDispatcher() val exHandler = FeatureCoroutineExceptionHandler.create(name) - return CoroutineScope(Job() + dispatcher + CoroutineName(name) + exHandler) + return CoroutineScope(SupervisorJob() + dispatcher + CoroutineName(name) + exHandler) } } \ No newline at end of file From d4c34f6af90c6420198cf3d54d6d768739654951 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 15 Nov 2022 00:17:49 +0500 Subject: [PATCH 45/47] Updated on 2026-08-14 --- .../main/java/com/tangem/tap/common/DialogManager.kt | 2 +- .../products/note/redux/OnboardingNoteMiddleware.kt | 9 ++++++--- .../tangem/tap/features/wallet/redux/WalletAction.kt | 5 ++++- .../redux/middlewares/WalletDialogsMiddleware.kt | 2 +- .../tap/features/wallet/redux/models/WalletDialog.kt | 5 ++++- .../RussianCardholdersWarningBottomSheetDialog.kt | 12 +++++++++--- 6 files changed, 25 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/common/DialogManager.kt b/app/src/main/java/com/tangem/tap/common/DialogManager.kt index a1739329b5..4d1c3734ea 100644 --- a/app/src/main/java/com/tangem/tap/common/DialogManager.kt +++ b/app/src/main/java/com/tangem/tap/common/DialogManager.kt @@ -153,7 +153,7 @@ class DialogManager : StoreSubscriber { primaryButtonAction = state.dialog.onOk, ) is WalletDialog.RussianCardholdersWarningDialog -> - RussianCardholdersWarningBottomSheetDialog(context, state.dialog.topUpUrl) + RussianCardholdersWarningBottomSheetDialog(context, state.dialog.data) else -> null } dialog?.show() diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteMiddleware.kt index 57940fe421..5ecccaa431 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/note/redux/OnboardingNoteMiddleware.kt @@ -13,6 +13,7 @@ import com.tangem.tap.common.extensions.dispatchErrorNotification import com.tangem.tap.common.extensions.dispatchOnMain import com.tangem.tap.common.extensions.dispatchOpenUrl import com.tangem.tap.common.extensions.getAddressData +import com.tangem.tap.common.extensions.getTopUpUrl import com.tangem.tap.common.extensions.onCardScanned import com.tangem.tap.common.postUi import com.tangem.tap.common.redux.AppDialog @@ -28,6 +29,7 @@ import com.tangem.tap.features.home.RUSSIA_COUNTRY_CODE import com.tangem.tap.features.wallet.models.Currency import com.tangem.tap.features.wallet.redux.ProgressState import com.tangem.tap.features.wallet.redux.WalletAction +import com.tangem.tap.features.wallet.redux.models.WalletDialog import com.tangem.tap.scope import com.tangem.tap.store import com.tangem.tap.tangemSdkManager @@ -174,13 +176,14 @@ private fun handleNoteAction(appState: () -> AppState?, action: Action, dispatch return } - val topUpUrl = noteState.walletManager.getToUpUrl() ?: return + val topUpUrl = walletManager.getTopUpUrl() ?: return + val blockchain = walletManager.wallet.blockchain if (globalState.userCountryCode == RUSSIA_COUNTRY_CODE) { - store.dispatchOnMain(WalletAction.DialogAction.RussianCardholdersWarningDialog(topUpUrl)) + val dialogData = WalletDialog.RussianCardholdersWarningDialog.Data(topUpUrl, blockchain) + store.dispatchOnMain(WalletAction.DialogAction.RussianCardholdersWarningDialog(dialogData)) return } - val blockchain = walletManager.wallet.blockchain val currencyType = AnalyticsParam.CurrencyType.Blockchain(blockchain) Analytics.send(Onboarding.Topup.ButtonBuyCrypto(currencyType)) diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletAction.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletAction.kt index b9451b117a..02e6073066 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletAction.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletAction.kt @@ -15,6 +15,7 @@ import com.tangem.tap.domain.TapError import com.tangem.tap.domain.configurable.warningMessage.WarningMessage import com.tangem.tap.domain.tokens.models.BlockchainNetwork import com.tangem.tap.features.wallet.models.Currency +import com.tangem.tap.features.wallet.redux.models.WalletDialog import com.tangem.wallet.R import org.rekotlin.Action import java.math.BigDecimal @@ -154,7 +155,9 @@ sealed class WalletAction : Action { object SignedHashesMultiWalletDialog : DialogAction() object ChooseTradeActionDialog : DialogAction() data class ChooseCurrency(val amounts: List?) : DialogAction() - data class RussianCardholdersWarningDialog(val topUpUrl: String? = null) : DialogAction() + data class RussianCardholdersWarningDialog( + val dialogData: WalletDialog.RussianCardholdersWarningDialog.Data? = null + ) : DialogAction() object Hide : DialogAction() } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletDialogsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletDialogsMiddleware.kt index 33e8e901f8..f94e6def86 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletDialogsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletDialogsMiddleware.kt @@ -38,7 +38,7 @@ class WalletDialogsMiddleware { ) } is WalletAction.DialogAction.RussianCardholdersWarningDialog -> { - store.dispatchDialogShow(WalletDialog.RussianCardholdersWarningDialog(action.topUpUrl)) + store.dispatchDialogShow(WalletDialog.RussianCardholdersWarningDialog(action.dialogData)) } is WalletAction.DialogAction.Hide -> { store.dispatchDialogHide() diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/models/WalletDialog.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/models/WalletDialog.kt index b4188f8dd8..fc182e2c4f 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/models/WalletDialog.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/models/WalletDialog.kt @@ -1,6 +1,7 @@ package com.tangem.tap.features.wallet.redux.models import com.tangem.blockchain.common.Amount +import com.tangem.blockchain.common.Blockchain import com.tangem.tap.common.entities.FiatCurrency import com.tangem.tap.common.redux.StateDialog import com.tangem.wallet.R @@ -31,5 +32,7 @@ sealed interface WalletDialog : StateDialog { val titleRes: Int = R.string.token_details_unable_hide_alert_title } - data class RussianCardholdersWarningDialog(val topUpUrl: String?) : WalletDialog + data class RussianCardholdersWarningDialog(val data: Data?) : WalletDialog { + data class Data(val topUpUrl: String, val blockchain: Blockchain) + } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/dialogs/RussianCardholdersWarningBottomSheetDialog.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/dialogs/RussianCardholdersWarningBottomSheetDialog.kt index 4073120f64..b8022e2724 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/dialogs/RussianCardholdersWarningBottomSheetDialog.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/dialogs/RussianCardholdersWarningBottomSheetDialog.kt @@ -5,16 +5,20 @@ import android.os.Bundle import android.view.LayoutInflater import com.google.android.material.bottomsheet.BottomSheetDialog import com.tangem.tap.common.analytics.Analytics +import com.tangem.tap.common.analytics.events.AnalyticsParam +import com.tangem.tap.common.analytics.events.Onboarding import com.tangem.tap.common.analytics.events.Token import com.tangem.tap.common.extensions.dispatchDialogHide import com.tangem.tap.common.extensions.dispatchOpenUrl import com.tangem.tap.common.redux.navigation.NavigationAction import com.tangem.tap.features.wallet.redux.WalletAction +import com.tangem.tap.features.wallet.redux.models.WalletDialog import com.tangem.tap.store import com.tangem.wallet.databinding.DialogRussiansCardholdersWarningBinding class RussianCardholdersWarningBottomSheetDialog( - context: Context, private val topUpUrl: String?, + context: Context, + private val dialogData: WalletDialog.RussianCardholdersWarningDialog.Data?, ) : BottomSheetDialog (context) { @@ -36,8 +40,10 @@ class RussianCardholdersWarningBottomSheetDialog( } binding?.btnYes?.setOnClickListener { - if (topUpUrl != null) { - store.dispatchOpenUrl(topUpUrl) + if (dialogData != null) { + val currencyType = AnalyticsParam.CurrencyType.Blockchain(dialogData.blockchain) + Analytics.send(Onboarding.Topup.ButtonBuyCrypto(currencyType)) + store.dispatchOpenUrl(dialogData.topUpUrl) } else { store.dispatch(WalletAction.TradeCryptoAction.Buy(checkUserLocation = false)) } From c70f4c5192f06fd808842d0b42dc784ab3f966d9 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 15 Nov 2022 02:27:54 +0500 Subject: [PATCH 46/47] Updated on 2026-08-14 --- .../java/com/tangem/tap/TapApplication.kt | 18 ++++++++-- .../com/tangem/tap/common/moshi/Adapters.kt | 16 +++++++++ .../tap/persistence/PreferencesStorage.kt | 8 ++--- .../tap/persistence/ToppedUpWalletStorage.kt | 21 ++++++++++- .../tangem/network/common/MoshiConverter.kt | 35 +++++++------------ 5 files changed, 69 insertions(+), 29 deletions(-) create mode 100644 app/src/main/java/com/tangem/tap/common/moshi/Adapters.kt diff --git a/app/src/main/java/com/tangem/tap/TapApplication.kt b/app/src/main/java/com/tangem/tap/TapApplication.kt index 568ca4af60..5074f09e8d 100644 --- a/app/src/main/java/com/tangem/tap/TapApplication.kt +++ b/app/src/main/java/com/tangem/tap/TapApplication.kt @@ -27,6 +27,7 @@ import com.tangem.tap.common.feedback.AdditionalFeedbackInfo import com.tangem.tap.common.feedback.FeedbackManager import com.tangem.tap.common.images.createCoilImageLoader import com.tangem.tap.common.log.TangemLogCollector +import com.tangem.tap.common.moshi.BigDecimalAdapter import com.tangem.tap.common.redux.AppState import com.tangem.tap.common.redux.appReducer import com.tangem.tap.common.redux.global.GlobalAction @@ -38,6 +39,7 @@ import com.tangem.tap.domain.configurable.warningMessage.WarningMessagesManager import com.tangem.tap.domain.tokens.UserTokensRepository import com.tangem.tap.domain.walletconnect.WalletConnectRepository import com.tangem.tap.network.NetworkConnectivity +import com.tangem.tap.persistence.CardBalanceStateAdapter import com.tangem.tap.persistence.PreferencesStorage import com.tangem.wallet.BuildConfig import com.zendesk.logger.Logger @@ -70,13 +72,14 @@ class TapApplication : Application(), ImageLoaderFactory { foregroundActivityObserver = ForegroundActivityObserver() registerActivityLifecycleCallbacks(foregroundActivityObserver.callbacks) + initMoshiConverter() DomainLayer.init() NetworkConnectivity.createInstance(store, this) preferencesStorage = PreferencesStorage(this) walletConnectRepository = WalletConnectRepository(this) assetReader = AndroidAssetReader(this) - val configLoader = FeaturesLocalLoader(assetReader, MoshiConverter.defaultMoshi()) + val configLoader = FeaturesLocalLoader(assetReader, MoshiConverter.INSTANCE.moshi) initConfigManager(configLoader, ::initWithConfigDependency) initWarningMessagesManager() @@ -88,6 +91,17 @@ class TapApplication : Application(), ImageLoaderFactory { ) } + private fun initMoshiConverter() { + fun appAdapters(): List = listOf( + BigDecimalAdapter(), + CardBalanceStateAdapter(), + ) + MoshiConverter.reInitInstance( + adapters = appAdapters() + MoshiJsonConverter.getTangemSdkAdapters(), + typedAdapters = MoshiJsonConverter.getTangemSdkTypedAdapters(), + ) + } + override fun newImageLoader(): ImageLoader { return createCoilImageLoader( context = this, @@ -124,7 +138,7 @@ class TapApplication : Application(), ImageLoaderFactory { config = config, isDebug = BuildConfig.DEBUG, logConfig = LogConfig.analyticsHandlers, - jsonConverter = MoshiJsonConverter.INSTANCE, + jsonConverter = MoshiConverter.INSTANCE, ) factory.build(Analytics, buildData) } diff --git a/app/src/main/java/com/tangem/tap/common/moshi/Adapters.kt b/app/src/main/java/com/tangem/tap/common/moshi/Adapters.kt new file mode 100644 index 0000000000..c0ec09ea9c --- /dev/null +++ b/app/src/main/java/com/tangem/tap/common/moshi/Adapters.kt @@ -0,0 +1,16 @@ +package com.tangem.tap.common.moshi + +import com.squareup.moshi.FromJson +import com.squareup.moshi.ToJson +import java.math.BigDecimal + +/** +[REDACTED_AUTHOR] + */ +class BigDecimalAdapter { + @FromJson + fun fromJson(value: String) = BigDecimal(value) + + @ToJson + fun toJson(value: BigDecimal) = value.toString() +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/persistence/PreferencesStorage.kt b/app/src/main/java/com/tangem/tap/persistence/PreferencesStorage.kt index 38a03e482d..0e213fc01b 100644 --- a/app/src/main/java/com/tangem/tap/persistence/PreferencesStorage.kt +++ b/app/src/main/java/com/tangem/tap/persistence/PreferencesStorage.kt @@ -4,7 +4,7 @@ import android.app.Application import android.content.Context import android.content.SharedPreferences import androidx.core.content.edit -import com.tangem.common.json.MoshiJsonConverter +import com.tangem.network.common.MoshiConverter import java.util.* class PreferencesStorage(applicationContext: Application) { @@ -21,12 +21,12 @@ class PreferencesStorage(applicationContext: Application) { init { incrementLaunchCounter() appRatingLaunchObserver = AppRatingLaunchObserver(preferences, getCountOfLaunches()) - usedCardsPrefStorage = UsedCardsPrefStorage(preferences, MoshiJsonConverter.INSTANCE) + usedCardsPrefStorage = UsedCardsPrefStorage(preferences, MoshiConverter.INSTANCE) usedCardsPrefStorage.migrate() - fiatCurrenciesPrefStorage = FiatCurrenciesPrefStorage(preferences, MoshiJsonConverter.INSTANCE) + fiatCurrenciesPrefStorage = FiatCurrenciesPrefStorage(preferences, MoshiConverter.INSTANCE) fiatCurrenciesPrefStorage.migrate() disclaimerPrefStorage = DisclaimerPrefStorage(preferences) - toppedUpWalletStorage = ToppedUpWalletStorage(preferences, MoshiJsonConverter.INSTANCE) + toppedUpWalletStorage = ToppedUpWalletStorage(preferences, MoshiConverter.INSTANCE) } var chatFirstLaunchTime: Long? diff --git a/app/src/main/java/com/tangem/tap/persistence/ToppedUpWalletStorage.kt b/app/src/main/java/com/tangem/tap/persistence/ToppedUpWalletStorage.kt index 7ec028e8ea..e270b2b820 100644 --- a/app/src/main/java/com/tangem/tap/persistence/ToppedUpWalletStorage.kt +++ b/app/src/main/java/com/tangem/tap/persistence/ToppedUpWalletStorage.kt @@ -2,7 +2,10 @@ package com.tangem.tap.persistence import android.content.SharedPreferences import androidx.core.content.edit +import com.squareup.moshi.FromJson +import com.squareup.moshi.ToJson import com.tangem.common.json.MoshiJsonConverter +import com.tangem.tap.common.analytics.events.AnalyticsParam import com.tangem.tap.common.analytics.filters.BasicTopUpFilter import timber.log.Timber @@ -44,7 +47,9 @@ class ToppedUpWalletStorage( private fun restore(): MutableSet { val json = preferences.getString(KEY, null) ?: return mutableSetOf() return try { - jsonConverter.fromJson(json, jsonConverter.typedList(BasicTopUpFilter.Data::class.java))!! + val typedList = jsonConverter.typedList(BasicTopUpFilter.Data::class.java) + val listData = jsonConverter.fromJson>(json, typedList)!! + listData.toMutableSet() } catch (ex: Exception) { preferences.edit(true) { remove(KEY) } mutableSetOf() @@ -54,4 +59,18 @@ class ToppedUpWalletStorage( companion object { private const val KEY = "userWalletsInfo" } +} + +class CardBalanceStateAdapter { + @ToJson + fun toJson(src: AnalyticsParam.CardBalanceState): String = src.value + + @FromJson + fun fromJson(json: String): AnalyticsParam.CardBalanceState { + return when (json) { + AnalyticsParam.CardBalanceState.Empty.value -> AnalyticsParam.CardBalanceState.Empty + AnalyticsParam.CardBalanceState.Full.value -> AnalyticsParam.CardBalanceState.Full + else -> throw IllegalArgumentException() + } + } } \ No newline at end of file diff --git a/network/src/main/java/com/tangem/network/common/MoshiConverter.kt b/network/src/main/java/com/tangem/network/common/MoshiConverter.kt index 1f967032e3..47b5cc4b64 100644 --- a/network/src/main/java/com/tangem/network/common/MoshiConverter.kt +++ b/network/src/main/java/com/tangem/network/common/MoshiConverter.kt @@ -1,38 +1,29 @@ package com.tangem.network.common -import com.squareup.moshi.FromJson +import com.squareup.moshi.JsonAdapter import com.squareup.moshi.Moshi -import com.squareup.moshi.ToJson -import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory import com.tangem.common.json.MoshiJsonConverter -import com.tangem.common.json.TangemSdkAdapter import retrofit2.Converter import retrofit2.converter.moshi.MoshiConverterFactory -import java.math.BigDecimal /** [REDACTED_AUTHOR] */ -class MoshiConverter { +object MoshiConverter { - companion object { - fun createFactory(moshi: Moshi = defaultMoshi()): Converter.Factory = MoshiConverterFactory.create(moshi) + var INSTANCE = MoshiJsonConverter() + private set - fun defaultMoshi(): Moshi = Moshi.Builder() - .add(BigDecimalAdapter) - .add(KotlinJsonAdapterFactory()) - .add(TangemSdkAdapter.DerivationPathAdapter()) - .add(TangemSdkAdapter.DerivationNodeAdapter()) - .build() - - fun sdkMoshi(): Moshi = MoshiJsonConverter.INSTANCE.moshi + fun reInitInstance( + adapters: List = listOf(), + typedAdapters: Map, JsonAdapter<*>> = mapOf(), + ) { + INSTANCE = MoshiJsonConverter(adapters, typedAdapters) } -} -object BigDecimalAdapter { - @FromJson - fun fromJson(string: String) = BigDecimal(string) + fun createFactory(moshi: Moshi = INSTANCE.moshi): Converter.Factory = MoshiConverterFactory.create(moshi) - @ToJson - fun toJson(value: BigDecimal) = value.toString() + fun defaultMoshi(): Moshi = INSTANCE.moshi + + fun sdkMoshi(): Moshi = MoshiJsonConverter.INSTANCE.moshi } \ No newline at end of file From 098f73eb380ecb3b1f4f417f83a3e86e98c0ad4f Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 16 Nov 2022 09:51:52 +0300 Subject: [PATCH 47/47] Updated on 2026-08-14 --- .../redux/middlewares/WalletMiddleware.kt | 36 ++++++++++++------- app/src/main/res/values-ru/strings_final.xml | 1 + app/src/main/res/values/strings_final.xml | 1 + 3 files changed, 26 insertions(+), 12 deletions(-) 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 30a72f0fd4..ea47afc58a 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 @@ -1,5 +1,6 @@ package com.tangem.tap.features.wallet.redux.middlewares +import com.google.firebase.crashlytics.FirebaseCrashlytics import com.tangem.blockchain.blockchains.solana.RentProvider import com.tangem.blockchain.common.Amount import com.tangem.blockchain.common.AmountType @@ -17,6 +18,7 @@ import com.tangem.tap.common.extensions.dispatchDebugErrorNotification import com.tangem.tap.common.extensions.dispatchErrorNotification import com.tangem.tap.common.extensions.dispatchOnMain import com.tangem.tap.common.extensions.dispatchOpenUrl +import com.tangem.tap.common.extensions.dispatchToastNotification import com.tangem.tap.common.extensions.onCardScanned import com.tangem.tap.common.extensions.shareText import com.tangem.tap.common.extensions.stripZeroPlainString @@ -45,6 +47,7 @@ import com.tangem.tap.preferencesStorage import com.tangem.tap.scope import com.tangem.tap.store import com.tangem.tap.tangemSdkManager +import com.tangem.wallet.R import kotlinx.coroutines.async import kotlinx.coroutines.awaitAll import kotlinx.coroutines.launch @@ -118,10 +121,9 @@ class WalletMiddleware { true, ), ) - store.dispatch(WalletAction.LoadWallet.Success( - action.wallet, - action.blockchain - )) + store.dispatch( + action = WalletAction.LoadWallet.Success(action.wallet, action.blockchain) + ) } } store.dispatch(WalletAction.Warnings.CheckHashesCount.CheckHashesCountOnline) @@ -257,9 +259,17 @@ class WalletMiddleware { return } val newAction = prepareSendAction(action.amount, store.state.walletState) - store.dispatch(newAction) - if (newAction is PrepareSendScreen) { - store.dispatch(NavigationAction.NavigateTo(AppScreen.Send)) + if (newAction is PrepareSendScreen && newAction.walletManager == null) { + store.dispatch(NavigationAction.PopBackTo(screen = AppScreen.Home)) + FirebaseCrashlytics.getInstance().recordException( + IllegalStateException("PrepareSendScreen: walletManager is null") + ) + store.dispatchToastNotification(R.string.internal_error_wallet_manager_not_found) + } else { + store.dispatch(newAction) + if (newAction is PrepareSendScreen) { + store.dispatch(NavigationAction.NavigateTo(AppScreen.Send)) + } } } } @@ -366,11 +376,13 @@ class WalletMiddleware { val currency = walletManager.wallet.blockchain.currency if (show) { - dispatchOnMain(WalletAction.SetWalletRent( - wallet = walletManager.wallet, - minRent = ("${rentProvider.rentAmount().stripZeroPlainString()} $currency"), - rentExempt = ("${rentExempt.stripZeroPlainString()} $currency") - )) + dispatchOnMain( + WalletAction.SetWalletRent( + wallet = walletManager.wallet, + minRent = ("${rentProvider.rentAmount().stripZeroPlainString()} $currency"), + rentExempt = ("${rentExempt.stripZeroPlainString()} $currency") + ) + ) } else { dispatchOnMain(WalletAction.RemoveWalletRent(walletManager.wallet)) } diff --git a/app/src/main/res/values-ru/strings_final.xml b/app/src/main/res/values-ru/strings_final.xml index fe86cb0019..ad4f23ca35 100644 --- a/app/src/main/res/values-ru/strings_final.xml +++ b/app/src/main/res/values-ru/strings_final.xml @@ -152,4 +152,5 @@ Вы хотите выйти из процесса активации? В этом случае вам будет необходимо начать процесс заново. Вы использовали карту от другого кошелька. Приложите карту, связанную с этим кошельком. + Внутренняя ошибка: не удается найти менеджер кошельков diff --git a/app/src/main/res/values/strings_final.xml b/app/src/main/res/values/strings_final.xml index f5e11c6885..70e85346c6 100644 --- a/app/src/main/res/values/strings_final.xml +++ b/app/src/main/res/values/strings_final.xml @@ -154,4 +154,5 @@ Do you want to exit the activation process? In this case, you will need to start from the beginning. You have used a card from another wallet. Tap the card associated with this wallet + Internal error: wallet manager not found