allow adjusting popup order and label source

This commit is contained in:
Helium314 2023-12-25 09:20:15 +01:00
parent 07f2c43e38
commit 7097fd8fae
19 changed files with 401 additions and 251 deletions

View file

@ -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.KeyboardIconsSet;
import org.dslul.openboard.inputmethod.keyboard.internal.KeyboardParams; import org.dslul.openboard.inputmethod.keyboard.internal.KeyboardParams;
import org.dslul.openboard.inputmethod.keyboard.internal.MoreKeySpec; 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.Constants;
import org.dslul.openboard.inputmethod.latin.common.StringUtils; import org.dslul.openboard.inputmethod.latin.common.StringUtils;
import org.dslul.openboard.inputmethod.latin.utils.MoreKeysUtilsKt;
import java.util.Arrays; import java.util.Arrays;
import java.util.Locale; import java.util.Locale;
@ -1047,9 +1049,9 @@ public class Key implements Comparable<Key> {
final float relativeWidth, final float relativeWidth,
final int labelFlags, final int labelFlags,
final int backgroundType, 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<Key> {
final float relativeWidth, final float relativeWidth,
final int labelFlags, final int labelFlags,
final int backgroundType, final int backgroundType,
@Nullable final String[] layoutMoreKeys // same style as current moreKeys (relevant for the special keys) @Nullable final PopupSet<?> popupSet
) { ) {
mKeyboardParams = params; mKeyboardParams = params;
mBackgroundType = backgroundType; mBackgroundType = backgroundType;
@ -1079,15 +1081,9 @@ public class Key implements Comparable<Key> {
if (params.mId.isNumberLayout()) if (params.mId.isNumberLayout())
actionFlags = ACTION_FLAGS_NO_KEY_PREVIEW; actionFlags = ACTION_FLAGS_NO_KEY_PREVIEW;
final String[] languageMoreKeys = params.mLocaleKeyTexts.getMoreKeys(keySpec); final String[] moreKeys = MoreKeysUtilsKt.createMoreKeysArray(popupSet, mKeyboardParams, keySpec);
if (languageMoreKeys != null && layoutMoreKeys != null && languageMoreKeys[0].startsWith("!fixedColumnOrder!")) mMoreKeysColumnAndFlags = getMoreKeysColumnAndFlagsAndSetNullInArray(params, moreKeys);
languageMoreKeys[0] = null; // we change the number of keys, so better not use fixedColumnOrder to avoid awkward layout final String[] finalMoreKeys = moreKeys == null ? null : MoreKeySpec.filterOutEmptyString(moreKeys);
// 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);
if (finalMoreKeys != null) { if (finalMoreKeys != null) {
actionFlags |= ACTION_FLAGS_ENABLE_LONG_PRESS; actionFlags |= ACTION_FLAGS_ENABLE_LONG_PRESS;
@ -1116,18 +1112,8 @@ public class Key implements Comparable<Key> {
mHintLabel = null; mHintLabel = null;
} else { } else {
// maybe also always null for comma and period keys // maybe also always null for comma and period keys
String hintLabel; // todo: maybe remove mKeyboardParams.mHintLabelFromFirstMoreKey?
if (mKeyboardParams.mHintLabelFromFirstMoreKey) { final String hintLabel = MoreKeysUtilsKt.getHintLabel(popupSet, params, keySpec);
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;
}
mHintLabel = needsToUpcase mHintLabel = needsToUpcase
? StringUtils.toTitleCaseOfKeyLabel(hintLabel, localeForUpcasing) ? StringUtils.toTitleCaseOfKeyLabel(hintLabel, localeForUpcasing)
: hintLabel; : hintLabel;

View file

@ -49,18 +49,10 @@ open class KeyboardBuilder<KP : KeyboardParams>(protected val mContext: Context,
// todo: further plan // todo: further plan
// after the old parser is removed // after the old parser is removed
// finally the spanish/german/swiss/nordic layouts can be removed and replaced by some hasExtraKeys parameter // maybe the language -> layout thing could be moved to assets? and maybe even here the extra keys could be defined...
// 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...
// should be either both in method.xml, or both in assets (actually method might be more suitable) // 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 // 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? // also remove the keyboard_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
// allow users to define their own layouts (maybe do everything else first?) // 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 // 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 // write up how things work for users, also regarding language more keys
@ -125,7 +117,10 @@ open class KeyboardBuilder<KP : KeyboardParams>(protected val mContext: Context,
keysInRows = EmojiParser(mParams, mContext).parse() keysInRows = EmojiParser(mParams, mContext).parse()
} else { } else {
try { 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) keysInRows = KeyboardParser.parseFromAssets(mParams, mContext)
determineAbsoluteValues() determineAbsoluteValues()
} catch (e: Exception) { } catch (e: Exception) {

View file

@ -81,11 +81,12 @@ public class KeyboardParams {
public final KeyboardIconsSet mIconsSet = new KeyboardIconsSet(); public final KeyboardIconsSet mIconsSet = new KeyboardIconsSet();
@NonNull // todo: not good, this only works because params are currently always created for the active subtype @NonNull // todo: not good, this only works because params are currently always created for the active subtype
public final List<Locale> mSecondaryLocales = Settings.getInstance().getCurrent().mSecondaryLocales; public final List<Locale> mSecondaryLocales = Settings.getInstance().getCurrent().mSecondaryLocales;
public final ArrayList<String> mMoreKeyTypes = new ArrayList<>();
public final ArrayList<String> mMoreKeyLabelSources = new ArrayList<>();
@NonNull @NonNull
private final UniqueKeysCache mUniqueKeysCache; private final UniqueKeysCache mUniqueKeysCache;
public boolean mAllowRedundantMoreKeys; public boolean mAllowRedundantMoreKeys;
public final boolean mHintLabelFromFirstMoreKey = Settings.getInstance().getCurrent().mHintLabelFromFirstMoreKey;
@NonNull @NonNull
public LocaleKeyTexts mLocaleKeyTexts; public LocaleKeyTexts mLocaleKeyTexts;

View file

@ -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.KeyboardParams
import org.dslul.openboard.inputmethod.keyboard.internal.keyboard_parser.floris.KeyData 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.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.R
import org.dslul.openboard.inputmethod.latin.common.Constants import org.dslul.openboard.inputmethod.latin.common.Constants
import org.dslul.openboard.inputmethod.latin.common.splitOnWhitespace 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() "period" -> adjustedKeys?.last()
else -> null 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 (key == "space") { // add the extra keys around space
if (params.mId.mElementId == KeyboardId.ELEMENT_SYMBOLS) { if (params.mId.mElementId == KeyboardId.ELEMENT_SYMBOLS) {
bottomRow.add(getFunctionalKeyParams(FunctionalKey.NUMPAD)) bottomRow.add(getFunctionalKeyParams(FunctionalKey.NUMPAD))
@ -346,7 +347,7 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co
params.mDefaultRelativeKeyWidth, params.mDefaultRelativeKeyWidth,
defaultLabelFlags, defaultLabelFlags,
Key.BACKGROUND_TYPE_FUNCTIONAL, Key.BACKGROUND_TYPE_FUNCTIONAL,
adjustedKeys?.get(1)?.popup?.toMoreKeys(params) adjustedKeys?.get(1)?.popup
)) ))
} else if (params.mId.mElementId == KeyboardId.ELEMENT_SYMBOLS_SHIFTED) { } else if (params.mId.mElementId == KeyboardId.ELEMENT_SYMBOLS_SHIFTED) {
bottomRow.add(KeyParams( bottomRow.add(KeyParams(
@ -355,7 +356,7 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co
params.mDefaultRelativeKeyWidth, params.mDefaultRelativeKeyWidth,
defaultLabelFlags or Key.LABEL_FLAGS_HAS_POPUP_HINT, defaultLabelFlags or Key.LABEL_FLAGS_HAS_POPUP_HINT,
Key.BACKGROUND_TYPE_FUNCTIONAL, 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)
bottomRow.add(KeyParams( bottomRow.add(KeyParams(
@ -364,7 +365,7 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co
params.mDefaultRelativeKeyWidth, params.mDefaultRelativeKeyWidth,
defaultLabelFlags or Key.LABEL_FLAGS_HAS_POPUP_HINT, defaultLabelFlags or Key.LABEL_FLAGS_HAS_POPUP_HINT,
Key.BACKGROUND_TYPE_FUNCTIONAL, Key.BACKGROUND_TYPE_FUNCTIONAL,
adjustedKeys?.get(2)?.popup?.toMoreKeys(params) ?: arrayOf("!fixedColumnOrder!3", "", "", "»") adjustedKeys?.get(2)?.popup ?: SimplePopups(listOf("!fixedColumnOrder!3", "", "", "»"))
)) ))
} else { // alphabet } else { // alphabet
if (params.mId.mLanguageSwitchKeyEnabled) 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) it.toKeyParams(params, additionalLabelFlags = Key.LABEL_FLAGS_DISABLE_HINT_LABEL or defaultLabelFlags)
} }
private fun getFunctionalKeyParams(def: String, label: String? = null, moreKeys: Array<String>? = null): KeyParams { private fun getFunctionalKeyParams(def: String, label: String? = null, moreKeys: Collection<String>? = null): KeyParams {
val split = def.trim().splitOnWhitespace() val split = def.trim().splitOnWhitespace()
val key = FunctionalKey.valueOf(split[0].uppercase()) val key = FunctionalKey.valueOf(split[0].uppercase())
val width = if (split.size == 2) split[1].substringBefore("%").toFloat() / 100f 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) return getFunctionalKeyParams(key, width, label, moreKeys)
} }
private fun getFunctionalKeyParams(key: FunctionalKey, relativeWidth: Float? = null, label: String? = null, moreKeys: Array<String>? = null): KeyParams { private fun getFunctionalKeyParams(key: FunctionalKey, relativeWidth: Float? = null, label: String? = null, moreKeys: Collection<String>? = null): KeyParams {
// for comma and period: label will override default, moreKeys will be appended // for comma and period: label will override default, moreKeys will be appended
val width = relativeWidth ?: params.mDefaultRelativeKeyWidth val width = relativeWidth ?: params.mDefaultRelativeKeyWidth
return when (key) { 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 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 if (label?.first()?.isLetter() == true) Key.BACKGROUND_TYPE_NORMAL // mimic behavior of old dvorak and halmak layouts
else Key.BACKGROUND_TYPE_FUNCTIONAL, else Key.BACKGROUND_TYPE_FUNCTIONAL,
moreKeys?.let { getCommaMoreKeys() + it } ?: getCommaMoreKeys() SimplePopups(moreKeys?.let { getCommaMoreKeys() + it } ?: getCommaMoreKeys())
) )
FunctionalKey.PERIOD -> KeyParams( FunctionalKey.PERIOD -> KeyParams(
// special period moreKey only in alphabet layout, except for ar and fa // 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, or defaultLabelFlags,
if (label?.first()?.isLetter() == true) Key.BACKGROUND_TYPE_NORMAL if (label?.first()?.isLetter() == true) Key.BACKGROUND_TYPE_NORMAL
else Key.BACKGROUND_TYPE_FUNCTIONAL, else Key.BACKGROUND_TYPE_FUNCTIONAL,
moreKeys?.let { getPunctuationMoreKeys() + it } ?: getPunctuationMoreKeys() SimplePopups(moreKeys?.let { getPunctuationMoreKeys() + it } ?: getPunctuationMoreKeys())
) )
FunctionalKey.SPACE -> KeyParams( FunctionalKey.SPACE -> KeyParams(
getSpaceLabel(), getSpaceLabel(),
@ -462,7 +463,7 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co
or Key.LABEL_FLAGS_HAS_POPUP_HINT or Key.LABEL_FLAGS_HAS_POPUP_HINT
or KeyboardTheme.getThemeActionAndEmojiKeyLabelFlags(params.mThemeId), or KeyboardTheme.getThemeActionAndEmojiKeyLabelFlags(params.mThemeId),
Key.BACKGROUND_TYPE_ACTION, Key.BACKGROUND_TYPE_ACTION,
getActionKeyMoreKeys() getActionKeyMoreKeys()?.let { SimplePopups(it) }
) )
FunctionalKey.DELETE -> KeyParams( FunctionalKey.DELETE -> KeyParams(
"!icon/delete_key|!code/key_delete", "!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) if (params.mId.mElementId == KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED || params.mId.mElementId == KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCKED)
Key.BACKGROUND_TYPE_STICKY_ON Key.BACKGROUND_TYPE_STICKY_ON
else Key.BACKGROUND_TYPE_STICKY_OFF, 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( FunctionalKey.EMOJI -> KeyParams(
"!icon/emoji_normal_key|!code/key_emoji", "!icon/emoji_normal_key|!code/key_emoji",
@ -503,7 +504,7 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co
width, 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.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, 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( FunctionalKey.LANGUAGE_SWITCH -> KeyParams(
"!icon/language_switch_key|!code/key_language_switch", "!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, 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) // 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, 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" "!code/key_shift_enter"
else "!code/key_enter" else "!code/key_enter"
private fun getActionKeyMoreKeys(): Array<String>? { private fun getActionKeyMoreKeys(): Collection<String>? {
val action = params.mId.imeAction() val action = params.mId.imeAction()
val navigatePrev = params.mId.navigatePrevious() val navigatePrev = params.mId.navigatePrevious()
val navigateNext = params.mId.navigateNext() val navigateNext = params.mId.navigateNext()
return when { return when {
params.mId.passwordInput() -> 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 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 action == EditorInfo.IME_ACTION_PREVIOUS -> null
navigateNext && navigatePrev -> createMoreKeysArray(MORE_KEYS_NAVIGATE_PREVIOUS_NEXT) navigateNext && navigatePrev -> createMoreKeys(MORE_KEYS_NAVIGATE_PREVIOUS_NEXT)
navigateNext -> createMoreKeysArray(MORE_KEYS_NAVIGATE_NEXT) navigateNext -> createMoreKeys(MORE_KEYS_NAVIGATE_NEXT)
navigatePrev -> createMoreKeysArray(MORE_KEYS_NAVIGATE_PREVIOUS) navigatePrev -> createMoreKeys(MORE_KEYS_NAVIGATE_PREVIOUS)
else -> null else -> null
} }
// could change definition of numbers to query a range, or have a pre-defined list, but not that crucial // 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 { 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_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 action == EditorInfo.IME_ACTION_PREVIOUS -> null
navigateNext && navigatePrev -> createMoreKeysArray(MORE_KEYS_NAVIGATE_PREVIOUS_NEXT) navigateNext && navigatePrev -> createMoreKeys(MORE_KEYS_NAVIGATE_PREVIOUS_NEXT)
navigateNext -> createMoreKeysArray(MORE_KEYS_NAVIGATE_NEXT) navigateNext -> createMoreKeys(MORE_KEYS_NAVIGATE_NEXT)
navigatePrev -> createMoreKeysArray(MORE_KEYS_NAVIGATE_PREVIOUS) navigatePrev -> createMoreKeys(MORE_KEYS_NAVIGATE_PREVIOUS)
else -> null else -> null
} }
action == EditorInfo.IME_ACTION_NEXT && navigatePrev -> createMoreKeysArray(MORE_KEYS_NAVIGATE_EMOJI_PREVIOUS) action == EditorInfo.IME_ACTION_NEXT && navigatePrev -> createMoreKeys(MORE_KEYS_NAVIGATE_EMOJI_PREVIOUS)
action == EditorInfo.IME_ACTION_NEXT -> createMoreKeysArray(MORE_KEYS_NAVIGATE_EMOJI) action == EditorInfo.IME_ACTION_NEXT -> createMoreKeys(MORE_KEYS_NAVIGATE_EMOJI)
action == EditorInfo.IME_ACTION_PREVIOUS && navigateNext -> createMoreKeysArray(MORE_KEYS_NAVIGATE_EMOJI_NEXT) action == EditorInfo.IME_ACTION_PREVIOUS && navigateNext -> createMoreKeys(MORE_KEYS_NAVIGATE_EMOJI_NEXT)
action == EditorInfo.IME_ACTION_PREVIOUS -> createMoreKeysArray(MORE_KEYS_NAVIGATE_EMOJI) action == EditorInfo.IME_ACTION_PREVIOUS -> createMoreKeys(MORE_KEYS_NAVIGATE_EMOJI)
navigateNext && navigatePrev -> createMoreKeysArray(MORE_KEYS_NAVIGATE_EMOJI_PREVIOUS_NEXT) navigateNext && navigatePrev -> createMoreKeys(MORE_KEYS_NAVIGATE_EMOJI_PREVIOUS_NEXT)
navigateNext -> createMoreKeysArray(MORE_KEYS_NAVIGATE_EMOJI_NEXT) navigateNext -> createMoreKeys(MORE_KEYS_NAVIGATE_EMOJI_NEXT)
navigatePrev -> createMoreKeysArray(MORE_KEYS_NAVIGATE_EMOJI_PREVIOUS) navigatePrev -> createMoreKeys(MORE_KEYS_NAVIGATE_EMOJI_PREVIOUS)
else -> createMoreKeysArray(MORE_KEYS_NAVIGATE_EMOJI) else -> createMoreKeys(MORE_KEYS_NAVIGATE_EMOJI)
} }
} }
private fun createMoreKeysArray(moreKeysDef: String): Array<String> { private fun createMoreKeys(moreKeysDef: String): List<String> {
val moreKeys = mutableListOf<String>() val moreKeys = mutableListOf<String>()
for (moreKey in moreKeysDef.split(",")) { for (moreKey in moreKeysDef.split(",")) {
val iconPrefixRemoved = moreKey.substringAfter("!icon/") 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) // remove emoji shortcut on enter in tablet mode (like original, because bottom row always has an emoji key)
// (probably not necessary, but whatever) // (probably not necessary, but whatever)
if (isTablet() && moreKeys.remove("!icon/emoji_action_key|!code/key_emoji")) { 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) { 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) if (n != null)
moreKeys[i] = moreKeys[i].replace(n.toString(), (n - 1).toString()) 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 { private fun String.replaceIconWithLabelIfNoDrawable(): String {
@ -705,7 +705,7 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co
return params.mLocaleKeyTexts.labelComma return params.mLocaleKeyTexts.labelComma
} }
private fun getCommaMoreKeys(): Array<String> { private fun getCommaMoreKeys(): List<String> {
val keys = mutableListOf<String>() val keys = mutableListOf<String>()
if (!params.mId.mDeviceLocked) if (!params.mId.mDeviceLocked)
keys.add("!icon/clipboard_normal_key|!code/key_clipboard") 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") keys.add("!icon/start_onehanded_mode_key|!code/key_start_onehanded")
if (!params.mId.mDeviceLocked) if (!params.mId.mDeviceLocked)
keys.add("!icon/settings_key|!code/key_settings") keys.add("!icon/settings_key|!code/key_settings")
return keys.toTypedArray() return keys
} }
private fun getPunctuationMoreKeys(): Array<String> { private fun getPunctuationMoreKeys(): List<String> {
if (params.mId.mElementId == KeyboardId.ELEMENT_SYMBOLS || params.mId.mElementId == KeyboardId.ELEMENT_SYMBOLS_SHIFTED) if (params.mId.mElementId == KeyboardId.ELEMENT_SYMBOLS || params.mId.mElementId == KeyboardId.ELEMENT_SYMBOLS_SHIFTED)
return arrayOf("") return listOf("")
if (params.mId.isNumberLayout) if (params.mId.isNumberLayout)
return arrayOf(":", "", ";", "", "π", "", "°", "^") return listOf(":", "", ";", "", "π", "", "°", "^")
val moreKeys = params.mLocaleKeyTexts.getMoreKeys("punctuation")!! val moreKeys = params.mLocaleKeyTexts.getMoreKeys("punctuation")!!
if (params.mId.mSubtype.isRtlSubtype) { if (params.mId.mSubtype.isRtlSubtype) {
for (i in moreKeys.indices) for (i in moreKeys.indices)
@ -739,7 +739,7 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co
if (columns != null) if (columns != null)
moreKeys[0] = "${Key.MORE_KEYS_AUTO_COLUMN_ORDER}${columns - 1}" moreKeys[0] = "${Key.MORE_KEYS_AUTO_COLUMN_ORDER}${columns - 1}"
} }
return moreKeys return moreKeys.toList()
} }
private fun getSpaceLabel(): String = private fun getSpaceLabel(): String =

View file

@ -15,7 +15,8 @@ import java.util.Locale
import kotlin.math.round import kotlin.math.round
class LocaleKeyTexts(dataStream: InputStream?, locale: Locale) { class LocaleKeyTexts(dataStream: InputStream?, locale: Locale) {
private val moreKeys = hashMapOf<String, Array<String>>() private val moreKeys = hashMapOf<String, Array<String>>() // todo: no need for arrays any more, better use a list?
private val priorityMoreKeys = hashMapOf<String, Array<String>>()
private val extraKeys = Array<MutableList<KeyData>?>(5) { null } private val extraKeys = Array<MutableList<KeyData>?>(5) { null }
var labelSymbol = "\\?123" var labelSymbol = "\\?123"
private set private set
@ -95,8 +96,8 @@ class LocaleKeyTexts(dataStream: InputStream?, locale: Locale) {
fun getShiftSymbolLabel(isTablet: Boolean) = if (isTablet) labelShiftSymbolTablet else labelShiftSymbol 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<String>? = moreKeys[label]
fun getMoreKeys(label: String): Array<String>? = moreKeys[label]?.copyOf() fun getPriorityMoreKeys(label: String): Array<String>? = priorityMoreKeys[label]
// used by simple parser only, but could be possible for json as well (if necessary) // used by simple parser only, but could be possible for json as well (if necessary)
fun getExtraKeys(row: Int): List<KeyData>? = fun getExtraKeys(row: Int): List<KeyData>? =
@ -115,6 +116,18 @@ class LocaleKeyTexts(dataStream: InputStream?, locale: Locale) {
else line.splitOnWhitespace() else line.splitOnWhitespace()
if (split.size == 1) return if (split.size == 1) return
val key = split.first() val key = split.first()
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 existingMoreKeys = moreKeys[key]
val newMoreKeys = if (existingMoreKeys == null) val newMoreKeys = if (existingMoreKeys == null)
Array(split.size - 1) { split[it + 1] } Array(split.size - 1) { split[it + 1] }
@ -124,6 +137,7 @@ class LocaleKeyTexts(dataStream: InputStream?, locale: Locale) {
else -> newMoreKeys else -> newMoreKeys
} }
} }
}
private fun addExtraKey(split: List<String>) { private fun addExtraKey(split: List<String>) {
if (split.size < 2) return if (split.size < 2) return
@ -183,33 +197,8 @@ class LocaleKeyTexts(dataStream: InputStream?, locale: Locale) {
} }
private fun mergeMoreKeys(original: Array<String>, added: List<String>): Array<String> { private fun mergeMoreKeys(original: Array<String>, added: List<String>): Array<String> {
val markerIndexInOriginal = original.indexOf("%") if (original.any { it.startsWith(Key.MORE_KEYS_AUTO_COLUMN_ORDER) } || added.any { it.startsWith(Key.MORE_KEYS_AUTO_COLUMN_ORDER) }) {
val markerIndexInAddedIndex = added.indexOf("%") val moreKeys = (original + added).toSet()
val moreKeys = mutableSetOf<String>()
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) }) {
val originalColumnCount = original.firstOrNull { it.startsWith(Key.MORE_KEYS_AUTO_COLUMN_ORDER) } val originalColumnCount = original.firstOrNull { it.startsWith(Key.MORE_KEYS_AUTO_COLUMN_ORDER) }
?.substringAfter(Key.MORE_KEYS_AUTO_COLUMN_ORDER)?.toIntOrNull() ?.substringAfter(Key.MORE_KEYS_AUTO_COLUMN_ORDER)?.toIntOrNull()
val l = moreKeys.filterNot { it.startsWith(Key.MORE_KEYS_AUTO_COLUMN_ORDER) } val l = moreKeys.filterNot { it.startsWith(Key.MORE_KEYS_AUTO_COLUMN_ORDER) }
@ -221,15 +210,15 @@ private fun mergeMoreKeys(original: Array<String>, added: List<String>): Array<S
// just drop autoColumnOrder otherwise // just drop autoColumnOrder otherwise
return l.toTypedArray() return l.toTypedArray()
} }
return moreKeys.toTypedArray() return original + added
} }
private fun addFixedColumnOrder(moreKeys: Array<String>): Array<String> { private fun addFixedColumnOrder(moreKeys: Array<String>): Array<String> {
if (moreKeys.none { it.startsWith("!fixedColumnOrder") }) if (moreKeys.none { it.startsWith(Key.MORE_KEYS_FIXED_COLUMN_ORDER) })
return arrayOf("!fixedColumnOrder!${moreKeys.size}", *moreKeys) return arrayOf("${Key.MORE_KEYS_FIXED_COLUMN_ORDER}${moreKeys.size}", *moreKeys)
val newMoreKeys = moreKeys.filterNot { it.startsWith("!fixedColumnOrder") } val newMoreKeys = moreKeys.filterNot { it.startsWith(Key.MORE_KEYS_FIXED_COLUMN_ORDER) }
return Array(newMoreKeys.size + 1) { 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] else newMoreKeys[it - 1]
} }
} }

View file

@ -129,7 +129,7 @@ interface KeyData : AbstractKeyData {
width, width,
labelFlags or additionalLabelFlags, labelFlags or additionalLabelFlags,
Key.BACKGROUND_TYPE_NORMAL, // todo (when supported): determine type Key.BACKGROUND_TYPE_NORMAL, // todo (when supported): determine type
popup.toMoreKeys(params), popup,
) )
} else { } else {
KeyParams( KeyParams(
@ -139,7 +139,7 @@ interface KeyData : AbstractKeyData {
width, width,
labelFlags or additionalLabelFlags, labelFlags or additionalLabelFlags,
Key.BACKGROUND_TYPE_NORMAL, Key.BACKGROUND_TYPE_NORMAL,
popup.toMoreKeys(params), popup,
) )
} }
} }

View file

@ -1,4 +1,5 @@
/* /*
* Copyright (C) 2020 Patrick Goldinger
* modified * modified
* SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-only * 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 kotlinx.serialization.Serializable
import org.dslul.openboard.inputmethod.keyboard.internal.KeyboardParams import org.dslul.openboard.inputmethod.keyboard.internal.KeyboardParams
import org.dslul.openboard.inputmethod.keyboard.internal.keyboard_parser.rtlLabel
// taken from FlorisBoard, small modifications // taken from FlorisBoard, considerably modified
// mutable set removed (currently the moreKeys assembly is happening in KeyParams) // we don't care about the difference between main and relevant in this app
// .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.
*/
@Serializable @Serializable
open class PopupSet<T : AbstractKeyData>( open class PopupSet<T : AbstractKeyData>(
open val main: T? = null, open val main: T? = null,
open val relevant: List<T> = emptyList() open val relevant: List<T>? = null
) { ) {
// todo (idea): // get labels of all popup keys
// this is very simple, but essentially what happens in the old system open fun getPopupKeyLabels(params: KeyboardParams): Collection<String>? {
// could make use of PopupKeys, and also provide a hint depending on user choice if (main == null && relevant == null) return null
// 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<String>? {
val moreKeys = mutableListOf<String>() val moreKeys = mutableListOf<String>()
// number + main + relevant in this order (label is later taken from first element in resulting array) main?.getLabel(params)?.let { moreKeys.add(it) }
params.mLocaleKeyTexts.getNumberLabel(numberIndex)?.let { moreKeys.add(it) } relevant?.let { moreKeys.addAll(it.map { it.getLabel(params) }) }
main?.getLabel(params)?.let { moreKeys.add(transformLabel(it, params)) } if (moreKeys.isEmpty()) return null
moreKeys.addAll(relevant.map { transformLabel(it.getLabel(params), params) }) return moreKeys
return moreKeys.takeIf { it.isNotEmpty() }?.toTypedArray()
} }
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<T> by lazy {
PopupKeys(null, listOfNotNull(main), relevant)
}
var numberIndex: Int? = null var numberIndex: Int? = null
} }
/** class SimplePopups(val moreKeys: Collection<String>?) : PopupSet<AbstractKeyData>() {
* A fully configured collection of popup keys. It contains a list of keys to be prioritized override fun getPopupKeyLabels(params: KeyboardParams) = moreKeys
* 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<T>(
val hint: T?,
val prioritized: List<T>,
val other: List<T>
) : Collection<T> {
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<T>): Boolean {
return (prioritized + other).containsAll(elements)
}
override fun isEmpty(): Boolean {
return prioritized.isEmpty() && other.isEmpty()
}
override fun iterator(): Iterator<T> {
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
}
}
} }

View file

@ -148,7 +148,5 @@ fun String.toTextKey(moreKeys: Collection<String>? = null, labelFlags: Int = 0):
TextKeyData( TextKeyData(
label = this, label = this,
labelFlags = labelFlags, labelFlags = labelFlags,
popup = moreKeys popup = SimplePopups(moreKeys)
?.let { keys -> PopupSet(null, keys.map { it.toTextKey() }) }
?: PopupSet()
) )

View file

@ -24,6 +24,7 @@ import org.dslul.openboard.inputmethod.keyboard.KeyboardSwitcher;
import org.dslul.openboard.inputmethod.latin.AudioAndHapticFeedbackManager; import org.dslul.openboard.inputmethod.latin.AudioAndHapticFeedbackManager;
import org.dslul.openboard.inputmethod.latin.R; import org.dslul.openboard.inputmethod.latin.R;
import org.dslul.openboard.inputmethod.latin.RichInputMethodManager; import org.dslul.openboard.inputmethod.latin.RichInputMethodManager;
import org.dslul.openboard.inputmethod.latin.utils.MoreKeysUtilsKt;
import kotlin.collections.ArraysKt; import kotlin.collections.ArraysKt;
@ -67,7 +68,15 @@ public final class PreferencesSettingsFragment extends SubScreenFragment {
setupHistoryRetentionTimeSettings(); setupHistoryRetentionTimeSettings();
refreshEnablingsOfKeypressSoundAndVibrationAndHistRetentionSettings(); refreshEnablingsOfKeypressSoundAndVibrationAndHistRetentionSettings();
setLocalizedNumberRowVisibility(); 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 @Override
@ -78,12 +87,13 @@ public final class PreferencesSettingsFragment extends SubScreenFragment {
@Override @Override
public void onSharedPreferenceChanged(final SharedPreferences prefs, final String key) { public void onSharedPreferenceChanged(final SharedPreferences prefs, final String key) {
refreshEnablingsOfKeypressSoundAndVibrationAndHistRetentionSettings(); 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)) if (key == null) return;
mReloadKeyboard = true; switch (key) {
if (key.equals(Settings.PREF_LOCALIZED_NUMBER_ROW)) case Settings.PREF_MORE_KEYS_ORDER, Settings.PREF_SHOW_POPUP_HINTS, Settings.PREF_SHOW_NUMBER_ROW, Settings.PREF_MORE_KEYS_LABELS_ORDER
KeyboardLayoutSet.onSystemLocaleChanged(); -> mReloadKeyboard = true;
if (Settings.PREF_SHOW_HINTS.equals(key)) { case Settings.PREF_LOCALIZED_NUMBER_ROW -> KeyboardLayoutSet.onSystemLocaleChanged();
findPreference(Settings.PREF_HINT_LABEL_FROM_FIRST_MORE_KEY).setVisible(prefs.getBoolean(Settings.PREF_SHOW_HINTS, false)); case Settings.PREF_SHOW_HINTS
-> findPreference(Settings.PREF_MORE_KEYS_LABELS_ORDER).setVisible(prefs.getBoolean(Settings.PREF_SHOW_HINTS, false));
} }
} }

View file

@ -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_LOCALIZED_NUMBER_ROW = "pref_localized_number_row";
public static final String PREF_SHOW_HINTS = "pref_show_hints"; 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_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_TO_CHANGE_LANG = "prefs_long_press_keyboard_to_change_lang";
public static final String PREF_SPACE_LANGUAGE_SLIDE = "pref_space_language_slide"; 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_ENABLED_INPUT_STYLES = "pref_enabled_input_styles";
public static final String PREF_SELECTED_INPUT_STYLE = "pref_selected_input_style"; 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_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_URL_DETECTION = "pref_url_detection";
public static final String PREF_DONT_SHOW_MISSING_DICTIONARY_DIALOG = "pref_dont_show_missing_dict_dialog"; public static final String PREF_DONT_SHOW_MISSING_DICTIONARY_DIALOG = "pref_dont_show_missing_dict_dialog";

View file

@ -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.common.Colors;
import org.dslul.openboard.inputmethod.latin.spellcheck.AndroidSpellCheckerService; import org.dslul.openboard.inputmethod.latin.spellcheck.AndroidSpellCheckerService;
import org.dslul.openboard.inputmethod.latin.utils.AsyncResultHolder; 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.ScriptUtils;
import org.dslul.openboard.inputmethod.latin.utils.TargetPackageInfoGetterTask; import org.dslul.openboard.inputmethod.latin.utils.TargetPackageInfoGetterTask;
@ -66,7 +67,6 @@ public class SettingsValues {
public final boolean mShowsNumberRow; public final boolean mShowsNumberRow;
public final boolean mLocalizedNumberRow; public final boolean mLocalizedNumberRow;
public final boolean mShowsHints; public final boolean mShowsHints;
public final boolean mHintLabelFromFirstMoreKey;
public final boolean mShowsPopupHints; public final boolean mShowsPopupHints;
public final boolean mSpaceForLangChange; public final boolean mSpaceForLangChange;
public final boolean mSpaceLanguageSlide; public final boolean mSpaceLanguageSlide;
@ -83,7 +83,9 @@ public class SettingsValues {
public final int mOneHandedModeGravity; public final int mOneHandedModeGravity;
public final float mOneHandedModeScale; public final float mOneHandedModeScale;
public final boolean mNarrowKeyGaps; public final boolean mNarrowKeyGaps;
public final int mShowMoreKeys; public final int mShowMoreMoreKeys;
public final List<String> mMoreKeyTypes;
public final List<String> mMoreKeyLabelSources;
public final List<Locale> mSecondaryLocales; public final List<Locale> mSecondaryLocales;
// Use bigrams to predict the next word when there is no input for it yet // Use bigrams to predict the next word when there is no input for it yet
public final boolean mBigramPredictionEnabled; public final boolean mBigramPredictionEnabled;
@ -152,7 +154,6 @@ public class SettingsValues {
mShowsNumberRow = prefs.getBoolean(Settings.PREF_SHOW_NUMBER_ROW, false); mShowsNumberRow = prefs.getBoolean(Settings.PREF_SHOW_NUMBER_ROW, false);
mLocalizedNumberRow = prefs.getBoolean(Settings.PREF_LOCALIZED_NUMBER_ROW, true); mLocalizedNumberRow = prefs.getBoolean(Settings.PREF_LOCALIZED_NUMBER_ROW, true);
mShowsHints = prefs.getBoolean(Settings.PREF_SHOW_HINTS, 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); mShowsPopupHints = prefs.getBoolean(Settings.PREF_SHOW_POPUP_HINTS, false);
mSpaceForLangChange = prefs.getBoolean(Settings.PREF_SPACE_TO_CHANGE_LANG, true); mSpaceForLangChange = prefs.getBoolean(Settings.PREF_SPACE_TO_CHANGE_LANG, true);
mSpaceLanguageSlide = prefs.getBoolean(Settings.PREF_SPACE_LANGUAGE_SLIDE, false); mSpaceLanguageSlide = prefs.getBoolean(Settings.PREF_SPACE_LANGUAGE_SLIDE, false);
@ -228,9 +229,12 @@ public class SettingsValues {
mOneHandedModeScale = 1f; mOneHandedModeScale = 1f;
final InputMethodSubtype selectedSubtype = SubtypeSettingsKt.getSelectedSubtype(prefs); final InputMethodSubtype selectedSubtype = SubtypeSettingsKt.getSelectedSubtype(prefs);
mSecondaryLocales = Settings.getSecondaryLocales(prefs, selectedSubtype.getLocale()); mSecondaryLocales = Settings.getSecondaryLocales(prefs, selectedSubtype.getLocale());
mShowMoreKeys = selectedSubtype.isAsciiCapable() mShowMoreMoreKeys = selectedSubtype.isAsciiCapable()
? Settings.readMoreMoreKeysPref(prefs) ? Settings.readMoreMoreKeysPref(prefs)
: LocaleKeyTextsKt.MORE_KEYS_NORMAL; : 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); mColors = Settings.getColorsForCurrentTheme(context, prefs);
mAddToPersonalDictionary = prefs.getBoolean(Settings.PREF_ADD_TO_PERSONAL_DICTIONARY, false); mAddToPersonalDictionary = prefs.getBoolean(Settings.PREF_ADD_TO_PERSONAL_DICTIONARY, false);

View file

@ -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<String>? {
val moreKeys = mutableSetOf<String>()
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<String> {
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<Pair<String, Boolean>>() {
override fun areItemsTheSame(p0: Pair<String, Boolean>, p1: Pair<String, Boolean>) = p0 == p1
override fun areContentsTheSame(p0: Pair<String, Boolean>, p1: Pair<String, Boolean>) = p0 == p1
}
val adapter = object : ListAdapter<Pair<String, Boolean>, 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<TextView>(R.id.morekeys_type)?.text = displayText
val switch = p0.itemView.findViewById<SwitchCompat>(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()
}

View file

@ -0,0 +1,13 @@
<!--
icon available in Android Studio
modified
SPDX-License-Identifier: Apache-2.0
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportHeight="24"
android:viewportWidth="24">
<path android:fillColor="#FFF"
android:pathData="M11,18c0,1.1 -0.9,2 -2,2s-2,-0.9 -2,-2 0.9,-2 2,-2 2,0.9 2,2zM9,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM9,4c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM15,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM15,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM15,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z"/>
</vector>

View file

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
SPDX-License-Identifier: GPL-3.0-only
-->
<!--
why is the android resource system sometimes so horrible to work with?
setting colorBackgroundFloating in code sets an empty background
using a color that's colorBackground, but colorBackgroundFloating in v23 crashes
with Failed to resolve attribute at index 13: TypedValue{t=0x2/d=0x1010031 a=3 r=0x7f06008c}
it seems to be absolutely necessary to clone the layout... wtf?
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:paddingHorizontal="10dp"
android:paddingVertical="4dp"
android:orientation="horizontal"
android:background="?android:attr/colorBackgroundFloating"
android:minHeight="48dp"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<TextView
android:id="@+id/morekeys_type"
style="@style/PreferenceTitleText"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content" />
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/morekeys_switch"
android:padding="6dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<ImageView
android:paddingEnd="10dp"
android:src="@drawable/ic_drag_indicator"
app:tint="@color/foreground_weak"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>

View file

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
SPDX-License-Identifier: GPL-3.0-only
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:paddingHorizontal="16dp"
android:paddingVertical="4dp"
android:orientation="horizontal"
android:background="?android:attr/colorBackground"
android:minHeight="48dp"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<TextView
android:id="@+id/morekeys_type"
style="@style/PreferenceTitleText"
android:layout_gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/morekeys_switch"
android:padding="6dp"
android:layout_gravity="center_vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<ImageView
android:paddingEnd="10dp"
android:src="@drawable/ic_drag_indicator"
app:tint="@color/foreground_weak"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>

View file

@ -209,8 +209,6 @@ Nouveau dictionnaire:
<string name="prefs_long_press_keyboard_to_change_lang_summary">Un appui long sur la barre d\'espace fera apparaître le menu de sélection des claviers</string> <string name="prefs_long_press_keyboard_to_change_lang_summary">Un appui long sur la barre d\'espace fera apparaître le menu de sélection des claviers</string>
<string name="show_hints">Afficher les indices de touches</string> <string name="show_hints">Afficher les indices de touches</string>
<string name="show_hints_summary">Affiche les caractères alternatifs lors d\'un appui long</string> <string name="show_hints_summary">Affiche les caractères alternatifs lors d\'un appui long</string>
<string name="show_hints_from_first_popup_key">Afficher les indices à partir de la première sélection du popup</string>
<string name="show_hints_from_first_popup_key_summary">Les caractères alternatifs par défaut sont remplacés par ceux sélectionnés en premier lors d\'un appui long</string>
<string name="show_popup_hints">Afficher les indices sur les touches fonctionnelles</string> <string name="show_popup_hints">Afficher les indices sur les touches fonctionnelles</string>
<string name="show_popup_hints_summary">Affiche un signe ( <b></b> ) sur les touches où un appui long déclenche une fonctionnalité supplémentaire</string> <string name="show_popup_hints_summary">Affiche un signe ( <b></b> ) sur les touches où un appui long déclenche une fonctionnalité supplémentaire</string>
<string name="prefs_keyboard_height_scale">Échelle de hauteur du clavier</string> <string name="prefs_keyboard_height_scale">Échelle de hauteur du clavier</string>

View file

@ -234,10 +234,15 @@
<string name="show_hints">Show key hints</string> <string name="show_hints">Show key hints</string>
<!-- Description of the settings to show hints --> <!-- Description of the settings to show hints -->
<string name="show_hints_summary">Show long-press hints</string> <string name="show_hints_summary">Show long-press hints</string>
<!-- Title of the settings to show hint based on actual long-press key --> <!-- Title of the settings to select key hints source -->
<string name="show_hints_from_first_popup_key">Take hint label from first popup key</string> <string name="hint_source">Select hint source</string>
<!-- Summary of the settings to show hint based on actual long-press key --> <!-- Title of the settings to set popup key order -->
<string name="show_hints_from_first_popup_key_summary">The default key hints are replaced by those selected first on a long press</string> <string name="popup_order">Select popup key order</string>
<string name="more_keys_number">Number</string>
<string name="more_keys_language">Language</string>
<string name="more_keys_language_priority">Language (priority)</string>
<string name="more_keys_layout">Layout</string>
<string name="more_keys_symbols">Symbols</string>
<!-- Title of the settings to show "..." as hints for more functionality on long-press --> <!-- Title of the settings to show "..." as hints for more functionality on long-press -->
<string name="show_popup_hints">Show functional hints</string> <string name="show_popup_hints">Show functional hints</string>
<!-- Description of the show_popup_hints setting --> <!-- Description of the show_popup_hints setting -->

View file

@ -17,12 +17,13 @@
android:defaultValue="true" android:defaultValue="true"
android:persistent="true" /> android:persistent="true" />
<SwitchPreferenceCompat <Preference
android:key="pref_hint_label_from_first_more_key" android:key="pref_more_keys_labels_order"
android:title="@string/show_hints_from_first_popup_key" android:title="@string/hint_source" />
android:summary="@string/show_hints_from_first_popup_key_summary"
android:defaultValue="false" <Preference
android:persistent="true" /> android:key="pref_more_keys_order"
android:title="@string/popup_order" />
<SwitchPreferenceCompat <SwitchPreferenceCompat
android:key="pref_show_popup_hints" android:key="pref_show_popup_hints"

View file

@ -7,7 +7,7 @@ buildscript {
google() google()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:8.2.0' classpath 'com.android.tools.build:gradle:8.1.4' // 8.2 requires newer Android Studio that is even worse than 2022.x in performance
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
@ -17,7 +17,7 @@ buildscript {
} }
plugins { plugins {
id 'org.jetbrains.kotlin.plugin.serialization' version '1.9.10' apply false id 'org.jetbrains.kotlin.plugin.serialization' version '1.9.21' apply false
} }
allprojects { allprojects {