diff --git a/common/ui/src/main/java/com/tangem/common/ui/tokens/TokenItemStateConverter.kt b/common/ui/src/main/java/com/tangem/common/ui/tokens/TokenItemStateConverter.kt index 38a1c8c270..c92f348a54 100644 --- a/common/ui/src/main/java/com/tangem/common/ui/tokens/TokenItemStateConverter.kt +++ b/common/ui/src/main/java/com/tangem/common/ui/tokens/TokenItemStateConverter.kt @@ -51,6 +51,8 @@ class TokenItemStateConverter( }, private val onApyLabelClick: ((CryptoCurrencyStatus, ApySource, String) -> Unit)? = null, private val onYieldPromoCloseClick: (() -> Unit)? = null, + private val onYieldPromoShown: ((cryptoCurrency: CryptoCurrency) -> Unit)? = null, + private val onYieldPromoClicked: ((cryptoCurrency: CryptoCurrency) -> Unit)? = null, private val titleStateProvider: (CryptoCurrencyStatus) -> TokenItemState.TitleState = { currencyStatus -> createTitleState( currencyStatus = currencyStatus, @@ -75,6 +77,8 @@ class TokenItemStateConverter( yieldSupplyPromoBannerKey = yieldSupplyPromoBannerKey, onApyLabelClick = onApyLabelClick, onYieldPromoCloseClick = onYieldPromoCloseClick, + onYieldPromoShown = onYieldPromoShown, + onYieldPromoClicked = onYieldPromoClicked, ) }, private val onItemClick: ((TokenItemState, CryptoCurrencyStatus) -> Unit)? = null, @@ -389,12 +393,15 @@ class TokenItemStateConverter( } } + @Suppress("LongParameterList") private fun createPromoBannerState( status: CryptoCurrencyStatus, yieldModuleApyMap: Map, yieldSupplyPromoBannerKey: String?, onApyLabelClick: ((CryptoCurrencyStatus, ApySource, String) -> Unit)?, onYieldPromoCloseClick: (() -> Unit)?, + onYieldPromoShown: ((cryptoCurrency: CryptoCurrency) -> Unit)?, + onYieldPromoClicked: ((cryptoCurrency: CryptoCurrency) -> Unit)?, ): TokenItemState.PromoBannerState { val token = status.currency as? CryptoCurrency.Token ?: return TokenItemState.PromoBannerState.Empty if (status.value !is CryptoCurrencyStatus.Loaded) { @@ -414,11 +421,15 @@ class TokenItemStateConverter( wrappedList(yieldSupplyApy), ), onPromoBannerClick = { + onYieldPromoClicked?.invoke(status.currency) onApyLabelClick?.invoke(status, ApySource.YIELD_SUPPLY, yieldSupplyApy.toString()) }, onCloseClick = { onYieldPromoCloseClick?.invoke() }, + onPromoShown = { + onYieldPromoShown?.invoke(status.currency) + }, ) } diff --git a/core/analytics/models/src/main/java/com/tangem/core/analytics/models/event/MainScreenAnalyticsEvent.kt b/core/analytics/models/src/main/java/com/tangem/core/analytics/models/event/MainScreenAnalyticsEvent.kt index c8864d3617..c7958a7e35 100644 --- a/core/analytics/models/src/main/java/com/tangem/core/analytics/models/event/MainScreenAnalyticsEvent.kt +++ b/core/analytics/models/src/main/java/com/tangem/core/analytics/models/event/MainScreenAnalyticsEvent.kt @@ -126,6 +126,28 @@ sealed class MainScreenAnalyticsEvent( STATE to state, ), ) + + data class YieldPromo( + val token: String, + val blockchain: String, + ) : MainScreenAnalyticsEvent( + event = "Yield Promo", + params = mapOf( + TOKEN_PARAM to token, + BLOCKCHAIN to blockchain, + ), + ) + + data class YieldPromoClicked( + val token: String, + val blockchain: String, + ) : MainScreenAnalyticsEvent( + event = "Yield Promo Clicked", + params = mapOf( + TOKEN_PARAM to token, + BLOCKCHAIN to blockchain, + ), + ) // endregion companion object { diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/token/internal/YieldSupplyPromoBanner.kt b/core/ui/src/main/java/com/tangem/core/ui/components/token/internal/YieldSupplyPromoBanner.kt index b949061451..71ccba070a 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/token/internal/YieldSupplyPromoBanner.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/token/internal/YieldSupplyPromoBanner.kt @@ -18,6 +18,7 @@ import android.content.res.Configuration import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Box import androidx.compose.material3.ripple +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.remember import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.vectorResource @@ -39,6 +40,9 @@ internal fun YieldSupplyPromoBanner(state: PromoBannerState, modifier: Modifier @Composable internal fun YieldSupplyPromoBanner(state: PromoBannerState.Content, modifier: Modifier = Modifier) { + LaunchedEffect(state) { + state.onPromoShown() + } val bgColor = TangemTheme.colors.control.unchecked Column(modifier = modifier) { Row( diff --git a/core/ui/src/main/java/com/tangem/core/ui/components/token/state/TokenItemState.kt b/core/ui/src/main/java/com/tangem/core/ui/components/token/state/TokenItemState.kt index a2180bb614..7193eed339 100644 --- a/core/ui/src/main/java/com/tangem/core/ui/components/token/state/TokenItemState.kt +++ b/core/ui/src/main/java/com/tangem/core/ui/components/token/state/TokenItemState.kt @@ -269,6 +269,7 @@ sealed class TokenItemState { val title: TextReference, val onPromoBannerClick: () -> Unit, val onCloseClick: () -> Unit, + val onPromoShown: () -> Unit = {}, ) : PromoBannerState() data object Empty : PromoBannerState() diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletContentClickIntents.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletContentClickIntents.kt index 4c0038bfe2..46fbfc16d4 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletContentClickIntents.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletContentClickIntents.kt @@ -7,6 +7,7 @@ import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.analytics.models.event.MainScreenAnalyticsEvent import com.tangem.core.decompose.di.ModelScoped import com.tangem.domain.models.account.Account +import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.currency.CryptoCurrencyStatus import com.tangem.domain.models.staking.YieldBalance import com.tangem.domain.models.wallet.UserWallet @@ -23,6 +24,7 @@ import com.tangem.domain.wallets.usecase.GetUserWalletUseCase import com.tangem.domain.yield.supply.usecase.YieldSupplyEnterStatusUseCase import com.tangem.domain.yield.supply.usecase.YieldSupplySetShouldShowMainPromoUseCase import com.tangem.feature.wallet.presentation.account.AccountDependencies +import com.tangem.feature.wallet.presentation.wallet.analytics.utils.TokenListAnalyticsSender import com.tangem.feature.wallet.presentation.wallet.domain.OnrampStatusFactory import com.tangem.feature.wallet.presentation.wallet.domain.unwrap import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController @@ -60,6 +62,10 @@ internal interface WalletContentClickIntents { fun onYieldPromoCloseClick() + fun onYieldPromoShown(cryptoCurrency: CryptoCurrency) + + fun onYieldPromoClicked(cryptoCurrency: CryptoCurrency) + fun onAccountExpandClick(account: Account) fun onAccountCollapseClick(account: Account) @@ -79,7 +85,7 @@ internal interface WalletContentClickIntents { fun onNFTClick(userWallet: UserWallet) } -@Suppress("LongParameterList") +@Suppress("LongParameterList", "LargeClass") @ModelScoped internal class WalletContentClickIntentsImplementor @Inject constructor( private val stateHolder: WalletStateController, @@ -98,6 +104,7 @@ internal class WalletContentClickIntentsImplementor @Inject constructor( private val accountDependencies: AccountDependencies, private val yieldSupplyEnterStatusUseCase: YieldSupplyEnterStatusUseCase, private val yieldSupplySetShouldShowMainPromoUseCase: YieldSupplySetShouldShowMainPromoUseCase, + private val tokenListAnalyticsSender: TokenListAnalyticsSender, ) : BaseWalletClickIntents(), WalletContentClickIntents { override fun onDetailsClick() { @@ -203,6 +210,27 @@ internal class WalletContentClickIntentsImplementor @Inject constructor( } } + override fun onYieldPromoShown(cryptoCurrency: CryptoCurrency) { + modelScope.launch(dispatchers.io) { + tokenListAnalyticsSender.sendYieldPromoShown( + userWalletId = stateHolder.getSelectedWalletId(), + token = cryptoCurrency.symbol, + blockchain = cryptoCurrency.network.name, + ) + } + } + + override fun onYieldPromoClicked(cryptoCurrency: CryptoCurrency) { + modelScope.launch(dispatchers.io) { + analyticsEventHandler.send( + MainScreenAnalyticsEvent.YieldPromoClicked( + token = cryptoCurrency.symbol, + blockchain = cryptoCurrency.network.name, + ), + ) + } + } + override fun onAccountExpandClick(account: Account) { val userWalletId = stateHolder.getSelectedWalletId() accountDependencies.expandedAccountsHolder.expandAccount(userWalletId, account.accountId) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/TokenListAnalyticsSender.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/TokenListAnalyticsSender.kt index fe583f7183..eb12beb3f3 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/TokenListAnalyticsSender.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/utils/TokenListAnalyticsSender.kt @@ -8,6 +8,7 @@ import com.tangem.blockchainsdk.utils.fromNetworkId import com.tangem.common.extensions.isZero import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.analytics.models.AnalyticsParam +import com.tangem.core.analytics.models.event.MainScreenAnalyticsEvent import com.tangem.core.decompose.di.ModelScoped import com.tangem.domain.analytics.CheckIsWalletToppedUpUseCase import com.tangem.domain.analytics.model.WalletBalanceState @@ -34,6 +35,7 @@ internal class TokenListAnalyticsSender @Inject constructor( ) { private val balanceWasSentMap = mutableMapOf() + private val yieldPromoShownMap = mutableMapOf() private val mutex = Mutex() private val loadingTraces = mutableMapOf() @@ -233,6 +235,19 @@ internal class TokenListAnalyticsSender @Inject constructor( } } + fun sendYieldPromoShown(userWalletId: UserWalletId, token: String, blockchain: String) { + val key = "${userWalletId.stringValue}_${blockchain}_$token" + if (yieldPromoShownMap[key] == true) return + + analyticsEventHandler.send( + MainScreenAnalyticsEvent.YieldPromo( + token = token, + blockchain = blockchain, + ), + ) + yieldPromoShownMap[key] = true + } + companion object { const val BALANCE_LOADED_TRACE_NAME = "Total_balance_loaded" const val HAS_ERROR = "has_error" diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TokenListStateConverter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TokenListStateConverter.kt index 2520491085..2d42286d42 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TokenListStateConverter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/TokenListStateConverter.kt @@ -78,6 +78,8 @@ internal class TokenListStateConverter( onItemLongClick = { _, status -> onTokenLongClick(accountId, status) }, onApyLabelClick = { status, apySource, apy -> onApyLabelClick(status, apySource, apy) }, onYieldPromoCloseClick = clickIntents::onYieldPromoCloseClick, + onYieldPromoShown = clickIntents::onYieldPromoShown, + onYieldPromoClicked = clickIntents::onYieldPromoClicked, ) override fun convert(value: WalletTokensListState): WalletTokensListState {