Updated on 2026-08-14

This commit is contained in:
Tangem 2023-01-20 19:56:32 +03:00
commit b10c16944f
34 changed files with 151 additions and 94 deletions

View file

@ -22,7 +22,6 @@ import com.tangem.tap.common.analytics.AnalyticsFactory
import com.tangem.tap.common.analytics.api.AnalyticsHandlerBuilder
import com.tangem.tap.common.analytics.filters.BasicSignInFilter
import com.tangem.tap.common.analytics.filters.BasicTopUpFilter
import com.tangem.tap.common.analytics.filters.ShopPurchasedEventFilter
import com.tangem.tap.common.analytics.handlers.amplitude.AmplitudeAnalyticsHandler
import com.tangem.tap.common.analytics.handlers.appsFlyer.AppsFlyerAnalyticsHandler
import com.tangem.tap.common.analytics.handlers.firebase.FirebaseAnalyticsHandler
@ -171,6 +170,17 @@ class TapApplication : Application(), ImageLoaderFactory {
)
}
private fun initMoshiConverter() {
fun appAdapters(): List<Any> = listOf(
BigDecimalAdapter(),
CardBalanceStateAdapter(),
)
MoshiConverter.reInitInstance(
adapters = appAdapters() + MoshiJsonConverter.getTangemSdkAdapters(),
typedAdapters = MoshiJsonConverter.getTangemSdkTypedAdapters(),
)
}
override fun newImageLoader(): ImageLoader {
return createCoilImageLoader(
context = this,
@ -198,7 +208,6 @@ class TapApplication : Application(), ImageLoaderFactory {
factory.addHandlerBuilder(AppsFlyerAnalyticsHandler.Builder())
factory.addHandlerBuilder(FirebaseAnalyticsHandler.Builder())
factory.addFilter(ShopPurchasedEventFilter())
factory.addFilter(BasicSignInFilter())
factory.addFilter(BasicTopUpFilter(preferencesStorage.toppedUpWalletStorage))

View file

@ -42,7 +42,7 @@ class IntentHandler {
intent.action = null
store.dispatch(NavigationAction.NavigateTo(AppScreen.Home))
store.dispatch(NavigationAction.PopBackTo(AppScreen.Home))
store.dispatch(HomeAction.ReadCard)
store.dispatch(HomeAction.ReadCard())
}
}
}

View file

@ -72,7 +72,7 @@ private fun statesIsReadyToCreateEvent(scanResponse: ScanResponse, state: Wallet
if (it.currencyData.amount == null) 0 else 1
}.reduce { acc, i -> acc + i }
if (balancesCount != state.walletsStores.size) return false
if (balancesCount != state.walletsDataFromStores.size) return false
return true
}

View file

