Replace bottom keys in emoji / clipboard view customizable keyboard (#966)

This commit is contained in:
Helium314 2024-09-01 21:33:49 +02:00 committed by GitHub
parent be13ca40a1
commit ab34815c7d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 231 additions and 429 deletions

View file

@ -0,0 +1,7 @@
[
[
{ "label": "alpha", "width": 0.15 },
{ "label": "space", "width": -1 },
{ "label": "delete", "width": 0.15 }
]
]

View file

@ -0,0 +1,7 @@
[
[
{ "label": "alpha", "width": 0.15 },
{ "label": "space", "width": -1 },
{ "label": "delete", "width": 0.15 }
]
]

View file

@ -63,6 +63,8 @@ public final class KeyboardId {
public static final int ELEMENT_EMOJI_CATEGORY16 = 26;
public static final int ELEMENT_CLIPBOARD = 27;
public static final int ELEMENT_NUMPAD = 28;
public static final int ELEMENT_EMOJI_BOTTOM_ROW = 29;
public static final int ELEMENT_CLIPBOARD_BOTTOM_ROW = 30;
public final RichInputMethodSubtype mSubtype;
public final int mWidth;
@ -191,6 +193,10 @@ public final class KeyboardId {
return mElementId >= ELEMENT_EMOJI_RECENTS && mElementId <= ELEMENT_EMOJI_CATEGORY16;
}
public boolean isEmojiClipBottomRow() {
return mElementId == ELEMENT_CLIPBOARD_BOTTOM_ROW || mElementId == ELEMENT_EMOJI_BOTTOM_ROW;
}
public int imeAction() {
return InputTypeUtils.getImeOptionsActionIdFromEditorInfo(mEditorInfo);
}

View file

@ -18,9 +18,12 @@ import helium314.keyboard.keyboard.internal.UniqueKeysCache;
import helium314.keyboard.keyboard.internal.keyboard_parser.LocaleKeyboardInfos;
import helium314.keyboard.keyboard.internal.keyboard_parser.LocaleKeyboardInfosKt;
import helium314.keyboard.keyboard.internal.keyboard_parser.RawKeyboardParser;
import helium314.keyboard.latin.RichInputMethodManager;
import helium314.keyboard.latin.RichInputMethodSubtype;
import helium314.keyboard.latin.settings.Settings;
import helium314.keyboard.latin.utils.InputTypeUtils;
import helium314.keyboard.latin.utils.Log;
import helium314.keyboard.latin.utils.ResourceUtils;
import helium314.keyboard.latin.utils.ScriptUtils;
import java.lang.ref.SoftReference;
@ -210,6 +213,18 @@ public final class KeyboardLayoutSet {
}
}
public static KeyboardLayoutSet buildEmojiClipBottomRow(final Context context, @Nullable final EditorInfo ei) {
final Builder builder = new Builder(context, ei);
builder.mParams.mMode = KeyboardId.MODE_TEXT;
// always full width, but height should consider scale and number row to align nicely
// actually the keyboard does not have full height, but at this point we use it to get correct key heights
final int width = ResourceUtils.getDefaultKeyboardWidth(context.getResources());
final int height = ResourceUtils.getKeyboardHeight(context.getResources(), Settings.getInstance().getCurrent());
builder.setKeyboardGeometry(width, height);
builder.setSubtype(RichInputMethodManager.getInstance().getCurrentSubtype());
return builder.build();
}
public Builder setKeyboardGeometry(final int keyboardWidth, final int keyboardHeight) {
mParams.mKeyboardWidth = keyboardWidth;
mParams.mKeyboardHeight = keyboardHeight;

View file

@ -302,6 +302,7 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
@NonNull final SettingsValues settingsValues,
@NonNull final KeyboardSwitchState toggleState) {
final int visibility = isImeSuppressedByHardwareKeyboard(settingsValues, toggleState) ? View.GONE : View.VISIBLE;
PointerTracker.switchTo(mKeyboardView);
mKeyboardView.setVisibility(visibility);
// The visibility of {@link #mKeyboardView} must be aligned with {@link #MainKeyboardFrame}.
// @see #getVisibleKeyboardView() and
@ -332,9 +333,8 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
mClipboardStripScrollView.setVisibility(View.GONE);
mEmojiTabStripView.setVisibility(View.VISIBLE);
mClipboardHistoryView.setVisibility(View.GONE);
mEmojiPalettesView.startEmojiPalettes(
mKeyboardLayoutSet.mLocaleKeyboardInfos.getLabelAlphabet(),
mKeyboardView.getKeyVisualAttribute(), keyboard.mIconsSet);
mEmojiPalettesView.startEmojiPalettes(mKeyboardView.getKeyVisualAttribute(),
mLatinIME.getCurrentInputEditorInfo(), mLatinIME.mKeyboardActionListener);
mEmojiPalettesView.setVisibility(View.VISIBLE);
}
@ -355,10 +355,8 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
mClipboardStripScrollView.post(() -> mClipboardStripScrollView.fullScroll(HorizontalScrollView.FOCUS_RIGHT));
mClipboardStripScrollView.setVisibility(View.VISIBLE);
mEmojiPalettesView.setVisibility(View.GONE);
mClipboardHistoryView.startClipboardHistory(
mLatinIME.getClipboardHistoryManager(),
mKeyboardLayoutSet.mLocaleKeyboardInfos.getLabelAlphabet(),
mKeyboardView.getKeyVisualAttribute(), keyboard.mIconsSet);
mClipboardHistoryView.startClipboardHistory(mLatinIME.getClipboardHistoryManager(), mKeyboardView.getKeyVisualAttribute(),
mLatinIME.getCurrentInputEditorInfo(), mLatinIME.mKeyboardActionListener);
mClipboardHistoryView.setVisibility(View.VISIBLE);
}
@ -633,6 +631,7 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
if (mKeyboardView != null) {
mKeyboardView.closing();
}
PointerTracker.clearOldViewData();
updateKeyboardThemeAndContextThemeWrapper(displayContext, KeyboardTheme.getKeyboardTheme(displayContext));
mCurrentInputView = (InputView)LayoutInflater.from(mThemeContext).inflate(R.layout.input_view, null);
@ -655,6 +654,7 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
mClipboardStripScrollView = mCurrentInputView.findViewById(R.id.clipboard_strip_scroll_view);
mSuggestionStripView = mCurrentInputView.findViewById(R.id.suggestion_strip_view);
PointerTracker.switchTo(mKeyboardView);
return mCurrentInputView;
}

View file

@ -40,6 +40,7 @@ import helium314.keyboard.latin.utils.Log;
import java.util.ArrayList;
import java.util.Locale;
import java.util.WeakHashMap;
public final class PointerTracker implements PointerTrackerQueue.Element,
BatchInputArbiterListener {
@ -73,6 +74,28 @@ public final class PointerTracker implements PointerTrackerQueue.Element,
}
}
// map to store static objects that should be unique for each DrawingProxy (i.e. MainKeyboardView as of now)
// this is a workaround, so we can have a MainKeyboardView in emoji and clipboard views too
// but it will not allow two simultaneously displayed MainKeyboardViews
private static final WeakHashMap<DrawingProxy, Object[]> sProxyMap = new WeakHashMap<>(4);
// called when creating a new InputView
// not sure why this is necessary... maybe misunderstanding regarding WeakHashMap?
public static void clearOldViewData() {
sProxyMap.clear();
}
public static void switchTo(DrawingProxy drawingProxy) {
sDrawingProxy = drawingProxy;
Object[] thatArray = sProxyMap.get(drawingProxy); // if it's null, the view we're switching to should not exist
sParams = (PointerTrackerParams) thatArray[0];
sGestureStrokeRecognitionParams = (GestureStrokeRecognitionParams) thatArray[1];
sGestureStrokeDrawingParams = (GestureStrokeDrawingParams) thatArray[2];
sTypingTimeRecorder = (TypingTimeRecorder) thatArray[3];
sTimerProxy = (TimerProxy) thatArray[4];
sTrackers = (ArrayList<PointerTracker>) thatArray[5];
}
private static final GestureEnabler sGestureEnabler = new GestureEnabler();
// Parameters for pointer handling.
@ -81,7 +104,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element,
private static GestureStrokeRecognitionParams sGestureStrokeRecognitionParams;
private static GestureStrokeDrawingParams sGestureStrokeDrawingParams;
private static final ArrayList<PointerTracker> sTrackers = new ArrayList<>();
private static ArrayList<PointerTracker> sTrackers = new ArrayList<>();
private static final PointerTrackerQueue sPointerTrackerQueue = new PointerTrackerQueue();
public final int mPointerId;
@ -163,6 +186,16 @@ public final class PointerTracker implements PointerTrackerQueue.Element,
sTimerProxy = timerProxy;
sDrawingProxy = drawingProxy;
sTrackers = new ArrayList<>();
sProxyMap.put(drawingProxy, new Object[] {
sParams,
sGestureStrokeRecognitionParams,
sGestureStrokeDrawingParams,
sTypingTimeRecorder,
sTimerProxy,
sTrackers
});
}
// Note that this method is called from a non-UI thread.

View file

@ -4,17 +4,20 @@ package helium314.keyboard.keyboard.clipboard
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.drawable.Drawable
import android.util.AttributeSet
import android.util.TypedValue
import android.view.MotionEvent
import android.view.View
import android.view.inputmethod.EditorInfo
import android.widget.ImageButton
import android.widget.LinearLayout
import android.widget.TextView
import androidx.recyclerview.widget.StaggeredGridLayoutManager
import helium314.keyboard.keyboard.KeyboardActionListener
import helium314.keyboard.keyboard.KeyboardId
import helium314.keyboard.keyboard.KeyboardLayoutSet
import helium314.keyboard.keyboard.KeyboardSwitcher
import helium314.keyboard.keyboard.MainKeyboardView
import helium314.keyboard.keyboard.PointerTracker
import helium314.keyboard.keyboard.internal.KeyDrawParams
import helium314.keyboard.keyboard.internal.KeyVisualAttributes
import helium314.keyboard.keyboard.internal.KeyboardIconsSet
@ -37,23 +40,18 @@ class ClipboardHistoryView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet?,
defStyle: Int = R.attr.clipboardHistoryViewStyle
) : LinearLayout(context, attrs, defStyle), View.OnTouchListener, View.OnClickListener,
) : LinearLayout(context, attrs, defStyle), View.OnClickListener,
ClipboardHistoryManager.OnHistoryChangeListener, OnKeyEventListener, View.OnLongClickListener {
private val clipboardLayoutParams = ClipboardLayoutParams(context.resources)
private val pinIconId: Int
private val functionalKeyBackgroundId: Int
private val keyBackgroundId: Int
private val spacebarBackground: Drawable
private var initialized = false
private lateinit var clipboardRecyclerView: ClipboardHistoryRecyclerView
private lateinit var placeholderView: TextView
private lateinit var alphabetKey: TextView
private val toolbarKeys = mutableListOf<ImageButton>()
private lateinit var clipboardAdapter: ClipboardAdapter
private lateinit var spacebar: View
private lateinit var deleteKey: ImageButton
var keyboardActionListener: KeyboardActionListener? = null
var clipboardHistoryManager: ClipboardHistoryManager? = null
@ -65,8 +63,6 @@ class ClipboardHistoryView @JvmOverloads constructor(
clipboardViewAttr.recycle()
val keyboardViewAttr = context.obtainStyledAttributes(attrs, R.styleable.KeyboardView, defStyle, R.style.KeyboardView)
keyBackgroundId = keyboardViewAttr.getResourceId(R.styleable.KeyboardView_keyBackground, 0)
functionalKeyBackgroundId = keyboardViewAttr.getResourceId(R.styleable.KeyboardView_functionalKeyBackground, keyBackgroundId)
spacebarBackground = Settings.getInstance().current.mColors.selectAndColorDrawable(keyboardViewAttr, ColorType.SPACE_BAR_BACKGROUND)
keyboardViewAttr.recycle()
val keyboardAttr = context.obtainStyledAttributes(attrs, R.styleable.Keyboard, defStyle, R.style.SuggestionStripView)
// todo (maybe): setting the correct color only works because the activated state is inverted
@ -84,7 +80,6 @@ class ClipboardHistoryView @JvmOverloads constructor(
// The main keyboard expands to the entire this {@link KeyboardView}.
val width = ResourceUtils.getKeyboardWidth(res, Settings.getInstance().current) + paddingLeft + paddingRight
val height = ResourceUtils.getKeyboardHeight(res, Settings.getInstance().current) + paddingTop + paddingBottom
findViewById<LinearLayout>(R.id.action_bar)?.layoutParams?.width = width
setMeasuredDimension(width, height)
}
@ -105,25 +100,9 @@ class ClipboardHistoryView @JvmOverloads constructor(
clipboardLayoutParams.setListProperties(this)
placeholderView = this@ClipboardHistoryView.placeholderView
}
alphabetKey = findViewById(R.id.key_alphabet)
alphabetKey.setBackgroundResource(functionalKeyBackgroundId)
alphabetKey.tag = KeyCode.ALPHA
alphabetKey.setOnTouchListener(this)
alphabetKey.setOnClickListener(this)
deleteKey = findViewById(R.id.key_delete)
deleteKey.setBackgroundResource(functionalKeyBackgroundId)
deleteKey.tag = KeyCode.DELETE
deleteKey.setOnTouchListener(this)
deleteKey.setOnClickListener(this)
spacebar = findViewById(R.id.key_space)
spacebar.background = spacebarBackground
spacebar.tag = Constants.CODE_SPACE
spacebar.setOnTouchListener(this)
spacebar.setOnClickListener(this)
val clipboardStrip = KeyboardSwitcher.getInstance().clipboardStrip
toolbarKeys.forEach {
clipboardStrip.addView(it)
it.setOnTouchListener(this@ClipboardHistoryView)
it.setOnClickListener(this@ClipboardHistoryView)
it.setOnLongClickListener(this@ClipboardHistoryView)
colors.setColor(it, ColorType.TOOL_BAR_KEY)
@ -132,24 +111,6 @@ class ClipboardHistoryView @JvmOverloads constructor(
initialized = true
}
private fun setupAlphabetKey(key: TextView, label: String, params: KeyDrawParams) {
key.apply {
text = label
typeface = params.mTypeface
Settings.getInstance().current.mColors.setBackground(this, ColorType.FUNCTIONAL_KEY_BACKGROUND)
setTextColor(params.mFunctionalTextColor)
setTextSize(TypedValue.COMPLEX_UNIT_PX, params.mLabelSize.toFloat())
}
}
private fun setupDeleteKey(key: ImageButton, icon: Drawable?) {
key.apply {
setImageDrawable(icon)
Settings.getInstance().current.mColors.setBackground(this, ColorType.FUNCTIONAL_KEY_BACKGROUND)
Settings.getInstance().current.mColors.setColor(this, ColorType.KEY_ICON)
}
}
private fun setupClipKey(params: KeyDrawParams) {
clipboardAdapter.apply {
itemBackgroundId = keyBackgroundId
@ -165,6 +126,15 @@ class ClipboardHistoryView @JvmOverloads constructor(
toolbarKeys.forEach { it.layoutParams = toolbarKeyLayoutParams }
}
private fun setupBottomRowKeyboard(editorInfo: EditorInfo, listener: KeyboardActionListener) {
val keyboardView = findViewById<MainKeyboardView>(R.id.bottom_row_keyboard)
keyboardView.setKeyboardActionListener(listener)
PointerTracker.switchTo(keyboardView)
val kls = KeyboardLayoutSet.Builder.buildEmojiClipBottomRow(context, editorInfo)
val keyboard = kls.getKeyboard(KeyboardId.ELEMENT_CLIPBOARD_BOTTOM_ROW)
keyboardView.setKeyboard(keyboard)
}
fun setHardwareAcceleratedDrawingEnabled(enabled: Boolean) {
if (!enabled) return
// TODO: Should use LAYER_TYPE_SOFTWARE when hardware acceleration is off?
@ -173,9 +143,9 @@ class ClipboardHistoryView @JvmOverloads constructor(
fun startClipboardHistory(
historyManager: ClipboardHistoryManager,
switchToAlphaLabel: String,
keyVisualAttr: KeyVisualAttributes?,
iconSet: KeyboardIconsSet
editorInfo: EditorInfo,
keyboardActionListener: KeyboardActionListener
) {
initialize()
setupToolbarKeys()
@ -183,15 +153,11 @@ class ClipboardHistoryView @JvmOverloads constructor(
historyManager.setHistoryChangeListener(this)
clipboardHistoryManager = historyManager
clipboardAdapter.clipboardHistoryManager = historyManager
findViewById<LinearLayout>(R.id.action_bar).apply {
clipboardLayoutParams.setActionBarProperties(this)
}
val params = KeyDrawParams()
params.updateParams(clipboardLayoutParams.actionBarContentHeight, keyVisualAttr)
setupAlphabetKey(alphabetKey, switchToAlphaLabel, params)
setupDeleteKey(deleteKey, iconSet.getIconDrawable(KeyboardIconsSet.NAME_DELETE_KEY))
params.updateParams(clipboardLayoutParams.bottomRowKeyboardHeight, keyVisualAttr)
setupClipKey(params)
setupBottomRowKeyboard(editorInfo, keyboardActionListener)
placeholderView.apply {
typeface = params.mTypeface
@ -212,27 +178,7 @@ class ClipboardHistoryView @JvmOverloads constructor(
clipboardAdapter.clipboardHistoryManager = null
}
// the touch & click thing is used to provide haptic and audio feedback if enabled
override fun onTouch(view: View, event: MotionEvent): Boolean {
if (event.actionMasked != MotionEvent.ACTION_DOWN) {
return false
}
when (view) {
alphabetKey, spacebar, deleteKey -> keyboardActionListener?.onPressKey(view.tag as Int, 0, true)
}
// It's important to return false here. Otherwise, {@link #onClick} and touch-down visual
// feedback stop working.
return false
}
override fun onClick(view: View) {
when (view) {
alphabetKey, spacebar, deleteKey -> {
keyboardActionListener?.onCodeInput(view.tag as Int,
Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE, false)
keyboardActionListener?.onReleaseKey(view.tag as Int, false)
}
}
val tag = view.tag
if (tag is ToolbarKey) {
val code = getCodeForToolbarKey(tag)

View file

@ -5,8 +5,8 @@ package helium314.keyboard.keyboard.clipboard
import android.content.res.Resources
import android.view.View
import android.widget.FrameLayout
import android.widget.LinearLayout
import androidx.recyclerview.widget.RecyclerView
import helium314.keyboard.keyboard.internal.KeyboardParams
import helium314.keyboard.latin.R
import helium314.keyboard.latin.settings.Settings
import helium314.keyboard.latin.utils.ResourceUtils
@ -15,20 +15,15 @@ class ClipboardLayoutParams(res: Resources) {
private val keyVerticalGap: Int
private val keyHorizontalGap: Int
private val topPadding: Int
private val bottomPadding: Int
private val listHeight: Int
private val actionBarHeight: Int
companion object {
private const val DEFAULT_KEYBOARD_ROWS = 4
}
val bottomRowKeyboardHeight: Int
init {
val defaultKeyboardHeight = ResourceUtils.getKeyboardHeight(res, Settings.getInstance().current)
val defaultKeyboardWidth = ResourceUtils.getKeyboardWidth(res, Settings.getInstance().current)
val sv = Settings.getInstance().current
val defaultKeyboardHeight = ResourceUtils.getKeyboardHeight(res, sv)
val defaultKeyboardWidth = ResourceUtils.getKeyboardWidth(res, sv)
if (Settings.getInstance().current.mNarrowKeyGaps) {
if (sv.mNarrowKeyGaps) {
keyVerticalGap = res.getFraction(R.fraction.config_key_vertical_gap_holo_narrow,
defaultKeyboardHeight, defaultKeyboardHeight).toInt()
keyHorizontalGap = res.getFraction(R.fraction.config_key_horizontal_gap_holo_narrow,
@ -39,14 +34,16 @@ class ClipboardLayoutParams(res: Resources) {
keyHorizontalGap = res.getFraction(R.fraction.config_key_horizontal_gap_holo,
defaultKeyboardWidth, defaultKeyboardWidth).toInt()
}
bottomPadding = (res.getFraction(R.fraction.config_keyboard_bottom_padding_holo,
defaultKeyboardHeight, defaultKeyboardHeight) * Settings.getInstance().current.mBottomPaddingScale).toInt()
topPadding = res.getFraction(R.fraction.config_keyboard_top_padding_holo,
val bottomPadding = (res.getFraction(R.fraction.config_keyboard_bottom_padding_holo,
defaultKeyboardHeight, defaultKeyboardHeight) * sv.mBottomPaddingScale).toInt()
val topPadding = res.getFraction(R.fraction.config_keyboard_top_padding_holo,
defaultKeyboardHeight, defaultKeyboardHeight).toInt()
val rowCount = DEFAULT_KEYBOARD_ROWS + if (Settings.getInstance().current.mShowsNumberRow) 1 else 0
actionBarHeight = (defaultKeyboardHeight - bottomPadding - topPadding) / rowCount - keyVerticalGap / 2
listHeight = defaultKeyboardHeight - actionBarHeight - bottomPadding
val rowCount = KeyboardParams.DEFAULT_KEYBOARD_ROWS + if (sv.mShowsNumberRow) 1 else 0
bottomRowKeyboardHeight = (defaultKeyboardHeight - bottomPadding - topPadding) / rowCount - keyVerticalGap / 2
// height calculation is not good enough, probably also because keyboard top padding might be off by a pixel (see KeyboardParser)
val offset = 1.25f * res.displayMetrics.density * sv.mKeyboardHeightScale
listHeight = defaultKeyboardHeight - bottomRowKeyboardHeight - bottomPadding + offset.toInt()
}
fun setListProperties(recycler: RecyclerView) {
@ -56,14 +53,6 @@ class ClipboardLayoutParams(res: Resources) {
}
}
fun setActionBarProperties(layout: LinearLayout) {
(layout.layoutParams as LinearLayout.LayoutParams).apply {
height = actionBarHeight
width = ResourceUtils.getKeyboardWidth(layout.resources, Settings.getInstance().current)
layout.layoutParams = this
}
}
fun setItemProperties(view: View) {
(view.layoutParams as RecyclerView.LayoutParams).apply {
topMargin = keyHorizontalGap / 2
@ -73,7 +62,4 @@ class ClipboardLayoutParams(res: Resources) {
view.layoutParams = this
}
}
val actionBarContentHeight
get() = actionBarHeight
}

View file

@ -1,90 +0,0 @@
/*
* Copyright (C) 2013 The Android Open Source Project
* modified
* SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-only
*/
package helium314.keyboard.keyboard.emoji;
import android.content.res.Resources;
import android.view.View;
import android.widget.LinearLayout;
import androidx.recyclerview.widget.RecyclerView;
import helium314.keyboard.latin.R;
import helium314.keyboard.latin.settings.Settings;
import helium314.keyboard.latin.settings.SettingsValues;
import helium314.keyboard.latin.utils.ResourceUtils;
final class EmojiLayoutParams {
private static final int DEFAULT_KEYBOARD_ROWS = 4;
public final int mEmojiListHeight;
private final int mEmojiListBottomMargin;
public final int mEmojiKeyboardHeight;
private final int mEmojiCategoryPageIdViewHeight;
public final int mEmojiActionBarHeight;
public final int mKeyVerticalGap;
private final int mKeyHorizontalGap;
private final int mBottomPadding;
private final int mTopPadding;
public EmojiLayoutParams(final Resources res) {
final SettingsValues settingsValues = Settings.getInstance().getCurrent();
final int defaultKeyboardHeight = ResourceUtils.getKeyboardHeight(res, settingsValues);
final int defaultKeyboardWidth = ResourceUtils.getKeyboardWidth(res, settingsValues);
if (settingsValues.mNarrowKeyGaps) {
mKeyVerticalGap = (int) res.getFraction(R.fraction.config_key_vertical_gap_holo_narrow,
defaultKeyboardHeight, defaultKeyboardHeight);
mKeyHorizontalGap = (int) (res.getFraction(R.fraction.config_key_horizontal_gap_holo_narrow,
defaultKeyboardWidth, defaultKeyboardWidth));
} else {
mKeyVerticalGap = (int) res.getFraction(R.fraction.config_key_vertical_gap_holo,
defaultKeyboardHeight, defaultKeyboardHeight);
mKeyHorizontalGap = (int) (res.getFraction(R.fraction.config_key_horizontal_gap_holo,
defaultKeyboardWidth, defaultKeyboardWidth));
}
final float defaultBottomPadding = res.getFraction(R.fraction.config_keyboard_bottom_padding_holo, defaultKeyboardHeight, defaultKeyboardHeight);
mBottomPadding = (int) (defaultBottomPadding * settingsValues.mBottomPaddingScale);
final int paddingScaleOffset = (int) (mBottomPadding - defaultBottomPadding);
mTopPadding = (int) res.getFraction(R.fraction.config_keyboard_top_padding_holo, defaultKeyboardHeight, defaultKeyboardHeight);
mEmojiCategoryPageIdViewHeight = (int) (res.getDimension(R.dimen.config_emoji_category_page_id_height));
final int baseheight = defaultKeyboardHeight - mBottomPadding - mTopPadding + mKeyVerticalGap;
final int rows = DEFAULT_KEYBOARD_ROWS + (settingsValues.mShowsNumberRow ? 1 : 0); // for proper size considering number row
mEmojiActionBarHeight = baseheight / rows - (mKeyVerticalGap - mBottomPadding) / 2 + paddingScaleOffset / 2;
mEmojiListHeight = defaultKeyboardHeight - mEmojiActionBarHeight - mEmojiCategoryPageIdViewHeight;
mEmojiListBottomMargin = 0;
mEmojiKeyboardHeight = mEmojiListHeight - mEmojiListBottomMargin - 1;
}
public void setEmojiListProperties(final RecyclerView vp) {
final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) vp.getLayoutParams();
lp.height = mEmojiKeyboardHeight;
lp.bottomMargin = mEmojiListBottomMargin;
vp.setLayoutParams(lp);
}
public void setCategoryPageIdViewProperties(final View v) {
final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) v.getLayoutParams();
lp.height = mEmojiCategoryPageIdViewHeight;
v.setLayoutParams(lp);
}
public int getActionBarHeight() {
return mEmojiActionBarHeight - mBottomPadding;
}
public void setActionBarProperties(final LinearLayout ll) {
final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) ll.getLayoutParams();
lp.height = getActionBarHeight();
lp.width = ResourceUtils.getKeyboardWidth(ll.getResources(), Settings.getInstance().getCurrent());
ll.setLayoutParams(lp);
}
public void setKeyProperties(final View v) {
final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) v.getLayoutParams();
lp.leftMargin = mKeyHorizontalGap / 2;
lp.rightMargin = mKeyHorizontalGap / 2;
v.setLayoutParams(lp);
}
}

View file

@ -0,0 +1,62 @@
/*
* Copyright (C) 2013 The Android Open Source Project
* modified
* SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-only
*/
package helium314.keyboard.keyboard.emoji
import android.content.res.Resources
import android.view.View
import android.widget.LinearLayout
import androidx.recyclerview.widget.RecyclerView
import helium314.keyboard.keyboard.internal.KeyboardParams
import helium314.keyboard.latin.R
import helium314.keyboard.latin.settings.Settings
import helium314.keyboard.latin.utils.ResourceUtils
internal class EmojiLayoutParams(res: Resources) {
private val emojiListBottomMargin: Int
val emojiKeyboardHeight: Int
private val emojiCategoryPageIdViewHeight: Int
val bottomRowKeyboardHeight: Int
init {
val sv = Settings.getInstance().current
val defaultKeyboardHeight = ResourceUtils.getKeyboardHeight(res, sv)
val keyVerticalGap = if (sv.mNarrowKeyGaps) {
res.getFraction(R.fraction.config_key_vertical_gap_holo_narrow,
defaultKeyboardHeight, defaultKeyboardHeight).toInt()
} else {
res.getFraction(R.fraction.config_key_vertical_gap_holo,
defaultKeyboardHeight, defaultKeyboardHeight).toInt()
}
val bottomPadding = (res.getFraction(R.fraction.config_keyboard_bottom_padding_holo,
defaultKeyboardHeight, defaultKeyboardHeight) * sv.mBottomPaddingScale).toInt()
val topPadding = res.getFraction(R.fraction.config_keyboard_top_padding_holo,
defaultKeyboardHeight, defaultKeyboardHeight).toInt()
val rowCount = KeyboardParams.DEFAULT_KEYBOARD_ROWS + if (sv.mShowsNumberRow) 1 else 0
bottomRowKeyboardHeight = (defaultKeyboardHeight - bottomPadding - topPadding) / rowCount - keyVerticalGap / 2
val pageIdHeight = res.getDimension(R.dimen.config_emoji_category_page_id_height)
emojiCategoryPageIdViewHeight = pageIdHeight.toInt()
val offset = 1.25f * res.displayMetrics.density * sv.mKeyboardHeightScale // like ClipboardLayoutParams
val emojiListHeight = defaultKeyboardHeight - bottomRowKeyboardHeight - bottomPadding + (offset.toInt())
emojiListBottomMargin = 0
emojiKeyboardHeight = emojiListHeight - emojiCategoryPageIdViewHeight - emojiListBottomMargin
}
fun setEmojiListProperties(vp: RecyclerView) {
val lp = vp.layoutParams as LinearLayout.LayoutParams
lp.height = emojiKeyboardHeight
lp.bottomMargin = emojiListBottomMargin
vp.layoutParams = lp
}
fun setCategoryPageIdViewProperties(v: View) {
val lp = v.layoutParams as LinearLayout.LayoutParams
lp.height = emojiCategoryPageIdViewHeight
v.layoutParams = lp
}
}

View file

@ -10,35 +10,33 @@ import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.view.inputmethod.EditorInfo;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import helium314.keyboard.keyboard.Key;
import helium314.keyboard.keyboard.Keyboard;
import helium314.keyboard.keyboard.KeyboardActionListener;
import helium314.keyboard.keyboard.KeyboardId;
import helium314.keyboard.keyboard.KeyboardLayoutSet;
import helium314.keyboard.keyboard.KeyboardSwitcher;
import helium314.keyboard.keyboard.KeyboardView;
import helium314.keyboard.keyboard.MainKeyboardView;
import helium314.keyboard.keyboard.PointerTracker;
import helium314.keyboard.keyboard.internal.KeyDrawParams;
import helium314.keyboard.keyboard.internal.KeyVisualAttributes;
import helium314.keyboard.keyboard.internal.KeyboardIconsSet;
import helium314.keyboard.keyboard.internal.keyboard_parser.floris.KeyCode;
import helium314.keyboard.latin.AudioAndHapticFeedbackManager;
import helium314.keyboard.latin.R;
import helium314.keyboard.latin.RichInputMethodSubtype;
import helium314.keyboard.latin.common.ColorType;
import helium314.keyboard.latin.common.Colors;
import helium314.keyboard.latin.common.Constants;
import helium314.keyboard.latin.settings.Settings;
import helium314.keyboard.latin.utils.DeviceProtectedUtils;
import helium314.keyboard.latin.utils.ResourceUtils;
@ -59,10 +57,8 @@ import static helium314.keyboard.latin.common.Constants.NOT_A_COORDINATE;
* Because of the above reasons, this class doesn't extend {@link KeyboardView}.
*/
public final class EmojiPalettesView extends LinearLayout
implements View.OnClickListener, View.OnTouchListener, OnKeyEventListener {
implements View.OnClickListener, OnKeyEventListener {
private boolean initialized = false;
private final int mFunctionalKeyBackgroundId;
private final Drawable mSpacebarBackground;
// keep the indicator in case emoji view is changed to tabs / viewpager
private final boolean mCategoryIndicatorEnabled;
private final int mCategoryIndicatorDrawableResId;
@ -71,14 +67,8 @@ public final class EmojiPalettesView extends LinearLayout
private final Colors mColors;
private EmojiPalettesAdapter mEmojiPalettesAdapter;
private final EmojiLayoutParams mEmojiLayoutParams;
private final DeleteKeyOnTouchListener mDeleteKeyOnTouchListener;
private final LinearLayoutManager mEmojiLayoutManager;
private ImageButton mDeleteKey;
private TextView mAlphabetKeyLeft;
private View mSpacebar;
// TODO: Remove this workaround.
private View mSpacebarIcon;
private LinearLayout mTabStrip;
private RecyclerView mEmojiRecyclerView;
private EmojiCategoryPageIndicatorView mEmojiCategoryPageIndicatorView;
@ -95,21 +85,13 @@ public final class EmojiPalettesView extends LinearLayout
public EmojiPalettesView(final Context context, final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle);
final TypedArray keyboardViewAttr = context.obtainStyledAttributes(attrs,
R.styleable.KeyboardView, defStyle, R.style.KeyboardView);
final int keyBackgroundId = keyboardViewAttr.getResourceId(
R.styleable.KeyboardView_keyBackground, 0);
mFunctionalKeyBackgroundId = keyboardViewAttr.getResourceId(
R.styleable.KeyboardView_functionalKeyBackground, keyBackgroundId);
mColors = Settings.getInstance().getCurrent().mColors;
mSpacebarBackground = mColors.selectAndColorDrawable(keyboardViewAttr, ColorType.SPACE_BAR_BACKGROUND);
keyboardViewAttr.recycle();
final KeyboardLayoutSet.Builder builder = new KeyboardLayoutSet.Builder(context, null);
final Resources res = context.getResources();
mEmojiLayoutParams = new EmojiLayoutParams(res);
builder.setSubtype(RichInputMethodSubtype.getEmojiSubtype());
builder.setKeyboardGeometry(ResourceUtils.getKeyboardWidth(res, Settings.getInstance().getCurrent()),
mEmojiLayoutParams.mEmojiKeyboardHeight);
mEmojiLayoutParams.getEmojiKeyboardHeight());
final KeyboardLayoutSet layoutSet = builder.build();
final TypedArray emojiPalettesViewAttr = context.obtainStyledAttributes(attrs,
R.styleable.EmojiPalettesView, defStyle, R.style.EmojiPalettesView);
@ -124,7 +106,6 @@ public final class EmojiPalettesView extends LinearLayout
mCategoryPageIndicatorColor = emojiPalettesViewAttr.getColor( // todo: remove this and related attr
R.styleable.EmojiPalettesView_categoryPageIndicatorColor, 0);
emojiPalettesViewAttr.recycle();
mDeleteKeyOnTouchListener = new DeleteKeyOnTouchListener();
mEmojiLayoutManager = new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false);
}
@ -222,73 +203,10 @@ public final class EmojiPalettesView extends LinearLayout
setCurrentCategoryAndPageId(mEmojiCategory.getCurrentCategoryId(), mEmojiCategory.getCurrentCategoryPageId(), true);
// deleteKey depends only on OnTouchListener.
mDeleteKey = findViewById(R.id.key_delete);
mDeleteKey.setBackgroundResource(mFunctionalKeyBackgroundId);
mColors.setColor(mDeleteKey, ColorType.KEY_ICON);
mDeleteKey.setTag(KeyCode.DELETE);
mDeleteKey.setOnTouchListener(mDeleteKeyOnTouchListener);
// {@link #mAlphabetKeyLeft} and spaceKey depend on
// {@link View.OnClickListener} as well as {@link View.OnTouchListener}.
// {@link View.OnTouchListener} is used as the trigger of key-press, while
// {@link View.OnClickListener} is used as the trigger of key-release which does not occur
// if the event is canceled by moving off the finger from the view.
// The text on alphabet keys are set at
// {@link #startEmojiPalettes(String,int,float,Typeface)}.
mAlphabetKeyLeft = findViewById(R.id.key_alphabet);
mAlphabetKeyLeft.setBackgroundResource(mFunctionalKeyBackgroundId);
mAlphabetKeyLeft.setTag(KeyCode.ALPHA);
mAlphabetKeyLeft.setOnTouchListener(this);
mAlphabetKeyLeft.setOnClickListener(this);
mSpacebar = findViewById(R.id.key_space);
mSpacebar.setBackground(mSpacebarBackground);
mSpacebar.setTag(Constants.CODE_SPACE);
mSpacebar.setOnTouchListener(this);
mSpacebar.setOnClickListener(this);
mEmojiLayoutParams.setKeyProperties(mSpacebar);
mSpacebarIcon = findViewById(R.id.key_space_icon);
mColors.setBackground(mAlphabetKeyLeft, ColorType.FUNCTIONAL_KEY_BACKGROUND);
mColors.setBackground(mDeleteKey, ColorType.FUNCTIONAL_KEY_BACKGROUND);
mColors.setBackground(mSpacebar, ColorType.SPACE_BAR_BACKGROUND);
mEmojiCategoryPageIndicatorView.setColors(mColors.get(ColorType.EMOJI_CATEGORY_SELECTED), mColors.get(ColorType.STRIP_BACKGROUND));
initialized = true;
}
@Override
public boolean dispatchTouchEvent(final MotionEvent ev) {
// Add here to the stack trace to nail down the {@link IllegalArgumentException} exception
// in MotionEvent that sporadically happens.
// TODO: Remove this override method once the issue has been addressed.
return super.dispatchTouchEvent(ev);
}
/**
* Called from {@link EmojiPageKeyboardView} through {@link android.view.View.OnTouchListener}
* interface to handle touch events from View-based elements such as the space bar.
* Note that this method is used only for observing {@link MotionEvent#ACTION_DOWN} to trigger
* {@link KeyboardActionListener#onPressKey}. {@link KeyboardActionListener#onReleaseKey} will
* be covered by {@link #onClick} as long as the event is not canceled.
*/
@Override
public boolean onTouch(final View v, final MotionEvent event) {
if (event.getActionMasked() != MotionEvent.ACTION_DOWN) {
return false;
}
final Object tag = v.getTag();
if (!(tag instanceof Integer)) {
return false;
}
final int code = (Integer) tag;
mKeyboardActionListener.onPressKey(
code, 0 /* repeatCount */, true /* isSinglePointer */);
// It's important to return false here. Otherwise, {@link #onClick} and touch-down visual
// feedback stop working.
return false;
}
/**
* Called from {@link EmojiPageKeyboardView} through {@link android.view.View.OnClickListener}
* interface to handle non-canceled touch-up events from View-based elements such as the space
@ -305,12 +223,6 @@ public final class EmojiPalettesView extends LinearLayout
updateEmojiCategoryPageIdView();
}
}
if (!(tag instanceof Integer)) {
return;
}
final int code = (Integer) tag;
mKeyboardActionListener.onCodeInput(code, NOT_A_COORDINATE, NOT_A_COORDINATE, false);
mKeyboardActionListener.onReleaseKey(code, false);
}
/**
@ -350,29 +262,28 @@ public final class EmojiPalettesView extends LinearLayout
setLayerType(LAYER_TYPE_HARDWARE, null);
}
private static void setupAlphabetKey(final TextView alphabetKey, final String label,
final KeyDrawParams params) {
alphabetKey.setText(label);
alphabetKey.setTextColor(params.mFunctionalTextColor);
alphabetKey.setTextSize(TypedValue.COMPLEX_UNIT_PX, params.mLabelSize);
alphabetKey.setTypeface(params.mTypeface);
}
public void startEmojiPalettes(final String switchToAlphaLabel,
final KeyVisualAttributes keyVisualAttr,
final KeyboardIconsSet iconSet) {
public void startEmojiPalettes(final KeyVisualAttributes keyVisualAttr,
final EditorInfo editorInfo, final KeyboardActionListener keyboardActionListener) {
initialize();
mDeleteKey.setImageDrawable(iconSet.getIconDrawable(KeyboardIconsSet.NAME_DELETE_KEY));
mEmojiLayoutParams.setActionBarProperties(findViewById(R.id.action_bar));
setupBottomRowKeyboard(editorInfo, keyboardActionListener);
final KeyDrawParams params = new KeyDrawParams();
params.updateParams(mEmojiLayoutParams.getActionBarHeight(), keyVisualAttr);
setupAlphabetKey(mAlphabetKeyLeft, switchToAlphaLabel, params);
params.updateParams(mEmojiLayoutParams.getBottomRowKeyboardHeight(), keyVisualAttr);
if (mEmojiRecyclerView.getAdapter() == null) {
mEmojiRecyclerView.setAdapter(mEmojiPalettesAdapter);
setCurrentCategoryAndPageId(mEmojiCategory.getCurrentCategoryId(), mEmojiCategory.getCurrentCategoryPageId(), true);
}
}
private void setupBottomRowKeyboard(final EditorInfo editorInfo, final KeyboardActionListener keyboardActionListener) {
MainKeyboardView keyboardView = findViewById(R.id.bottom_row_keyboard);
keyboardView.setKeyboardActionListener(keyboardActionListener);
PointerTracker.switchTo(keyboardView);
final KeyboardLayoutSet kls = KeyboardLayoutSet.Builder.buildEmojiClipBottomRow(getContext(), editorInfo);
final Keyboard keyboard = kls.getKeyboard(KeyboardId.ELEMENT_EMOJI_BOTTOM_ROW);
keyboardView.setKeyboard(keyboard);
}
public void stopEmojiPalettes() {
if (!initialized) return;
mEmojiPalettesAdapter.releaseCurrentKey(true);
@ -382,7 +293,6 @@ public final class EmojiPalettesView extends LinearLayout
public void setKeyboardActionListener(final KeyboardActionListener listener) {
mKeyboardActionListener = listener;
mDeleteKeyOnTouchListener.setKeyboardActionListener(listener);
}
private void updateEmojiCategoryPageIdView() {
@ -421,53 +331,6 @@ public final class EmojiPalettesView extends LinearLayout
Settings.getInstance().getCurrent().mColors.setColor((ImageView) current, ColorType.EMOJI_CATEGORY_SELECTED);
}
private static class DeleteKeyOnTouchListener implements OnTouchListener {
private KeyboardActionListener mKeyboardActionListener =
KeyboardActionListener.EMPTY_LISTENER;
public void setKeyboardActionListener(final KeyboardActionListener listener) {
mKeyboardActionListener = listener;
}
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouch(final View v, final MotionEvent event) {
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
onTouchDown(v);
return true;
case MotionEvent.ACTION_MOVE:
final float x = event.getX();
final float y = event.getY();
if (x < 0.0f || v.getWidth() < x || y < 0.0f || v.getHeight() < y) {
// Stop generating key events once the finger moves away from the view area.
onTouchCanceled(v);
}
return true;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
onTouchUp(v);
return true;
}
return false;
}
private void onTouchDown(final View v) {
mKeyboardActionListener.onPressKey(KeyCode.DELETE, 0, true);
v.setPressed(true /* pressed */);
}
private void onTouchUp(final View v) {
mKeyboardActionListener.onCodeInput(KeyCode.DELETE, NOT_A_COORDINATE, NOT_A_COORDINATE, false);
mKeyboardActionListener.onReleaseKey(KeyCode.DELETE, false);
v.setPressed(false /* pressed */);
}
private void onTouchCanceled(final View v) {
v.setPressed(false);
}
}
public void clearKeyboardCache() {
mEmojiCategory.clearKeyboardCache();
}

View file

@ -31,7 +31,7 @@ import java.util.TreeSet;
public class KeyboardParams {
private static final int DEFAULT_KEYBOARD_COLUMNS = 10;
private static final int DEFAULT_KEYBOARD_ROWS = 4;
public static final int DEFAULT_KEYBOARD_ROWS = 4;
public KeyboardId mId;
public int mThemeId;

View file

@ -26,6 +26,7 @@ import helium314.keyboard.latin.utils.getCustomLayoutFiles
import helium314.keyboard.latin.utils.replaceFirst
import helium314.keyboard.latin.utils.splitAt
import helium314.keyboard.latin.utils.sumOf
import kotlin.math.roundToInt
/**
* Abstract parser class that handles creation of keyboard from [KeyData] arranged in rows,
@ -50,8 +51,23 @@ class KeyboardParser(private val params: KeyboardParams, private val context: Co
val baseKeys = RawKeyboardParser.parseLayout(params, context)
val keysInRows = createRows(baseKeys)
// rescale height if we have anything but the usual 4 rows
val heightRescale = if (keysInRows.size != 4) 4f / keysInRows.size else 1f
val heightRescale: Float
if (params.mId.isEmojiClipBottomRow) {
heightRescale = 4f
// params rescale is not perfect, especially mTopPadding may cause 1 pixel offsets because it's already been converted to int once
if (Settings.getInstance().current.mShowsNumberRow) {
params.mOccupiedHeight /= 5
params.mBaseHeight /= 5
params.mTopPadding = (params.mTopPadding / 5.0).roundToInt()
} else {
params.mOccupiedHeight /= 4
params.mBaseHeight /= 4
params.mTopPadding = (params.mTopPadding / 4.0).roundToInt()
}
} else {
// rescale height if we have anything but the usual 4 rows
heightRescale = if (keysInRows.size != 4) 4f / keysInRows.size else 1f
}
if (heightRescale != 1f) {
keysInRows.forEach { row -> row.forEach { it.mHeight *= heightRescale } }
}
@ -314,3 +330,5 @@ const val LAYOUT_NUMBER = "number"
const val LAYOUT_PHONE = "phone"
const val LAYOUT_PHONE_SYMBOLS = "phone_symbols"
const val LAYOUT_NUMBER_ROW = "number_row"
const val LAYOUT_EMOJI_BOTTOM_ROW = "emoji_bottom_row"
const val LAYOUT_CLIPBOARD_BOTTOM_ROW = "clip_bottom_row"

View file

@ -37,7 +37,8 @@ object RawKeyboardParser {
private val rawLayoutCache = hashMapOf<String, (KeyboardParams) -> MutableList<MutableList<KeyData>>>()
val symbolAndNumberLayouts = listOf(LAYOUT_SYMBOLS, LAYOUT_SYMBOLS_SHIFTED, LAYOUT_SYMBOLS_ARABIC,
LAYOUT_NUMBER, LAYOUT_NUMPAD, LAYOUT_NUMPAD_LANDSCAPE, LAYOUT_PHONE, LAYOUT_PHONE_SYMBOLS, LAYOUT_NUMBER_ROW)
LAYOUT_NUMBER, LAYOUT_NUMPAD, LAYOUT_NUMPAD_LANDSCAPE, LAYOUT_PHONE, LAYOUT_PHONE_SYMBOLS,
LAYOUT_NUMBER_ROW, LAYOUT_EMOJI_BOTTOM_ROW, LAYOUT_CLIPBOARD_BOTTOM_ROW)
fun clearCache() = rawLayoutCache.clear()
@ -137,6 +138,8 @@ object RawKeyboardParser {
KeyboardId.ELEMENT_NUMBER -> LAYOUT_NUMBER
KeyboardId.ELEMENT_PHONE -> LAYOUT_PHONE
KeyboardId.ELEMENT_PHONE_SYMBOLS -> LAYOUT_PHONE_SYMBOLS
KeyboardId.ELEMENT_EMOJI_BOTTOM_ROW -> LAYOUT_EMOJI_BOTTOM_ROW
KeyboardId.ELEMENT_CLIPBOARD_BOTTOM_ROW -> LAYOUT_CLIPBOARD_BOTTOM_ROW
else -> params.mId.mSubtype.keyboardLayoutSetName.substringBeforeLast("+")
}

View file

@ -110,7 +110,7 @@ sealed interface KeyData : AbstractKeyData {
}
private fun getSpaceLabel(params: KeyboardParams): String =
if (params.mId.isAlphaOrSymbolKeyboard)
if (params.mId.isAlphaOrSymbolKeyboard || params.mId.isEmojiClipBottomRow)
"!icon/space_key|!code/key_space"
else "!icon/space_key_for_number_layout|!code/key_space"

View file

@ -1,64 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
SPDX-License-Identifier: GPL-3.0-only
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/action_bar"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1"
>
<!-- TODO: Implement a KeyView and replace this. -->
<!-- Provide audio and haptic feedback by ourselves based on the keyboard settings.
We just need to ignore the system's audio and haptic feedback settings. -->
<TextView
android:id="@+id/key_alphabet"
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="0.15"
android:layout_marginStart="2dp"
android:layout_marginTop="2dp"
android:layout_marginEnd="2dp"
android:gravity="center"
android:hapticFeedbackEnabled="false"
android:soundEffectsEnabled="false" />
<!-- TODO: Implement KeyView and replace this. -->
<!-- Provide audio and haptic feedback by ourselves based on the keyboard settings.
We just need to ignore the system's audio and haptic feedback settings. -->
<RelativeLayout
android:id="@+id/key_space"
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="0.70"
android:layout_marginStart="2dp"
android:layout_marginTop="2dp"
android:layout_marginEnd="2dp"
android:hapticFeedbackEnabled="false"
android:soundEffectsEnabled="false"
android:contentDescription="@string/spoken_description_space">
<!-- WORKAROUND: Show the spacebar icon as a background of this View. -->
<View
android:id="@+id/key_space_icon"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="12dp"
android:layout_marginRight="12dp"
android:layout_centerInParent="true" />
</RelativeLayout>
<!-- TODO: Implement KeyView and replace this. -->
<!-- Provide audio and haptic feedback by ourselves based on the keyboard settings.
We just need to ignore the system's audio and haptic feedback settings. -->
<ImageButton
android:id="@+id/key_delete"
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="0.15"
android:layout_marginStart="2dp"
android:layout_marginTop="2dp"
android:layout_marginEnd="2dp"
android:gravity="center"
android:hapticFeedbackEnabled="false"
android:soundEffectsEnabled="false"
android:contentDescription="@string/spoken_description_delete" />
</LinearLayout>

View file

@ -34,6 +34,9 @@
</FrameLayout>
<include layout="@layout/action_bar" />
<helium314.keyboard.keyboard.MainKeyboardView
android:id="@+id/bottom_row_keyboard"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</helium314.keyboard.keyboard.clipboard.ClipboardHistoryView>

View file

@ -24,6 +24,9 @@
android:id="@+id/emoji_category_page_id_view"
android:layout_width="match_parent"
android:layout_height="2dip" />
<include layout="@layout/action_bar" />
<helium314.keyboard.keyboard.MainKeyboardView
android:id="@+id/bottom_row_keyboard"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</helium314.keyboard.keyboard.emoji.EmojiPalettesView>

View file

@ -533,6 +533,10 @@ disposition rather than other common dispositions for Latin languages. [CHAR LIM
<string name="layout_numpad_landscape" tools:keep="@string/layout_numpad_landscape">Numpad (landscape)</string>
<!-- Name for number row layout -->
<string name="layout_number_row" tools:keep="@string/layout_number_row">Number row</string>
<!-- Name for bottom row layout in emoji view -->
<string name="layout_emoji_bottom_row" tools:keep="@string/layout_emoji_bottom_row">Emoji bottom row</string>
<!-- Name for bottom row layout in clipboard view -->
<string name="layout_clip_bottom_row" tools:keep="@string/layout_clip_bottom_row">Clipboard bottom row</string>
<!-- Title for customizing background image -->
<string name="customize_background_image">Set background image</string>
<!-- Title for customizing currencies -->