Replace DebugOverlay library with a custom composable

This commit is contained in:
Jobobby04 2022-12-05 14:57:33 -05:00
parent 0663928b6b
commit 266b4c4dd7
5 changed files with 173 additions and 95 deletions

View File

@ -298,13 +298,6 @@ dependencies {
// Better logging (EH)
implementation(sylibs.xlog)
// Debug utils (EH)
debugImplementation(sylibs.debugOverlay.standard)
"releaseTestImplementation"(sylibs.debugOverlay.noop)
"benchmarkImplementation"(sylibs.debugOverlay.noop)
releaseImplementation(sylibs.debugOverlay.noop)
testImplementation(sylibs.debugOverlay.noop)
// RatingBar (SY)
implementation(sylibs.ratingbar)
implementation(sylibs.composeRatingbar)

View File

@ -8,7 +8,6 @@ import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.graphics.Color
import android.os.Build
import android.os.Environment
import android.os.Looper
@ -36,8 +35,6 @@ import com.elvishew.xlog.printer.file.clean.FileLastModifiedCleanStrategy
import com.elvishew.xlog.printer.file.naming.DateFileNameGenerator
import com.google.firebase.analytics.ktx.analytics
import com.google.firebase.ktx.Firebase
import com.ms_square.debugoverlay.DebugOverlay
import com.ms_square.debugoverlay.modules.FpsModule
import eu.kanade.data.DatabaseHandler
import eu.kanade.domain.DomainModule
import eu.kanade.domain.SYDomainModule
@ -63,14 +60,11 @@ import eu.kanade.tachiyomi.util.system.animatorDurationScale
import eu.kanade.tachiyomi.util.system.isPreviewBuildType
import eu.kanade.tachiyomi.util.system.logcat
import eu.kanade.tachiyomi.util.system.notification
import exh.debug.DebugToggles
import exh.log.CrashlyticsPrinter
import exh.log.EHDebugModeOverlay
import exh.log.EHLogLevel
import exh.log.EnhancedFilePrinter
import exh.log.XLogLogcatLogger
import exh.log.xLogD
import exh.log.xLogE
import exh.syDebugVersion
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.distinctUntilChanged
@ -126,9 +120,6 @@ class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory {
// SY <--
setupNotificationChannels()
if ((BuildConfig.DEBUG || BuildConfig.BUILD_TYPE == "releaseTest") && DebugToggles.ENABLE_DEBUG_OVERLAY.enabled) {
setupDebugOverlay()
}
ProcessLifecycleOwner.get().lifecycle.addObserver(this)
@ -327,22 +318,6 @@ class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory {
)
}
// EXH
private fun setupDebugOverlay() {
try {
DebugOverlay.Builder(this)
.modules(FpsModule(), EHDebugModeOverlay(this))
.bgColor(Color.parseColor("#7F000000"))
.notification(false)
.allowSystemLayer(false)
.build()
.install()
} catch (e: IllegalStateException) {
// Crashes if app is in background
xLogE("Failed to initialize debug overlay, app in background?", e)
}
}
private inner class DisableIncognitoReceiver : BroadcastReceiver() {
private var registered = false

View File

@ -65,7 +65,9 @@ import eu.kanade.tachiyomi.util.system.toast
import eu.kanade.tachiyomi.util.view.setComposeContent
import eu.kanade.tachiyomi.util.view.setNavigationBarTransparentCompat
import exh.EXHMigrations
import exh.debug.DebugToggles
import exh.eh.EHentaiUpdateWorker
import exh.log.DebugModeOverlay
import exh.source.BlacklistedSources
import exh.source.EH_SOURCE_ID
import exh.source.EXH_SOURCE_ID
@ -162,6 +164,9 @@ class MainActivity : BaseActivity() {
return
}
@Suppress("KotlinConstantConditions")
val hasDebugOverlay = (BuildConfig.DEBUG || BuildConfig.BUILD_TYPE == "releaseTest")
// Draw edge-to-edge
WindowCompat.setDecorFitsSystemWindows(window, false)
@ -206,6 +211,15 @@ class MainActivity : BaseActivity() {
CheckForUpdate()
}
if (hasDebugOverlay) {
val isDebugOverlayEnabled by remember {
DebugToggles.ENABLE_DEBUG_OVERLAY.asPref(lifecycleScope)
}
if (isDebugOverlayEnabled) {
DebugModeOverlay()
}
}
var showChangelog by remember { mutableStateOf(didMigration && !BuildConfig.DEBUG) }
if (showChangelog) {
// SY -->

View File

@ -1,70 +1,170 @@
package exh.log
import android.content.Context
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import android.widget.TextView
import androidx.core.text.HtmlCompat
import com.ms_square.debugoverlay.DataObserver
import com.ms_square.debugoverlay.OverlayModule
import android.view.Choreographer
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.navigationBars
import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.RememberObserver
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.withStyle
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import eu.kanade.core.prefs.asState
import eu.kanade.domain.source.service.SourcePreferences
import eu.kanade.tachiyomi.BuildConfig
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.util.system.dpToPx
import uy.kohesive.injekt.injectLazy
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import java.text.DecimalFormat
import java.text.DecimalFormatSymbols
import java.util.Locale
import kotlin.time.Duration.Companion.nanoseconds
class EHDebugModeOverlay(private val context: Context) : OverlayModule<String>(null, null) {
private var textView: TextView? = null
private val preferences: SourcePreferences by injectLazy()
override fun start() {}
override fun stop() {}
override fun notifyObservers() {}
override fun addObserver(observer: DataObserver<Any>) {
observer.onDataAvailable(buildInfo())
}
override fun removeObserver(observer: DataObserver<Any>) {}
override fun onDataAvailable(data: String?) {
textView?.text = HtmlCompat.fromHtml(data.orEmpty(), HtmlCompat.FROM_HTML_MODE_LEGACY)
}
override fun createView(root: ViewGroup, textColor: Int, textSize: Float, textAlpha: Float): View {
val view = LinearLayout(root.context).apply {
layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT,
)
setPadding(4.dpToPx, 0, 4.dpToPx, 4.dpToPx)
@Composable
fun DebugModeOverlay() {
Box(Modifier.fillMaxSize()) {
Column(
Modifier
.windowInsetsPadding(
WindowInsets.navigationBars
.only(WindowInsetsSides.Bottom.plus(WindowInsetsSides.Start)),
)
.align(Alignment.BottomStart)
.background(Color(0x7F000000))
.padding(4.dp),
) {
FpsDebugModeOverlay()
EHDebugModeOverlay()
}
val textView = TextView(view.context).apply {
setTextColor(textColor)
this.textSize = textSize
alpha = textAlpha
text = HtmlCompat.fromHtml(buildInfo(), HtmlCompat.FROM_HTML_MODE_LEGACY)
layoutParams = LinearLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT,
)
}
view.addView(textView)
this.textView = textView
return view
}
private fun buildInfo() =
"""
<font color='green'>===[ ${context.getString(R.string.app_name)} ]===</font><br>
<b>Build type:</b> ${BuildConfig.BUILD_TYPE}<br>
<b>Debug mode:</b> ${BuildConfig.DEBUG.asEnabledString()}<br>
<b>Version code:</b> ${BuildConfig.VERSION_CODE}<br>
<b>Commit SHA:</b> ${BuildConfig.COMMIT_SHA}<br>
<b>Log level:</b> ${EHLogLevel.currentLogLevel.name.lowercase(Locale.getDefault())}<br>
<b>Source blacklist:</b> ${preferences.enableSourceBlacklist().get().asEnabledString()}
""".trimIndent()
private fun Boolean.asEnabledString() = if (this) "enabled" else "disabled"
}
@Composable
private fun FpsDebugModeOverlay() {
val fps by remember { FpsState(FpsState.DEFAULT_INTERVAL) }
val format = remember {
DecimalFormat(
"'fps:' 0.0",
DecimalFormatSymbols.getInstance(Locale.ENGLISH),
)
}
Text(
text = remember(fps) {
format.format(fps)
},
color = Color.White,
fontSize = 12.sp,
fontFamily = FontFamily.Monospace,
)
}
@Composable
private fun EHDebugModeOverlay() {
val scope = rememberCoroutineScope()
val enableSourceBlacklist by remember {
Injekt.get<SourcePreferences>().enableSourceBlacklist().asState(scope)
}
val context = LocalContext.current
Text(
text = remember(enableSourceBlacklist) {
buildInfo(context, enableSourceBlacklist)
},
color = Color.White,
fontSize = 12.sp,
lineHeight = 14.sp,
letterSpacing = 0.1f.sp,
)
}
private fun buildInfo(context: Context, sourceBlacklist: Boolean) = buildAnnotatedString {
withStyle(SpanStyle(color = Color.Green)) {
append("===[ ")
append(context.getString(R.string.app_name))
append(" ]===")
}
append('\n')
appendItem("Build type:", BuildConfig.BUILD_TYPE)
appendItem("Debug mode:", BuildConfig.DEBUG.asEnabledString())
appendItem("Version code:", BuildConfig.VERSION_CODE.toString())
appendItem("Commit SHA:", BuildConfig.COMMIT_SHA)
appendItem("Log level:", EHLogLevel.currentLogLevel.name.lowercase(Locale.getDefault()))
appendItem("Source blacklist:", sourceBlacklist.asEnabledString(), newLine = false)
}
fun AnnotatedString.Builder.appendItem(title: String, item: String, newLine: Boolean = true) {
withStyle(SpanStyle(fontWeight = FontWeight.Bold)) {
append(title)
}
append(' ')
append(item)
if (newLine) {
append('\n')
}
}
private fun Boolean.asEnabledString() = if (this) "enabled" else "disabled"
private class FpsState(private val interval: Int) :
Choreographer.FrameCallback,
RememberObserver,
MutableState<Double> by mutableStateOf(0.0) {
private val choreographer = Choreographer.getInstance()
private var startFrameTimeMillis: Long = 0
private var numFramesRendered = 0
override fun onRemembered() {
choreographer.postFrameCallback(this)
}
override fun onAbandoned() {
choreographer.removeFrameCallback(this)
}
override fun onForgotten() {
choreographer.removeFrameCallback(this)
}
override fun doFrame(frameTimeNanos: Long) {
val currentFrameTimeMillis = frameTimeNanos.nanoseconds.inWholeMilliseconds
if (startFrameTimeMillis > 0) {
val duration = currentFrameTimeMillis - startFrameTimeMillis
numFramesRendered++
if (duration > interval) {
value = (numFramesRendered * 1000f / duration).toDouble()
startFrameTimeMillis = currentFrameTimeMillis
numFramesRendered = 0
}
} else {
startFrameTimeMillis = currentFrameTimeMillis
}
choreographer.postFrameCallback(this)
}
companion object {
const val DEFAULT_INTERVAL = 1000
}
}

View File

@ -1,5 +1,4 @@
[versions]
debugOverlay = "1.1.3"
[libraries]
firebase-analytics = "com.google.firebase:firebase-analytics-ktx:21.0.0"
@ -9,8 +8,5 @@ firebase-crashlytics-gradle = "com.google.firebase:firebase-crashlytics-gradle:2
simularity = "info.debatty:java-string-similarity:2.0.0"
xlog = "com.elvishew:xlog:1.11.0"
debugOverlay-standard = { module = "com.ms-square:debugoverlay", version.ref = "debugOverlay" }
debugOverlay-noop = { module = "com.ms-square:debugoverlay-no-op", version.ref = "debugOverlay" }
ratingbar = "me.zhanghai.android.materialratingbar:library:1.4.0"
composeRatingbar = "com.github.a914-gowtham:compose-ratingbar:1.2.3"