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:
Helium314 2023-12-18 17:30:53 +01:00 committed by GitHub
parent e78618fd6a
commit 0b55a92e02
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 184 additions and 68 deletions

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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;

View file

@ -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)

View file

@ -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)

View file

@ -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;

View file

@ -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);

View file

@ -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() {

View file

@ -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>? {

View file

@ -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
}

View file

@ -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()
}
}

View file

@ -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();

View file

@ -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) {

View file

@ -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()

View file

@ -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(

View 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>

View file

@ -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>

View file

@ -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 -->

View file

@ -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" />

View file

@ -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>

View file

@ -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>

View file

@ -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>