Improve loading on Android, switch to posthog
This commit is contained in:
@ -144,7 +144,7 @@ dependencies {
|
|||||||
implementation 'com.google.code.gson:gson:2.8.9'
|
implementation 'com.google.code.gson:gson:2.8.9'
|
||||||
implementation 'com.pspdfkit:pspdfkit:8.4.1'
|
implementation 'com.pspdfkit:pspdfkit:8.4.1'
|
||||||
|
|
||||||
implementation 'com.segment.analytics.kotlin:android:1.10.0'
|
implementation 'com.posthog.android:posthog:1.+'
|
||||||
implementation 'io.intercom.android:intercom-sdk:15.1.0'
|
implementation 'io.intercom.android:intercom-sdk:15.1.0'
|
||||||
|
|
||||||
// Room Deps
|
// Room Deps
|
||||||
|
|||||||
@ -1,36 +1,34 @@
|
|||||||
package app.omnivore.omnivore
|
package app.omnivore.omnivore
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import com.segment.analytics.kotlin.android.Analytics
|
import com.posthog.android.PostHog
|
||||||
import com.segment.analytics.kotlin.core.*
|
import com.posthog.android.Properties
|
||||||
import io.intercom.android.sdk.Intercom
|
import io.intercom.android.sdk.Intercom
|
||||||
import io.intercom.android.sdk.identity.Registration
|
import io.intercom.android.sdk.identity.Registration
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
|
||||||
class EventTracker @Inject constructor(val app: Context) {
|
class EventTracker @Inject constructor(val app: Context) {
|
||||||
val segmentAnalytics: Analytics
|
private val posthog: PostHog
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val writeKey = app.getString(R.string.segment_write_key)
|
val posthogClientKey = app.getString(R.string.posthog_client_key)
|
||||||
|
val posthogInstanceAddress = app.getString(R.string.posthog_instance_address)
|
||||||
|
|
||||||
segmentAnalytics = Analytics(writeKey, app.applicationContext) {
|
posthog = PostHog.Builder(app, posthogClientKey, posthogInstanceAddress)
|
||||||
trackApplicationLifecycleEvents = true
|
.captureApplicationLifecycleEvents()
|
||||||
application = app.applicationContext
|
.build()
|
||||||
useLifecycleObserver = true
|
|
||||||
}
|
PostHog.setSingletonInstance(posthog)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun registerUser(userID: String) {
|
fun registerUser(userID: String) {
|
||||||
segmentAnalytics.identify(userID)
|
posthog.identify(userID)
|
||||||
Intercom.client().loginIdentifiedUser(Registration.create().withUserId(userID))
|
Intercom.client().loginIdentifiedUser(Registration.create().withUserId(userID))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun debugMessage(message: String) {
|
fun track(eventName: String, properties: Properties = Properties()) {
|
||||||
track(message)
|
posthog.capture(eventName, properties)
|
||||||
}
|
|
||||||
|
|
||||||
fun track(eventName: String, jsonObject: JSONObject = JSONObject()) {
|
|
||||||
segmentAnalytics.track(eventName, jsonObject)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,6 +13,7 @@ import android.webkit.JavascriptInterface
|
|||||||
import android.webkit.WebResourceRequest
|
import android.webkit.WebResourceRequest
|
||||||
import android.webkit.WebView
|
import android.webkit.WebView
|
||||||
import android.webkit.WebViewClient
|
import android.webkit.WebViewClient
|
||||||
|
import androidx.compose.foundation.isSystemInDarkTheme
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
@ -35,6 +36,7 @@ fun WebReader(
|
|||||||
val javascriptActionLoopUUID: UUID by webReaderViewModel
|
val javascriptActionLoopUUID: UUID by webReaderViewModel
|
||||||
.javascriptActionLoopUUIDLiveData
|
.javascriptActionLoopUUIDLiveData
|
||||||
.observeAsState(UUID.randomUUID())
|
.observeAsState(UUID.randomUUID())
|
||||||
|
val isDarkMode = isSystemInDarkTheme()
|
||||||
|
|
||||||
WebView.setWebContentsDebuggingEnabled(true)
|
WebView.setWebContentsDebuggingEnabled(true)
|
||||||
|
|
||||||
@ -56,7 +58,19 @@ fun WebReader(
|
|||||||
alpha = 1.0f
|
alpha = 1.0f
|
||||||
viewModel?.showNavBar()
|
viewModel?.showNavBar()
|
||||||
currentTheme?.let { theme ->
|
currentTheme?.let { theme ->
|
||||||
setBackgroundColor(theme.backgroundColor.toInt());
|
val bg = when (theme) {
|
||||||
|
Themes.SYSTEM -> {
|
||||||
|
if (isDarkMode) {
|
||||||
|
Color.BLACK
|
||||||
|
} else {
|
||||||
|
Color.WHITE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
theme.backgroundColor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setBackgroundColor(bg.toInt());
|
||||||
}
|
}
|
||||||
|
|
||||||
webViewClient = object : WebViewClient() {
|
webViewClient = object : WebViewClient() {
|
||||||
|
|||||||
@ -58,6 +58,8 @@ class WebReaderLoadingContainerActivity: ComponentActivity() {
|
|||||||
val requestID = intent.getStringExtra("SAVED_ITEM_REQUEST_ID")
|
val requestID = intent.getStringExtra("SAVED_ITEM_REQUEST_ID")
|
||||||
val slug = intent.getStringExtra("SAVED_ITEM_SLUG")
|
val slug = intent.getStringExtra("SAVED_ITEM_SLUG")
|
||||||
|
|
||||||
|
viewModel.loadItem(slug = slug, requestID = requestID)
|
||||||
|
|
||||||
setContent {
|
setContent {
|
||||||
val systemUiController = rememberSystemUiController()
|
val systemUiController = rememberSystemUiController()
|
||||||
val useDarkIcons = !isSystemInDarkTheme()
|
val useDarkIcons = !isSystemInDarkTheme()
|
||||||
@ -140,7 +142,6 @@ fun WebReaderLoadingContainer(slug: String? = null, requestID: String? = null,
|
|||||||
|
|
||||||
val maxToolbarHeight = 48.dp
|
val maxToolbarHeight = 48.dp
|
||||||
webReaderViewModel.maxToolbarHeightPx = with(LocalDensity.current) { maxToolbarHeight.roundToPx().toFloat() }
|
webReaderViewModel.maxToolbarHeightPx = with(LocalDensity.current) { maxToolbarHeight.roundToPx().toFloat() }
|
||||||
webReaderViewModel.loadItem(slug = slug, requestID = requestID)
|
|
||||||
|
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
|
|
||||||
|
|||||||
@ -7,11 +7,11 @@ import android.content.Intent
|
|||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.compose.ui.platform.LocalContext
|
|
||||||
import androidx.core.content.ContextCompat.startActivity
|
import androidx.core.content.ContextCompat.startActivity
|
||||||
import androidx.lifecycle.*
|
import androidx.lifecycle.*
|
||||||
import app.omnivore.omnivore.DatastoreKeys
|
import app.omnivore.omnivore.DatastoreKeys
|
||||||
import app.omnivore.omnivore.DatastoreRepository
|
import app.omnivore.omnivore.DatastoreRepository
|
||||||
|
import app.omnivore.omnivore.EventTracker
|
||||||
import app.omnivore.omnivore.dataService.*
|
import app.omnivore.omnivore.dataService.*
|
||||||
import app.omnivore.omnivore.graphql.generated.type.CreateLabelInput
|
import app.omnivore.omnivore.graphql.generated.type.CreateLabelInput
|
||||||
import app.omnivore.omnivore.graphql.generated.type.SetLabelsInput
|
import app.omnivore.omnivore.graphql.generated.type.SetLabelsInput
|
||||||
@ -20,7 +20,6 @@ import app.omnivore.omnivore.networking.*
|
|||||||
import app.omnivore.omnivore.persistence.entities.SavedItem
|
import app.omnivore.omnivore.persistence.entities.SavedItem
|
||||||
import app.omnivore.omnivore.persistence.entities.SavedItemAndSavedItemLabelCrossRef
|
import app.omnivore.omnivore.persistence.entities.SavedItemAndSavedItemLabelCrossRef
|
||||||
import app.omnivore.omnivore.persistence.entities.SavedItemLabel
|
import app.omnivore.omnivore.persistence.entities.SavedItemLabel
|
||||||
import app.omnivore.omnivore.ui.components.LabelSwatchHelper
|
|
||||||
import app.omnivore.omnivore.ui.library.SavedItemAction
|
import app.omnivore.omnivore.ui.library.SavedItemAction
|
||||||
import com.apollographql.apollo3.api.Optional
|
import com.apollographql.apollo3.api.Optional
|
||||||
import com.apollographql.apollo3.api.Optional.Companion.presentIfNotNull
|
import com.apollographql.apollo3.api.Optional.Companion.presentIfNotNull
|
||||||
@ -28,9 +27,6 @@ import com.google.gson.Gson
|
|||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
import java.time.LocalDate
|
|
||||||
import java.time.ZoneOffset
|
|
||||||
import java.time.format.DateTimeFormatter
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@ -46,7 +42,7 @@ data class AnnotationWebViewMessage(
|
|||||||
)
|
)
|
||||||
|
|
||||||
enum class Themes(val themeKey: String, val backgroundColor: Long, val foregroundColor: Long) {
|
enum class Themes(val themeKey: String, val backgroundColor: Long, val foregroundColor: Long) {
|
||||||
SYSTEM("System", 0xFFFFFFFF, 0xFF000000),
|
SYSTEM("System", 0xFF000000, 0xFF000000),
|
||||||
LIGHT("Light", 0xFFFFFFFF, 0xFF000000),
|
LIGHT("Light", 0xFFFFFFFF, 0xFF000000),
|
||||||
SEPIA("Sepia", 0xFFFBF0D9, 0xFF000000),
|
SEPIA("Sepia", 0xFFFBF0D9, 0xFF000000),
|
||||||
DARK("Dark", 0xFF2F3030, 0xFFFFFFFF),
|
DARK("Dark", 0xFF2F3030, 0xFFFFFFFF),
|
||||||
@ -58,7 +54,8 @@ enum class Themes(val themeKey: String, val backgroundColor: Long, val foregroun
|
|||||||
class WebReaderViewModel @Inject constructor(
|
class WebReaderViewModel @Inject constructor(
|
||||||
private val datastoreRepo: DatastoreRepository,
|
private val datastoreRepo: DatastoreRepository,
|
||||||
private val dataService: DataService,
|
private val dataService: DataService,
|
||||||
private val networker: Networker
|
private val networker: Networker,
|
||||||
|
private val eventTracker: EventTracker,
|
||||||
): ViewModel() {
|
): ViewModel() {
|
||||||
var lastJavascriptActionLoopUUID: UUID = UUID.randomUUID()
|
var lastJavascriptActionLoopUUID: UUID = UUID.randomUUID()
|
||||||
var javascriptDispatchQueue: MutableList<String> = mutableListOf()
|
var javascriptDispatchQueue: MutableList<String> = mutableListOf()
|
||||||
@ -174,6 +171,13 @@ class WebReaderViewModel @Inject constructor(
|
|||||||
|
|
||||||
if (webReaderParams != null) {
|
if (webReaderParams != null) {
|
||||||
Log.d("reader", "data loaded from server")
|
Log.d("reader", "data loaded from server")
|
||||||
|
eventTracker.track("link_read",
|
||||||
|
com.posthog.android.Properties()
|
||||||
|
.putValue("linkID", webReaderParams.item.savedItemId)
|
||||||
|
.putValue("slug", webReaderParams.item.slug)
|
||||||
|
.putValue("originalArticleURL", webReaderParams.item.pageURLString)
|
||||||
|
.putValue("loaded_from", "network")
|
||||||
|
)
|
||||||
webReaderParamsLiveData.postValue(webReaderParams)
|
webReaderParamsLiveData.postValue(webReaderParams)
|
||||||
isLoading = false
|
isLoading = false
|
||||||
}
|
}
|
||||||
@ -185,6 +189,13 @@ class WebReaderViewModel @Inject constructor(
|
|||||||
|
|
||||||
if (webReaderParams != null && isSuccessful) {
|
if (webReaderParams != null && isSuccessful) {
|
||||||
this.slug = webReaderParams.item.slug
|
this.slug = webReaderParams.item.slug
|
||||||
|
eventTracker.track("link_read",
|
||||||
|
com.posthog.android.Properties()
|
||||||
|
.putValue("linkID", webReaderParams.item.savedItemId)
|
||||||
|
.putValue("slug", webReaderParams.item.slug)
|
||||||
|
.putValue("originalArticleURL", webReaderParams.item.pageURLString)
|
||||||
|
.putValue("loaded_from", "request_id")
|
||||||
|
)
|
||||||
webReaderParamsLiveData.postValue(webReaderParams)
|
webReaderParamsLiveData.postValue(webReaderParams)
|
||||||
isLoading = false
|
isLoading = false
|
||||||
} else if (requestCount < 7) {
|
} else if (requestCount < 7) {
|
||||||
@ -210,14 +221,21 @@ class WebReaderViewModel @Inject constructor(
|
|||||||
labelsJSONString = Gson().toJson(persistedItem.labels)
|
labelsJSONString = Gson().toJson(persistedItem.labels)
|
||||||
)
|
)
|
||||||
|
|
||||||
Log.d("sync", "data loaded from db")
|
val webReaderParams = WebReaderParams(
|
||||||
webReaderParamsLiveData.postValue(
|
persistedItem.savedItem,
|
||||||
WebReaderParams(
|
articleContent,
|
||||||
persistedItem.savedItem,
|
persistedItem.labels
|
||||||
articleContent,
|
|
||||||
persistedItem.labels
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Log.d("sync", "data loaded from db")
|
||||||
|
eventTracker.track("link_read",
|
||||||
|
com.posthog.android.Properties()
|
||||||
|
.putValue("linkID", webReaderParams.item.savedItemId)
|
||||||
|
.putValue("slug", webReaderParams.item.slug)
|
||||||
|
.putValue("originalArticleURL", webReaderParams.item.pageURLString)
|
||||||
|
.putValue("loaded_from", "db")
|
||||||
|
)
|
||||||
|
webReaderParamsLiveData.postValue(webReaderParams)
|
||||||
}
|
}
|
||||||
isLoading = false
|
isLoading = false
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="pspdfkit_license_key">unset</string>
|
<string name="pspdfkit_license_key">unset</string>
|
||||||
<string name="segment_write_key">unset</string>
|
<string name="posthog_client_key">unset</string>
|
||||||
|
<string name="posthog_instance_address">unset</string>
|
||||||
<string name="intercom_api_key">unset</string>
|
<string name="intercom_api_key">unset</string>
|
||||||
<string name="intercom_app_id">unset</string>
|
<string name="intercom_app_id">unset</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
Reference in New Issue
Block a user