Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace bottom keys in emoji / clipboard view with keyboard #966

Merged
merged 17 commits into from
Sep 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions app/src/main/assets/layouts/clip_bottom_row.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[
[
{ "label": "alpha", "width": 0.15 },
{ "label": "space", "width": -1 },
{ "label": "delete", "width": 0.15 }
]
]
7 changes: 7 additions & 0 deletions app/src/main/assets/layouts/emoji_bottom_row.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[
[
{ "label": "alpha", "width": 0.15 },
{ "label": "space", "width": -1 },
{ "label": "delete", "width": 0.15 }
]
]
6 changes: 6 additions & 0 deletions app/src/main/java/helium314/keyboard/keyboard/KeyboardId.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -191,6 +193,10 @@ public boolean isEmojiKeyboard() {
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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,12 @@
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;
Expand Down Expand Up @@ -210,6 +213,18 @@ public Builder(final Context context, @Nullable final EditorInfo ei) {
}
}

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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,7 @@ private void setMainKeyboardFrame(
@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
Expand Down Expand Up @@ -332,9 +333,8 @@ public void setEmojiKeyboard() {
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);
}

Expand All @@ -355,10 +355,8 @@ public void setClipboardKeyboard() {
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);
}

Expand Down Expand Up @@ -633,6 +631,7 @@ public View onCreateInputView(@NonNull Context displayContext, final boolean isH
if (mKeyboardView != null) {
mKeyboardView.closing();
}
PointerTracker.clearOldViewData();

updateKeyboardThemeAndContextThemeWrapper(displayContext, KeyboardTheme.getKeyboardTheme(displayContext));
mCurrentInputView = (InputView)LayoutInflater.from(mThemeContext).inflate(R.layout.input_view, null);
Expand All @@ -655,6 +654,7 @@ public View onCreateInputView(@NonNull Context displayContext, final boolean isH
mClipboardStripScrollView = mCurrentInputView.findViewById(R.id.clipboard_strip_scroll_view);
mSuggestionStripView = mCurrentInputView.findViewById(R.id.suggestion_strip_view);

PointerTracker.switchTo(mKeyboardView);
return mCurrentInputView;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@

import java.util.ArrayList;
import java.util.Locale;
import java.util.WeakHashMap;

public final class PointerTracker implements PointerTrackerQueue.Element,
BatchInputArbiterListener {
Expand Down Expand Up @@ -73,6 +74,28 @@ public PointerTrackerParams(final TypedArray mainKeyboardViewAttr) {
}
}

// 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.
Expand All @@ -81,7 +104,7 @@ public PointerTrackerParams(final TypedArray mainKeyboardViewAttr) {
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;
Expand Down Expand Up @@ -163,6 +186,16 @@ public static void init(final TypedArray mainKeyboardViewAttr, final TimerProxy

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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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)
}

Expand All @@ -105,25 +100,9 @@ class ClipboardHistoryView @JvmOverloads constructor(
clipboardLayoutParams.setListProperties(this)
placeholderView = [email protected]
}
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)
Expand All @@ -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
Expand All @@ -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?
Expand All @@ -173,25 +143,21 @@ class ClipboardHistoryView @JvmOverloads constructor(

fun startClipboardHistory(
historyManager: ClipboardHistoryManager,
switchToAlphaLabel: String,
keyVisualAttr: KeyVisualAttributes?,
iconSet: KeyboardIconsSet
editorInfo: EditorInfo,
keyboardActionListener: KeyboardActionListener
) {
initialize()
setupToolbarKeys()
historyManager.prepareClipboardHistory()
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
Expand All @@ -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)
Expand Down
Loading