mirror of
https://github.com/rhunk/SnapEnhance.git
synced 2025-05-29 13:00:17 +02:00
fix(ui): social section
- fix logger line separator
This commit is contained in:
parent
61da95f41b
commit
c791fbbd00
@ -2,6 +2,7 @@ package me.rhunk.snapenhance
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import android.util.Log
|
||||
import com.google.gson.GsonBuilder
|
||||
import java.io.File
|
||||
import java.io.OutputStream
|
||||
import java.io.RandomAccessFile
|
||||
@ -42,6 +43,21 @@ class LogReader(
|
||||
private var startLineIndexes = mutableListOf<Long>()
|
||||
var lineCount = queryLineCount()
|
||||
|
||||
private fun readLogLine(): LogLine? {
|
||||
val lines = mutableListOf<String>()
|
||||
while (true) {
|
||||
val lastPointer = randomAccessFile.filePointer
|
||||
val line = randomAccessFile.readLine() ?: return null
|
||||
if (lines.size > 0 && line.startsWith("|")) {
|
||||
randomAccessFile.seek(lastPointer)
|
||||
break
|
||||
}
|
||||
lines.add(line)
|
||||
}
|
||||
val line = lines.joinToString("\n").replaceFirst("|", "")
|
||||
return LogLine.fromString(line)
|
||||
}
|
||||
|
||||
fun incrementLineCount() {
|
||||
randomAccessFile.seek(randomAccessFile.length())
|
||||
startLineIndexes.add(randomAccessFile.filePointer)
|
||||
@ -54,7 +70,7 @@ class LogReader(
|
||||
var lastIndex: Long
|
||||
while (true) {
|
||||
lastIndex = randomAccessFile.filePointer
|
||||
randomAccessFile.readLine() ?: break
|
||||
readLogLine() ?: break
|
||||
startLineIndexes.add(lastIndex)
|
||||
lines++
|
||||
}
|
||||
@ -64,7 +80,7 @@ class LogReader(
|
||||
private fun getLine(index: Int): String? {
|
||||
if (index <= 0 || index > lineCount) return null
|
||||
randomAccessFile.seek(startLineIndexes[index])
|
||||
return randomAccessFile.readLine()
|
||||
return readLogLine()?.toString()
|
||||
}
|
||||
|
||||
fun getLogLine(index: Int): LogLine? {
|
||||
@ -74,7 +90,7 @@ class LogReader(
|
||||
|
||||
|
||||
class LogManager(
|
||||
remoteSideContext: RemoteSideContext
|
||||
private val remoteSideContext: RemoteSideContext
|
||||
) {
|
||||
companion object {
|
||||
private const val TAG = "SnapEnhanceManager"
|
||||
@ -118,12 +134,10 @@ class LogManager(
|
||||
}
|
||||
|
||||
fun clearLogs() {
|
||||
logFile.delete()
|
||||
logFolder.listFiles()?.forEach { it.delete() }
|
||||
newLogFile()
|
||||
}
|
||||
|
||||
fun getLogFile() = logFile
|
||||
|
||||
fun exportLogsToZip(outputStream: OutputStream) {
|
||||
val zipOutputStream = ZipOutputStream(outputStream)
|
||||
//add logFolder to zip
|
||||
@ -136,8 +150,10 @@ class LogManager(
|
||||
}
|
||||
|
||||
//add device info to zip
|
||||
zipOutputStream.putNextEntry(ZipEntry("device_info.txt"))
|
||||
|
||||
zipOutputStream.putNextEntry(ZipEntry("device_info.json"))
|
||||
val gson = GsonBuilder().setPrettyPrinting().create()
|
||||
zipOutputStream.write(gson.toJson(remoteSideContext.installationSummary).toByteArray())
|
||||
zipOutputStream.closeEntry()
|
||||
|
||||
zipOutputStream.close()
|
||||
}
|
||||
@ -178,7 +194,7 @@ class LogManager(
|
||||
fun internalLog(tag: String, logLevel: LogLevel, message: Any?) {
|
||||
runCatching {
|
||||
val line = LogLine(logLevel, getCurrentDateTime(), tag, message.toString())
|
||||
logFile.appendText("$line\n", Charsets.UTF_8)
|
||||
logFile.appendText("|$line\n", Charsets.UTF_8)
|
||||
lineAddListener(line)
|
||||
Log.println(logLevel.priority, tag, message.toString())
|
||||
}.onFailure {
|
||||
|
@ -237,11 +237,15 @@ class HomeSection : Section() {
|
||||
})
|
||||
|
||||
DropdownMenuItem(onClick = {
|
||||
val logFile = context.log.getLogFile()
|
||||
activityLauncherHelper.saveFile(logFile.name, "text/plain") { uri ->
|
||||
activityLauncherHelper.saveFile("snapenhance-logs-${System.currentTimeMillis()}.zip", "application/zip") { uri ->
|
||||
context.androidContext.contentResolver.openOutputStream(Uri.parse(uri))?.use {
|
||||
logFile.inputStream().copyTo(it)
|
||||
context.longToast("Saved logs to $uri")
|
||||
runCatching {
|
||||
context.log.exportLogsToZip(it)
|
||||
context.longToast("Saved logs to $uri")
|
||||
}.onFailure {
|
||||
context.longToast("Failed to save logs to $uri!")
|
||||
context.log.error("Failed to save logs to $uri!", it)
|
||||
}
|
||||
}
|
||||
}
|
||||
showDropDown = false
|
||||
|
@ -3,10 +3,13 @@ package me.rhunk.snapenhance.ui.manager.sections.home
|
||||
import androidx.compose.foundation.ScrollState
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.gestures.detectTapGestures
|
||||
import androidx.compose.foundation.horizontalScroll
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.defaultMinSize
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
@ -19,9 +22,12 @@ import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.KeyboardDoubleArrowDown
|
||||
import androidx.compose.material.icons.filled.KeyboardDoubleArrowUp
|
||||
import androidx.compose.material.icons.filled.OpenInNew
|
||||
import androidx.compose.material.icons.outlined.BugReport
|
||||
import androidx.compose.material.icons.outlined.Info
|
||||
import androidx.compose.material.icons.outlined.Report
|
||||
import androidx.compose.material.icons.outlined.Warning
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.FilledIconButton
|
||||
import androidx.compose.material3.FloatingActionButton
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
@ -36,13 +42,19 @@ import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.pointer.pointerInput
|
||||
import androidx.compose.ui.platform.LocalClipboardManager
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.compose.ui.window.Dialog
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import me.rhunk.snapenhance.Constants
|
||||
import me.rhunk.snapenhance.LogChannels
|
||||
import me.rhunk.snapenhance.LogLevel
|
||||
import me.rhunk.snapenhance.LogReader
|
||||
import me.rhunk.snapenhance.RemoteSideContext
|
||||
import me.rhunk.snapenhance.action.EnumAction
|
||||
@ -106,6 +118,7 @@ class HomeSubSection(
|
||||
@Composable
|
||||
fun LogsSection() {
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
val clipboardManager = LocalClipboardManager.current
|
||||
var lineCount by remember { mutableIntStateOf(0) }
|
||||
var logReader by remember { mutableStateOf<LogReader?>(null) }
|
||||
logListState = remember { LazyListState(0) }
|
||||
@ -120,12 +133,65 @@ class HomeSubSection(
|
||||
) {
|
||||
items(lineCount) { index ->
|
||||
val line = logReader?.getLogLine(index) ?: return@items
|
||||
var expand by remember { mutableStateOf(false) }
|
||||
Box(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(
|
||||
if (index % 2 == 0) MaterialTheme.colorScheme.surface else MaterialTheme.colorScheme.surfaceVariant
|
||||
)) {
|
||||
Text(text = line.message, modifier = Modifier.padding(9.dp), fontSize = 10.sp)
|
||||
)
|
||||
.pointerInput(Unit) {
|
||||
detectTapGestures(
|
||||
onLongPress = {
|
||||
coroutineScope.launch {
|
||||
clipboardManager.setText(AnnotatedString(line.message))
|
||||
}
|
||||
},
|
||||
onTap = {
|
||||
expand = !expand
|
||||
}
|
||||
)
|
||||
}) {
|
||||
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.horizontalScroll(ScrollState(0))
|
||||
.padding(4.dp)
|
||||
.defaultMinSize(minHeight = 30.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
if (!expand) {
|
||||
Icon(
|
||||
imageVector = when (line.logLevel) {
|
||||
LogLevel.DEBUG -> Icons.Outlined.BugReport
|
||||
LogLevel.ERROR, LogLevel.ASSERT -> Icons.Outlined.Report
|
||||
LogLevel.INFO, LogLevel.VERBOSE -> Icons.Outlined.Info
|
||||
LogLevel.WARN -> Icons.Outlined.Warning
|
||||
},
|
||||
contentDescription = null,
|
||||
)
|
||||
|
||||
Text(
|
||||
text = LogChannels.fromChannel(line.tag)?.shortName ?: line.tag,
|
||||
modifier = Modifier.padding(start = 4.dp),
|
||||
fontWeight = FontWeight.Light,
|
||||
fontSize = 10.sp,
|
||||
)
|
||||
|
||||
Text(
|
||||
text = line.dateTime,
|
||||
modifier = Modifier.padding(start = 4.dp, end = 4.dp),
|
||||
fontSize = 10.sp
|
||||
)
|
||||
}
|
||||
|
||||
Text(
|
||||
text = line.message.trimIndent(),
|
||||
fontSize = 10.sp,
|
||||
maxLines = if (expand) Int.MAX_VALUE else 6,
|
||||
overflow = if (expand) TextOverflow.Visible else TextOverflow.Ellipsis,
|
||||
softWrap = !expand,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -241,10 +241,26 @@ class ScopeContent(
|
||||
return
|
||||
}
|
||||
|
||||
Column {
|
||||
Text(text = group.name, maxLines = 1)
|
||||
Text(text = "participantsCount: ${group.participantsCount}", maxLines = 1)
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(10.dp)
|
||||
.fillMaxWidth(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Text(
|
||||
text = group.name,
|
||||
maxLines = 1,
|
||||
fontSize = 20.sp,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
Spacer(modifier = Modifier.height(5.dp))
|
||||
Text(
|
||||
text = "Participants: ${group.participantsCount}",
|
||||
maxLines = 1,
|
||||
fontSize = 12.sp,
|
||||
fontWeight = FontWeight.Light
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@ package me.rhunk.snapenhance.ui.manager.sections.social
|
||||
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
@ -39,6 +40,7 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
@ -147,8 +149,7 @@ class SocialSection : Section() {
|
||||
|
||||
if (listSize == 0) {
|
||||
item {
|
||||
//TODO: i18n
|
||||
Text(text = "No ${scope.key.lowercase()}s found")
|
||||
Text(text = "(empty)", modifier = Modifier.fillMaxWidth().padding(10.dp), textAlign = TextAlign.Center)
|
||||
}
|
||||
}
|
||||
|
||||
@ -172,9 +173,13 @@ class SocialSection : Section() {
|
||||
when (scope) {
|
||||
SocialScope.GROUP -> {
|
||||
val group = groupList[index]
|
||||
Column {
|
||||
Text(text = group.name, maxLines = 1)
|
||||
Text(text = "participantsCount: ${group.participantsCount}", maxLines = 1)
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(10.dp)
|
||||
.fillMaxSize(),
|
||||
verticalArrangement = Arrangement.Center
|
||||
) {
|
||||
Text(text = group.name, maxLines = 1, fontWeight = FontWeight.Bold)
|
||||
}
|
||||
}
|
||||
SocialScope.FRIEND -> {
|
||||
|
@ -1,8 +1,11 @@
|
||||
package me.rhunk.snapenhance
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.util.Log
|
||||
import de.robv.android.xposed.XposedBridge
|
||||
import me.rhunk.snapenhance.core.bridge.BridgeClient
|
||||
import me.rhunk.snapenhance.hook.HookStage
|
||||
import me.rhunk.snapenhance.hook.hook
|
||||
|
||||
enum class LogLevel(
|
||||
val letter: String,
|
||||
@ -24,10 +27,28 @@ enum class LogLevel(
|
||||
fun fromShortName(shortName: String): LogLevel? {
|
||||
return values().find { it.shortName == shortName }
|
||||
}
|
||||
|
||||
fun fromPriority(priority: Int): LogLevel? {
|
||||
return values().find { it.priority == priority }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum class LogChannels(val channel: String, val shortName: String) {
|
||||
CORE("SnapEnhanceCore", "core"),
|
||||
NATIVE("SnapEnhanceNative", "native"),
|
||||
MANAGER("SnapEnhanceManager", "manager"),
|
||||
XPOSED("LSPosed-Bridge", "xposed");
|
||||
|
||||
companion object {
|
||||
fun fromChannel(channel: String): LogChannels? {
|
||||
return values().find { it.channel == channel }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@SuppressLint("PrivateApi")
|
||||
class Logger(
|
||||
private val bridgeClient: BridgeClient
|
||||
) {
|
||||
@ -55,11 +76,31 @@ class Logger(
|
||||
}
|
||||
}
|
||||
|
||||
private var invokeOriginalPrintLog: (Int, String, String) -> Unit
|
||||
|
||||
init {
|
||||
val printLnMethod = Log::class.java.getDeclaredMethod("println", Int::class.java, String::class.java, String::class.java)
|
||||
printLnMethod.hook(HookStage.BEFORE) { param ->
|
||||
val priority = param.arg(0) as Int
|
||||
val tag = param.arg(1) as String
|
||||
val message = param.arg(2) as String
|
||||
internalLog(tag, LogLevel.fromPriority(priority) ?: LogLevel.INFO, message)
|
||||
}
|
||||
|
||||
invokeOriginalPrintLog = { priority, tag, message ->
|
||||
XposedBridge.invokeOriginalMethod(
|
||||
printLnMethod,
|
||||
null,
|
||||
arrayOf(priority, tag, message)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun internalLog(tag: String, logLevel: LogLevel, message: Any?) {
|
||||
runCatching {
|
||||
bridgeClient.broadcastLog(tag, logLevel.shortName, message.toString())
|
||||
}.onFailure {
|
||||
Log.println(logLevel.priority, tag, message.toString())
|
||||
invokeOriginalPrintLog(logLevel.priority, tag, message.toString())
|
||||
}
|
||||
}
|
||||
|
||||
@ -69,7 +110,7 @@ class Logger(
|
||||
|
||||
fun error(message: Any?, throwable: Throwable, tag: String = TAG) {
|
||||
internalLog(tag, LogLevel.ERROR, message)
|
||||
internalLog(tag, LogLevel.ERROR, throwable)
|
||||
internalLog(tag, LogLevel.ERROR, throwable.stackTraceToString())
|
||||
}
|
||||
|
||||
fun info(message: Any?, tag: String = TAG) = internalLog(tag, LogLevel.INFO, message)
|
||||
|
Loading…
x
Reference in New Issue
Block a user