diff --git a/app/src/main/java/be/scri/helpers/KeyboardBase.kt b/app/src/main/java/be/scri/helpers/KeyboardBase.kt
index f5c89fdf..254c684a 100644
--- a/app/src/main/java/be/scri/helpers/KeyboardBase.kt
+++ b/app/src/main/java/be/scri/helpers/KeyboardBase.kt
@@ -660,51 +660,6 @@ class KeyboardBase {
}
}
- if (currentKeyboardMode == keyboardLettersMode && mKeys != null) {
- val spaceKey = mKeys!!.find { it?.code == 32 } ?: return
- val emojiKey = mKeys!!.find { it?.code == KEYCODE_EMOJI } ?: return
- val commaKey = mKeys!!.find { it?.code == ','.code } ?: return
- val periodKey = mKeys!!.find { it?.code == '.'.code }
- val enterKey = mKeys!!.find { it?.code == KEYCODE_ENTER }
- val modeChangeKey = mKeys!!.find { it?.code == KEYCODE_MODE_CHANGE }
-
- val row = mRows.lastOrNull() ?: return
-
- val clipWidth = (mDisplayWidth * 0.10).toInt()
-
- val clipKey = Key(row)
- clipKey.code = KEYCODE_CLIPBOARD
- clipKey.width = clipWidth
- clipKey.height = spaceKey.height
- clipKey.gap = spaceKey.gap
- clipKey.icon = context.resources.getDrawable(R.drawable.ic_clipboard_vector, context.theme)
- clipKey.icon?.setBounds(0, 0, clipKey.icon!!.intrinsicWidth, clipKey.icon!!.intrinsicHeight)
-
- spaceKey.width -= (clipWidth + clipKey.gap)
-
- val emojiIdxInList = mKeys!!.indexOf(emojiKey)
- val emojiIdxInRow = row.mKeys.indexOf(emojiKey)
-
- if (emojiIdxInList != -1 && emojiIdxInRow != -1) {
- modeChangeKey?.let { emojiKey.x = it.x + it.width + it.gap }
-
- clipKey.x = emojiKey.x + emojiKey.width + emojiKey.gap
- clipKey.y = emojiKey.y
-
- commaKey.x = clipKey.x + clipKey.width + clipKey.gap
- commaKey.y = emojiKey.y
-
- spaceKey.x = commaKey.x + commaKey.width + commaKey.gap
- periodKey?.x = spaceKey.x + spaceKey.width + spaceKey.gap
-
- val lastPositionedKey = periodKey ?: spaceKey
- enterKey?.x = lastPositionedKey.x + lastPositionedKey.width + lastPositionedKey.gap
-
- mKeys!!.add(emojiIdxInList + 1, clipKey)
- row.mKeys.add(emojiIdxInRow + 1, clipKey)
- }
- }
-
mHeight = y
}
diff --git a/app/src/main/java/be/scri/views/KeyboardView.kt b/app/src/main/java/be/scri/views/KeyboardView.kt
index 8efcf3f7..4e48a64a 100644
--- a/app/src/main/java/be/scri/views/KeyboardView.kt
+++ b/app/src/main/java/be/scri/views/KeyboardView.kt
@@ -64,6 +64,7 @@ import be.scri.helpers.KeyboardBase.Companion.KEYCODE_TAB
import be.scri.helpers.KeyboardBase.Companion.SHIFT_LOCKED
import be.scri.helpers.KeyboardBase.MyCustomActions
import be.scri.helpers.MAX_KEYS_PER_MINI_ROW
+import be.scri.helpers.PreferencesHelper
import be.scri.helpers.SHIFT_OFF
import be.scri.helpers.SHIFT_ON_ONE_CHAR
import be.scri.helpers.SHIFT_ON_PERMANENT
@@ -1151,12 +1152,41 @@ class KeyboardView
}
// Controls where icons are located on their keys.
- val drawableX = (key.width - key.icon!!.intrinsicWidth) / 2
- val drawableY = (key.height - key.icon!!.intrinsicHeight) / 2
+ var iconWidth = key.icon!!.intrinsicWidth
+ var iconHeight = key.icon!!.intrinsicHeight
+ val isEmojiOrClipboard = code == KeyboardBase.KEYCODE_EMOJI || code == KeyboardBase.KEYCODE_CLIPBOARD
+ val scaleFactor = if (isEmojiOrClipboard) 0.45f else 0.6f
+ val maxIconWidth = (key.width * scaleFactor).toInt()
+ val maxIconHeight = (key.height * scaleFactor).toInt()
+ if (iconWidth > maxIconWidth || iconHeight > maxIconHeight) {
+ val ratio = iconWidth.toFloat() / iconHeight.toFloat()
+ if (ratio > 1) {
+ iconWidth = maxIconWidth
+ iconHeight = (maxIconWidth / ratio).toInt()
+ } else {
+ iconHeight = maxIconHeight
+ iconWidth = (maxIconHeight * ratio).toInt()
+ }
+ }
+ val drawableX = (key.width - iconWidth) / 2
+ val drawableY = (key.height - iconHeight) / 2
canvas.translate(drawableX.toFloat(), drawableY.toFloat())
- key.icon!!.setBounds(0, 0, key.icon!!.intrinsicWidth, key.icon!!.intrinsicHeight)
+ key.icon!!.setBounds(0, 0, iconWidth, iconHeight)
key.icon!!.draw(canvas)
canvas.translate(-drawableX.toFloat(), -drawableY.toFloat())
+
+ if (code == KeyboardBase.KEYCODE_EMOJI) {
+ val settingsIcon = resources.getDrawable(R.drawable.ic_settings_cog_vector, context.theme)
+ settingsIcon.applyColorFilter(mTextColor)
+ val density = context.resources.displayMetrics.density
+ val cogSize = (12 * density).toInt()
+ val rightPadding = keyMargin - shadowOffset + padding + (2 * density).toInt()
+ val topPadding = keyMargin - shadowOffset + padding + (2 * density).toInt()
+ val cogX = key.width - cogSize - rightPadding
+ val cogY = topPadding
+ settingsIcon.setBounds(cogX, cogY, cogX + cogSize, cogY + cogSize)
+ settingsIcon.draw(canvas)
+ }
}
canvas.translate(-key.x.toFloat(), -key.y.toFloat())
}
@@ -1396,6 +1426,16 @@ class KeyboardView
}
private fun openPopupIfRequired(me: MotionEvent): Boolean {
+ val currentKey = if (mCurrentKey in mKeys.indices) mKeys[mCurrentKey] else null
+ if (currentKey?.code == KeyboardBase.KEYCODE_EMOJI) {
+ val result = onLongPress(currentKey, me)
+ if (result) {
+ mAbortKey = true
+ showPreview(NOT_A_KEY)
+ }
+ return result
+ }
+
if (mPopupLayout == 0 || mCurrentKey !in mKeys.indices) {
return false
}
@@ -1410,21 +1450,14 @@ class KeyboardView
return result
}
- /**
- * Called when a key is long pressed.
- * By default this will open any popup keyboard associated with this key through the attributes
- * popupLayout and popupCharacters.
- *
- * @param popupKey The key that was long pressed.
- *
- * @return true if the long press is handled, false otherwise.
- * Subclasses should call the method on the base class if the subclass doesn't wish to
- * handle the call.
- */
private fun onLongPress(
popupKey: KeyboardBase.Key,
me: MotionEvent,
): Boolean {
+ if (popupKey.code == KeyboardBase.KEYCODE_EMOJI) {
+ popupKey.popupResId = R.xml.keys_emoji_popup
+ }
+
val popupKeyboardId = popupKey.popupResId
if (popupKeyboardId != 0) {
mMiniKeyboardContainer = mMiniKeyboardCache[popupKey]
@@ -1517,11 +1550,9 @@ class KeyboardView
mPopupX = popupKey.x
mPopupY = popupKey.y
- val widthToUse =
- mMiniKeyboardContainer!!.measuredWidth -
- (popupKey.popupCharacters!!.length / 2) *
- popupKey.width
- mPopupX = mPopupX + popupKey.width - widthToUse
+ var leftX = popupKey.x + (popupKey.width - mMiniKeyboardContainer!!.measuredWidth) / 2
+ leftX = leftX.coerceIn(0, (width - mMiniKeyboardContainer!!.measuredWidth).coerceAtLeast(0))
+ mPopupX = leftX
mPopupY -= mMiniKeyboardContainer!!.measuredHeight
val x = mPopupX + mCoordinates[0]
val y = mPopupY + mCoordinates[1]
@@ -1544,7 +1575,14 @@ class KeyboardView
}
selectedKeyIndex = Math.max(0, Math.min(selectedKeyIndex, keysCnt - 1))
- if (setHoldForAltCharacters) {
+ val isEmojiPopup = mMiniKeyboard!!.mKeys.any { it.code == KeyboardBase.KEYCODE_EMOJI || it.code == KeyboardBase.KEYCODE_CLIPBOARD }
+ if (isEmojiPopup) {
+ // Emoji popup: start with no pre-selection; user slides to choose and lifts to confirm.
+ for (i in 0 until keysCnt) {
+ mMiniKeyboard!!.mKeys[i].focused = false
+ }
+ mMiniKeyboardSelectedKeyIndex = -1
+ } else if (setHoldForAltCharacters) {
for (i in 0 until keysCnt) {
mMiniKeyboard!!.mKeys[i].focused = i == selectedKeyIndex
}
@@ -1591,6 +1629,7 @@ class KeyboardView
}
if (mPopupKeyboard.isShowing) {
+ val isEmojiPopup = mMiniKeyboard?.mKeys?.any { it.code == KeyboardBase.KEYCODE_EMOJI || it.code == KeyboardBase.KEYCODE_CLIPBOARD } == true
when (action) {
MotionEvent.ACTION_MOVE -> {
val miniKeyboard = mMiniKeyboard
@@ -1601,11 +1640,11 @@ class KeyboardView
miniKeyboard.getGlobalVisibleRect(popupRect)
val widthPerKey = miniKeyboard.width / keysCnt.toFloat()
- var selectedKeyIndex = ((me.x - popupRect.left) / widthPerKey).toInt()
+ var selectedKeyIndex = ((me.rawX - popupRect.left) / widthPerKey).toInt()
selectedKeyIndex = selectedKeyIndex.coerceIn(0, keysCnt - 1)
if (selectedKeyIndex != mMiniKeyboardSelectedKeyIndex) {
- if (setHoldForAltCharacters) {
+ if (setHoldForAltCharacters || isEmojiPopup) {
for (i in 0 until keysCnt) {
miniKeyboard.mKeys[i].focused = i == selectedKeyIndex
}
@@ -1624,35 +1663,54 @@ class KeyboardView
mMiniKeyboardSelectedKeyIndex = selectedKeyIndex
- if (setHoldForAltCharacters) {
- // Hold mode, so use long delay.
- hoverRunnable =
- Runnable {
- val key = miniKeyboard.mKeys[mMiniKeyboardSelectedKeyIndex]
- key.focused = false
- miniKeyboard.invalidateAllKeys()
-
- mOnKeyboardActionListener?.onKey(key.code)
- mMiniKeyboardSelectedKeyIndex = -1
- hoverRunnable = null
- dismissPopupKeyboard()
- }
- hoverHandler?.postDelayed(hoverRunnable!!, hoverDelay)
- } else {
- hoverRunnable =
- Runnable {
- val key = miniKeyboard.mKeys[mMiniKeyboardSelectedKeyIndex]
- key.focused = false
- miniKeyboard.invalidateAllKeys()
-
- mOnKeyboardActionListener?.onKey(key.code)
- mMiniKeyboardSelectedKeyIndex = -1
- hoverRunnable = null
- dismissPopupKeyboard()
- }
- hoverHandler?.postDelayed(hoverRunnable!!, 220L)
+ if (!isEmojiPopup) {
+ // Non-emoji popup: auto-fire after hover delay.
+ if (setHoldForAltCharacters) {
+ hoverRunnable =
+ Runnable {
+ val key = miniKeyboard.mKeys[mMiniKeyboardSelectedKeyIndex]
+ key.focused = false
+ miniKeyboard.invalidateAllKeys()
+
+ mOnKeyboardActionListener?.onKey(key.code)
+ mMiniKeyboardSelectedKeyIndex = -1
+ hoverRunnable = null
+ dismissPopupKeyboard()
+ }
+ hoverHandler?.postDelayed(hoverRunnable!!, hoverDelay)
+ } else {
+ hoverRunnable =
+ Runnable {
+ val key = miniKeyboard.mKeys[mMiniKeyboardSelectedKeyIndex]
+ key.focused = false
+ miniKeyboard.invalidateAllKeys()
+
+ mOnKeyboardActionListener?.onKey(key.code)
+ mMiniKeyboardSelectedKeyIndex = -1
+ hoverRunnable = null
+ dismissPopupKeyboard()
+ }
+ hoverHandler?.postDelayed(hoverRunnable!!, 220L)
+ }
}
+ // Emoji popup: no auto-fire on hover; wait for finger lift (ACTION_UP).
+ }
+ }
+ }
+
+ MotionEvent.ACTION_UP -> {
+ if (isEmojiPopup) {
+ // Fire whichever key is currently highlighted when the finger lifts.
+ val idx = mMiniKeyboardSelectedKeyIndex
+ if (idx >= 0 && idx < (mMiniKeyboard?.mKeys?.size ?: 0)) {
+ val key = mMiniKeyboard!!.mKeys[idx]
+ key.focused = false
+ mMiniKeyboard!!.invalidateAllKeys()
+ mOnKeyboardActionListener?.onKey(key.code)
}
+ mMiniKeyboardSelectedKeyIndex = -1
+ dismissPopupKeyboard()
+ return true
}
}
@@ -1664,7 +1722,7 @@ class KeyboardView
return onModifiedTouchEvent(me)
}
- if (setHoldForAltCharacters) {
+ if (!isEmojiPopup && setHoldForAltCharacters) {
if (mMiniKeyboardSelectedKeyIndex >= 0) {
val key = mMiniKeyboard!!.mKeys[mMiniKeyboardSelectedKeyIndex]
mOnKeyboardActionListener?.onKey(key.code)
diff --git a/app/src/main/res/drawable/ic_settings_cog_vector.xml b/app/src/main/res/drawable/ic_settings_cog_vector.xml
index 3dcc7482..93e74c0d 100644
--- a/app/src/main/res/drawable/ic_settings_cog_vector.xml
+++ b/app/src/main/res/drawable/ic_settings_cog_vector.xml
@@ -1,3 +1,18 @@
-
-
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/emoji_key_long_hold_popup.xml b/app/src/main/res/layout/emoji_key_long_hold_popup.xml
new file mode 100644
index 00000000..fe3fb25e
--- /dev/null
+++ b/app/src/main/res/layout/emoji_key_long_hold_popup.xml
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index f2d1d411..6961a484 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -3,4 +3,7 @@
Scribe
+ Clipboard
+ Floating keyboard
+
diff --git a/app/src/main/res/xml/keys_emoji_popup.xml b/app/src/main/res/xml/keys_emoji_popup.xml
new file mode 100644
index 00000000..e86aaaf2
--- /dev/null
+++ b/app/src/main/res/xml/keys_emoji_popup.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/xml/keys_symbols.xml b/app/src/main/res/xml/keys_symbols.xml
index cb0b62d5..abe85d72 100755
--- a/app/src/main/res/xml/keys_symbols.xml
+++ b/app/src/main/res/xml/keys_symbols.xml
@@ -108,11 +108,11 @@
app:keyLabel="ABC"
app:keyWidth="15%p" />