mirror of
https://github.com/gkd-kit/gkd.git
synced 2024-11-16 19:57:15 +08:00
perf: 规则使用JSON5编辑复制
This commit is contained in:
parent
4cd992fdda
commit
3c49b60924
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
84
app/src/main/kotlin/li/songe/gkd/util/Json5.kt
Normal file
84
app/src/main/kotlin/li/songe/gkd/util/Json5.kt
Normal 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))
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user