Merge branch 'main' into side_padding

This commit is contained in:
Helium314 2025-01-26 15:31:54 +01:00 committed by GitHub
commit d9e81e7a33
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
76 changed files with 505 additions and 277 deletions

View file

@ -9,7 +9,7 @@ If you have difficulties implementing some functionality, you're welcome to ask
# Guidelines
HeliBoard is a complex application, when contributing, you must take a step back and make sure your contribution:
- **Is actually wanted**. Best check related open issues before you start working on a PR. Issues with "PR" and "contributor needed" labels are accepted, but still it would be good if you announced that you are working on it, so we can discuss how changes are best implemented.
- **Is actually wanted**. Best check related open issues before you start working on a PR. Issues with the [labels](https://github.com/Helium314/HeliBoard/labels) [_PR_](https://github.com/Helium314/HeliBoard/labels/PR) and [_contributor needed_](https://github.com/Helium314/HeliBoard/issues?q=label%3A%22contributor%20needed%22) (even closed ones) are accepted, but still it would be good if you announced that you are working on it, so we can discuss how changes are best implemented.
If there is no accepted issue related to your intended contribution, it's a good idea to open a new one (and of course getting one of "PR" or "contributor needed" labels) to avoid disappointment of the contribution not being accepted. For small changes or fixing obvious bugs this step is not necessary.
- **Is only about a single thing**. Mixing unrelated or semi-related contributions into a single PR is hard to review and can get messy.
- **Is finished or a draft**. When you keep changing the PR without reviewer's feedback, any attempt to review it is doomed and a waste of time. Better mark it as a draft in this case.
@ -18,6 +18,7 @@ HeliBoard is a complex application, when contributing, you must take a step back
- **Has a low footprint**. Some parts of the code are executed very frequently, and the keyboard should stay responsive even on older devices.
- **Does not bring any non-free code or proprietary binary blobs**. This also applies to code/binaries with unknown licenses. Make sure you do not introduce any closed-source library from Google.
If your contribution contains code that is not your own, provide a link to the source.
- **Does not increase app size too much**. Just code changes or adding icons is not in issue, but e.g. large dependencies or adding more default dictionaries will not be accepted.
- **Complies with the user privacy principle HeliBoard follows**.
A good description and small scope ("single thing") massively help with reviewing. Don't be surprised when your PR gets closes if you clearly / repeatedly violate these parts of the guidelines.

View file

@ -1,117 +0,0 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlinx-serialization'
android {
compileSdk 34
buildToolsVersion = '34.0.0'
defaultConfig {
applicationId "helium314.keyboard"
minSdkVersion 21
targetSdkVersion 34
versionCode 2301
versionName '2.3'
ndk {
abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
}
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
buildTypes {
release {
minifyEnabled true
shrinkResources false
debuggable false
jniDebuggable false
renderscriptDebuggable false
}
nouserlib { // same as release, but does not allow the user to provide a library
minifyEnabled true
shrinkResources false
debuggable false
jniDebuggable false
renderscriptDebuggable false
}
debug {
minifyEnabled true
jniDebuggable false
applicationIdSuffix ".debug"
}
runTests { // build variant for running tests on CI that skips tests known to fail
minifyEnabled true
jniDebuggable false
}
archivesBaseName = "HeliBoard_" + defaultConfig.versionName
}
buildFeatures {
viewBinding true
buildConfig true
}
externalNativeBuild {
ndkBuild {
path 'src/main/jni/Android.mk'
}
}
ndkVersion '26.2.11394342'
packagingOptions {
jniLibs {
// shrinks APK by 3 MB, zipped size unchanged
useLegacyPackaging true
}
}
testOptions {
unitTests {
includeAndroidResources = true
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_17.toString()
}
// see https://github.com/Helium314/HeliBoard/issues/477
dependenciesInfo {
includeInApk = false
includeInBundle = false
}
namespace "helium314.keyboard.latin"
lint {
abortOnError true
}
}
dependencies {
// androidx
implementation 'androidx.core:core-ktx:1.13.1'
implementation 'androidx.appcompat:appcompat:1.7.0'
implementation 'androidx.preference:preference:1.2.1'
implementation 'androidx.recyclerview:recyclerview:1.3.2'
implementation 'androidx.autofill:autofill:1.1.0'
// kotlin
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3"
// color picker for user-defined colors
implementation 'com.github.martin-stone:hsv-alpha-color-picker-android:3.1.0'
// test
testImplementation 'junit:junit:4.13.2'
testImplementation 'org.mockito:mockito-core:5.14.2'
testImplementation 'org.robolectric:robolectric:4.12.1'
testImplementation 'androidx.test:runner:1.6.2'
testImplementation 'androidx.test:core:1.6.1'
}

118
app/build.gradle.kts Executable file
View file

@ -0,0 +1,118 @@
plugins {
id("com.android.application")
kotlin("android")
kotlin("plugin.serialization") version "2.0.21"
}
android {
compileSdk = 34
buildToolsVersion = "34.0.0"
defaultConfig {
applicationId = "helium314.keyboard"
minSdk = 21
targetSdk = 34
versionCode = 2301
versionName = "2.3"
ndk {
abiFilters.clear()
abiFilters.addAll(listOf("armeabi-v7a", "arm64-v8a", "x86", "x86_64"))
}
proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro")
}
buildTypes {
release {
isMinifyEnabled = true
isShrinkResources = false
isDebuggable = false
isJniDebuggable = false
}
create("nouserlib") { // same as release, but does not allow the user to provide a library
isMinifyEnabled = true
isShrinkResources = false
isDebuggable = false
isJniDebuggable = false
}
debug {
isMinifyEnabled = true
isJniDebuggable = false
applicationIdSuffix = ".debug"
}
create("runTests") { // build variant for running tests on CI that skips tests known to fail
isMinifyEnabled = true
isJniDebuggable = false
}
base.archivesBaseName = "HeliBoard_" + defaultConfig.versionName
}
buildFeatures {
viewBinding = true
buildConfig = true
}
externalNativeBuild {
ndkBuild {
path = File("src/main/jni/Android.mk")
}
}
ndkVersion = "26.2.11394342"
packagingOptions {
jniLibs {
// shrinks APK by 3 MB, zipped size unchanged
useLegacyPackaging = true
}
}
testOptions {
unitTests {
isIncludeAndroidResources = true
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_17.toString()
}
// see https://github.com/Helium314/HeliBoard/issues/477
dependenciesInfo {
includeInApk = false
includeInBundle = false
}
namespace = "helium314.keyboard.latin"
lint {
abortOnError = true
}
}
dependencies {
// androidx
implementation("androidx.core:core-ktx:1.13.1")
implementation("androidx.appcompat:appcompat:1.7.0")
implementation("androidx.preference:preference:1.2.1")
implementation("androidx.recyclerview:recyclerview:1.3.2")
implementation("androidx.autofill:autofill:1.1.0")
// kotlin
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.8.0")
// color picker for user-defined colors
implementation("com.github.martin-stone:hsv-alpha-color-picker-android:3.1.0")
// test
testImplementation(kotlin("test"))
testImplementation("junit:junit:4.13.2")
testImplementation("org.mockito:mockito-core:5.15.2")
testImplementation("org.robolectric:robolectric:4.12.1")
testImplementation("androidx.test:runner:1.6.2")
testImplementation("androidx.test:core:1.6.1")
}

View file

@ -6,3 +6,6 @@ o ó ô ö ò õ œ ø ō
u ú û ü ù ū
n ñ ń
y ý ij
[tlds]
za

View file

@ -24,3 +24,6 @@ question: ؟
[number_row]
١ ٢ ٣ ٤ ٥ ٦ ٧ ٨ ٩ ٠
[tlds]
sa

View file

@ -3,3 +3,6 @@
[labels]
alphabet: АБВ
[tlds]
bg

View file

@ -10,3 +10,6 @@ punctuation !autoColumnOrder!9 \, ? ! · # ) ( / ; ' @ : - " + \% &
[extra_keys]
2: ç
[tlds]
cat es

View file

@ -14,3 +14,6 @@ y ý
z ž
'
" ” „ “ » «
[tlds]
cz

View file

@ -9,3 +9,6 @@ o ø
1: å
2: æ ä
2: ø ö
[tlds]
dk

View file

@ -5,3 +5,6 @@ u ü
s ß
'
" ” „ “ » «
[tlds]
de at ch

View file

@ -9,3 +9,6 @@
[labels]
alphabet: ΑΒΓ
[tlds]
gr

View file

@ -10,3 +10,6 @@ punctuation !autoColumnOrder!9 \, ? ! # ) ( / ; ¡ ' @ : - " + \% & ¿
[extra_keys]
2: ñ
[tlds]
es com.es

View file

@ -12,3 +12,6 @@ z ž
2: ö õ
2: ä
3: õ
[tlds]
ee

View file

@ -17,3 +17,6 @@ question: ؟
[number_row]
۱ ۲ ۳ ۴ ۵ ۶ ۷ ۸ ۹ ۰
[tlds]
ir

View file

@ -8,3 +8,6 @@ z ž
1: å
2: ö ø
2: ä æ
[tlds]
fi

View file

@ -11,3 +11,6 @@ y ÿ
1: è ü
2: é ö
2: à ä
[tlds]
fr

View file

@ -0,0 +1,2 @@
[tlds]
in

View file

@ -73,3 +73,6 @@ period: ।
[number_row]
१ २ ३ ४ ५ ६ ७ ८ ९
[tlds]
in

View file

@ -5,3 +5,6 @@ c č ć
d đ
'
" “ „ ” » «
[tlds]
hr

View file

@ -6,3 +6,6 @@ o ó ö ő
u ú ü ű
'
" “ „ ” » «
[tlds]
hu gov.hu

View file

@ -6,3 +6,6 @@ punctuation !autoColumnOrder!8 \, ՞ ՜ … ' = / ՝ ՛ ֊ » « ― ) (
[labels]
alphabet: ԱԲԳ
period: ։
[tlds]
am

View file

@ -9,3 +9,6 @@ y ý
t þ
'
" ” „ “
[tlds]
is

View file

@ -4,3 +4,6 @@ e è é ə
i ì
o ò ó º
u ù
[tlds]
it gov.it edu.it

View file

@ -10,3 +10,6 @@
[labels]
alphabet: אבג
[tlds]
il co.il gov.il

View file

@ -14,3 +14,5 @@ b p
[labels]
alphabet: AƐΓ
[tlds]
dz fr

View file

@ -1,2 +1,5 @@
[labels]
alphabet: ㄱㄴㄷ
[tlds]
kr

View file

@ -8,3 +8,6 @@ u ū ų
z ž
'
" ” „ “
[tlds]
lt

View file

@ -13,3 +13,6 @@ u ū
z ž
'
" ” „ “
[tlds]
lv

View file

@ -9,3 +9,6 @@ o ø
1: å
2: ø ö
2: æ ä
[tlds]
no

View file

@ -9,3 +9,6 @@ z ż ź
l ł
'
" “ „ ”
[tlds]
pl

View file

@ -5,3 +5,6 @@ s ș
t ț
'
" “ „ ”
[tlds]
ro

View file

@ -6,3 +6,6 @@
[labels]
alphabet: АБВ
[tlds]
ru

View file

@ -15,3 +15,6 @@ z ž
l ľ ĺ
'
" ” „ “ » «
[tlds]
sk

View file

@ -4,3 +4,6 @@ c č ć
z ž
'
" ” „ “ » «
[tlds]
si

View file

@ -10,3 +10,6 @@ d đ
2: ć
3: đ
3: ž
[tlds]
rs

View file

@ -6,3 +6,6 @@
[labels]
alphabet: АБВ
[tlds]
rs

View file

@ -8,3 +8,6 @@ o ö
1: å
2: ö
2: ä
[tlds]
sv

View file

@ -7,3 +7,6 @@ u ü û
s ş
g ğ
c ç
[tlds]
tr gov.tr edu.tr com.tr

View file

@ -7,3 +7,6 @@
[labels]
alphabet: АБВ
[tlds]
ua

View file

@ -6,3 +6,6 @@ o ò ó ỏ õ ọ ô ồ ố ổ ỗ ộ ơ ờ ớ ở ỡ ợ
u ù ú ủ ũ ụ ư ừ ứ ử ữ ự
y ỳ ý ỷ ỹ ỵ
d đ
[tlds]
vn

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

@ -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()
@ -183,6 +182,9 @@ class ClipboardHistoryView @JvmOverloads constructor(
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() {
@ -247,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

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

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

@ -43,6 +43,7 @@ class LocaleKeyboardInfos(dataStream: InputStream?, locale: Locale) {
"mns" -> Key.LABEL_FLAGS_FOLLOW_KEY_LETTER_RATIO
else -> 0
}
val tlds = getLocaleTlds(locale) // todo: USE IT
init {
readStream(dataStream, false, true)
@ -74,17 +75,25 @@ class LocaleKeyboardInfos(dataStream: InputStream?, locale: Locale) {
"[extra_keys]" -> { mode = READER_MODE_EXTRA_KEYS; return@forEachLine }
"[labels]" -> { mode = READER_MODE_LABELS; return@forEachLine }
"[number_row]" -> { mode = READER_MODE_NUMBER_ROW; return@forEachLine }
"[tlds]" -> { mode = READER_MODE_TLD; return@forEachLine }
}
when (mode) {
READER_MODE_POPUP_KEYS -> addPopupKeys(line, priority)
READER_MODE_EXTRA_KEYS -> if (!onlyPopupKeys) addExtraKey(line.split(colonSpaceRegex, 2))
READER_MODE_LABELS -> if (!onlyPopupKeys) addLabel(line.split(colonSpaceRegex, 2))
READER_MODE_NUMBER_ROW -> localizedNumberKeys = line.splitOnWhitespace()
READER_MODE_TLD -> line.splitOnWhitespace().forEach { tlds.add(".$it") }
}
}
}
}
fun addDefaultTlds(locale: Locale) {
if ((locale.language != "en" && euroLocales.matches(locale.language)) || euroCountries.matches(locale.country))
tlds.add(".eu")
tlds.addAll(defaultTlds.splitOnWhitespace())
}
/** Pair(extraKeysLeft, extraKeysRight) */
fun getTabletExtraKeys(elementId: Int): Pair<List<KeyData>, List<KeyData>> {
val flags = Key.LABEL_FLAGS_FONT_DEFAULT
@ -192,6 +201,7 @@ private fun createLocaleKeyTexts(context: Context, params: KeyboardParams, popup
if (locale == params.mId.locale) return@forEach
lkt.addFile(getStreamForLocale(locale, context), true)
}
lkt.addDefaultTlds(params.mId.locale)
when (popupKeysSetting) {
POPUP_KEYS_MAIN -> lkt.addFile(context.assets.open("$LOCALE_TEXTS_FOLDER/more_popups_main.txt"), false)
POPUP_KEYS_MORE -> lkt.addFile(context.assets.open("$LOCALE_TEXTS_FOLDER/more_popups_more.txt"), false)
@ -212,6 +222,20 @@ private fun getStreamForLocale(locale: Locale, context: Context) =
}
}
private fun getLocaleTlds(locale: Locale): LinkedHashSet<String> {
val ccLower = locale.country.lowercase()
val tlds = LinkedHashSet<String>()
if (ccLower.isEmpty() || ccLower == "zz")
return tlds
specialCountryTlds.forEach {
if (ccLower != it.first) return@forEach
tlds.addAll(it.second.splitOnWhitespace())
return tlds
}
tlds.add(".$ccLower")
return tlds
}
fun clearCache() = localeKeyboardInfosCache.clear()
// cache the texts, so they don't need to be read over and over
@ -222,6 +246,7 @@ private const val READER_MODE_POPUP_KEYS = 1
private const val READER_MODE_EXTRA_KEYS = 2
private const val READER_MODE_LABELS = 3
private const val READER_MODE_NUMBER_ROW = 4
private const val READER_MODE_TLD = 5
// probably could be improved and extended, currently this is what's done in key_styles_currency.xml
private fun getCurrencyKey(locale: Locale): Pair<String, List<String>> {
@ -294,3 +319,16 @@ const val POPUP_KEYS_MAIN = 3
const val POPUP_KEYS_NORMAL = 0
private const val LOCALE_TEXTS_FOLDER = "locale_key_texts"
// either tld is not simply lowercase ISO 3166-1 code, or there are multiple according to some list
private val specialCountryTlds = listOf(
"bd" to ".bd .com.bd",
"bq" to ".bq .an .nl",
"bl" to ".bl .gp .fr",
"sx" to ".sx .an",
"gb" to ".uk .co.uk",
"eh" to ".eh .ma",
"mf" to ".mf .gp .fr",
"tl" to ".tl .tp",
)
private const val defaultTlds = ".com .gov .edu .org .net"

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

@ -111,19 +111,17 @@ fun checkVersionUpgrade(context: Context) {
if (additionalSubtypeString.contains(".")) { // means there are custom layouts
val subtypeStrings = additionalSubtypeString.split(";")
val newSubtypeStrings = subtypeStrings.mapNotNull {
if ("." !in it) // not a custom subtype, nothing to do
return@mapNotNull it
val split = it.split(":").toMutableList()
Log.i("test", "0: $it")
if (split.size < 2) return@mapNotNull null // should never happen
val oldName = split[1]
val newName = oldName.substringBeforeLast(".") + "."
if (oldName == newName) return@mapNotNull split.joinToString(":") // should never happen
val oldFile = getCustomLayoutFile(oldName, context)
val newFile = getCustomLayoutFile(newName, context)
Log.i("test", "1")
if (!oldFile.exists()) return@mapNotNull null // should never happen
Log.i("test", "2")
if (newFile.exists()) newFile.delete() // should never happen
Log.i("test", "3")
oldFile.renameTo(newFile)
val enabledSubtypes = prefs.getString(Settings.PREF_ENABLED_SUBTYPES, "")!!
if (enabledSubtypes.contains(oldName))

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

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

View file

@ -105,6 +105,9 @@ 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) {

View file

@ -112,8 +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";
@ -501,6 +504,12 @@ 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);

View file

@ -121,6 +121,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
@ -263,7 +265,7 @@ 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);
@ -275,6 +277,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

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

@ -311,10 +311,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 -->

View file

@ -24,7 +24,7 @@
android:summary="@string/gnu_gpl"
android:icon="@drawable/ic_settings_about_license">
<intent android:action="android.intent.action.VIEW"
android:data="https://github.com/Helium314/HeliBoard/blob/main/LICENSE-GPL-3" />
android:data="https://github.com/Helium314/HeliBoard/blob/main/LICENSE" />
</Preference>
<Preference

View file

@ -111,6 +111,13 @@
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"
@ -137,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

@ -2,8 +2,8 @@ package helium314.keyboard
import helium314.keyboard.keyboard.internal.KeySpecParser
import helium314.keyboard.keyboard.internal.keyboard_parser.floris.KeyCode
import org.junit.Assert.assertEquals
import org.junit.Test
import kotlin.test.Test
import kotlin.test.assertEquals
class KeySpecParserTest {
@Test fun label() {

View file

@ -9,6 +9,7 @@ import helium314.keyboard.keyboard.Keyboard
import helium314.keyboard.keyboard.KeyboardId
import helium314.keyboard.keyboard.KeyboardLayoutSet
import helium314.keyboard.keyboard.internal.KeySpecParser
import helium314.keyboard.keyboard.internal.KeySpecParser.KeySpecParserError
import helium314.keyboard.keyboard.internal.KeyboardBuilder
import helium314.keyboard.keyboard.internal.KeyboardParams
import helium314.keyboard.keyboard.internal.TouchPositionCorrection
@ -22,11 +23,6 @@ import helium314.keyboard.latin.RichInputMethodSubtype
import helium314.keyboard.latin.utils.AdditionalSubtypeUtils.createEmojiCapableAdditionalSubtype
import helium314.keyboard.latin.utils.POPUP_KEYS_LAYOUT
import helium314.keyboard.latin.utils.checkKeys
import org.junit.Assert.assertEquals
import org.junit.Assert.assertThrows
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.Robolectric
import org.robolectric.RobolectricTestRunner
@ -35,6 +31,11 @@ import org.robolectric.annotation.Implementation
import org.robolectric.annotation.Implements
import org.robolectric.shadows.ShadowLog
import java.util.Locale
import kotlin.test.BeforeTest
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
import kotlin.test.assertTrue
@RunWith(RobolectricTestRunner::class)
@Config(shadows = [
@ -45,8 +46,7 @@ class ParserTest {
private lateinit var latinIME: LatinIME
private lateinit var params: KeyboardParams
@Before
fun setUp() {
@BeforeTest fun setUp() {
latinIME = Robolectric.setupService(LatinIME::class.java)
ShadowLog.setupLogging()
ShadowLog.stream = System.out
@ -320,7 +320,7 @@ f""", // no newline at the end
}
@Test fun invalidKeys() {
assertThrows(KeySpecParser.KeySpecParserError::class.java) {
assertFailsWith<KeySpecParserError> {
RawKeyboardParser.parseJsonString("""[[{ "label": "!icon/clipboard_action_key" }]]""").map { it.mapNotNull { it.compute(params)?.toKeyParams(params) } }
}
}
@ -402,7 +402,7 @@ f""", // no newline at the end
}
@Test fun invalidPopupKeys() {
assertThrows(KeySpecParser.KeySpecParserError::class.java) {
assertFailsWith<KeySpecParserError> {
RawKeyboardParser.parseJsonString("""[[{ "label": "a", "popup": {
"main": { "label": "!icon/clipboard_action_key" }
} }]]""").map { it.mapNotNull { it.compute(params)?.toKeyParams(params) } }

View file

@ -24,9 +24,6 @@ import helium314.keyboard.latin.inputlogic.SpaceState
import helium314.keyboard.latin.settings.Settings
import helium314.keyboard.latin.utils.DeviceProtectedUtils
import helium314.keyboard.latin.utils.ScriptUtils
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito
import org.robolectric.Robolectric
@ -37,6 +34,9 @@ import org.robolectric.annotation.Implements
import org.robolectric.shadows.ShadowLog
import java.util.*
import kotlin.math.min
import kotlin.test.BeforeTest
import kotlin.test.Test
import kotlin.test.assertEquals
@RunWith(RobolectricTestRunner::class)
@Config(shadows = [
@ -61,7 +61,8 @@ class InputLogicTest {
private val composingReader = RichInputConnection::class.java.getDeclaredField("mComposingText").apply { isAccessible = true }
private val connectionComposingText get() = (composingReader.get(connection) as CharSequence).toString()
@Before fun setUp() {
@BeforeTest
fun setUp() {
latinIME = Robolectric.setupService(LatinIME::class.java)
// start logging only after latinIME is created, avoids showing the stack traces if library is not found
ShadowLog.setupLogging()

View file

@ -2,8 +2,8 @@
package helium314.keyboard.latin
import helium314.keyboard.latin.common.LocaleUtils.constructLocale
import org.junit.Assert.assertEquals
import org.junit.Test
import kotlin.test.Test
import kotlin.test.assertEquals
class LocaleUtilsTest {
@Test fun createLocales() {

View file

@ -6,8 +6,8 @@ import helium314.keyboard.latin.utils.ScriptUtils.SCRIPT_CYRILLIC
import helium314.keyboard.latin.utils.ScriptUtils.SCRIPT_DEVANAGARI
import helium314.keyboard.latin.utils.ScriptUtils.SCRIPT_LATIN
import helium314.keyboard.latin.utils.ScriptUtils.script
import org.junit.Assert.assertEquals
import org.junit.Test
import kotlin.test.Test
import kotlin.test.assertEquals
class ScriptUtilsTest {
@Test fun defaultScript() {

View file

@ -3,8 +3,8 @@ package helium314.keyboard.latin
import helium314.keyboard.latin.common.StringUtils
import helium314.keyboard.latin.common.getFullEmojiAtEnd
import org.junit.Assert.assertEquals
import org.junit.Test
import kotlin.test.Test
import kotlin.test.assertEquals
// todo: actually this test could/should be significantly expanded...
class StringUtilsTest {

View file

@ -15,8 +15,6 @@ import helium314.keyboard.latin.settings.Settings
import helium314.keyboard.latin.settings.SettingsValuesForSuggestion
import helium314.keyboard.latin.utils.DeviceProtectedUtils
import helium314.keyboard.latin.utils.SuggestionResults
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.Robolectric
import org.robolectric.RobolectricTestRunner
@ -25,6 +23,8 @@ import org.robolectric.annotation.Implementation
import org.robolectric.annotation.Implements
import org.robolectric.shadows.ShadowLog
import java.util.*
import kotlin.test.BeforeTest
import kotlin.test.Test
@Suppress("NonAsciiCharacters")
@RunWith(RobolectricTestRunner::class)
@ -43,7 +43,7 @@ class SuggestTest {
private val thresholdAggressive = "1"
private val thresholdVeryAggressive = "2"
@Before fun setUp() {
@BeforeTest fun setUp() {
latinIME = Robolectric.setupService(LatinIME::class.java)
// start logging only after latinIME is created, avoids showing the stack traces if library is not found
ShadowLog.setupLogging()

View file

@ -1,33 +0,0 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext.kotlin_version = '2.0.21'
repositories {
mavenCentral()
google()
}
dependencies {
classpath 'com.android.tools.build:gradle:8.7.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
plugins {
id 'org.jetbrains.kotlin.plugin.serialization' version "$kotlin_version"
}
allprojects {
repositories {
google()
mavenCentral()
maven { url "https://jitpack.io" }
}
}
tasks.register('clean', Delete) {
delete rootProject.layout.buildDirectory
}

24
build.gradle.kts Executable file
View file

@ -0,0 +1,24 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
val kotlinVersion = "2.0.21"
repositories {
mavenCentral()
google()
}
dependencies {
classpath("com.android.tools.build:gradle:8.7.2")
classpath(kotlin("gradle-plugin", version = kotlinVersion))
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
mavenCentral()
maven { url = uri("https://jitpack.io") }
}
}

View file

@ -37,7 +37,7 @@ If the layout has exactly 2 keys in the bottom row, these keys will replace comm
* `shift_state_selector`: keys for `unshifted`, `shifted`, `shiftedManual`, `shiftedAutomatic`, `capsLock`, `manualOrLocked`, `default` (all optional)
* `variation_selector`: keys for input types `datetime`, `time`, `date`, `password`, `normal`, `uri`, `email`, `default` (all optional)
* `keyboard_state_selector`: keys for `emojiKeyEnabled`, `languageKeyEnabled`, `symbols`, `moreSymbols`, `alphabet`, `default` (all optional)
* the `keyEnabled` keys will be used if the corresponding setting is enabled, `symbols`, `moreSymbols`, `alphabet` will be used when the said keyboard view is active
* the `<emoji/language>KeyEnabled` keys will be used if the corresponding setting is enabled, `symbols`, `moreSymbols`, `alphabet` will be used when the said keyboard view is active
* `layout_direction_selector`: keys for `ltr` and `rtl` (both mandatory)
### Properties
* A (non-selector) key can have the following properties:

View file

@ -25,11 +25,9 @@ task makeEmoji(type: JavaExec, dependsOn: ['jar']) {
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation "org.jetbrains.kotlin:kotlin-stdlib:2.0.21"
}
java {
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21