diff --git a/domain/nft/build.gradle.kts b/domain/nft/build.gradle.kts index b5ce316d58..518f509278 100644 --- a/domain/nft/build.gradle.kts +++ b/domain/nft/build.gradle.kts @@ -13,6 +13,7 @@ dependencies { implementation(deps.arrow.core) implementation(deps.kotlin.coroutines) + implementation(projects.core.analytics.models) implementation(projects.core.utils) implementation(projects.domain.core) diff --git a/domain/nft/src/main/kotlin/com/tangem/domain/nft/analytics/NFTAnalyticsEvent.kt b/domain/nft/src/main/kotlin/com/tangem/domain/nft/analytics/NFTAnalyticsEvent.kt new file mode 100644 index 0000000000..dbb2139d18 --- /dev/null +++ b/domain/nft/src/main/kotlin/com/tangem/domain/nft/analytics/NFTAnalyticsEvent.kt @@ -0,0 +1,60 @@ +package com.tangem.domain.nft.analytics + +import com.tangem.core.analytics.models.AnalyticsEvent +import com.tangem.core.analytics.models.AnalyticsParam.Key.BLOCKCHAIN +import com.tangem.core.analytics.models.AnalyticsParam.Key.COUNT +import com.tangem.core.analytics.models.AnalyticsParam.Key.STATE + +sealed class NFTAnalyticsEvent( + event: String, + params: Map = mapOf(), +) : AnalyticsEvent( + category = "NFT", + event = event, + params = params, +) { + + data class NFTListScreenOpened( + val state: State, + ) : NFTAnalyticsEvent( + event = "NFT List Screen Opened", + params = buildMap { + put(STATE, state.value) + if (state is State.Full) { + put(COUNT, state.count.toString()) + } + }, + ) { + sealed class State(val value: String) { + data object Empty : State("Empty") + data class Full(val count: Int) : State("Full") + } + } + + object Receive { + data object ScreenOpened : NFTAnalyticsEvent(event = "Receive NFT Screen Opened") + + data class BlockchainChosen( + private val blockchain: String, + ) : NFTAnalyticsEvent(event = "Blockchain Chosen", params = mapOf(BLOCKCHAIN to blockchain)) + + data class CopyAddress( + private val blockchain: String, + ) : NFTAnalyticsEvent(event = "Button - Copy Address", params = mapOf(BLOCKCHAIN to blockchain)) + + data class ShareAddress( + private val blockchain: String, + ) : NFTAnalyticsEvent(event = "Button - Share Address", params = mapOf(BLOCKCHAIN to blockchain)) + } + + object Details { + data class ScreenOpened( + private val blockchain: String, + ) : NFTAnalyticsEvent(event = "NFT Details Screen Opened", params = mapOf(BLOCKCHAIN to blockchain)) + + data object ButtonReadMore : NFTAnalyticsEvent(event = "Button - Read More") + data object ButtonSeeAll : NFTAnalyticsEvent(event = "Button - See All") + data object ButtonExplore : NFTAnalyticsEvent(event = "Button - Explore") + data object ButtonSend : NFTAnalyticsEvent(event = "Button - Send") + } +} \ No newline at end of file diff --git a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/details/model/NFTDetailsModel.kt b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/details/model/NFTDetailsModel.kt index c81f317e67..918cfd4ab6 100644 --- a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/details/model/NFTDetailsModel.kt +++ b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/details/model/NFTDetailsModel.kt @@ -1,10 +1,12 @@ package com.tangem.features.nft.details.model import com.tangem.common.routing.AppRoute +import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.decompose.navigation.Router +import com.tangem.domain.nft.analytics.NFTAnalyticsEvent import com.tangem.features.nft.details.NFTDetailsComponent import com.tangem.features.nft.details.entity.NFTAssetUM import com.tangem.features.nft.details.entity.NFTDetailsUM @@ -18,6 +20,7 @@ import javax.inject.Inject internal class NFTDetailsModel @Inject constructor( override val dispatchers: CoroutineDispatcherProvider, private val router: Router, + private val analyticsEventHandler: AnalyticsEventHandler, paramsContainer: ParamsContainer, ) : Model() { @@ -37,22 +40,30 @@ internal class NFTDetailsModel @Inject constructor( ), onBackClick = params.onBackClick, onReadMoreClick = ::onReadMoreClick, - onSeeAllTraitsClick = params.onAllTraitsClick, + onSeeAllTraitsClick = { + analyticsEventHandler.send(NFTAnalyticsEvent.Details.ButtonSeeAll) + params.onAllTraitsClick() + }, onExploreClick = ::onExploreClick, onSendClick = ::onSendClick, bottomSheetConfig = null, ), ) + init { + analyticsEventHandler.send(NFTAnalyticsEvent.Details.ScreenOpened(params.nftAsset.network.name)) + } + private fun onReadMoreClick() { - // TODO implement + analyticsEventHandler.send(NFTAnalyticsEvent.Details.ButtonReadMore) } private fun onExploreClick() { - // TODO implement + analyticsEventHandler.send(NFTAnalyticsEvent.Details.ButtonExplore) } private fun onSendClick() { + analyticsEventHandler.send(NFTAnalyticsEvent.Details.ButtonSend) router.push( AppRoute.NFTSend( userWalletId = params.userWalletId, diff --git a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/model/NFTReceiveModel.kt b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/model/NFTReceiveModel.kt index 83bfeedb42..3d62d4c7e2 100644 --- a/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/model/NFTReceiveModel.kt +++ b/features/nft/impl/src/main/kotlin/com/tangem/features/nft/receive/model/NFTReceiveModel.kt @@ -1,5 +1,6 @@ package com.tangem.features.nft.receive.model +import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer @@ -11,6 +12,7 @@ import com.tangem.core.ui.extensions.resourceReference import com.tangem.domain.nft.FilterNFTAvailableNetworksUseCase import com.tangem.domain.nft.GetNFTAvailableNetworksUseCase import com.tangem.domain.nft.GetNFTNetworkStatusUseCase +import com.tangem.domain.nft.analytics.NFTAnalyticsEvent import com.tangem.domain.tokens.model.Network import com.tangem.domain.tokens.model.NetworkStatus import com.tangem.features.nft.impl.R @@ -36,6 +38,7 @@ internal class NFTReceiveModel @Inject constructor( private val getNFTNetworkStatusUseCase: GetNFTNetworkStatusUseCase, private val clipboardManager: ClipboardManager, private val shareManager: ShareManager, + private val analyticsEventHandler: AnalyticsEventHandler, paramsContainer: ParamsContainer, ) : Model() { @@ -53,6 +56,7 @@ internal class NFTReceiveModel @Inject constructor( val state: StateFlow get() = _state init { + analyticsEventHandler.send(NFTAnalyticsEvent.Receive.ScreenOpened) subscribeToNFTAvailableNetworks() } @@ -106,6 +110,8 @@ internal class NFTReceiveModel @Inject constructor( private fun onNetworkClick(network: Network) { modelScope.launch { + analyticsEventHandler.send(NFTAnalyticsEvent.Receive.BlockchainChosen(network.name)) + val networkStatus = getNFTNetworkStatusUseCase.invoke( userWalletId = params.userWalletId, network = network, @@ -118,8 +124,8 @@ internal class NFTReceiveModel @Inject constructor( network = network, networkAddress = value.address, onDismissBottomSheet = ::onReceiveBottomSheetDismiss, - onCopyClick = ::onCopyClick, - onShareClick = ::onShareClick, + onCopyClick = { text -> onCopyClick(text, network) }, + onShareClick = { text -> onShareClick(text, network) }, ).transform(it) } } @@ -131,11 +137,13 @@ internal class NFTReceiveModel @Inject constructor( } } - private fun onCopyClick(text: String) { + private fun onCopyClick(text: String, network: Network) { + analyticsEventHandler.send(NFTAnalyticsEvent.Receive.CopyAddress(network.name)) clipboardManager.setText(text = text, isSensitive = true) } - private fun onShareClick(text: String) { + private fun onShareClick(text: String, network: Network) { + analyticsEventHandler.send(NFTAnalyticsEvent.Receive.ShareAddress(network.name)) shareManager.shareText(text = text) } } \ No newline at end of file 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 c1e1f1fde0..680e373b9b 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 @@ -2,7 +2,9 @@ package com.tangem.feature.wallet.child.wallet.model.intents import arrow.core.getOrElse import com.tangem.common.ui.expressStatus.ExpressStatusBottomSheetConfig +import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.decompose.di.ModelScoped +import com.tangem.domain.nft.analytics.NFTAnalyticsEvent import com.tangem.domain.redux.ReduxStateHolder import com.tangem.domain.settings.ShouldShowMarketsTooltipUseCase import com.tangem.domain.tokens.GetCryptoCurrencyActionsUseCase @@ -75,6 +77,7 @@ internal class WalletContentClickIntentsImplementor @Inject constructor( private val dispatchers: CoroutineDispatcherProvider, private val reduxStateHolder: ReduxStateHolder, private val walletEventSender: WalletEventSender, + private val analyticsEventHandler: AnalyticsEventHandler, ) : BaseWalletClickIntents(), WalletContentClickIntents { override fun onDetailsClick() { @@ -240,6 +243,19 @@ internal class WalletContentClickIntentsImplementor @Inject constructor( } override fun onNFTClick(userWalletId: UserWalletId) { + val selectedWallet = stateHolder.getSelectedWallet() as? WalletState.MultiCurrency.Content ?: return + val analyticsState = when (val nftState = selectedWallet.nftState) { + is WalletNFTItemUM.Content -> NFTAnalyticsEvent.NFTListScreenOpened.State.Full(nftState.assetsCount) + is WalletNFTItemUM.Empty -> NFTAnalyticsEvent.NFTListScreenOpened.State.Empty + is WalletNFTItemUM.Failed, + is WalletNFTItemUM.Hidden, + is WalletNFTItemUM.Loading, + -> null + } + analyticsState?.let { + analyticsEventHandler.send(NFTAnalyticsEvent.NFTListScreenOpened(analyticsState)) + } + router.openNFT(userWalletId) } } \ No newline at end of file