Add options for keyboard height and bottom offset

This commit is contained in:
Aleksandras Kostarevas 2024-05-06 16:16:04 -05:00
parent 0e1a338f0d
commit 937ece0b34
9 changed files with 160 additions and 94 deletions

View File

@ -213,8 +213,10 @@ 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 int keyWidth = keyboard.mMostCommonKeyWidth;
mKeyDrawParams.updateParams(Math.min(keyWidth, keyHeight), mKeyVisualAttributes);
mKeyDrawParams.updateParams(Math.min(keyWidth, keyHeight), keyboard.mKeyVisualAttributes);
invalidateAllKeys();
requestLayout();
}
@ -239,7 +241,8 @@ public class KeyboardView extends View {
}
protected void updateKeyDrawParams(final int keyHeight) {
mKeyDrawParams.updateParams(keyHeight, mKeyVisualAttributes);
final int keyWidth = mKeyboard.mMostCommonKeyWidth;
mKeyDrawParams.updateParams(Math.min(keyWidth, keyHeight), mKeyVisualAttributes);
}
@Override
@ -354,7 +357,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(Math.min(key.getHeight(), key.getWidth()), attr);
params.mAnimAlpha = Constants.Color.ALPHA_OPAQUE;
if (!key.isSpacer()) {

View File

@ -255,14 +255,18 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
final TypedArray keyAttr = mResources.obtainAttributes(attr, R.styleable.Keyboard_Key);
try {
final KeyboardParams params = mParams;
final int height = params.mId.mHeight;
final int offset = (int)mProvider.getKeyboardBottomOffset();
final int height = (int) (params.mId.mHeight * mProvider.getKeyboardHeightMultiplier() + offset);
final int width = params.mId.mWidth;
params.mOccupiedHeight = height;
params.mOccupiedWidth = width;
params.mTopPadding = (int)keyboardAttr.getFraction(
R.styleable.Keyboard_keyboardTopPadding, height, height, 0);
params.mBottomPadding = (int)keyboardAttr.getFraction(
R.styleable.Keyboard_keyboardBottomPadding, height, height, 0);
params.mBottomPadding = (int)(keyboardAttr.getFraction(
R.styleable.Keyboard_keyboardBottomPadding, height, height, 0)
+ mProvider.getKeyboardBottomOffset()
);
params.mLeftPadding = (int)keyboardAttr.getFraction(
R.styleable.Keyboard_keyboardLeftPadding, width, width, 0);
params.mRightPadding = (int)keyboardAttr.getFraction(
@ -279,7 +283,7 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
// rows are determined based on the entire keyboard height including top and bottom
// paddings.
params.mVerticalGap = (int)keyboardAttr.getFraction(
R.styleable.Keyboard_verticalGap, height, height, 0);
R.styleable.Keyboard_verticalGap, height - offset, height - offset, 0);
final int baseHeight = params.mOccupiedHeight - params.mTopPadding
- params.mBottomPadding + params.mVerticalGap;
params.mBaseHeight = baseHeight;

View File

@ -257,11 +257,7 @@ class LatinIME : InputMethodService(), LifecycleOwner, ViewModelStoreOwner, Save
dataStore.data.collect {
drawableProvider?.let { provider ->
if(provider is BasicThemeProvider) {
if ((it[HiddenKeysSetting] ?: provider.expertMode) != provider.expertMode
|| (it[KeyBordersSetting] ?: provider.keyBorders) != provider.keyBorders
|| (it[KeyHintsSetting] ?: provider.showKeyHints) != provider.showKeyHints
) {
Log.w("LatinIME", "One of HiddenKeysSetting, KeyBordersSetting or KeyHintsSetting has changed")
if (provider.hasUpdated(it)) {
activeThemeOption?.obtainColors?.let { f ->
updateDrawableProvider(f(this@LatinIME))
if (!uixManager.isMainKeyboardHidden) {

View File

@ -18,15 +18,20 @@ import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.core.graphics.ColorUtils
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.floatPreferencesKey
import com.google.android.material.color.DynamicColors
import org.futo.inputmethod.latin.R
import org.futo.inputmethod.latin.uix.theme.DarkColorScheme
import kotlin.math.roundToInt
val KeyBordersSetting = booleanPreferencesKey("keyBorders")
val HiddenKeysSetting = booleanPreferencesKey("hiddenKeys")
val KeyHintsSetting = booleanPreferencesKey("keyHints")
val KeyBordersSetting = SettingsKey(booleanPreferencesKey("keyBorders"), true)
val HiddenKeysSetting = SettingsKey(booleanPreferencesKey("hiddenKeys"), false)
val KeyHintsSetting = SettingsKey(booleanPreferencesKey("keyHints"), false)
val KeyboardHeightMultiplierSetting = SettingsKey(floatPreferencesKey("keyboardHeightMultiplier"), 1.0f)
val KeyboardBottomOffsetSetting = SettingsKey(floatPreferencesKey("keyboardOffset"), 0.0f)
fun adjustColorBrightnessForContrast(bgColor: Int, fgColor: Int, desiredContrast: Float, adjustSaturation: Boolean = false): Int {
// Convert RGB colors to HSL
@ -76,6 +81,14 @@ class BasicThemeProvider(val context: Context, val overrideColorScheme: ColorSch
return drawables[i]
}
override fun getKeyboardHeightMultiplier(): Float {
return keyboardHeight
}
override fun getKeyboardBottomOffset(): Float {
return dp(keyboardBottomOffsetValue.dp)
}
private fun dp(dp: Dp): Float {
return TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
@ -122,6 +135,22 @@ class BasicThemeProvider(val context: Context, val overrideColorScheme: ColorSch
val keyBorders: Boolean
val showKeyHints: Boolean
val keyboardHeight: Float
val keyboardBottomOffsetValue: Float
fun hasUpdated(newPreferences: Preferences): Boolean {
return when {
newPreferences[HiddenKeysSetting.key] != expertMode -> true
newPreferences[KeyBordersSetting.key] != keyBorders -> true
newPreferences[KeyHintsSetting.key] != showKeyHints -> true
newPreferences[KeyboardHeightMultiplierSetting.key] != keyboardHeight -> true
newPreferences[KeyboardBottomOffsetSetting.key] != keyboardBottomOffsetValue -> true
else -> false
}
}
init {
val colorScheme = if(overrideColorScheme != null) {
overrideColorScheme
@ -133,9 +162,12 @@ class BasicThemeProvider(val context: Context, val overrideColorScheme: ColorSch
dynamicLightColorScheme(dCtx)
}
expertMode = context.getSettingBlocking(HiddenKeysSetting, false)
keyBorders = context.getSettingBlocking(KeyBordersSetting, false)
showKeyHints = context.getSettingBlocking(KeyHintsSetting, false)
expertMode = context.getSettingBlocking(HiddenKeysSetting)
keyBorders = context.getSettingBlocking(KeyBordersSetting)
showKeyHints = context.getSettingBlocking(KeyHintsSetting)
keyboardHeight = context.getSettingBlocking(KeyboardHeightMultiplierSetting.key, KeyboardHeightMultiplierSetting.default)
keyboardBottomOffsetValue = context.getSettingBlocking(KeyboardBottomOffsetSetting.key, KeyboardBottomOffsetSetting.default)
val primary = colorScheme.primary.toArgb()
val secondary = colorScheme.secondary.toArgb()

View File

@ -22,6 +22,9 @@ interface DynamicThemeProvider {
fun getDrawable(i: Int): Drawable?
fun getKeyboardHeightMultiplier(): Float
fun getKeyboardBottomOffset(): Float
companion object {
@ColorInt
fun getColorOrDefault(i: Int, @ColorInt default: Int, keyAttr: TypedArray, provider: DynamicThemeProvider?): Int {

View File

@ -49,6 +49,10 @@ fun <T> Context.getSettingBlocking(key: Preferences.Key<T>, default: T): T {
}
}
fun <T> Context.getSettingBlocking(key: SettingsKey<T>): T {
return getSettingBlocking(key.key, key.default)
}
fun <T> Context.setSettingBlocking(key: Preferences.Key<T>, value: T) {
val context = this
runBlocking {

View File

@ -304,71 +304,73 @@ fun<T: Number> SettingSlider(
if(isTextFieldVisible) focusRequester.requestFocus()
}
ScreenTitle(title, showBack = false)
if(subtitle != null) {
Text(subtitle, style = Typography.bodyMedium, modifier = Modifier.padding(12.dp, 0.dp))
}
Row(modifier = Modifier.padding(16.dp, 0.dp)) {
if (isTextFieldVisible) {
val apply = {
if(isTextFieldVisible) {
val number = textFieldValue.text.trim().toFloatOrNull()
val newValue = if (number != null) {
transform(number.coerceIn(hardRange))
} else {
setting.default
Column {
ScreenTitle(title, showBack = false)
if(subtitle != null) {
Text(subtitle, style = Typography.bodyMedium, modifier = Modifier.padding(12.dp, 0.dp))
}
Row(modifier = Modifier.padding(16.dp, 0.dp)) {
if (isTextFieldVisible) {
val apply = {
if(isTextFieldVisible) {
val number = textFieldValue.text.trim().toFloatOrNull()
val newValue = if (number != null) {
transform(number.coerceIn(hardRange))
} else {
setting.default
}
setValue(newValue)
virtualValue = newValue.toFloat().pow(1.0f / power)
isTextFieldVisible = false
textFieldValue = TextFieldValue()
}
setValue(newValue)
virtualValue = newValue.toFloat().pow(1.0f / power)
isTextFieldVisible = false
textFieldValue = TextFieldValue()
}
}
BasicTextField(
value = textFieldValue,
onValueChange = { textFieldValue = it },
modifier = Modifier
.weight(0.33f)
.align(Alignment.CenterVertically)
.focusRequester(focusRequester)
.onFocusChanged {
if(it.isFocused) hasTextFieldFocusedYet = true
else if(!it.isFocused && hasTextFieldFocusedYet) apply()
},
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
keyboardActions = KeyboardActions(
onDone = {
apply()
}
),
singleLine = true,
textStyle = Typography.labelMedium
)
BasicTextField(
value = textFieldValue,
onValueChange = { textFieldValue = it },
modifier = Modifier
.weight(0.33f)
.align(Alignment.CenterVertically)
.focusRequester(focusRequester)
.onFocusChanged {
if (it.isFocused) hasTextFieldFocusedYet = true
else if (!it.isFocused && hasTextFieldFocusedYet) apply()
},
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
keyboardActions = KeyboardActions(
onDone = {
apply()
}
),
singleLine = true,
textStyle = Typography.labelMedium
)
} else {
Text(
text = indicator(value),
modifier = Modifier
.weight(0.33f)
.align(Alignment.CenterVertically)
.clickable {
hasTextFieldFocusedYet = false
isTextFieldVisible = true
},
style = Typography.labelMedium
} else {
Text(
text = indicator(value),
modifier = Modifier
.weight(0.33f)
.align(Alignment.CenterVertically)
.clickable {
hasTextFieldFocusedYet = false
isTextFieldVisible = true
},
style = Typography.labelMedium
)
}
Slider(
value = virtualValue,
onValueChange = {
virtualValue = it
setValue(transform(it.pow(power))) },
valueRange = range.start.pow(1.0f / power) .. range.endInclusive.pow(1.0f / power),
enabled = !isTextFieldVisible,
modifier = Modifier.weight(1.0f)
)
}
Slider(
value = virtualValue,
onValueChange = {
virtualValue = it
setValue(transform(it.pow(power))) },
valueRange = range.start.pow(1.0f / power) .. range.endInclusive.pow(1.0f / power),
enabled = !isTextFieldVisible,
modifier = Modifier.weight(1.0f)
)
}
}

View File

@ -49,7 +49,7 @@ fun DeveloperScreen(navController: NavHostController = rememberNavController())
SettingToggleDataStore(
title = "Touch typing mode",
subtitle = "Hides all keys. Touch typists only! Recommended to disable emoji key and enable key borders",
setting = SettingsKey(HiddenKeysSetting, false)
setting = HiddenKeysSetting
)
NavigationItem(

View File

@ -33,11 +33,12 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import org.futo.inputmethod.latin.uix.HiddenKeysSetting
import org.futo.inputmethod.latin.uix.KeyBordersSetting
import org.futo.inputmethod.latin.uix.KeyHintsSetting
import org.futo.inputmethod.latin.uix.SettingsKey
import org.futo.inputmethod.latin.uix.KeyboardBottomOffsetSetting
import org.futo.inputmethod.latin.uix.KeyboardHeightMultiplierSetting
import org.futo.inputmethod.latin.uix.THEME_KEY
import org.futo.inputmethod.latin.uix.settings.SettingSlider
import org.futo.inputmethod.latin.uix.settings.SettingToggleDataStore
import org.futo.inputmethod.latin.uix.settings.useDataStore
import org.futo.inputmethod.latin.uix.theme.ThemeOption
@ -48,6 +49,7 @@ import org.futo.inputmethod.latin.uix.theme.UixThemeWrapper
import org.futo.inputmethod.latin.uix.theme.presets.AMOLEDDarkPurple
import org.futo.inputmethod.latin.uix.theme.presets.ClassicMaterialDark
import org.futo.inputmethod.latin.uix.theme.presets.VoiceInputTheme
import kotlin.math.roundToInt
// TODO: For Dynamic System we need to show the user that it switches between light/dark
@Composable
@ -185,18 +187,6 @@ fun ThemePicker(onSelected: (ThemeOption) -> Unit) {
modifier = Modifier.fillMaxWidth(),
columns = GridCells.Adaptive(minSize = 172.dp)
) {
item(span = { GridItemSpan(maxCurrentLineSpan) }) {
SettingToggleDataStore(
title = "Key borders",
setting = SettingsKey(KeyBordersSetting, false)
)
}
item(span = { GridItemSpan(maxCurrentLineSpan) }) {
SettingToggleDataStore(
title = "Show symbol hints",
setting = SettingsKey(KeyHintsSetting, false)
)
}
items(availableThemeOptions.count()) {
val themeOption = availableThemeOptions[it].second
@ -216,6 +206,38 @@ fun ThemePicker(onSelected: (ThemeOption) -> Unit) {
toast.show()
}
}
item(span = { GridItemSpan(maxCurrentLineSpan) }) { }
item(span = { GridItemSpan(maxCurrentLineSpan) }) {
SettingToggleDataStore(
title = "Key borders",
setting = KeyBordersSetting
)
}
item(span = { GridItemSpan(maxCurrentLineSpan) }) {
SettingToggleDataStore(
title = "Show symbol hints",
setting = KeyHintsSetting
)
}
item(span = { GridItemSpan(maxCurrentLineSpan) }) {
SettingSlider(
title = "Keyboard Height",
setting = KeyboardHeightMultiplierSetting,
range = 0.1f .. 2.0f, transform = { it },
indicator = { "${(it * 100.0f).roundToInt()}%" }
)
}
item(span = { GridItemSpan(maxCurrentLineSpan) }) {
SettingSlider(
title = "Keyboard Offset",
setting = KeyboardBottomOffsetSetting,
range = 0.0f .. 128.0f, transform = { it },
indicator = { "${String.format("%.1f", it)} dp" }
)
}
}
}
}