Updated on 2026-08-14
This commit is contained in:
parent
34dd15bea5
commit
88400cd0d5
11 changed files with 208 additions and 41 deletions
|
|
@ -1,25 +0,0 @@
|
|||
package com.tangem.tap.common.analytics.events
|
||||
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
sealed class MainScreen(
|
||||
event: String,
|
||||
params: Map<String, String> = mapOf(),
|
||||
) : AnalyticsEvent("Main Screen", event, params) {
|
||||
|
||||
class ScreenOpened : MainScreen("Screen opened")
|
||||
class ButtonScanCard : MainScreen("Button - Scan Card")
|
||||
|
||||
class EnableBiometrics(state: AnalyticsParam.OnOffState) : MainScreen(
|
||||
event = "Enable Biometric",
|
||||
params = mapOf("State" to state.value),
|
||||
)
|
||||
|
||||
class NoticeRateAppButton(result: AnalyticsParam.RateApp) : MainScreen(
|
||||
event = "Notice - Rate The App Button Tapped",
|
||||
params = mapOf("Result" to result.value),
|
||||
)
|
||||
}
|
||||
|
|
@ -9,7 +9,6 @@ import com.tangem.domain.wallets.builder.UserWalletIdBuilder
|
|||
import com.tangem.tap.common.analytics.converters.ParamCardCurrencyConverter
|
||||
import com.tangem.tap.common.analytics.events.AnalyticsParam
|
||||
import com.tangem.tap.common.analytics.events.IntroductionProcess
|
||||
import com.tangem.tap.common.analytics.events.MainScreen
|
||||
import com.tangem.tap.common.extensions.inject
|
||||
import com.tangem.tap.features.demo.DemoHelper
|
||||
import com.tangem.tap.proxy.redux.DaggerGraphState
|
||||
|
|
@ -31,7 +30,7 @@ class CardContextInterceptor(
|
|||
|
||||
override fun canBeAppliedTo(event: AnalyticsEvent): Boolean {
|
||||
return when (event) {
|
||||
is IntroductionProcess.ButtonScanCard, is MainScreen.ButtonScanCard -> false
|
||||
is IntroductionProcess.ButtonScanCard -> false
|
||||
else -> true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,11 +5,11 @@ import com.tangem.common.core.TangemSdkError
|
|||
import com.tangem.common.extensions.guard
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.core.analytics.Analytics
|
||||
import com.tangem.core.analytics.models.event.MainScreenAnalyticsEvent
|
||||
import com.tangem.domain.wallets.builder.UserWalletBuilder
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.tap.*
|
||||
import com.tangem.tap.common.analytics.events.AnalyticsParam
|
||||
import com.tangem.tap.common.analytics.events.MainScreen
|
||||
import com.tangem.tap.common.analytics.events.Onboarding
|
||||
import com.tangem.tap.common.extensions.dispatchNavigationAction
|
||||
import com.tangem.tap.common.extensions.dispatchWithMain
|
||||
|
|
@ -110,7 +110,11 @@ internal class SaveWalletMiddleware {
|
|||
// TODO: Remove after onboarding refactoring
|
||||
Analytics.send(Onboarding.EnableBiometrics(AnalyticsParam.OnOffState.On))
|
||||
} else {
|
||||
Analytics.send(MainScreen.EnableBiometrics(AnalyticsParam.OnOffState.On))
|
||||
Analytics.send(
|
||||
MainScreenAnalyticsEvent.EnableBiometrics(
|
||||
state = com.tangem.core.analytics.models.AnalyticsParam.OnOffState.On,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -148,7 +152,11 @@ internal class SaveWalletMiddleware {
|
|||
// TODO: Remove after onboarding refactoring
|
||||
Analytics.send(Onboarding.EnableBiometrics(AnalyticsParam.OnOffState.Off))
|
||||
} else {
|
||||
Analytics.send(MainScreen.EnableBiometrics(AnalyticsParam.OnOffState.Off))
|
||||
Analytics.send(
|
||||
MainScreenAnalyticsEvent.EnableBiometrics(
|
||||
com.tangem.core.analytics.models.AnalyticsParam.OnOffState.Off,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -76,6 +76,9 @@ sealed class AnalyticsParam {
|
|||
data object MyWallets : ScreensSources("My Wallets")
|
||||
data object Token : ScreensSources("Token")
|
||||
data object Stories : ScreensSources("Stories")
|
||||
data object Buy : ScreensSources("Buy")
|
||||
data object Swap : ScreensSources("Swap")
|
||||
data object Sell : ScreensSources("Sell")
|
||||
}
|
||||
|
||||
sealed class TxSentFrom(val value: String) {
|
||||
|
|
@ -161,6 +164,12 @@ sealed class AnalyticsParam {
|
|||
}
|
||||
}
|
||||
|
||||
enum class Status(val value: String) {
|
||||
Success(value = "Success"),
|
||||
Error(value = "Error"),
|
||||
Pending(value = "Pending"),
|
||||
}
|
||||
|
||||
companion object Key {
|
||||
const val BLOCKCHAIN = "blockchain"
|
||||
const val TOKEN_PARAM = "Token"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,75 @@
|
|||
package com.tangem.core.analytics.models.event
|
||||
|
||||
import com.tangem.core.analytics.models.AnalyticsEvent
|
||||
import com.tangem.core.analytics.models.AnalyticsParam
|
||||
import com.tangem.core.analytics.models.AnalyticsParam.Key.TOKEN_PARAM
|
||||
|
||||
/**
|
||||
* Main screen analytics event
|
||||
*
|
||||
* @param event event name
|
||||
* @param params params
|
||||
*/
|
||||
sealed class MainScreenAnalyticsEvent(
|
||||
event: String,
|
||||
params: Map<String, String> = mapOf(),
|
||||
) : AnalyticsEvent(category = "Main Screen", event = event, params = params) {
|
||||
|
||||
class EnableBiometrics(state: AnalyticsParam.OnOffState) : MainScreenAnalyticsEvent(
|
||||
event = "Enable Biometric",
|
||||
params = mapOf("State" to state.value),
|
||||
)
|
||||
|
||||
// region Action Buttons feature
|
||||
data class ButtonBuy(val status: AnalyticsParam.Status) : MainScreenAnalyticsEvent(
|
||||
event = "Button - Buy",
|
||||
params = mapOf(AnalyticsParam.STATUS to status.value),
|
||||
)
|
||||
|
||||
data class ButtonSwap(val status: AnalyticsParam.Status) : MainScreenAnalyticsEvent(
|
||||
event = "Button - Swap",
|
||||
params = mapOf(AnalyticsParam.STATUS to status.value),
|
||||
)
|
||||
|
||||
data class ButtonSell(val status: AnalyticsParam.Status) : MainScreenAnalyticsEvent(
|
||||
event = "Button - Sell",
|
||||
params = mapOf(AnalyticsParam.STATUS to status.value),
|
||||
)
|
||||
|
||||
data object BuyScreenOpened : MainScreenAnalyticsEvent(event = "Buy Screen Opened")
|
||||
|
||||
data object SwapScreenOpened : MainScreenAnalyticsEvent(event = "Swap Screen Opened")
|
||||
|
||||
data object SellScreenOpened : MainScreenAnalyticsEvent(event = "Sell Screen Opened")
|
||||
|
||||
data class BuyTokenClicked(val currencySymbol: String) : MainScreenAnalyticsEvent(
|
||||
event = "Buy Token Clicked",
|
||||
params = mapOf(TOKEN_PARAM to currencySymbol),
|
||||
)
|
||||
|
||||
data class SellTokenClicked(val currencySymbol: String) : MainScreenAnalyticsEvent(
|
||||
event = "Sell Token Clicked",
|
||||
params = mapOf(TOKEN_PARAM to currencySymbol),
|
||||
)
|
||||
|
||||
data class SwapTokenClicked(val currencySymbol: String) : MainScreenAnalyticsEvent(
|
||||
event = "Swap Token Clicked",
|
||||
params = mapOf(TOKEN_PARAM to currencySymbol),
|
||||
)
|
||||
|
||||
data class ReceiveTokenClicked(val currencySymbol: String) : MainScreenAnalyticsEvent(
|
||||
event = "Receive Token Clicked",
|
||||
params = mapOf(TOKEN_PARAM to currencySymbol),
|
||||
)
|
||||
|
||||
data class RemoveTokenClicked(val currencySymbol: String) : MainScreenAnalyticsEvent(
|
||||
event = "Remove Button Clicked",
|
||||
params = mapOf(TOKEN_PARAM to currencySymbol),
|
||||
)
|
||||
|
||||
data class ButtonClose(val source: AnalyticsParam.ScreensSources) : MainScreenAnalyticsEvent(
|
||||
event = "Button - Close",
|
||||
params = mapOf(AnalyticsParam.SOURCE to source.value),
|
||||
)
|
||||
// endregion
|
||||
}
|
||||
|
|
@ -19,10 +19,11 @@ dependencies {
|
|||
implementation(projects.features.swap.domain.models)
|
||||
|
||||
/** Project - Core */
|
||||
implementation(projects.core.decompose)
|
||||
implementation(projects.core.ui)
|
||||
implementation(projects.core.analytics)
|
||||
implementation(projects.core.configToggles)
|
||||
implementation(projects.core.decompose)
|
||||
implementation(projects.core.navigation)
|
||||
implementation(projects.core.ui)
|
||||
|
||||
/** Project - Common */
|
||||
implementation(projects.common.routing)
|
||||
|
|
|
|||
|
|
@ -3,6 +3,9 @@ package com.tangem.features.onramp.selecttoken
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import arrow.core.getOrElse
|
||||
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.context.AppComponentContext
|
||||
import com.tangem.core.decompose.context.child
|
||||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||
|
|
@ -20,6 +23,8 @@ import dagger.assisted.AssistedFactory
|
|||
import dagger.assisted.AssistedInject
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
// TODO: Add OnrampOperationModel
|
||||
@Suppress("LongParameterList")
|
||||
internal class DefaultOnrampOperationComponent @AssistedInject constructor(
|
||||
@Assisted appComponentContext: AppComponentContext,
|
||||
onrampTokenListComponentFactory: OnrampTokenListComponent.Factory,
|
||||
|
|
@ -27,6 +32,7 @@ internal class DefaultOnrampOperationComponent @AssistedInject constructor(
|
|||
private val reduxStateHolder: ReduxStateHolder,
|
||||
private val getWalletsUseCase: GetWalletsUseCase,
|
||||
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
) : AppComponentContext by appComponentContext, OnrampOperationComponent {
|
||||
|
||||
private val onrampTokenListComponent: OnrampTokenListComponent = onrampTokenListComponentFactory.create(
|
||||
|
|
@ -42,6 +48,15 @@ internal class DefaultOnrampOperationComponent @AssistedInject constructor(
|
|||
),
|
||||
)
|
||||
|
||||
init {
|
||||
analyticsEventHandler.send(
|
||||
event = when (params) {
|
||||
is OnrampOperationComponent.Params.Buy -> MainScreenAnalyticsEvent.BuyScreenOpened
|
||||
is OnrampOperationComponent.Params.Sell -> MainScreenAnalyticsEvent.SellScreenOpened
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
OnrampSelectToken(
|
||||
|
|
@ -49,13 +64,25 @@ internal class DefaultOnrampOperationComponent @AssistedInject constructor(
|
|||
is OnrampOperationComponent.Params.Buy -> R.string.common_buy
|
||||
is OnrampOperationComponent.Params.Sell -> R.string.common_sell
|
||||
},
|
||||
onBackClick = router::pop,
|
||||
onBackClick = ::onBackClick,
|
||||
onrampTokenListComponent = onrampTokenListComponent,
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
|
||||
private fun onTokenClick(status: CryptoCurrencyStatus) {
|
||||
val currencySymbol = status.currency.symbol
|
||||
analyticsEventHandler.send(
|
||||
event = when (params) {
|
||||
is OnrampOperationComponent.Params.Buy -> {
|
||||
MainScreenAnalyticsEvent.BuyTokenClicked(currencySymbol = currencySymbol)
|
||||
}
|
||||
is OnrampOperationComponent.Params.Sell -> {
|
||||
MainScreenAnalyticsEvent.SellTokenClicked(currencySymbol = currencySymbol)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
componentScope.launch {
|
||||
val appCurrencyCode = getSelectedAppCurrencyUseCase.invokeSync().getOrElse { AppCurrency.Default }.code
|
||||
|
||||
|
|
@ -76,6 +103,19 @@ internal class DefaultOnrampOperationComponent @AssistedInject constructor(
|
|||
)
|
||||
}
|
||||
|
||||
private fun onBackClick() {
|
||||
analyticsEventHandler.send(
|
||||
event = MainScreenAnalyticsEvent.ButtonClose(
|
||||
source = when (params) {
|
||||
is OnrampOperationComponent.Params.Buy -> AnalyticsParam.ScreensSources.Buy
|
||||
is OnrampOperationComponent.Params.Sell -> AnalyticsParam.ScreensSources.Sell
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
router.pop()
|
||||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory : OnrampOperationComponent.Factory {
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.analytics.models.event.MainScreenAnalyticsEvent
|
||||
import com.tangem.core.decompose.context.AppComponentContext
|
||||
import com.tangem.core.decompose.context.child
|
||||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
|
|
@ -21,6 +23,7 @@ import dagger.assisted.AssistedInject
|
|||
internal class DefaultSwapSelectTokensComponent @AssistedInject constructor(
|
||||
tokenListComponentFactory: OnrampTokenListComponent.Factory,
|
||||
availableSwapPairsComponentFactory: AvailableSwapPairsComponent.Factory,
|
||||
analyticsEventHandler: AnalyticsEventHandler,
|
||||
@Assisted private val appComponentContext: AppComponentContext,
|
||||
@Assisted private val params: SwapSelectTokensComponent.Params,
|
||||
) : AppComponentContext by appComponentContext, SwapSelectTokensComponent {
|
||||
|
|
@ -46,6 +49,10 @@ internal class DefaultSwapSelectTokensComponent @AssistedInject constructor(
|
|||
),
|
||||
)
|
||||
|
||||
init {
|
||||
analyticsEventHandler.send(event = MainScreenAnalyticsEvent.SwapScreenOpened)
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun Content(modifier: Modifier) {
|
||||
val state = model.state.collectAsStateWithLifecycle()
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package com.tangem.features.onramp.swap.entity
|
||||
|
||||
import com.tangem.core.decompose.navigation.Router
|
||||
import com.tangem.features.onramp.swap.entity.utils.createEmptyExchangeFrom
|
||||
import com.tangem.features.onramp.swap.entity.utils.createEmptyExchangeTo
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
|
@ -12,19 +11,15 @@ import javax.inject.Inject
|
|||
/**
|
||||
* [SwapSelectTokensUM] controller
|
||||
*
|
||||
* @property router router
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal class SwapSelectTokensController @Inject constructor(
|
||||
private val router: Router,
|
||||
) {
|
||||
internal class SwapSelectTokensController @Inject constructor() {
|
||||
|
||||
val state: StateFlow<SwapSelectTokensUM> get() = _state
|
||||
|
||||
private val _state: MutableStateFlow<SwapSelectTokensUM> = MutableStateFlow(
|
||||
value = SwapSelectTokensUM(
|
||||
onBackClick = router::pop,
|
||||
onBackClick = {},
|
||||
exchangeFrom = createEmptyExchangeFrom(),
|
||||
exchangeTo = createEmptyExchangeTo(),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
package com.tangem.features.onramp.swap.model
|
||||
|
||||
import com.tangem.common.routing.AppRoute
|
||||
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.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.core.decompose.navigation.Router
|
||||
|
|
@ -27,6 +30,7 @@ internal class SwapSelectTokensModel @Inject constructor(
|
|||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val controller: SwapSelectTokensController,
|
||||
private val router: Router,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
) : Model() {
|
||||
|
||||
val state: StateFlow<SwapSelectTokensUM> = controller.state
|
||||
|
|
@ -38,6 +42,12 @@ internal class SwapSelectTokensModel @Inject constructor(
|
|||
|
||||
private val params = paramsContainer.require<SwapSelectTokensComponent.Params>()
|
||||
|
||||
init {
|
||||
controller.update {
|
||||
it.copy(onBackClick = ::onBackClick)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Select "from" token
|
||||
*
|
||||
|
|
@ -45,12 +55,16 @@ internal class SwapSelectTokensModel @Inject constructor(
|
|||
* @param status crypto currency status
|
||||
*/
|
||||
fun selectFromToken(selectedTokenItemState: TokenItemState, status: CryptoCurrencyStatus) {
|
||||
analyticsEventHandler.send(
|
||||
event = MainScreenAnalyticsEvent.SwapTokenClicked(currencySymbol = status.currency.symbol),
|
||||
)
|
||||
|
||||
_fromCurrencyStatus.value = status
|
||||
|
||||
controller.update(
|
||||
transformer = SelectFromTokenTransformer(
|
||||
selectedTokenItemState = selectedTokenItemState,
|
||||
onRemoveClick = ::removeSelectedFromToken,
|
||||
onRemoveClick = ::onRemoveFromTokenClick,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -62,6 +76,10 @@ internal class SwapSelectTokensModel @Inject constructor(
|
|||
* @param status crypto currency status
|
||||
*/
|
||||
fun selectToToken(selectedTokenItemState: TokenItemState, status: CryptoCurrencyStatus) {
|
||||
analyticsEventHandler.send(
|
||||
event = MainScreenAnalyticsEvent.ReceiveTokenClicked(currencySymbol = status.currency.symbol),
|
||||
)
|
||||
|
||||
modelScope.launch {
|
||||
_toCurrencyStatus.value = status
|
||||
|
||||
|
|
@ -88,6 +106,26 @@ internal class SwapSelectTokensModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun onBackClick() {
|
||||
analyticsEventHandler.send(
|
||||
event = MainScreenAnalyticsEvent.ButtonClose(source = AnalyticsParam.ScreensSources.Swap),
|
||||
)
|
||||
|
||||
router.pop()
|
||||
}
|
||||
|
||||
private fun onRemoveFromTokenClick() {
|
||||
val currencySymbol = requireNotNull(_fromCurrencyStatus.value?.currency?.symbol) {
|
||||
"Token was not selected"
|
||||
}
|
||||
|
||||
analyticsEventHandler.send(
|
||||
event = MainScreenAnalyticsEvent.RemoveTokenClicked(currencySymbol = currencySymbol),
|
||||
)
|
||||
|
||||
removeSelectedFromToken()
|
||||
}
|
||||
|
||||
private fun removeSelectedFromToken() {
|
||||
_fromCurrencyStatus.value = null
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ import com.tangem.common.routing.AppRoute
|
|||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.common.ui.tokens.getUnavailabilityReasonText
|
||||
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.ui.clipboard.ClipboardManager
|
||||
import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent
|
||||
import com.tangem.core.ui.components.bottomsheets.chooseaddress.ChooseAddressBottomSheetConfig
|
||||
|
|
@ -439,16 +441,34 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
|
|||
}
|
||||
|
||||
override fun onMultiWalletSellClick(userWalletId: UserWalletId) {
|
||||
analyticsEventHandler.send(
|
||||
event = MainScreenAnalyticsEvent.ButtonSell(
|
||||
status = AnalyticsParam.Status.Success, // TODO [REDACTED_JIRA]
|
||||
),
|
||||
)
|
||||
|
||||
// TODO [REDACTED_JIRA]
|
||||
appRouter.push(route = AppRoute.SellCrypto(userWalletId = userWalletId))
|
||||
}
|
||||
|
||||
override fun onMultiWalletSwapClick(userWalletId: UserWalletId) {
|
||||
analyticsEventHandler.send(
|
||||
event = MainScreenAnalyticsEvent.ButtonSwap(
|
||||
status = AnalyticsParam.Status.Success, // TODO [REDACTED_JIRA]
|
||||
),
|
||||
)
|
||||
|
||||
// TODO [REDACTED_JIRA]
|
||||
appRouter.push(route = AppRoute.SwapCrypto(userWalletId = userWalletId))
|
||||
}
|
||||
|
||||
override fun onMultiWalletBuyClick(userWalletId: UserWalletId) {
|
||||
analyticsEventHandler.send(
|
||||
event = MainScreenAnalyticsEvent.ButtonBuy(
|
||||
status = AnalyticsParam.Status.Success, // TODO [REDACTED_JIRA]
|
||||
),
|
||||
)
|
||||
|
||||
// TODO [REDACTED_JIRA]
|
||||
appRouter.push(route = AppRoute.BuyCrypto(userWalletId = userWalletId))
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue