From 269fd531b30c832c46c2626442f7eff11abba181 Mon Sep 17 00:00:00 2001 From: rushiiMachine <33725716+rushiiMachine@users.noreply.github.com> Date: Sun, 18 May 2025 10:23:19 -0700 Subject: [PATCH] feat: logs list screen --- .../aliucord/manager/ManagerApplication.kt | 2 + .../manager/manager/InstallLogManager.kt | 18 +++ .../plugins/PluginsScreenNonePreview.kt | 1 - .../ui/screens/home/components/HomeAppBar.kt | 12 +- .../manager/ui/screens/log/LogScreen.kt | 10 +- .../{SelectableTextArea.kt => LogTextArea.kt} | 6 +- .../manager/ui/screens/logs/LogsListScreen.kt | 99 ++++++++++++++ .../ui/screens/logs/LogsListScreenModel.kt | 67 ++++++++++ .../screens/logs/components/LogEntryCard.kt | 122 ++++++++++++++++++ .../screens/logs/components/LogsListAppBar.kt | 37 ++++++ .../ui/screens/logs/components/LogsNone.kt | 33 +++++ .../components/dialogs/DeleteLogsDialog.kt | 49 +++++++ .../screens/patching/PatchingScreenModel.kt | 34 ++--- .../dialogs/UninstallPluginDialog.kt | 10 +- app/src/main/res/drawable/ic_receipt.xml | 9 ++ app/src/main/res/drawable/ic_reciept_off.xml | 9 ++ app/src/main/res/values/strings.xml | 8 ++ 17 files changed, 496 insertions(+), 30 deletions(-) rename app/src/main/kotlin/com/aliucord/manager/ui/screens/log/components/{SelectableTextArea.kt => LogTextArea.kt} (93%) create mode 100644 app/src/main/kotlin/com/aliucord/manager/ui/screens/logs/LogsListScreen.kt create mode 100644 app/src/main/kotlin/com/aliucord/manager/ui/screens/logs/LogsListScreenModel.kt create mode 100644 app/src/main/kotlin/com/aliucord/manager/ui/screens/logs/components/LogEntryCard.kt create mode 100644 app/src/main/kotlin/com/aliucord/manager/ui/screens/logs/components/LogsListAppBar.kt create mode 100644 app/src/main/kotlin/com/aliucord/manager/ui/screens/logs/components/LogsNone.kt create mode 100644 app/src/main/kotlin/com/aliucord/manager/ui/screens/logs/components/dialogs/DeleteLogsDialog.kt create mode 100644 app/src/main/res/drawable/ic_receipt.xml create mode 100644 app/src/main/res/drawable/ic_reciept_off.xml diff --git a/app/src/main/kotlin/com/aliucord/manager/ManagerApplication.kt b/app/src/main/kotlin/com/aliucord/manager/ManagerApplication.kt index 56a3a3c..310f2ae 100644 --- a/app/src/main/kotlin/com/aliucord/manager/ManagerApplication.kt +++ b/app/src/main/kotlin/com/aliucord/manager/ManagerApplication.kt @@ -11,6 +11,7 @@ import com.aliucord.manager.ui.screens.about.AboutModel import com.aliucord.manager.ui.screens.home.HomeModel import com.aliucord.manager.ui.screens.iconopts.IconOptionsModel import com.aliucord.manager.ui.screens.log.LogScreenModel +import com.aliucord.manager.ui.screens.logs.LogsListScreenModel import com.aliucord.manager.ui.screens.patching.PatchingScreenModel import com.aliucord.manager.ui.screens.patchopts.PatchOptionsModel import com.aliucord.manager.ui.screens.plugins.PluginsModel @@ -56,6 +57,7 @@ class ManagerApplication : Application() { factoryOf(::PatchOptionsModel) factoryOf(::IconOptionsModel) factoryOf(::LogScreenModel) + factoryOf(::LogsListScreenModel) viewModelOf(::UpdaterViewModel) }) diff --git a/app/src/main/kotlin/com/aliucord/manager/manager/InstallLogManager.kt b/app/src/main/kotlin/com/aliucord/manager/manager/InstallLogManager.kt index cff32b8..802c0a6 100644 --- a/app/src/main/kotlin/com/aliucord/manager/manager/InstallLogManager.kt +++ b/app/src/main/kotlin/com/aliucord/manager/manager/InstallLogManager.kt @@ -30,6 +30,19 @@ class InstallLogManager( ) { val logsDir = application.filesDir.resolve("install-logs").apply { mkdir() } + /** + * Lists all the install data entries that exist on disk, sorted decreasing by + * the file creation date. + * @return List of installation ids, most recent installation first. + */ + fun fetchInstallDataEntries(): List { + val files = logsDir.listFiles { it.extension == "json" } ?: emptyArray() + + return files + .sortedByDescending { it.lastModified() } + .map { it.nameWithoutExtension } + } + /** * Loads the install log from disk, if it exists. */ @@ -46,6 +59,11 @@ class InstallLogManager( } } + fun deleteAllEntries() { + logsDir.deleteRecursively() + logsDir.mkdir() + } + /** * Writes an install log entry to disk. */ diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/previews/screens/plugins/PluginsScreenNonePreview.kt b/app/src/main/kotlin/com/aliucord/manager/ui/previews/screens/plugins/PluginsScreenNonePreview.kt index 9dd264b..830d9a0 100644 --- a/app/src/main/kotlin/com/aliucord/manager/ui/previews/screens/plugins/PluginsScreenNonePreview.kt +++ b/app/src/main/kotlin/com/aliucord/manager/ui/previews/screens/plugins/PluginsScreenNonePreview.kt @@ -27,4 +27,3 @@ private fun PluginsScreenNonePreview() { ) } } - diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/screens/home/components/HomeAppBar.kt b/app/src/main/kotlin/com/aliucord/manager/ui/screens/home/components/HomeAppBar.kt index 28365b9..91eb8d1 100644 --- a/app/src/main/kotlin/com/aliucord/manager/ui/screens/home/components/HomeAppBar.kt +++ b/app/src/main/kotlin/com/aliucord/manager/ui/screens/home/components/HomeAppBar.kt @@ -7,6 +7,7 @@ import androidx.compose.ui.res.stringResource import cafe.adriel.voyager.navigator.LocalNavigator import com.aliucord.manager.R import com.aliucord.manager.ui.screens.about.AboutScreen +import com.aliucord.manager.ui.screens.logs.LogsListScreen import com.aliucord.manager.ui.screens.settings.SettingsScreen @Composable @@ -19,14 +20,21 @@ fun HomeAppBar() { IconButton(onClick = { navigator?.push(AboutScreen()) }) { Icon( painter = painterResource(R.drawable.ic_info), - contentDescription = stringResource(R.string.navigation_about) + contentDescription = stringResource(R.string.navigation_about), + ) + } + + IconButton(onClick = { navigator?.push(LogsListScreen()) }) { + Icon( + painter = painterResource(R.drawable.ic_receipt), + contentDescription = stringResource(R.string.navigation_about), ) } IconButton(onClick = { navigator?.push(SettingsScreen()) }) { Icon( painter = painterResource(R.drawable.ic_settings), - contentDescription = stringResource(R.string.navigation_settings) + contentDescription = stringResource(R.string.navigation_settings), ) } } diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/screens/log/LogScreen.kt b/app/src/main/kotlin/com/aliucord/manager/ui/screens/log/LogScreen.kt index 31eee18..8650507 100644 --- a/app/src/main/kotlin/com/aliucord/manager/ui/screens/log/LogScreen.kt +++ b/app/src/main/kotlin/com/aliucord/manager/ui/screens/log/LogScreen.kt @@ -18,7 +18,7 @@ import com.aliucord.manager.manager.InstallLogData import com.aliucord.manager.ui.components.Label import com.aliucord.manager.ui.components.back import com.aliucord.manager.ui.screens.log.components.LogAppBar -import com.aliucord.manager.ui.screens.log.components.SelectableTextArea +import com.aliucord.manager.ui.screens.log.components.LogTextArea import kotlinx.parcelize.IgnoredOnParcel import kotlinx.parcelize.Parcelize import org.koin.core.parameter.parametersOf @@ -73,7 +73,7 @@ fun LogScreenContent( name = stringResource(R.string.log_section_install_info), description = null, ) { - SelectableTextArea( + LogTextArea( text = """ Installation ID: ${data.id} Installation Date: ${data.installDate} @@ -88,7 +88,7 @@ fun LogScreenContent( name = stringResource(R.string.log_section_env_info), description = null, ) { - SelectableTextArea( + LogTextArea( text = data.environmentInfo, modifier = Modifier.fillMaxWidth(), ) @@ -101,7 +101,7 @@ fun LogScreenContent( name = stringResource(R.string.log_section_error), description = null, ) { - SelectableTextArea( + LogTextArea( text = data.errorStacktrace, modifier = Modifier.fillMaxWidth(), ) @@ -114,7 +114,7 @@ fun LogScreenContent( name = stringResource(R.string.log_section_log), description = null, ) { - SelectableTextArea( + LogTextArea( text = data.installationLog, modifier = Modifier.fillMaxWidth(), ) diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/screens/log/components/SelectableTextArea.kt b/app/src/main/kotlin/com/aliucord/manager/ui/screens/log/components/LogTextArea.kt similarity index 93% rename from app/src/main/kotlin/com/aliucord/manager/ui/screens/log/components/SelectableTextArea.kt rename to app/src/main/kotlin/com/aliucord/manager/ui/screens/log/components/LogTextArea.kt index ebb299d..d7b7962 100644 --- a/app/src/main/kotlin/com/aliucord/manager/ui/screens/log/components/SelectableTextArea.kt +++ b/app/src/main/kotlin/com/aliucord/manager/ui/screens/log/components/LogTextArea.kt @@ -11,11 +11,12 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp import com.aliucord.manager.ui.util.horizontalScrollbar import com.aliucord.manager.ui.util.thenIf @Composable -fun SelectableTextArea( +fun LogTextArea( text: String, modifier: Modifier = Modifier.Companion, ) { @@ -26,11 +27,12 @@ fun SelectableTextArea( Text( text = text, style = MaterialTheme.typography.labelSmall, + lineHeight = 18.sp, fontFamily = FontFamily.Companion.Monospace, softWrap = false, modifier = modifier .clip(RoundedCornerShape(10.dp)) - .background(MaterialTheme.colorScheme.surfaceContainerHighest) + .background(MaterialTheme.colorScheme.surfaceContainerHigh) .padding(start = 18.dp, end = 18.dp, top = 14.dp, bottom = 14.dp) .horizontalScroll(scrollState) .horizontalScrollbar(scrollState) diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/screens/logs/LogsListScreen.kt b/app/src/main/kotlin/com/aliucord/manager/ui/screens/logs/LogsListScreen.kt new file mode 100644 index 0000000..a9cde27 --- /dev/null +++ b/app/src/main/kotlin/com/aliucord/manager/ui/screens/logs/LogsListScreen.kt @@ -0,0 +1,99 @@ +package com.aliucord.manager.ui.screens.logs + +import android.os.Parcelable +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material3.Scaffold +import androidx.compose.runtime.* +import androidx.compose.runtime.snapshots.SnapshotStateList +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import cafe.adriel.voyager.core.screen.Screen +import cafe.adriel.voyager.core.screen.ScreenKey +import cafe.adriel.voyager.koin.getScreenModel +import cafe.adriel.voyager.navigator.LocalNavigator +import cafe.adriel.voyager.navigator.currentOrThrow +import com.aliucord.manager.ui.screens.log.LogScreen +import com.aliucord.manager.ui.screens.logs.components.* +import com.aliucord.manager.ui.screens.logs.components.dialogs.DeleteLogsDialog +import com.aliucord.manager.ui.util.paddings.PaddingValuesSides +import com.aliucord.manager.ui.util.paddings.exclude +import kotlinx.parcelize.IgnoredOnParcel +import kotlinx.parcelize.Parcelize + +@Parcelize +class LogsListScreen : Screen, Parcelable { + @IgnoredOnParcel + override val key: ScreenKey + get() = "LogsScreen" + + @Composable + override fun Content() { + val navigator = LocalNavigator.currentOrThrow + val model = getScreenModel() + + LogsScreenContent( + logs = model.logEntries, + onOpenLog = { navigator.push(LogScreen(installId = it)) }, + onDeleteLogs = model::deleteLogs, // TODO: show warning dialog first + ) + } +} + +@Composable +fun LogsScreenContent( + logs: SnapshotStateList, + onOpenLog: (id: String) -> Unit, + onDeleteLogs: () -> Unit, +) { + var showWipeConfirmDialog by remember { mutableStateOf(false) } + + if (showWipeConfirmDialog) { + DeleteLogsDialog( + onConfirm = { + showWipeConfirmDialog = false + onDeleteLogs() + }, + onDismiss = { + showWipeConfirmDialog = false + }, + ) + } + + Scaffold( + topBar = { + LogsListAppBar( + onDeleteLogs = { showWipeConfirmDialog = true }, + ) + }, + ) { paddingValues -> + LazyColumn( + verticalArrangement = Arrangement.spacedBy(16.dp), + contentPadding = paddingValues.exclude(PaddingValuesSides.Horizontal + PaddingValuesSides.Top), + modifier = Modifier + .padding(paddingValues.exclude(PaddingValuesSides.Bottom)) + .padding(vertical = 12.dp, horizontal = 22.dp) + ) { + if (logs.isEmpty()) { + item(key = "EMPTY") { + LogsNone( + modifier = Modifier.fillParentMaxSize(), + ) + } + } + + items( + items = logs, + contentType = { "LOG" }, + key = { it.id }, + ) { data -> + LogEntryCard( + data = data, + onClick = remember(onOpenLog, data.id) { { onOpenLog(data.id) } }, + modifier = Modifier.fillMaxWidth(), + ) + } + } + } +} diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/screens/logs/LogsListScreenModel.kt b/app/src/main/kotlin/com/aliucord/manager/ui/screens/logs/LogsListScreenModel.kt new file mode 100644 index 0000000..0c53962 --- /dev/null +++ b/app/src/main/kotlin/com/aliucord/manager/ui/screens/logs/LogsListScreenModel.kt @@ -0,0 +1,67 @@ +package com.aliucord.manager.ui.screens.logs + +import android.app.Application +import android.text.format.DateUtils +import androidx.compose.runtime.Immutable +import androidx.compose.runtime.mutableStateListOf +import cafe.adriel.voyager.core.model.ScreenModel +import cafe.adriel.voyager.core.model.screenModelScope +import com.aliucord.manager.R +import com.aliucord.manager.manager.InstallLogManager +import com.aliucord.manager.util.launchBlock +import com.aliucord.manager.util.showToast +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.toImmutableList + +class LogsListScreenModel( + private val logsManager: InstallLogManager, + private val application: Application, +) : ScreenModel { + /** + * All the loaded log entries sorted descending by creation date. + */ + val logEntries = mutableStateListOf() + + init { + loadLogsList() + } + + fun deleteLogs() = screenModelScope.launchBlock { + logsManager.deleteAllEntries() + logEntries.clear() + application.showToast(R.string.logs_status_delete_success) + } + + private fun loadLogsList() = screenModelScope.launchBlock { + for (installId in logsManager.fetchInstallDataEntries()) { + val data = logsManager.fetchInstallData(id = installId) + ?: continue + + logEntries += LogEntry( + id = data.id, + isError = data.isError, + installDate = DateUtils.getRelativeDateTimeString( + /* c = */ application, + /* time = */ data.installDate.toEpochMilliseconds(), + /* minResolution = */ DateUtils.SECOND_IN_MILLIS, + /* transitionResolution = */ DateUtils.WEEK_IN_MILLIS, + /* flags = */ DateUtils.FORMAT_ABBREV_ALL, + ).toString(), + durationSecs = data.installDuration.inWholeMilliseconds / 1000f, + stacktracePreview = data.errorStacktrace + ?.splitToSequence('\n') + ?.take(3) + ?.toImmutableList(), + ) + } + } +} + +@Immutable +data class LogEntry( + val id: String, + val isError: Boolean, + val installDate: String, + val durationSecs: Float, + val stacktracePreview: ImmutableList?, +) diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/screens/logs/components/LogEntryCard.kt b/app/src/main/kotlin/com/aliucord/manager/ui/screens/logs/components/LogEntryCard.kt new file mode 100644 index 0000000..58bfbdc --- /dev/null +++ b/app/src/main/kotlin/com/aliucord/manager/ui/screens/logs/components/LogEntryCard.kt @@ -0,0 +1,122 @@ +package com.aliucord.manager.ui.screens.logs.components + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.* +import androidx.compose.runtime.Composable +import androidx.compose.runtime.key +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.* +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.geometry.Size +import androidx.compose.ui.graphics.* +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.aliucord.manager.R +import com.aliucord.manager.patcher.steps.base.StepState +import com.aliucord.manager.ui.screens.logs.LogEntry +import com.aliucord.manager.ui.screens.patching.components.StepStateIcon +import com.aliucord.manager.ui.screens.patching.components.TimeElapsed + +@Composable +fun LogEntryCard( + data: LogEntry, + onClick: () -> Unit, + modifier: Modifier = Modifier, +) { + val errorColor = MaterialTheme.colorScheme.error + + ElevatedCard( + shape = RectangleShape, + modifier = modifier + .clickable(onClick = onClick) + .clip(RoundedCornerShape(topStart = 6.dp, 12.0.dp, bottomStart = 6.dp, bottomEnd = 12.0.dp)) + .drawWithCache { + val color = when (data.isError) { + true -> errorColor + false -> Color(0xFF59B463) + } + + onDrawWithContent { + drawContent() + drawRect( + color = color, + alpha = .8f, + topLeft = Offset.Zero, + size = Size(4.dp.toPx(), size.height), + ) + } + } + ) { + Row( + horizontalArrangement = Arrangement.spacedBy(14.dp), + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .padding(vertical = 18.dp, horizontal = 22.dp), + ) { + StepStateIcon( + state = if (data.isError) StepState.Error else StepState.Success, + size = 24.dp, + ) + + Column { + Text( + text = when (data.isError) { + true -> stringResource(R.string.status_failed) + false -> stringResource(R.string.status_success) + }, + ) + + Text( + text = data.installDate, + style = MaterialTheme.typography.labelSmall, + modifier = Modifier.alpha(.6f), + ) + } + + Spacer(Modifier.weight(1f, fill = true)) + + TimeElapsed( + seconds = data.durationSecs, + modifier = Modifier.alpha(.9f), + ) + } + + if (data.stacktracePreview != null) { + Column( + modifier = Modifier + .padding(start = 26.dp, end = 20.dp, bottom = 18.dp) + // https://stackoverflow.com/a/76270310/13964629 + .graphicsLayer( + alpha = .95f, + compositingStrategy = CompositingStrategy.Offscreen, + ) + .drawWithContent { + val colors = listOf(Color.Black, Color.Black, Color.Transparent) + drawContent() + drawRect( + brush = Brush.verticalGradient(colors), + blendMode = BlendMode.DstIn, + ) + } + ) { + // The stacktrace is separated into multiple Text elements because ellipsis is not supported per-line + for (line in data.stacktracePreview) key(line) { + Text( + text = line, + softWrap = false, + overflow = TextOverflow.Ellipsis, + lineHeight = 18.sp, + style = MaterialTheme.typography.labelSmall, + fontFamily = FontFamily.Companion.Monospace, + ) + } + } + } + } +} diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/screens/logs/components/LogsListAppBar.kt b/app/src/main/kotlin/com/aliucord/manager/ui/screens/logs/components/LogsListAppBar.kt new file mode 100644 index 0000000..f8a45e7 --- /dev/null +++ b/app/src/main/kotlin/com/aliucord/manager/ui/screens/logs/components/LogsListAppBar.kt @@ -0,0 +1,37 @@ +package com.aliucord.manager.ui.screens.logs.components + +import androidx.compose.material3.* +import androidx.compose.runtime.Composable +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import cafe.adriel.voyager.navigator.LocalNavigator +import com.aliucord.manager.R +import com.aliucord.manager.ui.components.BackButton +import com.aliucord.manager.ui.screens.settings.SettingsScreen + +@Composable +fun LogsListAppBar( + onDeleteLogs: () -> Unit, +) { + TopAppBar( + navigationIcon = { BackButton() }, + title = { Text(stringResource(R.string.logs_title)) }, + actions = { + val navigator = LocalNavigator.current + + IconButton(onClick = onDeleteLogs) { + Icon( + painter = painterResource(R.drawable.ic_delete_forever), + contentDescription = stringResource(R.string.logs_action_delete_all) + ) + } + + IconButton(onClick = { navigator?.push(SettingsScreen()) }) { + Icon( + painter = painterResource(R.drawable.ic_settings), + contentDescription = stringResource(R.string.navigation_settings) + ) + } + } + ) +} diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/screens/logs/components/LogsNone.kt b/app/src/main/kotlin/com/aliucord/manager/ui/screens/logs/components/LogsNone.kt new file mode 100644 index 0000000..5737684 --- /dev/null +++ b/app/src/main/kotlin/com/aliucord/manager/ui/screens/logs/components/LogsNone.kt @@ -0,0 +1,33 @@ +package com.aliucord.manager.ui.screens.logs.components + +import androidx.compose.foundation.layout.* +import androidx.compose.material3.* +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.alpha +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import com.aliucord.manager.R + +@Composable +fun LogsNone(modifier: Modifier = Modifier) { + Box(modifier = modifier) { + Column( + modifier = Modifier.align(Alignment.Center), + verticalArrangement = Arrangement.spacedBy(4.dp), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + Icon( + painter = painterResource(R.drawable.ic_reciept_off), + contentDescription = null, + ) + Text( + text = stringResource(R.string.logs_none), + style = MaterialTheme.typography.bodyLarge, + modifier = Modifier.alpha(.8f), + ) + } + } +} diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/screens/logs/components/dialogs/DeleteLogsDialog.kt b/app/src/main/kotlin/com/aliucord/manager/ui/screens/logs/components/dialogs/DeleteLogsDialog.kt new file mode 100644 index 0000000..77c3d02 --- /dev/null +++ b/app/src/main/kotlin/com/aliucord/manager/ui/screens/logs/components/dialogs/DeleteLogsDialog.kt @@ -0,0 +1,49 @@ +package com.aliucord.manager.ui.screens.logs.components.dialogs + +import androidx.compose.material3.* +import androidx.compose.runtime.Composable +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import com.aliucord.manager.R + +@Composable +fun DeleteLogsDialog( + onConfirm: () -> Unit, + onDismiss: () -> Unit, +) { + AlertDialog( + onDismissRequest = onDismiss, + icon = { + Icon( + painter = painterResource(R.drawable.ic_delete_forever), + contentDescription = null, + ) + }, + title = { Text(stringResource(R.string.logs_wipe_title)) }, + text = { + Text( + text = stringResource(R.string.logs_wipe_desc), + textAlign = TextAlign.Center, + ) + }, + confirmButton = { + Button( + onClick = onConfirm, + ) { + Text(stringResource(R.string.action_confirm)) + } + }, + dismissButton = { + Button( + onClick = onDismiss, + colors = ButtonDefaults.buttonColors( + contentColor = MaterialTheme.colorScheme.onSecondaryContainer, + containerColor = MaterialTheme.colorScheme.secondaryContainer + ) + ) { + Text(stringResource(R.string.action_cancel)) + } + } + ) +} diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/screens/patching/PatchingScreenModel.kt b/app/src/main/kotlin/com/aliucord/manager/ui/screens/patching/PatchingScreenModel.kt index dd3d84c..33e2538 100644 --- a/app/src/main/kotlin/com/aliucord/manager/ui/screens/patching/PatchingScreenModel.kt +++ b/app/src/main/kotlin/com/aliucord/manager/ui/screens/patching/PatchingScreenModel.kt @@ -134,40 +134,40 @@ class PatchingScreenModel( delay(400) // Execute all the steps and catch any errors - when (val error = runner.executeAll()) { + val error = when (val error = runner.executeAll()) { null -> { // If install step is marked skipped then the installation was manually aborted // and if so, immediately close install screen if (runner.getStep().state == StepState.Skipped) { mutableState.value = PatchingScreenState.CloseScreen + + Error("Installation was aborted or cancelled") + .apply { stackTrace = emptyArray() } } // At this point, the installation has successfully completed else { mutableState.value = PatchingScreenState.Success - installLogs.storeInstallData( - id = installId!!, - installDate = startTime!!, - installDuration = runner.steps.sumOf { it.getDuration() }.milliseconds, - options = options, - log = runner.getLog(), - error = null, - ) + + null } } else -> { Log.e(BuildConfig.TAG, "Failed to perform installation process", error) mutableState.value = PatchingScreenState.Failed(installId = installId!!) - installLogs.storeInstallData( - id = installId!!, - installDate = startTime!!, - installDuration = runner.steps.sumOf { it.getDuration() }.milliseconds, - options = options, - log = runner.getLog(), - error = error, - ) + + error } } + + installLogs.storeInstallData( + id = installId!!, + installDate = startTime!!, + installDuration = runner.steps.sumOf { it.getDuration() }.milliseconds, + options = options, + log = runner.getLog(), + error = error, + ) } private companion object { diff --git a/app/src/main/kotlin/com/aliucord/manager/ui/screens/plugins/components/dialogs/UninstallPluginDialog.kt b/app/src/main/kotlin/com/aliucord/manager/ui/screens/plugins/components/dialogs/UninstallPluginDialog.kt index 3fe09e9..46a4af3 100644 --- a/app/src/main/kotlin/com/aliucord/manager/ui/screens/plugins/components/dialogs/UninstallPluginDialog.kt +++ b/app/src/main/kotlin/com/aliucord/manager/ui/screens/plugins/components/dialogs/UninstallPluginDialog.kt @@ -4,6 +4,7 @@ import androidx.compose.material3.* import androidx.compose.runtime.Composable import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign import com.aliucord.manager.R @Composable @@ -24,13 +25,16 @@ fun UninstallPluginDialog( Text(stringResource(R.string.plugins_delete_plugin, pluginName)) }, text = { - Text(stringResource(R.string.plugins_delete_plugin_body)) + Text( + text = stringResource(R.string.plugins_delete_plugin_body), + textAlign = TextAlign.Center, + ) }, confirmButton = { Button( onClick = onConfirm, ) { - Text(stringResource(android.R.string.ok)) + Text(stringResource(R.string.action_confirm)) } }, dismissButton = { @@ -41,7 +45,7 @@ fun UninstallPluginDialog( containerColor = MaterialTheme.colorScheme.secondaryContainer ) ) { - Text(stringResource(android.R.string.cancel)) + Text(stringResource(R.string.action_cancel)) } } ) diff --git a/app/src/main/res/drawable/ic_receipt.xml b/app/src/main/res/drawable/ic_receipt.xml new file mode 100644 index 0000000..0b9203d --- /dev/null +++ b/app/src/main/res/drawable/ic_receipt.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_reciept_off.xml b/app/src/main/res/drawable/ic_reciept_off.xml new file mode 100644 index 0000000..e7c6f35 --- /dev/null +++ b/app/src/main/res/drawable/ic_reciept_off.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1dae263..ba12cbf 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -70,6 +70,7 @@ Back About + Open logs Settings Lead @@ -194,6 +195,13 @@ Export log Share log + Logs + No logs present! + Delete all logs + Successfully deleted all logs + Clear Logs + Are you sure you want to permanently delete all the logs? + Active installation Progress notifications sent during a minimized installation Aliucord installation ready!