Updated on 2026-08-14

This commit is contained in:
Tangem 2026-05-04 14:22:49 +05:00
parent a99a1b370a
commit 14178e9027
6 changed files with 100 additions and 19 deletions

View file

@ -3,16 +3,15 @@ package com.tangem.feature.swap.analytics
import com.tangem.core.analytics.models.AnalyticsEvent
import com.tangem.core.analytics.models.AnalyticsParam.Key.ACCOUNT_DERIVATION_FROM
import com.tangem.core.analytics.models.AnalyticsParam.Key.ACCOUNT_DERIVATION_TO
import com.tangem.core.analytics.models.AnalyticsParam.Key.BLOCKCHAIN
import com.tangem.core.analytics.models.AnalyticsParam.Key.ERROR_CODE
import com.tangem.core.analytics.models.AnalyticsParam.Key.ERROR_MESSAGE
import com.tangem.core.analytics.models.AnalyticsParam.Key.FEE_TOKEN
import com.tangem.core.analytics.models.AnalyticsParam.Key.PROVIDER
import com.tangem.core.analytics.models.AnalyticsParam.Key.RECEIVE_TOKEN
import com.tangem.core.analytics.models.AnalyticsParam.Key.SEND_TOKEN
import com.tangem.core.analytics.models.AnalyticsParam.Key.TOKEN_PARAM
import com.tangem.core.analytics.models.AppsFlyerIncludedEvent
import com.tangem.core.analytics.models.getReferralParams
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.feature.swap.domain.models.domain.SwapProvider
import com.tangem.feature.swap.domain.models.ui.FeeType
@ -25,13 +24,15 @@ sealed class SwapEvents(
) : AnalyticsEvent(SWAP_CATEGORY, event, params) {
class SwapScreenOpened(
val token: String,
val blockchain: String,
val fromCurrency: CryptoCurrency?,
val toCurrency: CryptoCurrency?,
) : SwapEvents(
event = "Swap Screen Opened",
params = mapOf(
TOKEN_PARAM to token,
BLOCKCHAIN to blockchain,
SEND_TOKEN to fromCurrency?.symbol.orEmpty(),
"Send Blockchain" to fromCurrency?.network?.name.orEmpty(),
RECEIVE_TOKEN to toCurrency?.symbol.orEmpty(),
"Receive Blockchain" to toCurrency?.network?.name.orEmpty(),
),
), AppsFlyerIncludedEvent
@ -48,6 +49,31 @@ sealed class SwapEvents(
},
)
class ChoosePopularToken(
val direction: String,
val currency: CryptoCurrency,
) : SwapEvents(
event = "Choose popular token",
params = mapOf(
"Direction" to direction,
"Token" to currency.symbol,
"Blockchain" to currency.network.name,
),
)
class PreselectedTokenChanged(
val direction: String,
val preSelectedToken: CryptoCurrency,
val selectedToken: CryptoCurrency,
) : SwapEvents(
event = "Pre-selected token changed",
params = mapOf(
"Direction" to direction,
"Pre-selected Token" to preSelectedToken.symbol,
"Selected Token" to selectedToken.symbol,
),
)
class ButtonSwapClicked(val sendToken: String, val receiveToken: String) : SwapEvents(
event = "Button - Swap",
params = mapOf("Send Token" to sendToken, "Receive Token" to receiveToken),

View file

@ -227,6 +227,9 @@ internal class SwapModel @Inject constructor(
private var isAmountChangedByUser: Boolean = false
private var lastPermissionNotificationTokens: Pair<String, String>? = null
private var preselectedFromCurrency: CryptoCurrency? = null
private var preselectedToCurrency: CryptoCurrency? = null
val approvalSlotNavigation = SlotNavigation<Unit>()
val approvalCallback = object : GiveApprovalComponent.Callback {
@ -275,14 +278,6 @@ internal class SwapModel @Inject constructor(
initTokens()
// TODO swap analytics
analyticsEventHandler.send(
SwapEvents.SwapScreenOpened(
token = initialCryptoCurrency?.symbol.orEmpty(),
blockchain = initialCryptoCurrency?.network?.name.orEmpty(),
),
)
getBalanceHidingSettingsUseCase().onEach { settings ->
isBalanceHidden = settings.isBalanceHidden
uiState = stateBuilder.updateBalanceHiddenState(uiState, isBalanceHidden)
@ -304,9 +299,28 @@ internal class SwapModel @Inject constructor(
}
private fun subscribeToTokenSelection() {
fun sendAnalytics(result: ChooseTokenResult, direction: String) {
result.analyticsPayload.forEach { analyticPayload ->
when (analyticPayload) {
is ChooseTokenAnalyticsPayload.IsMarketTokenSelected -> {
if (analyticPayload.value) {
analyticsEventHandler.send(
SwapEvents.ChoosePopularToken(
direction = direction,
currency = result.currency.currency,
),
)
}
}
else -> Unit
}
}
}
chooseFromTokenBridge.onCurrencyChosen.receiveAsFlow()
.onEach { result ->
onTokenSelect(result, isFromDirection = true)
onTokenSelect(result = result, isFromDirection = true)
sendAnalytics(result = result, direction = "From")
}
.launchIn(modelScope)
@ -320,6 +334,7 @@ internal class SwapModel @Inject constructor(
chooseToTokenBridge.onCurrencyChosen.receiveAsFlow()
.onEach { result ->
onTokenSelect(result, isFromDirection = false)
sendAnalytics(result = result, direction = "To")
}
.launchIn(modelScope)
@ -342,6 +357,16 @@ internal class SwapModel @Inject constructor(
isPaymentAccount = params.tangemPayInput != null,
)
preselectedFromCurrency = fromSwapCurrencyStatus?.currency
preselectedToCurrency = toSwapCurrencyStatus?.currency
analyticsEventHandler.send(
SwapEvents.SwapScreenOpened(
fromCurrency = fromSwapCurrencyStatus?.currency,
toCurrency = toSwapCurrencyStatus?.currency,
),
)
dataState = dataState.copy(
fromSwapCurrencyStatus = fromSwapCurrencyStatus,
toSwapCurrencyStatus = toSwapCurrencyStatus,
@ -416,6 +441,11 @@ internal class SwapModel @Inject constructor(
return
}
sendPreselectedTokenChangedIfNeeded(
isFromDirection = isFromDirection,
selectedCurrency = selectedCurrencyStatus.currency,
)
dataState = if (isFromDirection) {
// Reset amount if from token is changed
lastAmount.value = INITIAL_AMOUNT
@ -465,6 +495,25 @@ internal class SwapModel @Inject constructor(
}
}
private fun sendPreselectedTokenChangedIfNeeded(isFromDirection: Boolean, selectedCurrency: CryptoCurrency) {
val preselected = if (isFromDirection) preselectedFromCurrency else preselectedToCurrency
if (preselected == null || preselected == selectedCurrency) return
analyticsEventHandler.send(
SwapEvents.PreselectedTokenChanged(
direction = if (isFromDirection) "From" else "To",
preSelectedToken = preselected,
selectedToken = selectedCurrency,
),
)
if (isFromDirection) {
preselectedFromCurrency = null
} else {
preselectedToCurrency = null
}
}
private fun onChangeCardsClicked() {
modelScope.launch {
singleTaskScheduler.cancelTask()