Skip to content

Commit 2d59a5e

Browse files
authored
chore: allow screens to track own screen views on composition (#8)
Signed-off-by: Brandon McAnsh <git@bmcreations.dev>
1 parent a52ebb1 commit 2d59a5e

20 files changed

Lines changed: 323 additions & 146 deletions

api/src/main/java/com/getcode/manager/AnalyticsManager.kt

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,40 @@ import timber.log.Timber
1414
import javax.inject.Inject
1515
import javax.inject.Singleton
1616

17+
interface AnalyticsService {
18+
fun open(screen: AnalyticsManager.Screen)
19+
fun login(ownerPublicKey: String, autoCompleteCount: Int, inputChangeCount: Int)
20+
fun logout()
21+
fun track(event: AnalyticsManager.Name, vararg properties: Pair<AnalyticsManager.Property, String>)
22+
}
23+
24+
class AnalyticsServiceNull : AnalyticsService {
25+
override fun open(screen: AnalyticsManager.Screen) = Unit
26+
27+
override fun login(ownerPublicKey: String, autoCompleteCount: Int, inputChangeCount: Int) = Unit
28+
29+
override fun logout() = Unit
30+
31+
override fun track(
32+
event: AnalyticsManager.Name,
33+
vararg properties: Pair<AnalyticsManager.Property, String>
34+
) = Unit
35+
}
36+
1737
@Singleton
18-
class AnalyticsManager @Inject constructor(private val mixpanelAPI: MixpanelAPI) {
38+
class AnalyticsManager @Inject constructor(private val mixpanelAPI: MixpanelAPI): AnalyticsService {
1939
private var grabStartMillis: Long = 0L
2040
private var cashLinkGrabStartMillis: Long = 0L
2141

22-
fun open(screen: Screen) {
42+
override fun open(screen: Screen) {
2343
track(Name.Open, Pair(Property.Screen, screen.value))
2444
}
2545

26-
fun logout() {
46+
override fun logout() {
2747
track(Name.Logout)
2848
}
2949

30-
fun login(ownerPublicKey: String, autoCompleteCount: Int, inputChangeCount: Int) {
50+
override fun login(ownerPublicKey: String, autoCompleteCount: Int, inputChangeCount: Int) {
3151
track(
3252
Name.Login,
3353
Pair(Property.OwnerPublicKey, ownerPublicKey),
@@ -151,8 +171,11 @@ class AnalyticsManager @Inject constructor(private val mixpanelAPI: MixpanelAPI)
151171
Timber.i("Bill scanned. From start: " + (System.currentTimeMillis() - (timeAppInit ?: 0)))
152172
}
153173

154-
private fun track(event: Name, vararg properties: Pair<Property, String>) {
155-
if (BuildConfig.DEBUG) return //no logging in debug
174+
override fun track(event: Name, vararg properties: Pair<Property, String>) {
175+
if (BuildConfig.DEBUG) {
176+
Timber.d("debug track $event, ${properties.map { "${it.first.name}, ${it.second}" }}")
177+
return
178+
} //no logging in debug
156179

157180
val jsonObject = JSONObject()
158181
properties.forEach { property ->
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.getcode
2+
3+
import androidx.compose.runtime.ProvidableCompositionLocal
4+
import androidx.compose.runtime.staticCompositionLocalOf
5+
import com.getcode.manager.AnalyticsService
6+
import com.getcode.manager.AnalyticsServiceNull
7+
8+
val LocalAnalytics: ProvidableCompositionLocal<AnalyticsService> = staticCompositionLocalOf { AnalyticsServiceNull() }
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.getcode.analytics
2+
3+
import androidx.compose.runtime.Composable
4+
import androidx.lifecycle.LifecycleOwner
5+
import com.getcode.manager.AnalyticsManager
6+
7+
@Composable
8+
fun AnalyticsScreenWatcher(
9+
lifecycleOwner: LifecycleOwner,
10+
event: AnalyticsManager.Screen,
11+
) {
12+
AnalyticsWatcher(lifecycleOwner = lifecycleOwner, onEvent = { analytics, context ->
13+
analytics.open(event)
14+
})
15+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package com.getcode.analytics
2+
3+
import android.content.Context
4+
import androidx.compose.runtime.Composable
5+
import androidx.compose.runtime.getValue
6+
import androidx.compose.runtime.rememberUpdatedState
7+
import androidx.compose.ui.platform.LocalContext
8+
import androidx.lifecycle.Lifecycle
9+
import androidx.lifecycle.LifecycleOwner
10+
import com.getcode.LocalAnalytics
11+
import com.getcode.manager.AnalyticsService
12+
import com.getcode.util.RepeatOnLifecycle
13+
14+
@Composable
15+
fun AnalyticsWatcher(
16+
lifecycleOwner: LifecycleOwner,
17+
onEvent: (AnalyticsService, Context) -> Unit,
18+
onDispose: (AnalyticsService, Context) -> Unit = { _, _ -> },
19+
) {
20+
val context = LocalContext.current
21+
val analyticsService = LocalAnalytics.current
22+
23+
val updatedOnEvent by rememberUpdatedState(newValue = onEvent)
24+
val updatedOnDispose by rememberUpdatedState(newValue = onDispose)
25+
26+
RepeatOnLifecycle(
27+
lifecycleOwner = lifecycleOwner,
28+
targetState = Lifecycle.State.RESUMED,
29+
doOnDispose = {
30+
updatedOnDispose(analyticsService, context)
31+
},
32+
) {
33+
updatedOnEvent(analyticsService, context)
34+
}
35+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package com.getcode.util
2+
3+
import androidx.compose.runtime.Composable
4+
import androidx.compose.runtime.DisposableEffect
5+
import androidx.compose.ui.platform.LocalLifecycleOwner
6+
import androidx.lifecycle.Lifecycle
7+
import androidx.lifecycle.LifecycleOwner
8+
import androidx.lifecycle.lifecycleScope
9+
import androidx.lifecycle.repeatOnLifecycle
10+
import kotlinx.coroutines.launch
11+
12+
@Composable
13+
fun RepeatOnLifecycle(
14+
lifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current,
15+
targetState: Lifecycle.State,
16+
doOnDispose: () -> Unit = {},
17+
action: suspend () -> Unit,
18+
) {
19+
DisposableEffect(lifecycleOwner) {
20+
val job = lifecycleOwner.lifecycleScope.launch {
21+
lifecycleOwner.repeatOnLifecycle(targetState) {
22+
action()
23+
}
24+
}
25+
onDispose {
26+
job.cancel()
27+
doOnDispose()
28+
}
29+
}
30+
}

app/src/main/java/com/getcode/view/MainActivity.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import android.os.Bundle
66
import android.os.Debug
77
import androidx.activity.ComponentActivity
88
import androidx.activity.compose.setContent
9+
import androidx.compose.runtime.CompositionLocalProvider
910
import androidx.compose.runtime.DisposableEffect
1011
import androidx.compose.runtime.rememberUpdatedState
1112
import androidx.core.util.Consumer
@@ -15,6 +16,7 @@ import androidx.navigation.NavController
1516
import androidx.navigation.NavHostController
1617
import androidx.navigation.findNavController
1718
import com.getcode.CodeApp
19+
import com.getcode.LocalAnalytics
1820
import com.getcode.manager.AnalyticsManager
1921
import com.getcode.manager.AuthManager
2022
import com.getcode.manager.SessionManager
@@ -78,7 +80,9 @@ class MainActivity : FragmentActivity() {
7880
setContent {
7981
val appState = rememberCodeAppState()
8082
currentNavHostController = appState.navController
81-
CodeApp(appState)
83+
CompositionLocalProvider(LocalAnalytics provides analyticsManager) {
84+
CodeApp(appState)
85+
}
8286
}
8387
}
8488

app/src/main/java/com/getcode/view/main/account/AccountAccessKey.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import androidx.compose.ui.Modifier
1313
import androidx.compose.ui.graphics.asImageBitmap
1414
import androidx.compose.ui.layout.ContentScale
1515
import androidx.compose.ui.platform.LocalContext
16+
import androidx.compose.ui.platform.LocalLifecycleOwner
1617
import androidx.compose.ui.res.stringResource
1718
import androidx.compose.ui.text.style.TextAlign
1819
import androidx.compose.ui.unit.dp
@@ -22,6 +23,8 @@ import androidx.hilt.navigation.compose.hiltViewModel
2223
import androidx.navigation.NavController
2324
import com.getcode.App
2425
import com.getcode.R
26+
import com.getcode.analytics.AnalyticsScreenWatcher
27+
import com.getcode.manager.AnalyticsManager
2528
import com.getcode.manager.TopBarManager
2629
import com.getcode.theme.BrandLight
2730
import com.getcode.util.IntentUtils
@@ -76,6 +79,11 @@ fun AccountAccessKey(navController: NavController) {
7679
}
7780
}
7881

82+
AnalyticsScreenWatcher(
83+
lifecycleOwner = LocalLifecycleOwner.current,
84+
event = AnalyticsManager.Screen.Backup
85+
)
86+
7987
ConstraintLayout(
8088
modifier = Modifier
8189
.fillMaxSize()

app/src/main/java/com/getcode/view/main/account/AccountDeposit.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,14 @@ import androidx.compose.ui.Alignment
1010
import androidx.compose.ui.Modifier
1111
import androidx.compose.ui.draw.clip
1212
import androidx.compose.ui.platform.LocalClipboardManager
13+
import androidx.compose.ui.platform.LocalLifecycleOwner
1314
import androidx.compose.ui.res.stringResource
1415
import androidx.compose.ui.text.AnnotatedString
1516
import androidx.compose.ui.text.style.TextAlign
1617
import androidx.compose.ui.unit.dp
1718
import com.getcode.R
19+
import com.getcode.analytics.AnalyticsScreenWatcher
20+
import com.getcode.manager.AnalyticsManager
1821
import com.getcode.manager.SessionManager
1922
import com.getcode.solana.organizer.AccountType
2023
import com.getcode.theme.*
@@ -32,6 +35,11 @@ fun AccountDeposit() {
3235
val localClipboardManager = LocalClipboardManager.current
3336
var isCopied by remember { mutableStateOf(false) }
3437

38+
AnalyticsScreenWatcher(
39+
lifecycleOwner = LocalLifecycleOwner.current,
40+
event = AnalyticsManager.Screen.Deposit
41+
)
42+
3543
Column(
3644
modifier = Modifier
3745
.background(Brand)

app/src/main/java/com/getcode/view/main/account/AccountDetails.kt

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,6 @@ fun AccountDetails(
2222
viewModel: AccountSheetViewModel = hiltViewModel(),
2323
) {
2424
val dataState by viewModel.stateFlow.collectAsState()
25-
val context = LocalContext.current
26-
27-
fun onPage(page: AccountPage) {
28-
onPageSelected(page)
29-
viewModel.dispatchEvent(AccountSheetViewModel.Event.Navigate(page))
30-
}
3125

3226
Box(modifier = Modifier.fillMaxHeight()) {
3327
Column(
@@ -48,7 +42,7 @@ fun AccountDetails(
4842
positiveText = App.getInstance()
4943
.getString(R.string.action_viewAccessKey),
5044
negativeText = App.getInstance().getString(R.string.action_cancel),
51-
onPositive = { onPage(AccountPage.ACCESS_KEY) },
45+
onPositive = { onPageSelected(AccountPage.ACCESS_KEY) },
5246
onNegative = {}
5347
)
5448
)
@@ -58,11 +52,11 @@ fun AccountDetails(
5852
name = R.string.title_phoneNumber,
5953
icon = R.drawable.ic_menu_phone,
6054
isPhoneLinked = dataState.isPhoneLinked,
61-
) { onPage(AccountPage.PHONE) },
55+
) { onPageSelected(AccountPage.PHONE) },
6256
AccountMainItem(
6357
name = R.string.action_deleteAccount,
6458
icon = R.drawable.ic_delete
65-
) { onPage(AccountPage.DELETE_ACCOUNT) },
59+
) { onPageSelected(AccountPage.DELETE_ACCOUNT) },
6660
)
6761

6862
for (action in actions) {

app/src/main/java/com/getcode/view/main/account/AccountFaq.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,15 @@ import androidx.compose.runtime.LaunchedEffect
1010
import androidx.compose.runtime.collectAsState
1111
import androidx.compose.runtime.getValue
1212
import androidx.compose.ui.Modifier
13+
import androidx.compose.ui.platform.LocalLifecycleOwner
1314
import androidx.compose.ui.text.font.FontWeight
1415
import androidx.compose.ui.tooling.preview.Preview
1516
import androidx.compose.ui.unit.dp
1617
import androidx.compose.ui.unit.sp
1718
import androidx.hilt.navigation.compose.hiltViewModel
1819
import com.getcode.R
20+
import com.getcode.analytics.AnalyticsScreenWatcher
21+
import com.getcode.manager.AnalyticsManager
1922
import com.getcode.theme.White
2023
import com.getcode.theme.sheetHeight
2124
import com.getcode.view.components.MarkdownText
@@ -27,6 +30,11 @@ fun AccountFaq(
2730
) {
2831
val dataState by viewModel.stateFlow.collectAsState()
2932

33+
AnalyticsScreenWatcher(
34+
lifecycleOwner = LocalLifecycleOwner.current,
35+
event = AnalyticsManager.Screen.Faq
36+
)
37+
3038
Box(
3139
modifier = Modifier
3240
.padding(horizontal = 20.dp)

0 commit comments

Comments
 (0)