perf: 规则使用JSON5编辑复制

This commit is contained in:
lisonge 2023-12-06 16:28:52 +08:00
parent 4cd992fdda
commit 3c49b60924
3 changed files with 103 additions and 17 deletions

View File

@ -1,6 +1,5 @@
package li.songe.gkd.ui package li.songe.gkd.ui
import androidx.compose.foundation.Image
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
@ -63,6 +62,7 @@ import li.songe.gkd.ui.destinations.GroupItemPageDestination
import li.songe.gkd.util.LocalNavController import li.songe.gkd.util.LocalNavController
import li.songe.gkd.util.ProfileTransitions import li.songe.gkd.util.ProfileTransitions
import li.songe.gkd.util.appInfoCacheFlow import li.songe.gkd.util.appInfoCacheFlow
import li.songe.gkd.util.encodeToJson5String
import li.songe.gkd.util.json import li.songe.gkd.util.json
import li.songe.gkd.util.launchAsFn import li.songe.gkd.util.launchAsFn
import li.songe.gkd.util.launchTry import li.songe.gkd.util.launchTry
@ -257,7 +257,7 @@ fun AppItemPage(
} }
} }
TextButton(onClick = { TextButton(onClick = {
val groupAppText = json.encodeToString( val groupAppText = json.encodeToJson5String(
appRaw?.copy( appRaw?.copy(
groups = listOf(showGroupItemVal) groups = listOf(showGroupItemVal)
) )
@ -291,14 +291,15 @@ fun AppItemPage(
.clickable { .clickable {
vm.viewModelScope.launchTry(Dispatchers.IO) { vm.viewModelScope.launchTry(Dispatchers.IO) {
val subsRaw = subsIdToRawFlow.value[subsItemId] ?: return@launchTry val subsRaw = subsIdToRawFlow.value[subsItemId] ?: return@launchTry
val newSubsRaw = subsRaw.copy(apps = subsRaw.apps val newSubsRaw = subsRaw.copy(
.toMutableList() apps = subsRaw.apps
.apply { .toMutableList()
set( .apply {
indexOfFirst { a -> a.id == appRawVal.id }, set(
appRawVal.copy(groups = appRawVal.groups.filter { g -> g.key != menuGroupRaw.key }) indexOfFirst { a -> a.id == appRawVal.id },
) appRawVal.copy(groups = appRawVal.groups.filter { g -> g.key != menuGroupRaw.key })
}) )
})
subsItemVal.subsFile.writeText( subsItemVal.subsFile.writeText(
json.encodeToString( json.encodeToString(
newSubsRaw newSubsRaw
@ -321,7 +322,7 @@ fun AppItemPage(
if (editGroupRaw != null && appRawVal != null && subsItemVal != null) { if (editGroupRaw != null && appRawVal != null && subsItemVal != null) {
var source by remember { var source by remember {
mutableStateOf(json.encodeToString(editGroupRaw)) mutableStateOf(json.encodeToJson5String(editGroupRaw))
} }
val oldSource = remember { source } val oldSource = remember { source }
AlertDialog( AlertDialog(
@ -365,7 +366,8 @@ fun AppItemPage(
setEditGroupRaw(null) setEditGroupRaw(null)
val subsRaw = subsIdToRawFlow.value[subsItemId] ?: return@TextButton val subsRaw = subsIdToRawFlow.value[subsItemId] ?: return@TextButton
val newSubsRaw = subsRaw.copy(apps = subsRaw.apps.toMutableList().apply { val newSubsRaw = subsRaw.copy(apps = subsRaw.apps.toMutableList().apply {
set(indexOfFirst { a -> a.id == appRawVal.id }, set(
indexOfFirst { a -> a.id == appRawVal.id },
appRawVal.copy(groups = appRawVal.groups.toMutableList().apply { appRawVal.copy(groups = appRawVal.groups.toMutableList().apply {
set( set(
indexOfFirst { g -> g.key == newGroupRaw.key }, newGroupRaw indexOfFirst { g -> g.key == newGroupRaw.key }, newGroupRaw
@ -441,7 +443,8 @@ fun AppItemPage(
val newKey = appRawVal.groups.maxBy { g -> g.key }.key + 1 val newKey = appRawVal.groups.maxBy { g -> g.key }.key + 1
val subsRaw = subsIdToRawFlow.value[subsItemId] ?: return@TextButton val subsRaw = subsIdToRawFlow.value[subsItemId] ?: return@TextButton
val newSubsRaw = subsRaw.copy(apps = subsRaw.apps.toMutableList().apply { val newSubsRaw = subsRaw.copy(apps = subsRaw.apps.toMutableList().apply {
set(indexOfFirst { a -> a.id == appRawVal.id }, set(
indexOfFirst { a -> a.id == appRawVal.id },
appRawVal.copy(groups = appRawVal.groups + tempGroups.mapIndexed { i, g -> appRawVal.copy(groups = appRawVal.groups + tempGroups.mapIndexed { i, g ->
g.copy( g.copy(
key = newKey + i key = newKey + i

View File

@ -61,6 +61,7 @@ import li.songe.gkd.ui.destinations.AppItemPageDestination
import li.songe.gkd.util.LocalNavController import li.songe.gkd.util.LocalNavController
import li.songe.gkd.util.ProfileTransitions import li.songe.gkd.util.ProfileTransitions
import li.songe.gkd.util.appInfoCacheFlow import li.songe.gkd.util.appInfoCacheFlow
import li.songe.gkd.util.encodeToJson5String
import li.songe.gkd.util.json import li.songe.gkd.util.json
import li.songe.gkd.util.launchAsFn import li.songe.gkd.util.launchAsFn
import li.songe.gkd.util.launchTry import li.songe.gkd.util.launchTry
@ -306,7 +307,7 @@ fun SubsPage(
val editAppRawVal = editAppRaw val editAppRawVal = editAppRaw
if (editAppRawVal != null && subsItemVal != null && subsRaw != null) { if (editAppRawVal != null && subsItemVal != null && subsRaw != null) {
var source by remember { var source by remember {
mutableStateOf(json.encodeToString(editAppRawVal)) mutableStateOf(json.encodeToJson5String(editAppRawVal))
} }
AlertDialog(title = { Text(text = "编辑本地APP规则") }, text = { AlertDialog(title = { Text(text = "编辑本地APP规则") }, text = {
OutlinedTextField( OutlinedTextField(
@ -367,9 +368,7 @@ fun SubsPage(
Text(text = "复制", modifier = Modifier Text(text = "复制", modifier = Modifier
.clickable { .clickable {
ClipboardUtils.copyText( ClipboardUtils.copyText(
json.encodeToString( json.encodeToJson5String(menuAppRawVal)
menuAppRawVal
)
) )
ToastUtils.showShort("复制成功") ToastUtils.showShort("复制成功")
menuAppRaw = null menuAppRaw = null

View File

@ -0,0 +1,84 @@
package li.songe.gkd.util
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonArray
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.JsonPrimitive
import kotlinx.serialization.serializer
private val json5IdentifierReg = Regex("[a-zA-Z_][a-zA-Z0-9_]*")
/**
* https://spec.json5.org/#strings
*/
private fun escapeString(value: String): String {
val wrapChar = '\''
val sb = StringBuilder()
sb.append(wrapChar)
value.forEach { c ->
val escapeChar = when (c) {
wrapChar -> wrapChar
'\n' -> 'n'
'\r' -> 'r'
'\t' -> 't'
'\b' -> 'b'
'\\' -> '\\'
else -> null
}
if (escapeChar != null) {
sb.append("\\" + escapeChar)
} else {
when (c.code) {
in 0..0xf -> {
sb.append("\\x0" + c.code.toString(16))
}
in 0..0x1f -> {
sb.append("\\x" + c.code.toString(16))
}
else -> {
sb.append(c)
}
}
}
}
sb.append(wrapChar)
return sb.toString()
}
fun convertJsonElementToJson5(element: JsonElement): String {
return when (element) {
is JsonPrimitive -> {
val content = element.content
if (element.isString) {
escapeString(content)
} else {
content
}
}
is JsonObject -> {
// Handle JSON objects
val entries = element.entries.joinToString(",") { (key, value) ->
// If key is a valid identifier, no quotes are needed
if (key.matches(json5IdentifierReg)) {
"$key:${convertJsonElementToJson5(value)}"
} else {
"${escapeString(key)}:${convertJsonElementToJson5(value)}"
}
}
"{$entries}"
}
is JsonArray -> {
val elements = element.joinToString(",") { convertJsonElementToJson5(it) }
"[$elements]"
}
}
}
inline fun <reified T> Json.encodeToJson5String(value: T): String {
return convertJsonElementToJson5(encodeToJsonElement(serializersModule.serializer(), value))
}