Debug info

master
Zakhar Timoshenko 2 years ago
parent 4dbbd11bb9
commit 9436b36697
Signed by: Xtimms
SSH Key Fingerprint: SHA256:wH6spYepK/A5erBh7ZyAnr1ru9H4eaMVBEuiw6DSpxI

@ -1,3 +1,8 @@
import java.io.ByteArrayOutputStream
import java.text.SimpleDateFormat
import java.util.Date
import java.util.TimeZone
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
@ -19,6 +24,10 @@ android {
versionCode = 1
versionName = "1.0"
buildConfigField("String", "COMMIT_COUNT", "\"${getCommitCount()}\"")
buildConfigField("String", "COMMIT_SHA", "\"${getGitSha()}\"")
buildConfigField("String", "BUILD_TIME", "\"${getBuildTime()}\"")
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
useSupportLibrary = true
@ -79,6 +88,7 @@ dependencies {
implementation("androidx.compose.material3:material3-window-size-class:1.2.0-rc01")
implementation("androidx.hilt:hilt-navigation-compose:1.1.0")
implementation("androidx.navigation:navigation-compose:2.7.6")
implementation("androidx.profileinstaller:profileinstaller:1.3.1")
implementation("androidx.room:room-runtime:2.6.1")
implementation("androidx.room:room-ktx:2.6.1")
implementation("androidx.work:work-runtime-ktx:2.9.0")
@ -97,6 +107,7 @@ dependencies {
implementation("com.squareup.okio:okio:3.7.0")
implementation("com.tencent:mmkv:1.3.2")
implementation("org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.7")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-guava:1.7.3")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.2")
implementation("io.coil-kt:coil-compose:2.5.0")
testImplementation("junit:junit:4.13.2")
@ -107,3 +118,30 @@ dependencies {
debugImplementation("androidx.compose.ui:ui-tooling")
debugImplementation("androidx.compose.ui:ui-test-manifest")
}
// Git is needed in your system PATH for these commands to work.
// If it's not installed, you can return a random value as a workaround
fun Project.getCommitCount(): String {
return runCommand("git rev-list --count HEAD")
// return "1"
}
fun Project.getGitSha(): String {
return runCommand("git rev-parse --short HEAD")
// return "1"
}
fun Project.getBuildTime(): String {
val df = SimpleDateFormat("yyyy-MM-dd'T'HH:mm'Z'")
df.timeZone = TimeZone.getTimeZone("UTC")
return df.format(Date())
}
fun Project.runCommand(command: String): String {
val byteOut = ByteArrayOutputStream()
project.exec {
commandLine = command.split(" ")
standardOutput = byteOut
}
return String(byteOut.toByteArray()).trim()
}

@ -140,7 +140,8 @@ fun Navigation(
SettingsView(
navigateBack = navigateBack,
navigateToAppearance = { navController.navigate(APPEARANCE_DESTINATION) },
navigateToAbout = { navController.navigate(ABOUT_DESTINATION) }
navigateToAbout = { navController.navigate(ABOUT_DESTINATION) },
navigateToAdvanced = { navController.navigate(ADVANCED_DESTINATION) }
)
}
@ -165,6 +166,12 @@ fun Navigation(
)
}
composable(ADVANCED_DESTINATION) {
AdvancedView(
navigateBack = navigateBack,
)
}
composable(
route = LIST_DESTINATION,
arguments = listOf(

@ -121,8 +121,13 @@ fun PreferenceItem(
Column(
modifier = Modifier
.weight(1f)
.then(
if (icon != null)
Modifier
.padding(horizontal = 16.dp)
.padding(end = 8.dp)
else Modifier.padding(horizontal = 8.dp)
)
) {
PreferenceItemTitle(text = title, enabled = enabled)
if (!description.isNullOrEmpty()) PreferenceItemDescription(
@ -465,7 +470,8 @@ fun PreferenceSwitch(
)
}
Column(
modifier = Modifier.weight(1f)
modifier = Modifier
.weight(1f)
.padding(horizontal = 16.dp)
) {
PreferenceItemTitle(
@ -542,7 +548,7 @@ fun PreferencesHintCard(
@Preview
fun PreferenceItemPreview() {
Column {
PreferenceItem(title = "title", description = "description", icon = 0)
PreferenceItem(title = "title", description = "description")
PreferenceItem(title = "title", description = "description", icon = Icons.Outlined.Update)
}
}

@ -3,6 +3,7 @@ package org.xtimms.tokusho.sections.settings
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Code
import androidx.compose.material.icons.outlined.Info
import androidx.compose.material.icons.outlined.Palette
import androidx.compose.runtime.Composable
@ -19,6 +20,7 @@ fun SettingsView(
navigateBack: () -> Unit,
navigateToAppearance: () -> Unit,
navigateToAbout: () -> Unit,
navigateToAdvanced: () -> Unit
) {
ScaffoldWithTopAppBar(
title = stringResource(R.string.settings),
@ -36,6 +38,14 @@ fun SettingsView(
onClick = navigateToAppearance
)
}
item {
SettingItem(
title = stringResource(id = R.string.advanced),
description = stringResource(id = R.string.advanced_page),
icon = Icons.Outlined.Code,
onClick = navigateToAdvanced
)
}
item {
SettingItem(
title = stringResource(id = R.string.about),

@ -0,0 +1,142 @@
package org.xtimms.tokusho.sections.settings.advanced
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.runtime.Composable
import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.produceState
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.profileinstaller.ProfileVerifier
import kotlinx.coroutines.guava.await
import org.xtimms.tokusho.BuildConfig
import org.xtimms.tokusho.R
import org.xtimms.tokusho.core.components.PreferenceItem
import org.xtimms.tokusho.core.components.PreferenceSubtitle
import org.xtimms.tokusho.core.components.ScaffoldWithTopAppBar
import org.xtimms.tokusho.utils.WebViewUtil
import org.xtimms.tokusho.utils.lang.toDateTimestampString
import java.text.DateFormat
import java.text.SimpleDateFormat
import java.util.Locale
import java.util.TimeZone
const val ADVANCED_DESTINATION = "advanced"
@Composable
fun AdvancedView(
navigateBack: () -> Unit,
) {
ScaffoldWithTopAppBar(
title = stringResource(R.string.advanced),
navigateBack = navigateBack
) { padding ->
LazyColumn(
modifier = Modifier
.padding(padding)
) {
item {
PreferenceSubtitle(text = stringResource(id = R.string.app_info))
}
item {
PreferenceItem(
title = stringResource(id = R.string.app_version),
description = getVersionName(false)
)
}
item {
PreferenceItem(
title = stringResource(id = R.string.build_time),
description = getFormattedBuildTime()
)
}
item {
getProfileVerifierPreference()
}
item {
PreferenceItem(
title = stringResource(id = R.string.webview_version),
description = getWebViewVersion()
)
}
}
}
}
@Composable
@ReadOnlyComposable
private fun getWebViewVersion(): String {
return WebViewUtil.getVersion(LocalContext.current)
}
@Composable
private fun getProfileVerifierPreference() {
val status by produceState(initialValue = "-") {
val result = ProfileVerifier.getCompilationStatusAsync().await().profileInstallResultCode
value = when (result) {
ProfileVerifier.CompilationStatus.RESULT_CODE_NO_PROFILE -> "No profile installed"
ProfileVerifier.CompilationStatus.RESULT_CODE_COMPILED_WITH_PROFILE -> "Compiled"
ProfileVerifier.CompilationStatus.RESULT_CODE_COMPILED_WITH_PROFILE_NON_MATCHING ->
"Compiled non-matching"
ProfileVerifier.CompilationStatus.RESULT_CODE_ERROR_CACHE_FILE_EXISTS_BUT_CANNOT_BE_READ,
ProfileVerifier.CompilationStatus.RESULT_CODE_ERROR_CANT_WRITE_PROFILE_VERIFICATION_RESULT_CACHE_FILE,
ProfileVerifier.CompilationStatus.RESULT_CODE_ERROR_PACKAGE_NAME_DOES_NOT_EXIST,
-> "Error $result"
ProfileVerifier.CompilationStatus.RESULT_CODE_ERROR_UNSUPPORTED_API_VERSION -> "Not supported"
ProfileVerifier.CompilationStatus.RESULT_CODE_PROFILE_ENQUEUED_FOR_COMPILATION -> "Pending compilation"
else -> "Unknown code $result"
}
}
return PreferenceItem(
title = "Profile compilation status",
description = status,
)
}
fun getVersionName(withBuildDate: Boolean): String {
return when {
BuildConfig.DEBUG -> {
"Debug ${BuildConfig.COMMIT_SHA}".let {
if (withBuildDate) {
"$it (${getFormattedBuildTime()})"
} else {
it
}
}
}
else -> {
"Stable ${BuildConfig.VERSION_NAME}".let {
if (withBuildDate) {
"$it (${getFormattedBuildTime()})"
} else {
it
}
}
}
}
}
internal fun getFormattedBuildTime(): String {
return try {
val inputDf = SimpleDateFormat("yyyy-MM-dd'T'HH:mm'Z'", Locale.US)
inputDf.timeZone = TimeZone.getTimeZone("UTC")
val buildTime = inputDf.parse(BuildConfig.BUILD_TIME)
val outputDf = DateFormat.getDateTimeInstance(
DateFormat.MEDIUM,
DateFormat.SHORT,
Locale.getDefault(),
)
outputDf.timeZone = TimeZone.getDefault()
buildTime!!.toDateTimestampString(DateFormat.getDateTimeInstance())
} catch (e: Exception) {
BuildConfig.BUILD_TIME
}
}

@ -0,0 +1,16 @@
package org.xtimms.tokusho.utils
import android.content.Context
import android.webkit.WebView
object WebViewUtil {
fun getVersion(context: Context): String {
val webView = WebView.getCurrentWebViewPackage() ?: return "o_O"
val pm = context.packageManager
val label = webView.applicationInfo.loadLabel(pm)
val version = webView.versionName
return "$label $version"
}
}

@ -0,0 +1,10 @@
package org.xtimms.tokusho.utils.lang
import java.text.DateFormat
import java.util.Date
fun Date.toDateTimestampString(dateFormatter: DateFormat): String {
val date = dateFormatter.format(this)
val time = DateFormat.getTimeInstance(DateFormat.SHORT).format(this)
return "$date $time"
}

@ -73,4 +73,10 @@
<string name="manga_info_expand">More</string>
<string name="action_copy_to_clipboard">Copy to clipboard</string>
<string name="description_placeholder">No description</string>
<string name="advanced">Advanced</string>
<string name="app_info">App info</string>
<string name="app_version">App version</string>
<string name="build_time">Build time</string>
<string name="webview_version">WebView version</string>
<string name="advanced_page">Dump crash logs, debug info</string>
</resources>
Loading…
Cancel
Save