diff --git a/app/detekt-baseline.xml b/app/detekt-baseline.xml
index 8e02cdb26..4b051acb2 100644
--- a/app/detekt-baseline.xml
+++ b/app/detekt-baseline.xml
@@ -8,6 +8,7 @@
CommentWrapping:SignalMetrics.kt$Metric.SNR$/* Selected 12 as the max to get 4 equal vertical sections. */
ComposableNaming:NodeDetailScreen.kt$notesSection
ComposableParamOrder:Channel.kt$ChannelScreen
+ ComposableParamOrder:Channel.kt$EditChannelUrl
ComposableParamOrder:DeviceMetrics.kt$DeviceMetricsChart
ComposableParamOrder:EmptyStateContent.kt$EmptyStateContent
ComposableParamOrder:EnvironmentCharts.kt$ChartContent
diff --git a/app/src/main/java/com/geeksville/mesh/MeshUtilApplication.kt b/app/src/main/java/com/geeksville/mesh/MeshUtilApplication.kt
index 4aece39f0..e64e1ad94 100644
--- a/app/src/main/java/com/geeksville/mesh/MeshUtilApplication.kt
+++ b/app/src/main/java/com/geeksville/mesh/MeshUtilApplication.kt
@@ -19,9 +19,7 @@ package com.geeksville.mesh
import android.app.Application
import dagger.hilt.android.HiltAndroidApp
-import org.meshtastic.core.analytics.platform.PlatformAnalytics
import timber.log.Timber
-import javax.inject.Inject
/**
* The main application class for Meshtastic.
@@ -30,26 +28,7 @@ import javax.inject.Inject
* application components, including analytics and platform-specific helpers, and manages analytics consent based on
* user preferences.
*/
-@HiltAndroidApp
-class MeshUtilApplication : Application() {
-
- @Inject lateinit var platformAnalytics: PlatformAnalytics
-
- companion object {
- /**
- * Provides access to the platform-specific analytics provider. Initialized via the injected [PlatformAnalytics]
- * during [onCreate].
- */
- lateinit var analytics: PlatformAnalytics
- private set
- }
-
- override fun onCreate() {
- super.onCreate()
- // Initialize platform-specific features (analytics, crash reporting, etc.)
- analytics = platformAnalytics
- }
-}
+@HiltAndroidApp class MeshUtilApplication : Application()
fun logAssert(executeReliableWrite: Boolean) {
if (!executeReliableWrite) {
diff --git a/app/src/main/java/com/geeksville/mesh/model/UIState.kt b/app/src/main/java/com/geeksville/mesh/model/UIState.kt
index 8acdfd751..76cf72441 100644
--- a/app/src/main/java/com/geeksville/mesh/model/UIState.kt
+++ b/app/src/main/java/com/geeksville/mesh/model/UIState.kt
@@ -27,6 +27,7 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.asLiveData
import androidx.lifecycle.viewModelScope
+import androidx.navigation.NavHostController
import com.geeksville.mesh.AdminProtos
import com.geeksville.mesh.AppOnlyProtos
import com.geeksville.mesh.ConfigProtos.Config
@@ -55,6 +56,7 @@ import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.shareIn
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
+import org.meshtastic.core.analytics.platform.PlatformAnalytics
import org.meshtastic.core.data.repository.FirmwareReleaseRepository
import org.meshtastic.core.data.repository.MeshLogRepository
import org.meshtastic.core.data.repository.NodeRepository
@@ -130,6 +132,7 @@ constructor(
firmwareReleaseRepository: FirmwareReleaseRepository,
private val uiPreferencesDataSource: UiPreferencesDataSource,
private val meshServiceNotifications: MeshServiceNotifications,
+ private val analytics: PlatformAnalytics,
) : ViewModel() {
val theme: StateFlow = uiPreferencesDataSource.theme
@@ -351,4 +354,8 @@ constructor(
fun onAppIntroCompleted() {
uiPreferencesDataSource.setAppIntroCompleted(true)
}
+
+ fun addNavigationTrackingEffect(navController: NavHostController) {
+ analytics.addNavigationTrackingEffect(navController)
+ }
}
diff --git a/app/src/main/java/com/geeksville/mesh/repository/radio/RadioInterfaceService.kt b/app/src/main/java/com/geeksville/mesh/repository/radio/RadioInterfaceService.kt
index 94dd06dd5..2199f896d 100644
--- a/app/src/main/java/com/geeksville/mesh/repository/radio/RadioInterfaceService.kt
+++ b/app/src/main/java/com/geeksville/mesh/repository/radio/RadioInterfaceService.kt
@@ -24,7 +24,6 @@ import androidx.lifecycle.coroutineScope
import com.geeksville.mesh.BuildConfig
import com.geeksville.mesh.CoroutineDispatchers
import com.geeksville.mesh.MeshProtos
-import com.geeksville.mesh.MeshUtilApplication
import com.geeksville.mesh.android.BinaryLogFile
import com.geeksville.mesh.android.BuildUtils
import com.geeksville.mesh.concurrent.handledLaunch
@@ -46,6 +45,7 @@ import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
+import org.meshtastic.core.analytics.platform.PlatformAnalytics
import org.meshtastic.core.model.util.anonymize
import org.meshtastic.core.prefs.radio.RadioPrefs
import org.meshtastic.core.service.ConnectionState
@@ -74,6 +74,7 @@ constructor(
private val processLifecycle: Lifecycle,
private val radioPrefs: RadioPrefs,
private val interfaceFactory: InterfaceFactory,
+ private val analytics: PlatformAnalytics,
) {
private val _connectionState = MutableStateFlow(ConnectionState.DISCONNECTED)
@@ -307,7 +308,7 @@ constructor(
false
} else {
// Record that this use has configured a new radio
- MeshUtilApplication.analytics.track("mesh_bond")
+ analytics.track("mesh_bond")
// Ignore any errors that happen while closing old device
ignoreException { stopInterface() }
diff --git a/app/src/main/java/com/geeksville/mesh/ui/Main.kt b/app/src/main/java/com/geeksville/mesh/ui/Main.kt
index 578689587..3810cdc9e 100644
--- a/app/src/main/java/com/geeksville/mesh/ui/Main.kt
+++ b/app/src/main/java/com/geeksville/mesh/ui/Main.kt
@@ -75,7 +75,6 @@ import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
import com.geeksville.mesh.BuildConfig
import com.geeksville.mesh.MeshProtos
-import com.geeksville.mesh.MeshUtilApplication
import com.geeksville.mesh.model.BTScanModel
import com.geeksville.mesh.model.UIViewModel
import com.geeksville.mesh.navigation.channelsGraph
@@ -158,7 +157,7 @@ fun MainScreen(uIViewModel: UIViewModel = hiltViewModel(), scanModel: BTScanMode
}
}
- MeshUtilApplication.analytics.addNavigationTrackingEffect(navController = navController)
+ uIViewModel.addNavigationTrackingEffect(navController)
VersionChecks(uIViewModel)
val alertDialogState by uIViewModel.currentAlert.collectAsStateWithLifecycle()
diff --git a/app/src/main/java/com/geeksville/mesh/ui/sharing/Channel.kt b/app/src/main/java/com/geeksville/mesh/ui/sharing/Channel.kt
index 97b5d4779..f039a037e 100644
--- a/app/src/main/java/com/geeksville/mesh/ui/sharing/Channel.kt
+++ b/app/src/main/java/com/geeksville/mesh/ui/sharing/Channel.kt
@@ -92,7 +92,6 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.geeksville.mesh.AppOnlyProtos.ChannelSet
import com.geeksville.mesh.ChannelProtos
import com.geeksville.mesh.ConfigProtos
-import com.geeksville.mesh.MeshUtilApplication.Companion.analytics
import com.geeksville.mesh.channelSet
import com.geeksville.mesh.copy
import com.geeksville.mesh.ui.common.components.ScannedQrCodeDialog
@@ -102,7 +101,6 @@ import com.google.accompanist.permissions.rememberPermissionState
import com.journeyapps.barcodescanner.ScanContract
import com.journeyapps.barcodescanner.ScanOptions
import kotlinx.coroutines.launch
-import org.meshtastic.core.analytics.DataPair
import org.meshtastic.core.model.Channel
import org.meshtastic.core.model.util.getChannelUrl
import org.meshtastic.core.model.util.qrCode
@@ -311,6 +309,7 @@ fun ChannelScreen(
EditChannelUrl(
enabled = enabled,
channelUrl = selectedChannelSet.getChannelUrl(shouldAdd = shouldAddChannelsState),
+ onTrackShare = viewModel::trackShare,
onConfirm = {
viewModel.requestChannelUrl(it) {
Toast.makeText(context, R.string.channel_invalid, Toast.LENGTH_SHORT).show()
@@ -368,7 +367,13 @@ fun ChannelScreen(
@Suppress("LongMethod")
@Composable
-private fun EditChannelUrl(enabled: Boolean, channelUrl: Uri, modifier: Modifier = Modifier, onConfirm: (Uri) -> Unit) {
+private fun EditChannelUrl(
+ enabled: Boolean,
+ channelUrl: Uri,
+ modifier: Modifier = Modifier,
+ onTrackShare: () -> Unit,
+ onConfirm: (Uri) -> Unit,
+) {
val focusManager = LocalFocusManager.current
val clipboardManager = LocalClipboard.current
val coroutineScope = rememberCoroutineScope()
@@ -416,7 +421,7 @@ private fun EditChannelUrl(enabled: Boolean, channelUrl: Uri, modifier: Modifier
else -> {
// track how many times users share channels
- analytics.track("share", DataPair("content_type", "channel"))
+ onTrackShare()
coroutineScope.launch {
clipboardManager.setClipEntry(
ClipEntry(ClipData.newPlainText(label, valueState.toString())),
diff --git a/app/src/main/java/com/geeksville/mesh/ui/sharing/ChannelViewModel.kt b/app/src/main/java/com/geeksville/mesh/ui/sharing/ChannelViewModel.kt
index 20ec42095..e7caee9c3 100644
--- a/app/src/main/java/com/geeksville/mesh/ui/sharing/ChannelViewModel.kt
+++ b/app/src/main/java/com/geeksville/mesh/ui/sharing/ChannelViewModel.kt
@@ -34,6 +34,8 @@ import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
+import org.meshtastic.core.analytics.DataPair
+import org.meshtastic.core.analytics.platform.PlatformAnalytics
import org.meshtastic.core.data.repository.RadioConfigRepository
import org.meshtastic.core.model.util.toChannelSet
import org.meshtastic.core.proto.getChannelList
@@ -47,6 +49,7 @@ class ChannelViewModel
constructor(
private val serviceRepository: ServiceRepository,
private val radioConfigRepository: RadioConfigRepository,
+ private val analytics: PlatformAnalytics,
) : ViewModel() {
val connectionState = serviceRepository.connectionState
@@ -121,6 +124,10 @@ constructor(
}
}
+ fun trackShare() {
+ analytics.track("share", DataPair("content_type", "channel"))
+ }
+
private inline fun updateLoraConfig(crossinline body: (Config.LoRaConfig) -> Config.LoRaConfig) {
val data = body(localConfig.value.lora)
setConfig(config { lora = data })