diff --git a/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/floris/TextKeyData.kt b/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/floris/TextKeyData.kt index c5ec0ad6..dc527ce5 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/floris/TextKeyData.kt +++ b/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/floris/TextKeyData.kt @@ -337,7 +337,7 @@ sealed interface KeyData : AbstractKeyData { } 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(width >= 0f || width == -1f) { "illegal width $width" } val newLabel = label.convertFlorisLabel().resolveStringLabel(params) diff --git a/app/src/main/java/helium314/keyboard/latin/utils/CustomLayoutUtils.kt b/app/src/main/java/helium314/keyboard/latin/utils/CustomLayoutUtils.kt index e5ce2773..c314865d 100644 --- a/app/src/main/java/helium314/keyboard/latin/utils/CustomLayoutUtils.kt +++ b/app/src/main/java/helium314/keyboard/latin/utils/CustomLayoutUtils.kt @@ -20,6 +20,7 @@ import helium314.keyboard.keyboard.internal.keyboard_parser.addLocaleKeyTextsToP import helium314.keyboard.latin.R import helium314.keyboard.latin.common.Constants import helium314.keyboard.latin.common.FileUtils +import kotlinx.serialization.SerializationException import java.io.File import java.io.IOException import java.math.BigInteger @@ -75,6 +76,7 @@ fun loadCustomLayout(layoutContent: String, layoutName: String, languageTag: Str .show() } +/** @return true if json, false if simple, null if invalid */ private fun checkLayout(layoutContent: String, context: Context): Boolean? { val params = KeyboardParams() params.mId = KeyboardLayoutSet.getFakeKeyboardId(KeyboardId.ELEMENT_ALPHABET) @@ -85,18 +87,23 @@ private fun checkLayout(layoutContent: String, context: Context): Boolean? { if (!checkKeys(keys)) return null 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 { val keys = RawKeyboardParser.parseSimpleString(layoutContent).map { row -> row.map { it.toKeyParams(params) } } if (!checkKeys(keys)) return null return false } 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 try { 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 } diff --git a/layouts.md b/layouts.md index e6576eb4..bad08561 100644 --- a/layouts.md +++ b/layouts.md @@ -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` * `label`: text to display on the key, determined from code if empty * 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 * 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)