From c064ba199c2558be73665280c5981e09a7b628c1 Mon Sep 17 00:00:00 2001 From: Helium314 Date: Sat, 15 Jun 2024 21:54:47 +0200 Subject: [PATCH] move that special handling for emoji and language switch keys into layouts for that, a new keyboard_state_selector is added this allows modifying functional key layouts without having to manually adjust those keys --- README.md | 1 + .../main/assets/layouts/functional_keys.json | 6 +- .../keyboard_parser/KeyboardParser.kt | 11 +--- .../keyboard_parser/RawKeyboardParser.kt | 2 + .../keyboard_parser/floris/KeyData.kt | 59 ++++++++++++++++--- layouts.md | 4 +- 6 files changed, 61 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index bcbfa65f..04cb2158 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,7 @@ Features that may go unnoticed, and further potentially useful information * Select text and press shift to switch between uppercase, lowercase and capitalize words * You can add dictionaries by opening the file * This only works with _content-uris_ and not with _file-uris_, meaning that it may not work with some file explorers. +* Not really a feature, but you can restart the keyboard by going to the settings and swiping it away from recents * _Debug mode / debug APK_ * Long-press a suggestion in the suggestion strip twice to show the source dictionary. * When using debug APK, you can find _Debug Settings_ within the _Advanced Preferences_, though the usefulness is limited except for dumping dictionaries into the log. diff --git a/app/src/main/assets/layouts/functional_keys.json b/app/src/main/assets/layouts/functional_keys.json index 85830901..6d28dd24 100644 --- a/app/src/main/assets/layouts/functional_keys.json +++ b/app/src/main/assets/layouts/functional_keys.json @@ -11,9 +11,9 @@ "email": { "label": "@", "groupId": 1, "type": "function" }, "uri": { "label": "/", "groupId": 1, "type": "function" } }, - { "label": "language_switch" }, - { "label": "emoji" }, - { "label": "numpad" }, + { "$": "keyboard_state_selector", "languageKeyEnabled": { "$": "keyboard_state_selector", "alphabet": { "label": "language_switch" }}}, + { "$": "keyboard_state_selector", "emojiKeyEnabled": { "$": "keyboard_state_selector", "alphabet": { "label": "emoji" }}}, + { "$": "keyboard_state_selector", "symbols": { "label": "numpad" }}, { "label": "space" }, { "label": "period", "labelFlags": 1073741824 }, { "label": "action", "width": 0.15 } diff --git a/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/KeyboardParser.kt b/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/KeyboardParser.kt index b95994cc..c74991d7 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/KeyboardParser.kt +++ b/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/KeyboardParser.kt @@ -198,16 +198,7 @@ class KeyboardParser(private val params: KeyboardParams, private val context: Co val functionalKeysBottom = allFunctionalKeys.lastOrNull() ?: return if (!params.mId.isAlphaOrSymbolKeyboard || functionalKeysBottom.isEmpty() || functionalKeysBottom.any { it.isKeyPlaceholder() }) return - if (!Settings.getInstance().current.mHasCustomFunctionalLayout) { - // remove keys that should only exist on specific layouts or depend on setting (emoji, numpad, language switch) - if (!Settings.getInstance().current.mShowsEmojiKey || !params.mId.isAlphabetKeyboard) - functionalKeysBottom.removeFirst { it.label == toolbarKeyStrings[ToolbarKey.EMOJI] } - if (!Settings.getInstance().current.isLanguageSwitchKeyEnabled || !params.mId.isAlphabetKeyboard) - functionalKeysBottom.removeFirst { it.label == KeyLabel.LANGUAGE_SWITCH } - if (params.mId.mElementId != KeyboardId.ELEMENT_SYMBOLS) - functionalKeysBottom.removeFirst { it.label == KeyLabel.NUMPAD } - } - // replace comma / period if 2 keys in normal bottom row + // replace comma / period if 2 keys in normal bottom row if (baseKeys.last().size == 2) { functionalKeysBottom.replaceFirst( { it.label == KeyLabel.COMMA || it.groupId == KeyData.GROUP_COMMA}, diff --git a/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/RawKeyboardParser.kt b/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/RawKeyboardParser.kt index 37b532b8..69abe164 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/RawKeyboardParser.kt +++ b/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/RawKeyboardParser.kt @@ -11,6 +11,7 @@ import helium314.keyboard.keyboard.internal.keyboard_parser.floris.CaseSelector import helium314.keyboard.keyboard.internal.keyboard_parser.floris.CharWidthSelector import helium314.keyboard.keyboard.internal.keyboard_parser.floris.KanaSelector import helium314.keyboard.keyboard.internal.keyboard_parser.floris.KeyData +import helium314.keyboard.keyboard.internal.keyboard_parser.floris.KeyboardStateSelector import helium314.keyboard.keyboard.internal.keyboard_parser.floris.LayoutDirectionSelector import helium314.keyboard.keyboard.internal.keyboard_parser.floris.MultiTextKeyData import helium314.keyboard.keyboard.internal.keyboard_parser.floris.ShiftStateSelector @@ -171,6 +172,7 @@ object RawKeyboardParser { subclass(CaseSelector::class, CaseSelector.serializer()) subclass(ShiftStateSelector::class, ShiftStateSelector.serializer()) subclass(VariationSelector::class, VariationSelector.serializer()) + subclass(KeyboardStateSelector::class, KeyboardStateSelector.serializer()) subclass(LayoutDirectionSelector::class, LayoutDirectionSelector.serializer()) subclass(CharWidthSelector::class, CharWidthSelector.serializer()) subclass(KanaSelector::class, KanaSelector.serializer()) diff --git a/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/floris/KeyData.kt b/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/floris/KeyData.kt index c9d53acb..7c8b0736 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/floris/KeyData.kt +++ b/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/floris/KeyData.kt @@ -9,7 +9,6 @@ import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import helium314.keyboard.keyboard.KeyboardId import helium314.keyboard.keyboard.internal.KeyboardParams -import helium314.keyboard.latin.common.StringUtils // taken from FlorisBoard, small modifications // popup not nullable (maybe change back, but currently that's necessary for number keys) @@ -131,9 +130,7 @@ class ShiftStateSelector( } /** - * Allows to select an [AbstractKeyData] based on the current variation. Note that this type of selector only really - * makes sense in a text context, though technically speaking it can be used anywhere, so this implementation allows - * for any [AbstractKeyData] to be used here. The JSON class identifier for this selector is `variation_selector`. + * Allows to select an [AbstractKeyData] based on the current variation. The JSON class identifier for this selector is `variation_selector`. * * Example usage in a layout JSON file: * ``` @@ -155,6 +152,12 @@ class ShiftStateSelector( * [default] will be used instead. * @property password The key data to use if [KeyboardId.passwordInput] return true. If this value is * null, [default] will be used instead. + * @property date The key data to use if [KeyboardId.MODE_DATE] is active. If this value is null, + * null, [default] will be used instead. + * @property time The key data to use if [KeyboardId.MODE_TIME] is active. If this value is null, + * null, [default] will be used instead. + * @property datetime The key data to use if [KeyboardId.MODE_DATETIME] is active. If this value is null, + * null, [default] will be used instead. */ @Serializable @SerialName("variation_selector") @@ -170,16 +173,13 @@ data class VariationSelector( ) : AbstractKeyData { override fun compute(params: KeyboardParams): KeyData? { return when { - // todo: what is normal and all? -// KeyVariation.ALL -> default -// KeyVariation.NORMAL -> normal ?: default params.mId.passwordInput() -> password ?: default params.mId.mMode == KeyboardId.MODE_EMAIL -> email ?: default params.mId.mMode == KeyboardId.MODE_URL -> uri ?: default params.mId.mMode == KeyboardId.MODE_DATE -> date ?: default params.mId.mMode == KeyboardId.MODE_TIME -> time ?: default params.mId.mMode == KeyboardId.MODE_DATETIME -> datetime ?: default - else -> default + else -> normal ?: default }?.compute(params) } @@ -188,6 +188,49 @@ data class VariationSelector( } } +/** + * Allows to select an [AbstractKeyData] based on states saved in [KeyboardId]. + * The JSON class identifier for this selector is `keyboard_state_selector`. + * Note that the conditions are checked in order as given below, and the first non-null AbstractKeyData is selected. + * + * @property emojiKeyEnabled The key data to use if [KeyboardId.mEmojiKeyEnabled] is true. + * @property languageKeyEnabled The key data to use if [KeyboardId.mLanguageSwitchKeyEnabled] is true. + * @property symbols The key data to use if [KeyboardId.mElementId] is [KeyboardId.ELEMENT_SYMBOLS]. + * @property moreSymbols The key data to use if [KeyboardId.mElementId] is [KeyboardId.ELEMENT_SYMBOLS_SHIFTED]. + * @property alphabet The key data to use if [KeyboardId.isAlphabetKeyboard] is true. + * @property default The default key data which should be used in case none of the other conditions have a matching non-null + * AbstractKeyData. Can be null, in this case no key is displayed. + */ +@Serializable +@SerialName("keyboard_state_selector") +class KeyboardStateSelector( + val emojiKeyEnabled: AbstractKeyData? = null, + val languageKeyEnabled: AbstractKeyData? = null, + val symbols: AbstractKeyData? = null, + val moreSymbols: AbstractKeyData? = null, + val alphabet: AbstractKeyData? = null, + val default: AbstractKeyData? = null, +) : AbstractKeyData { + override fun compute(params: KeyboardParams): KeyData? { + if (params.mId.mEmojiKeyEnabled) + emojiKeyEnabled?.compute(params)?.let { return it } + if (params.mId.mLanguageSwitchKeyEnabled) + languageKeyEnabled?.compute(params)?.let { return it } + if (params.mId.mElementId == KeyboardId.ELEMENT_SYMBOLS) + symbols?.compute(params)?.let { return it } + if (params.mId.mElementId == KeyboardId.ELEMENT_SYMBOLS_SHIFTED) + moreSymbols?.compute(params)?.let { return it } + if (params.mId.isAlphabetKeyboard) + alphabet?.compute(params)?.let { return it } + + return default?.compute(params) + } + + override fun asString(isForDisplay: Boolean): String { + return "" + } +} + /** * Allows to select an [AbstractKeyData] based on the current layout direction. Note that this type of selector only * really makes sense in a text context, though technically speaking it can be used anywhere, so this implementation diff --git a/layouts.md b/layouts.md index c7361471..958942cd 100644 --- a/layouts.md +++ b/layouts.md @@ -33,7 +33,9 @@ If the layout has exactly 2 keys in the bottom row, these keys will replace comm * there are also selector classes, which allow to change keys conditionally, see the [dvorak layout](https://github.com/Helium314/HeliBoard/blob/main/app/src/main/assets/layouts/dvorak.json) for an example: * `case_selector`: keys for `lower` and `upper` (both mandatory), similar to `shift_state_selector` * `shift_state_selector`: keys for `unshifted`, `shifted`, `shiftedManual`, `shiftedAutomatic`, `capsLock`, `manualOrLocked`, `default` (all optional) - * `variation_selector`: keys for `datetime`, `time`, `date`, `password`, `normal`, `uri`, `email`, `default` (all optional) + * `variation_selector`: keys for input types `datetime`, `time`, `date`, `password`, `normal`, `uri`, `email`, `default` (all optional) + * `keyboard_state_selector`: keys for `emojiKeyEnabled`, `languageKeyEnabled`, `symbols`, `moreSymbols`, `alphabet`, `default` (all optional) + * the `keyEnabled` keys will be used if the corresponding setting is enabled, `symbols`, `moreSymbols`, `alphabet` will be used when the said keyboard view is active * `layout_direction_selector`: keys for `ltr` and `rtl` (both mandatory) ### Properties * A (non-selector) key can have the following properties: