diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsModel.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsModel.kt index cd2a54c343..46d7427763 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsModel.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsModel.kt @@ -88,6 +88,7 @@ import com.tangem.features.tokenreceive.TokenReceiveFeatureToggle import com.tangem.features.txhistory.entity.TxHistoryContentUpdateEmitter import com.tangem.features.yield.supply.api.YieldSupplyDepositedWarningComponent import com.tangem.features.yield.supply.api.YieldSupplyFeatureToggles +import com.tangem.features.yield.supply.api.analytics.YieldSupplyAnalytics import com.tangem.utils.Provider import com.tangem.utils.coroutines.* import com.tangem.utils.extensions.isZero @@ -1053,6 +1054,12 @@ internal class TokenDetailsModel @Inject constructor( } override fun onYieldInfoClick() { + analyticsEventsHandler.send( + YieldSupplyAnalytics.EarnedFundsInfo( + token = cryptoCurrency.symbol, + blockchain = cryptoCurrency.network.name, + ), + ) bottomSheetNavigation.activate( configuration = TokenDetailsBottomSheetConfig.YieldSupplyWarning( cryptoCurrency = cryptoCurrency, diff --git a/features/yield-supply/api/build.gradle.kts b/features/yield-supply/api/build.gradle.kts index 7fbd6e9fd1..162dfe30ca 100644 --- a/features/yield-supply/api/build.gradle.kts +++ b/features/yield-supply/api/build.gradle.kts @@ -12,6 +12,8 @@ dependencies { /** Core */ implementation(projects.core.decompose) implementation(projects.core.ui) + implementation(projects.core.analytics) + implementation(projects.core.analytics.models) /** Domain */ implementation(projects.domain.models) diff --git a/features/yield-supply/api/src/main/java/com/tangem/features/yield/supply/api/analytics/YieldSupplyAnalytics.kt b/features/yield-supply/api/src/main/java/com/tangem/features/yield/supply/api/analytics/YieldSupplyAnalytics.kt new file mode 100644 index 0000000000..a1860810d1 --- /dev/null +++ b/features/yield-supply/api/src/main/java/com/tangem/features/yield/supply/api/analytics/YieldSupplyAnalytics.kt @@ -0,0 +1,203 @@ +package com.tangem.features.yield.supply.api.analytics + +import com.tangem.core.analytics.models.AnalyticsEvent +import com.tangem.core.analytics.models.AnalyticsParam.Key.ACTION +import com.tangem.core.analytics.models.AnalyticsParam.Key.BLOCKCHAIN +import com.tangem.core.analytics.models.AnalyticsParam.Key.ERROR_DESCRIPTION +import com.tangem.core.analytics.models.AnalyticsParam.Key.STATUS +import com.tangem.core.analytics.models.AnalyticsParam.Key.TOKEN_PARAM + +sealed class YieldSupplyAnalytics( + event: String, + params: Map = mapOf(), +) : AnalyticsEvent(category = "Earning", event = event, params = params) { + + data class EarningScreenInfoOpened( + val token: String, + val blockchain: String, + ) : YieldSupplyAnalytics( + event = "Earning Screen Info Opened", + params = mapOf( + TOKEN_PARAM to token, + BLOCKCHAIN to blockchain, + ), + ) + + data class StartEarningScreen( + val token: String, + val blockchain: String, + ) : YieldSupplyAnalytics( + event = "Start Earning Screen", + params = mapOf( + TOKEN_PARAM to token, + BLOCKCHAIN to blockchain, + ), + ) + + data class ButtonStartEarning( + val token: String, + val blockchain: String, + ) : YieldSupplyAnalytics( + event = "Button - Start Earning", + params = mapOf( + TOKEN_PARAM to token, + BLOCKCHAIN to blockchain, + ), + ) + + data class ButtonStopEarning( + val token: String, + val blockchain: String, + ) : YieldSupplyAnalytics( + event = "Button - Stop Earning", + params = mapOf( + TOKEN_PARAM to token, + BLOCKCHAIN to blockchain, + ), + ) + + data object ButtonFeePolicy : YieldSupplyAnalytics( + event = "Button - Fee Policy", + ) + + data object EarnInProgressScreen : YieldSupplyAnalytics( + event = "Earn In Progress Screen", + ) + + data object FundsEarned : YieldSupplyAnalytics( + event = "Funds Earned", + ) + + data class FundsWithdrawn( + val token: String, + val blockchain: String, + ) : YieldSupplyAnalytics( + event = "Funds Withdrawn", + params = mapOf( + TOKEN_PARAM to token, + BLOCKCHAIN to blockchain, + ), + ) + + data class EarnedFundsInfo( + val token: String, + val blockchain: String, + ) : YieldSupplyAnalytics( + event = "Earned Funds Info", + params = mapOf( + TOKEN_PARAM to token, + BLOCKCHAIN to blockchain, + ), + ) + + data class NoticeNotEnoughFee( + val token: String, + val blockchain: String, + ) : YieldSupplyAnalytics( + event = "Notice - Not Enough Fee", + params = mapOf( + TOKEN_PARAM to token, + BLOCKCHAIN to blockchain, + ), + ) + + data class NoticeApproveNeeded( + val token: String, + val blockchain: String, + ) : YieldSupplyAnalytics( + event = "Notice - Approve Needed", + params = mapOf( + TOKEN_PARAM to token, + BLOCKCHAIN to blockchain, + ), + ) + + data class ApprovalAction( + val token: String, + val blockchain: String, + val action: Action, + ) : YieldSupplyAnalytics( + event = "Approval Action", + params = mapOf( + TOKEN_PARAM to token, + BLOCKCHAIN to blockchain, + ACTION to action.value, + ), + ) + + data class NoticeHighNetworkFee( + val token: String, + val blockchain: String, + ) : YieldSupplyAnalytics( + event = "Notice - High Network Fee", + params = mapOf( + TOKEN_PARAM to token, + BLOCKCHAIN to blockchain, + ), + ) + + data class EarnErrors( + val action: Action, + val errorDescription: String?, + ) : YieldSupplyAnalytics( + event = "Earn Errors", + params = buildMap { + ACTION to action + ERROR_DESCRIPTION to errorDescription.orEmpty() + }, + ) + + data class AssetStatusLoaded( + val status: AssetStatus, + ) : YieldSupplyAnalytics( + event = "Asset Status Loaded", + params = mapOf( + STATUS to status.value, + ), + ) + + data class ActionBlockedByStatus( + val status: AssetStatus, + ) : YieldSupplyAnalytics( + event = "Action Blocked by Status", + params = mapOf( + STATUS to status.value, + ), + ) + + data object ApyChartViewed : YieldSupplyAnalytics( + event = "APY Chart", + ) + + data class NoticeCommissionTooHigh( + val token: String, + val blockchain: String, + ) : YieldSupplyAnalytics( + event = "Notice - Commission Is Too High", + params = mapOf( + TOKEN_PARAM to token, + BLOCKCHAIN to blockchain, + ), + ) + + data class NoticeNotEnoughMinAmount( + val token: String, + val blockchain: String, + ) : YieldSupplyAnalytics( + event = "Notice - Not Enough Min Amount", + params = mapOf( + TOKEN_PARAM to token, + BLOCKCHAIN to blockchain, + ), + ) + + enum class Action(val value: String) { + Approve("Approve"), + Stop("Stop"), + } + + enum class AssetStatus(val value: String) { + Active("ACTIVE"), + Inactive("Inactive"), + } +} \ No newline at end of file diff --git a/features/yield-supply/impl/build.gradle.kts b/features/yield-supply/impl/build.gradle.kts index 02c2af1cb6..e79c976bd4 100644 --- a/features/yield-supply/impl/build.gradle.kts +++ b/features/yield-supply/impl/build.gradle.kts @@ -21,6 +21,8 @@ dependencies { implementation(projects.core.decompose) implementation(projects.core.ui) implementation(projects.core.navigation) + implementation(projects.core.analytics) + implementation(projects.core.analytics.models) /** Compose */ implementation(tangemDeps.vico.core) diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/model/YieldSupplyModel.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/model/YieldSupplyModel.kt index 243ae32425..0895525f5e 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/model/YieldSupplyModel.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/main/model/YieldSupplyModel.kt @@ -4,6 +4,7 @@ import com.arkivanov.decompose.router.slot.SlotNavigation import com.arkivanov.decompose.router.slot.activate import com.tangem.common.routing.AppRoute.YieldSupplyPromo import com.tangem.common.routing.AppRouter +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 @@ -25,6 +26,7 @@ import com.tangem.domain.yield.supply.usecase.YieldSupplyGetTokenStatusUseCase import com.tangem.domain.yield.supply.usecase.YieldSupplyIsAvailableUseCase import com.tangem.features.yield.supply.impl.R import com.tangem.features.yield.supply.api.YieldSupplyComponent +import com.tangem.features.yield.supply.api.analytics.YieldSupplyAnalytics import com.tangem.features.yield.supply.impl.main.entity.YieldSupplyUM import com.tangem.features.yield.supply.impl.main.model.transformers.YieldSupplyTokenStatusSuccessTransformer import com.tangem.utils.coroutines.CoroutineDispatcherProvider @@ -43,6 +45,7 @@ import kotlin.properties.Delegates internal class YieldSupplyModel @Inject constructor( paramsContainer: ParamsContainer, override val dispatchers: CoroutineDispatcherProvider, + private val analyticsEventsHandler: AnalyticsEventHandler, private val appRouter: AppRouter, private val getUserWalletUseCase: GetUserWalletUseCase, private val getSingleCryptoCurrencyStatusUseCase: GetSingleCryptoCurrencyStatusUseCase, @@ -188,6 +191,14 @@ internal class YieldSupplyModel @Inject constructor( } yieldSupplyStatus?.isActive == true -> { val cryptoCurrencyToken = cryptoCurrency as? CryptoCurrency.Token ?: return + if (!yieldSupplyStatus.isAllowedToSpend) { + analyticsEventsHandler.send( + YieldSupplyAnalytics.NoticeApproveNeeded( + token = cryptoCurrency.symbol, + blockchain = cryptoCurrency.network.name, + ), + ) + } modelScope.launch(dispatchers.default) { yieldSupplyGetTokenStatusUseCase(cryptoCurrencyToken) .onRight { tokenStatus -> diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/promo/model/YieldSupplyPromoModel.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/promo/model/YieldSupplyPromoModel.kt index 24be42b053..4a3d0411df 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/promo/model/YieldSupplyPromoModel.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/promo/model/YieldSupplyPromoModel.kt @@ -3,12 +3,16 @@ package com.tangem.features.yield.supply.impl.promo.model import com.arkivanov.decompose.router.slot.SlotNavigation import com.arkivanov.decompose.router.slot.activate import com.tangem.common.routing.AppRouter +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.navigation.url.UrlOpener import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.wrappedList +import com.tangem.features.yield.supply.api.YieldSupplyPromoComponent import com.tangem.features.yield.supply.impl.R +import com.tangem.features.yield.supply.api.analytics.YieldSupplyAnalytics import com.tangem.features.yield.supply.impl.promo.YieldSupplyPromoConfig import com.tangem.features.yield.supply.impl.promo.entity.YieldSupplyPromoUM import com.tangem.utils.TangemBlogUrlBuilder.YIELD_SUPPLY_HOW_IT_WORKS_URL @@ -18,16 +22,29 @@ import javax.inject.Inject @ModelScoped internal class YieldSupplyPromoModel @Inject constructor( override val dispatchers: CoroutineDispatcherProvider, + paramsContainer: ParamsContainer, + private val analytics: AnalyticsEventHandler, private val urlOpener: UrlOpener, private val appRouter: AppRouter, ) : Model(), YieldSupplyPromoClickIntents { + val params: YieldSupplyPromoComponent.Params = paramsContainer.require() + val uiState: YieldSupplyPromoUM = YieldSupplyPromoUM( tosLink = "https://tangem.com/terms-of-service/", // TODO replace with real link policyLink = "https://tangem.com/privacy-policy/", // TODO replace with real link title = resourceReference(R.string.yield_module_promo_screen_title, wrappedList("5.3")), ) + init { + analytics.send( + YieldSupplyAnalytics.EarningScreenInfoOpened( + token = params.currency.symbol, + blockchain = params.currency.network.name, + ), + ) + } + val bottomSheetNavigation: SlotNavigation = SlotNavigation() override fun onBackClick() { @@ -35,6 +52,7 @@ internal class YieldSupplyPromoModel @Inject constructor( } override fun onApyInfoClick() { + analytics.send(YieldSupplyAnalytics.ApyChartViewed) bottomSheetNavigation.activate(YieldSupplyPromoConfig.Apy) } diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/model/YieldSupplyActiveModel.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/model/YieldSupplyActiveModel.kt index 1241d2cebe..f54b17d1f9 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/model/YieldSupplyActiveModel.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/active/model/YieldSupplyActiveModel.kt @@ -2,6 +2,7 @@ package com.tangem.features.yield.supply.impl.subcomponents.active.model import arrow.core.getOrElse import com.tangem.common.ui.notifications.NotificationUM +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 @@ -19,6 +20,7 @@ import com.tangem.domain.yield.supply.usecase.YieldSupplyGetProtocolBalanceUseCa import com.tangem.domain.yield.supply.usecase.YieldSupplyGetTokenStatusUseCase import com.tangem.domain.yield.supply.usecase.YieldSupplyMinAmountUseCase import com.tangem.features.yield.supply.impl.R +import com.tangem.features.yield.supply.api.analytics.YieldSupplyAnalytics import com.tangem.features.yield.supply.impl.common.formatter.YieldSupplyMinAmountFormatter import com.tangem.features.yield.supply.impl.subcomponents.active.YieldSupplyActiveComponent import com.tangem.features.yield.supply.impl.subcomponents.active.entity.YieldSupplyActiveContentUM @@ -29,10 +31,12 @@ import kotlinx.coroutines.launch import timber.log.Timber import javax.inject.Inject +@Suppress("LongParameterList") @ModelScoped internal class YieldSupplyActiveModel @Inject constructor( paramsContainer: ParamsContainer, override val dispatchers: CoroutineDispatcherProvider, + analyticsHandler: AnalyticsEventHandler, private val yieldSupplyGetProtocolBalanceUseCase: YieldSupplyGetProtocolBalanceUseCase, private val yieldSupplyGetTokenStatusUseCase: YieldSupplyGetTokenStatusUseCase, private val yieldSupplyMinAmountUseCase: YieldSupplyMinAmountUseCase, @@ -62,6 +66,12 @@ internal class YieldSupplyActiveModel @Inject constructor( ) init { + analyticsHandler.send( + YieldSupplyAnalytics.EarningScreenInfoOpened( + token = cryptoCurrency.symbol, + blockchain = cryptoCurrency.network.name, + ), + ) subscribeOnCurrencyUpdates() modelScope.launch(dispatchers.default) { diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/approve/model/YieldSupplyApproveModel.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/approve/model/YieldSupplyApproveModel.kt index 4c3f65d7f9..5a7ac6bd0a 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/approve/model/YieldSupplyApproveModel.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/approve/model/YieldSupplyApproveModel.kt @@ -3,6 +3,7 @@ package com.tangem.features.yield.supply.impl.subcomponents.approve.model import arrow.core.getOrElse import com.tangem.blockchain.common.TransactionData import com.tangem.blockchain.common.transaction.TransactionFee +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 @@ -21,6 +22,7 @@ import com.tangem.domain.transaction.usecase.CreateApprovalTransactionUseCase import com.tangem.domain.transaction.usecase.GetFeeUseCase import com.tangem.domain.transaction.usecase.SendTransactionUseCase import com.tangem.domain.yield.supply.usecase.YieldSupplyGetContractAddressUseCase +import com.tangem.features.yield.supply.api.analytics.YieldSupplyAnalytics import com.tangem.features.yield.supply.impl.R import com.tangem.features.yield.supply.impl.common.YieldSupplyAlertFactory import com.tangem.features.yield.supply.impl.common.entity.YieldSupplyActionUM @@ -46,6 +48,7 @@ import javax.inject.Inject internal class YieldSupplyApproveModel @Inject constructor( override val dispatchers: CoroutineDispatcherProvider, paramsContainer: ParamsContainer, + private val analyticsEventHandler: AnalyticsEventHandler, private val urlOpener: UrlOpener, private val yieldSupplyNotificationsUpdateTrigger: YieldSupplyNotificationsUpdateTrigger, private val createApprovalTransactionUseCase: CreateApprovalTransactionUseCase, @@ -140,6 +143,11 @@ internal class YieldSupplyApproveModel @Inject constructor( ) }, ifRight = { + analyticsEventHandler.send(YieldSupplyAnalytics.ApprovalAction( + token = cryptoCurrency.symbol, + blockchain = cryptoCurrency.network.name, + action = YieldSupplyAnalytics.Action.Approve, + )) params.callback.onTransactionSent() }, ) diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/notifications/model/YieldSupplyNotificationsModel.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/notifications/model/YieldSupplyNotificationsModel.kt index be0223b21d..c758fe65c7 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/notifications/model/YieldSupplyNotificationsModel.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/notifications/model/YieldSupplyNotificationsModel.kt @@ -5,11 +5,13 @@ import com.tangem.common.routing.AppRouter import com.tangem.common.ui.notifications.NotificationUM import com.tangem.common.ui.notifications.NotificationsFactory.addExceedsBalanceNotification import com.tangem.common.ui.notifications.NotificationsFactory.addFeeUnreachableNotification +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.domain.models.currency.CryptoCurrency import com.tangem.domain.tokens.GetBalanceNotEnoughForFeeWarningUseCase +import com.tangem.features.yield.supply.api.analytics.YieldSupplyAnalytics import com.tangem.features.yield.supply.impl.subcomponents.notifications.YieldSupplyNotificationsComponent import com.tangem.features.yield.supply.impl.subcomponents.notifications.YieldSupplyNotificationsUpdateListener import com.tangem.lib.crypto.BlockchainUtils @@ -25,6 +27,7 @@ import javax.inject.Inject internal class YieldSupplyNotificationsModel @Inject constructor( paramsContainer: ParamsContainer, override val dispatchers: CoroutineDispatcherProvider, + private val analyticsEventHandler: AnalyticsEventHandler, private val appRouter: AppRouter, private val getBalanceNotEnoughForFeeWarningUseCase: GetBalanceNotEnoughForFeeWarningUseCase, private val yieldSupplyNotificationsUpdateListener: YieldSupplyNotificationsUpdateListener, @@ -72,6 +75,15 @@ internal class YieldSupplyNotificationsModel @Inject constructor( ) } + if (notifications.any { it is NotificationUM.Error.TokenExceedsBalance }) { + analyticsEventHandler.send( + YieldSupplyAnalytics.NoticeNotEnoughFee( + token = cryptoCurrencyStatus.currency.symbol, + blockchain = cryptoCurrencyStatus.currency.network.name, + ), + ) + } + uiState.update { notifications.toPersistentList() } yieldSupplyNotificationsUpdateListener.callbackHasError(notifications.any()) diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/startearning/model/YieldSupplyStartEarningEntryModel.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/startearning/model/YieldSupplyStartEarningEntryModel.kt index b2b2db7f41..d6de1559ac 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/startearning/model/YieldSupplyStartEarningEntryModel.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/startearning/model/YieldSupplyStartEarningEntryModel.kt @@ -1,5 +1,6 @@ package com.tangem.features.yield.supply.impl.subcomponents.startearning.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 @@ -8,6 +9,7 @@ import com.tangem.core.ui.components.currency.icon.converter.CryptoCurrencyToIco import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.wrappedList import com.tangem.features.yield.supply.impl.R +import com.tangem.features.yield.supply.api.analytics.YieldSupplyAnalytics import com.tangem.features.yield.supply.impl.common.entity.YieldSupplyActionUM import com.tangem.features.yield.supply.impl.common.entity.YieldSupplyFeeUM import com.tangem.features.yield.supply.impl.subcomponents.feepolicy.YieldSupplyFeePolicyComponent @@ -24,6 +26,7 @@ import javax.inject.Inject internal class YieldSupplyStartEarningEntryModel @Inject constructor( override val dispatchers: CoroutineDispatcherProvider, private val router: Router, + private val analyticsEventHandler: AnalyticsEventHandler, paramsContainer: ParamsContainer, ) : Model(), YieldSupplyStartEarningComponent.ModelCallback, YieldSupplyFeePolicyComponent.ModelCallback { @@ -55,6 +58,9 @@ internal class YieldSupplyStartEarningEntryModel @Inject constructor( } override fun onFeePolicyClick() { + analyticsEventHandler.send( + YieldSupplyAnalytics.ButtonFeePolicy, + ) router.push(YieldSupplyStartEarningRoute.FeePolicy) } diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/startearning/model/YieldSupplyStartEarningModel.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/startearning/model/YieldSupplyStartEarningModel.kt index d688a82ba8..f7390118e6 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/startearning/model/YieldSupplyStartEarningModel.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/startearning/model/YieldSupplyStartEarningModel.kt @@ -2,6 +2,7 @@ package com.tangem.features.yield.supply.impl.subcomponents.startearning.model import arrow.core.getOrElse import com.tangem.blockchain.common.TransactionSender +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 @@ -17,6 +18,7 @@ import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.tokens.FetchCurrencyStatusUseCase import com.tangem.domain.tokens.GetFeePaidCryptoCurrencyStatusSyncUseCase import com.tangem.domain.tokens.GetSingleCryptoCurrencyStatusUseCase +import com.tangem.domain.transaction.error.GetFeeError import com.tangem.domain.transaction.usecase.SendTransactionUseCase import com.tangem.domain.wallets.usecase.GetUserWalletUseCase import com.tangem.domain.yield.supply.usecase.YieldSupplyActivateUseCase @@ -25,6 +27,7 @@ import com.tangem.domain.yield.supply.usecase.YieldSupplyGetTokenStatusUseCase import com.tangem.domain.yield.supply.usecase.YieldSupplyMinAmountUseCase import com.tangem.domain.yield.supply.usecase.YieldSupplyStartEarningUseCase import com.tangem.features.yield.supply.impl.R +import com.tangem.features.yield.supply.api.analytics.YieldSupplyAnalytics import com.tangem.features.yield.supply.impl.common.YieldSupplyAlertFactory import com.tangem.features.yield.supply.impl.common.entity.YieldSupplyActionUM import com.tangem.features.yield.supply.impl.common.entity.YieldSupplyFeeUM @@ -38,6 +41,7 @@ import com.tangem.features.yield.supply.impl.subcomponents.startearning.model.tr import com.tangem.utils.coroutines.CoroutineDispatcherProvider import com.tangem.utils.extensions.orZero import com.tangem.utils.transformer.update +import kotlinx.coroutines.NonCancellable import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch import timber.log.Timber @@ -50,6 +54,7 @@ import kotlin.properties.Delegates internal class YieldSupplyStartEarningModel @Inject constructor( override val dispatchers: CoroutineDispatcherProvider, paramsContainer: ParamsContainer, + private val analytics: AnalyticsEventHandler, private val getUserWalletUseCase: GetUserWalletUseCase, private val getSingleCryptoCurrencyStatusUseCase: GetSingleCryptoCurrencyStatusUseCase, private val getFeePaidCryptoCurrencyStatusSyncUseCase: GetFeePaidCryptoCurrencyStatusSyncUseCase, @@ -108,6 +113,12 @@ internal class YieldSupplyStartEarningModel @Inject constructor( private var appCurrency = AppCurrency.Default init { + analytics.send( + YieldSupplyAnalytics.StartEarningScreen( + token = params.cryptoCurrency.symbol, + blockchain = params.cryptoCurrency.network.name, + ), + ) modelScope.launch { appCurrency = getSelectedAppCurrencyUseCase.invokeSync().getOrElse { AppCurrency.Default } subscribeOnCurrencyStatusUpdates() @@ -133,6 +144,10 @@ internal class YieldSupplyStartEarningModel @Inject constructor( private suspend fun onLoadFee() { if (cryptoCurrencyStatus.value is CryptoCurrencyStatus.Loading || uiState.value.isTransactionSending) return + uiState.update { + it.copy(yieldSupplyFeeUM = YieldSupplyFeeUM.Loading) + } + val maxFee = if (uiState.value.maxFee == BigDecimal.ZERO) { getMaxFee() } else { @@ -143,10 +158,19 @@ internal class YieldSupplyStartEarningModel @Inject constructor( userWalletId = userWallet.walletId, cryptoCurrencyStatus = cryptoCurrencyStatus, maxNetworkFee = maxFee, - ).getOrNull() ?: return + ).getOrNull() - uiState.update { - it.copy(yieldSupplyFeeUM = YieldSupplyFeeUM.Loading) + if (transactionListData == null) { + uiState.update { + it.copy(yieldSupplyFeeUM = YieldSupplyFeeUM.Error) + } + yieldSupplyNotificationsUpdateTrigger.triggerUpdate( + data = YieldSupplyNotificationData( + feeValue = null, + feeError = GetFeeError.UnknownError, + ), + ) + return } yieldSupplyEstimateEnterFeeUseCase.invoke( @@ -192,6 +216,12 @@ internal class YieldSupplyStartEarningModel @Inject constructor( fun onClick() { val yieldSupplyFeeUM = uiState.value.yieldSupplyFeeUM as? YieldSupplyFeeUM.Content ?: return + analytics.send( + YieldSupplyAnalytics.ButtonStartEarning( + token = params.cryptoCurrency.symbol, + blockchain = params.cryptoCurrency.network.name, + ), + ) uiState.update(YieldSupplyTransactionInProgressTransformer) modelScope.launch(dispatchers.default) { @@ -204,6 +234,10 @@ internal class YieldSupplyStartEarningModel @Inject constructor( ifLeft = { error -> Timber.e(error.toString()) uiState.update(YieldSupplyTransactionReadyTransformer) + analytics.send(YieldSupplyAnalytics.EarnErrors( + action = YieldSupplyAnalytics.Action.Approve, + errorDescription = error.getAnalyticsDescription(), + )) yieldSupplyAlertFactory.getSendTransactionErrorState( error = error, popBack = params.callback::onBackClick, @@ -219,8 +253,14 @@ internal class YieldSupplyStartEarningModel @Inject constructor( ) }, ifRight = { - fetchCurrencyStatusUseCase(userWalletId = userWallet.walletId, cryptoCurrency.id) yieldSupplyActivateUseCase(cryptoCurrency) + modelScope.launch(NonCancellable) { + fetchCurrencyStatusUseCase( + userWalletId = userWallet.walletId, + cryptoCurrency.id, + ) + } + analytics.send(YieldSupplyAnalytics.FundsEarned) modelScope.launch { params.callback.onTransactionSent() } diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/stopearning/model/YieldSupplyStopEarningModel.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/stopearning/model/YieldSupplyStopEarningModel.kt index 05545b93de..a6f111df3a 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/stopearning/model/YieldSupplyStopEarningModel.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/stopearning/model/YieldSupplyStopEarningModel.kt @@ -1,6 +1,7 @@ package com.tangem.features.yield.supply.impl.subcomponents.stopearning.model import arrow.core.getOrElse +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 @@ -19,6 +20,7 @@ import com.tangem.domain.transaction.usecase.SendTransactionUseCase import com.tangem.domain.yield.supply.usecase.YieldSupplyDeactivateUseCase import com.tangem.domain.yield.supply.usecase.YieldSupplyStopEarningUseCase import com.tangem.features.yield.supply.impl.R +import com.tangem.features.yield.supply.api.analytics.YieldSupplyAnalytics import com.tangem.features.yield.supply.impl.common.YieldSupplyAlertFactory import com.tangem.features.yield.supply.impl.common.entity.YieldSupplyActionUM import com.tangem.features.yield.supply.impl.common.entity.YieldSupplyFeeUM @@ -33,6 +35,7 @@ import com.tangem.utils.TangemBlogUrlBuilder import com.tangem.utils.coroutines.CoroutineDispatcherProvider import com.tangem.utils.extensions.orZero import com.tangem.utils.transformer.update +import kotlinx.coroutines.NonCancellable import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch import timber.log.Timber @@ -43,6 +46,7 @@ import javax.inject.Inject internal class YieldSupplyStopEarningModel @Inject constructor( override val dispatchers: CoroutineDispatcherProvider, paramsContainer: ParamsContainer, + private val analytics: AnalyticsEventHandler, private val getFeeUseCase: GetFeeUseCase, private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase, private val getFeePaidCryptoCurrencyStatusSyncUseCase: GetFeePaidCryptoCurrencyStatusSyncUseCase, @@ -112,6 +116,12 @@ internal class YieldSupplyStopEarningModel @Inject constructor( fun onClick() { val yieldSupplyFeeUM = uiState.value.yieldSupplyFeeUM as? YieldSupplyFeeUM.Content ?: return + analytics.send( + YieldSupplyAnalytics.ButtonStopEarning( + token = cryptoCurrency.symbol, + blockchain = cryptoCurrency.network.name, + ), + ) uiState.update(YieldSupplyTransactionInProgressTransformer) modelScope.launch(dispatchers.default) { @@ -138,8 +148,16 @@ internal class YieldSupplyStopEarningModel @Inject constructor( ) }, ifRight = { - fetchCurrencyStatusUseCase(userWalletId = userWallet.walletId, cryptoCurrency.id) + analytics.send( + YieldSupplyAnalytics.FundsWithdrawn( + token = cryptoCurrency.symbol, + blockchain = cryptoCurrency.network.name, + ), + ) yieldSupplyDeactivateUseCase(cryptoCurrency) + modelScope.launch(NonCancellable) { + fetchCurrencyStatusUseCase(userWalletId = userWallet.walletId, cryptoCurrency.id) + } params.callback.onTransactionSent() }, )