update layout checking

This commit is contained in:
Helium314 2024-07-07 18:55:42 +02:00
parent 0bd76de9d9
commit 1bd585ab76
3 changed files with 12 additions and 5 deletions

View file

@ -337,7 +337,7 @@ sealed interface KeyData : AbstractKeyData {
} }
override fun compute(params: KeyboardParams): KeyData? { override fun compute(params: KeyboardParams): KeyData? {
require(groupId <= GROUP_ENTER) { "only groups up to GROUP_ENTER are supported" } require(groupId in 0..GROUP_ENTER) { "only positive groupIds up to GROUP_ENTER are supported" }
require(label.isNotEmpty() || type == KeyType.PLACEHOLDER || code != KeyCode.UNSPECIFIED) { "non-placeholder key has no code and no label" } require(label.isNotEmpty() || type == KeyType.PLACEHOLDER || code != KeyCode.UNSPECIFIED) { "non-placeholder key has no code and no label" }
require(width >= 0f || width == -1f) { "illegal width $width" } require(width >= 0f || width == -1f) { "illegal width $width" }
val newLabel = label.convertFlorisLabel().resolveStringLabel(params) val newLabel = label.convertFlorisLabel().resolveStringLabel(params)

View file

@ -20,6 +20,7 @@ import helium314.keyboard.keyboard.internal.keyboard_parser.addLocaleKeyTextsToP
import helium314.keyboard.latin.R import helium314.keyboard.latin.R
import helium314.keyboard.latin.common.Constants import helium314.keyboard.latin.common.Constants
import helium314.keyboard.latin.common.FileUtils import helium314.keyboard.latin.common.FileUtils
import kotlinx.serialization.SerializationException
import java.io.File import java.io.File
import java.io.IOException import java.io.IOException
import java.math.BigInteger import java.math.BigInteger
@ -75,6 +76,7 @@ fun loadCustomLayout(layoutContent: String, layoutName: String, languageTag: Str
.show() .show()
} }
/** @return true if json, false if simple, null if invalid */
private fun checkLayout(layoutContent: String, context: Context): Boolean? { private fun checkLayout(layoutContent: String, context: Context): Boolean? {
val params = KeyboardParams() val params = KeyboardParams()
params.mId = KeyboardLayoutSet.getFakeKeyboardId(KeyboardId.ELEMENT_ALPHABET) params.mId = KeyboardLayoutSet.getFakeKeyboardId(KeyboardId.ELEMENT_ALPHABET)
@ -85,18 +87,23 @@ private fun checkLayout(layoutContent: String, context: Context): Boolean? {
if (!checkKeys(keys)) if (!checkKeys(keys))
return null return null
return true return true
} catch (e: Exception) { Log.w(TAG, "error parsing custom json layout", e) } } catch (e: SerializationException) {
Log.w(TAG, "json parsing error", e)
} catch (e: Exception) {
Log.w(TAG, "json layout parsed, but considered invalid", e)
return null
}
try { try {
val keys = RawKeyboardParser.parseSimpleString(layoutContent).map { row -> row.map { it.toKeyParams(params) } } val keys = RawKeyboardParser.parseSimpleString(layoutContent).map { row -> row.map { it.toKeyParams(params) } }
if (!checkKeys(keys)) if (!checkKeys(keys))
return null return null
return false return false
} catch (e: Exception) { Log.w(TAG, "error parsing custom simple layout", e) } } catch (e: Exception) { Log.w(TAG, "error parsing custom simple layout", e) }
if (layoutContent.trimStart().startsWith("[")) { if (layoutContent.trimStart().startsWith("[") && layoutContent.trimEnd().endsWith("]")) {
// layout can't be loaded, assume it's json -> load json layout again because the error message shown to the user is from the most recent error // layout can't be loaded, assume it's json -> load json layout again because the error message shown to the user is from the most recent error
try { try {
RawKeyboardParser.parseJsonString(layoutContent).map { row -> row.mapNotNull { it.compute(params)?.toKeyParams(params) } } RawKeyboardParser.parseJsonString(layoutContent).map { row -> row.mapNotNull { it.compute(params)?.toKeyParams(params) } }
} catch (e: Exception) { Log.w(TAG, "error parsing custom json layout", e) } } catch (e: Exception) { Log.w(TAG, "json parsing error", e) }
} }
return null return null
} }

View file

@ -58,7 +58,7 @@ If the layout has exactly 2 keys in the bottom row, these keys will replace comm
* `codePoints`: when multiple code points should be entered, only available for `multi_text_key` * `codePoints`: when multiple code points should be entered, only available for `multi_text_key`
* `label`: text to display on the key, determined from code if empty * `label`: text to display on the key, determined from code if empty
* There are some special values, see the [label section](#labels) * There are some special values, see the [label section](#labels)
* `groupId`: which additional popup keys to show, `0` is default and does not add anything, `1` adds the comma popup keys, and `2` adds the period popup keys * `groupId`: which additional popup keys to show, `0` is default and does not add anything, `1` adds the comma popup keys, `2` adds the period popup keys, `3` adds the action key popup keys (looks awkward though)
* `popup`: list of keys to add in the popup, e.g. `"label": ")", "popup": {"relevant": [{ "label": "." }]}` is a `)` key with a `.` popup * `popup`: list of keys to add in the popup, e.g. `"label": ")", "popup": {"relevant": [{ "label": "." }]}` is a `)` key with a `.` popup
* Note that in popup keys, properties are ignored with the exception of `$`, `code`, `codePoints`, and `label` * Note that in popup keys, properties are ignored with the exception of `$`, `code`, `codePoints`, and `label`
* When specifying a _selector_ key class in a popup key, it will be evaluated correctly (e.g. for changing popups dependent on shift state) * When specifying a _selector_ key class in a popup key, it will be evaluated correctly (e.g. for changing popups dependent on shift state)