Updated on 2026-08-14

This commit is contained in:
Tangem 2025-12-29 17:48:35 +04:00
parent 33f2e5f297
commit d128f48b05
7 changed files with 84 additions and 1 deletions

View file

@ -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<String, BigDecimal>,
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)
},
)
}

View file

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

View file

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

View file

@ -269,6 +269,7 @@ sealed class TokenItemState {
val title: TextReference,
val onPromoBannerClick: () -> Unit,
val onCloseClick: () -> Unit,
val onPromoShown: () -> Unit = {},
) : PromoBannerState()
data object Empty : PromoBannerState()

View file

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

View file

@ -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<String, Boolean>()
private val yieldPromoShownMap = mutableMapOf<String, Boolean>()
private val mutex = Mutex()
private val loadingTraces = mutableMapOf<UserWalletId, Trace>()
@ -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"

View file

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