identify keyboard icons by name only

re-work KeyboardIconsSet
also fixes a recent regression where some icons are not displayed
This commit is contained in:
Helium314 2024-05-12 18:08:15 +02:00
parent 789b76b790
commit 3862d1e9b2
12 changed files with 158 additions and 265 deletions

View file

@ -26,8 +26,6 @@ import helium314.keyboard.latin.utils.PopupKeysUtilsKt;
import java.util.Arrays;
import java.util.Locale;
import static helium314.keyboard.keyboard.internal.KeyboardIconsSet.ICON_UNDEFINED;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@ -80,7 +78,7 @@ public class Key implements Comparable<Key> {
public static final int LABEL_FLAGS_DISABLE_ADDITIONAL_POPUP_KEYS = 0x80000000;
/** Icon to display instead of a label. Icon takes precedence over a label */
private final int mIconId;
@NonNull private final String mIconName;
/** Width of the key, excluding the gap */
private final int mWidth;
@ -156,29 +154,29 @@ public class Key implements Comparable<Key> {
public final String mOutputText;
public final int mAltCode;
/** Icon for disabled state */
public final int mDisabledIconId;
public final String mDisabledIconName;
/** The visual insets */
public final int mVisualInsetsLeft;
public final int mVisualInsetsRight;
private OptionalAttributes(final String outputText, final int altCode,
final int disabledIconId, final int visualInsetsLeft, final int visualInsetsRight) {
final String disabledIconName, final int visualInsetsLeft, final int visualInsetsRight) {
mOutputText = outputText;
mAltCode = altCode;
mDisabledIconId = disabledIconId;
mDisabledIconName = disabledIconName;
mVisualInsetsLeft = visualInsetsLeft;
mVisualInsetsRight = visualInsetsRight;
}
@Nullable
public static OptionalAttributes newInstance(final String outputText, final int altCode,
final int disabledIconId, final int visualInsetsLeft, final int visualInsetsRight) {
final String disabledIconName, final int visualInsetsLeft, final int visualInsetsRight) {
if (outputText == null && altCode == KeyCode.NOT_SPECIFIED
&& disabledIconId == ICON_UNDEFINED && visualInsetsLeft == 0
&& disabledIconName.equals(KeyboardIconsSet.NAME_UNDEFINED) && visualInsetsLeft == 0
&& visualInsetsRight == 0) {
return null;
}
return new OptionalAttributes(outputText, altCode, disabledIconId, visualInsetsLeft,
return new OptionalAttributes(outputText, altCode, disabledIconName, visualInsetsLeft,
visualInsetsRight);
}
}
@ -193,7 +191,7 @@ public class Key implements Comparable<Key> {
/**
* Constructor for a key on <code>PopupKeyKeyboard</code> and on <code>MoreSuggestions</code>.
*/
public Key(@Nullable final String label, final int iconId, final int code,
public Key(@Nullable final String label, final String iconName, final int code,
@Nullable final String outputText, @Nullable final String hintLabel,
final int labelFlags, final int backgroundType, final int x, final int y,
final int width, final int height, final int horizontalGap, final int verticalGap) {
@ -210,10 +208,10 @@ public class Key implements Comparable<Key> {
mPopupKeysColumnAndFlags = 0;
mLabel = label;
mOptionalAttributes = OptionalAttributes.newInstance(outputText, KeyCode.NOT_SPECIFIED,
ICON_UNDEFINED, 0 /* visualInsetsLeft */, 0 /* visualInsetsRight */);
KeyboardIconsSet.NAME_UNDEFINED, 0, 0);
mCode = code;
mEnabled = (code != KeyCode.NOT_SPECIFIED);
mIconId = iconId;
mIconName = iconName;
// Horizontal gap is divided equally to both sides of the key.
mX = x + mHorizontalGap / 2;
mY = y;
@ -238,7 +236,7 @@ public class Key implements Comparable<Key> {
mLabel = key.mLabel;
mHintLabel = labelHint;
mLabelFlags = key.mLabelFlags;
mIconId = key.mIconId;
mIconName = key.mIconName;
mWidth = key.mWidth;
mHeight = key.mHeight;
mHorizontalGap = key.mHorizontalGap;
@ -266,7 +264,7 @@ public class Key implements Comparable<Key> {
mLabel = outputText == null ? StringUtils.newSingleCodePointString(code) : outputText;
mHintLabel = labelHint;
mLabelFlags = key.mLabelFlags;
mIconId = key.mIconId;
mIconName = key.mIconName;
mWidth = key.mWidth;
mHeight = key.mHeight;
mHorizontalGap = key.mHorizontalGap;
@ -279,7 +277,8 @@ public class Key implements Comparable<Key> {
mBackgroundType = backgroundType;
mActionFlags = key.mActionFlags;
mKeyVisualAttributes = key.mKeyVisualAttributes;
mOptionalAttributes = outputText == null ? null : Key.OptionalAttributes.newInstance(outputText, KeyCode.NOT_SPECIFIED, ICON_UNDEFINED, 0, 0);
mOptionalAttributes = outputText == null ? null
: Key.OptionalAttributes.newInstance(outputText, KeyCode.NOT_SPECIFIED, KeyboardIconsSet.NAME_UNDEFINED, 0, 0);
mHashCode = key.mHashCode;
// Key state.
mPressed = key.mPressed;
@ -293,7 +292,7 @@ public class Key implements Comparable<Key> {
mLabel = keyParams.mLabel;
mHintLabel = keyParams.mHintLabel;
mLabelFlags = keyParams.mLabelFlags;
mIconId = keyParams.mIconId;
mIconName = keyParams.mIconName;
mPopupKeys = keyParams.mPopupKeys;
mPopupKeysColumnAndFlags = keyParams.mPopupKeysColumnAndFlags;
mBackgroundType = keyParams.mBackgroundType;
@ -328,7 +327,7 @@ public class Key implements Comparable<Key> {
mLabel = key.mLabel;
mHintLabel = key.mHintLabel;
mLabelFlags = key.mLabelFlags;
mIconId = key.mIconId;
mIconName = key.mIconName;
mWidth = key.mWidth;
mHeight = key.mHeight;
mHorizontalGap = key.mHorizontalGap;
@ -378,7 +377,7 @@ public class Key implements Comparable<Key> {
key.mCode,
key.mLabel,
key.mHintLabel,
key.mIconId,
key.mIconName,
key.mBackgroundType,
Arrays.hashCode(key.mPopupKeys),
key.getOutputText(),
@ -405,7 +404,7 @@ public class Key implements Comparable<Key> {
&& o.mCode == mCode
&& TextUtils.equals(o.mLabel, mLabel)
&& TextUtils.equals(o.mHintLabel, mHintLabel)
&& o.mIconId == mIconId
&& o.mIconName == mIconName
&& o.mBackgroundType == mBackgroundType
&& Arrays.equals(o.mPopupKeys, mPopupKeys)
&& TextUtils.equals(o.getOutputText(), getOutputText())
@ -444,9 +443,9 @@ public class Key implements Comparable<Key> {
}
public String toLongString() {
final int iconId = getIconId();
final String topVisual = (iconId == KeyboardIconsSet.ICON_UNDEFINED)
? KeyboardIconsSet.PREFIX_ICON + KeyboardIconsSet.getIconName(iconId) : getLabel();
final String iconName = getIconName();
final String topVisual = (iconName.equals(KeyboardIconsSet.NAME_UNDEFINED))
? KeyboardIconsSet.PREFIX_ICON + iconName : getLabel();
final String hintLabel = getHintLabel();
final String visual = (hintLabel == null) ? topVisual : topVisual + "^" + hintLabel;
return toString() + " " + visual + "/" + backgroundName(mBackgroundType);
@ -702,16 +701,15 @@ public class Key implements Comparable<Key> {
return (attrs != null) ? attrs.mAltCode : KeyCode.NOT_SPECIFIED;
}
public int getIconId() {
return mIconId;
public String getIconName() {
return mIconName;
}
@Nullable
public Drawable getIcon(final KeyboardIconsSet iconSet, final int alpha) {
final OptionalAttributes attrs = mOptionalAttributes;
final int disabledIconId = (attrs != null) ? attrs.mDisabledIconId : ICON_UNDEFINED;
final int iconId = mEnabled ? getIconId() : disabledIconId;
final Drawable icon = iconSet.getIconDrawable(iconId);
final String iconName = mEnabled ? getIconName() : ((attrs != null) ? attrs.mDisabledIconName : KeyboardIconsSet.NAME_UNDEFINED);
final Drawable icon = iconSet.getIconDrawable(iconName);
if (icon != null) {
icon.setAlpha(alpha);
}
@ -720,7 +718,7 @@ public class Key implements Comparable<Key> {
@Nullable
public Drawable getPreviewIcon(final KeyboardIconsSet iconSet) {
return iconSet.getIconDrawable(getIconId());
return iconSet.getIconDrawable(getIconName());
}
/**
@ -902,7 +900,7 @@ public class Key implements Comparable<Key> {
public final Drawable selectBackgroundDrawable(@NonNull final Drawable keyBackground,
@NonNull final Drawable functionalKeyBackground,
@NonNull final Drawable spacebarBackground,
@NonNull final Drawable actionKeyBackground) {
@NonNull final Drawable actionKeyBackground) {
final Drawable background;
if (isAccentColored()) {
background = actionKeyBackground;
@ -920,7 +918,7 @@ public class Key implements Comparable<Key> {
public final boolean isAccentColored() {
if (hasActionKeyBackground()) return true;
final String iconName = KeyboardIconsSet.getIconName(getIconId());
final String iconName = getIconName();
return iconName.equals(KeyboardIconsSet.NAME_NEXT_KEY)
|| iconName.equals(KeyboardIconsSet.NAME_PREVIOUS_KEY)
|| iconName.equals(KeyboardIconsSet.NAME_CLIPBOARD_ACTION_KEY)
@ -943,8 +941,8 @@ public class Key implements Comparable<Key> {
*/
protected Spacer(final KeyboardParams params, final int x, final int y, final int width,
final int height) {
super(null /* label */, ICON_UNDEFINED, KeyCode.NOT_SPECIFIED, null /* outputText */,
null /* hintLabel */, 0 /* labelFlags */, BACKGROUND_TYPE_EMPTY, x, y, width,
super(null, KeyboardIconsSet.NAME_UNDEFINED, KeyCode.NOT_SPECIFIED, null,
null, 0, BACKGROUND_TYPE_EMPTY, x, y, width,
height, params.mHorizontalGap, params.mVerticalGap);
}
}
@ -968,7 +966,7 @@ public class Key implements Comparable<Key> {
@Nullable public String mLabel;
@Nullable public final String mHintLabel;
public final int mLabelFlags;
public final int mIconId;
@NonNull public final String mIconName;
@Nullable public PopupKeySpec[] mPopupKeys;
public final int mPopupKeysColumnAndFlags;
public int mBackgroundType;
@ -1062,7 +1060,7 @@ public class Key implements Comparable<Key> {
mLabelFlags = labelFlags;
mWidth = width;
mHeight = params.mDefaultRowHeight;
mIconId = KeySpecParser.getIconId(keySpec);
mIconName = KeySpecParser.getIconName(keySpec);
final boolean needsToUpcase = needsToUpcase(mLabelFlags, params.mId.mElementId);
final Locale localeForUpcasing = params.mId.getLocale();
@ -1167,7 +1165,7 @@ public class Key implements Comparable<Key> {
: altCodeInAttr;
mOptionalAttributes = OptionalAttributes.newInstance(outputText, altCode,
// disabled icon only ever for old version of shortcut key, visual insets can be replaced with spacer
KeyboardIconsSet.ICON_UNDEFINED, 0, 0);
KeyboardIconsSet.NAME_UNDEFINED, 0, 0);
// KeyVisualAttributes for a key essentially are what the theme has, but on a per-key base
// could be used e.g. for having a color gradient on key color
mKeyVisualAttributes = null;
@ -1207,11 +1205,11 @@ public class Key implements Comparable<Key> {
mLabel = label;
mOptionalAttributes = code == KeyCode.MULTIPLE_CODE_POINTS
? OptionalAttributes.newInstance(label, KeyCode.NOT_SPECIFIED, ICON_UNDEFINED, 0, 0)
? OptionalAttributes.newInstance(label, KeyCode.NOT_SPECIFIED, KeyboardIconsSet.NAME_UNDEFINED, 0, 0)
: null;
mCode = code;
mEnabled = (code != KeyCode.NOT_SPECIFIED);
mIconId = KeyboardIconsSet.ICON_UNDEFINED;
mIconName = KeyboardIconsSet.NAME_UNDEFINED;
mKeyVisualAttributes = null;
}
@ -1225,7 +1223,7 @@ public class Key implements Comparable<Key> {
mHintLabel = null;
mKeyVisualAttributes = null;
mOptionalAttributes = null;
mIconId = KeyboardIconsSet.ICON_UNDEFINED;
mIconName = KeyboardIconsSet.NAME_UNDEFINED;
mBackgroundType = BACKGROUND_TYPE_NORMAL;
mActionFlags = ACTION_FLAGS_NO_KEY_PREVIEW;
mPopupKeys = null;
@ -1247,7 +1245,7 @@ public class Key implements Comparable<Key> {
mLabel = keyParams.mLabel;
mHintLabel = keyParams.mHintLabel;
mLabelFlags = keyParams.mLabelFlags;
mIconId = keyParams.mIconId;
mIconName = keyParams.mIconName;
mAbsoluteWidth = keyParams.mAbsoluteWidth;
mAbsoluteHeight = keyParams.mAbsoluteHeight;
mPopupKeys = keyParams.mPopupKeys;

View file

@ -39,6 +39,7 @@ import helium314.keyboard.latin.common.StringUtils;
import helium314.keyboard.latin.settings.Settings;
import helium314.keyboard.latin.suggestions.MoreSuggestions;
import helium314.keyboard.latin.suggestions.PopupSuggestionsView;
import helium314.keyboard.latin.utils.Log;
import helium314.keyboard.latin.utils.TypefaceUtils;
import java.util.HashSet;

View file

@ -141,9 +141,9 @@ class ClipboardHistoryView @JvmOverloads constructor(
}
}
private fun setupDeleteKey(key: ImageButton, iconId: Int) {
private fun setupDeleteKey(key: ImageButton, icon: Drawable?) {
key.apply {
setImageResource(iconId)
setImageDrawable(icon)
Settings.getInstance().current.mColors.setBackground(this, ColorType.FUNCTIONAL_KEY_BACKGROUND)
Settings.getInstance().current.mColors.setColor(this, ColorType.KEY_ICON)
}
@ -189,7 +189,7 @@ class ClipboardHistoryView @JvmOverloads constructor(
val params = KeyDrawParams()
params.updateParams(clipboardLayoutParams.actionBarContentHeight, keyVisualAttr)
setupAlphabetKey(alphabetKey, switchToAlphaLabel, params)
setupDeleteKey(deleteKey, iconSet.getIconResourceId(KeyboardIconsSet.NAME_DELETE_KEY))
setupDeleteKey(deleteKey, iconSet.getIconDrawable(KeyboardIconsSet.NAME_DELETE_KEY))
setupClipKey(params)
placeholderView.apply {

View file

@ -360,10 +360,7 @@ public final class EmojiPalettesView extends LinearLayout
final KeyVisualAttributes keyVisualAttr,
final KeyboardIconsSet iconSet) {
initialize();
final int deleteIconResId = iconSet.getIconResourceId(KeyboardIconsSet.NAME_DELETE_KEY);
if (deleteIconResId != 0) {
mDeleteKey.setImageResource(deleteIconResId);
}
mDeleteKey.setImageDrawable(iconSet.getIconDrawable(KeyboardIconsSet.NAME_DELETE_KEY));
mEmojiLayoutParams.setActionBarProperties(findViewById(R.id.action_bar));
final KeyDrawParams params = new KeyDrawParams();
params.updateParams(mEmojiLayoutParams.getActionBarHeight(), keyVisualAttr);

View file

@ -43,11 +43,9 @@ public class KeyPreviewView extends AppCompatTextView {
setGravity(Gravity.CENTER);
}
public void setPreviewVisual(final Key key, final KeyboardIconsSet iconsSet,
final KeyDrawParams drawParams) {
public void setPreviewVisual(final Key key, final KeyboardIconsSet iconsSet, final KeyDrawParams drawParams) {
// What we show as preview should match what we show on a key top in onDraw().
final int iconId = key.getIconId();
if (iconId != KeyboardIconsSet.ICON_UNDEFINED) {
if (!key.getIconName().equals(KeyboardIconsSet.NAME_UNDEFINED)) {
setCompoundDrawables(null, null, null, key.getPreviewIcon(iconsSet));
setText(null);
return;

View file

@ -221,18 +221,17 @@ public final class KeySpecParser {
return defaultCode;
}
public static int getIconId(@Nullable final String keySpec) {
@NonNull
public static String getIconName(@Nullable final String keySpec) {
if (keySpec == null) {
// TODO: Throw {@link KeySpecParserError} once Key.keyLabel attribute becomes mandatory.
return KeyboardIconsSet.ICON_UNDEFINED;
return KeyboardIconsSet.NAME_UNDEFINED;
}
if (!hasIcon(keySpec)) {
return KeyboardIconsSet.ICON_UNDEFINED;
return KeyboardIconsSet.NAME_UNDEFINED;
}
final int labelEnd = indexOfLabelEnd(keySpec);
final String iconName = getBeforeLabelEnd(keySpec, labelEnd)
.substring(KeyboardIconsSet.PREFIX_ICON.length());
return KeyboardIconsSet.getIconId(iconName);
return getBeforeLabelEnd(keySpec, labelEnd).substring(KeyboardIconsSet.PREFIX_ICON.length()).intern();
}
public static final class KeySpecParserError extends RuntimeException {

View file

@ -1,196 +0,0 @@
/*
* Copyright (C) 2011 The Android Open Source Project
* modified
* SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-only
*/
package helium314.keyboard.keyboard.internal;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import helium314.keyboard.latin.utils.Log;
import android.util.SparseIntArray;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import helium314.keyboard.latin.R;
import helium314.keyboard.latin.utils.ToolbarKey;
import java.util.HashMap;
public final class KeyboardIconsSet {
private static final String TAG = KeyboardIconsSet.class.getSimpleName();
public static final String PREFIX_ICON = "!icon/";
public static final int ICON_UNDEFINED = 0;
private static final int ATTR_UNDEFINED = 0;
private static final String NAME_UNDEFINED = "undefined";
public static final String NAME_SHIFT_KEY = "shift_key";
public static final String NAME_SHIFT_KEY_SHIFTED = "shift_key_shifted";
public static final String NAME_DELETE_KEY = "delete_key";
public static final String NAME_SETTINGS_KEY = "settings_key";
public static final String NAME_SPACE_KEY = "space_key";
public static final String NAME_SPACE_KEY_FOR_NUMBER_LAYOUT = "space_key_for_number_layout";
public static final String NAME_ENTER_KEY = "enter_key";
public static final String NAME_GO_KEY = "go_key";
public static final String NAME_SEARCH_KEY = "search_key";
public static final String NAME_SEND_KEY = "send_key";
public static final String NAME_NEXT_KEY = "next_key";
public static final String NAME_DONE_KEY = "done_key";
public static final String NAME_PREVIOUS_KEY = "previous_key";
public static final String NAME_TAB_KEY = "tab_key";
public static final String NAME_SHORTCUT_KEY = "shortcut_key";
public static final String NAME_INCOGNITO_KEY = "incognito_key";
public static final String NAME_SHORTCUT_KEY_DISABLED = "shortcut_key_disabled";
public static final String NAME_LANGUAGE_SWITCH_KEY = "language_switch_key";
public static final String NAME_ZWNJ_KEY = "zwnj_key";
public static final String NAME_ZWJ_KEY = "zwj_key";
public static final String NAME_EMOJI_ACTION_KEY = "emoji_action_key";
public static final String NAME_EMOJI_NORMAL_KEY = "emoji_normal_key";
public static final String NAME_CLIPBOARD_ACTION_KEY = "clipboard_action_key";
public static final String NAME_CLIPBOARD_NORMAL_KEY = "clipboard_normal_key";
public static final String NAME_CLEAR_CLIPBOARD_KEY = "clear_clipboard_key";
public static final String NAME_CUT_KEY = "cut_key";
public static final String NAME_NUMPAD_KEY = "numpad_key";
public static final String NAME_START_ONEHANDED_KEY = "start_onehanded_mode_key";
public static final String NAME_STOP_ONEHANDED_KEY = "stop_onehanded_mode_key";
public static final String NAME_SWITCH_ONEHANDED_KEY = "switch_onehanded_key";
private static final SparseIntArray ATTR_ID_TO_ICON_ID = new SparseIntArray();
// Icon name to icon id map.
private static final HashMap<String, Integer> sNameToIdsMap = new HashMap<>();
private static final Object[] NAMES_AND_ATTR_IDS = {
NAME_UNDEFINED, ATTR_UNDEFINED,
NAME_SHIFT_KEY, R.styleable.Keyboard_iconShiftKey,
NAME_DELETE_KEY, R.styleable.Keyboard_iconDeleteKey,
NAME_SETTINGS_KEY, R.styleable.Keyboard_iconSettingsKey,
NAME_SPACE_KEY, R.styleable.Keyboard_iconSpaceKey,
NAME_ENTER_KEY, R.styleable.Keyboard_iconEnterKey,
NAME_GO_KEY, R.styleable.Keyboard_iconGoKey,
NAME_SEARCH_KEY, R.styleable.Keyboard_iconSearchKey,
NAME_SEND_KEY, R.styleable.Keyboard_iconSendKey,
NAME_NEXT_KEY, R.styleable.Keyboard_iconNextKey,
NAME_DONE_KEY, R.styleable.Keyboard_iconDoneKey,
NAME_PREVIOUS_KEY, R.styleable.Keyboard_iconPreviousKey,
NAME_TAB_KEY, R.styleable.Keyboard_iconTabKey,
NAME_SHORTCUT_KEY, R.styleable.Keyboard_iconShortcutKey,
NAME_INCOGNITO_KEY, R.styleable.Keyboard_iconIncognitoKey,
NAME_SPACE_KEY_FOR_NUMBER_LAYOUT, R.styleable.Keyboard_iconSpaceKeyForNumberLayout,
NAME_SHIFT_KEY_SHIFTED, R.styleable.Keyboard_iconShiftKeyShifted,
NAME_SHORTCUT_KEY_DISABLED, R.styleable.Keyboard_iconShortcutKeyDisabled,
NAME_LANGUAGE_SWITCH_KEY, R.styleable.Keyboard_iconLanguageSwitchKey,
NAME_ZWNJ_KEY, R.styleable.Keyboard_iconZwnjKey,
NAME_ZWJ_KEY, R.styleable.Keyboard_iconZwjKey,
NAME_EMOJI_ACTION_KEY, R.styleable.Keyboard_iconEmojiActionKey,
NAME_EMOJI_NORMAL_KEY, R.styleable.Keyboard_iconEmojiNormalKey,
NAME_CLIPBOARD_ACTION_KEY, R.styleable.Keyboard_iconClipboardActionKey,
NAME_CLIPBOARD_NORMAL_KEY, R.styleable.Keyboard_iconClipboardNormalKey,
NAME_CLEAR_CLIPBOARD_KEY, R.styleable.Keyboard_iconClearClipboardKey,
NAME_CUT_KEY, R.styleable.Keyboard_iconCutKey,
NAME_NUMPAD_KEY, R.styleable.Keyboard_iconNumpadKey,
NAME_START_ONEHANDED_KEY, R.styleable.Keyboard_iconStartOneHandedMode,
NAME_STOP_ONEHANDED_KEY, R.styleable.Keyboard_iconStopOneHandedMode,
NAME_SWITCH_ONEHANDED_KEY, R.styleable.Keyboard_iconSwitchOneHandedMode,
ToolbarKey.VOICE.name(), R.styleable.Keyboard_iconShortcutKey,
ToolbarKey.SETTINGS.name(), R.styleable.Keyboard_iconSettingsKey,
ToolbarKey.CLIPBOARD.name(), R.styleable.Keyboard_iconClipboardNormalKey,
ToolbarKey.SELECT_ALL.name(), R.styleable.Keyboard_iconSelectAll,
ToolbarKey.COPY.name(), R.styleable.Keyboard_iconCopyKey,
ToolbarKey.CUT.name(), R.styleable.Keyboard_iconCutKey,
ToolbarKey.ONE_HANDED.name(), R.styleable.Keyboard_iconStartOneHandedMode,
ToolbarKey.LEFT.name(), R.styleable.Keyboard_iconArrowLeft,
ToolbarKey.RIGHT.name(), R.styleable.Keyboard_iconArrowRight,
ToolbarKey.UP.name(), R.styleable.Keyboard_iconArrowUp,
ToolbarKey.DOWN.name(), R.styleable.Keyboard_iconArrowDown,
ToolbarKey.UNDO.name(), R.styleable.Keyboard_iconUndo,
ToolbarKey.REDO.name(), R.styleable.Keyboard_iconRedo,
ToolbarKey.INCOGNITO.name(), R.styleable.Keyboard_iconIncognitoKey,
ToolbarKey.AUTOCORRECT.name(), R.styleable.Keyboard_iconAutoCorrect,
ToolbarKey.CLEAR_CLIPBOARD.name(),R.styleable.Keyboard_iconClearClipboardKey,
ToolbarKey.FULL_LEFT.name(), R.styleable.Keyboard_iconFullLeft,
ToolbarKey.FULL_RIGHT.name(), R.styleable.Keyboard_iconFullRight,
ToolbarKey.SELECT_WORD.name(), R.styleable.Keyboard_iconSelectWord,
ToolbarKey.CLOSE_HISTORY.name(), R.styleable.Keyboard_iconClose,
};
private static final int NUM_ICONS = NAMES_AND_ATTR_IDS.length / 2;
private static final String[] ICON_NAMES = new String[NUM_ICONS];
private final Drawable[] mIcons = new Drawable[NUM_ICONS];
private final int[] mIconResourceIds = new int[NUM_ICONS];
static {
int iconId = ICON_UNDEFINED;
for (int i = 0; i < NAMES_AND_ATTR_IDS.length; i += 2) {
final String name = (String)NAMES_AND_ATTR_IDS[i];
final Integer attrId = (Integer)NAMES_AND_ATTR_IDS[i + 1];
if (attrId != ATTR_UNDEFINED) {
ATTR_ID_TO_ICON_ID.put(attrId, iconId);
}
sNameToIdsMap.put(name, iconId);
ICON_NAMES[iconId] = name;
iconId++;
}
}
public void loadIcons(final TypedArray keyboardAttrs) {
final int size = ATTR_ID_TO_ICON_ID.size();
for (int index = 0; index < size; index++) {
final int attrId = ATTR_ID_TO_ICON_ID.keyAt(index);
try {
final Drawable icon = keyboardAttrs.getDrawable(attrId);
setDefaultBounds(icon);
final Integer iconId = ATTR_ID_TO_ICON_ID.get(attrId);
mIcons[iconId] = icon;
mIconResourceIds[iconId] = keyboardAttrs.getResourceId(attrId, 0);
} catch (Resources.NotFoundException e) {
Log.w(TAG, "Drawable resource for icon #"
+ keyboardAttrs.getResources().getResourceEntryName(attrId)
+ " not found");
}
}
}
private static boolean isValidIconId(final int iconId) {
return iconId >= 0 && iconId < ICON_NAMES.length;
}
@NonNull
public static String getIconName(final int iconId) {
return isValidIconId(iconId) ? ICON_NAMES[iconId] : "unknown<" + iconId + ">";
}
public static int getIconId(final String name) {
Integer iconId = sNameToIdsMap.get(name);
if (iconId != null) {
return iconId;
}
throw new RuntimeException("unknown icon name: " + name);
}
public int getIconResourceId(final String name) {
final int iconId = getIconId(name);
if (isValidIconId(iconId)) {
return mIconResourceIds[iconId];
}
throw new RuntimeException("unknown icon name: " + name);
}
@Nullable
public Drawable getIconDrawable(final int iconId) {
if (isValidIconId(iconId)) {
return mIcons[iconId];
}
throw new RuntimeException("unknown icon id: " + getIconName(iconId));
}
private static void setDefaultBounds(final Drawable icon) {
if (icon != null) {
icon.setBounds(0, 0, icon.getIntrinsicWidth(), icon.getIntrinsicHeight());
}
}
}

View file

@ -0,0 +1,97 @@
package helium314.keyboard.keyboard.internal
import android.content.res.Resources
import android.content.res.TypedArray
import android.graphics.drawable.Drawable
import helium314.keyboard.latin.R
import helium314.keyboard.latin.utils.Log
import helium314.keyboard.latin.utils.ToolbarKey
import helium314.keyboard.latin.utils.getStyleableIconId
class KeyboardIconsSet {
private val iconsByName = HashMap<String, Drawable>(styleableIdByName.size)
fun loadIcons(keyboardAttrs: TypedArray) {
styleableIdByName.forEach { (name, id) ->
try {
val icon = keyboardAttrs.getDrawable(id) ?: return@forEach
icon.setBounds(0, 0, icon.intrinsicWidth, icon.intrinsicHeight)
iconsByName[name] = icon
} catch (e: Resources.NotFoundException) {
Log.w(TAG, "Drawable resource for icon #${keyboardAttrs.resources.getResourceEntryName(id)} not found")
}
}
}
fun getIconDrawable(name: String) = iconsByName[name]
companion object {
private val TAG = KeyboardIconsSet::class.simpleName
const val PREFIX_ICON = "!icon/"
const val NAME_UNDEFINED = "undefined"
const val NAME_SHIFT_KEY = "shift_key"
const val NAME_SHIFT_KEY_SHIFTED = "shift_key_shifted"
const val NAME_DELETE_KEY = "delete_key"
const val NAME_SETTINGS_KEY = "settings_key"
const val NAME_SPACE_KEY = "space_key"
const val NAME_SPACE_KEY_FOR_NUMBER_LAYOUT = "space_key_for_number_layout"
const val NAME_ENTER_KEY = "enter_key"
const val NAME_GO_KEY = "go_key"
const val NAME_SEARCH_KEY = "search_key"
const val NAME_SEND_KEY = "send_key"
const val NAME_NEXT_KEY = "next_key"
const val NAME_DONE_KEY = "done_key"
const val NAME_PREVIOUS_KEY = "previous_key"
const val NAME_TAB_KEY = "tab_key"
const val NAME_SHORTCUT_KEY = "shortcut_key"
const val NAME_INCOGNITO_KEY = "incognito_key"
const val NAME_SHORTCUT_KEY_DISABLED = "shortcut_key_disabled"
const val NAME_LANGUAGE_SWITCH_KEY = "language_switch_key"
const val NAME_ZWNJ_KEY = "zwnj_key"
const val NAME_ZWJ_KEY = "zwj_key"
const val NAME_EMOJI_ACTION_KEY = "emoji_action_key"
const val NAME_EMOJI_NORMAL_KEY = "emoji_normal_key"
const val NAME_CLIPBOARD_ACTION_KEY = "clipboard_action_key"
const val NAME_CLIPBOARD_NORMAL_KEY = "clipboard_normal_key"
const val NAME_CLEAR_CLIPBOARD_KEY = "clear_clipboard_key"
const val NAME_CUT_KEY = "cut_key"
const val NAME_NUMPAD_KEY = "numpad_key"
const val NAME_START_ONEHANDED_KEY = "start_onehanded_mode_key"
const val NAME_STOP_ONEHANDED_KEY = "stop_onehanded_mode_key"
const val NAME_SWITCH_ONEHANDED_KEY = "switch_onehanded_key"
private val styleableIdByName = hashMapOf(
NAME_SHIFT_KEY to R.styleable.Keyboard_iconShiftKey,
NAME_DELETE_KEY to R.styleable.Keyboard_iconDeleteKey,
NAME_SETTINGS_KEY to R.styleable.Keyboard_iconSettingsKey,
NAME_SPACE_KEY to R.styleable.Keyboard_iconSpaceKey,
NAME_ENTER_KEY to R.styleable.Keyboard_iconEnterKey,
NAME_GO_KEY to R.styleable.Keyboard_iconGoKey,
NAME_SEARCH_KEY to R.styleable.Keyboard_iconSearchKey,
NAME_SEND_KEY to R.styleable.Keyboard_iconSendKey,
NAME_NEXT_KEY to R.styleable.Keyboard_iconNextKey,
NAME_DONE_KEY to R.styleable.Keyboard_iconDoneKey,
NAME_PREVIOUS_KEY to R.styleable.Keyboard_iconPreviousKey,
NAME_TAB_KEY to R.styleable.Keyboard_iconTabKey,
NAME_SHORTCUT_KEY to R.styleable.Keyboard_iconShortcutKey,
NAME_INCOGNITO_KEY to R.styleable.Keyboard_iconIncognitoKey,
NAME_SPACE_KEY_FOR_NUMBER_LAYOUT to R.styleable.Keyboard_iconSpaceKeyForNumberLayout,
NAME_SHIFT_KEY_SHIFTED to R.styleable.Keyboard_iconShiftKeyShifted,
NAME_SHORTCUT_KEY_DISABLED to R.styleable.Keyboard_iconShortcutKeyDisabled,
NAME_LANGUAGE_SWITCH_KEY to R.styleable.Keyboard_iconLanguageSwitchKey,
NAME_ZWNJ_KEY to R.styleable.Keyboard_iconZwnjKey,
NAME_ZWJ_KEY to R.styleable.Keyboard_iconZwjKey,
NAME_EMOJI_ACTION_KEY to R.styleable.Keyboard_iconEmojiActionKey,
NAME_EMOJI_NORMAL_KEY to R.styleable.Keyboard_iconEmojiNormalKey,
NAME_CLIPBOARD_ACTION_KEY to R.styleable.Keyboard_iconClipboardActionKey,
NAME_CLIPBOARD_NORMAL_KEY to R.styleable.Keyboard_iconClipboardNormalKey,
NAME_CLEAR_CLIPBOARD_KEY to R.styleable.Keyboard_iconClearClipboardKey,
NAME_CUT_KEY to R.styleable.Keyboard_iconCutKey,
NAME_NUMPAD_KEY to R.styleable.Keyboard_iconNumpadKey,
NAME_START_ONEHANDED_KEY to R.styleable.Keyboard_iconStartOneHandedMode,
NAME_STOP_ONEHANDED_KEY to R.styleable.Keyboard_iconStopOneHandedMode,
NAME_SWITCH_ONEHANDED_KEY to R.styleable.Keyboard_iconSwitchOneHandedMode,
).apply { ToolbarKey.entries.forEach { put(it.name, getStyleableIconId(it)) } }
}
}

View file

@ -40,7 +40,8 @@ public final class PopupKeySpec {
public final String mLabel;
@Nullable
public final String mOutputText;
public final int mIconId;
@NonNull
public final String mIconName;
public PopupKeySpec(@NonNull final String popupKeySpec, boolean needsToUpperCase,
@NonNull final Locale locale) {
@ -63,13 +64,13 @@ public final class PopupKeySpec {
mOutputText = needsToUpperCase
? StringUtils.toTitleCaseOfKeyLabel(outputText, locale) : outputText;
}
mIconId = KeySpecParser.getIconId(popupKeySpec);
mIconName = KeySpecParser.getIconName(popupKeySpec);
}
@NonNull
public Key buildKey(final int x, final int y, final int labelFlags,
@NonNull final KeyboardParams params) {
return new Key(mLabel, mIconId, mCode, mOutputText, null /* hintLabel */, labelFlags,
return new Key(mLabel, mIconName, mCode, mOutputText, null /* hintLabel */, labelFlags,
Key.BACKGROUND_TYPE_NORMAL, x, y, params.mDefaultAbsoluteKeyWidth, params.mDefaultAbsoluteRowHeight,
params.mHorizontalGap, params.mVerticalGap);
}
@ -77,7 +78,7 @@ public final class PopupKeySpec {
@Override
public int hashCode() {
int hashCode = 31 + mCode;
hashCode = hashCode * 31 + mIconId;
hashCode = hashCode * 31 + mIconName.hashCode();
final String label = mLabel;
hashCode = hashCode * 31 + (label == null ? 0 : label.hashCode());
final String outputText = mOutputText;
@ -93,7 +94,7 @@ public final class PopupKeySpec {
if (o instanceof PopupKeySpec) {
final PopupKeySpec other = (PopupKeySpec)o;
return mCode == other.mCode
&& mIconId == other.mIconId
&& mIconName.equals(other.mIconName)
&& TextUtils.equals(mLabel, other.mLabel)
&& TextUtils.equals(mOutputText, other.mOutputText);
}
@ -102,8 +103,8 @@ public final class PopupKeySpec {
@Override
public String toString() {
final String label = (mIconId == KeyboardIconsSet.ICON_UNDEFINED ? mLabel
: KeyboardIconsSet.PREFIX_ICON + KeyboardIconsSet.getIconName(mIconId));
final String label = (mIconName.equals(KeyboardIconsSet.NAME_UNDEFINED) ? mLabel
: KeyboardIconsSet.PREFIX_ICON + mIconName);
final String output = (mCode == KeyCode.MULTIPLE_CODE_POINTS ? mOutputText
: Constants.printableCode(mCode));
if (StringUtils.codePointCount(label) == 1 && label.codePointAt(0) == mCode) {

View file

@ -467,7 +467,7 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co
}
private fun String.replaceIconWithLabelIfNoDrawable(): String {
if (params.mIconsSet.getIconDrawable(KeyboardIconsSet.getIconId(this)) != null) return this
if (params.mIconsSet.getIconDrawable(this) != null) return this
if (params.mId.mWidth == AndroidSpellCheckerService.SPELLCHECKER_DUMMY_KEYBOARD_WIDTH
&& params.mId.mHeight == AndroidSpellCheckerService.SPELLCHECKER_DUMMY_KEYBOARD_HEIGHT
&& !params.mId.mSubtype.hasExtraValue(Constants.Subtype.ExtraValue.EMOJI_CAPABLE)

View file

@ -230,8 +230,8 @@ public final class MoreSuggestions extends Keyboard {
public MoreSuggestionKey(final String word, final String info, final int index,
final MoreSuggestionsParam params) {
super(word /* label */, KeyboardIconsSet.ICON_UNDEFINED, KeyCode.MULTIPLE_CODE_POINTS,
word /* outputText */, info, 0 /* labelFlags */, Key.BACKGROUND_TYPE_NORMAL,
super(word, KeyboardIconsSet.NAME_UNDEFINED, KeyCode.MULTIPLE_CODE_POINTS,
word, info, 0, Key.BACKGROUND_TYPE_NORMAL,
params.getX(index), params.getY(index), params.getWidth(index),
params.mDefaultAbsoluteRowHeight, params.mHorizontalGap, params.mVerticalGap);
mSuggestedWordIndex = index;

View file

@ -10,7 +10,6 @@ import android.widget.ImageView
import androidx.appcompat.view.ContextThemeWrapper
import androidx.core.content.edit
import helium314.keyboard.keyboard.KeyboardTheme
import helium314.keyboard.keyboard.internal.KeyboardIconsSet
import helium314.keyboard.keyboard.internal.keyboard_parser.floris.KeyCode
import helium314.keyboard.latin.R
import helium314.keyboard.latin.settings.Settings
@ -74,8 +73,7 @@ fun getCodeForToolbarKeyLongClick(key: ToolbarKey) = when (key) {
else -> KeyCode.UNSPECIFIED
}
// todo: get the icons from KeyboardIconsSet (but currently it's loaded too late)
private fun getStyleableIconId(key: ToolbarKey) = when (key) {
fun getStyleableIconId(key: ToolbarKey) = when (key) {
VOICE -> R.styleable.Keyboard_iconShortcutKey
SETTINGS -> R.styleable.Keyboard_iconSettingsKey
CLIPBOARD -> R.styleable.Keyboard_iconClipboardNormalKey