@ -8,19 +8,19 @@ import com.tangem.tap.common.shop.data.ProductType
/**
[REDACTED_AUTHOR]
*/
class ShopOrderToEventConverter : Converter<Pair<Storefront.Order, ProductType>, Shop.Purchased> {
class ShopOrderToEventConverter : Converter<Pair<Storefront.Checkout, ProductType>, Shop.Purchased> {
override fun convert(value: Pair<Storefront.Order, ProductType>): Shop.Purchased {
val order = value.first
override fun convert(value: Pair<Storefront.Checkout, ProductType>): Shop.Purchased {
val checkout = value.first
val productType = value.second
val sku = order.lineItems.edges.firstOrNull()?.node?.variant?.sku ?: productType.sku
val sku = checkout.lineItems?.edges?.firstOrNull()?.node?.variant?.sku ?: productType.sku
val count = when (productType) {
ProductType.WALLET_2_CARDS -> "2"
ProductType.WALLET_3_CARDS -> "3"
}
val amount = "${order.totalPriceV2.amount} ${order.totalPriceV2.currencyCode.name}"
val code = (order.discountApplications.edges.firstOrNull()?.node as? Storefront.DiscountCodeApplication)?.code
val amount = "${checkout.totalPriceV2.amount} ${checkout.totalPriceV2.currencyCode.name}"
val code = (checkout.discountApplications.edges.firstOrNull()?.node as? Storefront.DiscountCodeApplication)?.code
return Shop.Purchased(sku, count, amount, code)
}

View file

@ -75,6 +75,8 @@ sealed class Onboarding(
class ClaimScreenOpened : Onboarding("Onboarding", "Claim screen opened")
class ButtonClaim : Onboarding("Onboarding", "Button - Claim")
class ClaimWasSuccessfully : Onboarding("Onboarding", "Claim was successfully")
class ButtonChat: Onboarding("Onboarding", "Button - Chat")
class EnableBiometrics(state: AnalyticsParam.OnOffState) : Onboarding(
category = "Onboarding / Biometric",
event = "Enable Biometric",

View file

@ -21,6 +21,7 @@ sealed class Settings(
class ButtonCardSettings : Settings(event = "Button - Card Settings")
class ButtonAppSettings : Settings(event = "Button - App Settings")
class ButtonCreateBackup : Settings(event = "Button - Create Backup")
class ButtonWalletConnect : Settings(event = "Button - Wallet Connect")
class ButtonSocialNetwork(network: SocialNetwork) : Settings(
event = "Button - Social Network",

View file

@ -11,7 +11,7 @@ sealed class Shop(
params: Map<String, String> = mapOf(),
) : AnalyticsEvent("Shop", event, params) {
class ScreenOpened : IntroductionProcess("Shop Screen Opened")
class ScreenOpened : Shop("Shop Screen Opened")
class Purchased(sku: String, count: String, amount: String, couponCode: String?) : Shop(
event = "Purchased",
@ -23,8 +23,8 @@ sealed class Shop(
).filterNotNull(),
)
class Redirected(partnerName: String) : Shop(
class Redirected(partnerName: String?) : Shop(
event = "Redirected",
params = mapOf("Partner" to partnerName),
params = partnerName?.let { mapOf("Partner" to partnerName) } ?: mapOf(),
)
}

View file

@ -11,6 +11,7 @@ sealed class WalletConnect(
error: Throwable? = null,
) : AnalyticsEvent("Wallet Connect", event, params, error) {
class ScreenOpened : Settings(event = "WC Screen Opened")
class NewSessionEstablished : WalletConnect("New Session Established")
class SessionDisconnected : WalletConnect("Session Disconnected")
class RequestSigned : WalletConnect("Request Signed")

View file

@ -1,25 +0,0 @@
package com.tangem.tap.common.analytics.filters
import com.tangem.core.analytics.api.AnalyticsEventFilter
import com.tangem.core.analytics.api.AnalyticsHandler
import com.tangem.core.analytics.AnalyticsEvent
import com.tangem.tap.common.analytics.events.Shop
import com.tangem.tap.common.analytics.handlers.appsFlyer.AppsFlyerAnalyticsHandler
import com.tangem.tap.common.analytics.handlers.firebase.FirebaseAnalyticsHandler
/**
[REDACTED_AUTHOR]
*/
class ShopPurchasedEventFilter : AnalyticsEventFilter {
override fun canBeAppliedTo(event: AnalyticsEvent): Boolean = event is Shop.Purchased
override fun canBeSent(event: AnalyticsEvent): Boolean = true
override fun canBeConsumedByHandler(handler: AnalyticsHandler, event: AnalyticsEvent): Boolean {
return when (handler) {
is AppsFlyerAnalyticsHandler, is FirebaseAnalyticsHandler -> true
else -> false
}
}
}

View file

@ -1,7 +1,11 @@
package com.tangem.tap.common.analytics.handlers.appsFlyer
import com.appsflyer.AFInAppEventType
import com.tangem.core.analytics.api.AnalyticsHandler
import com.tangem.tap.common.analytics.api.AnalyticsHandler
import com.tangem.tap.common.analytics.api.AnalyticsHandlerBuilder
import com.tangem.tap.common.analytics.events.AnalyticsEvent
import com.tangem.tap.common.analytics.events.Shop
class AppsFlyerAnalyticsHandler(
private val client: AppsFlyerAnalyticsClient,
@ -13,6 +17,14 @@ class AppsFlyerAnalyticsHandler(
client.logEvent(event, params)
}
override fun send(event: AnalyticsEvent) {
if (event is Shop.Purchased) {
send(AFInAppEventType.PURCHASE, event.params)
} else {
super.send(event)
}
}
companion object {
const val ID = "AppsFlyer"
}

View file

@ -1,10 +1,12 @@
package com.tangem.tap.common.analytics.handlers.firebase
import com.google.firebase.analytics.FirebaseAnalytics
import com.tangem.core.analytics.AnalyticsEvent
import com.tangem.core.analytics.api.AnalyticsHandler
import com.tangem.core.analytics.api.ErrorEventHandler
import com.tangem.tap.common.analytics.api.AnalyticsHandlerBuilder
import com.tangem.tap.common.analytics.converters.AnalyticsErrorConverter
import com.tangem.tap.common.analytics.events.Shop
class FirebaseAnalyticsHandler(
private val client: FirebaseAnalyticsClient,
@ -18,17 +20,23 @@ class FirebaseAnalyticsHandler(
override fun send(event: AnalyticsEvent) {
val error = event.error
if (error == null) {
super.send(event)
} else {
val errorConverter = AnalyticsErrorConverter()
if (!errorConverter.canBeHandled(error)) return
when {
error != null -> {
val errorConverter = AnalyticsErrorConverter()
if (!errorConverter.canBeHandled(error)) return
val errorParams = errorConverter.convert(error).toMutableMap()
errorParams["Category"] = event.category
errorParams["Event"] = event.event
errorParams.putAll(event.params)
send(error, errorParams)
val errorParams = errorConverter.convert(error).toMutableMap()
errorParams["Category"] = event.category
errorParams["Event"] = event.event
errorParams.putAll(event.params)
send(error, errorParams)
}
event is Shop.Purchased -> {
send(FirebaseAnalytics.Event.PURCHASE, event.params)
}
else -> {
super.send(event)
}
}
}

View file

@ -3,6 +3,7 @@ package com.tangem.tap.common.feedback
import android.content.Context
import android.os.Build
import com.tangem.domain.common.TapWorkarounds
import com.tangem.tap.common.analytics.Analytics
import com.tangem.tap.common.extensions.sendEmail
import com.tangem.tap.common.log.TangemLogCollector
import com.tangem.tap.common.zendesk.ZendeskConfig
@ -108,6 +109,7 @@ class FeedbackManager(
}
private fun showMessagingActivity(context: Context) {
Analytics.send(com.tangem.tap.common.analytics.events.Chat.ScreenOpened())
MessagingActivity.builder()
.withMultilineResponseOptionsEnabled(false)
.withBotLabelStringRes(R.string.chat_bot_name)

View file

@ -200,8 +200,8 @@ class TangemShopService(application: Application, shopifyShop: ShopifyShop) {
suspend fun waitForCheckout(productType: ProductType) {
val result = shopifyService.checkout(true, checkouts[productType]!!.id)
result.onSuccess { checkout ->
checkout.order?.let {
val event = ShopOrderToEventConverter().convert(it to productType)
if (checkout.order != null && checkout.lineItems != null) {
val event = ShopOrderToEventConverter().convert(checkout to productType)
Analytics.send(event)
}
}

View file

@ -134,8 +134,8 @@ class DetailsMiddleware {
}
}
.doOnFailure { error ->
(error as? TangemSdkError)?.let { sdkError ->
Analytics.send(Settings.CardSettings.FactoryResetFinished(sdkError))
if (error is TangemSdkError && error !is TangemSdkError.UserCancelled) {
Analytics.send(Settings.CardSettings.FactoryResetFinished(error))
}
}
}
@ -172,7 +172,8 @@ class DetailsMiddleware {
store.dispatch(DetailsAction.ManageSecurity.SaveChanges.Success)
}
is CompletionResult.Failure -> {
(result.error as? TangemSdkError)?.let { error ->
val error = result.error
if (error is TangemSdkError && error !is TangemSdkError.UserCancelled) {
Analytics.send(Settings.CardSettings.SecurityModeChanged(paramValue, error))
}
store.dispatch(DetailsAction.ManageSecurity.SaveChanges.Failure)

View file

@ -44,7 +44,7 @@ sealed class SocialNetwork(val id: String, val iconRes: Int) {
object Facebook : SocialNetwork("Facebook", R.drawable.ic_facebook)
object Instagram : SocialNetwork("Instagram", R.drawable.ic_instagram)
object GitHub : SocialNetwork("GitHub", R.drawable.ic_github)
object Youtube : SocialNetwork("Youtube", R.drawable.ic_youtube)
object YouTube : SocialNetwork("YouTube", R.drawable.ic_youtube)
object LinkedIn : SocialNetwork("LinkedIn", R.drawable.ic_linkedin)
}
@ -55,7 +55,7 @@ object TangemSocialAccounts {
SocialNetworkLink(SocialNetwork.Facebook, "https://m.facebook.com/TangemCards/"),
SocialNetworkLink(SocialNetwork.Instagram, "https://instagram.com/tangemcards"),
SocialNetworkLink(SocialNetwork.GitHub, "https://github.com/tangem"),
SocialNetworkLink(SocialNetwork.Youtube, "https://youtube.com/channel/UCFGwLS7yggzVkP6ozte0m1w"),
SocialNetworkLink(SocialNetwork.YouTube, "https://youtube.com/channel/UCFGwLS7yggzVkP6ozte0m1w"),
SocialNetworkLink(SocialNetwork.LinkedIn, "https://www.linkedin.com/company/tangem"),
)
val accountsRu: List<SocialNetworkLink> = listOf(
@ -64,7 +64,7 @@ object TangemSocialAccounts {
SocialNetworkLink(SocialNetwork.Facebook, "https://m.facebook.com/TangemCards/"),
SocialNetworkLink(SocialNetwork.Instagram, "https://instagram.com/tangemcards"),
SocialNetworkLink(SocialNetwork.GitHub, "https://github.com/tangem"),
SocialNetworkLink(SocialNetwork.Youtube, "https://youtube.com/channel/UCFGwLS7yggzVkP6ozte0m1w"),
SocialNetworkLink(SocialNetwork.YouTube, "https://youtube.com/channel/UCFGwLS7yggzVkP6ozte0m1w"),
SocialNetworkLink(SocialNetwork.LinkedIn, "https://www.linkedin.com/company/tangem"),
)
}

View file

@ -61,6 +61,7 @@ class DetailsViewModel(private val store: Store<AppState>) {
private fun handleClickingSettingsItem(item: SettingsElement) {
when (item) {
SettingsElement.WalletConnect -> {
Analytics.send(Settings.ButtonWalletConnect())
store.dispatch(NavigationAction.NavigateTo(AppScreen.WalletConnectSessions))
}
SettingsElement.Chat -> {

View file

@ -10,6 +10,8 @@ import androidx.compose.ui.platform.ComposeView
import androidx.fragment.app.Fragment
import androidx.transition.TransitionInflater
import com.tangem.core.ui.res.TangemTheme
import com.tangem.tap.common.analytics.Analytics
import com.tangem.tap.common.analytics.events.WalletConnect
import com.tangem.tap.common.redux.navigation.NavigationAction
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectAction
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectState
@ -23,6 +25,7 @@ class WalletConnectFragment : Fragment(), StoreSubscriber<WalletConnectState> {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Analytics.send(WalletConnect.ScreenOpened())
val inflater = TransitionInflater.from(requireContext())
enterTransition = inflater.inflateTransition(android.R.transition.fade)
exitTransition = inflater.inflateTransition(android.R.transition.fade)

View file

@ -82,7 +82,7 @@ class HomeFragment : Fragment(), StoreSubscriber<HomeState> {
homeState,
onScanButtonClick = {
Analytics.send(IntroductionProcess.ButtonScanCard())
store.dispatch(HomeAction.ReadCard)
store.dispatch(HomeAction.ReadCard())
},
onShopButtonClick = {
Analytics.send(IntroductionProcess.ButtonBuyCards())

View file

@ -1,6 +1,7 @@
package com.tangem.tap.features.home.redux
import com.tangem.tap.common.entities.IndeterminateProgressButton
import com.tangem.tap.common.redux.navigation.AppScreen
import org.rekotlin.Action
sealed class HomeAction : Action {
@ -9,7 +10,10 @@ sealed class HomeAction : Action {
data class ShouldScanCardOnResume(val shouldScanCard: Boolean) : HomeAction()
// from ui
object ReadCard : HomeAction()
data class ReadCard(
val fromScreen: AppScreen = AppScreen.Home,
) : HomeAction()
data class ScanInProgress(val scanInProgress: Boolean) : HomeAction()
data class GoToShop(val userCountryCode: String?) : HomeAction()

View file

@ -3,6 +3,11 @@ package com.tangem.tap.features.home.redux
import com.tangem.common.doOnFailure
import com.tangem.common.doOnResult
import com.tangem.common.doOnSuccess
import com.tangem.core.analytics.Analytics
import com.tangem.tap.common.analytics.events.IntroductionProcess
import com.tangem.tap.common.analytics.events.MainScreen
import com.tangem.tap.common.analytics.events.Shop
import com.tangem.tap.common.analytics.paramsInterceptor.BatchIdParamsInterceptor
import com.tangem.tap.common.entities.IndeterminateProgressButton
import com.tangem.tap.common.extensions.dispatchOnMain
import com.tangem.tap.common.extensions.dispatchOpenUrl
@ -57,11 +62,12 @@ private fun handleHomeAction(action: Action) {
is HomeAction.ShouldScanCardOnResume -> {
if (action.shouldScanCard) {
store.dispatch(HomeAction.ShouldScanCardOnResume(false))
postUiDelayBg(700) { store.dispatch(HomeAction.ReadCard) }
postUiDelayBg(700) { store.dispatch(HomeAction.ReadCard(AppScreen.Wallet)) }
}
}
is HomeAction.ReadCard -> readCard()
is HomeAction.ReadCard -> readCard(action.fromScreen)
is HomeAction.GoToShop -> {
Analytics.send(Shop.ScreenOpened())
when (action.userCountryCode) {
RUSSIA_COUNTRY_CODE, BELARUS_COUNTRY_CODE -> store.dispatchOpenUrl(BUY_WALLET_URL)
else -> store.dispatch(NavigationAction.NavigateTo(AppScreen.Shop))
@ -70,7 +76,7 @@ private fun handleHomeAction(action: Action) {
}
}
private fun readCard() = scope.launch {
private fun readCard(fromScreen: AppScreen) = scope.launch {
delay(timeMillis = 200)
tangemSdkManager.setAccessCodeRequestPolicy(
useBiometricsForAccessCode = preferencesStorage.shouldSaveAccessCodes,
@ -91,6 +97,10 @@ private fun readCard() = scope.launch {
changeButtonState(ButtonState.ENABLED)
},
onSuccess = { scanResponse ->
when (fromScreen) {
AppScreen.Wallet -> Analytics.send(MainScreen.CardWasScanned())
else -> Analytics.send(IntroductionProcess.CardWasScanned())
}
scope.launch {
if (preferencesStorage.shouldSaveUserWallets) {
val userWallet = UserWalletBuilder(scanResponse).build() ?: return@launch

View file

@ -4,6 +4,8 @@ import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import androidx.core.view.MenuProvider
import com.tangem.tap.common.analytics.Analytics
import com.tangem.tap.common.analytics.events.Onboarding
import com.tangem.tap.common.feedback.SupportInfo
import com.tangem.tap.common.redux.global.GlobalAction
import com.tangem.tap.store
@ -19,6 +21,7 @@ class OnboardingMenuProvider : MenuProvider {
override fun onMenuItemSelected(menuItem: MenuItem): Boolean = when (menuItem.itemId) {
R.id.menu_item_chat_support -> {
Analytics.send(Onboarding.ButtonChat())
store.dispatch(GlobalAction.OpenChat(SupportInfo()))
true
}

View file

@ -175,16 +175,16 @@ private fun handleNoteAction(appState: () -> AppState?, action: Action, dispatch
val topUpUrl = walletManager.getTopUpUrl() ?: return
val blockchain = walletManager.wallet.blockchain
if (globalState.userCountryCode == RUSSIA_COUNTRY_CODE) {
val dialogData = WalletDialog.RussianCardholdersWarningDialog.Data(topUpUrl, blockchain)
store.dispatchOnMain(WalletAction.DialogAction.RussianCardholdersWarningDialog(dialogData))
return
}
val currencyType = AnalyticsParam.CurrencyType.Blockchain(blockchain)
Analytics.send(Onboarding.Topup.ButtonBuyCrypto(currencyType))
store.dispatchOpenUrl(topUpUrl)
if (globalState.userCountryCode == RUSSIA_COUNTRY_CODE) {
val dialogData = WalletDialog.RussianCardholdersWarningDialog.Data(topUpUrl)
store.dispatchOnMain(WalletAction.DialogAction.RussianCardholdersWarningDialog(dialogData))
} else {
store.dispatchOpenUrl(topUpUrl)
}
}
OnboardingNoteAction.Done -> {
store.dispatch(GlobalAction.Onboarding.Stop)

View file

@ -1,6 +1,5 @@
package com.tangem.tap.features.onboarding.products.twins.redux
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchain.extensions.Result
import com.tangem.common.CompletionResult
import com.tangem.common.extensions.guard
@ -10,6 +9,7 @@ import com.tangem.tap.DELAY_SDK_DIALOG_CLOSE
import com.tangem.core.analytics.Analytics
import com.tangem.tap.common.analytics.events.AnalyticsParam
import com.tangem.tap.common.analytics.events.Onboarding
import com.tangem.tap.common.extensions.dispatchDebugErrorNotification
import com.tangem.tap.common.extensions.dispatchDialogShow
import com.tangem.tap.common.extensions.dispatchErrorNotification
import com.tangem.tap.common.extensions.dispatchOnMain
@ -27,8 +27,11 @@ import com.tangem.tap.domain.extensions.makePrimaryWalletManager
import com.tangem.tap.domain.model.builders.UserWalletIdBuilder
import com.tangem.tap.domain.twins.TwinCardsManager
import com.tangem.tap.features.onboarding.OnboardingHelper
import com.tangem.tap.features.home.RUSSIA_COUNTRY_CODE
import com.tangem.tap.features.wallet.models.Currency
import com.tangem.tap.features.wallet.redux.ProgressState
import com.tangem.tap.features.wallet.redux.WalletAction
import com.tangem.tap.features.wallet.redux.models.WalletDialog
import com.tangem.tap.preferencesStorage
import com.tangem.tap.scope
import com.tangem.tap.store
@ -104,10 +107,7 @@ private fun handle(action: Action, dispatch: DispatchFunction) {
CreateTwinWalletMode.CreateWallet -> {
if (preferencesStorage.wasTwinsOnboardingShown()) {
val step = when {
!scanResponse.twinsIsTwinned() -> {
Analytics.send(Onboarding.CreateWallet.ScreenOpened())
TwinCardsStep.CreateFirstWallet
}
!scanResponse.twinsIsTwinned() -> TwinCardsStep.CreateFirstWallet
twinCardsState.walletBalance.balanceIsToppedUp() -> TwinCardsStep.Done
else -> TwinCardsStep.TopUpWallet
}
@ -148,18 +148,23 @@ private fun handle(action: Action, dispatch: DispatchFunction) {
Analytics.send(Onboarding.Twins.ScreenOpened())
preferencesStorage.saveTwinsOnboardingShown()
}
TwinCardsStep.TopUpWallet -> store.dispatch(TwinCardsAction.Balance.Update)
TwinCardsStep.Done -> {
finishCardActivation()
postUi(500) { store.dispatch(TwinCardsAction.Confetti.Show) }
}
TwinCardsStep.CreateFirstWallet -> {
Analytics.send(Onboarding.CreateWallet.ScreenOpened())
Analytics.send(Onboarding.Twins.SetupStarted())
scope.launch {
userWalletsListManager.delete(
listOfNotNull(UserWalletIdBuilder.scanResponse(getScanResponse()).build()),
)
}
}
TwinCardsStep.TopUpWallet -> {
Analytics.send(Onboarding.Topup.ScreenOpened())
store.dispatch(TwinCardsAction.Balance.Update)
}
TwinCardsStep.Done -> {
finishCardActivation()
postUi(500) { store.dispatch(TwinCardsAction.Confetti.Show) }
}
TwinCardsStep.None,
TwinCardsStep.Warning,
TwinCardsStep.CreateSecondWallet,
@ -168,7 +173,6 @@ private fun handle(action: Action, dispatch: DispatchFunction) {
}
}
is TwinCardsAction.Wallet.LaunchFirstStep -> {
Analytics.send(Onboarding.Twins.SetupStarted())
val manager = TwinCardsManager(
card = getScanResponse().card,
assetReader = action.reader,
@ -289,12 +293,23 @@ private fun handle(action: Action, dispatch: DispatchFunction) {
store.dispatchDialogShow(appDialog)
}
is TwinCardsAction.TopUp -> {
val topUpUrl = twinCardsState.walletManager?.getTopUpUrl() ?: return
val walletManager = twinCardsState.walletManager.guard {
store.dispatchDebugErrorNotification("NPE: WalletManager")
return
}
val currencyType = AnalyticsParam.CurrencyType.Blockchain(Blockchain.Bitcoin)
val topUpUrl = walletManager.getTopUpUrl() ?: return
val blockchain = walletManager.wallet.blockchain
val currencyType = AnalyticsParam.CurrencyType.Blockchain(blockchain)
Analytics.send(Onboarding.Topup.ButtonBuyCrypto(currencyType))
store.dispatchOpenUrl(topUpUrl)
if (globalState.userCountryCode == RUSSIA_COUNTRY_CODE) {
val dialogData = WalletDialog.RussianCardholdersWarningDialog.Data(topUpUrl)
store.dispatchOnMain(WalletAction.DialogAction.RussianCardholdersWarningDialog(dialogData))
} else {
store.dispatchOpenUrl(topUpUrl)
}
}
TwinCardsAction.Done -> {
val scanResponse = getScanResponse()

View file

@ -156,7 +156,7 @@ private fun handleWalletAction(action: Action, state: () -> AppState?, dispatch:
if (scanResponse == null) {
store.dispatch(NavigationAction.PopBackTo())
store.dispatch(HomeAction.ReadCard)
store.dispatch(HomeAction.ReadCard())
} else {
val backupState = store.state.onboardingWalletState.backupState
val updatedScanResponse = updateScanResponseAfterBackup(scanResponse, backupState)

View file

@ -1,5 +1,7 @@
package com.tangem.tap.features.shop.redux
import com.tangem.tap.common.analytics.Analytics
import com.tangem.tap.common.analytics.events.Shop
import com.tangem.tap.common.extensions.dispatchOnMain
import com.tangem.tap.common.extensions.dispatchOpenUrl
import com.tangem.tap.common.redux.AppState
@ -113,6 +115,7 @@ private fun handle(action: Action) {
}
}
ShopAction.StartWebCheckout -> {
Analytics.send(Shop.Redirected(null))
store.dispatchOpenUrl(shopService.getCheckoutUrl(shopState.selectedProduct))
store.dispatch(ShopAction.FinishSuccessfulOrder)
}

View file

@ -12,8 +12,6 @@ import androidx.activity.OnBackPressedCallback
import by.kirich1409.viewbindingdelegate.viewBinding
import com.tangem.tap.common.GlobalLayoutStateHandler
import com.tangem.tap.common.KeyboardObserver
import com.tangem.core.analytics.Analytics
import com.tangem.tap.common.analytics.events.Shop
import com.tangem.tap.common.extensions.show
import com.tangem.tap.common.redux.navigation.NavigationAction
import com.tangem.tap.common.shop.data.ProductType
@ -43,7 +41,6 @@ class ShopFragment : BaseStoreFragment(R.layout.fragment_shop), StoreSubscriber<
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Analytics.send(Shop.ScreenOpened())
activity?.onBackPressedDispatcher?.addCallback(this, object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {

View file

@ -49,7 +49,6 @@ class AddTokensFragment : BaseFragment(R.layout.fragment_add_tokens), StoreSubsc
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setHasOptionsMenu(true)
Analytics.send(ManageTokens.ScreenOpened())
addBackPressHandler(this)
}

View file

@ -39,21 +39,22 @@ class TradeCryptoMiddleware {
state: () -> AppState?,
action: WalletAction.TradeCryptoAction.Buy,
) {
val selectedWalletData = store.state.walletState.selectedWalletData ?: return
val currency = selectedWalletData.currency
Analytics.send(Token.ButtonBuy(AnalyticsParam.CurrencyType.Currency(currency)))
if (action.checkUserLocation && state()?.globalState?.userCountryCode == RUSSIA_COUNTRY_CODE) {
store.dispatchOnMain(WalletAction.DialogAction.RussianCardholdersWarningDialog())
return
}
val selectedWalletData = store.state.walletState.selectedWalletData ?: return
val card = store.state.globalState.scanResponse?.card ?: return
val addresses = selectedWalletData.walletAddresses?.list.orEmpty()
if (addresses.isEmpty()) return
val exchangeManager = store.state.globalState.exchangeManager
val appCurrency = store.state.globalState.appCurrency
val currency = selectedWalletData.currency
Analytics.send(Token.ButtonBuy(AnalyticsParam.CurrencyType.Currency(currency)))
if (currency is Currency.Token && currency.blockchain.isTestnet()) {
val walletManager = store.state.walletState.getWalletManager(currency)

View file

@ -12,6 +12,7 @@ import com.tangem.core.analytics.Analytics
import com.tangem.domain.common.extensions.withMainContext
import com.tangem.operations.attestation.Attestation
import com.tangem.operations.attestation.OnlineCardVerifier
import com.tangem.tap.common.analytics.events.AnalyticsParam
import com.tangem.tap.common.analytics.events.MainScreen
import com.tangem.tap.common.analytics.events.Token
import com.tangem.tap.common.extensions.copyToClipboard
@ -248,10 +249,12 @@ class WalletMiddleware {
}
}
is WalletAction.CopyAddress -> {
Analytics.send(Token.Recieve.ButtonCopyAddress())
action.context.copyToClipboard(action.address)
store.dispatch(WalletAction.CopyAddress.Success)
}
is WalletAction.ShareAddress -> {
Analytics.send(Token.Recieve.ButtonShareAddress())
action.context.shareText(action.address)
}
is WalletAction.ExploreAddress -> {
@ -273,6 +276,9 @@ class WalletMiddleware {
} else {
store.dispatch(newAction)
if (newAction is PrepareSendScreen) {
store.state.walletState.getSelectedWalletData()?.currency?.let { currency ->
Analytics.send(Token.ButtonSend(AnalyticsParam.CurrencyType.Currency(currency)))
}
store.dispatch(NavigationAction.NavigateTo(AppScreen.Send))
}
}

View file

@ -1,7 +1,6 @@
package com.tangem.tap.features.wallet.redux.models
import com.tangem.blockchain.common.Amount
import com.tangem.blockchain.common.Blockchain
import com.tangem.tap.common.entities.FiatCurrency
import com.tangem.tap.common.redux.StateDialog
import com.tangem.wallet.R

View file

@ -24,7 +24,11 @@ class WalletWarningConverter(
is WalletWarning.BalanceNotEnoughForFee -> {
context.getString(
R.string.token_details_send_blocked_fee_format,
message.blockchainFullName, message.blockchainFullName,
message.tokenName,
message.blockchainFullName,
message.tokenName,
message.blockchainFullName,
message.blockchainCurrencyName,
)
}
is WalletWarning.TransactionInProgress -> {

View file

@ -41,8 +41,6 @@ class RussianCardholdersWarningBottomSheetDialog(
binding?.btnYes?.setOnClickListener {
if (dialogData != null) {
val currencyType = AnalyticsParam.CurrencyType.Blockchain(dialogData.blockchain)
Analytics.send(Onboarding.Topup.ButtonBuyCrypto(currencyType))
store.dispatchOpenUrl(dialogData.topUpUrl)
} else {
store.dispatch(WalletAction.TradeCryptoAction.Buy(checkUserLocation = false))

View file

@ -9,6 +9,7 @@ import com.tangem.core.analytics.Analytics
import com.tangem.domain.common.TapWorkarounds.derivationStyle
import com.tangem.domain.common.TapWorkarounds.isTestCard
import com.tangem.tap.common.analytics.events.MainScreen
import com.tangem.tap.common.analytics.events.ManageTokens
import com.tangem.tap.common.analytics.events.Portfolio
import com.tangem.tap.common.extensions.animateVisibility
import com.tangem.tap.common.extensions.formatAmountAsSpannedString
@ -136,6 +137,8 @@ class MultiWalletView : WalletView() {
derivationStyle = card.derivationStyle,
),
)
Analytics.send(ManageTokens.ScreenOpened())
store.dispatch(NavigationAction.NavigateTo(AppScreen.AddTokens))
}
handleErrorStates(state = state, binding = binding, fragment = fragment)