forked from geode-sdk/android-launcher
add support for text based crash dumps
This commit is contained in:
7 files changed
+53
-22
No files matched your search
@@ -103,7 +103,7 @@
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".preferences.GeodeLogViewActivity"
|
||||
android:name=".preferences.TextViewActivity"
|
||||
android:exported="false"
|
||||
android:theme="@style/Theme.GeodeLauncher">
|
||||
</activity>
|
||||
|
||||
@@ -13,7 +13,8 @@ import kotlin.time.Instant
|
||||
|
||||
data class CrashDump(
|
||||
val filename: String,
|
||||
val lastModified: Instant
|
||||
val lastModified: Instant,
|
||||
val fullPath: String,
|
||||
)
|
||||
|
||||
class CrashViewModel(crashDirectory: File) : BaseDirectoryViewModel<CrashDump>(crashDirectory) {
|
||||
@@ -41,16 +42,19 @@ class CrashViewModel(crashDirectory: File) : BaseDirectoryViewModel<CrashDump>(c
|
||||
|
||||
val children = crashDirectory.listFiles {
|
||||
// ignore indicator files (including old file)
|
||||
_, name -> name != LaunchUtils.CRASH_INDICATOR_NAME && name != "last-pid"
|
||||
_, name -> !LaunchUtils.CRASH_INDICATOR_NAMES.contains(name)
|
||||
} ?: return emptyList()
|
||||
|
||||
hasIndicator = File(crashDirectory, LaunchUtils.CRASH_INDICATOR_NAME).exists()
|
||||
hasIndicator = LaunchUtils.CRASH_INDICATOR_NAMES.any {
|
||||
File(crashDirectory, it).exists()
|
||||
}
|
||||
|
||||
return children
|
||||
.map {
|
||||
CrashDump(
|
||||
filename = it.name,
|
||||
lastModified = Instant.fromEpochMilliseconds(it.lastModified())
|
||||
lastModified = Instant.fromEpochMilliseconds(it.lastModified()),
|
||||
fullPath = it.path,
|
||||
)
|
||||
}
|
||||
.sortedByDescending { it.lastModified }
|
||||
@@ -58,7 +62,12 @@ class CrashViewModel(crashDirectory: File) : BaseDirectoryViewModel<CrashDump>(c
|
||||
|
||||
fun clearIndicator() {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
File(baseDirectory, LaunchUtils.CRASH_INDICATOR_NAME).delete()
|
||||
LaunchUtils.CRASH_INDICATOR_NAMES.forEach {
|
||||
val crashFile = File(baseDirectory, it)
|
||||
if (crashFile.exists()) {
|
||||
crashFile.delete()
|
||||
}
|
||||
}
|
||||
|
||||
hasIndicator = false
|
||||
}
|
||||
@@ -66,7 +75,8 @@ class CrashViewModel(crashDirectory: File) : BaseDirectoryViewModel<CrashDump>(c
|
||||
|
||||
fun createIndicator() {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
File(baseDirectory, LaunchUtils.CRASH_INDICATOR_NAME).createNewFile()
|
||||
val crashFile = File(baseDirectory, LaunchUtils.CRASH_INDICATOR_NAMES.first())
|
||||
crashFile.createNewFile()
|
||||
|
||||
hasIndicator = true
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ data class GeodeLog(
|
||||
val filename: String,
|
||||
val lastModified: Instant,
|
||||
val fileSize: Long,
|
||||
val fullPath: String,
|
||||
)
|
||||
|
||||
class GeodeLogsViewModel(crashDirectory: File) : BaseDirectoryViewModel<GeodeLog>(crashDirectory) {
|
||||
@@ -43,7 +44,8 @@ class GeodeLogsViewModel(crashDirectory: File) : BaseDirectoryViewModel<GeodeLog
|
||||
GeodeLog(
|
||||
filename = it.name,
|
||||
lastModified = Instant.fromEpochMilliseconds(it.lastModified()),
|
||||
fileSize = it.length()
|
||||
fileSize = it.length(),
|
||||
fullPath = it.path,
|
||||
)
|
||||
}
|
||||
.sortedByDescending { it.lastModified }
|
||||
|
||||
@@ -12,6 +12,7 @@ import androidx.activity.OnBackPressedDispatcher
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
@@ -110,11 +111,20 @@ fun shareCrash(context: Context, filename: String) {
|
||||
|
||||
@Composable
|
||||
fun CrashCard(crashDump: CrashDump, crashViewModel: CrashViewModel, modifier: Modifier = Modifier) {
|
||||
val isReadable = crashDump.filename.endsWith(".txt")
|
||||
val context = LocalContext.current
|
||||
|
||||
Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 1.dp, horizontal = 8.dp)
|
||||
.height(64.dp)
|
||||
.then(modifier)
|
||||
.clickable(isReadable) {
|
||||
val launchIntent = Intent(context, TextViewActivity::class.java).run {
|
||||
putExtra(TextViewActivity.EXTRA_LOG_VIEW_FILENAME, crashDump.fullPath)
|
||||
}
|
||||
context.startActivity(launchIntent)
|
||||
}
|
||||
.background(MaterialTheme.colorScheme.surfaceContainerLow)
|
||||
.padding(vertical = 8.dp, horizontal = 8.dp)
|
||||
) {
|
||||
|
||||
@@ -117,8 +117,8 @@ fun GeodeLogCard(geodeLog: GeodeLog, geodeLogsViewModel: GeodeLogsViewModel, mod
|
||||
.height(64.dp)
|
||||
.then(modifier)
|
||||
.clickable {
|
||||
val launchIntent = Intent(context, GeodeLogViewActivity::class.java).run {
|
||||
putExtra(GeodeLogViewActivity.EXTRA_LOG_VIEW_FILENAME, geodeLog.filename)
|
||||
val launchIntent = Intent(context, TextViewActivity::class.java).run {
|
||||
putExtra(TextViewActivity.EXTRA_LOG_VIEW_FILENAME, geodeLog.fullPath)
|
||||
}
|
||||
context.startActivity(launchIntent)
|
||||
}
|
||||
|
||||
+16
-7
@@ -12,7 +12,6 @@ import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.safeDrawingPadding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.text.selection.SelectionContainer
|
||||
@@ -40,18 +39,19 @@ import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.geode.launcher.R
|
||||
import com.geode.launcher.log.GeodeLogsViewModel
|
||||
import com.geode.launcher.ui.theme.GeodeLauncherTheme
|
||||
import com.geode.launcher.ui.theme.LocalTheme
|
||||
import com.geode.launcher.ui.theme.Theme
|
||||
import com.geode.launcher.ui.theme.Typography
|
||||
import com.geode.launcher.ui.theme.robotoMonoFamily
|
||||
import com.geode.launcher.utils.PreferenceUtils
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.File
|
||||
|
||||
|
||||
class GeodeLogViewActivity : ComponentActivity() {
|
||||
class TextViewActivity : ComponentActivity() {
|
||||
companion object {
|
||||
const val EXTRA_LOG_VIEW_FILENAME = "EXTRA_LOG_FILENAME"
|
||||
}
|
||||
@@ -95,14 +95,23 @@ class GeodeLogViewActivity : ComponentActivity() {
|
||||
fun GeodeLogView(
|
||||
onBackPressedDispatcher: OnBackPressedDispatcher?,
|
||||
filename: String,
|
||||
geodeLogsViewModel: GeodeLogsViewModel = viewModel(factory = GeodeLogsViewModel.Factory)
|
||||
) {
|
||||
var loadingFile by remember { mutableStateOf(true) }
|
||||
var description by remember { mutableStateOf(emptyList<String>()) }
|
||||
|
||||
val toRead = File(filename)
|
||||
|
||||
LaunchedEffect(filename) {
|
||||
loadingFile = true
|
||||
description = geodeLogsViewModel.getFileText(filename)
|
||||
|
||||
withContext(Dispatchers.IO) {
|
||||
if (!toRead.isFile) {
|
||||
description = listOf("File does not exist!")
|
||||
} else {
|
||||
description = toRead.readLines()
|
||||
}
|
||||
}
|
||||
|
||||
loadingFile = false
|
||||
}
|
||||
|
||||
@@ -123,7 +132,7 @@ fun GeodeLogView(
|
||||
},
|
||||
title = {
|
||||
Text(
|
||||
filename,
|
||||
toRead.name,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
@@ -73,7 +73,7 @@ object LaunchUtils {
|
||||
return File(getBaseDirectory(context), "save")
|
||||
}
|
||||
|
||||
const val CRASH_INDICATOR_NAME = "lastSessionDidCrash"
|
||||
val CRASH_INDICATOR_NAMES = setOf("lastSessionDidCrash", "last-pid", "last-crashed")
|
||||
|
||||
fun getCrashDirectory(context: Context): File {
|
||||
val base = getBaseDirectory(context)
|
||||
@@ -93,7 +93,7 @@ object LaunchUtils {
|
||||
|
||||
val children = crashDirectory.listFiles {
|
||||
// ignore indicator files (including old file)
|
||||
_, name -> name != CRASH_INDICATOR_NAME && name != "last-pid"
|
||||
_, name -> !CRASH_INDICATOR_NAMES.contains(name)
|
||||
}
|
||||
|
||||
return children?.maxByOrNull { it.lastModified() }
|
||||
@@ -101,9 +101,9 @@ object LaunchUtils {
|
||||
|
||||
fun lastSessionCrashed(context: Context): Boolean {
|
||||
val base = getCrashDirectory(context)
|
||||
val crashIndicatorFile = File(base, CRASH_INDICATOR_NAME)
|
||||
|
||||
return crashIndicatorFile.exists()
|
||||
return CRASH_INDICATOR_NAMES.any {
|
||||
File(base, it).exists()
|
||||
}
|
||||
}
|
||||
|
||||
enum class LauncherError : Serializable {
|
||||
|
||||
Reference in new issue
Block a user