mirror of
https://github.com/Helium314/HeliBoard.git
synced 2025-06-28 19:59:55 +00:00
Merge branch 'main' into add-broadcast-intent
This commit is contained in:
commit
de0362cd6e
54 changed files with 800 additions and 373 deletions
|
@ -12,13 +12,13 @@ android {
|
|||
applicationId = "helium314.keyboard"
|
||||
minSdk = 21
|
||||
targetSdk = 35
|
||||
versionCode = 3200
|
||||
versionName = "3.2-beta1"
|
||||
versionCode = 3201
|
||||
versionName = "3.2"
|
||||
ndk {
|
||||
abiFilters.clear()
|
||||
abiFilters.addAll(listOf("armeabi-v7a", "arm64-v8a", "x86", "x86_64"))
|
||||
}
|
||||
proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro")
|
||||
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
|
|
|
@ -136,32 +136,6 @@
|
|||
®️
|
||||
™️
|
||||
|
||||
🇦
|
||||
🇧
|
||||
🇨
|
||||
🇩
|
||||
🇪
|
||||
🇫
|
||||
🇬
|
||||
🇭
|
||||
🇮
|
||||
🇯
|
||||
🇰
|
||||
🇱
|
||||
🇲
|
||||
🇳
|
||||
🇴
|
||||
🇵
|
||||
🇶
|
||||
🇷
|
||||
🇸
|
||||
🇹
|
||||
🇺
|
||||
🇻
|
||||
🇼
|
||||
🇽
|
||||
🇾
|
||||
🇿
|
||||
#️⃣
|
||||
*️⃣
|
||||
0️⃣
|
||||
|
@ -247,4 +221,4 @@
|
|||
💠
|
||||
🔘
|
||||
🔳
|
||||
🔲
|
||||
🔲
|
||||
|
|
|
@ -138,7 +138,7 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
|
|||
return false;
|
||||
}
|
||||
|
||||
public void loadKeyboard(final EditorInfo editorInfo, final SettingsValues settingsValues,
|
||||
private void loadKeyboard(final EditorInfo editorInfo, final SettingsValues settingsValues,
|
||||
final int currentAutoCapsState, final int currentRecapitalizeState) {
|
||||
final KeyboardLayoutSet.Builder builder = new KeyboardLayoutSet.Builder(
|
||||
mThemeContext, editorInfo);
|
||||
|
@ -527,6 +527,10 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
|
|||
if (mCurrentInputView == null)
|
||||
return;
|
||||
mEmojiPalettesView.clearKeyboardCache();
|
||||
reloadMainKeyboard();
|
||||
}
|
||||
|
||||
public void reloadMainKeyboard() {
|
||||
loadKeyboard(mLatinIME.getCurrentInputEditorInfo(), Settings.getValues(),
|
||||
mLatinIME.getCurrentAutoCapsState(), mLatinIME.getCurrentRecapitalizeState());
|
||||
}
|
||||
|
|
|
@ -12,15 +12,15 @@ import android.graphics.Canvas;
|
|||
import android.graphics.Paint;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.Gravity;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import helium314.keyboard.accessibility.AccessibilityUtils;
|
||||
import helium314.keyboard.accessibility.PopupKeysKeyboardAccessibilityDelegate;
|
||||
import helium314.keyboard.keyboard.emoji.OnKeyEventListener;
|
||||
import helium314.keyboard.keyboard.emoji.EmojiViewCallback;
|
||||
import helium314.keyboard.keyboard.internal.KeyDrawParams;
|
||||
import helium314.keyboard.keyboard.internal.keyboard_parser.floris.KeyCode;
|
||||
import helium314.keyboard.latin.R;
|
||||
|
@ -39,7 +39,7 @@ public class PopupKeysKeyboardView extends KeyboardView implements PopupKeysPane
|
|||
protected final KeyDetector mKeyDetector;
|
||||
private Controller mController = EMPTY_CONTROLLER;
|
||||
protected KeyboardActionListener mListener;
|
||||
protected OnKeyEventListener mKeyEventListener;
|
||||
protected EmojiViewCallback mEmojiViewCallback;
|
||||
private int mOriginX;
|
||||
private int mOriginY;
|
||||
private Key mCurrentKey;
|
||||
|
@ -122,7 +122,7 @@ public class PopupKeysKeyboardView extends KeyboardView implements PopupKeysPane
|
|||
public void showPopupKeysPanel(final View parentView, final Controller controller,
|
||||
final int pointX, final int pointY, final KeyboardActionListener listener) {
|
||||
mListener = listener;
|
||||
mKeyEventListener = null;
|
||||
mEmojiViewCallback = null;
|
||||
showPopupKeysPanelInternal(parentView, controller, pointX, pointY);
|
||||
}
|
||||
|
||||
|
@ -131,9 +131,9 @@ public class PopupKeysKeyboardView extends KeyboardView implements PopupKeysPane
|
|||
*/
|
||||
@Override
|
||||
public void showPopupKeysPanel(final View parentView, final Controller controller,
|
||||
final int pointX, final int pointY, final OnKeyEventListener listener) {
|
||||
final int pointX, final int pointY, final EmojiViewCallback emojiViewCallback) {
|
||||
mListener = null;
|
||||
mKeyEventListener = listener;
|
||||
mEmojiViewCallback = emojiViewCallback;
|
||||
showPopupKeysPanelInternal(parentView, controller, pointX, pointY);
|
||||
}
|
||||
|
||||
|
@ -157,6 +157,9 @@ public class PopupKeysKeyboardView extends KeyboardView implements PopupKeysPane
|
|||
|
||||
mOriginX = x + container.getPaddingLeft();
|
||||
mOriginY = y + container.getPaddingTop();
|
||||
var center = panelX + getMeasuredWidth() / 2;
|
||||
// This is needed for cases where there's also a long text popup above this keyboard
|
||||
controller.setLayoutGravity(center < pointX? Gravity.RIGHT : center > pointX? Gravity.LEFT : Gravity.CENTER_HORIZONTAL);
|
||||
controller.onShowPopupKeysPanel(this);
|
||||
final PopupKeysKeyboardAccessibilityDelegate accessibilityDelegate = mAccessibilityDelegate;
|
||||
if (accessibilityDelegate != null
|
||||
|
@ -222,8 +225,8 @@ public class PopupKeysKeyboardView extends KeyboardView implements PopupKeysPane
|
|||
false /* isKeyRepeat */);
|
||||
}
|
||||
}
|
||||
} else if (mKeyEventListener != null) {
|
||||
mKeyEventListener.onReleaseKey(key);
|
||||
} else if (mEmojiViewCallback != null) {
|
||||
mEmojiViewCallback.onReleaseKey(key);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -314,28 +317,4 @@ public class PopupKeysKeyboardView extends KeyboardView implements PopupKeysPane
|
|||
}
|
||||
return super.onHoverEvent(event);
|
||||
}
|
||||
|
||||
private View getContainerView() {
|
||||
return (View)getParent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showInParent(final ViewGroup parentView) {
|
||||
removeFromParent();
|
||||
parentView.addView(getContainerView());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeFromParent() {
|
||||
final View containerView = getContainerView();
|
||||
final ViewGroup currentParent = (ViewGroup)containerView.getParent();
|
||||
if (currentParent != null) {
|
||||
currentParent.removeView(containerView);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isShowingInParent() {
|
||||
return (getContainerView().getParent() != null);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,10 +8,17 @@ package helium314.keyboard.keyboard;
|
|||
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import helium314.keyboard.keyboard.emoji.OnKeyEventListener;
|
||||
import helium314.keyboard.keyboard.emoji.EmojiViewCallback;
|
||||
|
||||
public interface PopupKeysPanel {
|
||||
interface Controller {
|
||||
/**
|
||||
* Set the layout gravity.
|
||||
* @param layoutGravity requested by the popup
|
||||
*/
|
||||
default void setLayoutGravity(int layoutGravity) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the {@link PopupKeysPanel} to the target view.
|
||||
* @param panel the panel to be shown.
|
||||
|
@ -59,19 +66,18 @@ public interface PopupKeysPanel {
|
|||
* Initializes the layout and event handling of this {@link PopupKeysPanel} and calls the
|
||||
* controller's onShowPopupKeysPanel to add the panel's container view.
|
||||
* Same as {@link PopupKeysPanel#showPopupKeysPanel(View, Controller, int, int, KeyboardActionListener)},
|
||||
* but with a {@link OnKeyEventListener}.
|
||||
* but with a {@link EmojiViewCallback}.
|
||||
*
|
||||
* @param parentView the parent view of this {@link PopupKeysPanel}
|
||||
* @param controller the controller that can dismiss this {@link PopupKeysPanel}
|
||||
* @param pointX x coordinate of this {@link PopupKeysPanel}
|
||||
* @param pointY y coordinate of this {@link PopupKeysPanel}
|
||||
* @param listener the listener that will receive keyboard action from this
|
||||
* {@link PopupKeysPanel}.
|
||||
* @param emojiViewCallback to receive keyboard actions from this {@link PopupKeysPanel}.
|
||||
*/
|
||||
// TODO: Currently the PopupKeysPanel is inside a container view that is added to the parent.
|
||||
// Consider the simpler approach of placing the PopupKeysPanel itself into the parent view.
|
||||
void showPopupKeysPanel(View parentView, Controller controller, int pointX,
|
||||
int pointY, OnKeyEventListener listener);
|
||||
int pointY, EmojiViewCallback emojiViewCallback);
|
||||
|
||||
/**
|
||||
* Dismisses the popup keys panel and calls the controller's onDismissPopupKeysPanel to remove
|
||||
|
@ -127,20 +133,35 @@ public interface PopupKeysPanel {
|
|||
*/
|
||||
int translateY(int y);
|
||||
|
||||
default View getContainerView() {
|
||||
return (View) ((View) this).getParent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show this {@link PopupKeysPanel} in the parent view.
|
||||
*
|
||||
* @param parentView the {@link ViewGroup} that hosts this {@link PopupKeysPanel}.
|
||||
*/
|
||||
void showInParent(ViewGroup parentView);
|
||||
default void showInParent(ViewGroup parentView) {
|
||||
removeFromParent();
|
||||
parentView.addView(getContainerView());
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove this {@link PopupKeysPanel} from the parent view.
|
||||
*/
|
||||
void removeFromParent();
|
||||
default void removeFromParent() {
|
||||
final View containerView = getContainerView();
|
||||
final ViewGroup currentParent = (ViewGroup)containerView.getParent();
|
||||
if (currentParent != null) {
|
||||
currentParent.removeView(containerView);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the panel is currently being shown.
|
||||
*/
|
||||
boolean isShowingInParent();
|
||||
default boolean isShowingInParent() {
|
||||
return getContainerView().getParent() != null;
|
||||
}
|
||||
}
|
||||
|
|
121
app/src/main/java/helium314/keyboard/keyboard/PopupTextView.java
Normal file
121
app/src/main/java/helium314/keyboard/keyboard/PopupTextView.java
Normal file
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
* modified
|
||||
* SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-only
|
||||
*/
|
||||
|
||||
package helium314.keyboard.keyboard;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Typeface;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.TypedValue;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
import helium314.keyboard.keyboard.emoji.EmojiViewCallback;
|
||||
import helium314.keyboard.keyboard.internal.KeyDrawParams;
|
||||
import helium314.keyboard.latin.R;
|
||||
import helium314.keyboard.latin.common.ColorType;
|
||||
import helium314.keyboard.latin.common.CoordinateUtils;
|
||||
import helium314.keyboard.latin.settings.Settings;
|
||||
|
||||
|
||||
/**
|
||||
* A view that displays popup text.
|
||||
*/
|
||||
public class PopupTextView extends TextView implements PopupKeysPanel {
|
||||
private final int[] mCoordinates = CoordinateUtils.newInstance();
|
||||
private final Typeface mTypeface;
|
||||
private Controller mController = EMPTY_CONTROLLER;
|
||||
private int mOriginX;
|
||||
private int mOriginY;
|
||||
private Key mKey;
|
||||
private EmojiViewCallback mEmojiViewCallback;
|
||||
|
||||
public PopupTextView(final Context context, final AttributeSet attrs) {
|
||||
this(context, attrs, R.attr.popupKeysKeyboardViewStyle);
|
||||
}
|
||||
|
||||
public PopupTextView(final Context context, final AttributeSet attrs,
|
||||
final int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
mTypeface = Settings.getInstance().getCustomTypeface();
|
||||
}
|
||||
|
||||
public void setKeyDrawParams(Key key, KeyDrawParams drawParams) {
|
||||
mKey = key;
|
||||
Settings.getValues().mColors.setBackground(this, ColorType.KEY_PREVIEW_BACKGROUND);
|
||||
setTextColor(drawParams.mPreviewTextColor);
|
||||
setTextSize(TypedValue.COMPLEX_UNIT_PX, key.selectHintTextSize(drawParams) << 1);
|
||||
setTypeface(mTypeface == null ? key.selectTypeface(drawParams) : mTypeface);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showPopupKeysPanel(final View parentView, final Controller controller,
|
||||
final int pointX, final int pointY, final KeyboardActionListener listener) {
|
||||
showPopupKeysPanelInternal(parentView, controller, pointX, pointY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showPopupKeysPanel(final View parentView, final Controller controller,
|
||||
final int pointX, final int pointY, final EmojiViewCallback emojiViewCallback) {
|
||||
mEmojiViewCallback = emojiViewCallback;
|
||||
showPopupKeysPanelInternal(parentView, controller, pointX, pointY);
|
||||
}
|
||||
|
||||
private void showPopupKeysPanelInternal(final View parentView, final Controller controller,
|
||||
final int pointX, final int pointY) {
|
||||
mController = controller;
|
||||
final View container = getContainerView();
|
||||
// The coordinates of panel's left-top corner in parentView's coordinate system.
|
||||
// We need to consider background drawable paddings.
|
||||
final int x = pointX - getMeasuredWidth() / 2 - container.getPaddingLeft() - getPaddingLeft();
|
||||
final int y = pointY - container.getMeasuredHeight() + container.getPaddingBottom()
|
||||
+ getPaddingBottom();
|
||||
|
||||
parentView.getLocationInWindow(mCoordinates);
|
||||
// Ensure the horizontal position of the panel does not extend past the parentView edges.
|
||||
final int maxX = parentView.getMeasuredWidth() - container.getMeasuredWidth();
|
||||
final int panelX = Math.max(0, Math.min(maxX, x)) + CoordinateUtils.x(mCoordinates);
|
||||
final int panelY = y + CoordinateUtils.y(mCoordinates);
|
||||
container.setX(panelX);
|
||||
container.setY(panelY);
|
||||
|
||||
mOriginX = x + container.getPaddingLeft();
|
||||
mOriginY = y + container.getPaddingTop();
|
||||
controller.setLayoutGravity(Gravity.NO_GRAVITY);
|
||||
controller.onShowPopupKeysPanel(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDownEvent(final int x, final int y, final int pointerId, final long eventTime) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMoveEvent(final int x, final int y, final int pointerId, final long eventTime) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpEvent(final int x, final int y, final int pointerId, final long eventTime) {
|
||||
mEmojiViewCallback.onReleaseKey(mKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dismissPopupKeysPanel() {
|
||||
if (!isShowingInParent()) {
|
||||
return;
|
||||
}
|
||||
mController.onDismissPopupKeysPanel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int translateX(final int x) {
|
||||
return x - mOriginX;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int translateY(final int y) {
|
||||
return y - mOriginY;
|
||||
}
|
||||
}
|
|
@ -13,6 +13,9 @@ import android.graphics.PorterDuff;
|
|||
import android.graphics.PorterDuffXfermode;
|
||||
import android.os.Handler;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.Gravity;
|
||||
import android.widget.LinearLayout;
|
||||
import helium314.keyboard.keyboard.PopupTextView;
|
||||
import helium314.keyboard.latin.utils.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
|
@ -53,14 +56,18 @@ public final class EmojiPageKeyboardView extends KeyboardView implements
|
|||
private static final long KEY_PRESS_DELAY_TIME = 250; // msec
|
||||
private static final long KEY_RELEASE_DELAY_TIME = 30; // msec
|
||||
|
||||
private static final OnKeyEventListener EMPTY_LISTENER = new OnKeyEventListener() {
|
||||
private static final EmojiViewCallback EMPTY_EMOJI_VIEW_CALLBACK = new EmojiViewCallback() {
|
||||
@Override
|
||||
public void onPressKey(final Key key) {}
|
||||
@Override
|
||||
public void onReleaseKey(final Key key) {}
|
||||
@Override
|
||||
public String getDescription(String emoji) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
private OnKeyEventListener mListener = EMPTY_LISTENER;
|
||||
private EmojiViewCallback mEmojiViewCallback = EMPTY_EMOJI_VIEW_CALLBACK;
|
||||
private final KeyDetector mKeyDetector = new KeyDetector();
|
||||
private KeyboardAccessibilityDelegate<EmojiPageKeyboardView> mAccessibilityDelegate;
|
||||
|
||||
|
@ -74,6 +81,8 @@ public final class EmojiPageKeyboardView extends KeyboardView implements
|
|||
|
||||
// More keys keyboard
|
||||
private final View mPopupKeysKeyboardContainer;
|
||||
private final PopupTextView mDescriptionView;
|
||||
private final PopupKeysKeyboardView mPopupKeysKeyboardView;
|
||||
private final WeakHashMap<Key, Keyboard> mPopupKeysKeyboardCache = new WeakHashMap<>();
|
||||
private final boolean mConfigShowPopupKeysKeyboardAtTouchedPoint;
|
||||
private final ViewGroup mPopupKeysPlacerView;
|
||||
|
@ -102,6 +111,8 @@ public final class EmojiPageKeyboardView extends KeyboardView implements
|
|||
|
||||
final LayoutInflater inflater = LayoutInflater.from(getContext());
|
||||
mPopupKeysKeyboardContainer = inflater.inflate(popupKeysKeyboardLayoutId, null);
|
||||
mDescriptionView = mPopupKeysKeyboardContainer.findViewById(R.id.description_view);
|
||||
mPopupKeysKeyboardView = mPopupKeysKeyboardContainer.findViewById(R.id.popup_keys_keyboard_view);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -146,8 +157,8 @@ public final class EmojiPageKeyboardView extends KeyboardView implements
|
|||
}
|
||||
}
|
||||
|
||||
public void setOnKeyEventListener(final OnKeyEventListener listener) {
|
||||
mListener = listener;
|
||||
public void setEmojiViewCallback(final EmojiViewCallback emojiViewCallback) {
|
||||
mEmojiViewCallback = emojiViewCallback;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -169,7 +180,8 @@ public final class EmojiPageKeyboardView extends KeyboardView implements
|
|||
}
|
||||
|
||||
@Nullable
|
||||
public PopupKeysPanel showPopupKeysKeyboard(@NonNull final Key key, final int lastX, final int lastY) {
|
||||
private PopupKeysPanel showPopupKeysKeyboard(@NonNull final Key key) {
|
||||
mPopupKeysKeyboardView.setVisibility(GONE);
|
||||
final PopupKeySpec[] popupKeys = key.getPopupKeys();
|
||||
if (popupKeys == null) {
|
||||
return null;
|
||||
|
@ -182,21 +194,9 @@ public final class EmojiPageKeyboardView extends KeyboardView implements
|
|||
mPopupKeysKeyboardCache.put(key, popupKeysKeyboard);
|
||||
}
|
||||
|
||||
final View container = mPopupKeysKeyboardContainer;
|
||||
final PopupKeysKeyboardView popupKeysKeyboardView = container.findViewById(R.id.popup_keys_keyboard_view);
|
||||
popupKeysKeyboardView.setKeyboard(popupKeysKeyboard);
|
||||
container.measure(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
|
||||
final int[] lastCoords = CoordinateUtils.newCoordinateArray(1, lastX, lastY);
|
||||
// The popup keys keyboard is usually horizontally aligned with the center of the parent key.
|
||||
// If showPopupKeysKeyboardAtTouchedPoint is true and the key preview is disabled, the more
|
||||
// keys keyboard is placed at the touch point of the parent key.
|
||||
final int pointX = mConfigShowPopupKeysKeyboardAtTouchedPoint
|
||||
? CoordinateUtils.x(lastCoords)
|
||||
: key.getX() + key.getWidth() / 2;
|
||||
final int pointY = key.getY();
|
||||
popupKeysKeyboardView.showPopupKeysPanel(this, this, pointX, pointY, mListener);
|
||||
return popupKeysKeyboardView;
|
||||
mPopupKeysKeyboardView.setKeyboard(popupKeysKeyboard);
|
||||
mPopupKeysKeyboardView.setVisibility(VISIBLE);
|
||||
return mPopupKeysKeyboardView;
|
||||
}
|
||||
|
||||
private void dismissPopupKeysPanel() {
|
||||
|
@ -209,6 +209,17 @@ public final class EmojiPageKeyboardView extends KeyboardView implements
|
|||
return mPopupKeysPanel != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLayoutGravity(int layoutGravity) {
|
||||
var layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
layoutParams.gravity = mDescriptionView.getMeasuredWidth() > mPopupKeysKeyboardView.getMeasuredWidth()?
|
||||
layoutGravity : Gravity.CENTER_HORIZONTAL;
|
||||
mPopupKeysKeyboardContainer.setLayoutParams(layoutParams);
|
||||
mDescriptionView.setLayoutParams(layoutParams);
|
||||
mPopupKeysKeyboardView.setLayoutParams(layoutParams);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onShowPopupKeysPanel(final PopupKeysPanel panel) {
|
||||
// install placer view only when needed instead of when this
|
||||
|
@ -290,9 +301,11 @@ public final class EmojiPageKeyboardView extends KeyboardView implements
|
|||
return;
|
||||
}
|
||||
|
||||
var descriptionPanel = showDescription(key);
|
||||
final PopupKeysPanel popupKeysPanel = showPopupKeysKeyboard(key);
|
||||
|
||||
final int x = mLastX;
|
||||
final int y = mLastY;
|
||||
final PopupKeysPanel popupKeysPanel = showPopupKeysKeyboard(key, x, y);
|
||||
if (popupKeysPanel != null) {
|
||||
final int translatedX = popupKeysPanel.translateX(x);
|
||||
final int translatedY = popupKeysPanel.translateY(y);
|
||||
|
@ -301,6 +314,34 @@ public final class EmojiPageKeyboardView extends KeyboardView implements
|
|||
// want any scroll to append during this entire input.
|
||||
disallowParentInterceptTouchEvent(true);
|
||||
}
|
||||
|
||||
if (popupKeysPanel != null || descriptionPanel != null) {
|
||||
mPopupKeysKeyboardContainer.measure(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
|
||||
final int[] lastCoords = CoordinateUtils.newCoordinateArray(1, x, y);
|
||||
// The popup keys keyboard is usually horizontally aligned with the center of the parent key.
|
||||
// If showPopupKeysKeyboardAtTouchedPoint is true and the key preview is disabled, the more
|
||||
// keys keyboard is placed at the touch point of the parent key.
|
||||
final int pointX = mConfigShowPopupKeysKeyboardAtTouchedPoint
|
||||
? CoordinateUtils.x(lastCoords)
|
||||
: key.getX() + key.getWidth() / 2;
|
||||
final int pointY = key.getY() - getKeyboard().mVerticalGap;
|
||||
(popupKeysPanel != null? popupKeysPanel : descriptionPanel)
|
||||
.showPopupKeysPanel(this, this, pointX, pointY, mEmojiViewCallback);
|
||||
}
|
||||
}
|
||||
|
||||
private PopupKeysPanel showDescription(Key key) {
|
||||
mDescriptionView.setVisibility(GONE);
|
||||
var description = mEmojiViewCallback.getDescription(key.getLabel());
|
||||
if (description == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
mDescriptionView.setText(description);
|
||||
mDescriptionView.setKeyDrawParams(key, getKeyDrawParams());
|
||||
mDescriptionView.setVisibility(VISIBLE);
|
||||
return mDescriptionView;
|
||||
}
|
||||
|
||||
private void registerPress(final Key key) {
|
||||
|
@ -318,7 +359,7 @@ public final class EmojiPageKeyboardView extends KeyboardView implements
|
|||
releasedKey.onReleased();
|
||||
invalidateKey(releasedKey);
|
||||
if (withKeyRegistering) {
|
||||
mListener.onReleaseKey(releasedKey);
|
||||
mEmojiViewCallback.onReleaseKey(releasedKey);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -326,7 +367,7 @@ public final class EmojiPageKeyboardView extends KeyboardView implements
|
|||
mPendingKeyDown = null;
|
||||
pressedKey.onPressed();
|
||||
invalidateKey(pressedKey);
|
||||
mListener.onPressKey(pressedKey);
|
||||
mEmojiViewCallback.onPressKey(pressedKey);
|
||||
}
|
||||
|
||||
public void releaseCurrentKey(final boolean withKeyRegistering) {
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
package helium314.keyboard.keyboard.emoji;
|
||||
|
||||
import helium314.keyboard.latin.utils.Log;
|
||||
import android.util.SparseArray;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
@ -23,13 +22,13 @@ final class EmojiPalettesAdapter extends RecyclerView.Adapter<EmojiPalettesAdapt
|
|||
private static final boolean DEBUG_PAGER = false;
|
||||
|
||||
private final int mCategoryId;
|
||||
private final OnKeyEventListener mListener;
|
||||
private final EmojiViewCallback mEmojiViewCallback;
|
||||
private final EmojiCategory mEmojiCategory;
|
||||
|
||||
public EmojiPalettesAdapter(final EmojiCategory emojiCategory, int categoryId, final OnKeyEventListener listener) {
|
||||
public EmojiPalettesAdapter(final EmojiCategory emojiCategory, int categoryId, final EmojiViewCallback emojiViewCallback) {
|
||||
mEmojiCategory = emojiCategory;
|
||||
mCategoryId = categoryId;
|
||||
mListener = listener;
|
||||
mEmojiViewCallback = emojiViewCallback;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
|
@ -38,6 +37,7 @@ final class EmojiPalettesAdapter extends RecyclerView.Adapter<EmojiPalettesAdapt
|
|||
final LayoutInflater inflater = LayoutInflater.from(parent.getContext());
|
||||
final EmojiPageKeyboardView keyboardView = (EmojiPageKeyboardView)inflater.inflate(
|
||||
R.layout.emoji_keyboard_page, parent, false);
|
||||
keyboardView.setEmojiViewCallback(mEmojiViewCallback);
|
||||
return new ViewHolder(keyboardView);
|
||||
}
|
||||
|
||||
|
@ -50,7 +50,6 @@ final class EmojiPalettesAdapter extends RecyclerView.Adapter<EmojiPalettesAdapt
|
|||
final Keyboard keyboard =
|
||||
mEmojiCategory.getKeyboardFromAdapterPosition(mCategoryId, position);
|
||||
holder.getKeyboardView().setKeyboard(keyboard);
|
||||
holder.getKeyboardView().setOnKeyEventListener(mListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -38,12 +38,16 @@ import helium314.keyboard.keyboard.internal.KeyDrawParams;
|
|||
import helium314.keyboard.keyboard.internal.KeyVisualAttributes;
|
||||
import helium314.keyboard.keyboard.internal.keyboard_parser.floris.KeyCode;
|
||||
import helium314.keyboard.latin.AudioAndHapticFeedbackManager;
|
||||
import helium314.keyboard.latin.DictionaryFactory;
|
||||
import helium314.keyboard.latin.R;
|
||||
import helium314.keyboard.latin.RichInputMethodManager;
|
||||
import helium314.keyboard.latin.RichInputMethodSubtype;
|
||||
import helium314.keyboard.latin.SingleDictionaryFacilitator;
|
||||
import helium314.keyboard.latin.common.ColorType;
|
||||
import helium314.keyboard.latin.common.Colors;
|
||||
import helium314.keyboard.latin.settings.Settings;
|
||||
import helium314.keyboard.latin.settings.SettingsValues;
|
||||
import helium314.keyboard.latin.utils.DictionaryInfoUtils;
|
||||
import helium314.keyboard.latin.utils.ResourceUtils;
|
||||
|
||||
import static helium314.keyboard.latin.common.Constants.NOT_A_COORDINATE;
|
||||
|
@ -60,7 +64,7 @@ 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, OnKeyEventListener {
|
||||
implements View.OnClickListener, EmojiViewCallback {
|
||||
private static final class PagerViewHolder extends RecyclerView.ViewHolder {
|
||||
private long mCategoryId;
|
||||
|
||||
|
@ -71,7 +75,7 @@ public final class EmojiPalettesView extends LinearLayout
|
|||
|
||||
private final class PagerAdapter extends RecyclerView.Adapter<PagerViewHolder> {
|
||||
private boolean mInitialized;
|
||||
private Map<Integer, RecyclerView> mViews = new HashMap<>(mEmojiCategory.getShownCategories().size());
|
||||
private final Map<Integer, RecyclerView> mViews = new HashMap<>(mEmojiCategory.getShownCategories().size());
|
||||
|
||||
private PagerAdapter(ViewPager2 pager) {
|
||||
setHasStableIds(true);
|
||||
|
@ -179,15 +183,14 @@ public final class EmojiPalettesView extends LinearLayout
|
|||
}
|
||||
}
|
||||
|
||||
private static SingleDictionaryFacilitator sDictionaryFacilitator;
|
||||
|
||||
private boolean initialized = false;
|
||||
private final Colors mColors;
|
||||
private final EmojiLayoutParams mEmojiLayoutParams;
|
||||
|
||||
private LinearLayout mTabStrip;
|
||||
private EmojiCategoryPageIndicatorView mEmojiCategoryPageIndicatorView;
|
||||
|
||||
private KeyboardActionListener mKeyboardActionListener = KeyboardActionListener.EMPTY_LISTENER;
|
||||
|
||||
private final EmojiCategory mEmojiCategory;
|
||||
private ViewPager2 mPager;
|
||||
|
||||
|
@ -254,9 +257,7 @@ public final class EmojiPalettesView extends LinearLayout
|
|||
mEmojiLayoutParams.setEmojiListProperties(mPager);
|
||||
mEmojiCategoryPageIndicatorView = findViewById(R.id.emoji_category_page_id_view);
|
||||
mEmojiLayoutParams.setCategoryPageIdViewProperties(mEmojiCategoryPageIndicatorView);
|
||||
|
||||
setCurrentCategoryId(mEmojiCategory.getCurrentCategoryId(), true);
|
||||
|
||||
mEmojiCategoryPageIndicatorView.setColors(mColors.get(ColorType.EMOJI_CATEGORY_SELECTED), mColors.get(ColorType.STRIP_BACKGROUND));
|
||||
initialized = true;
|
||||
}
|
||||
|
@ -280,8 +281,7 @@ public final class EmojiPalettesView extends LinearLayout
|
|||
}
|
||||
|
||||
/**
|
||||
* Called from {@link EmojiPageKeyboardView} through
|
||||
* {@link helium314.keyboard.keyboard.emoji.OnKeyEventListener}
|
||||
* Called from {@link EmojiPageKeyboardView} through {@link EmojiViewCallback}
|
||||
* interface to handle touch events from non-View-based elements such as Emoji buttons.
|
||||
*/
|
||||
@Override
|
||||
|
@ -291,10 +291,9 @@ public final class EmojiPalettesView extends LinearLayout
|
|||
}
|
||||
|
||||
/**
|
||||
* Called from {@link EmojiPageKeyboardView} through
|
||||
* {@link helium314.keyboard.keyboard.emoji.OnKeyEventListener}
|
||||
* Called from {@link EmojiPageKeyboardView} through {@link EmojiViewCallback}
|
||||
* interface to handle touch events from non-View-based elements such as Emoji buttons.
|
||||
* This may be called without any prior call to {@link OnKeyEventListener#onPressKey(Key)}.
|
||||
* This may be called without any prior call to {@link EmojiViewCallback#onPressKey(Key)}.
|
||||
*/
|
||||
@Override
|
||||
public void onReleaseKey(final Key key) {
|
||||
|
@ -310,6 +309,20 @@ public final class EmojiPalettesView extends LinearLayout
|
|||
mKeyboardActionListener.onCodeInput(KeyCode.ALPHA, NOT_A_COORDINATE, NOT_A_COORDINATE, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription(String emoji) {
|
||||
if (sDictionaryFacilitator == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var wordProperty = sDictionaryFacilitator.getWordProperty(emoji);
|
||||
if (wordProperty == null || ! wordProperty.mHasShortcuts) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return wordProperty.mShortcutTargets.get(0).mWord;
|
||||
}
|
||||
|
||||
public void setHardwareAcceleratedDrawingEnabled(final boolean enabled) {
|
||||
if (!enabled) return;
|
||||
// TODO: Should use LAYER_TYPE_SOFTWARE when hardware acceleration is off?
|
||||
|
@ -324,6 +337,7 @@ public final class EmojiPalettesView extends LinearLayout
|
|||
final KeyDrawParams params = new KeyDrawParams();
|
||||
params.updateParams(mEmojiLayoutParams.getBottomRowKeyboardHeight(), keyVisualAttr);
|
||||
setupSidePadding();
|
||||
initDictionaryFacilitator();
|
||||
}
|
||||
|
||||
private void addRecentKey(final Key key) {
|
||||
|
@ -403,7 +417,7 @@ public final class EmojiPalettesView extends LinearLayout
|
|||
if (mPager.getScrollState() != ViewPager2.SCROLL_STATE_DRAGGING) {
|
||||
// Not swiping
|
||||
mPager.setCurrentItem(mEmojiCategory.getTabIdFromCategoryId(
|
||||
mEmojiCategory.getCurrentCategoryId()), ! initial);
|
||||
mEmojiCategory.getCurrentCategoryId()), ! initial && ! isAnimationsDisabled());
|
||||
}
|
||||
|
||||
if (Settings.getValues().mSecondaryStripVisible) {
|
||||
|
@ -418,6 +432,11 @@ public final class EmojiPalettesView extends LinearLayout
|
|||
}
|
||||
}
|
||||
|
||||
private boolean isAnimationsDisabled() {
|
||||
return android.provider.Settings.Global.getFloat(getContext().getContentResolver(),
|
||||
android.provider.Settings.Global.ANIMATOR_DURATION_SCALE, 1.0f) == 0.0f;
|
||||
}
|
||||
|
||||
public void clearKeyboardCache() {
|
||||
if (!initialized) {
|
||||
return;
|
||||
|
@ -425,5 +444,27 @@ public final class EmojiPalettesView extends LinearLayout
|
|||
|
||||
mEmojiCategory.clearKeyboardCache();
|
||||
mPager.getAdapter().notifyDataSetChanged();
|
||||
closeDictionaryFacilitator();
|
||||
}
|
||||
|
||||
private void initDictionaryFacilitator() {
|
||||
if (Settings.getValues().mShowEmojiDescriptions) {
|
||||
var locale = RichInputMethodManager.getInstance().getCurrentSubtype().getLocale();
|
||||
if (sDictionaryFacilitator == null || ! sDictionaryFacilitator.isForLocale(locale)) {
|
||||
closeDictionaryFacilitator();
|
||||
var dictFile = DictionaryInfoUtils.getCachedDictForLocaleAndType(locale, "emoji", getContext());
|
||||
var dictionary = dictFile != null? DictionaryFactory.getDictionary(dictFile, locale) : null;
|
||||
sDictionaryFacilitator = dictionary != null? new SingleDictionaryFacilitator(dictionary) : null;
|
||||
}
|
||||
} else {
|
||||
closeDictionaryFacilitator();
|
||||
}
|
||||
}
|
||||
|
||||
private static void closeDictionaryFacilitator() {
|
||||
if (sDictionaryFacilitator != null) {
|
||||
sDictionaryFacilitator.closeDictionaries();
|
||||
sDictionaryFacilitator = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,10 +5,10 @@ package helium314.keyboard.keyboard.emoji;
|
|||
import helium314.keyboard.keyboard.Key;
|
||||
|
||||
/**
|
||||
* Interface to handle touch events from non-View-based elements
|
||||
* such as Emoji buttons.
|
||||
* Interface to handle callbacks from child elements
|
||||
* such as Emoji buttons and keyboard views.
|
||||
*/
|
||||
public interface OnKeyEventListener {
|
||||
public interface EmojiViewCallback {
|
||||
|
||||
/**
|
||||
* Called when a key is pressed by the user
|
||||
|
@ -17,8 +17,13 @@ public interface OnKeyEventListener {
|
|||
|
||||
/**
|
||||
* Called when a key is released.
|
||||
* This may be called without any prior call to {@link OnKeyEventListener#onPressKey(Key)},
|
||||
* This may be called without any prior call to {@link EmojiViewCallback#onPressKey(Key)},
|
||||
* for example when a key from a popup keys keyboard is selected by releasing touch on it.
|
||||
*/
|
||||
void onReleaseKey(Key key);
|
||||
|
||||
/**
|
||||
* Called from keyboard view to get an emoji description
|
||||
*/
|
||||
String getDescription(String emoji);
|
||||
}
|
|
@ -229,13 +229,15 @@ class KeyboardParser(private val params: KeyboardParams, private val context: Co
|
|||
return
|
||||
// replace comma / period if 2 keys in normal bottom row
|
||||
if (baseKeys.last().size == 2) {
|
||||
val newComma = baseKeys.last()[0]
|
||||
functionalKeysBottom.replaceFirst(
|
||||
{ it.label == KeyLabel.COMMA || it.groupId == KeyData.GROUP_COMMA},
|
||||
{ baseKeys.last()[0].copy(newGroupId = 1, newType = baseKeys.last()[0].type ?: it.type) }
|
||||
{ newComma.copy(newGroupId = 1, newType = newComma.type, newLabelFlags = it.labelFlags or newComma.labelFlags) }
|
||||
)
|
||||
val newPeriod = baseKeys.last()[1]
|
||||
functionalKeysBottom.replaceFirst(
|
||||
{ it.label == KeyLabel.PERIOD || it.groupId == KeyData.GROUP_PERIOD},
|
||||
{ baseKeys.last()[1].copy(newGroupId = 2, newType = baseKeys.last()[1].type ?: it.type) }
|
||||
{ newPeriod.copy(newGroupId = 2, newType = newPeriod.type, newLabelFlags = it.labelFlags or newPeriod.labelFlags) }
|
||||
)
|
||||
baseKeys.removeAt(baseKeys.lastIndex)
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ class LocaleKeyboardInfos(dataStream: InputStream?, locale: Locale) {
|
|||
"mns" -> Key.LABEL_FLAGS_FOLLOW_KEY_LETTER_RATIO
|
||||
else -> 0
|
||||
}
|
||||
val tlds = getLocaleTlds(locale)
|
||||
val tlds = mutableListOf<String>()
|
||||
|
||||
init {
|
||||
readStream(dataStream, false, true)
|
||||
|
@ -84,7 +84,7 @@ class LocaleKeyboardInfos(dataStream: InputStream?, locale: Locale) {
|
|||
READER_MODE_EXTRA_KEYS -> if (!onlyPopupKeys) addExtraKey(line.split(colonSpaceRegex, 2))
|
||||
READER_MODE_LABELS -> if (!onlyPopupKeys) addLabel(line.split(colonSpaceRegex, 2))
|
||||
READER_MODE_NUMBER_ROW -> localizedNumberKeys = line.splitOnWhitespace()
|
||||
READER_MODE_TLD -> SpacedTokens(line).forEach { tlds.add(".$it") }
|
||||
READER_MODE_TLD -> tlds.addAll(SpacedTokens(line).map { ".$it" })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -156,6 +156,16 @@ class LocaleKeyboardInfos(dataStream: InputStream?, locale: Locale) {
|
|||
}
|
||||
}
|
||||
|
||||
fun addLocaleTlds(locale: Locale) {
|
||||
tlds.add(0, comTld)
|
||||
val ccLower = locale.country.lowercase()
|
||||
if (ccLower.isNotEmpty() && locale.language != SubtypeLocaleUtils.NO_LANGUAGE) {
|
||||
specialCountryTlds[ccLower]?.let { tlds.addAll(SpacedTokens(it)) } ?: tlds.add(".$ccLower")
|
||||
}
|
||||
if ((locale.language != "en" && euroLocales.matches(locale.language)) || euroCountries.matches(locale.country))
|
||||
tlds.add(".eu")
|
||||
tlds.addAll(SpacedTokens(otherDefaultTlds))
|
||||
}
|
||||
}
|
||||
|
||||
private fun addFixedColumnOrder(popupKeys: MutableCollection<String>) {
|
||||
|
@ -205,6 +215,7 @@ private fun createLocaleKeyTexts(context: Context, params: KeyboardParams, popup
|
|||
POPUP_KEYS_MORE -> lkt.addFile(context.assets.open("$LOCALE_TEXTS_FOLDER/more_popups_more.txt"), false)
|
||||
POPUP_KEYS_ALL -> lkt.addFile(context.assets.open("$LOCALE_TEXTS_FOLDER/more_popups_all.txt"), false)
|
||||
}
|
||||
lkt.addLocaleTlds(params.mId.locale)
|
||||
return lkt
|
||||
}
|
||||
|
||||
|
@ -220,28 +231,6 @@ private fun getStreamForLocale(locale: Locale, context: Context) =
|
|||
}
|
||||
}
|
||||
|
||||
private fun getLocaleTlds(locale: Locale): LinkedHashSet<String> {
|
||||
val tlds = getDefaultTlds(locale)
|
||||
val ccLower = locale.country.lowercase()
|
||||
if (ccLower.isEmpty() || locale.language == SubtypeLocaleUtils.NO_LANGUAGE)
|
||||
return tlds
|
||||
specialCountryTlds.forEach {
|
||||
if (ccLower != it.first) return@forEach
|
||||
tlds.addAll(SpacedTokens(it.second))
|
||||
return@getLocaleTlds tlds
|
||||
}
|
||||
tlds.add(".$ccLower")
|
||||
return tlds
|
||||
}
|
||||
|
||||
private fun getDefaultTlds(locale: Locale): LinkedHashSet<String> {
|
||||
val tlds = linkedSetOf<String>()
|
||||
tlds.addAll(SpacedTokens(defaultTlds))
|
||||
if ((locale.language != "en" && euroLocales.matches(locale.language)) || euroCountries.matches(locale.country))
|
||||
tlds.add(".eu")
|
||||
return tlds
|
||||
}
|
||||
|
||||
fun clearCache() = localeKeyboardInfosCache.clear()
|
||||
|
||||
// cache the texts, so they don't need to be read over and over
|
||||
|
@ -341,7 +330,7 @@ const val POPUP_KEYS_NORMAL = "normal"
|
|||
private const val LOCALE_TEXTS_FOLDER = "locale_key_texts"
|
||||
|
||||
// either tld is not simply lowercase ISO 3166-1 code, or there are multiple according to some list
|
||||
private val specialCountryTlds = listOf(
|
||||
private val specialCountryTlds = hashMapOf<String, String>(
|
||||
"bd" to ".bd .com.bd",
|
||||
"bq" to ".bq .an .nl",
|
||||
"bl" to ".bl .gp .fr",
|
||||
|
@ -351,4 +340,5 @@ private val specialCountryTlds = listOf(
|
|||
"mf" to ".mf .gp .fr",
|
||||
"tl" to ".tl .tp",
|
||||
)
|
||||
private const val defaultTlds = ".com .gov .edu .org .net"
|
||||
private const val comTld = ".com"
|
||||
private const val otherDefaultTlds = ".gov .edu .org .net"
|
||||
|
|
|
@ -83,7 +83,7 @@ object KeyCode {
|
|||
const val LANGUAGE_SWITCH = -227
|
||||
|
||||
//const val IME_SHOW_UI = -231
|
||||
//const val IME_HIDE_UI = -232
|
||||
const val IME_HIDE_UI = -232
|
||||
const val VOICE_INPUT = -233
|
||||
|
||||
//const val TOGGLE_SMARTBAR_VISIBILITY = -241
|
||||
|
@ -187,7 +187,7 @@ object KeyCode {
|
|||
REDO, ARROW_DOWN, ARROW_UP, ARROW_RIGHT, ARROW_LEFT, CLIPBOARD_COPY, CLIPBOARD_PASTE, CLIPBOARD_SELECT_ALL,
|
||||
CLIPBOARD_SELECT_WORD, TOGGLE_INCOGNITO_MODE, TOGGLE_AUTOCORRECT, MOVE_START_OF_LINE, MOVE_END_OF_LINE,
|
||||
MOVE_START_OF_PAGE, MOVE_END_OF_PAGE, SHIFT, CAPS_LOCK, MULTIPLE_CODE_POINTS, UNSPECIFIED, CTRL, ALT,
|
||||
FN, CLIPBOARD_CLEAR_HISTORY, NUMPAD,
|
||||
FN, CLIPBOARD_CLEAR_HISTORY, NUMPAD, IME_HIDE_UI,
|
||||
|
||||
// heliboard only
|
||||
SYMBOL_ALPHA, TOGGLE_ONE_HANDED_MODE, SWITCH_ONE_HANDED_MODE, SPLIT_LAYOUT, SHIFT_ENTER,
|
||||
|
|
|
@ -11,6 +11,7 @@ import java.util.Locale;
|
|||
|
||||
import helium314.keyboard.latin.SuggestedWords.SuggestedWordInfo;
|
||||
import helium314.keyboard.latin.common.ComposedData;
|
||||
import helium314.keyboard.latin.makedict.WordProperty;
|
||||
import helium314.keyboard.latin.settings.SettingsValuesForSuggestion;
|
||||
|
||||
/**
|
||||
|
@ -177,6 +178,10 @@ public abstract class Dictionary {
|
|||
};
|
||||
}
|
||||
|
||||
public WordProperty getWordProperty(final String word, final boolean isBeginningOfSentence) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Not a true dictionary. A placeholder used to indicate suggestions that don't come from any
|
||||
* real dictionary.
|
||||
|
|
|
@ -381,6 +381,7 @@ class DictionaryFacilitatorImpl : DictionaryFacilitator {
|
|||
}
|
||||
|
||||
private fun addToPersonalDictionaryIfInvalidButInHistory(word: String) {
|
||||
if (word.length <= 1) return
|
||||
val dictionaryGroup = clearlyPreferredDictionaryGroup ?: return
|
||||
val userDict = dictionaryGroup.getSubDict(Dictionary.TYPE_USER) ?: return
|
||||
val userHistoryDict = dictionaryGroup.getSubDict(Dictionary.TYPE_USER_HISTORY) ?: return
|
||||
|
|
|
@ -64,10 +64,26 @@ object DictionaryFactory {
|
|||
* if the dictionary type already exists in [dicts], the [file] is skipped
|
||||
*/
|
||||
private fun checkAndAddDictionaryToListNewType(file: File, dicts: MutableList<Dictionary>, locale: Locale) {
|
||||
if (!file.isFile) return
|
||||
val header = DictionaryInfoUtils.getDictionaryFileHeaderOrNull(file) ?: return killDictionary(file)
|
||||
val dictionary = getDictionary(file, locale) ?: return
|
||||
if (dicts.any { it.mDictType == dictionary.mDictType }) {
|
||||
dictionary.close()
|
||||
return
|
||||
}
|
||||
dicts.add(dictionary)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getDictionary(
|
||||
file: File,
|
||||
locale: Locale
|
||||
): Dictionary? {
|
||||
if (!file.isFile) return null
|
||||
val header = DictionaryInfoUtils.getDictionaryFileHeaderOrNull(file)
|
||||
if (header == null) {
|
||||
killDictionary(file)
|
||||
return null
|
||||
}
|
||||
val dictType = header.mIdString.split(":").first()
|
||||
if (dicts.any { it.mDictType == dictType }) return
|
||||
val readOnlyBinaryDictionary = ReadOnlyBinaryDictionary(
|
||||
file.absolutePath, 0, file.length(), false, locale, dictType
|
||||
)
|
||||
|
@ -75,14 +91,13 @@ object DictionaryFactory {
|
|||
if (readOnlyBinaryDictionary.isValidDictionary) {
|
||||
if (locale.language == "ko") {
|
||||
// Use KoreanDictionary for Korean locale
|
||||
dicts.add(KoreanDictionary(readOnlyBinaryDictionary))
|
||||
} else {
|
||||
dicts.add(readOnlyBinaryDictionary)
|
||||
return KoreanDictionary(readOnlyBinaryDictionary)
|
||||
}
|
||||
} else {
|
||||
readOnlyBinaryDictionary.close()
|
||||
killDictionary(file)
|
||||
return readOnlyBinaryDictionary
|
||||
}
|
||||
readOnlyBinaryDictionary.close()
|
||||
killDictionary(file)
|
||||
return null
|
||||
}
|
||||
|
||||
private fun killDictionary(file: File) {
|
||||
|
|
|
@ -4,6 +4,7 @@ package helium314.keyboard.latin;
|
|||
|
||||
import helium314.keyboard.event.HangulCombiner;
|
||||
import helium314.keyboard.latin.common.ComposedData;
|
||||
import helium314.keyboard.latin.makedict.WordProperty;
|
||||
import helium314.keyboard.latin.settings.SettingsValuesForSuggestion;
|
||||
|
||||
import java.text.Normalizer;
|
||||
|
@ -72,6 +73,11 @@ public class KoreanDictionary extends Dictionary {
|
|||
return mDictionary.getMaxFrequencyOfExactMatches(processInput(word));
|
||||
}
|
||||
|
||||
@Override
|
||||
public WordProperty getWordProperty(String word, boolean isBeginningOfSentence) {
|
||||
return mDictionary.getWordProperty(processInput(word), isBeginningOfSentence);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean same(char[] word, int length, String typedWord) {
|
||||
word = processInput(new String(word)).toCharArray();
|
||||
|
|
|
@ -279,9 +279,7 @@ public class LatinIME extends InputMethodService implements
|
|||
msg.arg2 /* remainingTries */, this /* handler */)) {
|
||||
// If we were able to reset the caches, then we can reload the keyboard.
|
||||
// Otherwise, we'll do it when we can.
|
||||
latinIme.mKeyboardSwitcher.loadKeyboard(latinIme.getCurrentInputEditorInfo(),
|
||||
settingsValues, latinIme.getCurrentAutoCapsState(),
|
||||
latinIme.getCurrentRecapitalizeState());
|
||||
latinIme.mKeyboardSwitcher.reloadMainKeyboard();
|
||||
}
|
||||
break;
|
||||
case MSG_WAIT_FOR_DICTIONARY_LOAD:
|
||||
|
@ -1071,7 +1069,7 @@ public class LatinIME extends InputMethodService implements
|
|||
if (isDifferentTextField) {
|
||||
mainKeyboardView.closing();
|
||||
suggest.setAutoCorrectionThreshold(currentSettingsValues.mAutoCorrectionThreshold);
|
||||
switcher.loadKeyboard(editorInfo, currentSettingsValues, getCurrentAutoCapsState(), getCurrentRecapitalizeState());
|
||||
switcher.reloadMainKeyboard();
|
||||
if (needToCallLoadKeyboardLater) {
|
||||
// If we need to call loadKeyboard again later, we need to save its state now. The
|
||||
// later call will be done in #retryResetCaches.
|
||||
|
@ -1386,6 +1384,10 @@ public class LatinIME extends InputMethodService implements
|
|||
@RequiresApi(api = Build.VERSION_CODES.R)
|
||||
public boolean onInlineSuggestionsResponse(InlineSuggestionsResponse response) {
|
||||
Log.d(TAG,"onInlineSuggestionsResponse called");
|
||||
if (Settings.getValues().mSuggestionStripHiddenPerUserSettings) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final List<InlineSuggestion> inlineSuggestions = response.getInlineSuggestions();
|
||||
if (inlineSuggestions.isEmpty()) {
|
||||
return false;
|
||||
|
@ -1535,9 +1537,10 @@ public class LatinIME extends InputMethodService implements
|
|||
// Implementation of {@link SuggestionStripView.Listener}.
|
||||
@Override
|
||||
public void onCodeInput(final int codePoint, final int x, final int y, final boolean isKeyRepeat) {
|
||||
onCodeInput(codePoint, 0, x, y, isKeyRepeat);
|
||||
mKeyboardActionListener.onCodeInput(codePoint, x, y, isKeyRepeat);
|
||||
}
|
||||
|
||||
// called by KeyboardActionListener
|
||||
public void onCodeInput(final int codePoint, final int metaState, final int x, final int y, final boolean isKeyRepeat) {
|
||||
if (codePoint < 0) {
|
||||
switch (codePoint) {
|
||||
|
@ -1759,8 +1762,7 @@ public class LatinIME extends InputMethodService implements
|
|||
loadSettings();
|
||||
if (mKeyboardSwitcher.getMainKeyboardView() != null) {
|
||||
// Reload keyboard because the current language has been changed.
|
||||
mKeyboardSwitcher.loadKeyboard(getCurrentInputEditorInfo(), mSettings.getCurrent(),
|
||||
getCurrentAutoCapsState(), getCurrentRecapitalizeState());
|
||||
mKeyboardSwitcher.reloadMainKeyboard();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ import com.android.inputmethod.latin.BinaryDictionary;
|
|||
|
||||
import helium314.keyboard.latin.SuggestedWords.SuggestedWordInfo;
|
||||
import helium314.keyboard.latin.common.ComposedData;
|
||||
import helium314.keyboard.latin.makedict.WordProperty;
|
||||
import helium314.keyboard.latin.settings.SettingsValuesForSuggestion;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
@ -107,6 +108,18 @@ public final class ReadOnlyBinaryDictionary extends Dictionary {
|
|||
return NOT_A_PROBABILITY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WordProperty getWordProperty(String word, boolean isBeginningOfSentence) {
|
||||
if (mLock.readLock().tryLock()) {
|
||||
try {
|
||||
return mBinaryDictionary.getWordProperty(word, isBeginningOfSentence);
|
||||
} finally {
|
||||
mLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
mLock.writeLock().lock();
|
||||
|
|
|
@ -40,8 +40,6 @@ import helium314.keyboard.latin.settings.SpacingAndPunctuations;
|
|||
import helium314.keyboard.latin.utils.CapsModeUtils;
|
||||
import helium314.keyboard.latin.utils.DebugLogUtils;
|
||||
import helium314.keyboard.latin.utils.NgramContextUtils;
|
||||
import helium314.keyboard.latin.utils.ScriptUtils;
|
||||
import helium314.keyboard.latin.utils.SpannableStringUtils;
|
||||
import helium314.keyboard.latin.utils.StatsUtils;
|
||||
import helium314.keyboard.latin.utils.TextRange;
|
||||
|
||||
|
@ -718,8 +716,13 @@ public final class RichInputConnection implements PrivateCommandPerformer {
|
|||
if (start < 0 || end < 0) {
|
||||
return false;
|
||||
}
|
||||
mExpectedSelStart = start;
|
||||
mExpectedSelEnd = end;
|
||||
if (start > end) {
|
||||
mExpectedSelStart = end;
|
||||
mExpectedSelEnd = start;
|
||||
} else {
|
||||
mExpectedSelStart = start;
|
||||
mExpectedSelEnd = end;
|
||||
}
|
||||
if (isConnected()) {
|
||||
final boolean isIcValid = mIC.setSelection(start, end);
|
||||
if (!isIcValid) {
|
||||
|
@ -825,15 +828,6 @@ public final class RichInputConnection implements PrivateCommandPerformer {
|
|||
return NgramContextUtils.getNgramContextFromNthPreviousWord(prev, spacingAndPunctuations, n);
|
||||
}
|
||||
|
||||
private static boolean isPartOfCompositionForScript(final int codePoint,
|
||||
final SpacingAndPunctuations spacingAndPunctuations, final String script) {
|
||||
// We always consider word connectors part of compositions.
|
||||
return spacingAndPunctuations.isWordConnector(codePoint)
|
||||
// Otherwise, it's part of composition if it's part of script and not a separator.
|
||||
|| (!spacingAndPunctuations.isWordSeparator(codePoint)
|
||||
&& ScriptUtils.isLetterPartOfScript(codePoint, script));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the text surrounding the cursor.
|
||||
*
|
||||
|
@ -860,90 +854,7 @@ public final class RichInputConnection implements PrivateCommandPerformer {
|
|||
if (before == null || after == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Going backward, find the first breaking point (separator)
|
||||
int startIndexInBefore = before.length();
|
||||
int endIndexInAfter = -1;
|
||||
while (startIndexInBefore > 0) {
|
||||
final int codePoint = Character.codePointBefore(before, startIndexInBefore);
|
||||
if (!isPartOfCompositionForScript(codePoint, spacingAndPunctuations, script)) {
|
||||
if (Character.isWhitespace(codePoint) || !spacingAndPunctuations.mCurrentLanguageHasSpaces)
|
||||
break;
|
||||
// continue to the next whitespace and see whether this contains a sometimesWordConnector
|
||||
for (int i = startIndexInBefore - 1; i >= 0; i--) {
|
||||
final char c = before.charAt(i);
|
||||
if (spacingAndPunctuations.isSometimesWordConnector(c)) {
|
||||
// if yes -> whitespace is the index
|
||||
startIndexInBefore = Math.max(StringUtils.charIndexOfLastWhitespace(before), 0);
|
||||
final int firstSpaceAfter = StringUtils.charIndexOfFirstWhitespace(after);
|
||||
endIndexInAfter = firstSpaceAfter == -1 ? after.length() : firstSpaceAfter -1;
|
||||
break;
|
||||
} else if (Character.isWhitespace(c)) {
|
||||
// if no, just break normally
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
--startIndexInBefore;
|
||||
if (Character.isSupplementaryCodePoint(codePoint)) {
|
||||
--startIndexInBefore;
|
||||
}
|
||||
}
|
||||
|
||||
// Find last word separator after the cursor
|
||||
if (endIndexInAfter == -1) {
|
||||
while (++endIndexInAfter < after.length()) {
|
||||
final int codePoint = Character.codePointAt(after, endIndexInAfter);
|
||||
if (!isPartOfCompositionForScript(codePoint, spacingAndPunctuations, script)) {
|
||||
if (Character.isWhitespace(codePoint) || !spacingAndPunctuations.mCurrentLanguageHasSpaces)
|
||||
break;
|
||||
// continue to the next whitespace and see whether this contains a sometimesWordConnector
|
||||
for (int i = endIndexInAfter; i < after.length(); i++) {
|
||||
final char c = after.charAt(i);
|
||||
if (spacingAndPunctuations.isSometimesWordConnector(c)) {
|
||||
// if yes -> whitespace is next to the index
|
||||
startIndexInBefore = Math.max(StringUtils.charIndexOfLastWhitespace(before), 0);
|
||||
final int firstSpaceAfter = StringUtils.charIndexOfFirstWhitespace(after);
|
||||
endIndexInAfter = firstSpaceAfter == -1 ? after.length() : firstSpaceAfter - 1;
|
||||
break;
|
||||
} else if (Character.isWhitespace(c)) {
|
||||
// if no, just break normally
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (Character.isSupplementaryCodePoint(codePoint)) {
|
||||
++endIndexInAfter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// strip stuff before "//" (i.e. ignore http and other protocols)
|
||||
final String beforeConsideringStart = before.subSequence(startIndexInBefore, before.length()).toString();
|
||||
final int protocolEnd = beforeConsideringStart.lastIndexOf("//");
|
||||
if (protocolEnd != -1)
|
||||
startIndexInBefore += protocolEnd + 1;
|
||||
|
||||
// we don't want the end characters to be word separators
|
||||
while (endIndexInAfter > 0 && spacingAndPunctuations.isWordSeparator(after.charAt(endIndexInAfter - 1))) {
|
||||
--endIndexInAfter;
|
||||
}
|
||||
while (startIndexInBefore < before.length() && spacingAndPunctuations.isWordSeparator(before.charAt(startIndexInBefore))) {
|
||||
++startIndexInBefore;
|
||||
}
|
||||
|
||||
final boolean hasUrlSpans =
|
||||
SpannableStringUtils.hasUrlSpans(before, startIndexInBefore, before.length())
|
||||
|| SpannableStringUtils.hasUrlSpans(after, 0, endIndexInAfter);
|
||||
// We don't use TextUtils#concat because it copies all spans without respect to their
|
||||
// nature. If the text includes a PARAGRAPH span and it has been split, then
|
||||
// TextUtils#concat will crash when it tries to concat both sides of it.
|
||||
return new TextRange(
|
||||
SpannableStringUtils.concatWithNonParagraphSuggestionSpansOnly(before, after),
|
||||
startIndexInBefore, before.length() + endIndexInAfter, before.length(),
|
||||
hasUrlSpans);
|
||||
return StringUtilsKt.getTouchedWordRange(before, after, script, spacingAndPunctuations);
|
||||
}
|
||||
|
||||
public boolean isCursorTouchingWord(final SpacingAndPunctuations spacingAndPunctuations,
|
||||
|
@ -956,19 +867,7 @@ public final class RichInputConnection implements PrivateCommandPerformer {
|
|||
// a composing region should always count as a word
|
||||
return true;
|
||||
}
|
||||
final String textBeforeCursor = mCommittedTextBeforeComposingText.toString();
|
||||
int indexOfCodePointInJavaChars = textBeforeCursor.length();
|
||||
int consideredCodePoint = 0 == indexOfCodePointInJavaChars ? Constants.NOT_A_CODE
|
||||
: textBeforeCursor.codePointBefore(indexOfCodePointInJavaChars);
|
||||
// Search for the first non word-connector char
|
||||
if (spacingAndPunctuations.isWordConnector(consideredCodePoint)) {
|
||||
indexOfCodePointInJavaChars -= Character.charCount(consideredCodePoint);
|
||||
consideredCodePoint = 0 == indexOfCodePointInJavaChars ? Constants.NOT_A_CODE
|
||||
: textBeforeCursor.codePointBefore(indexOfCodePointInJavaChars);
|
||||
}
|
||||
return !(Constants.NOT_A_CODE == consideredCodePoint
|
||||
|| spacingAndPunctuations.isWordSeparator(consideredCodePoint)
|
||||
|| spacingAndPunctuations.isWordConnector(consideredCodePoint));
|
||||
return StringUtilsKt.endsWithWordCodepoint(mCommittedTextBeforeComposingText.toString(), spacingAndPunctuations);
|
||||
}
|
||||
|
||||
public boolean isCursorFollowedByWordCharacter(
|
||||
|
|
|
@ -7,6 +7,7 @@ import helium314.keyboard.keyboard.Keyboard
|
|||
import helium314.keyboard.keyboard.KeyboardSwitcher
|
||||
import helium314.keyboard.latin.DictionaryFacilitator.DictionaryInitializationListener
|
||||
import helium314.keyboard.latin.common.ComposedData
|
||||
import helium314.keyboard.latin.makedict.WordProperty
|
||||
import helium314.keyboard.latin.settings.SettingsValuesForSuggestion
|
||||
import helium314.keyboard.latin.utils.SuggestionResults
|
||||
import java.util.Locale
|
||||
|
@ -47,6 +48,8 @@ class SingleDictionaryFacilitator(private val dict: Dictionary) : DictionaryFaci
|
|||
return suggestionResults
|
||||
}
|
||||
|
||||
fun getWordProperty(word: String): WordProperty? = dict.getWordProperty(word, false)
|
||||
|
||||
// ------------ dummy functionality ----------------
|
||||
|
||||
override fun setValidSpellingWordReadCache(cache: LruCache<String, Boolean>) {}
|
||||
|
|
|
@ -6,13 +6,18 @@ import helium314.keyboard.keyboard.internal.keyboard_parser.floris.KeyCode
|
|||
import helium314.keyboard.latin.common.StringUtils.mightBeEmoji
|
||||
import helium314.keyboard.latin.common.StringUtils.newSingleCodePointString
|
||||
import helium314.keyboard.latin.settings.SpacingAndPunctuations
|
||||
import helium314.keyboard.latin.utils.ScriptUtils
|
||||
import helium314.keyboard.latin.utils.SpacedTokens
|
||||
import helium314.keyboard.latin.utils.SpannableStringUtils
|
||||
import helium314.keyboard.latin.utils.TextRange
|
||||
import java.math.BigInteger
|
||||
import java.util.Locale
|
||||
import kotlin.math.max
|
||||
|
||||
fun CharSequence.codePointAt(offset: Int) = Character.codePointAt(this, offset)
|
||||
fun CharSequence.codePointBefore(offset: Int) = Character.codePointBefore(this, offset)
|
||||
|
||||
/** Loops over the codepoints in [text]. Exits when [loop] returns true */
|
||||
inline fun loopOverCodePoints(text: CharSequence, loop: (cp: Int, charCount: Int) -> Boolean) {
|
||||
var offset = 0
|
||||
while (offset < text.length) {
|
||||
|
@ -23,6 +28,7 @@ inline fun loopOverCodePoints(text: CharSequence, loop: (cp: Int, charCount: Int
|
|||
}
|
||||
}
|
||||
|
||||
/** Loops backwards over the codepoints in [text]. Exits when [loop] returns true */
|
||||
inline fun loopOverCodePointsBackwards(text: CharSequence, loop: (cp: Int, charCount: Int) -> Boolean) {
|
||||
var offset = text.length
|
||||
while (offset > 0) {
|
||||
|
@ -88,6 +94,111 @@ fun getFullEmojiAtEnd(text: CharSequence): String {
|
|||
return s.substring(offset)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the [text] does not end with word separator, ignoring all word connectors.
|
||||
* If the [text] is empty (after ignoring word connectors), the method returns false.
|
||||
*/
|
||||
// todo: this returns true on numbers, why isn't Character.isLetter(code) used?
|
||||
fun endsWithWordCodepoint(text: String, spacingAndPunctuations: SpacingAndPunctuations): Boolean {
|
||||
if (text.isEmpty()) return false
|
||||
var codePoint = 0 // initial value irrelevant since length is always > 0
|
||||
loopOverCodePointsBackwards(text) { cp, _ ->
|
||||
codePoint = cp
|
||||
!spacingAndPunctuations.isWordConnector(cp)
|
||||
}
|
||||
// codePoint might still be a wordConnector (if text consists of wordConnectors)
|
||||
return !spacingAndPunctuations.isWordConnector(codePoint) && !spacingAndPunctuations.isWordSeparator(codePoint)
|
||||
}
|
||||
|
||||
// todo: simplify... maybe compare with original code?
|
||||
fun getTouchedWordRange(before: CharSequence, after: CharSequence, script: String, spacingAndPunctuations: SpacingAndPunctuations): TextRange {
|
||||
// Going backward, find the first breaking point (separator)
|
||||
var startIndexInBefore = before.length
|
||||
var endIndexInAfter = -1 // todo: clarify why might we want to set it when checking before
|
||||
loopOverCodePointsBackwards(before) { codePoint, cpLength ->
|
||||
if (!isPartOfCompositionForScript(codePoint, spacingAndPunctuations, script)) {
|
||||
if (Character.isWhitespace(codePoint) || !spacingAndPunctuations.mCurrentLanguageHasSpaces)
|
||||
return@loopOverCodePointsBackwards true
|
||||
// continue to the next whitespace and see whether this contains a sometimesWordConnector
|
||||
for (i in startIndexInBefore - 1 downTo 0) {
|
||||
val c = before[i]
|
||||
if (spacingAndPunctuations.isSometimesWordConnector(c.code)) {
|
||||
// if yes -> whitespace is the index
|
||||
startIndexInBefore = max(StringUtils.charIndexOfLastWhitespace(before).toDouble(), 0.0).toInt()
|
||||
val firstSpaceAfter = StringUtils.charIndexOfFirstWhitespace(after)
|
||||
endIndexInAfter = if (firstSpaceAfter == -1) after.length else firstSpaceAfter - 1
|
||||
return@loopOverCodePointsBackwards true
|
||||
} else if (Character.isWhitespace(c)) {
|
||||
// if no, just break normally
|
||||
return@loopOverCodePointsBackwards true
|
||||
}
|
||||
}
|
||||
return@loopOverCodePointsBackwards true
|
||||
}
|
||||
startIndexInBefore -= cpLength
|
||||
false
|
||||
}
|
||||
|
||||
// Find last word separator after the cursor
|
||||
if (endIndexInAfter == -1) {
|
||||
endIndexInAfter = 0
|
||||
loopOverCodePoints(after) { codePoint, cpLength ->
|
||||
if (!isPartOfCompositionForScript(codePoint, spacingAndPunctuations, script)) {
|
||||
if (Character.isWhitespace(codePoint) || !spacingAndPunctuations.mCurrentLanguageHasSpaces)
|
||||
return@loopOverCodePoints true
|
||||
// continue to the next whitespace and see whether this contains a sometimesWordConnector
|
||||
for (i in endIndexInAfter..<after.length) {
|
||||
val c = after[i]
|
||||
if (spacingAndPunctuations.isSometimesWordConnector(c.code)) {
|
||||
// if yes -> whitespace is next to the index
|
||||
startIndexInBefore = max(StringUtils.charIndexOfLastWhitespace(before), 0)
|
||||
val firstSpaceAfter = StringUtils.charIndexOfFirstWhitespace(after)
|
||||
endIndexInAfter = if (firstSpaceAfter == -1) after.length else firstSpaceAfter - 1
|
||||
return@loopOverCodePoints true
|
||||
} else if (Character.isWhitespace(c)) {
|
||||
// if no, just break normally
|
||||
return@loopOverCodePoints true
|
||||
}
|
||||
}
|
||||
return@loopOverCodePoints true
|
||||
}
|
||||
endIndexInAfter += cpLength
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
// strip text before "//" (i.e. ignore http and other protocols)
|
||||
val beforeConsideringStart = before.substring(startIndexInBefore, before.length)
|
||||
val protocolEnd = beforeConsideringStart.lastIndexOf("//")
|
||||
if (protocolEnd != -1) startIndexInBefore += protocolEnd + 1
|
||||
|
||||
// we don't want the end characters to be word separators
|
||||
while (endIndexInAfter > 0 && spacingAndPunctuations.isWordSeparator(after[endIndexInAfter - 1].code)) {
|
||||
--endIndexInAfter
|
||||
}
|
||||
while (startIndexInBefore < before.length && spacingAndPunctuations.isWordSeparator(before[startIndexInBefore].code)) {
|
||||
++startIndexInBefore
|
||||
}
|
||||
|
||||
val hasUrlSpans = SpannableStringUtils.hasUrlSpans(before, startIndexInBefore, before.length)
|
||||
|| SpannableStringUtils.hasUrlSpans(after, 0, endIndexInAfter)
|
||||
|
||||
// We don't use TextUtils#concat because it copies all spans without respect to their
|
||||
// nature. If the text includes a PARAGRAPH span and it has been split, then
|
||||
// TextUtils#concat will crash when it tries to concat both sides of it.
|
||||
return TextRange(
|
||||
SpannableStringUtils.concatWithNonParagraphSuggestionSpansOnly(before, after),
|
||||
startIndexInBefore, before.length + endIndexInAfter, before.length,
|
||||
hasUrlSpans
|
||||
)
|
||||
}
|
||||
|
||||
// actually this should not be in STRING Utils, but only used for getTouchedWordRange
|
||||
private fun isPartOfCompositionForScript(codePoint: Int, spacingAndPunctuations: SpacingAndPunctuations, script: String) =
|
||||
spacingAndPunctuations.isWordConnector(codePoint) // We always consider word connectors part of compositions.
|
||||
// Otherwise, it's part of composition if it's part of script and not a separator.
|
||||
|| (!spacingAndPunctuations.isWordSeparator(codePoint) && ScriptUtils.isLetterPartOfScript(codePoint, script))
|
||||
|
||||
/** split the string on the first of consecutive space only, further consecutive spaces are added to the next split */
|
||||
fun String.splitOnFirstSpacesOnly(): List<String> {
|
||||
val out = mutableListOf<String>()
|
||||
|
|
|
@ -770,6 +770,8 @@ public final class InputLogic {
|
|||
break;
|
||||
case KeyCode.SEND_INTENT_ONE, KeyCode.SEND_INTENT_TWO, KeyCode.SEND_INTENT_THREE:
|
||||
handleSendIntentKey(event.getMKeyCode());
|
||||
case KeyCode.IME_HIDE_UI:
|
||||
mLatinIME.hideWindow();
|
||||
break;
|
||||
case KeyCode.VOICE_INPUT:
|
||||
// switching to shortcut IME, shift state, keyboard,... is handled by LatinIME,
|
||||
|
|
|
@ -58,6 +58,7 @@ object Defaults {
|
|||
const val PREF_VIBRATE_ON = false
|
||||
const val PREF_VIBRATE_IN_DND_MODE = false
|
||||
const val PREF_SOUND_ON = false
|
||||
const val PREF_SHOW_EMOJI_DESCRIPTIONS = true
|
||||
@JvmField
|
||||
var PREF_POPUP_ON = true
|
||||
const val PREF_AUTO_CORRECTION = true
|
||||
|
|
|
@ -67,6 +67,7 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
|
|||
public static final String PREF_VIBRATE_ON = "vibrate_on";
|
||||
public static final String PREF_VIBRATE_IN_DND_MODE = "vibrate_in_dnd_mode";
|
||||
public static final String PREF_SOUND_ON = "sound_on";
|
||||
public static final String PREF_SHOW_EMOJI_DESCRIPTIONS = "show_emoji_descriptions";
|
||||
public static final String PREF_POPUP_ON = "popup_on";
|
||||
public static final String PREF_AUTO_CORRECTION = "auto_correction";
|
||||
public static final String PREF_MORE_AUTO_CORRECTION = "more_auto_correction";
|
||||
|
|
|
@ -54,6 +54,7 @@ public class SettingsValues {
|
|||
public final boolean mVibrateOn;
|
||||
public final boolean mVibrateInDndMode;
|
||||
public final boolean mSoundOn;
|
||||
public final boolean mShowEmojiDescriptions;
|
||||
public final boolean mKeyPreviewPopupOn;
|
||||
public final boolean mShowsVoiceInputKey;
|
||||
public final boolean mLanguageSwitchKeyToOtherImes;
|
||||
|
@ -169,6 +170,7 @@ public class SettingsValues {
|
|||
mVibrateOn = Settings.readVibrationEnabled(prefs);
|
||||
mVibrateInDndMode = prefs.getBoolean(Settings.PREF_VIBRATE_IN_DND_MODE, Defaults.PREF_VIBRATE_IN_DND_MODE);
|
||||
mSoundOn = prefs.getBoolean(Settings.PREF_SOUND_ON, Defaults.PREF_SOUND_ON);
|
||||
mShowEmojiDescriptions = prefs.getBoolean(Settings.PREF_SHOW_EMOJI_DESCRIPTIONS, Defaults.PREF_SHOW_EMOJI_DESCRIPTIONS);
|
||||
mKeyPreviewPopupOn = prefs.getBoolean(Settings.PREF_POPUP_ON, Defaults.PREF_POPUP_ON);
|
||||
mSlidingKeyInputPreviewEnabled = prefs.getBoolean(
|
||||
DebugSettings.PREF_SLIDING_KEY_INPUT_PREVIEW, Defaults.PREF_SLIDING_KEY_INPUT_PREVIEW);
|
||||
|
|
|
@ -116,6 +116,7 @@ class SuggestionStripView(context: Context, attrs: AttributeSet?, defStyle: Int)
|
|||
private val toolbarArrowIcon = KeyboardIconsSet.instance.getNewDrawable(KeyboardIconsSet.NAME_TOOLBAR_KEY, context)
|
||||
private val defaultToolbarBackground: Drawable = toolbarExpandKey.background
|
||||
private val enabledToolKeyBackground = GradientDrawable()
|
||||
private var direction = 1 // 1 if LTR, -1 if RTL
|
||||
init {
|
||||
val colors = Settings.getValues().mColors
|
||||
|
||||
|
@ -171,7 +172,6 @@ class SuggestionStripView(context: Context, attrs: AttributeSet?, defStyle: Int)
|
|||
private lateinit var listener: Listener
|
||||
private var suggestedWords = SuggestedWords.getEmptyInstance()
|
||||
private var startIndexOfMoreSuggestions = 0
|
||||
private var direction = 1 // 1 if LTR, -1 if RTL
|
||||
private var isExternalSuggestionVisible = false // Required to disable the more suggestions if other suggestions are visible
|
||||
private val layoutHelper = SuggestionStripLayoutHelper(context, attrs, defStyle, wordViews, dividerViews, debugInfoViews)
|
||||
private val moreSuggestionsView = moreSuggestionsContainer.findViewById<MoreSuggestionsView>(R.id.more_suggestions_view).apply {
|
||||
|
@ -234,6 +234,7 @@ class SuggestionStripView(context: Context, attrs: AttributeSet?, defStyle: Int)
|
|||
context, suggestedWords, suggestionsStrip, this
|
||||
)
|
||||
isExternalSuggestionVisible = false
|
||||
updateKeys();
|
||||
}
|
||||
|
||||
fun setExternalSuggestionView(view: View?) {
|
||||
|
|
|
@ -101,6 +101,10 @@ object DictionaryInfoUtils {
|
|||
return absoluteDirectoryName
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getCachedDictForLocaleAndType(locale: Locale, type: String, context: Context): File? =
|
||||
getCachedDictsForLocale(locale, context).firstOrNull { it.name.substringBefore("_") == type }
|
||||
|
||||
fun getCachedDictsForLocale(locale: Locale, context: Context) =
|
||||
getCacheDirectoryForLocale(locale, context)?.let { File(it).listFiles() }.orEmpty()
|
||||
|
||||
|
|
|
@ -7,9 +7,13 @@
|
|||
package helium314.keyboard.latin.utils;
|
||||
|
||||
import android.text.Spanned;
|
||||
import android.text.TextUtils;
|
||||
import android.text.style.SuggestionSpan;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Represents a range of text, relative to the current cursor position.
|
||||
|
@ -95,6 +99,28 @@ public final class TextRange {
|
|||
return writeIndex == readIndex ? spans : Arrays.copyOfRange(spans, 0, writeIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (!(other instanceof TextRange textRange)) return false;
|
||||
return mWordAtCursorStartIndex == textRange.mWordAtCursorStartIndex
|
||||
&& mWordAtCursorEndIndex == textRange.mWordAtCursorEndIndex
|
||||
&& mCursorIndex == textRange.mCursorIndex
|
||||
&& mHasUrlSpans == textRange.mHasUrlSpans
|
||||
&& TextUtils.equals(mTextAtCursor, textRange.mTextAtCursor)
|
||||
&& TextUtils.equals(mWord, textRange.mWord);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(mTextAtCursor, mWordAtCursorStartIndex, mWordAtCursorEndIndex, mCursorIndex, mWord, mHasUrlSpans);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return mTextAtCursor + ", " + mWord + ", " + mCursorIndex;
|
||||
}
|
||||
|
||||
public TextRange(final CharSequence textAtCursor, final int wordAtCursorStartIndex,
|
||||
final int wordAtCursorEndIndex, final int cursorIndex, final boolean hasUrlSpans) {
|
||||
if (wordAtCursorStartIndex < 0 || cursorIndex < wordAtCursorStartIndex
|
||||
|
@ -109,4 +135,4 @@ public final class TextRange {
|
|||
mHasUrlSpans = hasUrlSpans;
|
||||
mWord = mTextAtCursor.subSequence(mWordAtCursorStartIndex, mWordAtCursorEndIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -79,7 +79,8 @@ fun AppearanceScreen(
|
|||
SettingsWithoutKey.CUSTOM_FONT,
|
||||
Settings.PREF_FONT_SCALE,
|
||||
Settings.PREF_EMOJI_FONT_SCALE,
|
||||
Settings.PREF_EMOJI_KEY_FIT,
|
||||
if (prefs.getFloat(Settings.PREF_EMOJI_FONT_SCALE, Defaults.PREF_EMOJI_FONT_SCALE) != 1f)
|
||||
Settings.PREF_EMOJI_KEY_FIT else null,
|
||||
if (prefs.getInt(Settings.PREF_EMOJI_MAX_SDK, Defaults.PREF_EMOJI_MAX_SDK) >= 24)
|
||||
Settings.PREF_EMOJI_SKIN_TONE else null,
|
||||
)
|
||||
|
@ -109,6 +110,7 @@ fun createAppearanceSettings(context: Context) = listOf(
|
|||
prefs.edit().remove(Settings.PREF_THEME_COLORS_NIGHT).apply()
|
||||
}
|
||||
KeyboardIconsSet.needsReload = true // only relevant for Settings.PREF_CUSTOM_ICON_NAMES
|
||||
KeyboardSwitcher.getInstance().setThemeNeedsReload()
|
||||
}
|
||||
},
|
||||
Setting(context, Settings.PREF_ICON_STYLE, R.string.icon_style) { setting ->
|
||||
|
|
|
@ -57,8 +57,11 @@ fun DictionaryScreen(
|
|||
val enabledLanguages = SubtypeSettings.getEnabledSubtypes(true).map { it.locale().language }
|
||||
val cachedDictFolders = DictionaryInfoUtils.getCacheDirectories(ctx).map { it.name }
|
||||
val comparer = compareBy<Locale>({ it.language !in enabledLanguages }, { it.toLanguageTag() !in cachedDictFolders}, { it.displayName })
|
||||
val dictionaryLocales = remember { getDictionaryLocales(ctx).sortedWith(comparer).toMutableList() }
|
||||
dictionaryLocales.add(0, Locale(SubtypeLocaleUtils.NO_LANGUAGE))
|
||||
val dictionaryLocales = remember {
|
||||
getDictionaryLocales(ctx).sortedWith(comparer).toMutableList().apply {
|
||||
add(0, Locale(SubtypeLocaleUtils.NO_LANGUAGE))
|
||||
}
|
||||
}
|
||||
var selectedLocale: Locale? by remember { mutableStateOf(null) }
|
||||
var showAddDictDialog by remember { mutableStateOf(false) }
|
||||
val dictPicker = dictionaryFilePicker(selectedLocale)
|
||||
|
|
|
@ -20,12 +20,15 @@ import androidx.compose.material3.MaterialTheme
|
|||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextField
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
|
@ -83,6 +86,11 @@ fun PersonalDictionaryScreen(
|
|||
)
|
||||
if (selectedWord != null) {
|
||||
val selWord = selectedWord!!
|
||||
val focusRequester = remember { FocusRequester() }
|
||||
LaunchedEffect(selectedWord) {
|
||||
if (selWord.word == "" && selWord.weight == null && selWord.shortcut == null)
|
||||
focusRequester.requestFocus() // user clicked add word
|
||||
}
|
||||
var newWord by remember { mutableStateOf(selWord) }
|
||||
var newLocale by remember { mutableStateOf(locale) }
|
||||
val wordValid = (newWord.word == selWord.word && locale == newLocale) || !doesWordExist(newWord.word, newLocale, ctx)
|
||||
|
@ -119,7 +127,7 @@ fun PersonalDictionaryScreen(
|
|||
TextField(
|
||||
value = newWord.word,
|
||||
onValueChange = { newWord = newWord.copy(word = it) },
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
modifier = Modifier.fillMaxWidth().focusRequester(focusRequester),
|
||||
singleLine = true
|
||||
)
|
||||
Row(
|
||||
|
|
|
@ -57,6 +57,7 @@ fun PreferencesScreen(
|
|||
Settings.PREF_SOUND_ON,
|
||||
if (prefs.getBoolean(Settings.PREF_SOUND_ON, Defaults.PREF_SOUND_ON))
|
||||
Settings.PREF_KEYPRESS_SOUND_VOLUME else null,
|
||||
Settings.PREF_SHOW_EMOJI_DESCRIPTIONS,
|
||||
R.string.settings_category_additional_keys,
|
||||
Settings.PREF_SHOW_NUMBER_ROW,
|
||||
if (SubtypeSettings.getEnabledSubtypes(true).any { it.locale().language in localesWithLocalizedNumberRow })
|
||||
|
@ -111,6 +112,14 @@ fun createPreferencesSettings(context: Context) = listOf(
|
|||
Setting(context, Settings.PREF_SOUND_ON, R.string.sound_on_keypress) {
|
||||
SwitchPreference(it, Defaults.PREF_SOUND_ON)
|
||||
},
|
||||
Setting(
|
||||
context, Settings.PREF_SHOW_EMOJI_DESCRIPTIONS, R.string.show_emoji_descriptions,
|
||||
R.string.show_emoji_descriptions_summary
|
||||
) {
|
||||
SwitchPreference(it, Defaults.PREF_SHOW_EMOJI_DESCRIPTIONS) {
|
||||
KeyboardSwitcher.getInstance().reloadKeyboard()
|
||||
}
|
||||
},
|
||||
Setting(context, Settings.PREF_ENABLE_CLIPBOARD_HISTORY,
|
||||
R.string.enable_clipboard_history, R.string.enable_clipboard_history_summary)
|
||||
{
|
||||
|
|
|
@ -24,6 +24,7 @@ import helium314.keyboard.latin.settings.Defaults
|
|||
import helium314.keyboard.latin.settings.Settings
|
||||
import helium314.keyboard.latin.utils.JniUtils
|
||||
import helium314.keyboard.latin.utils.Log
|
||||
import helium314.keyboard.latin.utils.ToolbarMode
|
||||
import helium314.keyboard.latin.utils.getActivity
|
||||
import helium314.keyboard.latin.utils.prefs
|
||||
import helium314.keyboard.settings.NextScreenIcon
|
||||
|
@ -49,7 +50,8 @@ fun TextCorrectionScreen(
|
|||
if ((b?.value ?: 0) < 0)
|
||||
Log.v("irrelevant", "stupid way to trigger recomposition on preference change")
|
||||
val autocorrectEnabled = prefs.getBoolean(Settings.PREF_AUTO_CORRECTION, Defaults.PREF_AUTO_CORRECTION)
|
||||
val suggestionsEnabled = prefs.getBoolean(Settings.PREF_SHOW_SUGGESTIONS, Defaults.PREF_SHOW_SUGGESTIONS)
|
||||
val suggestionsVisible = Settings.readToolbarMode(prefs) in setOf(ToolbarMode.SUGGESTION_STRIP, ToolbarMode.EXPANDABLE)
|
||||
val suggestionsEnabled = suggestionsVisible && prefs.getBoolean(Settings.PREF_SHOW_SUGGESTIONS, Defaults.PREF_SHOW_SUGGESTIONS)
|
||||
val gestureEnabled = JniUtils.sHaveGestureLib && prefs.getBoolean(Settings.PREF_GESTURE_INPUT, Defaults.PREF_GESTURE_INPUT)
|
||||
val items = listOf(
|
||||
SettingsWithoutKey.EDIT_PERSONAL_DICTIONARY,
|
||||
|
@ -69,7 +71,7 @@ fun TextCorrectionScreen(
|
|||
if (gestureEnabled) Settings.PREF_AUTOSPACE_AFTER_GESTURE_TYPING else null,
|
||||
Settings.PREF_SHIFT_REMOVES_AUTOSPACE,
|
||||
R.string.settings_category_suggestions,
|
||||
Settings.PREF_SHOW_SUGGESTIONS,
|
||||
if (suggestionsVisible) Settings.PREF_SHOW_SUGGESTIONS else null,
|
||||
if (suggestionsEnabled) Settings.PREF_ALWAYS_SHOW_SUGGESTIONS else null,
|
||||
if (suggestionsEnabled && prefs.getBoolean(Settings.PREF_ALWAYS_SHOW_SUGGESTIONS, Defaults.PREF_ALWAYS_SHOW_SUGGESTIONS))
|
||||
Settings.PREF_ALWAYS_SHOW_SUGGESTIONS_EXCEPT_WEB_TEXT else null,
|
||||
|
|
|
@ -10,6 +10,15 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
>
|
||||
<helium314.keyboard.keyboard.PopupTextView
|
||||
android:id="@+id/description_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingHorizontal="8dp"
|
||||
android:paddingBottom="4dp"
|
||||
android:visibility="gone"
|
||||
android:maxLines="1" android:ellipsize="end"
|
||||
style="?attr/popupKeysKeyboardViewStyle" />
|
||||
<helium314.keyboard.keyboard.PopupKeysKeyboardView
|
||||
android:id="@+id/popup_keys_keyboard_view"
|
||||
android:layout_width="wrap_content"
|
||||
|
|
|
@ -426,4 +426,13 @@
|
|||
<string name="use_apps_dict_summary">Namen der installierten Apps für Vorschläge und Korrekturen verwenden</string>
|
||||
<string name="prefs_emoji_skin_tone">Standard-Emoji-Hautton</string>
|
||||
<string name="prefs_emoji_skin_tone_neutral">Neutral</string>
|
||||
<string name="toolbar_mode_expandable">Symbolleiste Tasten und Vorschläge</string>
|
||||
<string name="toolbar_mode_toolbar_keys">Symbolleiste nur Tasten</string>
|
||||
<string name="popup_order_and_hint_source">Popup Tasten Reihenfolge und Vorschlag Quelle</string>
|
||||
<string name="toolbar_mode_hidden">Versteckt</string>
|
||||
<string name="toolbar_hiding_global">Auch Zwischenablage und Emoji Symbolleisten verstecken</string>
|
||||
<string name="subtype_with_layout_generic">%1$s (%2$s)</string>
|
||||
<string name="landscape">Querformat</string>
|
||||
<string name="toolbar_mode_suggestion_strip">Nur Vorschläge</string>
|
||||
<string name="toolbar_mode">Symbolleiste Modus</string>
|
||||
</resources>
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2008 The Android Open Source Project
|
||||
modified
|
||||
SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-only
|
||||
-->
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
--><resources>
|
||||
<string name="use_contacts_dict">"Look up contact names"</string>
|
||||
<string name="vibrate_on_keypress">"Vibrate on keypress"</string>
|
||||
<string name="sound_on_keypress">"Sound on keypress"</string>
|
||||
|
@ -109,4 +108,29 @@
|
|||
<string name="label_search_key">"Search"</string>
|
||||
<string name="label_pause_key">"Pause"</string>
|
||||
<string name="label_wait_key">"Wait"</string>
|
||||
<string name="split_spacer_scale_landscape">Split distance (landscape)</string>
|
||||
<string name="spell_checker_service_name">HeliBoard Spell Checker</string>
|
||||
<string name="ime_settings">HeliBoard Settings</string>
|
||||
<string name="android_spell_checker_settings">HeliBoard Spell Checker Settings</string>
|
||||
<string name="split_spacer_scale">Split distance</string>
|
||||
<string name="show_emoji_key">Emoji key</string>
|
||||
<string name="switch_language">Switch Language</string>
|
||||
<string name="settings_category_input">Input</string>
|
||||
<string name="settings_category_additional_keys">Additional keys</string>
|
||||
<string name="settings_category_suggestions">Suggestions</string>
|
||||
<string name="vibrate_in_dnd_mode">Vibrate in do not disturb mode</string>
|
||||
<string name="settings_category_correction">Corrections</string>
|
||||
<string name="enable_split_keyboard_landscape">Enable split keyboard (landscape)</string>
|
||||
<string name="disable_personalized_dicts_message">Warning: Disabling this setting will clear learned data</string>
|
||||
<string name="settings_category_clipboard_history">Clipboard history</string>
|
||||
<string name="settings_category_space">Space</string>
|
||||
<string name="settings_category_experimental">Experimental</string>
|
||||
<string name="settings_category_miscellaneous">Uncategorised</string>
|
||||
<string name="language_switch_key_switch_both">Switch both</string>
|
||||
<string name="language_switch_key_behavior">Language switch key behavior</string>
|
||||
<string name="abbreviation_unit_minutes">%s min</string>
|
||||
<string name="settings_no_limit">No limit</string>
|
||||
<string name="add_to_personal_dictionary">Add learnt words to personal dictionary</string>
|
||||
<string name="use_apps_dict">Look up app names</string>
|
||||
<string name="use_apps_dict_summary">Use names of installed apps for suggestions and corrections</string>
|
||||
</resources>
|
||||
|
|
|
@ -124,7 +124,7 @@ Nouveau dictionnaire:
|
|||
<string name="dictionary_file_wrong_script">Erreur : script non compatible avec ce clavier</string>
|
||||
<string name="dictionary_file_wrong_locale_ok">"Utiliser quand même"</string>
|
||||
<string name="dictionary_load_error">"Erreur de chargement du fichier dictionnaire"</string>
|
||||
<string name="dictionary_available">"Dictionnaire disponible"</string>
|
||||
<string name="dictionary_available">Dictionnaires disponibles</string>
|
||||
<string name="last_update">"Dernière mise à jour"</string>
|
||||
<string name="delete">"Supprimer"</string>
|
||||
<string name="version_text">Version %s</string>
|
||||
|
|
|
@ -428,11 +428,19 @@
|
|||
<string name="timestamp_format_title">Formato per il tasto data/ora</string>
|
||||
<string name="subtype_dag">Dagbani</string>
|
||||
<string name="subtype_st">Sesotho</string>
|
||||
<string name="prefs_emoji_key_fit">Scala la dimensione dei tasti con la dimensione dei caratteri</string>
|
||||
<string name="prefs_emoji_key_fit">Ridimensiona il tasto emoji in base alla dimensione dei caratteri</string>
|
||||
<string name="subtype_with_layout_generic">%1$s (%2$s)</string>
|
||||
<string name="backup_restored">Backup ripristinato</string>
|
||||
<string name="use_apps_dict">Suggerisci nomi delle app installate</string>
|
||||
<string name="use_apps_dict_summary">Aggiunge i nomi delle app installate alla lista di suggerimenti e correzioni</string>
|
||||
<string name="prefs_emoji_skin_tone">Tonalità di pelle predefinita per le emoji</string>
|
||||
<string name="prefs_emoji_skin_tone_neutral">Neutro (giallo)</string>
|
||||
<string name="toolbar_mode_expandable">Tasti funzione e suggerimenti</string>
|
||||
<string name="toolbar_mode_toolbar_keys">Solo tasti funzione</string>
|
||||
<string name="toolbar_mode_hidden">Nascosta</string>
|
||||
<string name="toolbar_hiding_global">Nascondi anche le barre degli appunti e delle emoji</string>
|
||||
<string name="landscape">Orizzontale</string>
|
||||
<string name="popup_order_and_hint_source">Ordine dei caratteri popup e fonti dei suggerimenti</string>
|
||||
<string name="toolbar_mode_suggestion_strip">Solo suggerimenti</string>
|
||||
<string name="toolbar_mode">Modalità</string>
|
||||
</resources>
|
||||
|
|
|
@ -17,6 +17,10 @@
|
|||
<string name="vibrate_in_dnd_mode">Vibrate in do not disturb mode</string>
|
||||
<!-- Option to play back sound on keypress in soft keyboard -->
|
||||
<string name="sound_on_keypress">Sound on keypress</string>
|
||||
<!-- Option to show emoji descriptions on long press -->
|
||||
<string name="show_emoji_descriptions">Show emoji description on long press</string>
|
||||
<!-- Description for option to show emoji descriptions on long press -->
|
||||
<string name="show_emoji_descriptions_summary">Requires an emoji dictionary</string>
|
||||
<!-- Option to control whether or not to show a popup with a larger font on each key press. -->
|
||||
<string name="popup_on_keypress">Popup on keypress</string>
|
||||
<!-- Settings screen title for preferences-->
|
||||
|
|
|
@ -4,9 +4,13 @@ package helium314.keyboard.latin
|
|||
import androidx.test.core.app.ApplicationProvider
|
||||
import helium314.keyboard.ShadowInputMethodManager2
|
||||
import helium314.keyboard.latin.common.StringUtils
|
||||
import helium314.keyboard.latin.common.endsWithWordCodepoint
|
||||
import helium314.keyboard.latin.common.getFullEmojiAtEnd
|
||||
import helium314.keyboard.latin.common.getTouchedWordRange
|
||||
import helium314.keyboard.latin.common.nonWordCodePointAndNoSpaceBeforeCursor
|
||||
import helium314.keyboard.latin.settings.SpacingAndPunctuations
|
||||
import helium314.keyboard.latin.utils.ScriptUtils
|
||||
import helium314.keyboard.latin.utils.TextRange
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.annotation.Config
|
||||
|
@ -60,6 +64,54 @@ class StringUtilsTest {
|
|||
assert(nonWordCodePointAndNoSpaceBeforeCursor("th.is", sp))
|
||||
}
|
||||
|
||||
@Test fun `is word-like at end`() {
|
||||
val sp = SpacingAndPunctuations(ApplicationProvider.getApplicationContext<App>().resources, false)
|
||||
assert(!endsWithWordCodepoint("", sp))
|
||||
assert(endsWithWordCodepoint("don'", sp))
|
||||
assert(!endsWithWordCodepoint("hello!", sp))
|
||||
assert(!endsWithWordCodepoint("when ", sp))
|
||||
assert(endsWithWordCodepoint("3-", sp)) // todo: this seems wrong
|
||||
assert(endsWithWordCodepoint("5'", sp)) // todo: this seems wrong
|
||||
assert(endsWithWordCodepoint("1", sp)) // todo: this seems wrong
|
||||
assert(endsWithWordCodepoint("a-", sp))
|
||||
assert(!endsWithWordCodepoint("--", sp))
|
||||
}
|
||||
|
||||
@Test fun `get touched text range`() {
|
||||
val sp = SpacingAndPunctuations(ApplicationProvider.getApplicationContext<App>().resources, false)
|
||||
val spUrl = SpacingAndPunctuations(ApplicationProvider.getApplicationContext<App>().resources, true)
|
||||
val script = ScriptUtils.SCRIPT_LATIN
|
||||
checkTextRange("blabla this is v", "ery good", sp, script, 15, 19)
|
||||
checkTextRange(".hel", "lo...", sp, script, 1, 6)
|
||||
checkTextRange("(hi", ")", sp, script, 1, 3)
|
||||
checkTextRange("", "word", sp, script, 0, 4)
|
||||
|
||||
checkTextRange("mail: blorb@", "florb.com or", sp, script, 12, 17)
|
||||
checkTextRange("mail: blorb@", "florb.com or", spUrl, script, 6, 21)
|
||||
checkTextRange("mail: blor", "b@florb.com or", sp, script, 6, 11)
|
||||
checkTextRange("mail: blor", "b@florb.com or", spUrl, script, 6, 21)
|
||||
checkTextRange("mail: blorb@f", "lorb.com or", sp, script, 12, 17)
|
||||
checkTextRange("mail: blorb@f", "lorb.com or", spUrl, script, 6, 21)
|
||||
|
||||
checkTextRange("http://exam", "ple.com", sp, script, 7, 14)
|
||||
checkTextRange("http://exam", "ple.com", spUrl, script, 7, 18)
|
||||
checkTextRange("http://example.", "com", sp, script, 15, 18)
|
||||
checkTextRange("http://example.", "com", spUrl, script, 7, 18)
|
||||
checkTextRange("htt", "p://example.com", sp, script, 0, 4)
|
||||
checkTextRange("htt", "p://example.com", spUrl, script, 0, 18)
|
||||
checkTextRange("http:/", "/example.com", sp, script, 6, 6)
|
||||
checkTextRange("http:/", "/example.com", spUrl, script, 0, 18)
|
||||
|
||||
checkTextRange("..", ".", spUrl, script, 2, 2)
|
||||
checkTextRange("...", "", spUrl, script, 3, 3)
|
||||
|
||||
// todo: these are bad cases of url detection
|
||||
// also: sometimesWordConnectors are for URL and should be named accordingly
|
||||
checkTextRange("@@@", "@@@", spUrl, script, 0, 6)
|
||||
checkTextRange("a...", "", spUrl, script, 0, 4)
|
||||
checkTextRange("@@@", "", spUrl, script, 0, 3)
|
||||
}
|
||||
|
||||
@Test fun detectEmojisAtEnd() {
|
||||
assertEquals("", getFullEmojiAtEnd("\uD83C\uDF83 "))
|
||||
assertEquals("", getFullEmojiAtEnd("a"))
|
||||
|
@ -87,4 +139,10 @@ class StringUtilsTest {
|
|||
// could help towards fully fixing https://github.com/Helium314/HeliBoard/issues/22
|
||||
// though this might be tricky, as some emojis will show as one on new Android versions, and
|
||||
// as two on older versions
|
||||
|
||||
private fun checkTextRange(before: String, after: String, sp: SpacingAndPunctuations, script: String, wordStart: Int, WordEnd: Int) {
|
||||
val got = getTouchedWordRange(before, after, script, sp)
|
||||
val wanted = TextRange(before + after, wordStart, WordEnd, before.length, false)
|
||||
assertEquals(wanted, got)
|
||||
}
|
||||
}
|
||||
|
|
10
fastlane/metadata/android/ar/changelogs/3200.txt
Normal file
10
fastlane/metadata/android/ar/changelogs/3200.txt
Normal file
|
@ -0,0 +1,10 @@
|
|||
* إضافة أوضاع شريط الأدوات (تسمح بإخفاء شريط الأدوات)
|
||||
* إضافة بعض متغيرات الرموز التعبيرية المفقودة
|
||||
* تحسين شاشة النوع الفرعي وحوار القاموس
|
||||
* إصلاح الألوان عند فرض الوضع الداكن
|
||||
* نقل معظم إعدادات مقياس الوضع الرأسي/الأفقي إلى حوار
|
||||
* إزالة ترجمات السلاسل الموسومة على أنها غير قابلة للترجمة
|
||||
* إصلاح اتجاه سهم الشاشة التالية للغات اليمين إلى اليسار
|
||||
* إصلاح التحميل الصحيح للغة العبرية على أندرويد 15
|
||||
* توفير لوحة مفاتيح أساسية على الأقل عندما لا تعمل المكتبة على الإطلاق
|
||||
* إصلاحات أخطاء طفيفة
|
10
fastlane/metadata/android/ar/changelogs/3201.txt
Normal file
10
fastlane/metadata/android/ar/changelogs/3201.txt
Normal file
|
@ -0,0 +1,10 @@
|
|||
* إضافة أوضاع شريط الأدوات (تسمح بإخفاء شريط الأدوات)
|
||||
* إضافة بعض متغيرات الرموز التعبيرية المفقودة
|
||||
* تحسين شاشة النوع الفرعي وحوار القاموس
|
||||
* إصلاح الألوان عند فرض الوضع الداكن
|
||||
* نقل معظم إعدادات مقياس الوضع الرأسي/الأفقي إلى حوار
|
||||
* إزالة ترجمات السلاسل الموسومة على أنها غير قابلة للترجمة
|
||||
* إصلاح اتجاه سهم الشاشة التالية للغات اليمين إلى اليسار
|
||||
* إصلاح التحميل الصحيح للغة العبرية على أندرويد 15
|
||||
* توفير لوحة مفاتيح أساسية على الأقل عندما لا تعمل المكتبة على الإطلاق
|
||||
* إصلاحات أخطاء طفيفة
|
10
fastlane/metadata/android/ca/changelogs/3200.txt
Normal file
10
fastlane/metadata/android/ca/changelogs/3200.txt
Normal file
|
@ -0,0 +1,10 @@
|
|||
* af. modes de barra d'eines (permet ocultar-la)
|
||||
* af. alguns emojis
|
||||
* millorar pantalla de subtipus i el diàleg del dicc.
|
||||
* corr. colors en forçar el mode fosc
|
||||
* moure la majoria de la configuració d'escala vert/horiz a un diàleg
|
||||
* elim. les trads. de les cadenes marcades com a no traduïbles
|
||||
* corr. direcció de fletxa de la pantalla següent a idiomes RTL
|
||||
* corr. la càrrega correcta de la config. regional hebrea a Android 15
|
||||
* tenir almenys un teclat bàsic quan la biblio. no funciona
|
||||
* corr. etc
|
10
fastlane/metadata/android/ca/changelogs/3201.txt
Normal file
10
fastlane/metadata/android/ca/changelogs/3201.txt
Normal file
|
@ -0,0 +1,10 @@
|
|||
* af. modes de barra d'eines (permet ocultar-la)
|
||||
* af. alguns emojis
|
||||
* millorar pantalla de subtipus i el diàleg del dicc.
|
||||
* corr. colors en forçar el mode fosc
|
||||
* moure la majoria de la configuració d'escala vert/horiz a un diàleg
|
||||
* elim. les trads. de les cadenes marcades com a no traduïbles
|
||||
* corr. direcció de fletxa de la pantalla següent a idiomes RTL
|
||||
* corr. la càrrega correcta de la config. regional hebrea a Android 15
|
||||
* tenir almenys un teclat bàsic quan la biblio. no funciona
|
||||
* corr. etc
|
10
fastlane/metadata/android/cs-CZ/changelogs/3200.txt
Normal file
10
fastlane/metadata/android/cs-CZ/changelogs/3200.txt
Normal file
|
@ -0,0 +1,10 @@
|
|||
* přidány režimy panelu nástrojů (umožňuje skrýt p. n.)
|
||||
* přidány chybějící varianty emodži
|
||||
* vylepšena obrazovka podtypů a dialog slovníku
|
||||
* opraveny barvy při vynuceném tmavém režimu
|
||||
* přesun většiny nastavení měřítka do dialogu
|
||||
* odstraněny překlady řetězců označených jako nepřekládatelné
|
||||
* opraven směr šipky „dále“ pro jazyky RTL
|
||||
* opraveno správné načítání hebrejského jazyka na Androidu 15
|
||||
* zajištění alespoň základní klávesnice, když knihovna vůbec nefunguje
|
||||
* drobné opravy chyb
|
10
fastlane/metadata/android/cs-CZ/changelogs/3201.txt
Normal file
10
fastlane/metadata/android/cs-CZ/changelogs/3201.txt
Normal file
|
@ -0,0 +1,10 @@
|
|||
* přidány režimy panelu nástrojů (umožňuje skrýt p. n.)
|
||||
* přidány chybějící varianty emodži
|
||||
* vylepšena obrazovka podtypů a dialog slovníku
|
||||
* opraveny barvy při vynuceném tmavém režimu
|
||||
* přesun většiny nastavení měřítka do dialogu
|
||||
* odstraněny překlady řetězců označených jako nepřekládatelné
|
||||
* opraven směr šipky „dále“ pro jazyky RTL
|
||||
* opraveno správné načítání hebrejského jazyka na Androidu 15
|
||||
* zajištění alespoň základní klávesnice, když knihovna vůbec nefunguje
|
||||
* drobné opravy chyb
|
10
fastlane/metadata/android/en-US/changelogs/3201.txt
Normal file
10
fastlane/metadata/android/en-US/changelogs/3201.txt
Normal file
|
@ -0,0 +1,10 @@
|
|||
* add toolbar modes (allows hiding toolbar)
|
||||
* add some missing emoji variants
|
||||
* improve subtype screen and dictionary dialog
|
||||
* fix colors when forcing dark mode
|
||||
* move most of the portrait / landscape scale settings into a dialog
|
||||
* remove translations of strings marked as non-translatable
|
||||
* fix next-screen arrow direction for RTL languages
|
||||
* fix proper loading of Hebrew locale on Android 15
|
||||
* have at least a basic keyboard when library doesn't work at all
|
||||
* minor bug fixes
|
10
fastlane/metadata/android/iw-IL/changelogs/3200.txt
Normal file
10
fastlane/metadata/android/iw-IL/changelogs/3200.txt
Normal file
|
@ -0,0 +1,10 @@
|
|||
* הוספת מצבי סרגל כלים (מאפשר הסתרת סרגלי כלים)
|
||||
* הוספת גווני עור חסרים לחלק מהאמוג'ים
|
||||
* שיפור מסך הכתב התחתי ודו-שיח המילון
|
||||
* תיקון הצבעים בעת כפיית מצב כהה
|
||||
* העברת מרבית הגדרות קנה-המידה של מצב אנכי / אופקי לדו-שיח
|
||||
* הסרת תרגומי מחרוזות המסומנות כבלתי ניתנות לתרגום
|
||||
* תיקון כיווני החץ למעבר למסך הבא עבור שםות הנכתבות מימין לשמאל
|
||||
* תיקון טעינה נכונה של הגדרות השפה העברית באנדרואיד 15
|
||||
* הצגת מקלדת בסיסית לכל הפחות כאשר ספריה איננה עובדת כלל
|
||||
* תיקוני שגיאות שוליות
|
10
fastlane/metadata/android/iw-IL/changelogs/3201.txt
Normal file
10
fastlane/metadata/android/iw-IL/changelogs/3201.txt
Normal file
|
@ -0,0 +1,10 @@
|
|||
* הוספת מצבי סרגל כלים (מאפשר הסתרת סרגלי כלים)
|
||||
* הוספת גווני עור חסרים לחלק מהאמוג'ים
|
||||
* שיפור מסך הכתב התחתי ודו-שיח המילון
|
||||
* תיקון הצבעים בעת כפיית מצב כהה
|
||||
* העברת מרבית הגדרות קנה-המידה של מצב אנכי / אופקי לדו-שיח
|
||||
* הסרת תרגומי מחרוזות המסומנות כבלתי ניתנות לתרגום
|
||||
* תיקון כיווני החץ למעבר למסך הבא עבור שםות הנכתבות מימין לשמאל
|
||||
* תיקון טעינה נכונה של הגדרות השפה העברית באנדרואיד 15
|
||||
* הצגת מקלדת בסיסית לכל הפחות כאשר ספריה איננה עובדת כלל
|
||||
* תיקוני שגיאות שוליות
|
10
fastlane/metadata/android/ru-RU/changelogs/3200.txt
Normal file
10
fastlane/metadata/android/ru-RU/changelogs/3200.txt
Normal file
|
@ -0,0 +1,10 @@
|
|||
* добавлены режимы панели инструментов (появилась возможность скрывать панель)
|
||||
* добавлены некоторые недостающие варианты эмодзи
|
||||
* улучшены экран выбора подтипа и диалог словаря
|
||||
* исправлены цвета при принудительном тёмном режиме
|
||||
* большинство настроек масштабирования для портретного и ландшафтного режимов перенесены в отдельный диалог
|
||||
* удалены переводы строк, отмеченных как не подлежащие переводу
|
||||
* исправлено направление стрелки перехода на следующий экран для языков с письмом справа налево (RTL)
|
||||
* исправлена корректная загрузка иврита на Android 15
|
||||
* обеспечена работа хотя бы базовой клавиатуры, если библиотека не функционирует вовсе
|
||||
* мелкие исправления ошибок
|
10
fastlane/metadata/android/ru-RU/changelogs/3201.txt
Normal file
10
fastlane/metadata/android/ru-RU/changelogs/3201.txt
Normal file
|
@ -0,0 +1,10 @@
|
|||
* добавлены режимы панели инструментов (появилась возможность скрывать панель)
|
||||
* добавлены некоторые недостающие варианты эмодзи
|
||||
* улучшены экран выбора подтипа и диалог словаря
|
||||
* исправлены цвета при принудительном тёмном режиме
|
||||
* большинство настроек масштабирования для портретного и ландшафтного режимов перенесены в отдельный диалог
|
||||
* удалены переводы строк, отмеченных как не подлежащие переводу
|
||||
* исправлено направление стрелки перехода на следующий экран для языков с письмом справа налево (RTL)
|
||||
* исправлена корректная загрузка иврита на Android 15
|
||||
* обеспечена работа хотя бы базовой клавиатуры, если библиотека не функционирует вовсе
|
||||
* мелкие исправления ошибок
|
|
@ -33,36 +33,6 @@ class EmojiData {
|
|||
}
|
||||
|
||||
private fun onEmojiInserted(group: EmojiGroup, emoji: EmojiSpec): Boolean {
|
||||
// Unicode RGI does not include letter symbols but Android supports them, so we inject them manually.
|
||||
if (emoji.codes contentEquals RAW_CPS_KEYCAP_HASH) {
|
||||
insertEmoji(group, intArrayOf(CP_REGIONAL_INDICATOR_SYMBOL_LETTER_A), 2.0f, "regional indicator symbol letter a")
|
||||
insertEmoji(group, intArrayOf(CP_REGIONAL_INDICATOR_SYMBOL_LETTER_B), 2.0f, "regional indicator symbol letter b")
|
||||
insertEmoji(group, intArrayOf(CP_REGIONAL_INDICATOR_SYMBOL_LETTER_C), 2.0f, "regional indicator symbol letter c")
|
||||
insertEmoji(group, intArrayOf(CP_REGIONAL_INDICATOR_SYMBOL_LETTER_D), 2.0f, "regional indicator symbol letter d")
|
||||
insertEmoji(group, intArrayOf(CP_REGIONAL_INDICATOR_SYMBOL_LETTER_E), 2.0f, "regional indicator symbol letter e")
|
||||
insertEmoji(group, intArrayOf(CP_REGIONAL_INDICATOR_SYMBOL_LETTER_F), 2.0f, "regional indicator symbol letter f")
|
||||
insertEmoji(group, intArrayOf(CP_REGIONAL_INDICATOR_SYMBOL_LETTER_G), 2.0f, "regional indicator symbol letter g")
|
||||
insertEmoji(group, intArrayOf(CP_REGIONAL_INDICATOR_SYMBOL_LETTER_H), 2.0f, "regional indicator symbol letter h")
|
||||
insertEmoji(group, intArrayOf(CP_REGIONAL_INDICATOR_SYMBOL_LETTER_I), 2.0f, "regional indicator symbol letter i")
|
||||
insertEmoji(group, intArrayOf(CP_REGIONAL_INDICATOR_SYMBOL_LETTER_J), 2.0f, "regional indicator symbol letter j")
|
||||
insertEmoji(group, intArrayOf(CP_REGIONAL_INDICATOR_SYMBOL_LETTER_K), 2.0f, "regional indicator symbol letter k")
|
||||
insertEmoji(group, intArrayOf(CP_REGIONAL_INDICATOR_SYMBOL_LETTER_L), 2.0f, "regional indicator symbol letter l")
|
||||
insertEmoji(group, intArrayOf(CP_REGIONAL_INDICATOR_SYMBOL_LETTER_M), 2.0f, "regional indicator symbol letter m")
|
||||
insertEmoji(group, intArrayOf(CP_REGIONAL_INDICATOR_SYMBOL_LETTER_N), 2.0f, "regional indicator symbol letter n")
|
||||
insertEmoji(group, intArrayOf(CP_REGIONAL_INDICATOR_SYMBOL_LETTER_O), 2.0f, "regional indicator symbol letter o")
|
||||
insertEmoji(group, intArrayOf(CP_REGIONAL_INDICATOR_SYMBOL_LETTER_P), 2.0f, "regional indicator symbol letter p")
|
||||
insertEmoji(group, intArrayOf(CP_REGIONAL_INDICATOR_SYMBOL_LETTER_Q), 2.0f, "regional indicator symbol letter q")
|
||||
insertEmoji(group, intArrayOf(CP_REGIONAL_INDICATOR_SYMBOL_LETTER_R), 2.0f, "regional indicator symbol letter r")
|
||||
insertEmoji(group, intArrayOf(CP_REGIONAL_INDICATOR_SYMBOL_LETTER_S), 2.0f, "regional indicator symbol letter s")
|
||||
insertEmoji(group, intArrayOf(CP_REGIONAL_INDICATOR_SYMBOL_LETTER_T), 2.0f, "regional indicator symbol letter t")
|
||||
insertEmoji(group, intArrayOf(CP_REGIONAL_INDICATOR_SYMBOL_LETTER_U), 2.0f, "regional indicator symbol letter u")
|
||||
insertEmoji(group, intArrayOf(CP_REGIONAL_INDICATOR_SYMBOL_LETTER_V), 2.0f, "regional indicator symbol letter v")
|
||||
insertEmoji(group, intArrayOf(CP_REGIONAL_INDICATOR_SYMBOL_LETTER_W), 2.0f, "regional indicator symbol letter w")
|
||||
insertEmoji(group, intArrayOf(CP_REGIONAL_INDICATOR_SYMBOL_LETTER_X), 2.0f, "regional indicator symbol letter x")
|
||||
insertEmoji(group, intArrayOf(CP_REGIONAL_INDICATOR_SYMBOL_LETTER_Y), 2.0f, "regional indicator symbol letter y")
|
||||
insertEmoji(group, intArrayOf(CP_REGIONAL_INDICATOR_SYMBOL_LETTER_Z), 2.0f, "regional indicator symbol letter z")
|
||||
}
|
||||
|
||||
// Some multi-skin-tone variants use a different base code than their non-multi-skin-tone counterparts,
|
||||
// so they don't get grouped. We drop them here, to prevent each variant from being displayed separately.
|
||||
return ! hasMultipleSkinModifiers(emoji.codes)
|
||||
|
@ -118,9 +88,6 @@ class EmojiData {
|
|||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private val RAW_CPS_KEYCAP_HASH = intArrayOf(0x0023, 0xFE0F, 0x20E3)
|
||||
|
||||
const val CP_NUL = 0x0000
|
||||
|
||||
private const val CP_ZWJ = 0x200D
|
||||
|
@ -136,34 +103,5 @@ class EmojiData {
|
|||
private const val CP_WHITE_HAIR = 0x1F9B3
|
||||
private const val CP_BARLD = 0x1F9B2
|
||||
private const val CP_VARIANT_SELECTOR = 0xFE0F
|
||||
|
||||
private const val CP_REGIONAL_INDICATOR_SYMBOL_LETTER_A = 0x1F1E6
|
||||
private const val CP_REGIONAL_INDICATOR_SYMBOL_LETTER_B = 0x1F1E7
|
||||
private const val CP_REGIONAL_INDICATOR_SYMBOL_LETTER_C = 0x1F1E8
|
||||
private const val CP_REGIONAL_INDICATOR_SYMBOL_LETTER_D = 0x1F1E9
|
||||
private const val CP_REGIONAL_INDICATOR_SYMBOL_LETTER_E = 0x1F1EA
|
||||
private const val CP_REGIONAL_INDICATOR_SYMBOL_LETTER_F = 0x1F1EB
|
||||
private const val CP_REGIONAL_INDICATOR_SYMBOL_LETTER_G = 0x1F1EC
|
||||
private const val CP_REGIONAL_INDICATOR_SYMBOL_LETTER_H = 0x1F1ED
|
||||
private const val CP_REGIONAL_INDICATOR_SYMBOL_LETTER_I = 0x1F1EE
|
||||
private const val CP_REGIONAL_INDICATOR_SYMBOL_LETTER_J = 0x1F1EF
|
||||
private const val CP_REGIONAL_INDICATOR_SYMBOL_LETTER_K = 0x1F1F0
|
||||
private const val CP_REGIONAL_INDICATOR_SYMBOL_LETTER_L = 0x1F1F1
|
||||
private const val CP_REGIONAL_INDICATOR_SYMBOL_LETTER_M = 0x1F1F2
|
||||
private const val CP_REGIONAL_INDICATOR_SYMBOL_LETTER_N = 0x1F1F3
|
||||
private const val CP_REGIONAL_INDICATOR_SYMBOL_LETTER_O = 0x1F1F4
|
||||
private const val CP_REGIONAL_INDICATOR_SYMBOL_LETTER_P = 0x1F1F5
|
||||
private const val CP_REGIONAL_INDICATOR_SYMBOL_LETTER_Q = 0x1F1F6
|
||||
private const val CP_REGIONAL_INDICATOR_SYMBOL_LETTER_R = 0x1F1F7
|
||||
private const val CP_REGIONAL_INDICATOR_SYMBOL_LETTER_S = 0x1F1F8
|
||||
private const val CP_REGIONAL_INDICATOR_SYMBOL_LETTER_T = 0x1F1F9
|
||||
private const val CP_REGIONAL_INDICATOR_SYMBOL_LETTER_U = 0x1F1FA
|
||||
private const val CP_REGIONAL_INDICATOR_SYMBOL_LETTER_V = 0x1F1FB
|
||||
private const val CP_REGIONAL_INDICATOR_SYMBOL_LETTER_W = 0x1F1FC
|
||||
private const val CP_REGIONAL_INDICATOR_SYMBOL_LETTER_X = 0x1F1FD
|
||||
private const val CP_REGIONAL_INDICATOR_SYMBOL_LETTER_Y = 0x1F1FE
|
||||
private const val CP_REGIONAL_INDICATOR_SYMBOL_LETTER_Z = 0x1F1FF
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -3866,31 +3866,5 @@ U+1F532 # black square button
|
|||
U+1F3C1 # chequered flag
|
||||
U+1F6A9 # triangular flag
|
||||
U+1F38C # crossed flags
|
||||
U+1F1E6 # regional indicator symbol letter a
|
||||
U+1F1E7 # regional indicator symbol letter b
|
||||
U+1F1E8 # regional indicator symbol letter c
|
||||
U+1F1E9 # regional indicator symbol letter d
|
||||
U+1F1EA # regional indicator symbol letter e
|
||||
U+1F1EB # regional indicator symbol letter f
|
||||
U+1F1EC # regional indicator symbol letter g
|
||||
U+1F1ED # regional indicator symbol letter h
|
||||
U+1F1EE # regional indicator symbol letter i
|
||||
U+1F1EF # regional indicator symbol letter j
|
||||
U+1F1F0 # regional indicator symbol letter k
|
||||
U+1F1F1 # regional indicator symbol letter l
|
||||
U+1F1F2 # regional indicator symbol letter m
|
||||
U+1F1F3 # regional indicator symbol letter n
|
||||
U+1F1F4 # regional indicator symbol letter o
|
||||
U+1F1F5 # regional indicator symbol letter p
|
||||
U+1F1F6 # regional indicator symbol letter q
|
||||
U+1F1F7 # regional indicator symbol letter r
|
||||
U+1F1F8 # regional indicator symbol letter s
|
||||
U+1F1F9 # regional indicator symbol letter t
|
||||
U+1F1FA # regional indicator symbol letter u
|
||||
U+1F1FB # regional indicator symbol letter v
|
||||
U+1F1FC # regional indicator symbol letter w
|
||||
U+1F1FD # regional indicator symbol letter x
|
||||
U+1F1FE # regional indicator symbol letter y
|
||||
U+1F1FF # regional indicator symbol letter z
|
||||
# Above emojis are supported from Android 4.4 (API level 19)
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue