Skip to content

Commit 13f20f5

Browse files
committed
feat: add analytics metrics around deeplink success rates
Signed-off-by: Brandon McAnsh <git@bmcreations.dev>
1 parent 186b6c3 commit 13f20f5

9 files changed

Lines changed: 71 additions & 10 deletions

File tree

apps/flipcash/app/src/main/kotlin/com/flipcash/app/internal/ui/App.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import cafe.adriel.voyager.navigator.Navigator
2929
import cafe.adriel.voyager.navigator.currentOrThrow
3030
import cafe.adriel.voyager.transitions.CrossfadeTransition
3131
import cafe.adriel.voyager.transitions.SlideTransition
32+
import com.flipcash.app.analytics.rememberAnalytics
3233
import com.flipcash.app.android.BuildConfig
3334
import com.flipcash.app.bill.customization.BillPlaygroundScaffold
3435
import com.flipcash.app.core.LocalUserManager
@@ -80,7 +81,7 @@ internal fun App(
8081
solanaRpcConfig: RpcConfig,
8182
) {
8283
val router = LocalRouter.currentOrThrow
83-
84+
val analytics = rememberAnalytics()
8485
val viewModel = getActivityScopedViewModel<HomeViewModel>()
8586
val requireBiometrics by viewModel.requireBiometrics.collectAsStateWithLifecycle()
8687
val biometricsState = rememberBiometricsState(
@@ -104,7 +105,9 @@ internal fun App(
104105
var loginRequest by remember { mutableStateOf<String?>(null) }
105106
val userManager = LocalUserManager.currentOrThrow
106107
DeepLinkListener {
108+
analytics.deeplinkOpened(it.data)
107109
val type = router.processType(it)
110+
analytics.deeplinkParsed(type, it.data)
108111
if (type is DeeplinkType.Login) {
109112
loginRequest = type.entropy
110113
}

apps/flipcash/features/scanner/src/main/kotlin/com/flipcash/app/scanner/internal/Scanner.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ internal fun Scanner(deepLink: DeeplinkType?) {
7474
previewing = previewing,
7575
session = session,
7676
navigator = navigator,
77+
analytics = analytics,
7778
) {
7879
deepLinkSaved = null
7980
}
@@ -115,9 +116,10 @@ internal fun Scanner(deepLink: DeeplinkType?) {
115116
is CodeScanResult.QrCode -> {
116117
val urls = result.results
117118
val deeplink = urls.firstNotNullOfOrNull { url ->
118-
router.processType(DeepLink(url))
119+
val type = router.processType(DeepLink(url))
120+
analytics.deeplinkParsed(type, url)
121+
type
119122
}
120-
println("deeplink type = $deeplink")
121123
if (deeplink != null) {
122124
vibrator.vibrate(duration = 50)
123125
deepLinkSaved = deeplink

apps/flipcash/features/scanner/src/main/kotlin/com/flipcash/app/scanner/internal/ScannerDeepLinkHandler.kt

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ internal fun ScannerDeepLinkHandler(
2020
previewing: Boolean?,
2121
session: SessionController,
2222
navigator: CodeNavigator,
23+
analytics: FlipcashAnalyticsService,
2324
onDeeplinkHandled: () -> Unit,
2425
) {
2526

@@ -32,11 +33,7 @@ internal fun ScannerDeepLinkHandler(
3233
NavigationStateRestorer(navigator)
3334
}
3435

35-
LaunchedEffect(
36-
biometricsState,
37-
previewing,
38-
deepLink
39-
) {
36+
LaunchedEffect(biometricsState, previewing) {
4037
if (previewing == true) {
4138
focusManager.clearFocus()
4239
}
@@ -46,16 +43,20 @@ internal fun ScannerDeepLinkHandler(
4643
if (previewing != null) {
4744
session.onCameraScanning(previewing)
4845
}
46+
}
47+
48+
LaunchedEffect(deepLink, biometricsState.passed) {
49+
if (!biometricsState.passed) return@LaunchedEffect
4950

5051
val link = deepLink ?: return@LaunchedEffect
5152

5253
when (link) {
5354
is DeeplinkType.CashLink -> {
5455
session.openCashLink(link.entropy)
5556
}
56-
5757
is DeeplinkType.Login -> Unit
5858
is DeeplinkType.Navigatable -> {
59+
analytics.deeplinkRouted(link)
5960
stateRestorer.restoreState(link, animationScale)
6061
}
6162
}

apps/flipcash/shared/analytics/src/main/kotlin/com/flipcash/app/analytics/Analytics.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ interface FlipcashAnalyticsService : AnalyticsService {
2828
fun openTokenInfo(source: Analytics.TokenInfoSource, mint: Mint)
2929
fun buy(method: Analytics.PurchaseMethod, mint: Mint, amount: Fiat, error: Throwable? = null)
3030
fun sell(mint: Mint, amount: Fiat, feeAmount: Fiat, error: Throwable? = null)
31+
fun deeplinkOpened(url: String)
32+
fun deeplinkParsed(type: DeeplinkType?, url: String)
33+
fun deeplinkRouted(type: DeeplinkType, error: Throwable? = null)
3134

3235
fun buttonTapped(button: Button) {
3336
action(button)
@@ -84,6 +87,10 @@ class StubFlipcashAnalytics : FlipcashAnalyticsService {
8487
override fun openTokenInfo(source: Analytics.TokenInfoSource, mint: Mint) = Unit
8588
override fun buy(method: Analytics.PurchaseMethod, mint: Mint, amount: Fiat, error: Throwable?) = Unit
8689
override fun sell(mint: Mint, amount: Fiat, feeAmount: Fiat, error: Throwable?) = Unit
90+
91+
override fun deeplinkOpened(url: String) = Unit
92+
override fun deeplinkParsed(type: DeeplinkType?, url: String) = Unit
93+
override fun deeplinkRouted(type: DeeplinkType, error: Throwable?) = Unit
8794
}
8895

8996
@Composable

apps/flipcash/shared/analytics/src/main/kotlin/com/flipcash/app/analytics/Events.kt

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,37 @@ internal sealed interface AnalyticsEvent {
2929
)
3030
}
3131

32+
sealed interface DeeplinkEvent : AnalyticsEvent {
33+
data class Open(val url: String) : DeeplinkEvent {
34+
override val name = "Deeplink: Open"
35+
override fun toProperties() = mapOf("URL" to url)
36+
}
37+
38+
data class Parse(
39+
val type: DeeplinkType? = null,
40+
val url: String,
41+
) : DeeplinkEvent {
42+
override val name = "Deeplink: Parse"
43+
override fun toProperties() = buildMap {
44+
type?.let { put("Type", it.javaClass.simpleName) }
45+
if (type == null) {
46+
put("Error", "Failed to parse deeplink => $url")
47+
}
48+
}
49+
}
50+
51+
data class Routed(
52+
val type: DeeplinkType,
53+
val error: Throwable? = null
54+
) : DeeplinkEvent {
55+
override val name = "Deeplink: Routed"
56+
override fun toProperties() = buildMap {
57+
put("Type", type.javaClass.simpleName)
58+
error?.let { put("Error", it.message.orEmpty()) }
59+
}
60+
}
61+
}
62+
3263
sealed interface Transfer : AnalyticsEvent
3364

3465
data class GrabBill(val time: Long?) : Transfer {

apps/flipcash/shared/analytics/src/main/kotlin/com/flipcash/app/analytics/internal/MixpanelAnalyticsDelegate.kt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,18 @@ internal class MixpanelAnalyticsDelegate @Inject constructor(
200200
track(AnalyticsEvent.TokenTransactionEvent.Sell(mint, amount, feeAmount, error))
201201
}
202202

203+
override fun deeplinkOpened(url: String) {
204+
track(AnalyticsEvent.DeeplinkEvent.Open(url))
205+
}
206+
207+
override fun deeplinkParsed(type: DeeplinkType?, url: String) {
208+
track(AnalyticsEvent.DeeplinkEvent.Parse(type, url))
209+
}
210+
211+
override fun deeplinkRouted(type: DeeplinkType, error: Throwable?) {
212+
track(AnalyticsEvent.DeeplinkEvent.Routed(type, error))
213+
}
214+
203215
// region Internal
204216

205217
private fun track(event: AnalyticsEvent, vararg extra: Pair<String, String>) {

apps/flipcash/shared/router/src/main/kotlin/com/flipcash/app/router/inject/RouterModule.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.flipcash.app.router.inject
22

3+
import com.flipcash.app.analytics.FlipcashAnalyticsService
34
import com.flipcash.app.router.internal.AppRouter
45
import com.flipcash.app.router.Router
56
import com.flipcash.services.user.UserManager
@@ -17,5 +18,6 @@ object RouterModule {
1718
@Provides
1819
fun providesRouter(
1920
userManager: UserManager,
20-
): Router = AppRouter(userManager)
21+
analytics: FlipcashAnalyticsService,
22+
): Router = AppRouter(userManager, analytics)
2123
}

apps/flipcash/shared/router/src/main/kotlin/com/flipcash/app/router/internal/AppRouter.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package com.flipcash.app.router.internal
33
import androidx.core.net.toUri
44
import cafe.adriel.voyager.core.registry.ScreenRegistry
55
import cafe.adriel.voyager.core.screen.Screen
6+
import com.flipcash.app.analytics.FlipcashAnalyticsService
67
import com.flipcash.app.core.AppRoute
78
import com.flipcash.app.core.navigation.DeeplinkType
89
import com.flipcash.app.core.navigation.Key
@@ -30,6 +31,7 @@ import org.json.JSONObject
3031

3132
internal class AppRouter(
3233
private val userManager: UserManager,
34+
private val analytics: FlipcashAnalyticsService,
3335
) : Router, CoroutineScope by CoroutineScope(Dispatchers.IO) {
3436
companion object {
3537
val login = listOf("login")

apps/flipcash/shared/session/src/main/kotlin/com/flipcash/app/session/internal/RealSessionController.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -707,6 +707,7 @@ class RealSessionController @Inject constructor(
707707

708708
if (giftCardClaimInProgress.value == null) {
709709
giftCardClaimInProgress.value = entropy
710+
analytics.deeplinkRouted(DeeplinkType.CashLink(entropy))
710711
claimGiftCard(owner = owner, entropy = entropy, claimIfOwned = false)
711712
}
712713
}

0 commit comments

Comments
 (0)