Updated on 2026-08-14

This commit is contained in:
Tangem 2022-11-03 17:45:42 +05:00
parent e8ed347498
commit d2d725c4e9
9 changed files with 195 additions and 49 deletions

View file

@ -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) }
}

View file

@ -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<WalletState, Basic.SignedIn?> {
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<WalletState, Basic.ToppedUp?> {
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<WalletData>): 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
}

View file

@ -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<Any?, Basic.SignedIn?> {
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()
}
}
}

View file

@ -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) {

View file

@ -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(

View file

@ -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
}
}

View file

@ -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<Walle
}
private fun handleBasicAnalyticsEvent(state: WalletState) {
if (state.walletsData.isEmpty()) return
val scanResponse = store.state.globalState.scanResponse ?: return
val totalBalanceState = state.totalBalance?.state ?: return
val totalCryptoAmount = state.walletsData.calculateTotalCryptoAmount()
BasicSignInEventConverter(scanResponse, totalBalanceState, totalCryptoAmount).convert(null)?.let {
Analytics.send(it)
}
BasicSignInEventConverter(scanResponse).convert(state)?.let { Analytics.send(it) }
BasicTopUpEventConverter(scanResponse).convert(state)?.let { Analytics.send(it) }
}
}

View file

@ -16,6 +16,7 @@ class PreferencesStorage(applicationContext: Application) {
val usedCardsPrefStorage: UsedCardsPrefStorage
val fiatCurrenciesPrefStorage: FiatCurrenciesPrefStorage
val disclaimerPrefStorage: DisclaimerPrefStorage
val toppedUpWalletStorage: ToppedUpWalletStorage
init {
incrementLaunchCounter()
@ -25,6 +26,7 @@ class PreferencesStorage(applicationContext: Application) {
fiatCurrenciesPrefStorage = FiatCurrenciesPrefStorage(preferences, MoshiJsonConverter.INSTANCE)
fiatCurrenciesPrefStorage.migrate()
disclaimerPrefStorage = DisclaimerPrefStorage(preferences)
toppedUpWalletStorage = ToppedUpWalletStorage(preferences, MoshiJsonConverter.INSTANCE)
}
var chatFirstLaunchTime: Long?

View file

@ -0,0 +1,57 @@
package com.tangem.tap.persistence
import android.content.SharedPreferences
import androidx.core.content.edit
import com.tangem.common.json.MoshiJsonConverter
import com.tangem.tap.common.analytics.filters.BasicTopUpFilter
import timber.log.Timber
/**
[REDACTED_AUTHOR]
*/
class ToppedUpWalletStorage(
private val preferences: SharedPreferences,
private val jsonConverter: MoshiJsonConverter,
) {
private val walletList: MutableSet<BasicTopUpFilter.Data> = 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<BasicTopUpFilter.Data>): 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<BasicTopUpFilter.Data> {
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"
}
}