Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.flipcash.app.balance.internal

import androidx.lifecycle.viewModelScope
import com.flipcash.app.analytics.Analytics
import com.flipcash.app.analytics.FlipcashAnalyticsService
import com.flipcash.app.core.AppRoute
import com.flipcash.app.featureflags.FeatureFlag
import com.flipcash.app.featureflags.FeatureFlagController
Expand Down Expand Up @@ -28,6 +30,7 @@ internal class BalanceViewModel @Inject constructor(
dispatchers: DispatcherProvider,
purchaseMethodController: PurchaseMethodController,
featureFlags: FeatureFlagController,
analytics: FlipcashAnalyticsService,
) : BaseViewModel<BalanceViewModel.State, BalanceViewModel.Event>(
initialState = State(),
updateStateForEvent = updateStateForEvent,
Expand Down Expand Up @@ -68,6 +71,7 @@ internal class BalanceViewModel @Inject constructor(
dispatchEvent(Event.OpenScreen(AppRoute.Token.Discovery))
return@mapNotNull null
}
analytics.addMoneyOpened(Analytics.AddMoneySource.Balance)
purchaseMethodController.presentDepositOptions(popToRoot = true) }
.onEach { route -> dispatchEvent(Event.OpenScreen(route)) }
.launchIn(viewModelScope)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.flipcash.app.cash.internal

