Updated on 2026-08-14
This commit is contained in:
parent
a99a1b370a
commit
14178e9027
6 changed files with 100 additions and 19 deletions
|
|
@ -6,8 +6,8 @@ import com.tangem.domain.models.account.AccountStatus
|
|||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.features.commonfeatures.api.choosetoken.model.ChooseTokenPortfolioFullBlockUM
|
||||
import com.tangem.features.commonfeatures.api.R
|
||||
import com.tangem.features.commonfeatures.api.choosetoken.model.ChooseTokenPortfolioFullBlockUM
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
|
@ -95,4 +95,8 @@ sealed interface ChooseTokenAnalyticsPayload {
|
|||
|
||||
@JvmInline
|
||||
value class ScreensSources(val value: String) : ChooseTokenAnalyticsPayload
|
||||
|
||||
@Suppress("BooleanPropertyNaming")
|
||||
@JvmInline
|
||||
value class IsMarketTokenSelected(val value: Boolean) : ChooseTokenAnalyticsPayload
|
||||
}
|
||||
|
|
@ -80,11 +80,12 @@ internal class ChooseTokenModel @Inject constructor(
|
|||
addToPortfolioManager.onSuccessAdded.receiveAsFlow()
|
||||
.onEach { addedResult ->
|
||||
val isSearched = ChooseTokenAnalyticsPayload.IsSearched(isSearchingState)
|
||||
val isMarketToken = ChooseTokenAnalyticsPayload.IsMarketTokenSelected(true)
|
||||
val chooseTokenResult = ChooseTokenResult(
|
||||
currency = addedResult.addedCurrency,
|
||||
account = addedResult.account,
|
||||
wallet = addedResult.wallet,
|
||||
analyticsPayload = setOf(isSearched),
|
||||
analyticsPayload = setOf(isSearched, isMarketToken),
|
||||
)
|
||||
bridge.onCurrencyChosen(chooseTokenResult)
|
||||
marketBlockDelegate.addToPortfolioSlot.dismiss()
|
||||
|
|
|
|||
|
|
@ -112,6 +112,7 @@ internal class PortfolioListBlockDelegate @AssistedInject constructor(
|
|||
private fun onTokenItemClick(wallet: UserWallet, account: AccountStatus, currencyStatus: CryptoCurrencyStatus) {
|
||||
val analyticsPayload = setOf(
|
||||
ChooseTokenAnalyticsPayload.IsSearched(searchQueryState.isSearchingState),
|
||||
ChooseTokenAnalyticsPayload.IsMarketTokenSelected(false),
|
||||
)
|
||||
val result = ChooseTokenResult(
|
||||
account = account,
|
||||
|
|
|
|||
|
|
@ -159,8 +159,8 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
return pairs.firstOrNull { pair ->
|
||||
pair.from.network == fromSwapCurrencyStatus.currency.network.rawId &&
|
||||
pair.from.contractAddress == fromSwapCurrencyStatus.currency.getContractAddress() &&
|
||||
pair.to.network == toSwapCurrencyStatus.currency.network.rawId
|
||||
pair.to.contractAddress == toSwapCurrencyStatus.currency.getContractAddress()
|
||||
pair.to.network == toSwapCurrencyStatus.currency.network.rawId &&
|
||||
pair.to.contractAddress == toSwapCurrencyStatus.currency.getContractAddress()
|
||||
}?.providers.orEmpty()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue