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_EMOJI_CATEGORY16 = 26;
public static final int ELEMENT_CLIPBOARD = 27; public static final int ELEMENT_CLIPBOARD = 27;
public static final int ELEMENT_NUMPAD = 28; 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 RichInputMethodSubtype mSubtype;
public final int mWidth; public final int mWidth;
@ -191,6 +193,10 @@ public final class KeyboardId {
return mElementId >= ELEMENT_EMOJI_RECENTS && mElementId <= ELEMENT_EMOJI_CATEGORY16; 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() { public int imeAction() {
return InputTypeUtils.getImeOptionsActionIdFromEditorInfo(mEditorInfo); 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.LocaleKeyboardInfos;
import helium314.keyboard.keyboard.internal.keyboard_parser.LocaleKeyboardInfosKt; import helium314.keyboard.keyboard.internal.keyboard_parser.LocaleKeyboardInfosKt;
import helium314.keyboard.keyboard.internal.keyboard_parser.RawKeyboardParser; import helium314.keyboard.keyboard.internal.keyboard_parser.RawKeyboardParser;
import helium314.keyboard.latin.RichInputMethodManager;
import helium314.keyboard.latin.RichInputMethodSubtype; import helium314.keyboard.latin.RichInputMethodSubtype;
import helium314.keyboard.latin.settings.Settings;
import helium314.keyboard.latin.utils.InputTypeUtils; import helium314.keyboard.latin.utils.InputTypeUtils;
import helium314.keyboard.latin.utils.Log; import helium314.keyboard.latin.utils.Log;
import helium314.keyboard.latin.utils.ResourceUtils;
import helium314.keyboard.latin.utils.ScriptUtils; import helium314.keyboard.latin.utils.ScriptUtils;
import java.lang.ref.SoftReference; 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) { public Builder setKeyboardGeometry(final int keyboardWidth, final int keyboardHeight) {
mParams.mKeyboardWidth = keyboardWidth; mParams.mKeyboardWidth = keyboardWidth;
mParams.mKeyboardHeight = keyboardHeight; mParams.mKeyboardHeight = keyboardHeight;

View file

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

View file

@ -40,6 +40,7 @@ import helium314.keyboard.latin.utils.Log;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Locale; import java.util.Locale;
import java.util.WeakHashMap;
public final class PointerTracker implements PointerTrackerQueue.Element, public final class PointerTracker implements PointerTrackerQueue.Element,
BatchInputArbiterListener { 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(); private static final GestureEnabler sGestureEnabler = new GestureEnabler();
// Parameters for pointer handling. // Parameters for pointer handling.
@ -81,7 +104,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element,
private static GestureStrokeRecognitionParams sGestureStrokeRecognitionParams; private static GestureStrokeRecognitionParams sGestureStrokeRecognitionParams;
private static GestureStrokeDrawingParams sGestureStrokeDrawingParams; 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(); private static final PointerTrackerQueue sPointerTrackerQueue = new PointerTrackerQueue();
public final int mPointerId; public final int mPointerId;
@ -163,6 +186,16 @@ public final class PointerTracker implements PointerTrackerQueue.Element,
sTimerProxy = timerProxy; sTimerProxy = timerProxy;
sDrawingProxy = drawingProxy; 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. // 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.annotation.SuppressLint
import android.content.Context import android.content.Context
import android.graphics.drawable.Drawable
import android.util.AttributeSet import android.util.AttributeSet
import android.util.TypedValue import android.util.TypedValue
import android.view.MotionEvent
import android.view.View import android.view.View
import android.view.inputmethod.EditorInfo
import android.widget.ImageButton import android.widget.ImageButton
import android.widget.LinearLayout import android.widget.LinearLayout
import android.widget.TextView import android.widget.TextView
import androidx.recyclerview.widget.StaggeredGridLayoutManager import androidx.recyclerview.widget.StaggeredGridLayoutManager
import helium314.keyboard.keyboard.KeyboardActionListener import helium314.keyboard.keyboard.KeyboardActionListener
import helium314.keyboard.keyboard.KeyboardId
import helium314.keyboard.keyboard.KeyboardLayoutSet
import helium314.keyboard.keyboard.KeyboardSwitcher 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.KeyDrawParams
import helium314.keyboard.keyboard.internal.KeyVisualAttributes import helium314.keyboard.keyboard.internal.KeyVisualAttributes
import helium314.keyboard.keyboard.internal.KeyboardIconsSet import helium314.keyboard.keyboard.internal.KeyboardIconsSet
@ -37,23 +40,18 @@ class ClipboardHistoryView @JvmOverloads constructor(
context: Context, context: Context,
attrs: AttributeSet?, attrs: AttributeSet?,
defStyle: Int = R.attr.clipboardHistoryViewStyle defStyle: Int = R.attr.clipboardHistoryViewStyle
) : LinearLayout(context, attrs, defStyle), View.OnTouchListener, View.OnClickListener, ) : LinearLayout(context, attrs, defStyle), View.OnClickListener,
ClipboardHistoryManager.OnHistoryChangeListener, OnKeyEventListener, View.OnLongClickListener { ClipboardHistoryManager.OnHistoryChangeListener, OnKeyEventListener, View.OnLongClickListener {
private val clipboardLayoutParams = ClipboardLayoutParams(context.resources) private val clipboardLayoutParams = ClipboardLayoutParams(context.resources)
private val pinIconId: Int private val pinIconId: Int
private val functionalKeyBackgroundId: Int
private val keyBackgroundId: Int private val keyBackgroundId: Int
private val spacebarBackground: Drawable
private var initialized = false private var initialized = false
private lateinit var clipboardRecyclerView: ClipboardHistoryRecyclerView private lateinit var clipboardRecyclerView: ClipboardHistoryRecyclerView
private lateinit var placeholderView: TextView private lateinit var placeholderView: TextView
private lateinit var alphabetKey: TextView
private val toolbarKeys = mutableListOf<ImageButton>() private val toolbarKeys = mutableListOf<ImageButton>()
private lateinit var clipboardAdapter: ClipboardAdapter private lateinit var clipboardAdapter: ClipboardAdapter
private lateinit var spacebar: View
private lateinit var deleteKey: ImageButton
var keyboardActionListener: KeyboardActionListener? = null var keyboardActionListener: KeyboardActionListener? = null
var clipboardHistoryManager: ClipboardHistoryManager? = null var clipboardHistoryManager: ClipboardHistoryManager? = null
@ -65,8 +63,6 @@ class ClipboardHistoryView @JvmOverloads constructor(
clipboardViewAttr.recycle() clipboardViewAttr.recycle()
val keyboardViewAttr = context.obtainStyledAttributes(attrs, R.styleable.KeyboardView, defStyle, R.style.KeyboardView) val keyboardViewAttr = context.obtainStyledAttributes(attrs, R.styleable.KeyboardView, defStyle, R.style.KeyboardView)
keyBackgroundId = keyboardViewAttr.getResourceId(R.styleable.KeyboardView_keyBackground, 0) 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() keyboardViewAttr.recycle()
val keyboardAttr = context.obtainStyledAttributes(attrs, R.styleable.Keyboard, defStyle, R.style.SuggestionStripView) 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 // 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}. // The main keyboard expands to the entire this {@link KeyboardView}.
val width = ResourceUtils.getKeyboardWidth(res, Settings.getInstance().current) + paddingLeft + paddingRight val width = ResourceUtils.getKeyboardWidth(res, Settings.getInstance().current) + paddingLeft + paddingRight
val height = ResourceUtils.getKeyboardHeight(res, Settings.getInstance().current) + paddingTop + paddingBottom val height = ResourceUtils.getKeyboardHeight(res, Settings.getInstance().current) + paddingTop + paddingBottom
findViewById<LinearLayout>(R.id.action_bar)?.layoutParams?.width = width
setMeasuredDimension(width, height) setMeasuredDimension(width, height)
} }
@ -105,25 +100,9 @@ class ClipboardHistoryView @JvmOverloads constructor(
clipboardLayoutParams.setListProperties(this) clipboardLayoutParams.setListProperties(this)
placeholderView = this@ClipboardHistoryView.placeholderView 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 val clipboardStrip = KeyboardSwitcher.getInstance().clipboardStrip
toolbarKeys.forEach { toolbarKeys.forEach {
clipboardStrip.addView(it) clipboardStrip.addView(it)
it.setOnTouchListener(this@ClipboardHistoryView)
it.setOnClickListener(this@ClipboardHistoryView) it.setOnClickListener(this@ClipboardHistoryView)
it.setOnLongClickListener(this@ClipboardHistoryView) it.setOnLongClickListener(this@ClipboardHistoryView)
colors.setColor(it, ColorType.TOOL_BAR_KEY) colors.setColor(it, ColorType.TOOL_BAR_KEY)
@ -132,24 +111,6 @@ class ClipboardHistoryView @JvmOverloads constructor(
initialized = true 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) { private fun setupClipKey(params: KeyDrawParams) {
clipboardAdapter.apply { clipboardAdapter.apply {
itemBackgroundId = keyBackgroundId itemBackgroundId = keyBackgroundId
@ -165,6 +126,15 @@ class ClipboardHistoryView @JvmOverloads constructor(
toolbarKeys.forEach { it.layoutParams = toolbarKeyLayoutParams } 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) { fun setHardwareAcceleratedDrawingEnabled(enabled: Boolean) {
if (!enabled) return if (!enabled) return
// TODO: Should use LAYER_TYPE_SOFTWARE when hardware acceleration is off? // TODO: Should use LAYER_TYPE_SOFTWARE when hardware acceleration is off?
@ -173,9 +143,9 @@ class ClipboardHistoryView @JvmOverloads constructor(
fun startClipboardHistory( fun startClipboardHistory(
historyManager: ClipboardHistoryManager, historyManager: ClipboardHistoryManager,
switchToAlphaLabel: String,
keyVisualAttr: KeyVisualAttributes?, keyVisualAttr: KeyVisualAttributes?,
iconSet: KeyboardIconsSet editorInfo: EditorInfo,
keyboardActionListener: KeyboardActionListener
) { ) {
initialize() initialize()
setupToolbarKeys() setupToolbarKeys()
@ -183,15 +153,11 @@ class ClipboardHistoryView @JvmOverloads constructor(
historyManager.setHistoryChangeListener(this) historyManager.setHistoryChangeListener(this)
clipboardHistoryManager = historyManager clipboardHistoryManager = historyManager
clipboardAdapter.clipboardHistoryManager = historyManager clipboardAdapter.clipboardHistoryManager = historyManager
findViewById<LinearLayout>(R.id.action_bar).apply {
clipboardLayoutParams.setActionBarProperties(this)
}
val params = KeyDrawParams() val params = KeyDrawParams()
params.updateParams(clipboardLayoutParams.actionBarContentHeight, keyVisualAttr) params.updateParams(clipboardLayoutParams.bottomRowKeyboardHeight, keyVisualAttr)
setupAlphabetKey(alphabetKey, switchToAlphaLabel, params)
setupDeleteKey(deleteKey, iconSet.getIconDrawable(KeyboardIconsSet.NAME_DELETE_KEY))
setupClipKey(params) setupClipKey(params)
setupBottomRowKeyboard(editorInfo, keyboardActionListener)
placeholderView.apply { placeholderView.apply {
typeface = params.mTypeface typeface = params.mTypeface
@ -212,27 +178,7 @@ class ClipboardHistoryView @JvmOverloads constructor(
clipboardAdapter.clipboardHistoryManager = null 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) { 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 val tag = view.tag
if (tag is ToolbarKey) { if (tag is ToolbarKey) {
val code = getCodeForToolbarKey(tag) val code = getCodeForToolbarKey(tag)

View file

@ -5,8 +5,8 @@ package helium314.keyboard.keyboard.clipboard
import android.content.res.Resources import android.content.res.Resources
import android.view.View import android.view.View
import android.widget.FrameLayout import android.widget.FrameLayout
import android.widget.LinearLayout
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import helium314.keyboard.keyboard.internal.KeyboardParams
import helium314.keyboard.latin.R import helium314.keyboard.latin.R
import helium314.keyboard.latin.settings.Settings import helium314.keyboard.latin.settings.Settings
import helium314.keyboard.latin.utils.ResourceUtils import helium314.keyboard.latin.utils.ResourceUtils
@ -15,20 +15,15 @@ class ClipboardLayoutParams(res: Resources) {
private val keyVerticalGap: Int private val keyVerticalGap: Int
private val keyHorizontalGap: Int private val keyHorizontalGap: Int
private val topPadding: Int
private val bottomPadding: Int
private val listHeight: Int private val listHeight: Int
private val actionBarHeight: Int val bottomRowKeyboardHeight: Int
companion object {
private const val DEFAULT_KEYBOARD_ROWS = 4
}
init { init {
val defaultKeyboardHeight = ResourceUtils.getKeyboardHeight(res, Settings.getInstance().current) val sv = Settings.getInstance().current
val defaultKeyboardWidth = ResourceUtils.getKeyboardWidth(res, 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, keyVerticalGap = res.getFraction(R.fraction.config_key_vertical_gap_holo_narrow,
defaultKeyboardHeight, defaultKeyboardHeight).toInt() defaultKeyboardHeight, defaultKeyboardHeight).toInt()
keyHorizontalGap = res.getFraction(R.fraction.config_key_horizontal_gap_holo_narrow, 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, keyHorizontalGap = res.getFraction(R.fraction.config_key_horizontal_gap_holo,
defaultKeyboardWidth, defaultKeyboardWidth).toInt() defaultKeyboardWidth, defaultKeyboardWidth).toInt()
} }
bottomPadding = (res.getFraction(R.fraction.config_keyboard_bottom_padding_holo, val bottomPadding = (res.getFraction(R.fraction.config_keyboard_bottom_padding_holo,
defaultKeyboardHeight, defaultKeyboardHeight) * Settings.getInstance().current.mBottomPaddingScale).toInt() defaultKeyboardHeight, defaultKeyboardHeight) * sv.mBottomPaddingScale).toInt()
topPadding = res.getFraction(R.fraction.config_keyboard_top_padding_holo, val topPadding = res.getFraction(R.fraction.config_keyboard_top_padding_holo,
defaultKeyboardHeight, defaultKeyboardHeight).toInt() defaultKeyboardHeight, defaultKeyboardHeight).toInt()
val rowCount = DEFAULT_KEYBOARD_ROWS + if (Settings.getInstance().current.mShowsNumberRow) 1 else 0 val rowCount = KeyboardParams.DEFAULT_KEYBOARD_ROWS + if (sv.mShowsNumberRow) 1 else 0
actionBarHeight = (defaultKeyboardHeight - bottomPadding - topPadding) / rowCount - keyVerticalGap / 2 bottomRowKeyboardHeight = (defaultKeyboardHeight - bottomPadding - topPadding) / rowCount - keyVerticalGap / 2
listHeight = defaultKeyboardHeight - actionBarHeight - bottomPadding // 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) { 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) { fun setItemProperties(view: View) {
(view.layoutParams as RecyclerView.LayoutParams).apply { (view.layoutParams as RecyclerView.LayoutParams).apply {
topMargin = keyHorizontalGap / 2 topMargin = keyHorizontalGap / 2
@ -73,7 +62,4 @@ class ClipboardLayoutParams(res: Resources) {
view.layoutParams = this 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.Context;
import android.content.res.Resources; import android.content.res.Resources;
import android.content.res.TypedArray; import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ImageButton; import android.view.inputmethod.EditorInfo;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import helium314.keyboard.keyboard.Key; import helium314.keyboard.keyboard.Key;
import helium314.keyboard.keyboard.Keyboard;
import helium314.keyboard.keyboard.KeyboardActionListener; import helium314.keyboard.keyboard.KeyboardActionListener;
import helium314.keyboard.keyboard.KeyboardId;
import helium314.keyboard.keyboard.KeyboardLayoutSet; import helium314.keyboard.keyboard.KeyboardLayoutSet;
import helium314.keyboard.keyboard.KeyboardSwitcher; import helium314.keyboard.keyboard.KeyboardSwitcher;
import helium314.keyboard.keyboard.KeyboardView; 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.KeyDrawParams;
import helium314.keyboard.keyboard.internal.KeyVisualAttributes; import helium314.keyboard.keyboard.internal.KeyVisualAttributes;
import helium314.keyboard.keyboard.internal.KeyboardIconsSet;
import helium314.keyboard.keyboard.internal.keyboard_parser.floris.KeyCode; import helium314.keyboard.keyboard.internal.keyboard_parser.floris.KeyCode;
import helium314.keyboard.latin.AudioAndHapticFeedbackManager; import helium314.keyboard.latin.AudioAndHapticFeedbackManager;
import helium314.keyboard.latin.R; import helium314.keyboard.latin.R;
import helium314.keyboard.latin.RichInputMethodSubtype; import helium314.keyboard.latin.RichInputMethodSubtype;
import helium314.keyboard.latin.common.ColorType; import helium314.keyboard.latin.common.ColorType;
import helium314.keyboard.latin.common.Colors; import helium314.keyboard.latin.common.Colors;
import helium314.keyboard.latin.common.Constants;
import helium314.keyboard.latin.settings.Settings; import helium314.keyboard.latin.settings.Settings;
import helium314.keyboard.latin.utils.DeviceProtectedUtils; import helium314.keyboard.latin.utils.DeviceProtectedUtils;
import helium314.keyboard.latin.utils.ResourceUtils; 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}. * Because of the above reasons, this class doesn't extend {@link KeyboardView}.
*/ */
public final class EmojiPalettesView extends LinearLayout public final class EmojiPalettesView extends LinearLayout
implements View.OnClickListener, View.OnTouchListener, OnKeyEventListener { implements View.OnClickListener, OnKeyEventListener {
private boolean initialized = false; private boolean initialized = false;
private final int mFunctionalKeyBackgroundId;
private final Drawable mSpacebarBackground;
// keep the indicator in case emoji view is changed to tabs / viewpager // keep the indicator in case emoji view is changed to tabs / viewpager
private final boolean mCategoryIndicatorEnabled; private final boolean mCategoryIndicatorEnabled;
private final int mCategoryIndicatorDrawableResId; private final int mCategoryIndicatorDrawableResId;
@ -71,14 +67,8 @@ public final class EmojiPalettesView extends LinearLayout
private final Colors mColors; private final Colors mColors;
private EmojiPalettesAdapter mEmojiPalettesAdapter; private EmojiPalettesAdapter mEmojiPalettesAdapter;
private final EmojiLayoutParams mEmojiLayoutParams; private final EmojiLayoutParams mEmojiLayoutParams;
private final DeleteKeyOnTouchListener mDeleteKeyOnTouchListener;
private final LinearLayoutManager mEmojiLayoutManager; private final LinearLayoutManager mEmojiLayoutManager;
private ImageButton mDeleteKey;
private TextView mAlphabetKeyLeft;
private View mSpacebar;
// TODO: Remove this workaround.
private View mSpacebarIcon;
private LinearLayout mTabStrip; private LinearLayout mTabStrip;
private RecyclerView mEmojiRecyclerView; private RecyclerView mEmojiRecyclerView;
private EmojiCategoryPageIndicatorView mEmojiCategoryPageIndicatorView; private EmojiCategoryPageIndicatorView mEmojiCategoryPageIndicatorView;
@ -95,21 +85,13 @@ public final class EmojiPalettesView extends LinearLayout
public EmojiPalettesView(final Context context, final AttributeSet attrs, final int defStyle) { public EmojiPalettesView(final Context context, final AttributeSet attrs, final int defStyle) {
super(context, attrs, 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; 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 KeyboardLayoutSet.Builder builder = new KeyboardLayoutSet.Builder(context, null);
final Resources res = context.getResources(); final Resources res = context.getResources();
mEmojiLayoutParams = new EmojiLayoutParams(res); mEmojiLayoutParams = new EmojiLayoutParams(res);
builder.setSubtype(RichInputMethodSubtype.getEmojiSubtype()); builder.setSubtype(RichInputMethodSubtype.getEmojiSubtype());
builder.setKeyboardGeometry(ResourceUtils.getKeyboardWidth(res, Settings.getInstance().getCurrent()), builder.setKeyboardGeometry(ResourceUtils.getKeyboardWidth(res, Settings.getInstance().getCurrent()),
mEmojiLayoutParams.mEmojiKeyboardHeight); mEmojiLayoutParams.getEmojiKeyboardHeight());
final KeyboardLayoutSet layoutSet = builder.build(); final KeyboardLayoutSet layoutSet = builder.build();
final TypedArray emojiPalettesViewAttr = context.obtainStyledAttributes(attrs, final TypedArray emojiPalettesViewAttr = context.obtainStyledAttributes(attrs,
R.styleable.EmojiPalettesView, defStyle, R.style.EmojiPalettesView); 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 mCategoryPageIndicatorColor = emojiPalettesViewAttr.getColor( // todo: remove this and related attr
R.styleable.EmojiPalettesView_categoryPageIndicatorColor, 0); R.styleable.EmojiPalettesView_categoryPageIndicatorColor, 0);
emojiPalettesViewAttr.recycle(); emojiPalettesViewAttr.recycle();
mDeleteKeyOnTouchListener = new DeleteKeyOnTouchListener();
mEmojiLayoutManager = new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false); mEmojiLayoutManager = new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false);
} }
@ -222,73 +203,10 @@ public final class EmojiPalettesView extends LinearLayout
setCurrentCategoryAndPageId(mEmojiCategory.getCurrentCategoryId(), mEmojiCategory.getCurrentCategoryPageId(), true); 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)); mEmojiCategoryPageIndicatorView.setColors(mColors.get(ColorType.EMOJI_CATEGORY_SELECTED), mColors.get(ColorType.STRIP_BACKGROUND));
initialized = true; 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} * 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 * 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(); 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); setLayerType(LAYER_TYPE_HARDWARE, null);
} }
private static void setupAlphabetKey(final TextView alphabetKey, final String label, public void startEmojiPalettes(final KeyVisualAttributes keyVisualAttr,
final KeyDrawParams params) { final EditorInfo editorInfo, final KeyboardActionListener keyboardActionListener) {
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) {
initialize(); initialize();
mDeleteKey.setImageDrawable(iconSet.getIconDrawable(KeyboardIconsSet.NAME_DELETE_KEY));
mEmojiLayoutParams.setActionBarProperties(findViewById(R.id.action_bar)); setupBottomRowKeyboard(editorInfo, keyboardActionListener);
final KeyDrawParams params = new KeyDrawParams(); final KeyDrawParams params = new KeyDrawParams();
params.updateParams(mEmojiLayoutParams.getActionBarHeight(), keyVisualAttr); params.updateParams(mEmojiLayoutParams.getBottomRowKeyboardHeight(), keyVisualAttr);
setupAlphabetKey(mAlphabetKeyLeft, switchToAlphaLabel, params);
if (mEmojiRecyclerView.getAdapter() == null) { if (mEmojiRecyclerView.getAdapter() == null) {
mEmojiRecyclerView.setAdapter(mEmojiPalettesAdapter); mEmojiRecyclerView.setAdapter(mEmojiPalettesAdapter);
setCurrentCategoryAndPageId(mEmojiCategory.getCurrentCategoryId(), mEmojiCategory.getCurrentCategoryPageId(), true); 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() { public void stopEmojiPalettes() {
if (!initialized) return; if (!initialized) return;
mEmojiPalettesAdapter.releaseCurrentKey(true); mEmojiPalettesAdapter.releaseCurrentKey(true);
@ -382,7 +293,6 @@ public final class EmojiPalettesView extends LinearLayout
public void setKeyboardActionListener(final KeyboardActionListener listener) { public void setKeyboardActionListener(final KeyboardActionListener listener) {
mKeyboardActionListener = listener; mKeyboardActionListener = listener;
mDeleteKeyOnTouchListener.setKeyboardActionListener(listener);
} }
private void updateEmojiCategoryPageIdView() { private void updateEmojiCategoryPageIdView() {
@ -421,53 +331,6 @@ public final class EmojiPalettesView extends LinearLayout
Settings.getInstance().getCurrent().mColors.setColor((ImageView) current, ColorType.EMOJI_CATEGORY_SELECTED); 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() { public void clearKeyboardCache() {
mEmojiCategory.clearKeyboardCache(); mEmojiCategory.clearKeyboardCache();
} }

View file

@ -31,7 +31,7 @@ import java.util.TreeSet;
public class KeyboardParams { public class KeyboardParams {
private static final int DEFAULT_KEYBOARD_COLUMNS = 10; 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 KeyboardId mId;
public int mThemeId; 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.replaceFirst
import helium314.keyboard.latin.utils.splitAt import helium314.keyboard.latin.utils.splitAt
import helium314.keyboard.latin.utils.sumOf import helium314.keyboard.latin.utils.sumOf
import kotlin.math.roundToInt
/** /**
* Abstract parser class that handles creation of keyboard from [KeyData] arranged in rows, * 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 baseKeys = RawKeyboardParser.parseLayout(params, context)
val keysInRows = createRows(baseKeys) val keysInRows = createRows(baseKeys)
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 // rescale height if we have anything but the usual 4 rows
val heightRescale = if (keysInRows.size != 4) 4f / keysInRows.size else 1f heightRescale = if (keysInRows.size != 4) 4f / keysInRows.size else 1f
}
if (heightRescale != 1f) { if (heightRescale != 1f) {
keysInRows.forEach { row -> row.forEach { it.mHeight *= heightRescale } } 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 = "phone"
const val LAYOUT_PHONE_SYMBOLS = "phone_symbols" const val LAYOUT_PHONE_SYMBOLS = "phone_symbols"
const val LAYOUT_NUMBER_ROW = "number_row" 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>>>() private val rawLayoutCache = hashMapOf<String, (KeyboardParams) -> MutableList<MutableList<KeyData>>>()
val symbolAndNumberLayouts = listOf(LAYOUT_SYMBOLS, LAYOUT_SYMBOLS_SHIFTED, LAYOUT_SYMBOLS_ARABIC, 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() fun clearCache() = rawLayoutCache.clear()
@ -137,6 +138,8 @@ object RawKeyboardParser {
KeyboardId.ELEMENT_NUMBER -> LAYOUT_NUMBER KeyboardId.ELEMENT_NUMBER -> LAYOUT_NUMBER
KeyboardId.ELEMENT_PHONE -> LAYOUT_PHONE KeyboardId.ELEMENT_PHONE -> LAYOUT_PHONE
KeyboardId.ELEMENT_PHONE_SYMBOLS -> LAYOUT_PHONE_SYMBOLS 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("+") else -> params.mId.mSubtype.keyboardLayoutSetName.substringBeforeLast("+")
} }

View file

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

View file

@ -24,6 +24,9 @@
android:id="@+id/emoji_category_page_id_view" android:id="@+id/emoji_category_page_id_view"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="2dip" /> 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> </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> <string name="layout_numpad_landscape" tools:keep="@string/layout_numpad_landscape">Numpad (landscape)</string>
<!-- Name for number row layout --> <!-- Name for number row layout -->
<string name="layout_number_row" tools:keep="@string/layout_number_row">Number row</string> <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 --> <!-- Title for customizing background image -->
<string name="customize_background_image">Set background image</string> <string name="customize_background_image">Set background image</string>
<!-- Title for customizing currencies --> <!-- Title for customizing currencies -->