make crashviewmodel abstract

This commit is contained in:
Chloe committed 2026-02-24 15:27:05 -07:00
1 parent c404f977e5
commit 6d5de931fc
4 files changed
+108 -72

No files matched your search

@@ -0,0 +1,68 @@
package com.geode.launcher.log
import androidx.compose.runtime.mutableStateListOf
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import java.io.File
abstract class BaseDirectoryViewModel<T>(protected val baseDirectory: File) : ViewModel() {
private val _lineState = mutableStateListOf<T>()
val lineState = _lineState
private val _isLoading = MutableStateFlow(false)
val isLoading = _isLoading.asStateFlow()
private var logJob: Job? = null
abstract fun getFileList(): List<T>
open fun clearAllFiles() {
logJob?.cancel()
viewModelScope.launch(Dispatchers.IO) {
if (baseDirectory.exists()) {
val files = baseDirectory.listFiles()
files?.forEach {
it.delete()
}
}
}
_lineState.clear()
}
private fun loadLogs() {
_isLoading.value = true
logJob?.cancel()
logJob = viewModelScope.launch(Dispatchers.IO) {
val lines = getFileList()
_lineState.clear()
_lineState.addAll(lines)
_isLoading.value = false
logJob = null
}
}
fun removeFile(filename: String) {
logJob?.cancel()
val crashPath = File(baseDirectory, filename)
if (crashPath.exists()) {
crashPath.delete()
loadLogs()
}
}
init {
loadLogs()
}
}
@@ -1,17 +1,12 @@
package com.geode.launcher.log package com.geode.launcher.log
import android.app.Application import android.app.Application
import androidx.compose.runtime.mutableStateListOf
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import androidx.lifecycle.viewmodel.initializer import androidx.lifecycle.viewmodel.initializer
import androidx.lifecycle.viewmodel.viewModelFactory import androidx.lifecycle.viewmodel.viewModelFactory
import com.geode.launcher.utils.LaunchUtils import com.geode.launcher.utils.LaunchUtils
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.io.File import java.io.File
import kotlin.time.ExperimentalTime import kotlin.time.ExperimentalTime
@@ -22,33 +17,23 @@ data class CrashDump @OptIn(ExperimentalTime::class) constructor(
val lastModified: Instant val lastModified: Instant
) )
class CrashViewModel(private val application: Application) : ViewModel() { class CrashViewModel(crashDirectory: File) : BaseDirectoryViewModel<CrashDump>(crashDirectory) {
companion object { companion object {
val Factory: ViewModelProvider.Factory = viewModelFactory { val Factory: ViewModelProvider.Factory = viewModelFactory {
initializer { initializer {
val application = this[ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY] as Application val application = this[ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY] as Application
val crashDirectory = LaunchUtils.getCrashDirectory(application)
CrashViewModel( CrashViewModel(crashDirectory)
application = application
)
} }
} }
} }
private val _lineState = mutableStateListOf<CrashDump>()
val lineState = _lineState
private val _isLoading = MutableStateFlow(false)
val isLoading = _isLoading.asStateFlow()
private var failedToLoad = false
private var logJob: Job? = null
var hasIndicator = false var hasIndicator = false
private fun getCrashList(): List<CrashDump> { override fun getFileList(): List<CrashDump> {
val crashDirectory = LaunchUtils.getCrashDirectory(application) val crashDirectory = baseDirectory
if (!crashDirectory.exists()) { if (!crashDirectory.exists()) {
return emptyList() return emptyList()
} }
@@ -72,8 +57,7 @@ class CrashViewModel(private val application: Application) : ViewModel() {
fun clearIndicator() { fun clearIndicator() {
viewModelScope.launch(Dispatchers.IO) { viewModelScope.launch(Dispatchers.IO) {
val crashDirectory = LaunchUtils.getCrashDirectory(application) File(baseDirectory, LaunchUtils.CRASH_INDICATOR_NAME).delete()
File(crashDirectory, LaunchUtils.CRASH_INDICATOR_NAME).delete()
hasIndicator = false hasIndicator = false
} }
@@ -81,56 +65,14 @@ class CrashViewModel(private val application: Application) : ViewModel() {
fun createIndicator() { fun createIndicator() {
viewModelScope.launch(Dispatchers.IO) { viewModelScope.launch(Dispatchers.IO) {
val crashDirectory = LaunchUtils.getCrashDirectory(application) File(baseDirectory, LaunchUtils.CRASH_INDICATOR_NAME).createNewFile()
File(crashDirectory, LaunchUtils.CRASH_INDICATOR_NAME).createNewFile()
hasIndicator = true hasIndicator = true
} }
} }
fun clearCrashes() { override fun clearAllFiles() {
logJob?.cancel() super.clearAllFiles()
hasIndicator = false
viewModelScope.launch(Dispatchers.IO) {
val crashDirectory = LaunchUtils.getCrashDirectory(application)
if (crashDirectory.exists()) {
val files = crashDirectory.listFiles()
files?.forEach {
it.delete()
}
}
}
_lineState.clear()
}
private fun loadLogs() {
_isLoading.value = true
logJob?.cancel()
logJob = viewModelScope.launch(Dispatchers.IO) {
val lines = getCrashList()
_lineState.clear()
_lineState.addAll(lines)
_isLoading.value = false
logJob = null
}
}
fun removeCrash(filename: String) {
logJob?.cancel()
val crashPath = File(LaunchUtils.getCrashDirectory(application), filename)
if (crashPath.exists()) {
crashPath.delete()
loadLogs()
}
}
init {
loadLogs()
} }
} }
@@ -169,7 +169,7 @@ fun CrashCard(crashDump: CrashDump, crashViewModel: CrashViewModel, modifier: Mo
} }
IconButton(onClick = { IconButton(onClick = {
crashViewModel.removeCrash(crashDump.filename) crashViewModel.removeFile(crashDump.filename)
}) { }) {
Icon( Icon(
painterResource(R.drawable.icon_delete), painterResource(R.drawable.icon_delete),
@@ -228,14 +228,13 @@ fun CrashLogsScreen(
text = { text = {
Text(stringResource(R.string.application_logs_delete)) Text(stringResource(R.string.application_logs_delete))
}, onClick = { }, onClick = {
crashViewModel.clearCrashes() crashViewModel.clearAllFiles()
showMoreOptions = false showMoreOptions = false
} }
) )
val developerMode by PreferenceUtils.useBooleanPreference(PreferenceUtils.Key.DEVELOPER_MODE) val developerMode by PreferenceUtils.useBooleanPreference(PreferenceUtils.Key.DEVELOPER_MODE)
if (developerMode) { if (developerMode) {
if (crashViewModel.hasIndicator) { if (crashViewModel.hasIndicator) {
DropdownMenuItem( DropdownMenuItem(
leadingIcon = { leadingIcon = {
@@ -463,6 +463,33 @@ fun GameplaySettingsGroup() {
preferenceKey = PreferenceUtils.Key.LIMIT_FRAME_RATE, preferenceKey = PreferenceUtils.Key.LIMIT_FRAME_RATE,
maxFrameRate = maxFrameRate maxFrameRate = maxFrameRate
) )
var showSafeModeDialog by remember { mutableStateOf(false) }
OptionsButton(
title = stringResource(R.string.preference_launch_safe_mode),
icon = {
Icon(
painterResource(R.drawable.icon_shield),
contentDescription = null
)
}
) {
showSafeModeDialog = true
}
if (showSafeModeDialog) {
SafeModeDialog(onDismiss = {
showSafeModeDialog = false
}) {
val launchIntent = Intent(context, MainActivity::class.java).apply {
// hardcode it, why not
action = Intent.ACTION_VIEW
data = "geode-launcher://main/launch?safe-mode=true".toUri()
}
context.startActivity(launchIntent)
}
}
} }
} }