From 266b4c4dd750604b0637e7e74df386f1f39bbf98 Mon Sep 17 00:00:00 2001 From: Jobobby04 Date: Mon, 5 Dec 2022 14:57:33 -0500 Subject: [PATCH] Replace DebugOverlay library with a custom composable --- app/build.gradle.kts | 7 - app/src/main/java/eu/kanade/tachiyomi/App.kt | 25 -- .../kanade/tachiyomi/ui/main/MainActivity.kt | 14 ++ .../main/java/exh/log/EHDebugModeOverlay.kt | 218 +++++++++++++----- gradle/sy.versions.toml | 4 - 5 files changed, 173 insertions(+), 95 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 93332e870..f08392ecd 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -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) diff --git a/app/src/main/java/eu/kanade/tachiyomi/App.kt b/app/src/main/java/eu/kanade/tachiyomi/App.kt index bc0bef390..7bd489bca 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/App.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/App.kt @@ -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 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt index 5daecb9e7..d977fbc43 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt @@ -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 --> diff --git a/app/src/main/java/exh/log/EHDebugModeOverlay.kt b/app/src/main/java/exh/log/EHDebugModeOverlay.kt index 237dbb38f..9ecafcca8 100644 --- a/app/src/main/java/exh/log/EHDebugModeOverlay.kt +++ b/app/src/main/java/exh/log/EHDebugModeOverlay.kt @@ -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(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) { - observer.onDataAvailable(buildInfo()) - } - override fun removeObserver(observer: DataObserver) {} - 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() = - """ - ===[ ${context.getString(R.string.app_name)} ]===
- Build type: ${BuildConfig.BUILD_TYPE}
- Debug mode: ${BuildConfig.DEBUG.asEnabledString()}
- Version code: ${BuildConfig.VERSION_CODE}
- Commit SHA: ${BuildConfig.COMMIT_SHA}
- Log level: ${EHLogLevel.currentLogLevel.name.lowercase(Locale.getDefault())}
- Source blacklist: ${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().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 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 + } } diff --git a/gradle/sy.versions.toml b/gradle/sy.versions.toml index d4d281113..5849a2e63 100644 --- a/gradle/sy.versions.toml +++ b/gradle/sy.versions.toml @@ -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" \ No newline at end of file