import androidx.lifecycle.viewModelScope
import com.flipcash.app.analytics.Analytics
import com.flipcash.app.analytics.FlipcashAnalyticsService
import com.flipcash.app.core.AppRoute
import com.flipcash.app.core.bill.Bill
import com.flipcash.app.core.tokens.SwapPurpose
Expand All @@ -24,6 +26,7 @@ import com.getcode.opencode.model.financial.LocalFiat
import com.getcode.opencode.model.financial.SendLimit
import com.getcode.opencode.model.financial.TokenWithLocalizedBalance
import com.getcode.opencode.model.financial.minus
import com.getcode.opencode.model.financial.usdf
import com.getcode.solana.keys.Mint
import com.getcode.util.resources.ResourceHelper
import com.getcode.view.BaseViewModel
Expand Down Expand Up @@ -55,6 +58,7 @@ internal class CashScreenViewModel @Inject constructor(
private val verifiedFiatCalculator: VerifiedFiatCalculator,
tokenCoordinator: TokenCoordinator,
transactionController: TransactionOperations,
analytics: FlipcashAnalyticsService,
dispatchers: DispatcherProvider,
) : BaseViewModel<CashScreenViewModel.State, CashScreenViewModel.Event>(
initialState = State(),
Expand Down Expand Up @@ -272,6 +276,9 @@ internal class CashScreenViewModel @Inject constructor(
.onEach { shortfall ->
// route directly to the swap amount screen, skipping token info
val mint = stateFlow.value.selectedTokenAddress!!
if (mint == Mint.usdf) {
analytics.addMoneyOpened(Analytics.AddMoneySource.GiveShortfall)
}
dispatchEvent(
Event.OpenScreen(
AppRoute.Token.Swap(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.flipcash.app.cash.internal

import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import com.flipcash.app.analytics.StubFlipcashAnalytics
import com.flipcash.app.core.MainCoroutineRule
import com.flipcash.app.core.dispatchers.TestDispatchers
import com.flipcash.app.tokens.TokenCoordinator
Expand Down Expand Up @@ -78,6 +79,7 @@ class CashScreenViewModelTest {
verifiedFiatCalculator = verifiedFiatCalculator,
tokenCoordinator = tokenCoordinator,
transactionController = transactionController,
analytics = StubFlipcashAnalytics(),
dispatchers = dispatchers,
)
}
Expand Down
1 change: 1 addition & 0 deletions apps/flipcash/features/deposit/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ dependencies {

implementation(project(":libs:messaging"))

implementation(project(":apps:flipcash:shared:analytics"))
implementation(project(":apps:flipcash:shared:featureflags"))
implementation(project(":apps:flipcash:shared:tokens"))
implementation(project(":services:flipcash"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.flipcash.app.deposit.internal

import android.content.ClipboardManager
import androidx.lifecycle.viewModelScope
import com.flipcash.app.analytics.FlipcashAnalyticsService
import com.flipcash.app.core.extensions.onResult
import com.flipcash.app.core.extensions.setText
import com.flipcash.features.deposit.R
Expand Down Expand Up @@ -34,6 +35,7 @@ internal class DepositViewModel @Inject constructor(
resources: ResourceHelper,
dispatchers: DispatcherProvider,
featureFlags: FeatureFlagController,
analytics: FlipcashAnalyticsService,
) : BaseViewModel<DepositViewModel.State, DepositViewModel.Event>(
initialState = State(),
updateStateForEvent = updateStateForEvent,
Expand Down Expand Up @@ -106,6 +108,9 @@ internal class DepositViewModel @Inject constructor(
text = stateFlow.value.depositAddress,
label = resources.getString(R.string.title_clipboardLabelDepositAddress),
)
stateFlow.value.selectedTokenAddress?.let { mint ->
analytics.addMoneyAddressCopied(mint)
}
}
.onEach {
dispatchEvent(Event.SetCopied(true))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.flipcash.app.menu.internal

import androidx.lifecycle.viewModelScope
import com.flipcash.app.analytics.Analytics
import com.flipcash.app.analytics.FlipcashAnalyticsService
import com.flipcash.app.auth.AuthManager
import com.flipcash.app.core.AppRoute
import com.flipcash.app.core.android.VersionInfo
Expand Down Expand Up @@ -53,6 +55,7 @@ internal class MenuScreenViewModel @Inject constructor(
dispatchers: DispatcherProvider,
releaseStageProvider: ReleaseStageProvider,
purchaseMethodController: PurchaseMethodController,
analytics: FlipcashAnalyticsService,
) :
BaseViewModel<MenuScreenViewModel.State, MenuScreenViewModel.Event>(
initialState = State(),
Expand Down Expand Up @@ -165,6 +168,7 @@ internal class MenuScreenViewModel @Inject constructor(
eventFlow
.filterIsInstance<Event.PresentDepositOptions>()
.mapNotNull {
analytics.addMoneyOpened(Analytics.AddMoneySource.Menu)
val depositFirstUx = featureFlags.get(FeatureFlag.AddMoneyUX)
if (!depositFirstUx) {
return@mapNotNull AppRoute.Transfers.Deposit()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,7 @@ internal class ChatViewModel @Inject constructor(
eventFlow
.filterIsInstance<Event.PresentDepositOptions>()
.onEach {
analytics.addMoneyOpened(Analytics.AddMoneySource.Chat)
purchaseMethodController.presentDepositOptions()?.let { route ->
dispatchEvent(Event.OpenScreen(route))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ interface FlipcashAnalyticsService : AnalyticsService {
fun openOnramp(source: Analytics.OnrampSource)
fun onrampVerification(step: Analytics.OnrampVerificationStep)
fun onrampPurchase(step: Analytics.OnrampPurchaseStep, amount: Fiat? = null)
fun addMoneyOpened(source: Analytics.AddMoneySource)
fun addMoneyMethodSelected(method: Analytics.AddMoneyMethod)
fun addMoneyAmountConfirmed(method: Analytics.AddMoneyMethod, amount: Fiat)
fun addMoneyPaymentInvoked(method: Analytics.AddMoneyMethod, amount: Fiat)
fun addMoneyAddressCopied(mint: Mint)
fun addMoney(method: Analytics.AddMoneyMethod, amount: Fiat? = null, successful: Boolean = true, error: Throwable? = null)
fun connectWallet(provider: OnRampProvider.UsesDeeplinks)
fun amountSelectedForWalletTransfer(provider: OnRampProvider.UsesDeeplinks, amount: Fiat)
fun transactionSubmittedToWallet(provider: OnRampProvider.UsesDeeplinks)
Expand Down Expand Up @@ -60,6 +66,8 @@ object Analytics {
data object SentCash : Transfer
}
enum class OnrampSource { Settings, Balance, Give }
enum class AddMoneySource { Menu, GiveShortfall, BuyShortfall, Chat, Scanner, Balance }
enum class AddMoneyMethod { Coinbase, Phantom, OtherWallet, Reserves }
enum class OnrampVerificationStep { ShowInfo, EnterPhone, ConfirmPhone, EnterEmail, ConfirmEmail }
enum class OnrampPurchaseStep { PresetSelected, EnterCustomAmount, InvokePayment, InvokePaymentCustom, Completed }
enum class TokenInfoSource { Deeplink, Wallet, Give }
Expand Down Expand Up @@ -89,6 +97,13 @@ class StubFlipcashAnalytics : FlipcashAnalyticsService {
override fun onrampVerification(step: Analytics.OnrampVerificationStep) = Unit
override fun onrampPurchase(step: Analytics.OnrampPurchaseStep, amount: Fiat?) = Unit

override fun addMoneyOpened(source: Analytics.AddMoneySource) = Unit
override fun addMoneyMethodSelected(method: Analytics.AddMoneyMethod) = Unit
override fun addMoneyAmountConfirmed(method: Analytics.AddMoneyMethod, amount: Fiat) = Unit
override fun addMoneyPaymentInvoked(method: Analytics.AddMoneyMethod, amount: Fiat) = Unit
override fun addMoneyAddressCopied(mint: Mint) = Unit
override fun addMoney(method: Analytics.AddMoneyMethod, amount: Fiat?, successful: Boolean, error: Throwable?) = Unit

override fun connectWallet(provider: OnRampProvider.UsesDeeplinks) = Unit
override fun amountSelectedForWalletTransfer(provider: OnRampProvider.UsesDeeplinks, amount: Fiat) = Unit
override fun transactionSubmittedToWallet(provider: OnRampProvider.UsesDeeplinks) = Unit
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,50 @@ internal sealed interface AnalyticsEvent {
}
}

sealed interface AddMoneyEvent : AnalyticsEvent {
data class Opened(val source: Analytics.AddMoneySource) : AddMoneyEvent {
override val name = "Add Money: Opened"
override fun toProperties() = mapOf("Source" to source.propertyValue)
}

data class MethodSelected(val method: Analytics.AddMoneyMethod) : AddMoneyEvent {
override val name = "Add Money: Method Selected"
override fun toProperties() = mapOf("Method" to method.propertyValue)
}

data class AmountConfirmed(
val method: Analytics.AddMoneyMethod,
val amount: Fiat,
) : AddMoneyEvent {
override val name = "Add Money: Amount Confirmed"
override fun toProperties() = buildMap {
put("Method", method.propertyValue)
putAll(amount.asProperties())
}
}

data class PaymentInvoked(
val method: Analytics.AddMoneyMethod,
val amount: Fiat,
) : AddMoneyEvent {
override val name = "Add Money: Payment Invoked"
override fun toProperties() = buildMap {
put("Method", method.propertyValue)
putAll(amount.asProperties())
}
}

data class AddressCopied(val mint: Mint) : AddMoneyEvent {
override val name = "Add Money: Address Copied"
override fun toProperties() = mapOf("Mint" to mint.base58())
}

data class Terminal(val method: Analytics.AddMoneyMethod) : AddMoneyEvent {
override val name = "Add Money"
override fun toProperties() = mapOf("Method" to method.propertyValue)
}
}

sealed interface OpenTokenInfoEvent : AnalyticsEvent {
val mint: Mint
override fun toProperties() = mapOf("Mint" to mint.base58())
Expand Down Expand Up @@ -297,6 +341,24 @@ internal sealed interface AnalyticsEvent {
}
}

internal val Analytics.AddMoneySource.propertyValue: String
get() = when (this) {
Analytics.AddMoneySource.Menu -> "Menu"
Analytics.AddMoneySource.GiveShortfall -> "Give Shortfall"
Analytics.AddMoneySource.BuyShortfall -> "Buy Shortfall"
Analytics.AddMoneySource.Chat -> "Chat"
Analytics.AddMoneySource.Scanner -> "Scanner"
Analytics.AddMoneySource.Balance -> "Balance"
}

internal val Analytics.AddMoneyMethod.propertyValue: String
get() = when (this) {
Analytics.AddMoneyMethod.Coinbase -> "Coinbase"
Analytics.AddMoneyMethod.Phantom -> "Phantom"
Analytics.AddMoneyMethod.OtherWallet -> "Other Wallet"
Analytics.AddMoneyMethod.Reserves -> "Reserves"
}

internal fun LocalFiat.asProperties(): Map<String, String> {
return buildMap {
putAll(underlyingTokenAmount.asProperties())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,40 @@ internal class MixpanelAnalyticsDelegate @Inject constructor(
track(event)
}

override fun addMoneyOpened(source: Analytics.AddMoneySource) {
track(AnalyticsEvent.AddMoneyEvent.Opened(source))
}

override fun addMoneyMethodSelected(method: Analytics.AddMoneyMethod) {
track(AnalyticsEvent.AddMoneyEvent.MethodSelected(method))
}

override fun addMoneyAmountConfirmed(method: Analytics.AddMoneyMethod, amount: Fiat) {
track(AnalyticsEvent.AddMoneyEvent.AmountConfirmed(method, amount))
}

override fun addMoneyPaymentInvoked(method: Analytics.AddMoneyMethod, amount: Fiat) {
track(AnalyticsEvent.AddMoneyEvent.PaymentInvoked(method, amount))
}

override fun addMoneyAddressCopied(mint: Mint) {
track(AnalyticsEvent.AddMoneyEvent.AddressCopied(mint))
}

override fun addMoney(
method: Analytics.AddMoneyMethod,
amount: Fiat?,
successful: Boolean,
error: Throwable?
) {
track(
AnalyticsEvent.AddMoneyEvent.Terminal(method),
"State" to if (successful) "Success" else "Failure",
*amount?.asProperties()?.toList()?.toTypedArray() ?: emptyArray(),
*error.asProperty()
)
}

override fun connectWallet(provider: OnRampProvider.UsesDeeplinks) {
track(AnalyticsEvent.WalletConnect(provider))
}
Expand Down
1 change: 1 addition & 0 deletions apps/flipcash/shared/payments/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ android {
}

dependencies {
implementation(project(":apps:flipcash:shared:analytics"))
implementation(project(":apps:flipcash:shared:featureflags"))
implementation(project(":apps:flipcash:shared:tokens:core"))
implementation(project(":apps:flipcash:shared:userflags"))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.flipcash.app.payments.internal

import com.flipcash.app.analytics.Analytics
import com.flipcash.app.analytics.FlipcashAnalyticsService
import com.flipcash.app.core.AppRoute
import com.flipcash.app.core.tokens.FundingSource
import com.flipcash.app.core.tokens.SwapPurpose
Expand Down Expand Up @@ -54,6 +56,7 @@ class InternalPurchaseMethodController @Inject constructor(
exchange: Exchange,
private val resources: ResourceHelper,
private val userManager: UserManager,
private val analytics: FlipcashAnalyticsService,
) : PurchaseMethodController {

private val scope = CoroutineScope(SupervisorJob())
Expand Down Expand Up @@ -148,6 +151,18 @@ class InternalPurchaseMethodController @Inject constructor(
_dismissals.map { null },
).first()

when (result) {
PurchaseMethod.CoinbaseOnRamp ->
analytics.addMoneyMethodSelected(Analytics.AddMoneyMethod.Coinbase)
PurchaseMethod.PhantomWallet ->
analytics.addMoneyMethodSelected(Analytics.AddMoneyMethod.Phantom)
PurchaseMethod.OtherWallet ->
analytics.addMoneyMethodSelected(Analytics.AddMoneyMethod.OtherWallet)
is PurchaseMethod.CashReserves ->
analytics.addMoneyMethodSelected(Analytics.AddMoneyMethod.Reserves)
null -> Unit
}

return when (result) {
PurchaseMethod.CoinbaseOnRamp -> {
val profile = userManager.profile
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.flipcash.app.session.internal.delegates

import com.flipcash.app.analytics.Analytics
import com.flipcash.app.analytics.FlipcashAnalyticsService
import com.flipcash.app.core.AppRoute
import com.flipcash.app.featureflags.FeatureFlag
import com.flipcash.app.featureflags.FeatureFlagController
Expand Down Expand Up @@ -38,6 +40,7 @@ class DepositDelegate @Inject constructor(
private val usdcSweep: UsdcDepositSweep,
private val userManager: UserManager,
private val resources: ResourceHelper,
private val analytics: FlipcashAnalyticsService,
dispatchers: DispatcherProvider,
featureFlagController: FeatureFlagController,
) : DepositOperations {
Expand Down Expand Up @@ -77,6 +80,8 @@ class DepositDelegate @Inject constructor(
text = resources.getString(R.string.action_addMoney)
) {
scope.launch {
// the scanner's Give action is the only session caller today
analytics.addMoneyOpened(Analytics.AddMoneySource.Scanner)
val destination = purchaseMethodController.presentDepositOptions(popToRoot = true)
if (destination != null) {
onRoute?.invoke(destination)
Expand Down
Loading
Loading