feat: make map and []any config fields editable as JSON text in Android UI
Replace ReadOnlyField with JsonField composable that provides multi-line JSON editing with real-time validation feedback. Add prettyPrint serialization for readable display and parseToJsonElement for save, letting parse errors propagate to the existing error snackbar. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
76d669efb5
commit
7746cafe50
2 changed files with 23 additions and 6 deletions
|
|
@ -201,7 +201,7 @@ private fun ConfigField(
|
|||
"float" -> NumberField(field, onValueChanged, KeyboardType.Decimal)
|
||||
"[]string" -> StringArrayField(field, onValueChanged)
|
||||
"directory" -> DirectoryField(field, onValueChanged, snackbarHostState)
|
||||
"map", "[]any" -> ReadOnlyField(field)
|
||||
"map", "[]any" -> JsonField(field, onValueChanged)
|
||||
else -> StringField(field, onValueChanged)
|
||||
}
|
||||
}
|
||||
|
|
@ -296,13 +296,26 @@ private fun StringArrayField(field: FieldState, onValueChanged: (String) -> Unit
|
|||
}
|
||||
|
||||
@Composable
|
||||
private fun ReadOnlyField(field: FieldState) {
|
||||
private fun JsonField(field: FieldState, onValueChanged: (String) -> Unit) {
|
||||
val jsonError = remember(field.value) {
|
||||
if (field.value.isBlank()) null
|
||||
else try {
|
||||
kotlinx.serialization.json.Json.parseToJsonElement(field.value); null
|
||||
} catch (e: Exception) {
|
||||
e.message
|
||||
}
|
||||
}
|
||||
|
||||
OutlinedTextField(
|
||||
value = field.value.ifEmpty { "(complex value)" },
|
||||
onValueChange = {},
|
||||
value = field.value,
|
||||
onValueChange = onValueChanged,
|
||||
label = { Text(field.label, color = TextSecondary) },
|
||||
readOnly = true,
|
||||
enabled = false,
|
||||
singleLine = false,
|
||||
minLines = 3,
|
||||
isError = jsonError != null,
|
||||
supportingText = if (jsonError != null) {
|
||||
{ Text(jsonError, color = MaterialTheme.colorScheme.error) }
|
||||
} else null,
|
||||
colors = configFieldColors(),
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import kotlinx.coroutines.flow.StateFlow
|
|||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.JsonArray
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
import kotlinx.serialization.json.JsonNull
|
||||
|
|
@ -29,6 +30,7 @@ class ConfigViewModel(private val apiClient: ConfigApiClient) : ViewModel() {
|
|||
private var configValues: JsonObject? = null
|
||||
private var saveJob: Job? = null
|
||||
private var pendingSectionKey: String? = null
|
||||
private val prettyJson = Json { prettyPrint = true }
|
||||
|
||||
init {
|
||||
loadData()
|
||||
|
|
@ -193,6 +195,7 @@ class ConfigViewModel(private val apiClient: ConfigApiClient) : ViewModel() {
|
|||
element.map { it.jsonPrimitive.contentOrNull ?: "" }.joinToString(", ")
|
||||
} else ""
|
||||
}
|
||||
"map", "[]any" -> prettyJson.encodeToString(JsonElement.serializer(), element)
|
||||
else -> (element as? JsonPrimitive)?.contentOrNull ?: element.toString()
|
||||
}
|
||||
}
|
||||
|
|
@ -232,6 +235,7 @@ class ConfigViewModel(private val apiClient: ConfigApiClient) : ViewModel() {
|
|||
.filter { it.isNotEmpty() }
|
||||
.map { JsonPrimitive(it) }
|
||||
)
|
||||
"map", "[]any" -> prettyJson.parseToJsonElement(field.value)
|
||||
else -> JsonPrimitive(field.value)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue