mirror of
https://github.com/Helium314/HeliBoard.git
synced 2025-04-21 06:39:09 +00:00
Improve main views (#321)
* views now have the same height * add one-handed mode width setting * key text and emojis scale more adequately with keyboard height and one-handed mode width * slightly adjust landscape config to match better with portrait
This commit is contained in:
parent
e78618fd6a
commit
0b55a92e02
22 changed files with 184 additions and 68 deletions
|
@ -316,9 +316,7 @@ public class Key implements Comparable<Key> {
|
|||
mHorizontalGap = Math.round(horizontalGapFloat);
|
||||
mVerticalGap = Math.round(keyParams.mKeyboardParams.mVerticalGap);
|
||||
mWidth = Math.round(keyParams.mFullWidth - horizontalGapFloat);
|
||||
// todo (later): height better should be rounded, but this may end up shifting all keys up by one pixel,
|
||||
// increasing the keyboard height by one pixel, but not for emoji keyboard -> the 1 pixel shift feels very wrong
|
||||
// how to do it properly? check again when keyboard height is same for all views!
|
||||
// height is always rounded down, because rounding up may make the keyboard too high to fit, leading to issues
|
||||
mHeight = (int) (keyParams.mFullHeight - keyParams.mKeyboardParams.mVerticalGap);
|
||||
if (!isSpacer() && (mWidth == 0 || mHeight == 0)) {
|
||||
throw new IllegalStateException("key needs positive width and height");
|
||||
|
@ -326,7 +324,7 @@ public class Key implements Comparable<Key> {
|
|||
// Horizontal gap is divided equally to both sides of the key.
|
||||
mX = Math.round(keyParams.xPos + horizontalGapFloat / 2);
|
||||
mY = Math.round(keyParams.yPos);
|
||||
mHitBox.set(Math.round(keyParams.xPos), (int) keyParams.yPos, Math.round(keyParams.xPos + keyParams.mFullWidth) + 1,
|
||||
mHitBox.set(Math.round(keyParams.xPos), Math.round(keyParams.yPos), Math.round(keyParams.xPos + keyParams.mFullWidth) + 1,
|
||||
Math.round(keyParams.yPos + keyParams.mFullHeight));
|
||||
mHashCode = computeHashCode(this);
|
||||
}
|
||||
|
|
|
@ -183,6 +183,10 @@ public final class KeyboardId {
|
|||
|| mElementId == ELEMENT_PHONE || mElementId == ELEMENT_PHONE_SYMBOLS;
|
||||
}
|
||||
|
||||
public boolean isEmojiKeyboard() {
|
||||
return mElementId >= ELEMENT_EMOJI_RECENTS && mElementId <= ELEMENT_EMOJI_CATEGORY16;
|
||||
}
|
||||
|
||||
public int imeAction() {
|
||||
return InputTypeUtils.getImeOptionsActionIdFromEditorInfo(mEditorInfo);
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@ import org.dslul.openboard.inputmethod.latin.common.Colors;
|
|||
import org.dslul.openboard.inputmethod.latin.common.Constants;
|
||||
import org.dslul.openboard.inputmethod.latin.common.StringUtils;
|
||||
import org.dslul.openboard.inputmethod.latin.settings.Settings;
|
||||
import org.dslul.openboard.inputmethod.latin.settings.SettingsValues;
|
||||
import org.dslul.openboard.inputmethod.latin.suggestions.MoreSuggestionsView;
|
||||
import org.dslul.openboard.inputmethod.latin.utils.TypefaceUtils;
|
||||
|
||||
|
@ -95,6 +96,7 @@ public class KeyboardView extends View {
|
|||
private final Rect mKeyBackgroundPadding = new Rect();
|
||||
private static final float KET_TEXT_SHADOW_RADIUS_DISABLED = -1.0f;
|
||||
private final Colors mColors;
|
||||
private float mKeyScaleForText;
|
||||
|
||||
// The maximum key label width in the proportion to the key width.
|
||||
private static final float MAX_LABEL_RATIO = 0.90f;
|
||||
|
@ -203,9 +205,15 @@ public class KeyboardView extends View {
|
|||
*/
|
||||
public void setKeyboard(@NonNull final Keyboard keyboard) {
|
||||
mKeyboard = keyboard;
|
||||
final int keyHeight = keyboard.mMostCommonKeyHeight - keyboard.mVerticalGap;
|
||||
mKeyDrawParams.updateParams(keyHeight, mKeyVisualAttributes);
|
||||
mKeyDrawParams.updateParams(keyHeight, keyboard.mKeyVisualAttributes);
|
||||
final SettingsValues sv = Settings.getInstance().getCurrent();
|
||||
// scale should not depend on mOneHandedModeScale for emoji and clipboard, because those views are not affected by one-handed mode (yet)
|
||||
if (keyboard.mId.isEmojiKeyboard() || keyboard.mId.mElementId == KeyboardId.ELEMENT_CLIPBOARD)
|
||||
mKeyScaleForText = (float) Math.sqrt(1 / sv.mKeyboardHeightScale);
|
||||
else
|
||||
mKeyScaleForText = (float) Math.sqrt(sv.mOneHandedModeScale / sv.mKeyboardHeightScale);
|
||||
final int scaledKeyHeight = (int) ((keyboard.mMostCommonKeyHeight - keyboard.mVerticalGap) * mKeyScaleForText);
|
||||
mKeyDrawParams.updateParams(scaledKeyHeight, mKeyVisualAttributes);
|
||||
mKeyDrawParams.updateParams(scaledKeyHeight, keyboard.mKeyVisualAttributes);
|
||||
invalidateAllKeys();
|
||||
requestLayout();
|
||||
}
|
||||
|
@ -346,7 +354,7 @@ public class KeyboardView extends View {
|
|||
canvas.translate(keyDrawX, keyDrawY);
|
||||
|
||||
final KeyVisualAttributes attr = key.getVisualAttributes();
|
||||
final KeyDrawParams params = mKeyDrawParams.mayCloneAndUpdateParams(key.getHeight(), attr);
|
||||
final KeyDrawParams params = mKeyDrawParams.mayCloneAndUpdateParams((int) (key.getHeight() * mKeyScaleForText), attr);
|
||||
params.mAnimAlpha = Constants.Color.ALPHA_OPAQUE;
|
||||
|
||||
if (!key.isSpacer()) {
|
||||
|
@ -413,7 +421,8 @@ public class KeyboardView extends View {
|
|||
if (key.isAlignLabelOffCenter() && mShowsHints) {
|
||||
// The label is placed off center of the key. Currently used only on "phone number" layout
|
||||
// to have letter hints shown nicely. We don't want to align it off center if hints are off.
|
||||
labelX = centerX + params.mLabelOffCenterRatio * labelCharWidth;
|
||||
// use a non-negative number to avoid label starting left of the letter for high keyboard scale on holo phone layout
|
||||
labelX = Math.max(0f, centerX + params.mLabelOffCenterRatio * labelCharWidth);
|
||||
paint.setTextAlign(Align.LEFT);
|
||||
} else {
|
||||
labelX = centerX;
|
||||
|
@ -474,6 +483,11 @@ public class KeyboardView extends View {
|
|||
hintBaseline = centerY + labelCharHeight / 2.0f;
|
||||
}
|
||||
paint.setTextAlign(Align.LEFT);
|
||||
// shrink hint label before it's off the key
|
||||
// looks bad, but still better than the alternative
|
||||
final float ratio = Math.min(1.0f, (keyWidth - hintX) * 0.95f / TypefaceUtils.getStringWidth(hintLabel, paint));
|
||||
final float autoSize = paint.getTextSize() * ratio;
|
||||
paint.setTextSize(autoSize);
|
||||
} else if (key.hasShiftedLetterHint()) {
|
||||
// The hint label is placed at top-right corner of the key. Used mainly on tablet.
|
||||
hintX = keyWidth - mKeyShiftedLetterHintPadding - labelCharWidth / 2.0f;
|
||||
|
|
|
@ -61,7 +61,7 @@ class ClipboardHistoryView @JvmOverloads constructor(
|
|||
val res = context.resources
|
||||
// The main keyboard expands to the entire this {@link KeyboardView}.
|
||||
val width = (ResourceUtils.getDefaultKeyboardWidth(res) + paddingLeft + paddingRight)
|
||||
val height = (ResourceUtils.getDefaultKeyboardHeight(res)
|
||||
val height = (ResourceUtils.getKeyboardHeight(res, Settings.getInstance().current)
|
||||
+ res.getDimensionPixelSize(R.dimen.config_suggestions_strip_height)
|
||||
+ paddingTop + paddingBottom)
|
||||
setMeasuredDimension(width, height)
|
||||
|
|
|
@ -25,7 +25,7 @@ class ClipboardLayoutParams(res: Resources) {
|
|||
}
|
||||
|
||||
init {
|
||||
val defaultKeyboardHeight = ResourceUtils.getDefaultKeyboardHeight(res)
|
||||
val defaultKeyboardHeight = ResourceUtils.getKeyboardHeight(res, Settings.getInstance().current)
|
||||
val suggestionStripHeight = res.getDimensionPixelSize(R.dimen.config_suggestions_strip_height)
|
||||
val defaultKeyboardWidth = ResourceUtils.getDefaultKeyboardWidth(res)
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ import android.widget.LinearLayout;
|
|||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import org.dslul.openboard.inputmethod.latin.R;
|
||||
import org.dslul.openboard.inputmethod.latin.settings.Settings;
|
||||
import org.dslul.openboard.inputmethod.latin.settings.SettingsValues;
|
||||
import org.dslul.openboard.inputmethod.latin.utils.ResourceUtils;
|
||||
|
||||
final class EmojiLayoutParams {
|
||||
|
@ -29,9 +30,10 @@ final class EmojiLayoutParams {
|
|||
private final int mTopPadding;
|
||||
|
||||
public EmojiLayoutParams(final Resources res) {
|
||||
final int defaultKeyboardHeight = ResourceUtils.getDefaultKeyboardHeight(res);
|
||||
final SettingsValues settingsValues = Settings.getInstance().getCurrent();
|
||||
final int defaultKeyboardHeight = ResourceUtils.getKeyboardHeight(res, settingsValues);
|
||||
final int defaultKeyboardWidth = ResourceUtils.getDefaultKeyboardWidth(res);
|
||||
if (Settings.getInstance().getCurrent().mNarrowKeyGaps) {
|
||||
if (settingsValues.mNarrowKeyGaps) {
|
||||
mKeyVerticalGap = (int) res.getFraction(R.fraction.config_key_vertical_gap_holo_narrow,
|
||||
defaultKeyboardHeight, defaultKeyboardHeight);
|
||||
mKeyHorizontalGap = (int) (res.getFraction(R.fraction.config_key_horizontal_gap_holo_narrow,
|
||||
|
@ -42,13 +44,14 @@ final class EmojiLayoutParams {
|
|||
mKeyHorizontalGap = (int) (res.getFraction(R.fraction.config_key_horizontal_gap_holo,
|
||||
defaultKeyboardWidth, defaultKeyboardWidth));
|
||||
}
|
||||
mBottomPadding = (int) (res.getFraction(R.fraction.config_keyboard_bottom_padding_holo,
|
||||
defaultKeyboardHeight, defaultKeyboardHeight) * Settings.getInstance().getCurrent().mBottomPaddingScale);
|
||||
mTopPadding = (int) res.getFraction(R.fraction.config_keyboard_top_padding_holo,
|
||||
defaultKeyboardHeight, defaultKeyboardHeight);
|
||||
final float defaultBottomPadding = res.getFraction(R.fraction.config_keyboard_bottom_padding_holo, defaultKeyboardHeight, defaultKeyboardHeight);
|
||||
mBottomPadding = (int) (defaultBottomPadding * settingsValues.mBottomPaddingScale);
|
||||
final int paddingScaleOffset = (int) (mBottomPadding - defaultBottomPadding);
|
||||
mTopPadding = (int) res.getFraction(R.fraction.config_keyboard_top_padding_holo, defaultKeyboardHeight, defaultKeyboardHeight);
|
||||
mEmojiCategoryPageIdViewHeight = (int) (res.getDimension(R.dimen.config_emoji_category_page_id_height));
|
||||
final int baseheight = defaultKeyboardHeight - mBottomPadding - mTopPadding + mKeyVerticalGap;
|
||||
mEmojiActionBarHeight = baseheight / DEFAULT_KEYBOARD_ROWS - (mKeyVerticalGap - mBottomPadding) / 2;
|
||||
final int rows = DEFAULT_KEYBOARD_ROWS + (settingsValues.mShowsNumberRow ? 1 : 0); // for proper size considering number row
|
||||
mEmojiActionBarHeight = baseheight / rows - (mKeyVerticalGap - mBottomPadding) / 2 + paddingScaleOffset / 2;
|
||||
mEmojiListHeight = defaultKeyboardHeight - mEmojiActionBarHeight - mEmojiCategoryPageIdViewHeight;
|
||||
mEmojiListBottomMargin = 0;
|
||||
mEmojiKeyboardHeight = mEmojiListHeight - mEmojiListBottomMargin - 1;
|
||||
|
|
|
@ -135,7 +135,7 @@ public final class EmojiPalettesView extends LinearLayout
|
|||
// The main keyboard expands to the entire this {@link KeyboardView}.
|
||||
final int width = ResourceUtils.getDefaultKeyboardWidth(res)
|
||||
+ getPaddingLeft() + getPaddingRight();
|
||||
final int height = ResourceUtils.getDefaultKeyboardHeight(res)
|
||||
final int height = ResourceUtils.getKeyboardHeight(res, Settings.getInstance().getCurrent())
|
||||
+ res.getDimensionPixelSize(R.dimen.config_suggestions_strip_height)
|
||||
+ getPaddingTop() + getPaddingBottom();
|
||||
setMeasuredDimension(width, height);
|
||||
|
|
|
@ -140,7 +140,7 @@ open class KeyboardBuilder<KP : KeyboardParams>(protected val mContext: Context,
|
|||
|
||||
fun loadFromXml(xmlId: Int, id: KeyboardId): KeyboardBuilder<KP> {
|
||||
if (Settings.getInstance().current.mUseNewKeyboardParsing) {
|
||||
if (id.mElementId >= KeyboardId.ELEMENT_EMOJI_RECENTS && id.mElementId <= KeyboardId.ELEMENT_EMOJI_CATEGORY16) {
|
||||
if (id.isEmojiKeyboard) {
|
||||
mParams.mId = id
|
||||
readAttributes(R.xml.kbd_emoji_category1) // all the same anyway, gridRows are ignored
|
||||
keysInRows = EmojiParser(mParams, mContext).parse(Settings.getInstance().current.mIsSplitKeyboardEnabled)
|
||||
|
@ -222,10 +222,7 @@ open class KeyboardBuilder<KP : KeyboardParams>(protected val mContext: Context,
|
|||
Log.d(TAG, "setting size and position for ${it.mLabel}, ${it.mCode}: x ${currentX.toInt()}, w ${it.mFullWidth.toInt()}")
|
||||
currentX += it.mFullWidth
|
||||
}
|
||||
// need to truncate to int here, otherwise it may end up one pixel lower than original
|
||||
// though actually not truncating would be more correct... but that's already an y / height issue somewhere in Key
|
||||
// todo (later): round, and do the change together with the some thing in Key(KeyParams keyParams)
|
||||
currentY += row.first().mFullHeight.toInt()
|
||||
currentY += row.first().mFullHeight
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -371,8 +368,13 @@ open class KeyboardBuilder<KP : KeyboardParams>(protected val mContext: Context,
|
|||
mParams.removeRedundantMoreKeys()
|
||||
// {@link #parseGridRows(XmlPullParser,boolean)} may populate keyboard rows higher than
|
||||
// previously expected.
|
||||
// todo (low priority): mCurrentY may end up too high with the new parser and 4 row keyboards in landscape mode
|
||||
// -> why is this happening?
|
||||
// but anyway, since the height is resized correctly already, we don't need to adjust the
|
||||
// occupied height, except for the scrollable emoji keyoards
|
||||
if (!mParams.mId.isEmojiKeyboard) return
|
||||
val actualHeight = mCurrentY - mParams.mVerticalGap + mParams.mBottomPadding
|
||||
mParams.mOccupiedHeight = Math.max(mParams.mOccupiedHeight, actualHeight)
|
||||
mParams.mOccupiedHeight = mParams.mOccupiedHeight.coerceAtLeast(actualHeight)
|
||||
}
|
||||
|
||||
private fun addKeysToParams() {
|
||||
|
|
|
@ -10,6 +10,9 @@ import org.dslul.openboard.inputmethod.keyboard.internal.KeyboardParams
|
|||
import org.dslul.openboard.inputmethod.latin.R
|
||||
import org.dslul.openboard.inputmethod.latin.common.Constants
|
||||
import org.dslul.openboard.inputmethod.latin.common.StringUtils
|
||||
import org.dslul.openboard.inputmethod.latin.settings.Settings
|
||||
import kotlin.math.round
|
||||
import kotlin.math.sqrt
|
||||
|
||||
class EmojiParser(private val params: KeyboardParams, private val context: Context) {
|
||||
|
||||
|
@ -60,10 +63,18 @@ class EmojiParser(private val params: KeyboardParams, private val context: Conte
|
|||
val row = ArrayList<KeyParams>(emojiArray.size)
|
||||
var currentX = params.mLeftPadding.toFloat()
|
||||
val currentY = params.mTopPadding.toFloat()
|
||||
|
||||
val widthScale = getWidthScale()
|
||||
// extra scale for height only, to undo the effect of number row increasing absolute key height
|
||||
// todo: with this things look ok, but number row still slightly affects emoji size (which it should not)
|
||||
val numScale = if (Settings.getInstance().current.mShowsNumberRow) 1.25f else 1f
|
||||
|
||||
emojiArray.forEachIndexed { i, codeArraySpec ->
|
||||
val keyParams = parseEmojiKey(codeArraySpec, moreEmojisArray?.get(i)?.takeIf { it.isNotEmpty() }) ?: return@forEachIndexed
|
||||
keyParams.setDimensionsFromRelativeSize(currentX, currentY)
|
||||
currentX += keyParams.mFullWidth // exact value seems to be not really relevant, but keeping 0 doesn't work
|
||||
keyParams.mFullHeight /= numScale
|
||||
keyParams.mFullWidth *= widthScale
|
||||
currentX += keyParams.mFullWidth
|
||||
row.add(keyParams)
|
||||
// if (row.size % numColumns == spacerIndex) { // also removed for now (would be missing setting the size and updating x
|
||||
// repeat(spacerNumKeys) { row.add(KeyParams.newSpacer(params, params.mDefaultRelativeKeyWidth)) }
|
||||
|
@ -72,6 +83,16 @@ class EmojiParser(private val params: KeyboardParams, private val context: Conte
|
|||
return arrayListOf(row)
|
||||
}
|
||||
|
||||
private fun getWidthScale(): Float {
|
||||
// height scale affects emoji size, but then emojis may be too wide or too narrow
|
||||
// so we re-scale width too
|
||||
// but not with exactly the same factor, adjust it a little so emojis fill the entire available width
|
||||
// this looks much better than setting some offset in DynamicGridKeyboard (to center the rows)
|
||||
val numColumnsNew = round(1f / (params.mDefaultRelativeKeyWidth * sqrt(Settings.getInstance().current.mKeyboardHeightScale)))
|
||||
val numColumnsOld = round(1f / params.mDefaultRelativeKeyWidth)
|
||||
return numColumnsOld / numColumnsNew - 0.0001f // small offset to have more emojis in a row in edge cases
|
||||
}
|
||||
|
||||
// private fun Float.roundTo(even: Boolean) = if (toInt() % 2 == if (even) 0 else 1) toInt() else toInt() + 1
|
||||
|
||||
private fun getLabelAndCode(spec: String): Pair<String, Int>? {
|
||||
|
|
|
@ -70,20 +70,14 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co
|
|||
}
|
||||
// rescale height if we have more than 4 rows (todo: there is some default row count in params that could be used)
|
||||
val heightRescale = if (keysInRows.size > 4) 4f / keysInRows.size else 1f
|
||||
if (params.mId.mNumberRowEnabled && params.mId.mElementId <= KeyboardId.ELEMENT_SYMBOLS_SHIFTED)
|
||||
keysInRows.add(0, getNumberRow()) // todo: maybe this should be in createAlphaSymbolRows, but first need to decide height stuff below
|
||||
if (heightRescale != 1f) {
|
||||
// rescale all keys, so number row doesn't look weird (this is done like in current parsing)
|
||||
// todo: in symbols view, number row is not rescaled
|
||||
// so the symbols keyboard is higher than the normal one
|
||||
// not a new issue, but should be solved in this migration
|
||||
// how? possibly scale all keyboards to height of main alphabet? (consider suggestion strip)
|
||||
keysInRows.forEach { row -> row.forEach { it.mRelativeHeight *= heightRescale } }
|
||||
}
|
||||
|
||||
return keysInRows
|
||||
}
|
||||
|
||||
// todo: get rid if the bottom-to-top thing, feels weird (then number row could also be added first)
|
||||
private fun createAlphaSymbolRows(baseKeys: MutableList<List<KeyData>>): ArrayList<ArrayList<KeyParams>> {
|
||||
// number row related modifications of baseKeys
|
||||
if (!params.mId.mNumberRowEnabled && params.mId.mElementId == KeyboardId.ELEMENT_SYMBOLS) {
|
||||
|
@ -97,7 +91,7 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co
|
|||
) {
|
||||
// add number to the first 10 keys in first row
|
||||
// setting the correct moreKeys is handled in PopupSet
|
||||
// not for korean/lao/thai layouts, todo: should be decided in the layout, not in the parser
|
||||
// not for korean/lao/thai layouts, todo: should be decided in the layout / layoutInfos, not in the parser
|
||||
baseKeys.first().take(10).forEachIndexed { index, keyData -> keyData.popup.numberIndex = index }
|
||||
if (DebugFlags.DEBUG_ENABLED && baseKeys.first().size < 10) {
|
||||
val message = "first row only has ${baseKeys.first().size} keys: ${baseKeys.first().map { it.label }}"
|
||||
|
@ -192,6 +186,8 @@ abstract class KeyboardParser(private val params: KeyboardParams, private val co
|
|||
functionalKeysRight.forEach { paramsRow.add(it) }
|
||||
keysInRows.add(0, paramsRow) // we're doing it backwards, so add on top
|
||||
}
|
||||
if (params.mId.mNumberRowEnabled)
|
||||
keysInRows.add(0, getNumberRow())
|
||||
resizeLastNormalRowIfNecessaryForAlignment(keysInRows)
|
||||
return keysInRows
|
||||
}
|
||||
|
|
|
@ -4,9 +4,11 @@ package org.dslul.openboard.inputmethod.latin
|
|||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
import android.graphics.Color
|
||||
import android.util.AttributeSet
|
||||
import android.view.Gravity
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.ImageButton
|
||||
|
@ -14,6 +16,8 @@ import org.dslul.openboard.inputmethod.keyboard.KeyboardActionListener
|
|||
import org.dslul.openboard.inputmethod.latin.common.BackgroundType
|
||||
import org.dslul.openboard.inputmethod.latin.common.Constants
|
||||
import org.dslul.openboard.inputmethod.latin.settings.Settings
|
||||
import org.dslul.openboard.inputmethod.latin.utils.DeviceProtectedUtils
|
||||
import kotlin.math.abs
|
||||
|
||||
class KeyboardWrapperView @JvmOverloads constructor(
|
||||
context: Context,
|
||||
|
@ -26,8 +30,10 @@ class KeyboardWrapperView @JvmOverloads constructor(
|
|||
private lateinit var stopOneHandedModeBtn: ImageButton
|
||||
private lateinit var switchOneHandedModeBtn: ImageButton
|
||||
private lateinit var keyboardView: View
|
||||
private lateinit var resizeOneHandedModeBtn: ImageButton
|
||||
private val iconStopOneHandedModeId: Int
|
||||
private val iconSwitchOneHandedModeId: Int
|
||||
private val iconResizeOneHandedModeId: Int
|
||||
|
||||
var oneHandedModeEnabled = false
|
||||
set(enabled) {
|
||||
|
@ -44,6 +50,7 @@ class KeyboardWrapperView @JvmOverloads constructor(
|
|||
}
|
||||
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
override fun onFinishInflate() {
|
||||
super.onFinishInflate()
|
||||
stopOneHandedModeBtn = findViewById(R.id.btn_stop_one_handed_mode)
|
||||
|
@ -52,11 +59,41 @@ class KeyboardWrapperView @JvmOverloads constructor(
|
|||
switchOneHandedModeBtn = findViewById(R.id.btn_switch_one_handed_mode)
|
||||
switchOneHandedModeBtn.setImageResource(iconSwitchOneHandedModeId)
|
||||
switchOneHandedModeBtn.visibility = GONE
|
||||
resizeOneHandedModeBtn = findViewById(R.id.btn_resize_one_handed_mode)
|
||||
resizeOneHandedModeBtn.setImageResource(iconResizeOneHandedModeId)
|
||||
resizeOneHandedModeBtn.visibility = GONE
|
||||
keyboardView = findViewById(R.id.keyboard_view)
|
||||
|
||||
stopOneHandedModeBtn.setOnClickListener(this)
|
||||
switchOneHandedModeBtn.setOnClickListener(this)
|
||||
|
||||
var x = 0f
|
||||
resizeOneHandedModeBtn.setOnTouchListener { _, motionEvent ->
|
||||
when (motionEvent.action) {
|
||||
MotionEvent.ACTION_DOWN -> x = motionEvent.rawX
|
||||
MotionEvent.ACTION_MOVE -> {
|
||||
// performance is not great because settings are reloaded and keyboard is redrawn
|
||||
// on every move, but it's good enough
|
||||
val sign = -switchOneHandedModeBtn.scaleX
|
||||
// factor 2 to make it more sensitive (maybe could be tuned a little)
|
||||
val changePercent = 2 * sign * (x - motionEvent.rawX) / context.resources.displayMetrics.density
|
||||
if (abs(changePercent) < 1) return@setOnTouchListener true
|
||||
x = motionEvent.rawX
|
||||
val prefs = DeviceProtectedUtils.getSharedPreferences(context)
|
||||
val oldScale = Settings.readOneHandedModeScale(prefs, Settings.getInstance().current.mDisplayOrientation == Configuration.ORIENTATION_PORTRAIT)
|
||||
val newScale = (oldScale + changePercent / 100f).coerceAtMost(2.5f).coerceAtLeast(0.5f)
|
||||
if (newScale == oldScale) return@setOnTouchListener true
|
||||
Settings.getInstance().writeOneHandedModeScale(newScale)
|
||||
prefs.edit().putFloat(Settings.PREF_ONE_HANDED_SCALE, newScale).apply()
|
||||
oneHandedModeEnabled = false // intentionally putting wrong value, so KeyboardSwitcher.setOneHandedModeEnabled does actually reload
|
||||
keyboardActionListener?.onCodeInput(Constants.CODE_START_ONE_HANDED_MODE,
|
||||
Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE, false)
|
||||
}
|
||||
else -> x = 0f
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
val colors = Settings.getInstance().current.mColors
|
||||
stopOneHandedModeBtn.colorFilter = colors.keyTextFilter
|
||||
switchOneHandedModeBtn.colorFilter = colors.keyTextFilter
|
||||
|
@ -74,6 +111,7 @@ class KeyboardWrapperView @JvmOverloads constructor(
|
|||
private fun updateViewsVisibility() {
|
||||
stopOneHandedModeBtn.visibility = if (oneHandedModeEnabled) VISIBLE else GONE
|
||||
switchOneHandedModeBtn.visibility = if (oneHandedModeEnabled) VISIBLE else GONE
|
||||
resizeOneHandedModeBtn.visibility = if (oneHandedModeEnabled) VISIBLE else GONE
|
||||
}
|
||||
|
||||
@SuppressLint("RtlHardcoded")
|
||||
|
@ -114,21 +152,17 @@ class KeyboardWrapperView @JvmOverloads constructor(
|
|||
|
||||
val scale = Settings.getInstance().current.mKeyboardHeightScale
|
||||
// scale one-handed mode button height if keyboard height scale is < 80%
|
||||
// more relevant: also change the distance, so the buttons are actually visible
|
||||
val heightScale = if (scale < 0.8f) scale + 0.2f else 1f
|
||||
val buttonsLeft = if (isLeftGravity) keyboardView.measuredWidth else 0
|
||||
stopOneHandedModeBtn.layout(
|
||||
buttonsLeft + (spareWidth - stopOneHandedModeBtn.measuredWidth) / 2,
|
||||
(heightScale * stopOneHandedModeBtn.measuredHeight / 2).toInt(),
|
||||
buttonsLeft + (spareWidth + stopOneHandedModeBtn.measuredWidth) / 2,
|
||||
(heightScale * 3 * stopOneHandedModeBtn.measuredHeight / 2).toInt()
|
||||
)
|
||||
switchOneHandedModeBtn.layout(
|
||||
buttonsLeft + (spareWidth - switchOneHandedModeBtn.measuredWidth) / 2,
|
||||
(heightScale * 2 * stopOneHandedModeBtn.measuredHeight).toInt(),
|
||||
buttonsLeft + (spareWidth + switchOneHandedModeBtn.measuredWidth) / 2,
|
||||
(heightScale * (2 * stopOneHandedModeBtn.measuredHeight + switchOneHandedModeBtn.measuredHeight)).toInt()
|
||||
)
|
||||
val buttonXLeft = buttonsLeft + (spareWidth - stopOneHandedModeBtn.measuredWidth) / 2
|
||||
val buttonXRight = buttonsLeft + (spareWidth + stopOneHandedModeBtn.measuredWidth) / 2
|
||||
val buttonHeight = (heightScale * stopOneHandedModeBtn.measuredHeight).toInt()
|
||||
fun View.setLayout(yPosition: Int) {
|
||||
layout(buttonXLeft, yPosition - buttonHeight / 2, buttonXRight, yPosition + buttonHeight / 2)
|
||||
}
|
||||
stopOneHandedModeBtn.setLayout((keyboardView.measuredHeight * 0.2f).toInt())
|
||||
switchOneHandedModeBtn.setLayout((keyboardView.measuredHeight * 0.5f).toInt())
|
||||
resizeOneHandedModeBtn.setLayout((keyboardView.measuredHeight * 0.8f).toInt())
|
||||
}
|
||||
|
||||
init {
|
||||
|
@ -136,6 +170,7 @@ class KeyboardWrapperView @JvmOverloads constructor(
|
|||
val keyboardAttr = context.obtainStyledAttributes(attrs, R.styleable.Keyboard, defStyle, R.style.Keyboard)
|
||||
iconStopOneHandedModeId = keyboardAttr.getResourceId(R.styleable.Keyboard_iconStopOneHandedMode, 0)
|
||||
iconSwitchOneHandedModeId = keyboardAttr.getResourceId(R.styleable.Keyboard_iconSwitchOneHandedMode, 0)
|
||||
iconResizeOneHandedModeId = keyboardAttr.getResourceId(R.styleable.Keyboard_iconResizeOneHandedMode, 0)
|
||||
keyboardAttr.recycle()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -78,7 +78,7 @@ public final class PreferencesSettingsFragment extends SubScreenFragment {
|
|||
@Override
|
||||
public void onSharedPreferenceChanged(final SharedPreferences prefs, final String key) {
|
||||
refreshEnablingsOfKeypressSoundAndVibrationAndHistRetentionSettings();
|
||||
if (Settings.PREF_SHOW_POPUP_HINTS.equals(key) || Settings.PREF_HINT_LABEL_FROM_FIRST_MORE_KEY.equals(key))
|
||||
if (Settings.PREF_SHOW_POPUP_HINTS.equals(key) || Settings.PREF_HINT_LABEL_FROM_FIRST_MORE_KEY.equals(key) || Settings.PREF_SHOW_NUMBER_ROW.equals(key))
|
||||
mReloadKeyboard = true;
|
||||
if (key.equals(Settings.PREF_LOCALIZED_NUMBER_ROW))
|
||||
KeyboardLayoutSet.onSystemLocaleChanged();
|
||||
|
|
|
@ -105,8 +105,9 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
|
|||
public static final String PREF_SHOW_SETUP_WIZARD_ICON = "pref_show_setup_wizard_icon";
|
||||
public static final String PREF_USE_NEW_KEYBOARD_PARSING = "pref_use_new_keyboard_parsing2"; // todo: remove later
|
||||
|
||||
public static final String PREF_ONE_HANDED_MODE = "pref_one_handed_mode_enabled";
|
||||
public static final String PREF_ONE_HANDED_GRAVITY = "pref_one_handed_mode_gravity";
|
||||
public static final String PREF_ONE_HANDED_MODE = "pref_one_handed_mode_enabled_p_";
|
||||
public static final String PREF_ONE_HANDED_GRAVITY = "pref_one_handed_mode_gravity_p_";
|
||||
public static final String PREF_ONE_HANDED_SCALE = "pref_one_handed_mode_scale_p_";
|
||||
|
||||
public static final String PREF_SHOW_NUMBER_ROW = "pref_show_number_row";
|
||||
public static final String PREF_LOCALIZED_NUMBER_ROW = "pref_localized_number_row";
|
||||
|
@ -393,21 +394,29 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
|
|||
return prefs.getBoolean(PREF_SHOW_SETUP_WIZARD_ICON, false);
|
||||
}
|
||||
|
||||
public static boolean readOneHandedModeEnabled(final SharedPreferences prefs) {
|
||||
return prefs.getBoolean(PREF_ONE_HANDED_MODE, false);
|
||||
public static boolean readOneHandedModeEnabled(final SharedPreferences prefs, final boolean portrait) {
|
||||
return prefs.getBoolean(PREF_ONE_HANDED_MODE + portrait, false);
|
||||
}
|
||||
|
||||
public void writeOneHandedModeEnabled(final boolean enabled) {
|
||||
mPrefs.edit().putBoolean(PREF_ONE_HANDED_MODE, enabled).apply();
|
||||
mPrefs.edit().putBoolean(PREF_ONE_HANDED_MODE + (getCurrent().mDisplayOrientation == Configuration.ORIENTATION_PORTRAIT), enabled).apply();
|
||||
}
|
||||
|
||||
public static float readOneHandedModeScale(final SharedPreferences prefs, final boolean portrait) {
|
||||
return prefs.getFloat(PREF_ONE_HANDED_SCALE + portrait, 1f);
|
||||
}
|
||||
|
||||
public void writeOneHandedModeScale(final Float scale) {
|
||||
mPrefs.edit().putFloat(PREF_ONE_HANDED_SCALE + (getCurrent().mDisplayOrientation == Configuration.ORIENTATION_PORTRAIT), scale).apply();
|
||||
}
|
||||
|
||||
@SuppressLint("RtlHardcoded")
|
||||
public static int readOneHandedModeGravity(final SharedPreferences prefs) {
|
||||
return prefs.getInt(PREF_ONE_HANDED_GRAVITY, Gravity.LEFT);
|
||||
public static int readOneHandedModeGravity(final SharedPreferences prefs, final boolean portrait) {
|
||||
return prefs.getInt(PREF_ONE_HANDED_GRAVITY + portrait, Gravity.LEFT);
|
||||
}
|
||||
|
||||
public void writeOneHandedModeGravity(final int gravity) {
|
||||
mPrefs.edit().putInt(PREF_ONE_HANDED_GRAVITY, gravity).apply();
|
||||
mPrefs.edit().putInt(PREF_ONE_HANDED_GRAVITY + (getCurrent().mDisplayOrientation == Configuration.ORIENTATION_PORTRAIT), gravity).apply();
|
||||
}
|
||||
|
||||
public static boolean readHasHardwareKeyboard(final Configuration conf) {
|
||||
|
|
|
@ -81,6 +81,7 @@ public class SettingsValues {
|
|||
public final long mClipboardHistoryRetentionTime;
|
||||
public final boolean mOneHandedModeEnabled;
|
||||
public final int mOneHandedModeGravity;
|
||||
public final float mOneHandedModeScale;
|
||||
public final boolean mNarrowKeyGaps;
|
||||
public final int mShowMoreKeys;
|
||||
public final List<Locale> mSecondaryLocales;
|
||||
|
@ -217,8 +218,15 @@ public class SettingsValues {
|
|||
mAutospaceAfterPunctuationEnabled = Settings.readAutospaceAfterPunctuationEnabled(prefs);
|
||||
mClipboardHistoryEnabled = Settings.readClipboardHistoryEnabled(prefs);
|
||||
mClipboardHistoryRetentionTime = Settings.readClipboardHistoryRetentionTime(prefs, res);
|
||||
mOneHandedModeEnabled = Settings.readOneHandedModeEnabled(prefs);
|
||||
mOneHandedModeGravity = Settings.readOneHandedModeGravity(prefs);
|
||||
|
||||
mOneHandedModeEnabled = Settings.readOneHandedModeEnabled(prefs, mDisplayOrientation == Configuration.ORIENTATION_PORTRAIT);
|
||||
mOneHandedModeGravity = Settings.readOneHandedModeGravity(prefs, mDisplayOrientation == Configuration.ORIENTATION_PORTRAIT);
|
||||
if (mOneHandedModeEnabled) {
|
||||
final float baseScale = res.getFraction(R.fraction.config_one_handed_mode_width, 1, 1);
|
||||
final float extraScale = Settings.readOneHandedModeScale(prefs, mDisplayOrientation == Configuration.ORIENTATION_PORTRAIT);
|
||||
mOneHandedModeScale = 1 - (1 - baseScale) * extraScale;
|
||||
} else
|
||||
mOneHandedModeScale = 1f;
|
||||
final InputMethodSubtype selectedSubtype = SubtypeSettingsKt.getSelectedSubtype(prefs);
|
||||
mSecondaryLocales = Settings.getSecondaryLocales(prefs, selectedSubtype.getLocale());
|
||||
mShowMoreKeys = selectedSubtype.isAsciiCapable()
|
||||
|
|
|
@ -176,8 +176,7 @@ public final class ResourceUtils {
|
|||
public static int getKeyboardWidth(final Resources res, final SettingsValues settingsValues) {
|
||||
final int defaultKeyboardWidth = getDefaultKeyboardWidth(res);
|
||||
if (settingsValues.mOneHandedModeEnabled) {
|
||||
return (int) res.getFraction(R.fraction.config_one_handed_mode_width,
|
||||
defaultKeyboardWidth, defaultKeyboardWidth);
|
||||
return (int) (settingsValues.mOneHandedModeScale * defaultKeyboardWidth);
|
||||
}
|
||||
return defaultKeyboardWidth;
|
||||
}
|
||||
|
@ -188,14 +187,14 @@ public final class ResourceUtils {
|
|||
}
|
||||
|
||||
public static int getKeyboardHeight(final Resources res, final SettingsValues settingsValues) {
|
||||
final int defaultKeyboardHeight = getDefaultKeyboardHeight(res);
|
||||
final int defaultKeyboardHeight = getDefaultKeyboardHeight(res, settingsValues.mShowsNumberRow);
|
||||
// mKeyboardHeightScale Ranges from [.5,1.5], from xml/prefs_screen_appearance.xml
|
||||
return (int)(defaultKeyboardHeight * settingsValues.mKeyboardHeightScale);
|
||||
}
|
||||
|
||||
public static int getDefaultKeyboardHeight(final Resources res) {
|
||||
private static int getDefaultKeyboardHeight(final Resources res, final boolean showsNumberRow) {
|
||||
final DisplayMetrics dm = res.getDisplayMetrics();
|
||||
final float keyboardHeight = res.getDimension(R.dimen.config_default_keyboard_height);
|
||||
final float keyboardHeight = res.getDimension(R.dimen.config_default_keyboard_height) * (showsNumberRow ? 1.25f : 1f);
|
||||
final float maxKeyboardHeight = res.getFraction(
|
||||
R.fraction.config_max_keyboard_height, dm.heightPixels, dm.heightPixels);
|
||||
float minKeyboardHeight = res.getFraction(
|
||||
|
|
15
app/src/main/res/drawable/ic_arrow_horizontal.xml
Normal file
15
app/src/main/res/drawable/ic_arrow_horizontal.xml
Normal file
|
@ -0,0 +1,15 @@
|
|||
<!--
|
||||
icon available in Android Studio
|
||||
modified
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:width="24dp"
|
||||
android:viewportHeight="24"
|
||||
android:viewportWidth="24">
|
||||
<group android:rotation="90" android:pivotX="12" android:pivotY="12" >
|
||||
<path android:fillColor="#FFF"
|
||||
android:pathData="M13,6.99l3,0l-4,-3.99l-4,3.99l3,0l0,10.02l-3,0l4,3.99l4,-3.99l-3,0z"/>
|
||||
</group>
|
||||
</vector>
|
|
@ -52,6 +52,14 @@
|
|||
android:scaleType="fitCenter"
|
||||
style="?attr/suggestionWordStyle" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/btn_resize_one_handed_mode"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp"
|
||||
android:scaleType="fitCenter"
|
||||
style="?attr/suggestionWordStyle" />
|
||||
|
||||
</org.dslul.openboard.inputmethod.latin.KeyboardWrapperView>
|
||||
|
||||
</LinearLayout>
|
||||
|
|
|
@ -24,8 +24,8 @@
|
|||
<fraction name="config_keyboard_bottom_padding_holo">0.0%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">5.368%p</fraction>
|
||||
<fraction name="config_key_horizontal_gap_holo_narrow">1.020%p</fraction>
|
||||
<fraction name="config_key_vertical_gap_holo_narrow">4.85%p</fraction>
|
||||
<fraction name="config_key_horizontal_gap_holo_narrow">0.920%p</fraction>
|
||||
<!-- config_more_keys_keyboard_key_height x -0.5 -->
|
||||
<dimen name="config_more_keys_keyboard_vertical_correction_holo">-22.4dp</dimen>
|
||||
<dimen name="config_key_preview_offset_holo">1.6dp</dimen>
|
||||
|
@ -67,9 +67,9 @@
|
|||
|
||||
<!-- Emoji keyboard -->
|
||||
<fraction name="config_emoji_keyboard_key_width">8.33%p</fraction>
|
||||
<fraction name="config_emoji_keyboard_row_height">40%p</fraction>
|
||||
<fraction name="config_emoji_keyboard_key_letter_size">70%p</fraction>
|
||||
<fraction name="config_emoji_keyboard_key_label_size">70%p</fraction>
|
||||
<fraction name="config_emoji_keyboard_row_height">41%p</fraction>
|
||||
<fraction name="config_emoji_keyboard_key_letter_size">78%p</fraction>
|
||||
<fraction name="config_emoji_keyboard_key_label_size">78%p</fraction>
|
||||
<integer name="config_emoji_keyboard_max_recents_key_count">32</integer>
|
||||
|
||||
<!-- Clipboard keyboard -->
|
||||
|
|
|
@ -271,6 +271,7 @@
|
|||
<attr name="iconStartOneHandedMode" format="reference" />
|
||||
<attr name="iconStopOneHandedMode" format="reference" />
|
||||
<attr name="iconSwitchOneHandedMode" format="reference" />
|
||||
<attr name="iconResizeOneHandedMode" format="reference" />
|
||||
<attr name="iconNumpadKey" format="reference" />
|
||||
<attr name="iconToolbarKey" format="reference" />
|
||||
<attr name="iconSelectAll" format="reference" />
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
<item name="iconStartOneHandedMode">@drawable/sym_keyboard_start_onehanded_holo</item>
|
||||
<item name="iconStopOneHandedMode">@drawable/sym_keyboard_stop_onehanded_holo</item>
|
||||
<item name="iconSwitchOneHandedMode">@drawable/sym_keyboard_switch_onehanded_holo</item>
|
||||
<item name="iconResizeOneHandedMode">@drawable/ic_arrow_horizontal</item>
|
||||
<item name="iconNumpadKey">@drawable/sym_keyboard_numpad_key_holo</item>
|
||||
<item name="iconToolbarKey">@drawable/ic_arrow_right</item>
|
||||
<item name="iconSelectAll">@drawable/ic_select_all</item>
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
<item name="iconStartOneHandedMode">@drawable/sym_keyboard_start_onehanded_lxx</item>
|
||||
<item name="iconStopOneHandedMode">@drawable/sym_keyboard_stop_onehanded_lxx</item>
|
||||
<item name="iconSwitchOneHandedMode">@drawable/ic_arrow_left</item>
|
||||
<item name="iconResizeOneHandedMode">@drawable/ic_arrow_horizontal</item>
|
||||
<item name="iconNumpadKey">@drawable/sym_keyboard_numpad_key_lxx</item>
|
||||
<item name="iconToolbarKey">@drawable/ic_arrow_right</item>
|
||||
<item name="iconSelectAll">@drawable/ic_select_all</item>
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
<item name="iconStartOneHandedMode">@drawable/sym_keyboard_start_onehanded_rounded</item>
|
||||
<item name="iconStopOneHandedMode">@drawable/sym_keyboard_stop_onehanded_rounded</item>
|
||||
<item name="iconSwitchOneHandedMode">@drawable/ic_arrow_left_rounded</item>
|
||||
<item name="iconResizeOneHandedMode">@drawable/ic_arrow_horizontal</item>
|
||||
<item name="iconNumpadKey">@drawable/sym_keyboard_numpad_key_lxx</item>
|
||||
<item name="iconToolbarKey">@drawable/ic_arrow_right_rounded</item>
|
||||
<item name="iconSelectAll">@drawable/ic_select_all_rounded</item>
|
||||
|
|
Loading…
Add table
Reference in a new issue