Merge branch 'main' into settings_new

This commit is contained in:
Helium314 2025-02-06 22:52:05 +01:00
commit ed48d5096a
51 changed files with 1126 additions and 226 deletions

View file

@ -0,0 +1,34 @@
ز
ر
ذ
د
خ
ح
ج
ث
ت
ب
ا
ك
ق
ف
غ
ع
ظ
ط
ض
ص
ش
س
ء
ى
ي
ؤ
و
ة
ن
م
ل

View file

@ -1,112 +1,556 @@
[
[
{ "$": "shift_state_selector",
"manualOrLocked": { "label": "ং" },
"default": { "label": "ঙ" }
{
"$": "shift_state_selector",
"manualOrLocked": {
"label": "ং",
"labelFlags": 1073741824
},
"default": {
"label": "ঙ",
"popup": {
"main": {
"label": "ং"
},
"relevant": [
{
"label": "১"
}
]
}
}
},
{ "$": "shift_state_selector",
"manualOrLocked": { "label": "য়" },
"default": { "label": "য" }
{
"$": "shift_state_selector",
"manualOrLocked": {
"label": "য়",
"labelFlags": 1073741824
},
"default": {
"label": "য",
"popup": {
"main": {
"label": "য়"
},
"relevant": [
{
"label": "২"
}
]
}
}
},
{ "$": "shift_state_selector",
"manualOrLocked": { "label": "ঢ" },
"default": { "label": "ড" }
{
"$": "shift_state_selector",
"manualOrLocked": {
"label": "ঢ",
"labelFlags": 1073741824
},
"default": {
"label": "ড",
"popup": {
"main": {
"label": "ঢ"
},
"relevant": [
{
"label": "৩"
}
]
}
}
},
{ "$": "shift_state_selector",
"manualOrLocked": { "label": "ফ" },
"default": { "label": "প" }
{
"$": "shift_state_selector",
"manualOrLocked": {
"label": "ফ",
"labelFlags": 1073741824
},
"default": {
"label": "প",
"popup": {
"main": {
"label": "ফ"
},
"relevant": [
{
"label": ""
}
]
}
}
},
{ "$": "shift_state_selector",
"manualOrLocked": { "label": "ঠ" },
"default": { "label": "ট" }
{
"$": "shift_state_selector",
"manualOrLocked": {
"label": "ঠ",
"labelFlags": 1073741824
},
"default": {
"label": "ট",
"popup": {
"main": {
"label": "ঠ"
},
"relevant": [
{
"label": "৫"
}
]
}
}
},
{ "$": "shift_state_selector",
"manualOrLocked": { "label": "ছ" },
"default": { "label": "চ" }
{
"$": "shift_state_selector",
"manualOrLocked": {
"label": "ছ",
"labelFlags": 1073741824
},
"default": {
"label": "চ",
"popup": {
"main": {
"label": "ছ"
},
"relevant": [
{
"label": "৬"
}
]
}
}
},
{ "$": "shift_state_selector",
"manualOrLocked": { "label": "ঝ" },
"default": { "label": "জ" }
{
"$": "shift_state_selector",
"manualOrLocked": {
"label": "ঝ",
"labelFlags": 1073741824
},
"default": {
"label": "জ",
"popup": {
"main": {
"label": "ঝ"
},
"relevant": [
{
"label": ""
}
]
}
}
},
{ "$": "shift_state_selector",
"manualOrLocked": { "label": "ঞ" },
"default": { "label": "হ" }
{
"$": "shift_state_selector",
"manualOrLocked": {
"label": "ঞ",
"labelFlags": 1073741824
},
"default": {
"label": "হ",
"popup": {
"main": {
"label": "ঞ"
},
"relevant": [
{
"label": "৮"
}
]
}
}
},
{ "$": "shift_state_selector",
"manualOrLocked": { "label": "ঘ" },
"default": { "label": "গ" }
{
"$": "shift_state_selector",
"manualOrLocked": {
"label": "ঘ",
"labelFlags": 1073741824
},
"default": {
"label": "গ",
"popup": {
"main": {
"label": "ঘ"
},
"relevant": [
{
"label": "৯"
}
]
}
}
},
{ "$": "shift_state_selector",
"manualOrLocked": { "label": "ঢ়" },
"default": { "label": "ড়" }
{
"$": "shift_state_selector",
"manualOrLocked": {
"label": "ঢ়",
"labelFlags": 1073741824
},
"default": {
"label": "ড়",
"popup": {
"main": {
"label": "ঢ়"
},
"relevant": [
{
"label": ""
}
]
}
}
}
],
[
{ "$": "shift_state_selector",
"manualOrLocked": { "label": "ঃ" },
"default": { "label": "ৃ" }
{
"$": "shift_state_selector",
"manualOrLocked": {
"label": "ঃ",
"labelFlags": 1073741824
},
"default": {
"label": "ৃ",
"popup": {
"relevant": [
{
"label": "ঋ"
}
]
}
}
},
{ "$": "shift_state_selector",
"manualOrLocked": { "label": "ূ" },
"default": { "label": "ু" }
{
"$": "shift_state_selector",
"manualOrLocked": {
"label": "ূ",
"popup": {
"relevant": [
{
"label": "ঊ"
}
]
}
},
"default": {
"label": "ু",
"popup": {
"relevant": [
{
"label": "উ"
}
]
}
}
},
{ "$": "shift_state_selector",
"manualOrLocked": { "label": "ী" },
"default": { "label": "ি" }
{
"$": "shift_state_selector",
"manualOrLocked": {
"label": "ী",
"popup": {
"relevant": [
{
"label": "ঈ"
}
]
}
},
"default": {
"label": "ি",
"popup": {
"relevant": [
{
"label": "ই"
}
]
}
}
},
{ "$": "shift_state_selector",
"manualOrLocked": { "label": "অ" },
"default": { "label": "া" }
{
"$": "shift_state_selector",
"manualOrLocked": {
"label": "অ",
"labelFlags": 1073741824
},
"default": {
"label": "া",
"popup": {
"main": {
"label": "আ"
},
"relevant": [
{
"label": "অ"
}
]
}
}
},
{ "$": "shift_state_selector",
"manualOrLocked": { "label": "ঁ" },
"default": { "label": "্" }
{
"$": "shift_state_selector",
"manualOrLocked": {
"label": "ঁ",
"labelFlags": 1073741824,
"popup": {
"relevant": [
{
"label": "!autoColumnOrder!6"
},
{
"label": "়"
},
{
"label": "ৄ"
},
{
"label": "ঽ"
},
{
"label": "ৢ"
},
{
"label": "ৱ"
},
{
"label": "ৣ"
},
{
"label": "ৗ"
},
{
"label": "ৠ"
},
{
"label": "৺"
},
{
"label": "ঌ"
},
{
"label": "ৰ"
},
{
"label": "ৡ"
}
]
}
},
"default": {
"label": "্",
"popup": {
"relevant": [
{
"label": "ঁ"
}
]
}
}
},
{ "$": "shift_state_selector",
"manualOrLocked": { "label": "ভ" },
"default": { "label": "ব" }
{
"$": "shift_state_selector",
"manualOrLocked": {
"label": "ভ",
"labelFlags": 1073741824
},
"default": {
"label": "ব",
"popup": {
"relevant": [
{
"label": "ভ"
}
]
}
}
},
{ "$": "shift_state_selector",
"manualOrLocked": { "label": "খ" },
"default": { "label": "ক" }
{
"$": "shift_state_selector",
"manualOrLocked": {
"label": "খ",
"labelFlags": 1073741824
},
"default": {
"label": "ক",
"popup": {
"relevant": [
{
"label": "খ"
}
]
}
}
},
{ "$": "shift_state_selector",
"manualOrLocked": { "label": "থ" },
"default": { "label": "ত" }
{
"$": "shift_state_selector",
"manualOrLocked": {
"label": "থ",
"labelFlags": 1073741824
},
"default": {
"label": "ত",
"popup": {
"main": {
"label": "থ"
},
"relevant": [
{
"label": "ৎ"
}
]
}
}
},
{ "$": "shift_state_selector",
"manualOrLocked": { "label": "ধ" },
"default": { "label": "দ" }
{
"$": "shift_state_selector",
"manualOrLocked": {
"label": "ধ",
"labelFlags": 1073741824
},
"default": {
"label": "দ",
"popup": {
"relevant": [
{
"label": "ধ"
}
]
}
}
}
],
[
{ "$": "shift_state_selector",
"manualOrLocked": { "label": "্য" },
"default": { "label": "্র" }
{
"$": "shift_state_selector",
"manualOrLocked": {
"label": "্য",
"labelFlags": 1073741824
},
"default": {
"label": "্র",
"popup": {
"relevant": [
{
"label": "্য"
}
]
}
}
},
{ "$": "shift_state_selector",
"manualOrLocked": { "label": "ৌ" },
"default": { "label": "ো" }
{
"$": "shift_state_selector",
"manualOrLocked": {
"label": "ৌ",
"popup": {
"relevant": [
{
"label": "ঔ"
}
]
}
},
"default": {
"label": "ো",
"popup": {
"relevant": [
{
"label": "ও"
}
]
}
}
},
{ "$": "shift_state_selector",
"manualOrLocked": { "label": "ৈ" },
"default": { "label": "ে" }
{
"$": "shift_state_selector",
"manualOrLocked": {
"label": "ৈ",
"popup": {
"relevant": [
{
"label": "ঐ"
}
]
}
},
"default": {
"label": "ে",
"popup": {
"relevant": [
{
"label": "এ"
}
]
}
}
},
{ "$": "shift_state_selector",
"manualOrLocked": { "label": "ল" },
"default": { "label": "র" }
{
"$": "shift_state_selector",
"manualOrLocked": {
"label": "ল",
"labelFlags": 1073741824
},
"default": {
"label": "র",
"popup": {
"main": {
"label": "ল"
},
"relevant": [
{
"label": "র‍্য"
}
]
}
}
},
{ "$": "shift_state_selector",
"manualOrLocked": { "label": "ণ" },
"default": { "label": "ন" }
{
"$": "shift_state_selector",
"manualOrLocked": {
"label": "ণ",
"labelFlags": 1073741824
},
"default": {
"label": "ন",
"popup": {
"relevant": [
{
"label": "ণ"
}
]
}
}
},
{ "$": "shift_state_selector",
"manualOrLocked": { "label": "ষ" },
"default": { "label": "স" }
{
"$": "shift_state_selector",
"manualOrLocked": {
"label": "ষ",
"labelFlags": 1073741824
},
"default": {
"label": "স",
"popup": {
"relevant": [
{
"label": "ষ"
}
]
}
}
},
{ "$": "shift_state_selector",
"manualOrLocked": { "label": "শ" },
"default": { "label": "ম" }
{
"$": "shift_state_selector",
"manualOrLocked": {
"label": "শ",
"labelFlags": 1073741824
},
"default": {
"label": "ম",
"popup": {
"relevant": [
{
"label": "শ"
}
]
}
}
}
]
]
]

View file

@ -16,7 +16,7 @@
ী ঈ
া আ অ
্ ঁ
় ৺ ঽ ৗ ঌ ৡ ৠ ৱ ৢ ৣ ৄ ৰ
!autoColumnOrder!6 ় ৄ ঽ ৢ ৱ ৣ ৗ ৠ ৺ ঌ ৰ ৡ
ব ভ
ক খ
ত থ ৎ

View file

@ -97,6 +97,7 @@ public interface KeyboardActionListener {
*/
boolean onHorizontalSpaceSwipe(int steps);
boolean onVerticalSpaceSwipe(int steps);
void onEndSpaceSwipe();
boolean toggleNumpad(boolean withSliding, boolean forceReturnToAlpha);
void onMoveDeletePointer(int steps);
@ -148,6 +149,8 @@ public interface KeyboardActionListener {
return false;
}
@Override
public void onEndSpaceSwipe() {}
@Override
public void onMoveDeletePointer(int steps) {}
@Override
public void onUpWithDeletePointerActive() {}

View file

@ -1,6 +1,7 @@
package helium314.keyboard.keyboard
import android.view.KeyEvent
import android.view.inputmethod.InputMethodSubtype
import helium314.keyboard.keyboard.internal.keyboard_parser.floris.KeyCode
import helium314.keyboard.latin.LatinIME
import helium314.keyboard.latin.RichInputMethodManager
@ -19,6 +20,10 @@ class KeyboardActionListenerImpl(private val latinIME: LatinIME, private val inp
private val settings = Settings.getInstance()
private var metaState = 0 // is this enough, or are there threading issues with the different PointerTrackers?
// language slide state
private var initialSubtype: InputMethodSubtype? = null
private var subtypeSwitchCount = 0
// todo: maybe keep meta state presses to KeyboardActionListenerImpl, and avoid calls to press/release key
private fun adjustMetaState(code: Int, remove: Boolean) {
val metaCode = when (code) {
@ -84,6 +89,11 @@ class KeyboardActionListenerImpl(private val latinIME: LatinIME, private val inp
else -> false
}
override fun onEndSpaceSwipe(){
initialSubtype = null
subtypeSwitchCount = 0
}
override fun toggleNumpad(withSliding: Boolean, forceReturnToAlpha: Boolean): Boolean {
KeyboardSwitcher.getInstance().toggleNumpad(withSliding, latinIME.currentAutoCapsState, latinIME.currentRecapitalizeState, forceReturnToAlpha)
return true
@ -124,7 +134,7 @@ class KeyboardActionListenerImpl(private val latinIME: LatinIME, private val inp
}
private fun onLanguageSlide(steps: Int): Boolean {
if (abs(steps) < 4) return false
if (abs(steps) < settings.current.mLanguageSwipeDistance) return false
val subtypes = RichInputMethodManager.getInstance().getMyEnabledInputMethodSubtypeList(false)
if (subtypes.size <= 1) { // only allow if we have more than one subtype
return false
@ -135,7 +145,18 @@ class KeyboardActionListenerImpl(private val latinIME: LatinIME, private val inp
wantedIndex %= subtypes.size
if (wantedIndex < 0)
wantedIndex += subtypes.size
KeyboardSwitcher.getInstance().switchToSubtype(subtypes[wantedIndex])
val newSubtype = subtypes[wantedIndex]
// do not switch if we would switch to the initial subtype after cycling all other subtypes
if (initialSubtype == null)
initialSubtype = current
if (initialSubtype == newSubtype) {
if ((subtypeSwitchCount > 0 && steps > 0) || ((subtypeSwitchCount < 0 && steps < 0)))
return true
}
if (steps > 0) subtypeSwitchCount++ else subtypeSwitchCount--
KeyboardSwitcher.getInstance().switchToSubtype(newSubtype)
return true
}

View file

@ -8,6 +8,7 @@ package helium314.keyboard.keyboard;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
@ -40,8 +41,10 @@ import helium314.keyboard.latin.RichInputMethodSubtype;
import helium314.keyboard.latin.WordComposer;
import helium314.keyboard.latin.settings.Settings;
import helium314.keyboard.latin.settings.SettingsValues;
import helium314.keyboard.latin.suggestions.SuggestionStripView;
import helium314.keyboard.latin.utils.AdditionalSubtypeUtils;
import helium314.keyboard.latin.utils.CapsModeUtils;
import helium314.keyboard.latin.utils.DeviceProtectedUtils;
import helium314.keyboard.latin.utils.LanguageOnSpacebarUtils;
import helium314.keyboard.latin.utils.Log;
import helium314.keyboard.latin.utils.RecapitalizeStatus;
@ -59,7 +62,7 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
private View mEmojiTabStripView;
private LinearLayout mClipboardStripView;
private HorizontalScrollView mClipboardStripScrollView;
private View mSuggestionStripView;
private SuggestionStripView mSuggestionStripView;
private ClipboardHistoryView mClipboardHistoryView;
private TextView mFakeToastView;
private LatinIME mLatinIME;
@ -325,7 +328,6 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
if (DEBUG_ACTION) {
Log.d(TAG, "setEmojiKeyboard");
}
final Keyboard keyboard = mKeyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET);
mMainKeyboardFrame.setVisibility(View.VISIBLE);
// The visibility of {@link #mKeyboardView} must be aligned with {@link #MainKeyboardFrame}.
// @see #getVisibleKeyboardView() and
@ -346,7 +348,6 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
if (DEBUG_ACTION) {
Log.d(TAG, "setClipboardKeyboard");
}
final Keyboard keyboard = mKeyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET);
mMainKeyboardFrame.setVisibility(View.VISIBLE);
// The visibility of {@link #mKeyboardView} must be aligned with {@link #MainKeyboardFrame}.
// @see #getVisibleKeyboardView() and
@ -634,6 +635,11 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
mKeyboardView.closing();
}
PointerTracker.clearOldViewData();
final SharedPreferences prefs = DeviceProtectedUtils.getSharedPreferences(displayContext);
if (mSuggestionStripView != null)
prefs.unregisterOnSharedPreferenceChangeListener(mSuggestionStripView);
if (mClipboardHistoryView != null)
prefs.unregisterOnSharedPreferenceChangeListener(mClipboardHistoryView);
updateKeyboardThemeAndContextThemeWrapper(displayContext, KeyboardTheme.getKeyboardTheme(displayContext));
mCurrentInputView = (InputView)LayoutInflater.from(mThemeContext).inflate(R.layout.input_view, null);
@ -656,6 +662,8 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
mClipboardStripScrollView = mCurrentInputView.findViewById(R.id.clipboard_strip_scroll_view);
mSuggestionStripView = mCurrentInputView.findViewById(R.id.suggestion_strip_view);
prefs.registerOnSharedPreferenceChangeListener(mSuggestionStripView);
prefs.registerOnSharedPreferenceChangeListener(mClipboardHistoryView);
PointerTracker.switchTo(mKeyboardView);
return mCurrentInputView;
}

View file

@ -65,6 +65,7 @@ public class KeyboardView extends View {
private static final float KET_TEXT_SHADOW_RADIUS_DISABLED = -1.0f;
private final Colors mColors;
private float mKeyScaleForText;
protected float mFontSizeMultiplier;
// The maximum key label width in the proportion to the key width.
private static final float MAX_LABEL_RATIO = 0.90f;
@ -189,6 +190,9 @@ public class KeyboardView extends View {
mKeyDrawParams.updateParams(scaledKeyHeight, keyboard.mKeyVisualAttributes);
invalidateAllKeys();
requestLayout();
mFontSizeMultiplier = mKeyboard.mId.isEmojiKeyboard()
? Settings.getInstance().getCurrent().mFontSizeMultiplierEmoji
: Settings.getInstance().getCurrent().mFontSizeMultiplier;
}
/**
@ -384,7 +388,7 @@ public class KeyboardView extends View {
final String label = key.getLabel();
if (label != null) {
paint.setTypeface(mTypeface == null ? key.selectTypeface(params) : mTypeface);
paint.setTextSize(key.selectTextSize(params));
paint.setTextSize(key.selectTextSize(params) * mFontSizeMultiplier);
final float labelCharHeight = TypefaceUtils.getReferenceCharHeight(paint);
final float labelCharWidth = TypefaceUtils.getReferenceCharWidth(paint);
@ -446,10 +450,10 @@ public class KeyboardView extends View {
// Draw hint label.
final String hintLabel = key.getHintLabel();
if (hintLabel != null && mShowsHints) {
paint.setTextSize(key.selectHintTextSize(params));
paint.setTextSize(key.selectHintTextSize(params) * mFontSizeMultiplier); // maybe take sqrt to not have such extreme changes?
paint.setColor(key.selectHintTextColor(params));
// TODO: Should add a way to specify type face for hint letters
paint.setTypeface(Typeface.DEFAULT_BOLD);
paint.setTypeface(mTypeface == null ? Typeface.DEFAULT_BOLD : mTypeface);
blendAlpha(paint, params.mAnimAlpha);
final float labelCharHeight = TypefaceUtils.getReferenceCharHeight(paint);
final float labelCharWidth = TypefaceUtils.getReferenceCharWidth(paint);
@ -561,7 +565,7 @@ public class KeyboardView extends View {
} else {
paint.setColor(key.selectTextColor(mKeyDrawParams));
paint.setTypeface(key.selectTypeface(mKeyDrawParams));
paint.setTextSize(key.selectTextSize(mKeyDrawParams));
paint.setTextSize(key.selectTextSize(mKeyDrawParams) * mFontSizeMultiplier);
}
return paint;
}

View file

@ -164,7 +164,8 @@ public final class MainKeyboardView extends KeyboardView implements DrawingProxy
mBackgroundDimAlphaPaint.setColor(Color.BLACK);
mBackgroundDimAlphaPaint.setAlpha(backgroundDimAlpha);
mLanguageOnSpacebarTextRatio = mainKeyboardViewAttr.getFraction(
R.styleable.MainKeyboardView_languageOnSpacebarTextRatio, 1, 1, 1.0f);
R.styleable.MainKeyboardView_languageOnSpacebarTextRatio, 1, 1, 1.0f)
* Settings.getInstance().getCurrent().mFontSizeMultiplier;
final Colors colors = Settings.getInstance().getCurrent().mColors;
mLanguageOnSpacebarTextColor = colors.get(ColorType.SPACE_BAR_TEXT);
mLanguageOnSpacebarTextShadowRadius = mainKeyboardViewAttr.getFloat(

View file

@ -1076,6 +1076,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element,
if (mInHorizontalSwipe || mInVerticalSwipe) {
mInHorizontalSwipe = false;
mInVerticalSwipe = false;
sListener.onEndSpaceSwipe();
return;
}
}

View file

@ -4,6 +4,7 @@ package helium314.keyboard.keyboard.clipboard
import android.annotation.SuppressLint
import android.content.Context
import android.content.SharedPreferences
import android.util.AttributeSet
import android.util.TypedValue
import android.view.View
@ -34,6 +35,7 @@ import helium314.keyboard.latin.utils.createToolbarKey
import helium314.keyboard.latin.utils.getCodeForToolbarKey
import helium314.keyboard.latin.utils.getCodeForToolbarKeyLongClick
import helium314.keyboard.latin.utils.getEnabledClipboardToolbarKeys
import helium314.keyboard.latin.utils.setToolbarButtonsActivatedStateOnPrefChange
@SuppressLint("CustomViewStyleable")
class ClipboardHistoryView @JvmOverloads constructor(
@ -41,7 +43,8 @@ class ClipboardHistoryView @JvmOverloads constructor(
attrs: AttributeSet?,
defStyle: Int = R.attr.clipboardHistoryViewStyle
) : LinearLayout(context, attrs, defStyle), View.OnClickListener,
ClipboardHistoryManager.OnHistoryChangeListener, OnKeyEventListener, View.OnLongClickListener {
ClipboardHistoryManager.OnHistoryChangeListener, OnKeyEventListener,
View.OnLongClickListener, SharedPreferences.OnSharedPreferenceChangeListener {
private val clipboardLayoutParams = ClipboardLayoutParams(context)
private val pinIconId: Int
@ -65,10 +68,6 @@ class ClipboardHistoryView @JvmOverloads constructor(
keyBackgroundId = keyboardViewAttr.getResourceId(R.styleable.KeyboardView_keyBackground, 0)
keyboardViewAttr.recycle()
val keyboardAttr = context.obtainStyledAttributes(attrs, R.styleable.Keyboard, defStyle, R.style.SuggestionStripView)
// todo (maybe): setting the correct color only works because the activated state is inverted
// even when state is activated, the not activated color is set
// in suggestionStripView the same thing works correctly, wtf?
// need to properly fix it (and maybe undo the inverted isActivated) when adding a toggle key
getEnabledClipboardToolbarKeys(DeviceProtectedUtils.getSharedPreferences(context))
.forEach { toolbarKeys.add(createToolbarKey(context, KeyboardIconsSet.instance, it)) }
keyboardAttr.recycle()
@ -156,7 +155,8 @@ class ClipboardHistoryView @JvmOverloads constructor(
val params = KeyDrawParams()
params.updateParams(clipboardLayoutParams.bottomRowKeyboardHeight, keyVisualAttr)
Settings.getInstance().getCustomTypeface()?.let { params.mTypeface = it }
val settings = Settings.getInstance()
settings.getCustomTypeface()?.let { params.mTypeface = it }
setupClipKey(params)
setupBottomRowKeyboard(editorInfo, keyboardActionListener)
@ -167,8 +167,24 @@ class ClipboardHistoryView @JvmOverloads constructor(
}
clipboardRecyclerView.apply {
adapter = clipboardAdapter
layoutParams.width = ResourceUtils.getKeyboardWidth(context, Settings.getInstance().current)
val keyboardWidth = ResourceUtils.getKeyboardWidth(context, settings.current)
layoutParams.width = keyboardWidth
// set side padding
val keyboardAttr = context.obtainStyledAttributes(
null, R.styleable.Keyboard, R.attr.keyboardStyle, R.style.Keyboard);
val leftPadding = (keyboardAttr.getFraction(R.styleable.Keyboard_keyboardLeftPadding,
keyboardWidth, keyboardWidth, 0f)
* settings.current.mSidePaddingScale).toInt()
val rightPadding = (keyboardAttr.getFraction(R.styleable.Keyboard_keyboardRightPadding,
keyboardWidth, keyboardWidth, 0f)
* settings.current.mSidePaddingScale).toInt()
keyboardAttr.recycle()
setPadding(leftPadding, paddingTop, rightPadding, paddingBottom)
}
// absurd workaround so Android sets the correct color from stateList (depending on "activated")
toolbarKeys.forEach { it.isEnabled = false; it.isEnabled = true }
}
fun stopClipboardHistory() {
@ -233,4 +249,8 @@ class ClipboardHistoryView @JvmOverloads constructor(
clipboardAdapter.notifyItemChanged(to)
if (to < from) clipboardRecyclerView.smoothScrollToPosition(to)
}
}
override fun onSharedPreferenceChanged(prefs: SharedPreferences?, key: String?) {
setToolbarButtonsActivatedStateOnPrefChange(KeyboardSwitcher.getInstance().clipboardStrip, key)
}
}

View file

@ -173,6 +173,8 @@ final class EmojiCategory {
public void clearKeyboardCache() {
mCategoryKeyboardMap.clear();
for (CategoryProperties props: mShownCategories)
props.mPageCount = -1; // reset page count in case size (number of keys per row) changed
}
private void addShownCategoryId(final int categoryId) {

View file

@ -18,6 +18,7 @@ public final class EmojiCategoryPageIndicatorView extends View {
private int mCategoryPageSize = 0;
private int mCurrentCategoryPageId = 0;
private float mOffset = 0.0f;
int mWidth = 0;
public EmojiCategoryPageIndicatorView(final Context context, final AttributeSet attrs) {
this(context, attrs, 0);
@ -49,12 +50,13 @@ public final class EmojiCategoryPageIndicatorView extends View {
return;
}
final float height = getHeight();
final float width = getWidth();
final float leftPadding = getPaddingLeft();
final float width = mWidth - leftPadding - getPaddingRight();
final float unitWidth = width / mCategoryPageSize;
final float left = Math.min(unitWidth * mCurrentCategoryPageId + mOffset * unitWidth, width - unitWidth);
final float top = 0.0f;
final float right = Math.min(left + unitWidth, width);
final float bottom = height * BOTTOM_MARGIN_RATIO;
canvas.drawRect(left, top, right, bottom, mPaint);
canvas.drawRect(left + leftPadding, top, right + leftPadding, bottom, mPaint);
}
}

View file

@ -38,7 +38,7 @@ import helium314.keyboard.latin.RichInputMethodSubtype;
import helium314.keyboard.latin.common.ColorType;
import helium314.keyboard.latin.common.Colors;
import helium314.keyboard.latin.settings.Settings;
import helium314.keyboard.latin.utils.DeviceProtectedUtils;
import helium314.keyboard.latin.settings.SettingsValues;
import helium314.keyboard.latin.utils.ResourceUtils;
import org.jetbrains.annotations.NotNull;
@ -117,6 +117,7 @@ public final class EmojiPalettesView extends LinearLayout
+ getPaddingLeft() + getPaddingRight();
final int height = ResourceUtils.getKeyboardHeight(res, Settings.getInstance().getCurrent())
+ getPaddingTop() + getPaddingBottom();
mEmojiCategoryPageIndicatorView.mWidth = width;
setMeasuredDimension(width, height);
}
@ -272,6 +273,7 @@ public final class EmojiPalettesView extends LinearLayout
mEmojiRecyclerView.setAdapter(mEmojiPalettesAdapter);
setCurrentCategoryAndPageId(mEmojiCategory.getCurrentCategoryId(), mEmojiCategory.getCurrentCategoryPageId(), true);
}
setupSidePadding();
}
private void setupBottomRowKeyboard(final EditorInfo editorInfo, final KeyboardActionListener keyboardActionListener) {
@ -283,6 +285,31 @@ public final class EmojiPalettesView extends LinearLayout
keyboardView.setKeyboard(keyboard);
}
private void setupSidePadding() {
final SettingsValues sv = Settings.getInstance().getCurrent();
final int keyboardWidth = ResourceUtils.getKeyboardWidth(getContext(), sv);
final TypedArray keyboardAttr = getContext().obtainStyledAttributes(
null, R.styleable.Keyboard, R.attr.keyboardStyle, R.style.Keyboard);
final float leftPadding = keyboardAttr.getFraction(R.styleable.Keyboard_keyboardLeftPadding,
keyboardWidth, keyboardWidth, 0f) * sv.mSidePaddingScale;
final float rightPadding = keyboardAttr.getFraction(R.styleable.Keyboard_keyboardRightPadding,
keyboardWidth, keyboardWidth, 0f) * sv.mSidePaddingScale;
keyboardAttr.recycle();
mEmojiRecyclerView.setPadding(
(int) leftPadding,
mEmojiRecyclerView.getPaddingTop(),
(int) rightPadding,
mEmojiRecyclerView.getPaddingBottom()
);
mEmojiCategoryPageIndicatorView.setPadding(
(int) leftPadding,
mEmojiCategoryPageIndicatorView.getPaddingTop(),
(int) rightPadding,
mEmojiCategoryPageIndicatorView.getPaddingBottom()
);
// setting width does not do anything, so we have some workaround in EmojiCategoryPageIndicatorView
}
public void stopEmojiPalettes() {
if (!initialized) return;
mEmojiPalettesAdapter.releaseCurrentKey(true);

View file

@ -57,8 +57,8 @@ public class KeyPreviewView extends AppCompatTextView {
setCompoundDrawables(null, null, null, null);
setTextColor(drawParams.mPreviewTextColor);
setTextSize(TypedValue.COMPLEX_UNIT_PX, key.selectPreviewTextSize(drawParams));
// wie hier machen?
setTextSize(TypedValue.COMPLEX_UNIT_PX, key.selectPreviewTextSize(drawParams)
* Settings.getInstance().getCurrent().mFontSizeMultiplier);
setTypeface(mTypeface == null ? key.selectPreviewTypeface(drawParams) : mTypeface);
// TODO Should take care of temporaryShiftLabel here.
setTextAndScaleX(key.getPreviewLabel());

View file

@ -52,8 +52,9 @@ public final class KeyboardCodesSet {
"key_emoji",
"key_unspecified",
"key_clipboard",
"key_start_onehanded",
"key_stop_onehanded",
"key_toggle_onehanded",
"key_start_onehanded", // keep name to avoid breaking custom layouts
"key_stop_onehanded", // keep name to avoid breaking custom layouts
"key_switch_onehanded"
};
@ -77,8 +78,9 @@ public final class KeyboardCodesSet {
KeyCode.EMOJI,
KeyCode.NOT_SPECIFIED,
KeyCode.CLIPBOARD,
KeyCode.START_ONE_HANDED_MODE,
KeyCode.STOP_ONE_HANDED_MODE,
KeyCode.TOGGLE_ONE_HANDED_MODE,
KeyCode.TOGGLE_ONE_HANDED_MODE,
KeyCode.TOGGLE_ONE_HANDED_MODE,
KeyCode.SWITCH_ONE_HANDED_MODE
};

View file

@ -225,10 +225,12 @@ public class KeyboardParams {
mBottomPadding = (int) (keyboardAttr.getFraction(
R.styleable.Keyboard_keyboardBottomPadding, height, height, 0)
* Settings.getInstance().getCurrent().mBottomPaddingScale);
mLeftPadding = (int) keyboardAttr.getFraction(
R.styleable.Keyboard_keyboardLeftPadding, width, width, 0);
mRightPadding = (int) keyboardAttr.getFraction(
R.styleable.Keyboard_keyboardRightPadding, width, width, 0);
mLeftPadding = (int) (keyboardAttr.getFraction(
R.styleable.Keyboard_keyboardLeftPadding, width, width, 0)
* Settings.getInstance().getCurrent().mSidePaddingScale);
mRightPadding = (int) (keyboardAttr.getFraction(
R.styleable.Keyboard_keyboardRightPadding, width, width, 0)
* Settings.getInstance().getCurrent().mSidePaddingScale);
mBaseWidth = mOccupiedWidth - mLeftPadding - mRightPadding;
final float defaultKeyWidthFactor = context.getResources().getInteger(R.integer.config_screen_metrics) > 2 ? 0.9f : 1f;
@ -238,7 +240,6 @@ public class KeyboardParams {
mDefaultAbsoluteKeyWidth = (int) (mDefaultKeyWidth * mBaseWidth);
mAbsolutePopupKeyWidth = (int) (alphaSymbolKeyWidth * mBaseWidth);
// todo: maybe settings should not be accessed from here?
if (Settings.getInstance().getCurrent().mNarrowKeyGaps) {
mRelativeHorizontalGap = keyboardAttr.getFraction(
R.styleable.Keyboard_horizontalGapNarrow, 1, 1, 0);

View file

@ -808,10 +808,8 @@ public final class KeyboardState {
toggleNumpad(false, autoCapsFlags, recapitalizeMode, false, true);
} else if (code == KeyCode.SYMBOL) {
setSymbolsKeyboard();
} else if (code == KeyCode.START_ONE_HANDED_MODE) {
setOneHandedModeEnabled(true);
} else if (code == KeyCode.STOP_ONE_HANDED_MODE) {
setOneHandedModeEnabled(false);
} else if (code == KeyCode.TOGGLE_ONE_HANDED_MODE) {
setOneHandedModeEnabled(!Settings.getInstance().getCurrent().mOneHandedModeEnabled);
} else if (code == KeyCode.SWITCH_ONE_HANDED_MODE) {
switchOneHandedMode();
}

View file

@ -42,7 +42,8 @@ class EmojiParser(private val params: KeyboardParams, private val context: Conte
// determine key width for default settings (no number row, no one-handed mode, 100% height and bottom padding scale)
// this is a bit long, but ensures that emoji size stays the same, independent of these settings
val defaultKeyWidth = (ResourceUtils.getDefaultKeyboardWidth(context) - params.mLeftPadding - params.mRightPadding) * params.mDefaultKeyWidth
// we also ignore side padding for key width, and prefer fewer keys per row over narrower keys
val defaultKeyWidth = ResourceUtils.getDefaultKeyboardWidth(context) * params.mDefaultKeyWidth
val keyWidth = defaultKeyWidth * sqrt(Settings.getInstance().current.mKeyboardHeightScale)
val defaultKeyboardHeight = ResourceUtils.getDefaultKeyboardHeight(context.resources, false)
val defaultBottomPadding = context.resources.getFraction(R.fraction.config_keyboard_bottom_padding_holo, defaultKeyboardHeight, defaultKeyboardHeight)

View file

@ -17,12 +17,10 @@ import helium314.keyboard.keyboard.internal.keyboard_parser.floris.TextKeyData
import helium314.keyboard.latin.common.isEmoji
import helium314.keyboard.latin.define.DebugFlags
import helium314.keyboard.latin.settings.Settings
import helium314.keyboard.latin.utils.CUSTOM_LAYOUT_PREFIX
import helium314.keyboard.latin.utils.POPUP_KEYS_LAYOUT
import helium314.keyboard.latin.utils.POPUP_KEYS_NUMBER
import helium314.keyboard.latin.utils.ScriptUtils
import helium314.keyboard.latin.utils.ScriptUtils.script
import helium314.keyboard.latin.utils.getCustomLayoutFiles
import helium314.keyboard.latin.utils.replaceFirst
import helium314.keyboard.latin.utils.splitAt
import helium314.keyboard.latin.utils.sumOf
@ -88,9 +86,11 @@ class KeyboardParser(private val params: KeyboardParams, private val context: Co
addNumberRowOrPopupKeys(baseKeys, numberRow)
if (params.mId.isAlphabetKeyboard)
addSymbolPopupKeys(baseKeys)
if (params.mId.isAlphaOrSymbolKeyboard && params.mId.mNumberRowEnabled)
baseKeys.add(0, numberRow
.mapTo(mutableListOf()) { it.copy(newLabelFlags = Key.LABEL_FLAGS_DISABLE_HINT_LABEL or defaultLabelFlags) })
if (params.mId.isAlphaOrSymbolKeyboard && params.mId.mNumberRowEnabled) {
val newLabelFlags = defaultLabelFlags or
if (Settings.getInstance().current.mShowNumberRowHints) 0 else Key.LABEL_FLAGS_DISABLE_HINT_LABEL
baseKeys.add(0, numberRow.mapTo(mutableListOf()) { it.copy(newLabelFlags = newLabelFlags) })
}
if (!params.mAllowRedundantPopupKeys)
params.baseKeys = baseKeys.flatMap { it.map { it.toKeyParams(params) } }

View file

@ -125,8 +125,8 @@ object KeyCode {
// heliboard only codes
const val SYMBOL_ALPHA = -10001
const val START_ONE_HANDED_MODE = -10002
const val STOP_ONE_HANDED_MODE = -10003
const val TOGGLE_ONE_HANDED_MODE = -10002
const val TOGGLE_ONE_HANDED_MODE_2 = -10003 // does the same as TOGGLE_ONE_HANDED_MODE (used to be start & stop)
const val SWITCH_ONE_HANDED_MODE = -10004
const val SHIFT_ENTER = -10005
const val ACTION_NEXT = -10006
@ -179,7 +179,7 @@ object KeyCode {
FN, CLIPBOARD_CLEAR_HISTORY, NUMPAD,
// heliboard only
SYMBOL_ALPHA, START_ONE_HANDED_MODE, STOP_ONE_HANDED_MODE, SWITCH_ONE_HANDED_MODE, SHIFT_ENTER,
SYMBOL_ALPHA, TOGGLE_ONE_HANDED_MODE, SWITCH_ONE_HANDED_MODE, SHIFT_ENTER,
ACTION_NEXT, ACTION_PREVIOUS, NOT_SPECIFIED, CLIPBOARD_COPY_ALL, WORD_LEFT, WORD_RIGHT, PAGE_UP,
PAGE_DOWN, META, TAB, ESCAPE, INSERT, SLEEP, MEDIA_PLAY, MEDIA_PAUSE, MEDIA_PLAY_PAUSE, MEDIA_NEXT,
MEDIA_PREVIOUS, VOL_UP, VOL_DOWN, MUTE, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, BACK
@ -189,6 +189,7 @@ object KeyCode {
IME_UI_MODE_TEXT -> ALPHA
VIEW_PHONE -> ALPHA // phone keyboard is treated like alphabet, just with different layout
VIEW_PHONE2 -> SYMBOL
TOGGLE_ONE_HANDED_MODE_2 -> TOGGLE_ONE_HANDED_MODE
else -> throw IllegalStateException("key code $this not yet supported")
}

View file

@ -127,7 +127,7 @@ sealed interface KeyData : AbstractKeyData {
if (!params.mId.mLanguageSwitchKeyEnabled && !params.mId.isNumberLayout && RichInputMethodManager.canSwitchLanguage())
keys.add("!icon/language_switch_key|!code/key_language_switch")
if (!params.mId.mOneHandedModeEnabled)
keys.add("!icon/start_onehanded_mode_key|!code/key_start_onehanded")
keys.add("!icon/start_onehanded_mode_key|!code/key_toggle_onehanded")
if (!params.mId.mDeviceLocked)
keys.add("!icon/settings_key|!code/key_settings")
return keys

View file

@ -84,8 +84,7 @@ class KeyboardWrapperView @JvmOverloads constructor(
if (newScale == oldScale) return@setOnTouchListener true
Settings.getInstance().writeOneHandedModeScale(newScale)
oneHandedModeEnabled = false // intentionally putting wrong value, so KeyboardSwitcher.setOneHandedModeEnabled does actually reload
keyboardActionListener?.onCodeInput(KeyCode.START_ONE_HANDED_MODE,
Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE, false)
KeyboardSwitcher.getInstance().setOneHandedModeEnabled(true)
}
else -> x = 0f
}
@ -119,7 +118,7 @@ class KeyboardWrapperView @JvmOverloads constructor(
override fun onClick(view: View) {
if (view === stopOneHandedModeBtn) {
keyboardActionListener?.onCodeInput(KeyCode.STOP_ONE_HANDED_MODE,
keyboardActionListener?.onCodeInput(KeyCode.TOGGLE_ONE_HANDED_MODE,
Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE,
false /* isKeyRepeat */)
} else if (view === switchOneHandedModeBtn) {

View file

@ -150,7 +150,11 @@ class DynamicColors(context: Context, override val themeStyle: String, override
private val spaceBarStateList: ColorStateList
private val adjustedBackgroundStateList: ColorStateList
private val stripBackgroundList: ColorStateList
private val toolbarKeyStateList = activatedStateList(keyText, darken(darken(keyText)))
private val toolbarKeyStateList = activatedStateList(
keyText,
if (isBrightColor(keyText)) darken(darken(keyText))
else brighten(brighten(keyText))
)
/** darkened variant of [accent] because the accent color is always light for dynamic colors */
private val adjustedAccent: Int = darken(accent)
@ -195,12 +199,12 @@ class DynamicColors(context: Context, override val themeStyle: String, override
}
adjustedBackgroundStateList =
if (themeStyle == STYLE_HOLO) {
stateList(accent, adjustedBackground)
pressedStateList(accent, adjustedBackground)
} else if (isNight) {
if (hasKeyBorders) stateList(doubleAdjustedAccent, keyBackground)
else stateList(adjustedAccent, adjustedKeyBackground)
if (hasKeyBorders) pressedStateList(doubleAdjustedAccent, keyBackground)
else pressedStateList(adjustedAccent, adjustedKeyBackground)
} else {
stateList(accent, Color.WHITE)
pressedStateList(accent, Color.WHITE)
}
val stripBackground = if (keyboardBackground == null && !hasKeyBorders) {
@ -210,7 +214,7 @@ class DynamicColors(context: Context, override val themeStyle: String, override
}
val pressedStripElementBackground = if (keyboardBackground == null) adjustedBackground
else if (isDarkColor(background)) 0x22ffffff else 0x11000000
stripBackgroundList = stateList(pressedStripElementBackground, stripBackground)
stripBackgroundList = pressedStateList(pressedStripElementBackground, stripBackground)
adjustedBackgroundFilter =
if (themeStyle == STYLE_HOLO) colorFilter(adjustedBackground)
@ -218,47 +222,47 @@ class DynamicColors(context: Context, override val themeStyle: String, override
if (hasKeyBorders) {
backgroundStateList =
if (!isNight) stateList(adjustedFunctionalKey, background)
else stateList(adjustedKeyBackground, background)
if (!isNight) pressedStateList(adjustedFunctionalKey, background)
else pressedStateList(adjustedKeyBackground, background)
keyStateList =
if (!isNight) stateList(adjustedBackground, keyBackground)
else stateList(adjustedKeyBackground, keyBackground)
if (!isNight) pressedStateList(adjustedBackground, keyBackground)
else pressedStateList(adjustedKeyBackground, keyBackground)
functionalKeyStateList =
if (!isNight) stateList(doubleAdjustedFunctionalKey, functionalKey)
else stateList(functionalKey, doubleAdjustedKeyBackground)
if (!isNight) pressedStateList(doubleAdjustedFunctionalKey, functionalKey)
else pressedStateList(functionalKey, doubleAdjustedKeyBackground)
actionKeyStateList =
if (!isNight) stateList(gesture, accent)
else stateList(doubleAdjustedAccent, accent)
if (!isNight) pressedStateList(gesture, accent)
else pressedStateList(doubleAdjustedAccent, accent)
spaceBarStateList =
if (themeStyle == STYLE_HOLO) stateList(spaceBar, spaceBar)
if (themeStyle == STYLE_HOLO) pressedStateList(spaceBar, spaceBar)
else keyStateList
} else {
// need to set color to background if key borders are disabled, or there will be ugly keys
backgroundStateList =
if (!isNight) stateList(adjustedFunctionalKey, background)
else stateList(adjustedKeyBackground, background)
if (!isNight) pressedStateList(adjustedFunctionalKey, background)
else pressedStateList(adjustedKeyBackground, background)
keyStateList =
if (!isNight) stateList(adjustedFunctionalKey, Color.TRANSPARENT)
else stateList(functionalKey, Color.TRANSPARENT)
if (!isNight) pressedStateList(adjustedFunctionalKey, Color.TRANSPARENT)
else pressedStateList(functionalKey, Color.TRANSPARENT)
functionalKeyStateList =
if (themeStyle == STYLE_HOLO) stateList(functionalKey, Color.TRANSPARENT)
if (themeStyle == STYLE_HOLO) pressedStateList(functionalKey, Color.TRANSPARENT)
else keyStateList
actionKeyStateList =
if (themeStyle == STYLE_HOLO) stateList(accent, Color.TRANSPARENT)
else if (!isNight) stateList(gesture, accent)
else stateList(doubleAdjustedAccent, accent)
if (themeStyle == STYLE_HOLO) pressedStateList(accent, Color.TRANSPARENT)
else if (!isNight) pressedStateList(gesture, accent)
else pressedStateList(doubleAdjustedAccent, accent)
spaceBarStateList =
if (!isNight) stateList(gesture, adjustedFunctionalKey)
else stateList(adjustedKeyBackground, spaceBar)
if (!isNight) pressedStateList(gesture, adjustedFunctionalKey)
else pressedStateList(adjustedKeyBackground, spaceBar)
}
keyTextFilter = colorFilter(keyText)
@ -398,7 +402,11 @@ class DefaultColors (
private val spaceBarStateList: ColorStateList
private val adjustedBackgroundStateList: ColorStateList
private val stripBackgroundList: ColorStateList
private val toolbarKeyStateList = activatedStateList(suggestionText, darken(darken(suggestionText)))
private val toolbarKeyStateList = activatedStateList(
suggestionText,
if (isBrightColor(suggestionText)) darken(darken(suggestionText))
else brighten(brighten(suggestionText))
)
private var backgroundSetupDone = false
init {
@ -409,7 +417,7 @@ class DefaultColors (
adjustedBackground = darken(background)
doubleAdjustedBackground = darken(adjustedBackground)
}
adjustedBackgroundStateList = stateList(doubleAdjustedBackground, adjustedBackground)
adjustedBackgroundStateList = pressedStateList(doubleAdjustedBackground, adjustedBackground)
val stripBackground: Int
val pressedStripElementBackground: Int
@ -424,7 +432,7 @@ class DefaultColors (
stripBackground = adjustedBackground
pressedStripElementBackground = doubleAdjustedBackground
}
stripBackgroundList = stateList(pressedStripElementBackground, stripBackground)
stripBackgroundList = pressedStateList(pressedStripElementBackground, stripBackground)
if (themeStyle == STYLE_HOLO && keyboardBackground == null) {
val darkerBackground = adjustLuminosityAndKeepAlpha(background, -0.2f)
@ -437,22 +445,22 @@ class DefaultColors (
adjustedBackgroundFilter = colorFilter(adjustedBackground)
if (hasKeyBorders) {
backgroundStateList = stateList(brightenOrDarken(background, true), background)
keyStateList = if (themeStyle == STYLE_HOLO) stateList(keyBackground, keyBackground)
else stateList(brightenOrDarken(keyBackground, true), keyBackground)
functionalKeyStateList = stateList(brightenOrDarken(functionalKey, true), functionalKey)
backgroundStateList = pressedStateList(brightenOrDarken(background, true), background)
keyStateList = if (themeStyle == STYLE_HOLO) pressedStateList(keyBackground, keyBackground)
else pressedStateList(brightenOrDarken(keyBackground, true), keyBackground)
functionalKeyStateList = pressedStateList(brightenOrDarken(functionalKey, true), functionalKey)
actionKeyStateList = if (themeStyle == STYLE_HOLO) functionalKeyStateList
else stateList(brightenOrDarken(accent, true), accent)
spaceBarStateList = if (themeStyle == STYLE_HOLO) stateList(spaceBar, spaceBar)
else stateList(brightenOrDarken(spaceBar, true), spaceBar)
else pressedStateList(brightenOrDarken(accent, true), accent)
spaceBarStateList = if (themeStyle == STYLE_HOLO) pressedStateList(spaceBar, spaceBar)
else pressedStateList(brightenOrDarken(spaceBar, true), spaceBar)
} else {
// need to set color to background if key borders are disabled, or there will be ugly keys
backgroundStateList = stateList(brightenOrDarken(background, true), background)
keyStateList = stateList(keyBackground, Color.TRANSPARENT)
backgroundStateList = pressedStateList(brightenOrDarken(background, true), background)
keyStateList = pressedStateList(keyBackground, Color.TRANSPARENT)
functionalKeyStateList = keyStateList
actionKeyStateList = if (themeStyle == STYLE_HOLO) functionalKeyStateList
else stateList(brightenOrDarken(accent, true), accent)
spaceBarStateList = stateList(brightenOrDarken(spaceBar, true), spaceBar)
else pressedStateList(brightenOrDarken(accent, true), accent)
spaceBarStateList = pressedStateList(brightenOrDarken(spaceBar, true), spaceBar)
}
keyTextFilter = colorFilter(keyText)
actionKeyIconColorFilter = when {
@ -556,7 +564,7 @@ class AllColors(private val colorMap: EnumMap<ColorType, Int>, override val them
override fun get(color: ColorType): Int = colorMap[color] ?: color.default()
override fun setColor(drawable: Drawable, color: ColorType) {
val colorStateList = stateListMap.getOrPut(color) { stateList(brightenOrDarken(get(color), true), get(color)) }
val colorStateList = stateListMap.getOrPut(color) { pressedStateList(brightenOrDarken(get(color), true), get(color)) }
DrawableCompat.setTintMode(drawable, PorterDuff.Mode.MULTIPLY)
DrawableCompat.setTintList(drawable, colorStateList)
}
@ -621,14 +629,14 @@ private fun colorFilter(color: Int, mode: BlendModeCompat = BlendModeCompat.MODU
return BlendModeColorFilterCompat.createBlendModeColorFilterCompat(color, mode)!!
}
private fun stateList(pressed: Int, normal: Int): ColorStateList {
private fun pressedStateList(pressed: Int, normal: Int): ColorStateList {
val states = arrayOf(intArrayOf(android.R.attr.state_pressed), intArrayOf(-android.R.attr.state_pressed))
return ColorStateList(states, intArrayOf(pressed, normal))
}
private fun activatedStateList(normal: Int, activated: Int): ColorStateList {
val states = arrayOf(intArrayOf(-android.R.attr.state_activated), intArrayOf(android.R.attr.state_activated))
return ColorStateList(states, intArrayOf(normal, activated))
private fun activatedStateList(activated: Int, normal: Int): ColorStateList {
val states = arrayOf(intArrayOf(android.R.attr.state_activated), intArrayOf(-android.R.attr.state_activated))
return ColorStateList(states, intArrayOf(activated, normal))
}
enum class ColorType {

View file

@ -224,8 +224,7 @@ public final class Constants {
case CODE_TAB: return "tab";
case CODE_ENTER: return "enter";
case CODE_SPACE: return "space";
case KeyCode.START_ONE_HANDED_MODE: return "startOneHandedMode";
case KeyCode.STOP_ONE_HANDED_MODE: return "stopOneHandedMode";
case KeyCode.TOGGLE_ONE_HANDED_MODE: return "toggleOneHandedMode";
case KeyCode.SWITCH_ONE_HANDED_MODE: return "switchOneHandedMode";
case KeyCode.NUMPAD: return "numpad";
default:

View file

@ -62,21 +62,32 @@ fun getFullEmojiAtEnd(s: CharSequence): String {
while (offset > 0) {
val codepoint = text.codePointBefore(offset)
// stop if codepoint can't be emoji
if (!mightBeEmoji(codepoint)) return ""
if (!mightBeEmoji(codepoint))
return text.substring(offset)
offset -= Character.charCount(codepoint)
// todo: if codepoint in 0x1F3FB..0x1F3FF -> combine with other emojis in front, but only if they actually combine
// why isn't this done with zwj like everything else? skin tones can be emojis by themselves...
if (offset > 0 && text[offset - 1].code == KeyCode.ZWJ) {
// todo: this appends ZWJ in weird cases like text, ZWJ, emoji
// and detects single ZWJ as emoji (at least irrelevant for current use of getFullEmojiAtEnd)
offset -= 1
continue
}
if (codepoint in 0x1F3FB..0x1F3FF) {
// Skin tones are not added with ZWJ, but just appended. This is not nice as they can be emojis on their own,
// but that's how it is done. Assume that an emoji before the skin tone will get merged (usually correct in practice)
val codepointBefore = text.codePointBefore(offset)
if (isEmoji(codepointBefore)) {
offset -= Character.charCount(codepointBefore)
continue
}
}
// check the whole text after offset
val textToCheck = text.substring(offset)
if (isEmoji(textToCheck)) {
return textToCheck
}
}
return ""
return text.substring(offset)
}
/** split the string on the first of consecutive space only, further consecutive spaces are added to the next split */

View file

@ -779,7 +779,7 @@ public final class InputLogic {
// We need to switch to the shortcut IME. This is handled by LatinIME since the
// input logic has no business with IME switching.
case KeyCode.CAPS_LOCK, KeyCode.SYMBOL_ALPHA, KeyCode.ALPHA, KeyCode.SYMBOL, KeyCode.NUMPAD, KeyCode.EMOJI,
KeyCode.START_ONE_HANDED_MODE, KeyCode.STOP_ONE_HANDED_MODE, KeyCode.SWITCH_ONE_HANDED_MODE,
KeyCode.TOGGLE_ONE_HANDED_MODE, KeyCode.SWITCH_ONE_HANDED_MODE,
KeyCode.CTRL, KeyCode.ALT, KeyCode.FN, KeyCode.META:
break;
default:
@ -1212,7 +1212,12 @@ public final class InputLogic {
}
return;
}
if (mEnteredText != null && mConnection.sameAsTextBeforeCursor(mEnteredText)) {
// todo: this is currently disabled, as it causes inconsistencies with textInput, depending whether the end
// is part of a word (where we start composing) or not (where we end in code below)
// see https://github.com/Helium314/HeliBoard/issues/1019
// with better emoji detection on backspace (getFullEmojiAtEnd), this functionality might not be necessary
// -> enable again if there are issues, otherwise delete the code, together with mEnteredText
if (false && mEnteredText != null && mConnection.sameAsTextBeforeCursor(mEnteredText)) {
// Cancel multi-character input: remove the text we just entered.
// This is triggered on backspace after a key that inputs multiple characters,
// like the smiley key or the .com key.

View file

@ -25,6 +25,7 @@ import androidx.preference.PreferenceManager
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import helium314.keyboard.dictionarypack.DictionaryPackConstants
import helium314.keyboard.keyboard.KeyboardActionListener
import helium314.keyboard.latin.utils.ChecksumCalculator
import helium314.keyboard.keyboard.KeyboardLayoutSet
import helium314.keyboard.keyboard.KeyboardSwitcher
@ -125,6 +126,8 @@ class AdvancedSettingsFragment : SubScreenFragment() {
}
setupKeyLongpressTimeoutSettings()
setupEmojiSdkSetting()
setupLanguageSwipeDistanceSettings()
updateLangSwipeDistanceVisibility(sharedPreferences)
findPreference<Preference>("load_gesture_library")?.setOnPreferenceClickListener { onClickLoadLibrary() }
findPreference<Preference>("backup_restore")?.setOnPreferenceClickListener { showBackupRestoreDialog() }
@ -560,10 +563,37 @@ class AdvancedSettingsFragment : SubScreenFragment() {
})
}
private fun setupLanguageSwipeDistanceSettings() {
val prefs = sharedPreferences
findPreference<SeekBarDialogPreference>(Settings.PREF_LANGUAGE_SWIPE_DISTANCE)?.setInterface(object : ValueProxy {
override fun writeValue(value: Int, key: String) = prefs.edit().putInt(key, value).apply()
override fun writeDefaultValue(key: String) = prefs.edit().remove(key).apply()
override fun readValue(key: String) = Settings.readLanguageSwipeDistance(prefs, resources)
override fun readDefaultValue(key: String) = Settings.readDefaultLanguageSwipeDistance(resources)
override fun getValueText(value: Int) = value.toString()
override fun feedbackValue(value: Int) {}
})
}
private fun updateLangSwipeDistanceVisibility(prefs: SharedPreferences) {
val horizontalSpaceSwipe = Settings.readHorizontalSpaceSwipe(prefs)
val verticalSpaceSwipe = Settings.readVerticalSpaceSwipe(prefs)
val visibility = horizontalSpaceSwipe == KeyboardActionListener.SWIPE_SWITCH_LANGUAGE
|| verticalSpaceSwipe == KeyboardActionListener.SWIPE_SWITCH_LANGUAGE
setPreferenceVisible(Settings.PREF_LANGUAGE_SWIPE_DISTANCE, visibility)
}
override fun onSharedPreferenceChanged(prefs: SharedPreferences, key: String?) {
when (key) {
Settings.PREF_SHOW_SETUP_WIZARD_ICON -> SystemBroadcastReceiver.toggleAppIcon(requireContext())
Settings.PREF_MORE_POPUP_KEYS -> KeyboardLayoutSet.onSystemLocaleChanged()
Settings.PREF_SPACE_HORIZONTAL_SWIPE -> updateLangSwipeDistanceVisibility(prefs)
Settings.PREF_SPACE_VERTICAL_SWIPE -> updateLangSwipeDistanceVisibility(prefs)
Settings.PREF_EMOJI_MAX_SDK -> KeyboardSwitcher.getInstance().forceUpdateKeyboardTheme(requireContext())
}
}

View file

@ -105,6 +105,11 @@ class AppearanceSettingsFragment : SubScreenFragment() {
setupScalePrefs(Settings.PREF_KEYBOARD_HEIGHT_SCALE, SettingsValues.DEFAULT_SIZE_SCALE)
setupScalePrefs(Settings.PREF_BOTTOM_PADDING_SCALE, SettingsValues.DEFAULT_SIZE_SCALE)
setupScalePrefs(Settings.PREF_BOTTOM_PADDING_SCALE_LANDSCAPE, 0f)
setupScalePrefs(Settings.PREF_FONT_SCALE, SettingsValues.DEFAULT_SIZE_SCALE)
setupScalePrefs(Settings.PREF_EMOJI_FONT_SCALE, SettingsValues.DEFAULT_SIZE_SCALE)
setupScalePrefs(Settings.PREF_SIDE_PADDING_SCALE, 0f)
setupScalePrefs(Settings.PREF_SIDE_PADDING_SCALE_LANDSCAPE, 0f)
if (splitScalePref != null) {
setupScalePrefs(Settings.PREF_SPLIT_SPACER_SCALE, SettingsValues.DEFAULT_SIZE_SCALE)
splitScalePref?.isVisible = splitPref?.isChecked == true

View file

@ -54,6 +54,7 @@ public final class PreferencesSettingsFragment extends SubScreenFragment {
setupHistoryRetentionTimeSettings();
refreshEnablingsOfKeypressSoundAndVibrationAndHistRetentionSettings();
setLocalizedNumberRowVisibility();
setNumberRowHintsVisibility();
findPreference(Settings.PREF_POPUP_KEYS_LABELS_ORDER).setVisible(getSharedPreferences().getBoolean(Settings.PREF_SHOW_HINTS, false));
findPreference(Settings.PREF_POPUP_KEYS_ORDER).setOnPreferenceClickListener((pref) -> {
DialogUtilsKt.reorderDialog(requireContext(), Settings.PREF_POPUP_KEYS_ORDER,
@ -77,12 +78,18 @@ public final class PreferencesSettingsFragment extends SubScreenFragment {
refreshEnablingsOfKeypressSoundAndVibrationAndHistRetentionSettings();
if (key == null) return;
switch (key) {
case Settings.PREF_POPUP_KEYS_ORDER, Settings.PREF_SHOW_POPUP_HINTS, Settings.PREF_SHOW_NUMBER_ROW,
case Settings.PREF_POPUP_KEYS_ORDER, Settings.PREF_SHOW_POPUP_HINTS, Settings.PREF_SHOW_NUMBER_ROW_HINTS,
Settings.PREF_POPUP_KEYS_LABELS_ORDER, Settings.PREF_LANGUAGE_SWITCH_KEY,
Settings.PREF_SHOW_LANGUAGE_SWITCH_KEY , Settings.PREF_REMOVE_REDUNDANT_POPUPS-> mReloadKeyboard = true;
Settings.PREF_SHOW_LANGUAGE_SWITCH_KEY, Settings.PREF_REMOVE_REDUNDANT_POPUPS -> mReloadKeyboard = true;
case Settings.PREF_SHOW_NUMBER_ROW -> {
setNumberRowHintsVisibility();
mReloadKeyboard = true;
}
case Settings.PREF_LOCALIZED_NUMBER_ROW -> KeyboardLayoutSet.onSystemLocaleChanged();
case Settings.PREF_SHOW_HINTS
-> findPreference(Settings.PREF_POPUP_KEYS_LABELS_ORDER).setVisible(prefs.getBoolean(Settings.PREF_SHOW_HINTS, false));
case Settings.PREF_SHOW_HINTS -> {
findPreference(Settings.PREF_POPUP_KEYS_LABELS_ORDER).setVisible(prefs.getBoolean(Settings.PREF_SHOW_HINTS, false));
setNumberRowHintsVisibility();
}
}
}
@ -108,6 +115,12 @@ public final class PreferencesSettingsFragment extends SubScreenFragment {
pref.setVisible(false);
}
private void setNumberRowHintsVisibility() {
var prefs = getSharedPreferences();
setPreferenceVisible(Settings.PREF_SHOW_NUMBER_ROW_HINTS, prefs.getBoolean(Settings.PREF_SHOW_HINTS, false)
&& prefs.getBoolean(Settings.PREF_SHOW_NUMBER_ROW, false));
}
private void refreshEnablingsOfKeypressSoundAndVibrationAndHistRetentionSettings() {
final SharedPreferences prefs = getSharedPreferences();
final Resources res = getResources();

View file

@ -112,6 +112,11 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
public static final String PREF_SPLIT_SPACER_SCALE = "split_spacer_scale";
public static final String PREF_KEYBOARD_HEIGHT_SCALE = "keyboard_height_scale";
public static final String PREF_BOTTOM_PADDING_SCALE = "bottom_padding_scale";
public static final String PREF_BOTTOM_PADDING_SCALE_LANDSCAPE = "bottom_padding_scale_landscape";
public static final String PREF_SIDE_PADDING_SCALE = "side_padding_scale";
public static final String PREF_SIDE_PADDING_SCALE_LANDSCAPE = "side_padding_scale_landscape";
public static final String PREF_FONT_SCALE = "font_scale";
public static final String PREF_EMOJI_FONT_SCALE = "emoji_font_scale";
public static final String PREF_SPACE_HORIZONTAL_SWIPE = "horizontal_space_swipe";
public static final String PREF_SPACE_VERTICAL_SWIPE = "vertical_space_swipe";
public static final String PREF_DELETE_SWIPE = "delete_swipe";
@ -142,6 +147,7 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
public static final String PREF_SHOW_NUMBER_ROW = "show_number_row";
public static final String PREF_LOCALIZED_NUMBER_ROW = "localized_number_row";
public static final String PREF_SHOW_NUMBER_ROW_HINTS = "show_number_row_hints";
public static final String PREF_CUSTOM_CURRENCY_KEY = "custom_currency_key";
public static final String PREF_SHOW_HINTS = "show_hints";
@ -151,6 +157,7 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
public static final String PREF_MORE_POPUP_KEYS = "more_popup_keys";
public static final String PREF_SPACE_TO_CHANGE_LANG = "prefs_long_press_keyboard_to_change_lang";
public static final String PREF_LANGUAGE_SWIPE_DISTANCE = "language_swipe_distance";
public static final String PREF_ENABLE_CLIPBOARD_HISTORY = "enable_clipboard_history";
public static final String PREF_CLIPBOARD_HISTORY_RETENTION_TIME = "clipboard_history_retention_time";
@ -447,6 +454,18 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
};
}
public static int readLanguageSwipeDistance(final SharedPreferences prefs,
final Resources res) {
final int sensitivity = prefs.getInt(
PREF_LANGUAGE_SWIPE_DISTANCE, UNDEFINED_PREFERENCE_VALUE_INT);
return (sensitivity != UNDEFINED_PREFERENCE_VALUE_INT) ? sensitivity
: readDefaultLanguageSwipeDistance(res);
}
public static int readDefaultLanguageSwipeDistance(final Resources res) {
return 5;
}
public static boolean readDeleteSwipeEnabled(final SharedPreferences prefs) {
return prefs.getBoolean(PREF_DELETE_SWIPE, true);
}
@ -499,6 +518,18 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
(getCurrent().mDisplayOrientation == Configuration.ORIENTATION_PORTRAIT), gravity).apply();
}
public static float readBottomPaddingScale(final SharedPreferences prefs, final boolean landscape) {
if (landscape)
return prefs.getFloat(PREF_BOTTOM_PADDING_SCALE_LANDSCAPE, 0f);
return prefs.getFloat(PREF_BOTTOM_PADDING_SCALE, SettingsValues.DEFAULT_SIZE_SCALE);
}
public static float readSidePaddingScale(final SharedPreferences prefs, final boolean landscape) {
if (landscape)
return prefs.getFloat(PREF_SIDE_PADDING_SCALE_LANDSCAPE, 0f);
return prefs.getFloat(PREF_SIDE_PADDING_SCALE, 0f);
}
public static boolean readHasHardwareKeyboard(final Configuration conf) {
// The standard way of finding out whether we have a hardware keyboard. This code is taken
// from InputMethodService#onEvaluateInputShown, which canonically determines this.

View file

@ -70,6 +70,7 @@ public class SettingsValues {
private final boolean mShowsLanguageSwitchKey;
public final boolean mShowsNumberRow;
public final boolean mLocalizedNumberRow;
public final boolean mShowNumberRowHints;
public final boolean mShowsHints;
public final boolean mShowsPopupHints;
public final boolean mSpaceForLangChange;
@ -80,6 +81,7 @@ public class SettingsValues {
public final boolean mBlockPotentiallyOffensive;
public final int mSpaceSwipeHorizontal;
public final int mSpaceSwipeVertical;
public final int mLanguageSwipeDistance;
public final boolean mDeleteSwipeEnabled;
public final boolean mAutospaceAfterPunctuationEnabled;
public final boolean mClipboardHistoryEnabled;
@ -113,6 +115,7 @@ public class SettingsValues {
public final float mKeyboardHeightScale;
public final boolean mUrlDetectionEnabled;
public final float mBottomPaddingScale;
public final float mSidePaddingScale;
public final boolean mAutoShowToolbar;
public final boolean mAutoHideToolbar;
public final boolean mAlphaAfterEmojiInEmojiView;
@ -120,6 +123,8 @@ public class SettingsValues {
public final boolean mAlphaAfterSymbolAndSpace;
public final boolean mRemoveRedundantPopups;
public final String mSpaceBarText;
public final float mFontSizeMultiplier;
public final float mFontSizeMultiplierEmoji;
// From the input box
@NonNull
@ -171,6 +176,7 @@ public class SettingsValues {
mShowsLanguageSwitchKey = prefs.getBoolean(Settings.PREF_SHOW_LANGUAGE_SWITCH_KEY, false); // only relevant for default functional key layout
mShowsNumberRow = prefs.getBoolean(Settings.PREF_SHOW_NUMBER_ROW, false);
mLocalizedNumberRow = prefs.getBoolean(Settings.PREF_LOCALIZED_NUMBER_ROW, true);
mShowNumberRowHints = prefs.getBoolean(Settings.PREF_SHOW_NUMBER_ROW_HINTS, false);
mShowsHints = prefs.getBoolean(Settings.PREF_SHOW_HINTS, true);
mShowsPopupHints = prefs.getBoolean(Settings.PREF_SHOW_POPUP_HINTS, false);
mSpaceForLangChange = prefs.getBoolean(Settings.PREF_SPACE_TO_CHANGE_LANG, true);
@ -227,6 +233,7 @@ public class SettingsValues {
mDisplayOrientation = res.getConfiguration().orientation;
mSpaceSwipeHorizontal = Settings.readHorizontalSpaceSwipe(prefs);
mSpaceSwipeVertical = Settings.readVerticalSpaceSwipe(prefs);
mLanguageSwipeDistance = Settings.readLanguageSwipeDistance(prefs, res);
mDeleteSwipeEnabled = Settings.readDeleteSwipeEnabled(prefs);
mAutospaceAfterPunctuationEnabled = Settings.readAutospaceAfterPunctuationEnabled(prefs);
mClipboardHistoryEnabled = Settings.readClipboardHistoryEnabled(prefs);
@ -262,7 +269,8 @@ public class SettingsValues {
prefs.getBoolean(Settings.PREF_GESTURE_SPACE_AWARE, false)
);
mSpacingAndPunctuations = new SpacingAndPunctuations(res, mUrlDetectionEnabled);
mBottomPaddingScale = prefs.getFloat(Settings.PREF_BOTTOM_PADDING_SCALE, DEFAULT_SIZE_SCALE);
mBottomPaddingScale = Settings.readBottomPaddingScale(prefs, mDisplayOrientation == Configuration.ORIENTATION_LANDSCAPE);
mSidePaddingScale = Settings.readSidePaddingScale(prefs, mDisplayOrientation == Configuration.ORIENTATION_LANDSCAPE);
mLongPressSymbolsForNumpad = prefs.getBoolean(Settings.PREFS_LONG_PRESS_SYMBOLS_FOR_NUMPAD, false);
mAutoShowToolbar = prefs.getBoolean(Settings.PREF_AUTO_SHOW_TOOLBAR, false);
mAutoHideToolbar = readSuggestionsEnabled(prefs) && prefs.getBoolean(Settings.PREF_AUTO_HIDE_TOOLBAR, false);
@ -273,6 +281,8 @@ public class SettingsValues {
mRemoveRedundantPopups = prefs.getBoolean(Settings.PREF_REMOVE_REDUNDANT_POPUPS, false);
mSpaceBarText = prefs.getString(Settings.PREF_SPACE_BAR_TEXT, "");
mEmojiMaxSdk = prefs.getInt(Settings.PREF_EMOJI_MAX_SDK, Build.VERSION.SDK_INT);
mFontSizeMultiplier = prefs.getFloat(Settings.PREF_FONT_SCALE, DEFAULT_SIZE_SCALE);
mFontSizeMultiplierEmoji = prefs.getFloat(Settings.PREF_EMOJI_FONT_SCALE, DEFAULT_SIZE_SCALE);
}
public boolean isApplicationSpecifiedCompletionsOn() {

View file

@ -70,7 +70,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
public final class SuggestionStripView extends RelativeLayout implements OnClickListener,
OnLongClickListener {
OnLongClickListener, SharedPreferences.OnSharedPreferenceChangeListener {
public interface Listener {
void pickSuggestionManually(SuggestedWordInfo word);
void onCodeInput(int primaryCode, int x, int y, boolean isKeyRepeat);
@ -231,6 +231,12 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
colors.setBackground(this, ColorType.STRIP_BACKGROUND);
}
@Override
public void onSharedPreferenceChanged(SharedPreferences prefs, @Nullable String key) {
ToolbarUtilsKt.setToolbarButtonsActivatedStateOnPrefChange(mPinnedKeys, key);
ToolbarUtilsKt.setToolbarButtonsActivatedStateOnPrefChange(mToolbar, key);
}
/**
* A connection back to the input method.
*/
@ -647,11 +653,8 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
if (code != KeyCode.UNSPECIFIED) {
Log.d(TAG, "click toolbar key "+tag);
mListener.onCodeInput(code, Constants.SUGGESTION_STRIP_COORDINATE, Constants.SUGGESTION_STRIP_COORDINATE, false);
if (tag == ToolbarKey.INCOGNITO || tag == ToolbarKey.AUTOCORRECT || tag == ToolbarKey.ONE_HANDED) {
if (tag == ToolbarKey.INCOGNITO)
updateKeys(); // update icon
view.setActivated(!view.isActivated());
}
if (tag == ToolbarKey.INCOGNITO)
updateKeys(); // update expand key icon
return;
}
}

View file

@ -6,6 +6,7 @@ import android.content.Context
import android.content.DialogInterface
import android.content.SharedPreferences
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.EditText
import android.widget.ImageButton
import android.widget.ImageView
@ -16,6 +17,7 @@ import androidx.core.content.ContextCompat
import androidx.core.content.edit
import androidx.core.graphics.BlendModeColorFilterCompat
import androidx.core.graphics.BlendModeCompat
import androidx.core.view.forEach
import androidx.core.view.isGone
import androidx.core.view.isVisible
import androidx.core.widget.doAfterTextChanged
@ -26,7 +28,9 @@ import helium314.keyboard.latin.R
import helium314.keyboard.latin.databinding.ReorderDialogItemBinding
import helium314.keyboard.latin.settings.Settings
import helium314.keyboard.latin.utils.ToolbarKey.*
import kotlinx.serialization.encodeToString
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.serialization.json.Json
import java.util.EnumMap
import java.util.Locale
@ -38,14 +42,31 @@ fun createToolbarKey(context: Context, iconsSet: KeyboardIconsSet, key: ToolbarK
val contentDescriptionId = context.resources.getIdentifier(key.name.lowercase(), "string", context.packageName)
if (contentDescriptionId != 0)
button.contentDescription = context.getString(contentDescriptionId)
button.isActivated = !when (key) {
INCOGNITO -> Settings.readAlwaysIncognitoMode(DeviceProtectedUtils.getSharedPreferences(context))
setToolbarButtonActivatedState(button)
button.setImageDrawable(iconsSet.getNewDrawable(key.name, context))
return button
}
fun setToolbarButtonsActivatedStateOnPrefChange(buttonsGroup: ViewGroup, key: String?) {
// settings need to be updated when buttons change
if (key != Settings.PREF_AUTO_CORRECTION
&& key != Settings.PREF_ALWAYS_INCOGNITO_MODE
&& key?.startsWith(Settings.PREF_ONE_HANDED_MODE_PREFIX) == false)
return
GlobalScope.launch {
delay(10) // need to wait until SettingsValues are reloaded
buttonsGroup.forEach { if (it is ImageButton) setToolbarButtonActivatedState(it) }
}
}
private fun setToolbarButtonActivatedState(button: ImageButton) {
button.isActivated = when (button.tag) {
INCOGNITO -> Settings.readAlwaysIncognitoMode(DeviceProtectedUtils.getSharedPreferences(button.context))
ONE_HANDED -> Settings.getInstance().current.mOneHandedModeEnabled
AUTOCORRECT -> Settings.getInstance().current.mAutoCorrectionEnabledPerUserSettings
else -> true
}
button.setImageDrawable(iconsSet.getNewDrawable(key.name, context))
return button
}
fun getCodeForToolbarKey(key: ToolbarKey) = Settings.getInstance().getCustomToolbarKeyCode(key) ?: when (key) {
@ -60,7 +81,7 @@ fun getCodeForToolbarKey(key: ToolbarKey) = Settings.getInstance().getCustomTool
COPY -> KeyCode.CLIPBOARD_COPY
CUT -> KeyCode.CLIPBOARD_CUT
PASTE -> KeyCode.CLIPBOARD_PASTE
ONE_HANDED -> if (Settings.getInstance().current.mOneHandedModeEnabled) KeyCode.STOP_ONE_HANDED_MODE else KeyCode.START_ONE_HANDED_MODE
ONE_HANDED -> KeyCode.TOGGLE_ONE_HANDED_MODE
INCOGNITO -> KeyCode.TOGGLE_INCOGNITO_MODE
AUTOCORRECT -> KeyCode.TOGGLE_AUTOCORRECT
CLEAR_CLIPBOARD -> KeyCode.CLIPBOARD_CLEAR_HISTORY

View file

@ -377,6 +377,7 @@
<string name="prefs_long_press_symbol_for_numpad">নম্বর প্যাডের জন্য প্রতীক বোতামে দীর্ঘ চাপ</string>
<string name="var_toolbar_direction">টুলবারের পরিবর্তনশীল দিক</string>
<string name="var_toolbar_direction_summary">ডান থেকে বাম কিবোর্ড নির্বাচন করলে দিক বিপরীত হবে</string>
<string name="prefs_language_swipe_distance">ভাষা পরিবর্তন অভিস্পর্শের দূরত্ব</string>
<string name="subtype_generic_student"><xliff:g id="LANGUAGE_NAME" example="Russian">%s</xliff:g> (শিক্ষার্থী)</string>
<string name="language_switch_key_behavior">ভাষা পরিবর্তন বোতামের আচরণ</string>
<string name="pinned_toolbar_keys">পিন করে রাখা টুলবার বোতাম নির্বাচন</string>

View file

@ -21,7 +21,7 @@
<dimen name="config_popup_keys_keyboard_slide_allowance">53.76dp</dimen>
<fraction name="config_keyboard_top_padding_holo">2.727%p</fraction>
<fraction name="config_keyboard_bottom_padding_holo">0.0%p</fraction>
<fraction name="config_keyboard_bottom_padding_holo">2.5%p</fraction>
<fraction name="config_key_vertical_gap_holo">5.368%p</fraction>
<fraction name="config_key_horizontal_gap_holo">1.020%p</fraction>
<fraction name="config_key_vertical_gap_holo_narrow">4.85%p</fraction>

View file

@ -15,7 +15,7 @@
<dimen name="config_popup_keys_keyboard_key_height">81.9dp</dimen>
<fraction name="config_keyboard_top_padding_holo">2.727%p</fraction>
<fraction name="config_keyboard_bottom_padding_holo">0.0%p</fraction>
<fraction name="config_keyboard_bottom_padding_holo">2.0%p</fraction>
<fraction name="config_key_vertical_gap_holo">4.5%p</fraction>
<fraction name="config_key_horizontal_gap_holo">0.9%p</fraction>
<fraction name="config_key_vertical_gap_holo_narrow">4.5%p</fraction>

View file

@ -79,8 +79,8 @@
<integer name="config_touch_noise_threshold_time">40</integer>
<!-- Common keyboard configuration. -->
<fraction name="config_keyboard_left_padding">0%p</fraction>
<fraction name="config_keyboard_right_padding">0%p</fraction>
<fraction name="config_keyboard_left_padding">8%p</fraction>
<fraction name="config_keyboard_right_padding">8%p</fraction>
<dimen name="config_keyboard_vertical_correction">0.0dp</dimen>
<!-- Common key top visual configuration. -->

View file

@ -86,6 +86,9 @@
<!-- Description for Arabic (PC) subtype. -->
<string name="subtype_arabic_pc" translatable="false">%s (PC)</string>
<!-- Description for Arabic (Hija'i) subtype. -->
<string name="subtype_arabic_hijai" translatable="false">%s (Hija\'i)</string>
<!-- Description for Hebrew 2 subtype. -->
<string name="subtype_hebrew_1452_2" translatable="false">%s (1452-2)</string>

View file

@ -239,6 +239,8 @@
<string name="localized_number_row">Localize number row</string>
<!-- Description of the settings to localize number row -->
<string name="localized_number_row_summary">Prefer localized over latin numbers</string>
<!-- Title of the setting to enable number row hints -->
<string name="number_row_hints">Show hints on number row</string>
<!-- Title of the setting to show key hints -->
<string name="show_hints">Show key hints</string>
<!-- Description of the settings to show hints -->
@ -311,6 +313,16 @@
<string name="prefs_keyboard_height_scale">Keyboard height scale</string>
<!-- Title of the setting for setting bottom padding height -->
<string name="prefs_bottom_padding_scale">Bottom padding scale</string>
<!-- Title of the setting for setting bottom padding height in landscape mode -->
<string name="prefs_bottom_padding_scale_landscape">Bottom padding scale (landscape)</string>
<!-- Title of the setting for adjusting font size on the keyboard -->
<!-- Title of the setting for setting side padding -->
<string name="prefs_side_padding_scale">Side padding scale</string>
<!-- Title of the setting for setting side padding in landscape mode -->
<string name="prefs_side_padding_scale_landscape">Side padding scale (landscape)</string>
<string name="prefs_font_scale">Keyboard font scale</string>
<!-- Title of the setting for adjusting font size in emoji view -->
<string name="prefs_emoji_font_scale">Emoji view font scale</string>
<!-- Title of the setting for customizing space bar text -->
<string name="prefs_space_bar_text">Custom text on space bar</string>
<!-- Title of the setting for adding / removing custom font file -->
@ -946,6 +958,8 @@ New dictionary:
<string name="var_toolbar_direction">Variable toolbar direction</string>
<!-- Description of the variable toolbar direction setting -->
<string name="var_toolbar_direction_summary">Reverse direction when a right-to-left keyboard subtype is selected</string>
<!-- Title of the settings for adjusting the language swipe gesture distance -->
<string name="prefs_language_swipe_distance">Switch language swipe distance</string>
<!-- Title of the setting to customize toolbar key codes -->
<string name="customize_toolbar_key_codes">Customize toolbar key codes</string>
<!-- Confirmation message when resetting all custom toolbar key codes -->

View file

@ -97,6 +97,8 @@
>
<item name="keyboardTopPadding">0%p</item>
<item name="keyboardBottomPadding">0%p</item>
<item name="keyboardLeftPadding">0%p</item>
<item name="keyboardRightPadding">0%p</item>
<item name="horizontalGap">0%p</item>
<item name="horizontalGapNarrow">0%p</item>
<item name="touchPositionCorrectionData">@null</item>

View file

@ -81,6 +81,8 @@
>
<item name="keyboardTopPadding">0%p</item>
<item name="keyboardBottomPadding">0%p</item>
<item name="keyboardLeftPadding">0%p</item>
<item name="keyboardRightPadding">0%p</item>
<item name="horizontalGap">0%p</item>
<item name="horizontalGapNarrow">0%p</item>
<item name="touchPositionCorrectionData">@null</item>

View file

@ -90,6 +90,8 @@
>
<item name="keyboardTopPadding">0%p</item>
<item name="keyboardBottomPadding">0%p</item>
<item name="keyboardLeftPadding">0%p</item>
<item name="keyboardRightPadding">0%p</item>
<item name="horizontalGap">0%p</item>
<item name="horizontalGapNarrow">0%p</item>
<item name="touchPositionCorrectionData">@null</item>

View file

@ -178,6 +178,15 @@
android:imeSubtypeExtraValue="KeyboardLayoutSet=arabic_pc,NoShiftKey,EmojiCapable"
android:isAsciiCapable="false"
/>
<subtype android:icon="@drawable/ic_ime_switcher"
android:label="@string/subtype_arabic_hijai"
android:subtypeId="0x590dde42"
android:imeSubtypeLocale="ar"
android:languageTag="ar"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="KeyboardLayoutSet=arabic_hijai,NoShiftKey,SupportTouchPositionCorrection,EmojiCapable"
android:isAsciiCapable="false"
/>
<subtype android:icon="@drawable/ic_ime_switcher"
android:label="@string/subtype_generic"
android:subtypeId="0x70b0f974"

View file

@ -43,6 +43,13 @@
android:title="@string/show_vertical_space_swipe"
latin:singleLineTitle="false" />
<helium314.keyboard.latin.settings.SeekBarDialogPreference
android:key="language_swipe_distance"
android:title="@string/prefs_language_swipe_distance"
latin:minValue="2"
latin:maxValue="18"
latin:stepValue="1" />
<SwitchPreference
android:key="delete_swipe"
android:title="@string/delete_swipe"

View file

@ -111,6 +111,27 @@
latin:minValue="0"
latin:maxValue="500" /> <!-- percentage -->
<helium314.keyboard.latin.settings.SeekBarDialogPreference
android:key="bottom_padding_scale_landscape"
android:title="@string/prefs_bottom_padding_scale_landscape"
latin:defaultValue="0"
latin:minValue="0"
latin:maxValue="500" /> <!-- percentage -->
<helium314.keyboard.latin.settings.SeekBarDialogPreference
android:key="side_padding_scale"
android:title="@string/prefs_side_padding_scale"
latin:defaultValue="0"
latin:minValue="0"
latin:maxValue="300" /> <!-- percentage -->
<helium314.keyboard.latin.settings.SeekBarDialogPreference
android:key="side_padding_scale_landscape"
android:title="@string/prefs_side_padding_scale_landscape"
latin:defaultValue="0"
latin:minValue="0"
latin:maxValue="300" /> <!-- percentage -->
<EditTextPreference
android:key="space_bar_text"
android:title="@string/prefs_space_bar_text"
@ -123,6 +144,18 @@
android:defaultValue=""
android:persistent="true" />
<helium314.keyboard.latin.settings.SeekBarDialogPreference
android:key="font_scale"
android:title="@string/prefs_font_scale"
latin:minValue="50"
latin:maxValue="150" /> <!-- percentage -->
<helium314.keyboard.latin.settings.SeekBarDialogPreference
android:key="emoji_font_scale"
android:title="@string/prefs_emoji_font_scale"
latin:minValue="50"
latin:maxValue="150" /> <!-- percentage -->
</PreferenceCategory>
</PreferenceScreen>

View file

@ -85,6 +85,12 @@
android:defaultValue="true"
android:persistent="true" />
<SwitchPreference
android:key="show_number_row_hints"
android:title="@string/number_row_hints"
android:defaultValue="false"
android:persistent="true" />
<SwitchPreference
android:key="show_language_switch_key"
android:title="@string/show_language_switch_key"

View file

@ -613,6 +613,57 @@ class InputLogicTest {
assertEquals("{\"label\": \"c", text)
}
@Test fun `text input and delete`() {
reset()
input("hello")
assertEquals("hello", text)
functionalKeyPress(KeyCode.DELETE)
assertEquals("hell", text)
reset()
input("hello ")
assertEquals("hello ", text)
functionalKeyPress(KeyCode.DELETE)
assertEquals("hello", text)
}
@Test fun `emoji text input and delete`() {
reset()
input("🕵🏼")
functionalKeyPress(KeyCode.DELETE)
assertEquals("", text)
reset()
input("\uD83D\uDD75\uD83C\uDFFC")
input(' ')
assertEquals("🕵🏼 ", text)
functionalKeyPress(KeyCode.DELETE)
functionalKeyPress(KeyCode.DELETE)
assertEquals("", text)
}
@Test fun `revert autocorrect on delete`() {
reset()
chainInput("hullo")
getAutocorrectedWithSpaceAfter("hello", "hullo")
functionalKeyPress(KeyCode.DELETE)
assertEquals("hullo", text)
// todo: now we want some way to disable revert on backspace, either per setting or something else
// need to avoid getting into the mLastComposedWord.canRevertCommit() part of handleBackspaceEvent
}
@Test fun `remove glide typing word on delete`() {
reset()
glideTypingInput("hello")
assertEquals("hello", text)
functionalKeyPress(KeyCode.DELETE)
assertEquals("", text)
// todo: now we want some way to disable delete-all on backspace, either per setting or something else
// need to avoid getting into the mWordComposer.isBatchMode() part of handleBackspaceEvent
}
// ------- helper functions ---------
// should be called before every test, so the same state is guaranteed
@ -646,6 +697,7 @@ class InputLogicTest {
if (currentScript != ScriptUtils.SCRIPT_HANGUL // check fails if hangul combiner merges symbols
&& !(codePoint == Constants.CODE_SPACE && oldBefore.lastOrNull() == ' ') // check fails when 2 spaces are converted into a period
&& !latinIME.mInputLogic.mSuggestedWords.mWillAutoCorrect // autocorrect obviously creates inconsistencies
) {
if (phantomSpaceToInsert.isEmpty())
assertEquals(oldBefore + insert, textBeforeCursor)
@ -751,6 +803,22 @@ class InputLogicTest {
checkConnectionConsistency()
}
// only works when autocorrect is on, separator after word is required
private fun getAutocorrectedWithSpaceAfter(suggestion: String, typedWord: String?) {
val info = SuggestedWordInfo(suggestion, "", 0, 0, null, 0, 0)
val typedInfo = SuggestedWordInfo(typedWord, "", 0, 0, null, 0, 0)
val sw = SuggestedWords(ArrayList(listOf(typedInfo, info)), null, typedInfo, false, true, false, 0, 0)
latinIME.mInputLogic.setSuggestedWords(sw)
input(' ')
checkConnectionConsistency()
}
private fun glideTypingInput(word: String) {
val info = SuggestedWordInfo(word, "", 0, 0, null, 0, 0)
val sw = SuggestedWords(ArrayList(listOf(info)), null, info, true, false, false, 0, 0)
latinIME.mInputLogic.onUpdateTailBatchInputCompleted(settingsValues, sw, KeyboardSwitcher.getInstance())
}
private fun checkConnectionConsistency() {
// RichInputConnection only has composing text up to cursor, but InputConnection has full composing text
val expectedConnectionComposingText = if (composingStart == -1 || composingEnd == -1) ""
@ -969,11 +1037,12 @@ private val ic = object : InputConnection {
it.selectionEnd = selectionEnd
}
}
// only effect is flashing, so whatever...
override fun commitCorrection(p0: CorrectionInfo?): Boolean = true
// implement only when necessary
override fun getCursorCapsMode(p0: Int): Int = TODO("Not yet implemented")
override fun deleteSurroundingTextInCodePoints(p0: Int, p1: Int): Boolean = TODO("Not yet implemented")
override fun commitCompletion(p0: CompletionInfo?): Boolean = TODO("Not yet implemented")
override fun commitCorrection(p0: CorrectionInfo?): Boolean = TODO("Not yet implemented")
override fun performEditorAction(p0: Int): Boolean = TODO("Not yet implemented")
override fun performContextMenuAction(p0: Int): Boolean = TODO("Not yet implemented")
override fun clearMetaKeyStates(p0: Int): Boolean = TODO("Not yet implemented")

View file

@ -42,6 +42,8 @@ class StringUtilsTest {
}
@Test fun detectEmojisAtEnd() {
assertEquals("", getFullEmojiAtEnd("\uD83C\uDF83 "))
assertEquals("", getFullEmojiAtEnd("a"))
assertEquals("\uD83C\uDF83", getFullEmojiAtEnd("\uD83C\uDF83"))
assertEquals("", getFullEmojiAtEnd(""))
assertEquals("", getFullEmojiAtEnd(""))
@ -51,6 +53,15 @@ class StringUtilsTest {
assertEquals("\uD83C\uDFF3\u200D\uD83C\uDF08", getFullEmojiAtEnd("\uD83C\uDFF3\u200D\uD83C\uDF08"))
assertEquals("\uD83C\uDFF3\u200D\uD83C\uDF08", getFullEmojiAtEnd("\uD83C\uDFF4\u200D☠️\uD83C\uDFF3\u200D\uD83C\uDF08"))
assertEquals("\uD83C\uDFF3\u200D⚧️", getFullEmojiAtEnd("hello there🏳"))
assertEquals("\uD83D\uDD75\uD83C\uDFFC", getFullEmojiAtEnd(" 🕵🏼"))
assertEquals("\uD83D\uDD75\uD83C\uDFFC", getFullEmojiAtEnd("🕵🏼"))
assertEquals("\uD83C\uDFFC", getFullEmojiAtEnd(" \uD83C\uDFFC"))
// fails, but unlikely enough that we leave it unfixed
//assertEquals("\uD83C\uDFFC", getFullEmojiAtEnd("\uD83C\uDF84\uD83C\uDFFC"))
// below also fail, because ZWJ handling is not suitable for some unusual cases
//assertEquals("", getFullEmojiAtEnd("\u200D"))
//assertEquals("", getFullEmojiAtEnd("a\u200D"))
//assertEquals("\uD83D\uDE22", getFullEmojiAtEnd(" \u200D\uD83D\uDE22"))
}
// todo: add tests for emoji detection?