diff --git a/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/Key.java b/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/Key.java index bd81fb1c..5706f7ec 100644 --- a/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/Key.java +++ b/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/Key.java @@ -17,8 +17,10 @@ import org.dslul.openboard.inputmethod.keyboard.internal.KeyVisualAttributes; import org.dslul.openboard.inputmethod.keyboard.internal.KeyboardIconsSet; import org.dslul.openboard.inputmethod.keyboard.internal.KeyboardParams; import org.dslul.openboard.inputmethod.keyboard.internal.MoreKeySpec; +import org.dslul.openboard.inputmethod.keyboard.internal.keyboard_parser.floris.PopupSet; import org.dslul.openboard.inputmethod.latin.common.Constants; import org.dslul.openboard.inputmethod.latin.common.StringUtils; +import org.dslul.openboard.inputmethod.latin.utils.MoreKeysUtilsKt; import java.util.Arrays; import java.util.Locale; @@ -1047,9 +1049,9 @@ public class Key implements Comparable { final float relativeWidth, final int labelFlags, final int backgroundType, - @Nullable final String[] layoutMoreKeys + @Nullable final PopupSet popupSet ) { - this(keySpec, KeySpecParser.getCode(keySpec), params, relativeWidth, labelFlags, backgroundType, layoutMoreKeys); + this(keySpec, KeySpecParser.getCode(keySpec), params, relativeWidth, labelFlags, backgroundType, popupSet); } /** @@ -1064,7 +1066,7 @@ public class Key implements Comparable { final float relativeWidth, final int labelFlags, final int backgroundType, - @Nullable final String[] layoutMoreKeys // same style as current moreKeys (relevant for the special keys) + @Nullable final PopupSet popupSet ) { mKeyboardParams = params; mBackgroundType = backgroundType; @@ -1079,15 +1081,9 @@ public class Key implements Comparable { if (params.mId.isNumberLayout()) actionFlags = ACTION_FLAGS_NO_KEY_PREVIEW; - final String[] languageMoreKeys = params.mLocaleKeyTexts.getMoreKeys(keySpec); - if (languageMoreKeys != null && layoutMoreKeys != null && languageMoreKeys[0].startsWith("!fixedColumnOrder!")) - languageMoreKeys[0] = null; // we change the number of keys, so better not use fixedColumnOrder to avoid awkward layout - // todo: after removing old parser this could be done in a less awkward way without almostFinalMoreKeys - final String[] almostFinalMoreKeys = MoreKeySpec.insertAdditionalMoreKeys(languageMoreKeys, layoutMoreKeys); - mMoreKeysColumnAndFlags = getMoreKeysColumnAndFlagsAndSetNullInArray(params, almostFinalMoreKeys); - final String[] finalMoreKeys = almostFinalMoreKeys == null - ? null - : MoreKeySpec.filterOutEmptyString(almostFinalMoreKeys); + final String[] moreKeys = MoreKeysUtilsKt.createMoreKeysArray(popupSet, mKeyboardParams, keySpec); + mMoreKeysColumnAndFlags = getMoreKeysColumnAndFlagsAndSetNullInArray(params, moreKeys); + final String[] finalMoreKeys = moreKeys == null ? null : MoreKeySpec.filterOutEmptyString(moreKeys); if (finalMoreKeys != null) { actionFlags |= ACTION_FLAGS_ENABLE_LONG_PRESS; @@ -1116,18 +1112,8 @@ public class Key implements Comparable { mHintLabel = null; } else { // maybe also always null for comma and period keys - String hintLabel; - if (mKeyboardParams.mHintLabelFromFirstMoreKey) { - hintLabel = mMoreKeys == null ? null : mMoreKeys[0].mLabel; - if (hintLabel != null && backgroundType == BACKGROUND_TYPE_FUNCTIONAL && mKeyboardParams.mId.isAlphabetKeyboard()) - // bad workaround for the ugly comma label on period key, todo: do it better when re-working moreKey stuff - hintLabel = null; - } else { - hintLabel = layoutMoreKeys == null ? null : KeySpecParser.getLabel(layoutMoreKeys[0]); // note that some entries may have been changed to other string or null - // todo: this should be adjusted when re-working moreKey stuff... also KeySpecParser.getLabel may throw, which is bad when users do uncommon things - if (hintLabel != null && hintLabel.length() > 1 && hintLabel.startsWith("!")) // this is not great, but other than removing com key label this is definitely ok - hintLabel = null; - } + // todo: maybe remove mKeyboardParams.mHintLabelFromFirstMoreKey? + final String hintLabel = MoreKeysUtilsKt.getHintLabel(popupSet, params, keySpec); mHintLabel = needsToUpcase ? StringUtils.toTitleCaseOfKeyLabel(hintLabel, localeForUpcasing) : hintLabel; diff --git a/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/KeyboardBuilder.kt b/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/KeyboardBuilder.kt index 4c37bb1b..4d96ac7f 100644 --- a/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/KeyboardBuilder.kt +++ b/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/KeyboardBuilder.kt @@ -49,18 +49,10 @@ open class KeyboardBuilder(protected val mContext: Context, // todo: further plan // after the old parser is removed - // finally the spanish/german/swiss/nordic layouts can be removed and replaced by some hasExtraKeys parameter - // still they should keep their name though... or switch to sth like "default"? - // also the "eo" check could then be removed - // and maybe the language -> layout thing could be moved to assets? and maybe even here the extra keys could be defined... + // maybe the language -> layout thing could be moved to assets? and maybe even here the extra keys could be defined... // should be either both in method.xml, or both in assets (actually method might be more suitable) // go through a lot of todos in parsers, key, keyboardlayoutset, ... as a lot of things should only change after old parser is removed - // also remove the keybpard_layout_set files? - // they are still in use e.g. for enableProximityCharsCorrection and supportedScript - // but ideally this should be replaced - // enableProximityCharsCorrection should be in LayoutInfos - // supportedScript could be determined using ScriptUtils, but first make sure that there is less latin fallback happening - // or use locale to store script, but that's only possible starting at api 21 + // also remove the keyboard_layout_set files? // allow users to define their own layouts (maybe do everything else first?) // need to solve the scaling issue with number row and 5 row keyboards // write up how things work for users, also regarding language more keys @@ -125,7 +117,10 @@ open class KeyboardBuilder(protected val mContext: Context, keysInRows = EmojiParser(mParams, mContext).parse() } else { try { - addLocaleKeyTextsToParams(mContext, mParams, Settings.getInstance().current.mShowMoreKeys) + val sv = Settings.getInstance().current + addLocaleKeyTextsToParams(mContext, mParams, sv.mShowMoreMoreKeys) + mParams.mMoreKeyTypes.addAll(sv.mMoreKeyTypes) + mParams.mMoreKeyLabelSources.addAll(sv.mMoreKeyLabelSources) keysInRows = KeyboardParser.parseFromAssets(mParams, mContext) determineAbsoluteValues() } catch (e: Exception) { diff --git a/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/KeyboardParams.java b/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/KeyboardParams.java index e9a86fe7..16c26a96 100644 --- a/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/KeyboardParams.java +++ b/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/KeyboardParams.java @@ -81,11 +81,12 @@ public class KeyboardParams { public final KeyboardIconsSet mIconsSet = new KeyboardIconsSet(); @NonNull // todo: not good, this only works because params are currently always created for the active subtype public final List mSecondaryLocales = Settings.getInstance().getCurrent().mSecondaryLocales; + public final ArrayList mMoreKeyTypes = new ArrayList<>(); + public final ArrayList mMoreKeyLabelSources = new ArrayList<>(); @NonNull private final UniqueKeysCache mUniqueKeysCache; public boolean mAllowRedundantMoreKeys; - public final boolean mHintLabelFromFirstMoreKey = Settings.getInstance().getCurrent().mHintLabelFromFirstMoreKey; @NonNull public LocaleKeyTexts mLocaleKeyTexts; diff --git a/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/keyboard_parser/KeyboardParser.kt b/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/keyboard_parser/KeyboardParser.kt index ec126055..bb57ab5d 100644 --- a/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/keyboard_parser/KeyboardParser.kt +++ b/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/keyboard_parser/KeyboardParser.kt @@ -16,6 +16,7 @@ import org.dslul.openboard.inputmethod.keyboard.internal.KeyboardIconsSet import org.dslul.openboard.inputmethod.keyboard.internal.KeyboardParams import org.dslul.openboard.inputmethod.keyboard.internal.keyboard_parser.floris.KeyData import org.dslul.openboard.inputmethod.keyboard.internal.keyboard_parser.floris.KeyType +import org.dslul.openboard.inputmethod.keyboard.internal.keyboard_parser.floris.SimplePopups import org.dslul.openboard.inputmethod.latin.R import org.dslul.openboard.inputmethod.latin.common.Constants import org.dslul.openboard.inputmethod.latin.common.splitOnWhitespace @@ -335,7 +336,7 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co "period" -> adjustedKeys?.last() else -> null } - val keyParams = getFunctionalKeyParams(it, adjustKey?.label, adjustKey?.popup?.toMoreKeys(params)) + val keyParams = getFunctionalKeyParams(it, adjustKey?.label, adjustKey?.popup?.getPopupKeyLabels(params)) if (key == "space") { // add the extra keys around space if (params.mId.mElementId == KeyboardId.ELEMENT_SYMBOLS) { bottomRow.add(getFunctionalKeyParams(FunctionalKey.NUMPAD)) @@ -346,7 +347,7 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co params.mDefaultRelativeKeyWidth, defaultLabelFlags, Key.BACKGROUND_TYPE_FUNCTIONAL, - adjustedKeys?.get(1)?.popup?.toMoreKeys(params) + adjustedKeys?.get(1)?.popup )) } else if (params.mId.mElementId == KeyboardId.ELEMENT_SYMBOLS_SHIFTED) { bottomRow.add(KeyParams( @@ -355,7 +356,7 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co params.mDefaultRelativeKeyWidth, defaultLabelFlags or Key.LABEL_FLAGS_HAS_POPUP_HINT, Key.BACKGROUND_TYPE_FUNCTIONAL, - adjustedKeys?.get(1)?.popup?.toMoreKeys(params) ?: arrayOf("!fixedColumnOrder!3", "‹", "≤", "«") + adjustedKeys?.get(1)?.popup ?: SimplePopups(listOf("!fixedColumnOrder!3", "‹", "≤", "«")) )) bottomRow.add(keyParams) bottomRow.add(KeyParams( @@ -364,7 +365,7 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co params.mDefaultRelativeKeyWidth, defaultLabelFlags or Key.LABEL_FLAGS_HAS_POPUP_HINT, Key.BACKGROUND_TYPE_FUNCTIONAL, - adjustedKeys?.get(2)?.popup?.toMoreKeys(params) ?: arrayOf("!fixedColumnOrder!3", "›", "≥", "»") + adjustedKeys?.get(2)?.popup ?: SimplePopups(listOf("!fixedColumnOrder!3", "›", "≥", "»")) )) } else { // alphabet if (params.mId.mLanguageSwitchKeyEnabled) @@ -390,7 +391,7 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co it.toKeyParams(params, additionalLabelFlags = Key.LABEL_FLAGS_DISABLE_HINT_LABEL or defaultLabelFlags) } - private fun getFunctionalKeyParams(def: String, label: String? = null, moreKeys: Array? = null): KeyParams { + private fun getFunctionalKeyParams(def: String, label: String? = null, moreKeys: Collection? = null): KeyParams { val split = def.trim().splitOnWhitespace() val key = FunctionalKey.valueOf(split[0].uppercase()) val width = if (split.size == 2) split[1].substringBefore("%").toFloat() / 100f @@ -398,7 +399,7 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co return getFunctionalKeyParams(key, width, label, moreKeys) } - private fun getFunctionalKeyParams(key: FunctionalKey, relativeWidth: Float? = null, label: String? = null, moreKeys: Array? = null): KeyParams { + private fun getFunctionalKeyParams(key: FunctionalKey, relativeWidth: Float? = null, label: String? = null, moreKeys: Collection? = null): KeyParams { // for comma and period: label will override default, moreKeys will be appended val width = relativeWidth ?: params.mDefaultRelativeKeyWidth return when (key) { @@ -427,7 +428,7 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co Key.LABEL_FLAGS_HAS_POPUP_HINT, // previously only if normal comma, but always is more correct if (label?.first()?.isLetter() == true) Key.BACKGROUND_TYPE_NORMAL // mimic behavior of old dvorak and halmak layouts else Key.BACKGROUND_TYPE_FUNCTIONAL, - moreKeys?.let { getCommaMoreKeys() + it } ?: getCommaMoreKeys() + SimplePopups(moreKeys?.let { getCommaMoreKeys() + it } ?: getCommaMoreKeys()) ) FunctionalKey.PERIOD -> KeyParams( // special period moreKey only in alphabet layout, except for ar and fa @@ -441,7 +442,7 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co or defaultLabelFlags, if (label?.first()?.isLetter() == true) Key.BACKGROUND_TYPE_NORMAL else Key.BACKGROUND_TYPE_FUNCTIONAL, - moreKeys?.let { getPunctuationMoreKeys() + it } ?: getPunctuationMoreKeys() + SimplePopups(moreKeys?.let { getPunctuationMoreKeys() + it } ?: getPunctuationMoreKeys()) ) FunctionalKey.SPACE -> KeyParams( getSpaceLabel(), @@ -462,7 +463,7 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co or Key.LABEL_FLAGS_HAS_POPUP_HINT or KeyboardTheme.getThemeActionAndEmojiKeyLabelFlags(params.mThemeId), Key.BACKGROUND_TYPE_ACTION, - getActionKeyMoreKeys() + getActionKeyMoreKeys()?.let { SimplePopups(it) } ) FunctionalKey.DELETE -> KeyParams( "!icon/delete_key|!code/key_delete", @@ -481,7 +482,7 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co if (params.mId.mElementId == KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED || params.mId.mElementId == KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCKED) Key.BACKGROUND_TYPE_STICKY_ON else Key.BACKGROUND_TYPE_STICKY_OFF, - if (params.mId.isAlphabetKeyboard) arrayOf("!noPanelAutoMoreKey!", " |!code/key_capslock") else null // why the alphabe morekeys actually? + if (params.mId.isAlphabetKeyboard) SimplePopups(listOf("!noPanelAutoMoreKey!", " |!code/key_capslock")) else null // why the alphabet morekeys actually? ) FunctionalKey.EMOJI -> KeyParams( "!icon/emoji_normal_key|!code/key_emoji", @@ -503,7 +504,7 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co width, Key.LABEL_FLAGS_AUTO_X_SCALE or Key.LABEL_FLAGS_FONT_NORMAL or Key.LABEL_FLAGS_HAS_POPUP_HINT or Key.LABEL_FLAGS_PRESERVE_CASE, Key.BACKGROUND_TYPE_FUNCTIONAL, - arrayOf(Key.MORE_KEYS_HAS_LABELS, ".net", ".org", ".gov", ".edu") + SimplePopups(listOf(Key.MORE_KEYS_HAS_LABELS, ".net", ".org", ".gov", ".edu")) ) FunctionalKey.LANGUAGE_SWITCH -> KeyParams( "!icon/language_switch_key|!code/key_language_switch", @@ -528,7 +529,7 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co Key.LABEL_FLAGS_HAS_POPUP_HINT, // this may not be a good place to make this choice, but probably it's fine (though reading from settings here is not good) if (Settings.getInstance().current.mColors.hasKeyBorders) Key.BACKGROUND_TYPE_SPACEBAR else Key.BACKGROUND_TYPE_NORMAL, - arrayOf("!icon/zwj_key|\u200D") + SimplePopups(listOf("!icon/zwj_key|\u200D")) ) } } @@ -558,44 +559,44 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co "!code/key_shift_enter" else "!code/key_enter" - private fun getActionKeyMoreKeys(): Array? { + private fun getActionKeyMoreKeys(): Collection? { val action = params.mId.imeAction() val navigatePrev = params.mId.navigatePrevious() val navigateNext = params.mId.navigateNext() return when { params.mId.passwordInput() -> when { - navigatePrev && action == EditorInfo.IME_ACTION_NEXT -> createMoreKeysArray(MORE_KEYS_NAVIGATE_PREVIOUS) + navigatePrev && action == EditorInfo.IME_ACTION_NEXT -> createMoreKeys(MORE_KEYS_NAVIGATE_PREVIOUS) action == EditorInfo.IME_ACTION_NEXT -> null - navigateNext && action == EditorInfo.IME_ACTION_PREVIOUS -> createMoreKeysArray(MORE_KEYS_NAVIGATE_NEXT) + navigateNext && action == EditorInfo.IME_ACTION_PREVIOUS -> createMoreKeys(MORE_KEYS_NAVIGATE_NEXT) action == EditorInfo.IME_ACTION_PREVIOUS -> null - navigateNext && navigatePrev -> createMoreKeysArray(MORE_KEYS_NAVIGATE_PREVIOUS_NEXT) - navigateNext -> createMoreKeysArray(MORE_KEYS_NAVIGATE_NEXT) - navigatePrev -> createMoreKeysArray(MORE_KEYS_NAVIGATE_PREVIOUS) + navigateNext && navigatePrev -> createMoreKeys(MORE_KEYS_NAVIGATE_PREVIOUS_NEXT) + navigateNext -> createMoreKeys(MORE_KEYS_NAVIGATE_NEXT) + navigatePrev -> createMoreKeys(MORE_KEYS_NAVIGATE_PREVIOUS) else -> null } // could change definition of numbers to query a range, or have a pre-defined list, but not that crucial params.mId.isNumberLayout || params.mId.mMode in listOf(KeyboardId.MODE_EMAIL, KeyboardId.MODE_DATE, KeyboardId.MODE_TIME, KeyboardId.MODE_DATETIME) -> when { - action == EditorInfo.IME_ACTION_NEXT && navigatePrev -> createMoreKeysArray(MORE_KEYS_NAVIGATE_PREVIOUS) + action == EditorInfo.IME_ACTION_NEXT && navigatePrev -> createMoreKeys(MORE_KEYS_NAVIGATE_PREVIOUS) action == EditorInfo.IME_ACTION_NEXT -> null - action == EditorInfo.IME_ACTION_PREVIOUS && navigateNext -> createMoreKeysArray(MORE_KEYS_NAVIGATE_NEXT) + action == EditorInfo.IME_ACTION_PREVIOUS && navigateNext -> createMoreKeys(MORE_KEYS_NAVIGATE_NEXT) action == EditorInfo.IME_ACTION_PREVIOUS -> null - navigateNext && navigatePrev -> createMoreKeysArray(MORE_KEYS_NAVIGATE_PREVIOUS_NEXT) - navigateNext -> createMoreKeysArray(MORE_KEYS_NAVIGATE_NEXT) - navigatePrev -> createMoreKeysArray(MORE_KEYS_NAVIGATE_PREVIOUS) + navigateNext && navigatePrev -> createMoreKeys(MORE_KEYS_NAVIGATE_PREVIOUS_NEXT) + navigateNext -> createMoreKeys(MORE_KEYS_NAVIGATE_NEXT) + navigatePrev -> createMoreKeys(MORE_KEYS_NAVIGATE_PREVIOUS) else -> null } - action == EditorInfo.IME_ACTION_NEXT && navigatePrev -> createMoreKeysArray(MORE_KEYS_NAVIGATE_EMOJI_PREVIOUS) - action == EditorInfo.IME_ACTION_NEXT -> createMoreKeysArray(MORE_KEYS_NAVIGATE_EMOJI) - action == EditorInfo.IME_ACTION_PREVIOUS && navigateNext -> createMoreKeysArray(MORE_KEYS_NAVIGATE_EMOJI_NEXT) - action == EditorInfo.IME_ACTION_PREVIOUS -> createMoreKeysArray(MORE_KEYS_NAVIGATE_EMOJI) - navigateNext && navigatePrev -> createMoreKeysArray(MORE_KEYS_NAVIGATE_EMOJI_PREVIOUS_NEXT) - navigateNext -> createMoreKeysArray(MORE_KEYS_NAVIGATE_EMOJI_NEXT) - navigatePrev -> createMoreKeysArray(MORE_KEYS_NAVIGATE_EMOJI_PREVIOUS) - else -> createMoreKeysArray(MORE_KEYS_NAVIGATE_EMOJI) + action == EditorInfo.IME_ACTION_NEXT && navigatePrev -> createMoreKeys(MORE_KEYS_NAVIGATE_EMOJI_PREVIOUS) + action == EditorInfo.IME_ACTION_NEXT -> createMoreKeys(MORE_KEYS_NAVIGATE_EMOJI) + action == EditorInfo.IME_ACTION_PREVIOUS && navigateNext -> createMoreKeys(MORE_KEYS_NAVIGATE_EMOJI_NEXT) + action == EditorInfo.IME_ACTION_PREVIOUS -> createMoreKeys(MORE_KEYS_NAVIGATE_EMOJI) + navigateNext && navigatePrev -> createMoreKeys(MORE_KEYS_NAVIGATE_EMOJI_PREVIOUS_NEXT) + navigateNext -> createMoreKeys(MORE_KEYS_NAVIGATE_EMOJI_NEXT) + navigatePrev -> createMoreKeys(MORE_KEYS_NAVIGATE_EMOJI_PREVIOUS) + else -> createMoreKeys(MORE_KEYS_NAVIGATE_EMOJI) } } - private fun createMoreKeysArray(moreKeysDef: String): Array { + private fun createMoreKeys(moreKeysDef: String): List { val moreKeys = mutableListOf() for (moreKey in moreKeysDef.split(",")) { val iconPrefixRemoved = moreKey.substringAfter("!icon/") @@ -615,15 +616,14 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co // remove emoji shortcut on enter in tablet mode (like original, because bottom row always has an emoji key) // (probably not necessary, but whatever) if (isTablet() && moreKeys.remove("!icon/emoji_action_key|!code/key_emoji")) { - val i = moreKeys.indexOfFirst { it.startsWith("!fixedColumnOrder") } + val i = moreKeys.indexOfFirst { it.startsWith(Key.MORE_KEYS_FIXED_COLUMN_ORDER) } if (i > -1) { - val n = moreKeys[i].substringAfter("!fixedColumnOrder!").toIntOrNull() + val n = moreKeys[i].substringAfter(Key.MORE_KEYS_FIXED_COLUMN_ORDER).toIntOrNull() if (n != null) moreKeys[i] = moreKeys[i].replace(n.toString(), (n - 1).toString()) } - // remove emoji on enter, because tablet layout has a separate emoji key } - return moreKeys.toTypedArray() + return moreKeys } private fun String.replaceIconWithLabelIfNoDrawable(): String { @@ -705,7 +705,7 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co return params.mLocaleKeyTexts.labelComma } - private fun getCommaMoreKeys(): Array { + private fun getCommaMoreKeys(): List { val keys = mutableListOf() if (!params.mId.mDeviceLocked) keys.add("!icon/clipboard_normal_key|!code/key_clipboard") @@ -717,14 +717,14 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co keys.add("!icon/start_onehanded_mode_key|!code/key_start_onehanded") if (!params.mId.mDeviceLocked) keys.add("!icon/settings_key|!code/key_settings") - return keys.toTypedArray() + return keys } - private fun getPunctuationMoreKeys(): Array { + private fun getPunctuationMoreKeys(): List { if (params.mId.mElementId == KeyboardId.ELEMENT_SYMBOLS || params.mId.mElementId == KeyboardId.ELEMENT_SYMBOLS_SHIFTED) - return arrayOf("…") + return listOf("…") if (params.mId.isNumberLayout) - return arrayOf(":", "…", ";", "∞", "π", "√", "°", "^") + return listOf(":", "…", ";", "∞", "π", "√", "°", "^") val moreKeys = params.mLocaleKeyTexts.getMoreKeys("punctuation")!! if (params.mId.mSubtype.isRtlSubtype) { for (i in moreKeys.indices) @@ -739,7 +739,7 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co if (columns != null) moreKeys[0] = "${Key.MORE_KEYS_AUTO_COLUMN_ORDER}${columns - 1}" } - return moreKeys + return moreKeys.toList() } private fun getSpaceLabel(): String = diff --git a/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/keyboard_parser/LocaleKeyTexts.kt b/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/keyboard_parser/LocaleKeyTexts.kt index 2c6ffdaf..4c5a03da 100644 --- a/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/keyboard_parser/LocaleKeyTexts.kt +++ b/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/keyboard_parser/LocaleKeyTexts.kt @@ -15,7 +15,8 @@ import java.util.Locale import kotlin.math.round class LocaleKeyTexts(dataStream: InputStream?, locale: Locale) { - private val moreKeys = hashMapOf>() + private val moreKeys = hashMapOf>() // todo: no need for arrays any more, better use a list? + private val priorityMoreKeys = hashMapOf>() private val extraKeys = Array?>(5) { null } var labelSymbol = "\\?123" private set @@ -95,8 +96,8 @@ class LocaleKeyTexts(dataStream: InputStream?, locale: Locale) { fun getShiftSymbolLabel(isTablet: Boolean) = if (isTablet) labelShiftSymbolTablet else labelShiftSymbol - // need tp provide a copy because some functions like MoreKeySpec.insertAdditionalMoreKeys may modify the array - fun getMoreKeys(label: String): Array? = moreKeys[label]?.copyOf() + fun getMoreKeys(label: String): Array? = moreKeys[label] + fun getPriorityMoreKeys(label: String): Array? = priorityMoreKeys[label] // used by simple parser only, but could be possible for json as well (if necessary) fun getExtraKeys(row: Int): List? = @@ -115,13 +116,26 @@ class LocaleKeyTexts(dataStream: InputStream?, locale: Locale) { else line.splitOnWhitespace() if (split.size == 1) return val key = split.first() - val existingMoreKeys = moreKeys[key] - val newMoreKeys = if (existingMoreKeys == null) - Array(split.size - 1) { split[it + 1] } - else mergeMoreKeys(existingMoreKeys, split.drop(1)) - moreKeys[key] = when (key) { - "'", "\"", "«", "»", ")", "(" -> addFixedColumnOrder(newMoreKeys) - else -> newMoreKeys + val priorityMarkerIndex = split.indexOf("%") + if (priorityMarkerIndex > 0) { + val existingPriorityMoreKeys = priorityMoreKeys[key] + priorityMoreKeys[key] = if (existingPriorityMoreKeys == null) + Array(priorityMarkerIndex - 1) { split[it + 1] } + else existingPriorityMoreKeys + split.subList(1, priorityMarkerIndex) + val existingMoreKeys = moreKeys[key] + moreKeys[key] = if (existingMoreKeys == null) + Array(split.size - priorityMarkerIndex - 1) { split[it + priorityMarkerIndex + 1] } + else existingMoreKeys + split.subList(priorityMarkerIndex, split.size) + } else { + // a but more special treatment, this should not occur together with priority marker (but technically could) + val existingMoreKeys = moreKeys[key] + val newMoreKeys = if (existingMoreKeys == null) + Array(split.size - 1) { split[it + 1] } + else mergeMoreKeys(existingMoreKeys, split.drop(1)) + moreKeys[key] = when (key) { + "'", "\"", "«", "»", ")", "(" -> addFixedColumnOrder(newMoreKeys) + else -> newMoreKeys + } } } @@ -183,33 +197,8 @@ class LocaleKeyTexts(dataStream: InputStream?, locale: Locale) { } private fun mergeMoreKeys(original: Array, added: List): Array { - val markerIndexInOriginal = original.indexOf("%") - val markerIndexInAddedIndex = added.indexOf("%") - val moreKeys = mutableSetOf() - if (markerIndexInOriginal != -1 && markerIndexInAddedIndex != -1) { - // add original and then added until % - original.forEachIndexed { index, s -> if (index < markerIndexInOriginal) moreKeys.add(s) } - added.forEachIndexed { index, s -> if (index < markerIndexInAddedIndex) moreKeys.add(s) } - // add % and remaining moreKeys - original.forEachIndexed { index, s -> if (index >= markerIndexInOriginal) moreKeys.add(s) } - added.forEachIndexed { index, s -> if (index > markerIndexInAddedIndex) moreKeys.add(s) } - } else if (markerIndexInOriginal != -1) { - // add original until %, then added, then remaining original - original.forEachIndexed { index, s -> if (index <= markerIndexInOriginal) moreKeys.add(s) } - moreKeys.addAll(added) - original.forEachIndexed { index, s -> if (index > markerIndexInOriginal) moreKeys.add(s) } - } else if (markerIndexInAddedIndex != -1) { - // add added until %, then original, then remaining added - added.forEachIndexed { index, s -> if (index <= markerIndexInAddedIndex) moreKeys.add(s) } - moreKeys.addAll(original) - added.forEachIndexed { index, s -> if (index > markerIndexInAddedIndex) moreKeys.add(s) } - } else { - // use original, then added - moreKeys.addAll(original) - moreKeys.addAll(added) - } - // in fact this is only special treatment for the punctuation moreKeys - if (moreKeys.any { it.startsWith(Key.MORE_KEYS_AUTO_COLUMN_ORDER) }) { + if (original.any { it.startsWith(Key.MORE_KEYS_AUTO_COLUMN_ORDER) } || added.any { it.startsWith(Key.MORE_KEYS_AUTO_COLUMN_ORDER) }) { + val moreKeys = (original + added).toSet() val originalColumnCount = original.firstOrNull { it.startsWith(Key.MORE_KEYS_AUTO_COLUMN_ORDER) } ?.substringAfter(Key.MORE_KEYS_AUTO_COLUMN_ORDER)?.toIntOrNull() val l = moreKeys.filterNot { it.startsWith(Key.MORE_KEYS_AUTO_COLUMN_ORDER) } @@ -221,15 +210,15 @@ private fun mergeMoreKeys(original: Array, added: List): Array): Array { - if (moreKeys.none { it.startsWith("!fixedColumnOrder") }) - return arrayOf("!fixedColumnOrder!${moreKeys.size}", *moreKeys) - val newMoreKeys = moreKeys.filterNot { it.startsWith("!fixedColumnOrder") } + if (moreKeys.none { it.startsWith(Key.MORE_KEYS_FIXED_COLUMN_ORDER) }) + return arrayOf("${Key.MORE_KEYS_FIXED_COLUMN_ORDER}${moreKeys.size}", *moreKeys) + val newMoreKeys = moreKeys.filterNot { it.startsWith(Key.MORE_KEYS_FIXED_COLUMN_ORDER) } return Array(newMoreKeys.size + 1) { - if (it == 0) "!fixedColumnOrder!${newMoreKeys.size}" + if (it == 0) "${Key.MORE_KEYS_FIXED_COLUMN_ORDER}${newMoreKeys.size}" else newMoreKeys[it - 1] } } diff --git a/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/keyboard_parser/floris/KeyData.kt b/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/keyboard_parser/floris/KeyData.kt index 0fa824cf..a629d911 100644 --- a/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/keyboard_parser/floris/KeyData.kt +++ b/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/keyboard_parser/floris/KeyData.kt @@ -129,7 +129,7 @@ interface KeyData : AbstractKeyData { width, labelFlags or additionalLabelFlags, Key.BACKGROUND_TYPE_NORMAL, // todo (when supported): determine type - popup.toMoreKeys(params), + popup, ) } else { KeyParams( @@ -139,7 +139,7 @@ interface KeyData : AbstractKeyData { width, labelFlags or additionalLabelFlags, Key.BACKGROUND_TYPE_NORMAL, - popup.toMoreKeys(params), + popup, ) } } diff --git a/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/keyboard_parser/floris/PopupSet.kt b/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/keyboard_parser/floris/PopupSet.kt index e7d53963..83d1c0fc 100644 --- a/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/keyboard_parser/floris/PopupSet.kt +++ b/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/keyboard_parser/floris/PopupSet.kt @@ -1,4 +1,5 @@ /* + * Copyright (C) 2020 Patrick Goldinger * modified * SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-only */ @@ -6,114 +7,27 @@ package org.dslul.openboard.inputmethod.keyboard.internal.keyboard_parser.floris import kotlinx.serialization.Serializable import org.dslul.openboard.inputmethod.keyboard.internal.KeyboardParams -import org.dslul.openboard.inputmethod.keyboard.internal.keyboard_parser.rtlLabel -// taken from FlorisBoard, small modifications -// mutable set removed (currently the moreKeys assembly is happening in KeyParams) -// .toMoreKeys added -// PopupKeys not used, but might switch to this later -// currently hint would be taken from other, and languageMoreKeys are prioritized -/** - * A popup set for a single key. This set describes, if the key has a [main] character and other [relevant] popups. - * - * Note that a hint character cannot and should not be set in a json extended popup file, rather it - * should only be dynamically set by the LayoutManager. - */ +// taken from FlorisBoard, considerably modified +// we don't care about the difference between main and relevant in this app @Serializable open class PopupSet( open val main: T? = null, - open val relevant: List = emptyList() + open val relevant: List? = null ) { - // todo (idea): - // this is very simple, but essentially what happens in the old system - // could make use of PopupKeys, and also provide a hint depending on user choice - // then language key joining should be done in here too - // also what about getting the moreKeys and key hint from chosen symbol layout? - fun toMoreKeys(params: KeyboardParams): Array? { + // get labels of all popup keys + open fun getPopupKeyLabels(params: KeyboardParams): Collection? { + if (main == null && relevant == null) return null val moreKeys = mutableListOf() - // number + main + relevant in this order (label is later taken from first element in resulting array) - params.mLocaleKeyTexts.getNumberLabel(numberIndex)?.let { moreKeys.add(it) } - main?.getLabel(params)?.let { moreKeys.add(transformLabel(it, params)) } - moreKeys.addAll(relevant.map { transformLabel(it.getLabel(params), params) }) - return moreKeys.takeIf { it.isNotEmpty() }?.toTypedArray() + main?.getLabel(params)?.let { moreKeys.add(it) } + relevant?.let { moreKeys.addAll(it.map { it.getLabel(params) }) } + if (moreKeys.isEmpty()) return null + return moreKeys } - private fun transformLabel(label: String, params: KeyboardParams): String = - if (label == "$$$") { // currency key - if (params.mId.passwordInput()) "$" - else params.mLocaleKeyTexts.currencyKey.first - } else if (params.mId.mSubtype.isRtlSubtype) { - label.rtlLabel(params) - } else label - - private val popupKeys: PopupKeys by lazy { - PopupKeys(null, listOfNotNull(main), relevant) - } var numberIndex: Int? = null } -/** - * A fully configured collection of popup keys. It contains a list of keys to be prioritized - * during rendering (ordered by relevance descending) by showing those keys close to the - * popup spawning point. - * - * The keys contain a separate [hint] key to ease rendering the hint label, but the hint, if - * present, also occurs in the [prioritized] list. - * - * The popup keys can be accessed like an array with the addition that negative indexes defined - * within this companion object are allowed (as long as the corresponding [prioritized] list - * contains the corresponding amount of keys. - */ -class PopupKeys( - val hint: T?, - val prioritized: List, - val other: List -) : Collection { - companion object { - const val FIRST_PRIORITIZED = -1 - const val SECOND_PRIORITIZED = -2 - const val THIRD_PRIORITIZED = -3 - } - - override val size: Int - get() = prioritized.size + other.size - - override fun contains(element: T): Boolean { - return prioritized.contains(element) || other.contains(element) - } - - override fun containsAll(elements: Collection): Boolean { - return (prioritized + other).containsAll(elements) - } - - override fun isEmpty(): Boolean { - return prioritized.isEmpty() && other.isEmpty() - } - - override fun iterator(): Iterator { - return (prioritized + other).listIterator() - } - - fun getOrNull(index: Int): T? { - if (index >= other.size || index < -prioritized.size) { - return null - } - return when (index) { - FIRST_PRIORITIZED -> prioritized[0] - SECOND_PRIORITIZED -> prioritized[1] - THIRD_PRIORITIZED -> prioritized[2] - else -> other.getOrNull(index) - } - } - - operator fun get(index: Int): T { - val item = getOrNull(index) - if (item == null) { - throw IndexOutOfBoundsException( - "Specified index $index is not an valid entry in this PopupKeys!" - ) - } else { - return item - } - } +class SimplePopups(val moreKeys: Collection?) : PopupSet() { + override fun getPopupKeyLabels(params: KeyboardParams) = moreKeys } diff --git a/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/keyboard_parser/floris/TextKeyData.kt b/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/keyboard_parser/floris/TextKeyData.kt index b2504c24..7161648f 100644 --- a/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/keyboard_parser/floris/TextKeyData.kt +++ b/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/keyboard_parser/floris/TextKeyData.kt @@ -148,7 +148,5 @@ fun String.toTextKey(moreKeys: Collection? = null, labelFlags: Int = 0): TextKeyData( label = this, labelFlags = labelFlags, - popup = moreKeys - ?.let { keys -> PopupSet(null, keys.map { it.toTextKey() }) } - ?: PopupSet() + popup = SimplePopups(moreKeys) ) diff --git a/app/src/main/java/org/dslul/openboard/inputmethod/latin/settings/PreferencesSettingsFragment.java b/app/src/main/java/org/dslul/openboard/inputmethod/latin/settings/PreferencesSettingsFragment.java index 7c94b974..bd01a6b4 100644 --- a/app/src/main/java/org/dslul/openboard/inputmethod/latin/settings/PreferencesSettingsFragment.java +++ b/app/src/main/java/org/dslul/openboard/inputmethod/latin/settings/PreferencesSettingsFragment.java @@ -24,6 +24,7 @@ import org.dslul.openboard.inputmethod.keyboard.KeyboardSwitcher; import org.dslul.openboard.inputmethod.latin.AudioAndHapticFeedbackManager; import org.dslul.openboard.inputmethod.latin.R; import org.dslul.openboard.inputmethod.latin.RichInputMethodManager; +import org.dslul.openboard.inputmethod.latin.utils.MoreKeysUtilsKt; import kotlin.collections.ArraysKt; @@ -67,7 +68,15 @@ public final class PreferencesSettingsFragment extends SubScreenFragment { setupHistoryRetentionTimeSettings(); refreshEnablingsOfKeypressSoundAndVibrationAndHistRetentionSettings(); setLocalizedNumberRowVisibility(); - findPreference(Settings.PREF_HINT_LABEL_FROM_FIRST_MORE_KEY).setVisible(getSharedPreferences().getBoolean(Settings.PREF_SHOW_HINTS, false)); + findPreference(Settings.PREF_MORE_KEYS_LABELS_ORDER).setVisible(getSharedPreferences().getBoolean(Settings.PREF_SHOW_HINTS, false)); + findPreference(Settings.PREF_MORE_KEYS_ORDER).setOnPreferenceClickListener((pref) -> { + MoreKeysUtilsKt.reorderMoreKeysDialog(requireContext(), Settings.PREF_MORE_KEYS_ORDER, MoreKeysUtilsKt.MORE_KEYS_ORDER_DEFAULT, R.string.popup_order); + return true; + }); + findPreference(Settings.PREF_MORE_KEYS_LABELS_ORDER).setOnPreferenceClickListener((pref) -> { + MoreKeysUtilsKt.reorderMoreKeysDialog(requireContext(), Settings.PREF_MORE_KEYS_LABELS_ORDER, MoreKeysUtilsKt.MORE_KEYS_LABEL_DEFAULT, R.string.hint_source); + return true; + }); } @Override @@ -78,12 +87,13 @@ public final class PreferencesSettingsFragment extends SubScreenFragment { @Override public void onSharedPreferenceChanged(final SharedPreferences prefs, final String key) { refreshEnablingsOfKeypressSoundAndVibrationAndHistRetentionSettings(); - if (Settings.PREF_SHOW_POPUP_HINTS.equals(key) || Settings.PREF_HINT_LABEL_FROM_FIRST_MORE_KEY.equals(key) || Settings.PREF_SHOW_NUMBER_ROW.equals(key)) - mReloadKeyboard = true; - if (key.equals(Settings.PREF_LOCALIZED_NUMBER_ROW)) - KeyboardLayoutSet.onSystemLocaleChanged(); - if (Settings.PREF_SHOW_HINTS.equals(key)) { - findPreference(Settings.PREF_HINT_LABEL_FROM_FIRST_MORE_KEY).setVisible(prefs.getBoolean(Settings.PREF_SHOW_HINTS, false)); + if (key == null) return; + switch (key) { + case Settings.PREF_MORE_KEYS_ORDER, Settings.PREF_SHOW_POPUP_HINTS, Settings.PREF_SHOW_NUMBER_ROW, Settings.PREF_MORE_KEYS_LABELS_ORDER + -> mReloadKeyboard = true; + case Settings.PREF_LOCALIZED_NUMBER_ROW -> KeyboardLayoutSet.onSystemLocaleChanged(); + case Settings.PREF_SHOW_HINTS + -> findPreference(Settings.PREF_MORE_KEYS_LABELS_ORDER).setVisible(prefs.getBoolean(Settings.PREF_SHOW_HINTS, false)); } } diff --git a/app/src/main/java/org/dslul/openboard/inputmethod/latin/settings/Settings.java b/app/src/main/java/org/dslul/openboard/inputmethod/latin/settings/Settings.java index ad415ea0..b09bd7da 100644 --- a/app/src/main/java/org/dslul/openboard/inputmethod/latin/settings/Settings.java +++ b/app/src/main/java/org/dslul/openboard/inputmethod/latin/settings/Settings.java @@ -112,8 +112,10 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang public static final String PREF_LOCALIZED_NUMBER_ROW = "pref_localized_number_row"; public static final String PREF_SHOW_HINTS = "pref_show_hints"; - public static final String PREF_HINT_LABEL_FROM_FIRST_MORE_KEY = "pref_hint_label_from_first_more_key"; + public static final String PREF_MORE_KEYS_ORDER = "pref_more_keys_order"; + public static final String PREF_MORE_KEYS_LABELS_ORDER = "pref_more_keys_labels_order"; public static final String PREF_SHOW_POPUP_HINTS = "pref_show_popup_hints"; + public static final String PREF_MORE_MORE_KEYS = "pref_more_more_keys"; public static final String PREF_SPACE_TO_CHANGE_LANG = "prefs_long_press_keyboard_to_change_lang"; public static final String PREF_SPACE_LANGUAGE_SLIDE = "pref_space_language_slide"; @@ -128,7 +130,6 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang public static final String PREF_ENABLED_INPUT_STYLES = "pref_enabled_input_styles"; public static final String PREF_SELECTED_INPUT_STYLE = "pref_selected_input_style"; public static final String PREF_USE_SYSTEM_LOCALES = "pref_use_system_locales"; - public static final String PREF_MORE_MORE_KEYS = "pref_more_more_keys"; public static final String PREF_URL_DETECTION = "pref_url_detection"; public static final String PREF_DONT_SHOW_MISSING_DICTIONARY_DIALOG = "pref_dont_show_missing_dict_dialog"; diff --git a/app/src/main/java/org/dslul/openboard/inputmethod/latin/settings/SettingsValues.java b/app/src/main/java/org/dslul/openboard/inputmethod/latin/settings/SettingsValues.java index e5addd46..d72709af 100644 --- a/app/src/main/java/org/dslul/openboard/inputmethod/latin/settings/SettingsValues.java +++ b/app/src/main/java/org/dslul/openboard/inputmethod/latin/settings/SettingsValues.java @@ -26,6 +26,7 @@ import org.dslul.openboard.inputmethod.latin.RichInputMethodManager; import org.dslul.openboard.inputmethod.latin.common.Colors; import org.dslul.openboard.inputmethod.latin.spellcheck.AndroidSpellCheckerService; import org.dslul.openboard.inputmethod.latin.utils.AsyncResultHolder; +import org.dslul.openboard.inputmethod.latin.utils.MoreKeysUtilsKt; import org.dslul.openboard.inputmethod.latin.utils.ScriptUtils; import org.dslul.openboard.inputmethod.latin.utils.TargetPackageInfoGetterTask; @@ -66,7 +67,6 @@ public class SettingsValues { public final boolean mShowsNumberRow; public final boolean mLocalizedNumberRow; public final boolean mShowsHints; - public final boolean mHintLabelFromFirstMoreKey; public final boolean mShowsPopupHints; public final boolean mSpaceForLangChange; public final boolean mSpaceLanguageSlide; @@ -83,7 +83,9 @@ public class SettingsValues { public final int mOneHandedModeGravity; public final float mOneHandedModeScale; public final boolean mNarrowKeyGaps; - public final int mShowMoreKeys; + public final int mShowMoreMoreKeys; + public final List mMoreKeyTypes; + public final List mMoreKeyLabelSources; public final List mSecondaryLocales; // Use bigrams to predict the next word when there is no input for it yet public final boolean mBigramPredictionEnabled; @@ -152,7 +154,6 @@ public class SettingsValues { mShowsNumberRow = prefs.getBoolean(Settings.PREF_SHOW_NUMBER_ROW, false); mLocalizedNumberRow = prefs.getBoolean(Settings.PREF_LOCALIZED_NUMBER_ROW, true); mShowsHints = prefs.getBoolean(Settings.PREF_SHOW_HINTS, true); - mHintLabelFromFirstMoreKey = mShowsHints && prefs.getBoolean(Settings.PREF_HINT_LABEL_FROM_FIRST_MORE_KEY, false); mShowsPopupHints = prefs.getBoolean(Settings.PREF_SHOW_POPUP_HINTS, false); mSpaceForLangChange = prefs.getBoolean(Settings.PREF_SPACE_TO_CHANGE_LANG, true); mSpaceLanguageSlide = prefs.getBoolean(Settings.PREF_SPACE_LANGUAGE_SLIDE, false); @@ -228,9 +229,12 @@ public class SettingsValues { mOneHandedModeScale = 1f; final InputMethodSubtype selectedSubtype = SubtypeSettingsKt.getSelectedSubtype(prefs); mSecondaryLocales = Settings.getSecondaryLocales(prefs, selectedSubtype.getLocale()); - mShowMoreKeys = selectedSubtype.isAsciiCapable() + mShowMoreMoreKeys = selectedSubtype.isAsciiCapable() ? Settings.readMoreMoreKeysPref(prefs) : LocaleKeyTextsKt.MORE_KEYS_NORMAL; + mMoreKeyTypes = MoreKeysUtilsKt.getEnabledMoreKeys(prefs, Settings.PREF_MORE_KEYS_ORDER, MoreKeysUtilsKt.MORE_KEYS_ORDER_DEFAULT); + // todo: if the type is disabled, the label should not occur too? + mMoreKeyLabelSources = MoreKeysUtilsKt.getEnabledMoreKeys(prefs, Settings.PREF_MORE_KEYS_LABELS_ORDER, MoreKeysUtilsKt.MORE_KEYS_LABEL_DEFAULT); mColors = Settings.getColorsForCurrentTheme(context, prefs); mAddToPersonalDictionary = prefs.getBoolean(Settings.PREF_ADD_TO_PERSONAL_DICTIONARY, false); diff --git a/app/src/main/java/org/dslul/openboard/inputmethod/latin/utils/MoreKeysUtils.kt b/app/src/main/java/org/dslul/openboard/inputmethod/latin/utils/MoreKeysUtils.kt new file mode 100644 index 00000000..31beb940 --- /dev/null +++ b/app/src/main/java/org/dslul/openboard/inputmethod/latin/utils/MoreKeysUtils.kt @@ -0,0 +1,163 @@ +// SPDX-License-Identifier: GPL-3.0-only +package org.dslul.openboard.inputmethod.latin.utils + +import android.content.Context +import android.content.SharedPreferences +import android.view.LayoutInflater +import android.view.ViewGroup +import android.widget.TextView +import androidx.appcompat.app.AlertDialog +import androidx.appcompat.widget.SwitchCompat +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.ItemTouchHelper +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.ListAdapter +import androidx.recyclerview.widget.RecyclerView +import org.dslul.openboard.inputmethod.keyboard.Key +import org.dslul.openboard.inputmethod.keyboard.internal.KeyboardParams +import org.dslul.openboard.inputmethod.keyboard.internal.keyboard_parser.floris.PopupSet +import org.dslul.openboard.inputmethod.keyboard.internal.keyboard_parser.rtlLabel +import org.dslul.openboard.inputmethod.latin.R +import java.util.Collections + +private const val MORE_KEYS_NUMBER = "more_keys_number" +private const val MORE_KEYS_LANGUAGE_PRIORITY = "more_keys_language_priority" +private const val MORE_KEYS_LAYOUT = "more_keys_layout" +private const val MORE_KEYS_SYMBOLS = "more_keys_symbols" +private const val MORE_KEYS_LANGUAGE = "more_keys_language" +const val MORE_KEYS_LABEL_DEFAULT = "$MORE_KEYS_NUMBER,true;$MORE_KEYS_LANGUAGE_PRIORITY,false;$MORE_KEYS_LAYOUT,true;$MORE_KEYS_SYMBOLS,true;$MORE_KEYS_LANGUAGE,false" +const val MORE_KEYS_ORDER_DEFAULT = "$MORE_KEYS_LANGUAGE_PRIORITY,true;$MORE_KEYS_NUMBER,true;$MORE_KEYS_SYMBOLS,true;$MORE_KEYS_LAYOUT,true;$MORE_KEYS_LANGUAGE,true" + +// todo: +// take moreKeys from symbols layout (in a separate commit) +// maybe also add a (simple) parser cache... or cache the layout somewhere else? +// that might be annoying with base and full layout (functional keys and spacers) +// because base layout not available later... put it to keyParams? +// or create symbol moreKeys in the parser? that should work best, there we have proper access to layouts + +fun createMoreKeysArray(popupSet: PopupSet<*>?, params: KeyboardParams, label: String): Array? { + val moreKeys = mutableSetOf() + params.mMoreKeyTypes.forEach { type -> + when (type) { + MORE_KEYS_NUMBER -> params.mLocaleKeyTexts.getNumberLabel(popupSet?.numberIndex)?.let { moreKeys.add(it) } + MORE_KEYS_LAYOUT -> popupSet?.getPopupKeyLabels(params)?.let { moreKeys.addAll(it) } + MORE_KEYS_SYMBOLS -> {} // todo + MORE_KEYS_LANGUAGE -> params.mLocaleKeyTexts.getMoreKeys(label)?.let { moreKeys.addAll(it) } + MORE_KEYS_LANGUAGE_PRIORITY -> params.mLocaleKeyTexts.getPriorityMoreKeys(label)?.let { moreKeys.addAll(it) } + } + } + if (moreKeys.isEmpty()) return null + val fco = moreKeys.firstOrNull { it.startsWith(Key.MORE_KEYS_FIXED_COLUMN_ORDER) } + if (fco != null && fco.substringAfter(Key.MORE_KEYS_FIXED_COLUMN_ORDER).toIntOrNull() != moreKeys.size - 1) { + moreKeys.remove(fco) // maybe rather adjust the number instead of remove? + } + // autoColumnOrder should be fine + + val array = moreKeys.toTypedArray() + for (i in array.indices) { + array[i] = transformLabel(array[i], params) + } + return array +} + +fun getHintLabel(popupSet: PopupSet<*>?, params: KeyboardParams, label: String): String? { + var hintLabel: String? = null + for (type in params.mMoreKeyLabelSources) { + when (type) { + MORE_KEYS_NUMBER -> params.mLocaleKeyTexts.getNumberLabel(popupSet?.numberIndex)?.let { hintLabel = it } + MORE_KEYS_LAYOUT -> popupSet?.getPopupKeyLabels(params)?.let { hintLabel = it.firstOrNull() } + MORE_KEYS_SYMBOLS -> {} // todo + MORE_KEYS_LANGUAGE -> params.mLocaleKeyTexts.getMoreKeys(label)?.let { hintLabel = it.firstOrNull() } + MORE_KEYS_LANGUAGE_PRIORITY -> params.mLocaleKeyTexts.getPriorityMoreKeys(label)?.let { hintLabel = it.firstOrNull() } + } + if (hintLabel != null) break + } + + // avoid e.g. !autoColumnOrder! as label + // this will avoid having labels on comma and period keys + return hintLabel?.let { transformLabel(it, params) } + ?.takeIf { !it.startsWith("!") || it == "!" } +} + +private fun transformLabel(label: String, params: KeyboardParams): String = + if (label == "$$$") { // currency key + if (params.mId.passwordInput()) "$" + else params.mLocaleKeyTexts.currencyKey.first + } else if (params.mId.mSubtype.isRtlSubtype) { + label.rtlLabel(params) + } else label + +/** returns a list of enabled more keys for pref [key] */ +fun getEnabledMoreKeys(prefs: SharedPreferences, key: String, defaultSetting: String): List { + return prefs.getString(key, defaultSetting)?.split(";")?.mapNotNull { + val split = it.split(",") + if (split.last() == "true") split.first() else null + } ?: emptyList() +} + +/** + * show a dialog that allows re-ordering and dis/enabling the more keys list for the pref [key] + * see e.g. [MORE_KEYS_LABEL_DEFAULT] for the internally used format + */ +fun reorderMoreKeysDialog(context: Context, key: String, defaultSetting: String, title: Int) { + val prefs = DeviceProtectedUtils.getSharedPreferences(context) + val orderedItems = prefs.getString(key, defaultSetting)!!.split(";").mapTo(ArrayList()) { + val both = it.split(",") + both.first() to both.last().toBoolean() + } + val rv = RecyclerView(context) + rv.setPadding(30, 10, 10, 10) + rv.layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false) + val callback = object : DiffUtil.ItemCallback>() { + override fun areItemsTheSame(p0: Pair, p1: Pair) = p0 == p1 + override fun areContentsTheSame(p0: Pair, p1: Pair) = p0 == p1 + } + val adapter = object : ListAdapter, RecyclerView.ViewHolder>(callback) { + override fun onCreateViewHolder(p0: ViewGroup, p1: Int): RecyclerView.ViewHolder { + val b = LayoutInflater.from(context).inflate(R.layout.morekeys_list_item, rv, false) + // wtf? this results in transparent background, but when the background is set in xml it's fine? + // but of course when setting in xml i need to duplicate the entire thing except for background because of api things + // why tf is it so complicated to just use the dialog's background? +// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { +// b.setBackgroundColor(android.R.attr.colorBackgroundFloating) +// } + return object : RecyclerView.ViewHolder(b) { } + } + override fun onBindViewHolder(p0: RecyclerView.ViewHolder, p1: Int) { + val (text, wasChecked) = orderedItems[p1] + val displayTextId = context.resources.getIdentifier(text, "string", context.packageName) + val displayText = if (displayTextId == 0) text else context.getString(displayTextId) + p0.itemView.findViewById(R.id.morekeys_type)?.text = displayText + val switch = p0.itemView.findViewById(R.id.morekeys_switch) + switch?.isChecked = wasChecked + switch?.setOnCheckedChangeListener { _, isChecked -> + val position = orderedItems.indexOfFirst { it.first == text } + orderedItems[position] = text to isChecked + } + } + } + rv.adapter = adapter + ItemTouchHelper(object : ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP or ItemTouchHelper.DOWN, 0) { + override fun onMove(p0: RecyclerView, p1: RecyclerView.ViewHolder, p2: RecyclerView.ViewHolder): Boolean { + val pos1 = p1.absoluteAdapterPosition + val pos2 = p2.absoluteAdapterPosition + Collections.swap(orderedItems, pos1, pos2) + adapter.notifyItemMoved(pos1, pos2) + return true + } + override fun onSwiped(p0: RecyclerView.ViewHolder, p1: Int) { } + }).attachToRecyclerView(rv) + adapter.submitList(orderedItems) + AlertDialog.Builder(context) + .setTitle(title) + .setPositiveButton(android.R.string.ok) { _, _ -> + val value = orderedItems.joinToString(";") { it.first + "," + it.second } + prefs.edit().putString(key, value).apply() + } + .setNegativeButton(android.R.string.cancel, null) + .setNeutralButton(R.string.button_default) { _, _ -> + prefs.edit().remove(key).apply() + } + .setView(rv) + .show() +} diff --git a/app/src/main/res/drawable/ic_drag_indicator.xml b/app/src/main/res/drawable/ic_drag_indicator.xml new file mode 100644 index 00000000..25691a52 --- /dev/null +++ b/app/src/main/res/drawable/ic_drag_indicator.xml @@ -0,0 +1,13 @@ + + + + diff --git a/app/src/main/res/layout-v23/morekeys_list_item.xml b/app/src/main/res/layout-v23/morekeys_list_item.xml new file mode 100644 index 00000000..eaa54beb --- /dev/null +++ b/app/src/main/res/layout-v23/morekeys_list_item.xml @@ -0,0 +1,39 @@ + + + + + + + + + diff --git a/app/src/main/res/layout/morekeys_list_item.xml b/app/src/main/res/layout/morekeys_list_item.xml new file mode 100644 index 00000000..5c151c69 --- /dev/null +++ b/app/src/main/res/layout/morekeys_list_item.xml @@ -0,0 +1,33 @@ + + + + + + + + diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 74e04c94..bdd7e278 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -209,8 +209,6 @@ Nouveau dictionnaire: Un appui long sur la barre d\'espace fera apparaître le menu de sélection des claviers Afficher les indices de touches Affiche les caractères alternatifs lors d\'un appui long - Afficher les indices à partir de la première sélection du popup - Les caractères alternatifs par défaut sont remplacés par ceux sélectionnés en premier lors d\'un appui long Afficher les indices sur les touches fonctionnelles Affiche un signe ( ) sur les touches où un appui long déclenche une fonctionnalité supplémentaire Échelle de hauteur du clavier diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index aa51cb2a..c0040bda 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -234,10 +234,15 @@ Show key hints Show long-press hints - - Take hint label from first popup key - - The default key hints are replaced by those selected first on a long press + + Select hint source + + Select popup key order + Number + Language + Language (priority) + Layout + Symbols Show functional hints diff --git a/app/src/main/res/xml/prefs_screen_preferences.xml b/app/src/main/res/xml/prefs_screen_preferences.xml index 5d787375..7c47dee3 100644 --- a/app/src/main/res/xml/prefs_screen_preferences.xml +++ b/app/src/main/res/xml/prefs_screen_preferences.xml @@ -17,12 +17,13 @@ android:defaultValue="true" android:persistent="true" /> - + + +