feat(LogScreen): add log sharing

This commit is contained in:
rushiiMachine 2025-04-06 22:50:03 -07:00
parent 3a9e3562ca
commit d64a1767fc
No known key found for this signature in database
GPG key ID: DCBE5952BB3B6420
9 changed files with 155 additions and 43 deletions

View file

@ -34,6 +34,16 @@
android:name=".installers.pm.PMIntentReceiver"
android:exported="false" />
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths" />
</provider>
<activity
android:name=".MainActivity"
android:exported="true"

View file

@ -1,5 +1,6 @@
package com.aliucord.manager.manager
import android.annotation.SuppressLint
import android.app.Application
import android.os.Build
import android.util.Log
@ -13,6 +14,9 @@ import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.decodeFromStream
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
/**
* Central manager for storing all attempted installations and
@ -103,4 +107,35 @@ data class InstallLogData(
) {
val isError: Boolean
get() = errorStacktrace != null
fun getFormattedInstallDate(): String {
@SuppressLint("SimpleDateFormat")
return SimpleDateFormat("yyyy-MM-dd HH-mm-ss", Locale.ENGLISH)
.format(Date(installDate.toEpochMilliseconds()))
}
fun getLogFileContents(): String = buildString {
appendLine("////////////////// Environment Info //////////////////")
appendLine(environmentInfo)
append("\n\n")
appendLine("////////////////// Installation Info //////////////////")
appendLine()
append("Install ID: ")
appendLine(id)
append("Install time: ")
appendLine(getFormattedInstallDate())
append("Result: ")
appendLine(if (isError) "Failure" else "Success")
append("\n\n")
appendLine("////////////////// Error Stacktrace //////////////////")
appendLine()
appendLine(errorStacktrace ?: "None")
append("\n\n")
appendLine("////////////////// Installation Log //////////////////")
appendLine()
appendLine(installationLog)
}
}

View file

@ -3,10 +3,9 @@ package com.aliucord.manager.ui.screens.log
import android.os.Parcelable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material3.*
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import cafe.adriel.voyager.core.screen.Screen
@ -16,7 +15,8 @@ import cafe.adriel.voyager.navigator.LocalNavigator
import cafe.adriel.voyager.navigator.currentOrThrow
import com.aliucord.manager.R
import com.aliucord.manager.manager.InstallLogData
import com.aliucord.manager.ui.components.*
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.patchopts.components.options.PatchOption
import kotlinx.parcelize.IgnoredOnParcel
@ -41,7 +41,8 @@ class LogScreen(private val installId: String) : Screen, Parcelable {
model.data?.let {
LogScreenContent(
data = it,
onSaveLog = model::saveLog,
onExportLog = model::saveLog,
onShareLog = model::shareLog,
)
}
}
@ -50,13 +51,14 @@ class LogScreen(private val installId: String) : Screen, Parcelable {
@Composable
fun LogScreenContent(
data: InstallLogData,
onSaveLog: () -> Unit,
onExportLog: () -> Unit,
onShareLog: () -> Unit,
) {
Scaffold(
topBar = {
TopAppBar(
title = { Text(stringResource(R.string.log_title)) },
navigationIcon = { BackButton() },
LogAppBar(
onExportLog = onExportLog,
onShareLog = onShareLog,
)
},
) { paddingValues ->
@ -118,15 +120,6 @@ fun LogScreenContent(
// )
// }
// }
item("SAVE_BUTTON") {
MainActionButton(
text = stringResource(R.string.log_action_export),
icon = painterResource(R.drawable.ic_download),
onClick = onSaveLog,
modifier = Modifier.padding(top = 10.dp),
)
}
}
}
}

View file

@ -1,17 +1,17 @@
package com.aliucord.manager.ui.screens.log
import android.annotation.SuppressLint
import android.app.Application
import android.content.Intent
import android.util.Log
import androidx.compose.runtime.*
import androidx.core.content.FileProvider
import cafe.adriel.voyager.core.model.ScreenModel
import cafe.adriel.voyager.core.model.screenModelScope
import com.aliucord.manager.BuildConfig
import com.aliucord.manager.R
import com.aliucord.manager.manager.InstallLogData
import com.aliucord.manager.manager.InstallLogManager
import com.aliucord.manager.util.*
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
class LogScreenModel(
private val installId: String,
@ -34,33 +34,49 @@ class LogScreenModel(
fun saveLog() = screenModelScope.launchBlock {
val data = data ?: return@launchBlock
@SuppressLint("SimpleDateFormat")
val formattedDate = SimpleDateFormat("yyyy-MM-dd hh-mm-s a", Locale.ENGLISH)
.format(Date(data.installDate.toEpochMilliseconds()))
val formattedDate = data.getFormattedInstallDate()
val content = data.getLogFileContents()
val content = buildString {
appendLine("////////////////// Installation Info //////////////////")
append("Install ID: ")
appendLine(data.id)
append("Install time: ")
appendLine(formattedDate)
append("Result: ")
appendLine(if (data.isError) "Failure" else "Success")
application.saveFile("Aliucord Install $formattedDate.log", content)
}
append("\n\n")
appendLine("////////////////// Environment Info //////////////////")
appendLine(data.environmentInfo)
/**
* Writes the log to internal cache and launches a share intent of the log file.
*/
fun shareLog() = screenModelScope.launchBlock {
val data = data ?: return@launchBlock
val formattedDate = data.getFormattedInstallDate()
val formattedName = "Aliucord Install $formattedDate.log"
val content = data.getLogFileContents()
append("\n\n")
appendLine("////////////////// Error Stacktrace //////////////////")
appendLine(data.errorStacktrace ?: "None")
val file = application.cacheDir.resolve(formattedName)
val fileUri = FileProvider.getUriForFile(
/* context = */ application,
/* authority = */ "${BuildConfig.APPLICATION_ID}.provider",
/* file = */ file,
/* displayName = */ formattedName,
)
append("\n\n")
appendLine("////////////////// Installation Log //////////////////")
appendLine(data.installationLog)
val intent = Intent(Intent.ACTION_SEND)
.setType("text/*")
.putExtra(Intent.EXTRA_STREAM, fileUri)
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
.let {
Intent.createChooser(
/* target = */ it,
/* title = */ application.getString(R.string.log_action_share),
)
}
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
try {
file.writeText(content)
file.deleteOnExit()
application.startActivity(intent)
} catch (t: Throwable) {
Log.w(BuildConfig.TAG, "Failed to share log", t)
application.showToast(R.string.status_failed)
}
application.saveFile("Aliucord Manager $formattedDate.log", content)
}
private fun loadLogData() = screenModelScope.launchBlock {

View file

@ -0,0 +1,33 @@
package com.aliucord.manager.ui.screens.log.components
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import com.aliucord.manager.R
import com.aliucord.manager.ui.components.BackButton
@Composable
fun LogAppBar(
onExportLog: () -> Unit,
onShareLog: () -> Unit,
) {
TopAppBar(
title = { Text(stringResource(R.string.log_title)) },
navigationIcon = { BackButton() },
actions = {
IconButton(onClick = onExportLog) {
Icon(
painter = painterResource(R.drawable.ic_save),
contentDescription = stringResource(R.string.log_action_export),
)
}
IconButton(onClick = onShareLog) {
Icon(
painter = painterResource(R.drawable.ic_share),
contentDescription = stringResource(R.string.log_action_share),
)
}
},
)
}

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="#e8eaed"
android:pathData="M200,840q-33,0 -56.5,-23.5T120,760v-560q0,-33 23.5,-56.5T200,120h447q16,0 30.5,6t25.5,17l114,114q11,11 17,25.5t6,30.5v447q0,33 -23.5,56.5T760,840L200,840ZM480,720q50,0 85,-35t35,-85q0,-50 -35,-85t-85,-35q-50,0 -85,35t-35,85q0,50 35,85t85,35ZM280,400h280q17,0 28.5,-11.5T600,360v-80q0,-17 -11.5,-28.5T560,240L280,240q-17,0 -28.5,11.5T240,280v80q0,17 11.5,28.5T280,400Z" />
</vector>

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="#e8eaed"
android:pathData="M680,880q-50,0 -85,-35t-35,-85q0,-6 3,-28L282,568q-16,15 -37,23.5t-45,8.5q-50,0 -85,-35t-35,-85q0,-50 35,-85t85,-35q24,0 45,8.5t37,23.5l281,-164q-2,-7 -2.5,-13.5T560,200q0,-50 35,-85t85,-35q50,0 85,35t35,85q0,50 -35,85t-85,35q-24,0 -45,-8.5T598,288L317,452q2,7 2.5,13.5t0.5,14.5q0,8 -0.5,14.5T317,508l281,164q16,-15 37,-23.5t45,-8.5q50,0 85,35t35,85q0,50 -35,85t-85,35Z" />
</vector>

View file

@ -192,6 +192,7 @@
<string name="log_section_error">Error Stacktrace</string>
<string name="log_section_log">Installation Log</string>
<string name="log_action_export">Export log</string>
<string name="log_action_share">Share log</string>
<string name="notif_group_install_title">Active installation</string>
<string name="notif_group_install_desc">Progress notifications sent during a minimized installation</string>

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<paths>
<cache-path
name="cache"
path="." />
</paths>