Merge branch 'Helium314:main' into optimize-build

This commit is contained in:
Eran Leshem 2025-04-02 03:44:12 +03:00 committed by GitHub
commit 8bb8b732d8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
89 changed files with 1243 additions and 449 deletions

View file

@ -100,8 +100,6 @@ __Planned features and improvements:__
* Add and enable emoji dictionaries by default (if available for language)
* Clearer / more intuitive arrangement of settings
* Maybe hide some less used settings by default (similar to color customization)
* Make use of the `.com` key in URL fields (currently only available for tablets)
* With language-dependent TLDs
* [Bug fixes](https://github.com/Helium314/HeliBoard/issues?q=is%3Aissue+is%3Aopen+label%3Abug)
__What will _not_ be added:__

View file

@ -6,15 +6,15 @@ plugins {
}
android {
compileSdk = 34
compileSdk = 35
buildToolsVersion = "34.0.0"
defaultConfig {
applicationId = "helium314.keyboard"
minSdk = 21
targetSdk = 34
versionCode = 3000
versionName = "3.0-alpha1"
targetSdk = 35
versionCode = 3003
versionName = "3.0-alpha3"
ndk {
abiFilters.clear()
abiFilters.addAll(listOf("armeabi-v7a", "arm64-v8a", "x86", "x86_64"))
@ -58,7 +58,7 @@ android {
path = File("src/main/jni/Android.mk")
}
}
ndkVersion = "26.2.11394342"
ndkVersion = "28.0.13004108"
packagingOptions {
jniLibs {
@ -96,9 +96,8 @@ android {
dependencies {
// androidx
implementation("androidx.core:core-ktx:1.13.1")
implementation("androidx.appcompat:appcompat:1.7.0")
implementation("androidx.recyclerview:recyclerview:1.3.2")
implementation("androidx.core:core-ktx:1.15.0")
implementation("androidx.recyclerview:recyclerview:1.4.0")
implementation("androidx.autofill:autofill:1.1.0")
// kotlin
@ -118,7 +117,7 @@ dependencies {
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("org.robolectric:robolectric:4.14.1")
testImplementation("androidx.test:runner:1.6.2")
testImplementation("androidx.test:core:1.6.1")
}

View file

@ -15,7 +15,7 @@
{ "$": "keyboard_state_selector", "emojiKeyEnabled": { "$": "keyboard_state_selector", "alphabet": { "label": "emoji" }}},
{ "$": "keyboard_state_selector", "symbols": { "label": "numpad" }},
{ "label": "space" },
{ "label": "period", "labelFlags": 1073741824 },
{ "label": "period" },
{ "label": "action", "width": 0.15 }
]
]

View file

@ -0,0 +1,31 @@
ق
و
ە
ر
ت
ی
ێ
ئ
ۆ
پ
ا
س
ش
د
ف
ھ|ه
ژ
ل
ک
گ
ز
ع
ح
ج
چ
خ
ب
ن
م

View file

@ -8,7 +8,7 @@
ш
щ
з
х
х ъ [ {
ф
ы
@ -20,7 +20,7 @@
л
д
ж
э
э э́ ] }
я
ч

View file

@ -0,0 +1,34 @@
й
ц
у
к
е
н
г
ш
щ
з
х [ {
ъ ] }
ф
ы
в
а
п
р
о
л
д
ж
э э́
я
ч
с
м
и
т
ь
б <
ю >

View file

@ -8,7 +8,8 @@
ш
щ
з
х
х [ {
ї ] }
ф
і
@ -20,7 +21,7 @@
л
д
ж
є
є ' "
я
ч
@ -30,4 +31,4 @@
т
ь
б <
ю >
ю > ґ

View file

@ -0,0 +1,35 @@
й
ц
у
к
е
н
г
ш
щ
з
х [ {
ї ] }
ф
і
в
а
п
р
о
л
д
ж
є ' "
' "
я
ч
с
м
и
т
ь
б <
ю > ґ

View file

@ -0,0 +1,44 @@
[
[
{ "$": "shift_state_selector",
"manualOrLocked": { "label": "!" },
"default": { "label": "1", "popup": { "relevant": [{ "label": "¹" }, { "label": "½" }, { "label": "⅓" }, { "label": "¼" }, { "label": "⅛" }] } }
},
{ "$": "shift_state_selector",
"manualOrLocked": { "label": "@" },
"default": { "label": "2", "popup": { "relevant": [{ "label": "²" }, { "label": "⅔" }] } }
},
{ "$": "shift_state_selector",
"manualOrLocked": { "label": "#" },
"default": { "label": "3", "popup": { "relevant": [{ "label": "³" }, { "label": "¾" }, { "label": "⅜" }] } }
},
{ "$": "shift_state_selector",
"manualOrLocked": { "label": "$" },
"default": { "label": "4", "popup": { "relevant": [{ "label": "⁴" }] } }
},
{ "$": "shift_state_selector",
"manualOrLocked": { "label": "%" },
"default": { "label": "5", "popup": { "relevant": [{ "label": "⁵" }, { "label": "⅝" }] } }
},
{ "$": "shift_state_selector",
"manualOrLocked": { "label": "^" },
"default": { "label": "6", "popup": { "relevant": [{ "label": "⁶" }] } }
},
{ "$": "shift_state_selector",
"manualOrLocked": { "label": "&" },
"default": { "label": "7", "popup": { "relevant": [{ "label": "⁷" }, { "label": "⅞" }] } }
},
{ "$": "shift_state_selector",
"manualOrLocked": { "label": "*" },
"default": { "label": "8", "popup": { "relevant": [{ "label": "⁸" }] } }
},
{ "$": "shift_state_selector",
"manualOrLocked": { "label": "(" },
"default": { "label": "9", "popup": { "relevant": [{ "label": "⁹" }] } }
},
{ "$": "shift_state_selector",
"manualOrLocked": { "label": ")" },
"default": { "label": "0", "popup": { "relevant": [{ "label": "⁰" }, { "label": "ⁿ" }, { "label": "∅" }] } }
}
]
]

View file

@ -7,4 +7,4 @@
7 ⁷ ⅞
8 ⁸
9 ⁹
0 ⁰ ⁿ ∅
0 ⁰ ⁿ ∅

View file

@ -0,0 +1,39 @@
[popup_keys]
ق ٯ
و وو
ە ة ـہ
ر ڕ ڒ ࢪ
ت ط
ی ي ې ۍ
ێ ؽ
ئ ء ﺋ
ۆ ؤ ۏ ۊ ۋ ۉ ۇ
پ ث
ا أ إ آ ٱ
س ص
ش ض
د ۮ ڌ ﮆ
ف ڤ ڡ
ھ ھ
ژ ━|ـ
ل ڵ
ک ك ڪ
گ غ
ز ظ
ع ؏
ب ى
punctuation !autoColumnOrder!8 \؟ ! ، ٫ ؍ : ؛ ; : | - @ _ # * ٪ & ^
« „ “ ”
»
[labels]
alphabet: ئ‌پ‌گ
symbol: ٣٢١؟
comma: ،
question: ؟
[number_row]
١ ٢ ٣ ٤ ٥ ٦ ٧ ٨ ٩ ٠
[tlds]
iq krd

View file

@ -1,9 +1,19 @@
[popup_keys]
е ё
ь ъ
е ё е́ ѣ
ф ѳ
ы ы́
а а́
о о́
я я́
и и́
ь ъ ы
ю ю́
'
" ” „ “ » «
і ы
є э э́
[labels]
alphabet: АБВ

View file

@ -1,9 +1,19 @@
[popup_keys]
е е́
г ґ
ь
ф ѳ
і ї
'
" ” „ “
а а́
о о́
я я́
и и́ і ї
г ґ
ю ю́
'
" ” „ “ » «
ы і ї
э є
[labels]
alphabet: АБВ

View file

@ -24,6 +24,7 @@ import helium314.keyboard.latin.common.StringUtils;
import helium314.keyboard.latin.utils.PopupKeysUtilsKt;
import helium314.keyboard.latin.utils.ToolbarKey;
import helium314.keyboard.latin.utils.ToolbarUtilsKt;
import kotlin.collections.ArraysKt;
import java.util.Arrays;
import java.util.Locale;
@ -919,7 +920,7 @@ public class Key implements Comparable<Key> {
@NonNull final Drawable spacebarBackground,
@NonNull final Drawable actionKeyBackground) {
final Drawable background;
if (isAccentColored()) {
if (hasActionKeyBackground()) {
background = actionKeyBackground;
} else if (hasFunctionalBackground()) {
background = functionalKeyBackground;
@ -933,17 +934,10 @@ public class Key implements Comparable<Key> {
return background;
}
public final boolean isAccentColored() {
if (hasActionKeyBackground()) return true;
final String iconName = getIconName();
if (iconName == null) return false;
// todo: other way of identifying the color?
// this should be done differently, as users can set any icon now
// how is the background drawable selected? can we use the same way?
return iconName.equals(KeyboardIconsSet.NAME_NEXT_KEY)
|| iconName.equals(KeyboardIconsSet.NAME_PREVIOUS_KEY)
|| iconName.equals("clipboard_action_key")
|| iconName.equals("emoji_action_key");
public final boolean hasActionKeyPopups() {
if (!hasActionKeyBackground()) return false;
// only use the special action key popups for action colored keys, and only for icon popups
return ArraysKt.none(getPopupKeys(), (key) -> key.mIconName == null);
}
public boolean hasFunctionalBackground() {

View file

@ -1,5 +1,6 @@
package helium314.keyboard.keyboard
import android.text.InputType
import android.view.KeyEvent
import android.view.inputmethod.InputMethodSubtype
import helium314.keyboard.keyboard.internal.keyboard_parser.floris.KeyCode
@ -211,13 +212,24 @@ class KeyboardActionListenerImpl(private val latinIME: LatinIME, private val inp
return true
}
}
if (inputLogic.moveCursorByAndReturnIfInsideComposingWord(moveSteps)) {
// the shortcut below causes issues due to horrible handling of text fields by Firefox and forks
// issues:
// * setSelection "will cause the editor to call onUpdateSelection", see: https://developer.android.com/reference/android/view/inputmethod/InputConnection#setSelection(int,%20int)
// but Firefox is simply not doing this within the same word... WTF?
// https://github.com/Helium314/HeliBoard/issues/1139#issuecomment-2588169384
// * inputType is NOT if variant InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT (variant appears to always be 0)
// so we can't even only do it for browsers (identifying by app name will break for forks)
// best "solution" is not doing this for InputType variation 0 but this applies to the majority of text fields...
val variation = InputType.TYPE_MASK_VARIATION and Settings.getValues().mInputAttributes.mInputType
if (variation != 0 && inputLogic.moveCursorByAndReturnIfInsideComposingWord(moveSteps)) {
// no need to finish input and restart suggestions if we're still in the word
// this is a noticeable performance improvement
// this is a noticeable performance improvement when moving through long words
val newPosition = inputLogic.mConnection.expectedSelectionStart + moveSteps
inputLogic.mConnection.setSelection(newPosition, newPosition)
return true
}
inputLogic.finishInput()
val newPosition = inputLogic.mConnection.expectedSelectionStart + moveSteps
inputLogic.mConnection.setSelection(newPosition, newPosition)

View file

@ -405,14 +405,7 @@ private constructor(val themeId: Int, @JvmField val mStyleId: Int) {
}
fun getUnusedThemeName(initialName: String, prefs: SharedPreferences): String {
val existingNames = prefs.all.keys.mapNotNull {
when {
it.startsWith(Settings.PREF_USER_COLORS_PREFIX) -> it.substringAfter(Settings.PREF_USER_COLORS_PREFIX)
it.startsWith(Settings.PREF_USER_ALL_COLORS_PREFIX) -> it.substringAfter(Settings.PREF_USER_ALL_COLORS_PREFIX)
it.startsWith(Settings.PREF_USER_MORE_COLORS_PREFIX) -> it.substringAfter(Settings.PREF_USER_MORE_COLORS_PREFIX)
else -> null
}
}.toSortedSet()
val existingNames = getExistingThemeNames(prefs)
if (initialName !in existingNames) return initialName
var i = 1
while ("$initialName$i" in existingNames)
@ -420,11 +413,8 @@ private constructor(val themeId: Int, @JvmField val mStyleId: Int) {
return "$initialName$i"
}
// returns false if not renamed due to invalid name or collision
fun renameUserColors(from: String, to: String, prefs: SharedPreferences): Boolean {
if (to.isBlank()) return false // don't want that
if (to == from) return true // nothing to do
val existingNames = prefs.all.keys.mapNotNull {
private fun getExistingThemeNames(prefs: SharedPreferences) =
prefs.all.keys.mapNotNull {
when {
it.startsWith(Settings.PREF_USER_COLORS_PREFIX) -> it.substringAfter(Settings.PREF_USER_COLORS_PREFIX)
it.startsWith(Settings.PREF_USER_ALL_COLORS_PREFIX) -> it.substringAfter(Settings.PREF_USER_ALL_COLORS_PREFIX)
@ -432,6 +422,12 @@ private constructor(val themeId: Int, @JvmField val mStyleId: Int) {
else -> null
}
}.toSortedSet()
// returns false if not renamed due to invalid name or collision
fun renameUserColors(from: String, to: String, prefs: SharedPreferences): Boolean {
if (to.isBlank()) return false // don't want that
if (to == from) return true // nothing to do
val existingNames = getExistingThemeNames(prefs)
if (to in existingNames) return false
// all good, now rename
prefs.edit {

View file

@ -27,6 +27,7 @@ import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import helium314.keyboard.keyboard.emoji.EmojiPageKeyboardView;
import helium314.keyboard.keyboard.internal.KeyDrawParams;
import helium314.keyboard.keyboard.internal.KeyVisualAttributes;
import helium314.keyboard.keyboard.internal.keyboard_parser.floris.KeyCode;
@ -34,7 +35,7 @@ import helium314.keyboard.latin.R;
import helium314.keyboard.latin.common.ColorType;
import helium314.keyboard.latin.common.Colors;
import helium314.keyboard.latin.common.Constants;
import helium314.keyboard.latin.common.StringUtils;
import helium314.keyboard.latin.common.StringUtilsKt;
import helium314.keyboard.latin.settings.Settings;
import helium314.keyboard.latin.suggestions.MoreSuggestions;
import helium314.keyboard.latin.suggestions.PopupSuggestionsView;
@ -423,10 +424,14 @@ public class KeyboardView extends View {
}
if (key.isEnabled()) {
if (StringUtils.mightBeEmoji(label))
if (StringUtilsKt.isEmoji(label))
paint.setColor(key.selectTextColor(params) | 0xFF000000); // ignore alpha for emojis (though actually color isn't applied anyway and we could just set white)
else if (key.hasActionKeyBackground())
paint.setColor(mColors.get(ColorType.ACTION_KEY_ICON));
else if (this instanceof EmojiPageKeyboardView)
paint.setColor(mColors.get(ColorType.EMOJI_KEY_TEXT));
else if (this instanceof PopupKeysKeyboardView)
paint.setColor(mColors.get(ColorType.POPUP_KEY_TEXT));
else
paint.setColor(key.selectTextColor(params));
// Set a drop shadow for the text if the shadow radius is positive value.
@ -610,7 +615,7 @@ public class KeyboardView extends View {
}
private void setKeyIconColor(Key key, Drawable icon, Keyboard keyboard) {
if (key.isAccentColored()) {
if (key.hasActionKeyBackground()) {
mColors.setColor(icon, ColorType.ACTION_KEY_ICON);
} else if (key.isShift() && keyboard != null) {
if (keyboard.mId.mElementId == KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED

View file

@ -18,6 +18,7 @@ import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
@ -25,7 +26,6 @@ import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.view.ContextThemeWrapper;
import helium314.keyboard.accessibility.AccessibilityUtils;
import helium314.keyboard.accessibility.MainKeyboardAccessibilityDelegate;
@ -505,7 +505,7 @@ public final class MainKeyboardView extends KeyboardView implements DrawingProxy
mPopupKeysKeyboardCache.put(key, popupKeysKeyboard);
}
final View container = key.hasActionKeyBackground() ? mPopupKeysKeyboardForActionContainer
final View container = key.hasActionKeyPopups() ? mPopupKeysKeyboardForActionContainer
: mPopupKeysKeyboardContainer;
final PopupKeysKeyboardView popupKeysKeyboardView =
container.findViewById(R.id.popup_keys_keyboard_view);

View file

@ -328,12 +328,13 @@ public final class PopupKeysKeyboard extends Keyboard {
final PopupKeysKeyboardParams params = mParams;
final int popupKeyFlags = mParentKey.getPopupKeyLabelFlags();
final PopupKeySpec[] popupKeys = mParentKey.getPopupKeys();
final int background = mParentKey.hasActionKeyPopups() ? Key.BACKGROUND_TYPE_ACTION : Key.BACKGROUND_TYPE_NORMAL;
for (int n = 0; n < popupKeys.length; n++) {
final PopupKeySpec popupKeySpec = popupKeys[n];
final int row = n / params.mNumColumns;
final int x = params.getX(n, row);
final int y = params.getY(row);
final Key key = popupKeySpec.buildKey(x, y, popupKeyFlags, params);
final Key key = popupKeySpec.buildKey(x, y, popupKeyFlags, background, params);
params.markAsEdgeKey(key, row);
params.onAddKey(key);

View file

@ -108,7 +108,7 @@ public final class KeyPreviewChoreographer {
final boolean hasPopupKeys = (key.getPopupKeys() != null);
keyPreviewView.setPreviewBackground(hasPopupKeys, keyPreviewPosition);
final Colors colors = Settings.getValues().mColors;
colors.setBackground(keyPreviewView, ColorType.KEY_PREVIEW);
colors.setBackground(keyPreviewView, ColorType.KEY_PREVIEW_BACKGROUND);
// The key preview is placed vertically above the top edge of the parent key with an
// arbitrary offset.

View file

@ -15,8 +15,7 @@ import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.Gravity;
import androidx.appcompat.widget.AppCompatTextView;
import android.widget.TextView;
import helium314.keyboard.keyboard.Key;
import helium314.keyboard.latin.R;
@ -25,10 +24,9 @@ import helium314.keyboard.latin.settings.Settings;
import java.util.HashSet;
/**
* The pop up key preview view.
*/
public class KeyPreviewView extends AppCompatTextView {
/** The pop up key preview view. */
// Android Studio complains about TextView, but we're not using tint or auto-size that should be the relevant differences
public class KeyPreviewView extends TextView {
public static final int POSITION_MIDDLE = 0;
public static final int POSITION_LEFT = 1;
public static final int POSITION_RIGHT = 2;

View file

@ -129,7 +129,7 @@ public final class KeyVisualAttributes {
// when? -> hasShiftedLetterHint and isShiftedLetterActivated -> both are label flags
mShiftedLetterHintActivatedColor = keyAttr.getColor(
R.styleable.Keyboard_Key_keyShiftedLetterHintActivatedColor, 0);
mPreviewTextColor = colors.get(ColorType.KEY_TEXT);
mPreviewTextColor = colors.get(ColorType.KEY_PREVIEW_TEXT);
mHintLabelVerticalAdjustment = ResourceUtils.getFraction(keyAttr,
R.styleable.Keyboard_Key_keyHintLabelVerticalAdjustment, 0.0f);

View file

@ -80,6 +80,7 @@ public final class KeyboardState {
private static final int SWITCH_STATE_SYMBOL_BEGIN = 1;
private static final int SWITCH_STATE_SYMBOL = 2;
private static final int SWITCH_STATE_NUMPAD = 3;
private static final int SWITCH_STATE_NUMPAD_BEGIN = 9;
private static final int SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL = 4;
private static final int SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE = 5;
private static final int SWITCH_STATE_MOMENTARY_ALPHA_SHIFT = 6;
@ -403,7 +404,7 @@ public final class KeyboardState {
mMode = MODE_NUMPAD;
mRecapitalizeMode = RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE;
mSwitchActions.setNumpadKeyboard();
mSwitchState = withSliding ? SWITCH_STATE_MOMENTARY_TO_NUMPAD : SWITCH_STATE_NUMPAD;
mSwitchState = withSliding ? SWITCH_STATE_MOMENTARY_TO_NUMPAD : SWITCH_STATE_NUMPAD_BEGIN;
}
public void toggleNumpad(final boolean withSliding, final int autoCapsFlags, final int recapitalizeMode,
@ -789,6 +790,17 @@ public final class KeyboardState {
mPrevSymbolsKeyboardWasShifted = false;
}
break;
case SWITCH_STATE_NUMPAD:
// Switch back to alpha keyboard mode if user types one or more non-space/enter
// characters followed by a space/enter.
if (isSpaceOrEnter(code) && Settings.getValues().mAlphaAfterNumpadAndSpace) {
toggleNumpad(false, autoCapsFlags, recapitalizeMode, true, false);
}
break;
case SWITCH_STATE_NUMPAD_BEGIN:
if (!isSpaceOrEnter(code))
mSwitchState = SWITCH_STATE_NUMPAD;
break;
}
// If the code is a letter, update keyboard shift state.
@ -833,6 +845,7 @@ public final class KeyboardState {
case SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE -> "MOMENTARY-SYMBOL-MORE";
case SWITCH_STATE_MOMENTARY_ALPHA_SHIFT -> "MOMENTARY-ALPHA_SHIFT";
case SWITCH_STATE_NUMPAD -> "NUMPAD";
case SWITCH_STATE_NUMPAD_BEGIN -> "NUMPAD-BEGIN";
case SWITCH_STATE_MOMENTARY_TO_NUMPAD -> "MOMENTARY-TO-NUMPAD";
case SWITCH_STATE_MOMENTARY_FROM_NUMPAD -> "MOMENTARY-FROM-NUMPAD";
default -> null;

View file

@ -68,11 +68,9 @@ public final class PopupKeySpec {
}
@NonNull
public Key buildKey(final int x, final int y, final int labelFlags,
@NonNull final KeyboardParams params) {
return new Key(mLabel, mIconName, mCode, mOutputText, null /* hintLabel */, labelFlags,
Key.BACKGROUND_TYPE_NORMAL, x, y, params.mDefaultAbsoluteKeyWidth, params.mDefaultAbsoluteRowHeight,
params.mHorizontalGap, params.mVerticalGap);
public Key buildKey(final int x, final int y, final int labelFlags, final int background, @NonNull final KeyboardParams params) {
return new Key(mLabel, mIconName, mCode, mOutputText, null, labelFlags, background, x, y,
params.mDefaultAbsoluteKeyWidth, params.mDefaultAbsoluteRowHeight, params.mHorizontalGap, params.mVerticalGap);
}
@Override

View file

@ -237,7 +237,7 @@ class KeyboardParser(private val params: KeyboardParams, private val context: Co
{ it.label == KeyLabel.PERIOD || it.groupId == KeyData.GROUP_PERIOD},
{ baseKeys.last()[1].copy(newGroupId = 2, newType = baseKeys.last()[1].type ?: it.type) }
)
baseKeys.removeLast()
baseKeys.removeAt(baseKeys.lastIndex)
}
// add zwnj key next to space if necessary
val spaceIndex = functionalKeysBottom.indexOfFirst { it.label == KeyLabel.SPACE && it.width <= 0 } // width could be 0 or -1

View file

@ -44,7 +44,7 @@ class LocaleKeyboardInfos(dataStream: InputStream?, locale: Locale) {
"mns" -> Key.LABEL_FLAGS_FOLLOW_KEY_LETTER_RATIO
else -> 0
}
val tlds = getLocaleTlds(locale) // todo: USE IT
val tlds = getLocaleTlds(locale)
init {
readStream(dataStream, false, true)
@ -89,12 +89,6 @@ class LocaleKeyboardInfos(dataStream: InputStream?, locale: Locale) {
}
}
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
@ -205,7 +199,6 @@ 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)
@ -227,19 +220,27 @@ private fun getStreamForLocale(locale: Locale, context: Context) =
}
private fun getLocaleTlds(locale: Locale): LinkedHashSet<String> {
val tlds = getDefaultTlds(locale)
val ccLower = locale.country.lowercase()
val tlds = LinkedHashSet<String>()
if (ccLower.isEmpty() || locale.language == SubtypeLocaleUtils.NO_LANGUAGE)
return tlds
specialCountryTlds.forEach {
if (ccLower != it.first) return@forEach
tlds.addAll(it.second.splitOnWhitespace())
return tlds
return@getLocaleTlds tlds
}
tlds.add(".$ccLower")
return tlds
}
private fun getDefaultTlds(locale: Locale): LinkedHashSet<String> {
val tlds = linkedSetOf<String>()
tlds.addAll(defaultTlds.splitOnWhitespace())
if ((locale.language != "en" && euroLocales.matches(locale.language)) || euroCountries.matches(locale.country))
tlds.add(".eu")
return tlds
}
fun clearCache() = localeKeyboardInfosCache.clear()
// cache the texts, so they don't need to be read over and over

View file

@ -167,6 +167,7 @@ object KeyCode {
const val BACK = -10040
const val SELECT_LEFT = -10041
const val SELECT_RIGHT = -10042
const val TIMESTAMP = -10043
/** to make sure a FlorisBoard code works when reading a JSON layout */
fun Int.checkAndConvertCode(): Int = if (this > 0) this else when (this) {
@ -182,7 +183,8 @@ object KeyCode {
SYMBOL_ALPHA, TOGGLE_ONE_HANDED_MODE, SWITCH_ONE_HANDED_MODE, SPLIT_LAYOUT, 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
MEDIA_PREVIOUS, VOL_UP, VOL_DOWN, MUTE, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, BACK,
TIMESTAMP
-> this
// conversion
@ -194,8 +196,12 @@ object KeyCode {
else -> throw IllegalStateException("key code $this not yet supported")
}
// todo: three are many more keys, see near https://developer.android.com/reference/android/view/KeyEvent#KEYCODE_0
/** convert a keyCode / codePoint to a KeyEvent.KEYCODE_<xxx>, fallback to KeyEvent.KEYCODE_UNKNOWN */
// todo: there are many more keys, see near https://developer.android.com/reference/android/view/KeyEvent#KEYCODE_0
/**
* Convert a keyCode / codePoint to a KeyEvent.KEYCODE_<xxx>.
* Fallback to KeyEvent.KEYCODE_UNKNOWN.
* To be uses for fake hardware key press.
* */
fun Int.toKeyEventCode(): Int = if (this > 0)
when (this.toChar().uppercaseChar()) {
'/' -> KeyEvent.KEYCODE_SLASH

View file

@ -24,6 +24,7 @@ import helium314.keyboard.latin.common.StringUtils
import helium314.keyboard.latin.settings.Settings
import helium314.keyboard.latin.spellcheck.AndroidSpellCheckerService
import helium314.keyboard.latin.utils.InputTypeUtils
import helium314.keyboard.latin.utils.LayoutType
import helium314.keyboard.latin.utils.Log
import helium314.keyboard.latin.utils.ToolbarKey
import helium314.keyboard.latin.utils.getCodeForToolbarKey
@ -482,8 +483,7 @@ sealed interface KeyData : AbstractKeyData {
KeyLabel.DELETE -> "!icon/delete_key|!code/key_delete"
KeyLabel.SHIFT -> "${getShiftLabel(params)}|!code/key_shift"
// KeyLabel.EMOJI -> "!icon/emoji_normal_key|!code/key_emoji"
// todo (later): label and popupKeys for .com should be in localeKeyTexts, handled similar to currency key
KeyLabel.COM -> ".com"
KeyLabel.COM -> params.mLocaleKeyboardInfos.tlds.first()
KeyLabel.LANGUAGE_SWITCH -> "!icon/language_switch_key|!code/key_language_switch"
KeyLabel.ZWNJ -> "!icon/zwnj_key|\u200C"
KeyLabel.CURRENCY -> params.mLocaleKeyboardInfos.currencyKey.first
@ -526,8 +526,11 @@ sealed interface KeyData : AbstractKeyData {
return when (label) {
KeyLabel.ALPHA, KeyLabel.SYMBOL_ALPHA, KeyLabel.SYMBOL -> Key.LABEL_FLAGS_PRESERVE_CASE or Key.LABEL_FLAGS_FOLLOW_FUNCTIONAL_TEXT_COLOR
KeyLabel.COMMA -> Key.LABEL_FLAGS_HAS_POPUP_HINT
// essentially this only changes the appearance of the armenian period key in holo theme
KeyLabel.PERIOD -> Key.LABEL_FLAGS_HAS_POPUP_HINT and if (params.mId.isAlphabetKeyboard) params.mLocaleKeyboardInfos.labelFlags else 0
// essentially the first term only changes the appearance of the armenian period key in holo theme
KeyLabel.PERIOD -> (Key.LABEL_FLAGS_HAS_POPUP_HINT and
if (params.mId.isAlphabetKeyboard) params.mLocaleKeyboardInfos.labelFlags else 0) or
(if (shouldShowTldPopups(params)) 0 else Key.LABEL_FLAGS_DISABLE_HINT_LABEL) or
Key.LABEL_FLAGS_PRESERVE_CASE
KeyLabel.ACTION -> {
Key.LABEL_FLAGS_PRESERVE_CASE or Key.LABEL_FLAGS_AUTO_X_SCALE or
Key.LABEL_FLAGS_FOLLOW_KEY_LABEL_RATIO or Key.LABEL_FLAGS_FOLLOW_FUNCTIONAL_TEXT_COLOR or
@ -546,12 +549,12 @@ sealed interface KeyData : AbstractKeyData {
private fun getAdditionalPopupKeys(params: KeyboardParams): PopupSet<AbstractKeyData>? {
if (groupId == GROUP_COMMA) return SimplePopups(getCommaPopupKeys(params))
if (groupId == GROUP_PERIOD) return SimplePopups(getPunctuationPopupKeys(params))
if (groupId == GROUP_PERIOD) return getPeriodPopups(params)
if (groupId == GROUP_ENTER) return getActionKeyPopupKeys(params)
if (groupId == GROUP_NO_DEFAULT_POPUP) return null
return when (label) {
KeyLabel.COMMA -> SimplePopups(getCommaPopupKeys(params))
KeyLabel.PERIOD -> SimplePopups(getPunctuationPopupKeys(params))
KeyLabel.PERIOD -> getPeriodPopups(params)
KeyLabel.ACTION -> getActionKeyPopupKeys(params)
KeyLabel.SHIFT -> {
if (params.mId.isAlphabetKeyboard) SimplePopups(
@ -561,13 +564,27 @@ sealed interface KeyData : AbstractKeyData {
)
) else null // why the alphabet popup keys actually?
}
KeyLabel.COM -> SimplePopups(listOf(Key.POPUP_KEYS_HAS_LABELS, ".net", ".org", ".gov", ".edu"))
KeyLabel.COM -> SimplePopups(
listOf(Key.POPUP_KEYS_HAS_LABELS).plus(params.mLocaleKeyboardInfos.tlds.drop(1))
)
KeyLabel.ZWNJ -> SimplePopups(listOf("!icon/zwj_key|\u200D"))
// only add currency popups if there are none defined on the key
KeyLabel.CURRENCY -> if (popup.isEmpty()) SimplePopups(params.mLocaleKeyboardInfos.currencyKey.second) else null
else -> null
}
}
private fun getPeriodPopups(params: KeyboardParams): SimplePopups =
SimplePopups(
if (shouldShowTldPopups(params)) params.mLocaleKeyboardInfos.tlds
else getPunctuationPopupKeys(params)
)
private fun shouldShowTldPopups(params: KeyboardParams): Boolean =
(Settings.getInstance().current.mShowTldPopupKeys
&& params.mId.mSubtype.layouts[LayoutType.FUNCTIONAL] != "functional_keys_tablet"
&& params.mId.mMode in setOf(KeyboardId.MODE_URL, KeyboardId.MODE_EMAIL))
}
/**

View file

@ -232,7 +232,7 @@ fun checkVersionUpgrade(context: Context) {
KeyboardTheme.writeUserMoreColors(prefs, themeNameNight, moreColorsNight)
}
if (prefs.contains("theme_dark_color_all_colors")) {
val allColorsNight = readAllColorsMap(false)
val allColorsNight = readAllColorsMap(true)
prefs.edit().remove("theme_dark_color_all_colors").apply()
KeyboardTheme.writeUserAllColors(prefs, themeNameNight, allColorsNight)
}
@ -530,18 +530,29 @@ fun checkVersionUpgrade(context: Context) {
prefs.edit().remove("auto_correction_confidence").putFloat(Settings.PREF_AUTO_CORRECT_THRESHOLD, value).apply()
}
}
if (oldVersion <= 2310) {
listOf(
Settings.PREF_ENABLED_SUBTYPES,
Settings.PREF_SELECTED_SUBTYPE,
Settings.PREF_ADDITIONAL_SUBTYPES
).forEach { key ->
val value = prefs.getString(key, "")!!
if ("bengali," in value) {
prefs.edit().putString(key, value.replace("bengali,", "bengali_inscript,")).apply()
if (oldVersion <= 2310) {
listOf(
Settings.PREF_ENABLED_SUBTYPES,
Settings.PREF_SELECTED_SUBTYPE,
Settings.PREF_ADDITIONAL_SUBTYPES
).forEach { key ->
val value = prefs.getString(key, "")!!
if ("bengali," in value) {
prefs.edit().putString(key, value.replace("bengali,", "bengali_inscript,")).apply()
}
}
}
if (oldVersion <= 3001 && prefs.getInt(Settings.PREF_CLIPBOARD_HISTORY_RETENTION_TIME, Defaults.PREF_CLIPBOARD_HISTORY_RETENTION_TIME) <= 0) {
prefs.edit().putInt(Settings.PREF_CLIPBOARD_HISTORY_RETENTION_TIME, 121).apply()
}
if (oldVersion <= 3002) {
prefs.all.filterKeys { it.startsWith(Settings.PREF_USER_ALL_COLORS_PREFIX) }.forEach {
val oldValue = prefs.getString(it.key, "")!!
if ("KEY_PREVIEW" !in oldValue) return@forEach
val newValue = oldValue.replace("KEY_PREVIEW", "KEY_PREVIEW_BACKGROUND")
prefs.edit().putString(it.key, newValue).apply()
}
}
}
upgradeToolbarPrefs(prefs)
LayoutUtilsCustom.onLayoutFileChanged() // just to be sure
prefs.edit { putInt(Settings.PREF_VERSION_CODE, BuildConfig.VERSION_CODE) }

View file

@ -2,18 +2,12 @@
package helium314.keyboard.latin
import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializable
import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
@Serializable
data class ClipboardHistoryEntry (
var timeStamp: Long,
@Serializable(with = CharSequenceStringSerializer::class)
val content: CharSequence,
val content: String,
var isPinned: Boolean = false
) : Comparable<ClipboardHistoryEntry> {
override fun compareTo(other: ClipboardHistoryEntry): Int {
@ -21,13 +15,3 @@ data class ClipboardHistoryEntry (
return if (result != 0) result else other.timeStamp.compareTo(timeStamp)
}
}
class CharSequenceStringSerializer : KSerializer<CharSequence> {
override val descriptor = PrimitiveSerialDescriptor("CharSequence", PrimitiveKind.STRING)
override fun serialize(encoder: Encoder, value: CharSequence) {
encoder.encodeString(value.toString())
}
override fun deserialize(decoder: Decoder) = decoder.decodeString()
}

View file

@ -61,7 +61,7 @@ class ClipboardHistoryManager(
val content = clipItem.coerceToText(latinIME)
if (TextUtils.isEmpty(content)) return
val duplicateEntryIndex = historyEntries.indexOfFirst { it.content.toString() == content.toString() }
val duplicateEntryIndex = historyEntries.indexOfFirst { it.content == content.toString() }
if (duplicateEntryIndex != -1) {
val existingEntry = historyEntries[duplicateEntryIndex]
if (existingEntry.timeStamp == timeStamp) return // nothing to change (may occur frequently starting with API 30)
@ -74,9 +74,9 @@ class ClipboardHistoryManager(
onHistoryChangeListener?.onClipboardHistoryEntryMoved(duplicateEntryIndex, newIndex)
return
}
if (historyEntries.any { it.content.toString() == content.toString() }) return
if (historyEntries.any { it.content == content.toString() }) return
val entry = ClipboardHistoryEntry(timeStamp, content)
val entry = ClipboardHistoryEntry(timeStamp, content.toString())
historyEntries.add(entry)
sortHistoryEntries()
val at = historyEntries.indexOf(entry)
@ -120,7 +120,7 @@ class ClipboardHistoryManager(
private fun checkClipRetentionElapsed() {
val mins = latinIME.mSettings.current.mClipboardHistoryRetentionTime
if (mins <= 0) return // No retention limit
if (mins > 120) return // No retention limit, changed from <= 0 because we want it to be larger than all other choices
val maxClipRetentionTime = mins * 60 * 1000L
val now = System.currentTimeMillis()
historyEntries.removeAll { !it.isPinned && (now - it.timeStamp) > maxClipRetentionTime }

View file

@ -7,6 +7,7 @@
package helium314.keyboard.latin;
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@ -100,7 +101,6 @@ import java.util.concurrent.TimeUnit;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AlertDialog;
import androidx.core.content.ContextCompat;
/**
@ -523,6 +523,11 @@ public class LatinIME extends InputMethodService implements
}
final class SubtypeState {
// When HintLocales causes a subtype override, we store
// the overridden subtype here in order to restore it when
// we switch to another input context that has no HintLocales.
private InputMethodSubtype mOverriddenByLocale;
private InputMethodSubtype mLastActiveSubtype;
private boolean mCurrentSubtypeHasBeenUsed = true; // starting with true avoids immediate switch
@ -530,6 +535,70 @@ public class LatinIME extends InputMethodService implements
mCurrentSubtypeHasBeenUsed = true;
}
// TextFields can provide locale/language hints that the IME should use via 'hintLocales'.
// If a matching subtype is found, we temporarily switch to that subtype until
// we return to a context that does not provide any hints, or until the user
// explicitly changes the language/subtype in use.
public InputMethodSubtype getSubtypeForLocales(final RichInputMethodManager richImm, final Iterable<Locale> locales) {
final InputMethodSubtype overriddenByLocale = mOverriddenByLocale;
if (locales == null) {
if (overriddenByLocale != null) {
// no locales provided, so switch back to
// whatever subtype was used last time.
mOverriddenByLocale = null;
return overriddenByLocale;
}
return null;
}
final InputMethodSubtype currentSubtype = richImm.getCurrentSubtype().getRawSubtype();
final Locale currentSubtypeLocale = richImm.getCurrentSubtypeLocale();
final int minimumMatchLevel = 3; // LocaleUtils.LOCALE_LANGUAGE_MATCH_COUNTRY_DIFFER;
// Try finding a subtype matching the hint language.
for (final Locale hintLocale : locales) {
if (LocaleUtils.INSTANCE.getMatchLevel(hintLocale, currentSubtypeLocale) >= minimumMatchLevel
|| CollectionsKt.any(mSettings.getCurrent().mSecondaryLocales,
(secLocale) -> LocaleUtils.INSTANCE.getMatchLevel(hintLocale, secLocale) >= minimumMatchLevel)) {
// current locales are already a good match, and we want to avoid unnecessary layout switches.
return null;
}
final InputMethodSubtype subtypeForHintLocale = richImm.findSubtypeForHintLocale(hintLocale);
if (subtypeForHintLocale == null) {
continue;
}
if (subtypeForHintLocale.equals(currentSubtype)) {
// no need to switch, we already use the correct locale.
return null;
}
if (overriddenByLocale == null) {
// auto-switching based on hint locale, so store
// whatever subtype was in use so we can switch back
// to it later when there are no hint locales.
mOverriddenByLocale = currentSubtype;
}
return subtypeForHintLocale;
}
return null;
}
public void onSubtypeChanged(final InputMethodSubtype oldSubtype,
final InputMethodSubtype newSubtype) {
if (oldSubtype != mOverriddenByLocale) {
// Whenever the subtype is changed, clear tracking
// the subtype that is overridden by a HintLocale as
// we no longer have a subtype to automatically switch back to.
mOverriddenByLocale = null;
}
}
public void switchSubtype(final RichInputMethodManager richImm) {
final InputMethodSubtype currentSubtype = richImm.getCurrentSubtype().getRawSubtype();
final InputMethodSubtype lastActiveSubtype = mLastActiveSubtype;
@ -858,6 +927,8 @@ public class LatinIME extends InputMethodService implements
return;
}
InputMethodSubtype oldSubtype = mRichImm.getCurrentSubtype().getRawSubtype();
mSubtypeState.onSubtypeChanged(oldSubtype, subtype);
StatsUtils.onSubtypeChanged(oldSubtype, subtype);
mRichImm.onSubtypeChanged(subtype);
mInputLogic.onSubtypeChanged(SubtypeLocaleUtils.getCombiningRulesExtraValue(subtype),
@ -876,20 +947,10 @@ public class LatinIME extends InputMethodService implements
super.onStartInput(editorInfo, restarting);
final List<Locale> hintLocales = EditorInfoCompatUtils.getHintLocales(editorInfo);
if (hintLocales == null) {
return;
}
// Try switching to a subtype matching the hint language.
for (final Locale hintLocale : hintLocales) {
if (LocaleUtils.INSTANCE.getMatchLevel(hintLocale, mRichImm.getCurrentSubtypeLocale()) >= 3
|| CollectionsKt.any(mSettings.getCurrent().mSecondaryLocales, (secLocale) -> LocaleUtils.INSTANCE.getMatchLevel(hintLocale, secLocale) >= 3))
return; // current locales are already a good match, and we want to avoid unnecessary layout switches
final InputMethodSubtype newSubtype = mRichImm.findSubtypeForHintLocale(hintLocale);
if (newSubtype == null) continue;
if (newSubtype.equals(mRichImm.getCurrentSubtype().getRawSubtype()))
return; // no need to switch, we already use the correct locale
mHandler.postSwitchLanguage(newSubtype);
break;
final InputMethodSubtype subtypeForLocales = mSubtypeState.getSubtypeForLocales(mRichImm, hintLocales);
if (subtypeForLocales != null) {
// found a better subtype using hint locales that we should switch to.
mHandler.postSwitchLanguage(subtypeForLocales);
}
}

View file

@ -474,6 +474,10 @@ public final class WordComposer {
return mIsBatchMode;
}
public void unsetBatchMode() {
mIsBatchMode = false;
}
public void setRejectedBatchModeSuggestion(final String rejectedSuggestion) {
mRejectedBatchModeSuggestion = rejectedSuggestion;
}

View file

@ -274,10 +274,10 @@ class DynamicColors(context: Context, override val themeStyle: String, override
override fun get(color: ColorType): Int = when (color) {
TOOL_BAR_KEY_ENABLED_BACKGROUND, EMOJI_CATEGORY_SELECTED, ACTION_KEY_BACKGROUND,
CLIPBOARD_PIN, SHIFT_KEY_ICON -> accent
AUTOFILL_BACKGROUND_CHIP, GESTURE_PREVIEW, POPUP_KEYS_BACKGROUND, MORE_SUGGESTIONS_BACKGROUND, KEY_PREVIEW -> adjustedBackground
AUTOFILL_BACKGROUND_CHIP, GESTURE_PREVIEW, POPUP_KEYS_BACKGROUND, MORE_SUGGESTIONS_BACKGROUND, KEY_PREVIEW_BACKGROUND -> adjustedBackground
TOOL_BAR_EXPAND_KEY_BACKGROUND -> if (!isNight) accent else doubleAdjustedBackground
GESTURE_TRAIL -> gesture
KEY_TEXT, SUGGESTION_AUTO_CORRECT, REMOVE_SUGGESTION_ICON,
KEY_TEXT, SUGGESTION_AUTO_CORRECT, REMOVE_SUGGESTION_ICON, EMOJI_KEY_TEXT, KEY_PREVIEW_TEXT, POPUP_KEY_TEXT,
KEY_ICON, ONE_HANDED_MODE_BUTTON, EMOJI_CATEGORY, TOOL_BAR_KEY, FUNCTIONAL_KEY_TEXT -> keyText
KEY_HINT_TEXT -> keyHintText
SPACE_BAR_TEXT -> spaceBarText
@ -327,7 +327,7 @@ class DynamicColors(context: Context, override val themeStyle: String, override
EMOJI_CATEGORY_SELECTED, CLIPBOARD_PIN, SHIFT_KEY_ICON -> accentColorFilter
REMOVE_SUGGESTION_ICON, EMOJI_CATEGORY, KEY_TEXT,
KEY_ICON, ONE_HANDED_MODE_BUTTON, TOOL_BAR_KEY, TOOL_BAR_EXPAND_KEY -> keyTextFilter
KEY_PREVIEW -> adjustedBackgroundFilter
KEY_PREVIEW_BACKGROUND -> adjustedBackgroundFilter
ACTION_KEY_ICON -> actionKeyIconColorFilter
else -> colorFilter(get(color))
}
@ -336,7 +336,7 @@ class DynamicColors(context: Context, override val themeStyle: String, override
if (view.background == null)
view.setBackgroundColor(Color.WHITE) // set white to make the color filters work
when (color) {
KEY_PREVIEW -> view.background.colorFilter = adjustedBackgroundFilter
KEY_PREVIEW_BACKGROUND -> view.background.colorFilter = adjustedBackgroundFilter
FUNCTIONAL_KEY_BACKGROUND, KEY_BACKGROUND, MORE_SUGGESTIONS_WORD_BACKGROUND, SPACE_BAR_BACKGROUND, STRIP_BACKGROUND -> setColor(view.background, color)
ONE_HANDED_MODE_BUTTON -> setColor(view.background, if (keyboardBackground == null) MAIN_BACKGROUND else STRIP_BACKGROUND)
MORE_SUGGESTIONS_BACKGROUND -> view.background.colorFilter = backgroundFilter
@ -472,10 +472,11 @@ class DefaultColors (
TOOL_BAR_KEY_ENABLED_BACKGROUND, EMOJI_CATEGORY_SELECTED, ACTION_KEY_BACKGROUND,
CLIPBOARD_PIN, SHIFT_KEY_ICON -> accent
AUTOFILL_BACKGROUND_CHIP -> if (themeStyle == STYLE_MATERIAL && !hasKeyBorders) background else adjustedBackground
GESTURE_PREVIEW, POPUP_KEYS_BACKGROUND, MORE_SUGGESTIONS_BACKGROUND, KEY_PREVIEW -> adjustedBackground
GESTURE_PREVIEW, POPUP_KEYS_BACKGROUND, MORE_SUGGESTIONS_BACKGROUND, KEY_PREVIEW_BACKGROUND -> adjustedBackground
TOOL_BAR_EXPAND_KEY_BACKGROUND, CLIPBOARD_SUGGESTION_BACKGROUND -> doubleAdjustedBackground
GESTURE_TRAIL -> gesture
KEY_TEXT, REMOVE_SUGGESTION_ICON, FUNCTIONAL_KEY_TEXT, KEY_ICON -> keyText
KEY_TEXT, REMOVE_SUGGESTION_ICON, FUNCTIONAL_KEY_TEXT, KEY_ICON, EMOJI_KEY_TEXT,
POPUP_KEY_TEXT, KEY_PREVIEW_TEXT -> keyText
KEY_HINT_TEXT -> keyHintText
SPACE_BAR_TEXT -> spaceBarText
FUNCTIONAL_KEY_BACKGROUND -> functionalKey
@ -524,7 +525,7 @@ class DefaultColors (
if (view.background == null)
view.setBackgroundColor(Color.WHITE) // set white to make the color filters work
when (color) {
KEY_PREVIEW, POPUP_KEYS_BACKGROUND -> view.background.colorFilter = adjustedBackgroundFilter
KEY_PREVIEW_BACKGROUND, POPUP_KEYS_BACKGROUND -> view.background.colorFilter = adjustedBackgroundFilter
FUNCTIONAL_KEY_BACKGROUND, KEY_BACKGROUND, MORE_SUGGESTIONS_WORD_BACKGROUND, SPACE_BAR_BACKGROUND, STRIP_BACKGROUND, CLIPBOARD_SUGGESTION_BACKGROUND -> setColor(view.background, color)
ONE_HANDED_MODE_BUTTON -> setColor(view.background, if (keyboardBackground == null) MAIN_BACKGROUND else STRIP_BACKGROUND)
MORE_SUGGESTIONS_BACKGROUND -> view.background.colorFilter = backgroundFilter
@ -547,7 +548,7 @@ class DefaultColors (
EMOJI_CATEGORY_SELECTED, CLIPBOARD_PIN, SHIFT_KEY_ICON -> accentColorFilter
KEY_TEXT, KEY_ICON -> keyTextFilter
REMOVE_SUGGESTION_ICON, EMOJI_CATEGORY, ONE_HANDED_MODE_BUTTON, TOOL_BAR_KEY, TOOL_BAR_EXPAND_KEY -> suggestionTextFilter
KEY_PREVIEW -> adjustedBackgroundFilter
KEY_PREVIEW_BACKGROUND -> adjustedBackgroundFilter
ACTION_KEY_ICON -> actionKeyIconColorFilter
else -> colorFilter(get(color)) // create color filter (not great for performance, so the frequently used filters should be stored)
}
@ -620,6 +621,7 @@ enum class ColorType {
CLIPBOARD_PIN,
EMOJI_CATEGORY,
EMOJI_CATEGORY_SELECTED,
EMOJI_KEY_TEXT,
FUNCTIONAL_KEY_TEXT,
FUNCTIONAL_KEY_BACKGROUND,
GESTURE_TRAIL,
@ -628,11 +630,13 @@ enum class ColorType {
KEY_ICON,
KEY_TEXT,
KEY_HINT_TEXT,
KEY_PREVIEW,
KEY_PREVIEW_BACKGROUND,
KEY_PREVIEW_TEXT,
MORE_SUGGESTIONS_HINT,
MORE_SUGGESTIONS_BACKGROUND,
MORE_SUGGESTIONS_WORD_BACKGROUND,
POPUP_KEYS_BACKGROUND,
POPUP_KEY_TEXT,
NAVIGATION_BAR,
SHIFT_KEY_ICON,
SPACE_BAR_BACKGROUND,

View file

@ -54,6 +54,7 @@ import helium314.keyboard.latin.utils.RecapitalizeStatus;
import helium314.keyboard.latin.utils.ScriptUtils;
import helium314.keyboard.latin.utils.StatsUtils;
import helium314.keyboard.latin.utils.TextRange;
import helium314.keyboard.latin.utils.TimestampKt;
import java.util.ArrayList;
import java.util.Locale;
@ -323,7 +324,8 @@ public final class InputLogic {
// Don't allow cancellation of manual pick
mLastComposedWord.deactivate();
// Space state must be updated before calling updateShiftState
mSpaceState = SpaceState.PHANTOM;
if (settingsValues.mAutospaceAfterSuggestion)
mSpaceState = SpaceState.PHANTOM;
inputTransaction.requireShiftUpdate(InputTransaction.SHIFT_UPDATE_NOW);
// If we're not showing the "Touch again to save", then update the suggestion strip.
@ -546,7 +548,8 @@ public final class InputLogic {
|| settingsValues.isUsuallyFollowedBySpace(codePointBeforeCursor)) {
final boolean autoShiftHasBeenOverriden = keyboardSwitcher.getKeyboardShiftMode() !=
getCurrentAutoCapsState(settingsValues);
mSpaceState = SpaceState.PHANTOM;
if (settingsValues.mAutospaceBeforeGestureTyping)
mSpaceState = SpaceState.PHANTOM;
if (!autoShiftHasBeenOverriden) {
// When we change the space state, we need to update the shift state of the
// keyboard unless it has been overridden manually. This is happening for example
@ -686,10 +689,7 @@ public final class InputLogic {
if (mSuggestedWords.isPrediction()) {
inputTransaction.setRequiresUpdateSuggestions();
}
// undo phantom space if it's because after punctuation
// users who want to start a sentence with a lowercase letter may not like it
if (mSpaceState == SpaceState.PHANTOM
&& inputTransaction.getMSettingsValues().isUsuallyFollowedBySpace(mConnection.getCodePointBeforeCursor()))
if (mSpaceState == SpaceState.PHANTOM && inputTransaction.getMSettingsValues().mShiftRemovesAutospace)
mSpaceState = SpaceState.NONE;
break;
case KeyCode.SETTINGS:
@ -776,6 +776,9 @@ public final class InputLogic {
case KeyCode.SPLIT_LAYOUT:
KeyboardSwitcher.getInstance().toggleSplitKeyboardMode();
break;
case KeyCode.TIMESTAMP:
mLatinIME.onTextInput(TimestampKt.getTimestamp(mLatinIME));
break;
case KeyCode.VOICE_INPUT:
// switching to shortcut IME, shift state, keyboard,... is handled by LatinIME,
// {@link KeyboardSwitcher#onEvent(Event)}, or {@link #onPressKey(int,int,boolean)} and {@link #onReleaseKey(int,boolean)}.
@ -930,6 +933,7 @@ public final class InputLogic {
// handleNonSpecialCharacterEvent which has the same name as other handle* methods but is
// not the same.
boolean isComposingWord = mWordComposer.isComposingWord();
mWordComposer.unsetBatchMode(); // relevant in case we continue a batch word with normal typing
// if we continue directly after a sometimesWordConnector, restart suggestions for the whole word
// (only with URL detection and suggestions enabled)
@ -949,7 +953,9 @@ public final class InputLogic {
// TODO: remove isWordConnector() and use isUsuallyFollowedBySpace() instead.
// See onStartBatchInput() to see how to do it.
if (SpaceState.PHANTOM == inputTransaction.getMSpaceState()
&& !settingsValues.isWordConnector(codePoint)) {
&& !settingsValues.isWordConnector(codePoint)
&& !settingsValues.isUsuallyFollowedBySpace(codePoint) // only relevant in rare cases
) {
if (isComposingWord) {
// Sanity check
throw new RuntimeException("Should not be composing here");
@ -1127,7 +1133,7 @@ public final class InputLogic {
// A double quote behaves like it's usually followed by space if we're inside
// a double quote.
if (wasComposingWord
&& settingsValues.mAutospaceAfterPunctuationEnabled
&& settingsValues.mAutospaceAfterPunctuation
&& (settingsValues.isUsuallyFollowedBySpace(codePoint) || isInsideDoubleQuoteOrAfterDigit)) {
mSpaceState = SpaceState.PHANTOM;
}
@ -1196,7 +1202,7 @@ public final class InputLogic {
}
inputTransaction.setRequiresUpdateSuggestions();
} else {
if (mLastComposedWord.canRevertCommit()) {
if (mLastComposedWord.canRevertCommit() && inputTransaction.getMSettingsValues().mBackspaceRevertsAutocorrect) {
final String lastComposedWord = mLastComposedWord.mTypedWord;
revertCommit(inputTransaction);
StatsUtils.onRevertAutoCorrect();
@ -2168,6 +2174,7 @@ public final class InputLogic {
&& !(mConnection.getCodePointBeforeCursor() == Constants.CODE_PERIOD && mConnection.wordBeforeCursorMayBeEmail())
) {
mConnection.commitCodePoint(Constants.CODE_SPACE);
// todo: why not remove phantom space state?
}
}
@ -2202,12 +2209,14 @@ public final class InputLogic {
mConnection.beginBatchEdit();
if (SpaceState.PHANTOM == mSpaceState) {
insertAutomaticSpaceIfOptionsAndTextAllow(settingsValues);
mSpaceState = SpaceState.NONE;
}
mWordComposer.setBatchInputWord(batchInputText);
setComposingTextInternal(batchInputText, 1);
mConnection.endBatchEdit();
// Space state must be updated before calling updateShiftState
mSpaceState = SpaceState.PHANTOM;
if (settingsValues.mAutospaceAfterGestureTyping)
mSpaceState = SpaceState.PHANTOM;
keyboardSwitcher.requestUpdatingShiftState(getCurrentAutoCapsState(settingsValues), getCurrentRecapitalizeState());
}

View file

@ -9,7 +9,6 @@ import helium314.keyboard.keyboard.KeyboardTheme
import helium314.keyboard.latin.BuildConfig
import helium314.keyboard.latin.common.Constants.Separators
import helium314.keyboard.latin.common.Constants.Subtype.ExtraValue
import helium314.keyboard.latin.utils.JniUtils
import helium314.keyboard.latin.utils.LayoutType
import helium314.keyboard.latin.utils.POPUP_KEYS_LABEL_DEFAULT
import helium314.keyboard.latin.utils.POPUP_KEYS_ORDER_DEFAULT
@ -64,9 +63,11 @@ object Defaults {
const val PREF_MORE_AUTO_CORRECTION = false
const val PREF_AUTO_CORRECT_THRESHOLD = 0.185f
const val PREF_AUTOCORRECT_SHORTCUTS = true
const val PREF_BACKSPACE_REVERTS_AUTOCORRECT = true
const val PREF_CENTER_SUGGESTION_TEXT_TO_ENTER = false
const val PREF_SHOW_SUGGESTIONS = true
const val PREF_ALWAYS_SHOW_SUGGESTIONS = false
const val PREF_ALWAYS_SHOW_SUGGESTIONS_EXCEPT_WEB_TEXT = true
const val PREF_KEY_USE_PERSONALIZED_DICTS = true
const val PREF_KEY_USE_DOUBLE_SPACE_PERIOD = true
const val PREF_BLOCK_POTENTIALLY_OFFENSIVE = true
@ -92,6 +93,10 @@ object Defaults {
const val PREF_SPACE_VERTICAL_SWIPE = "none"
const val PREF_DELETE_SWIPE = true
const val PREF_AUTOSPACE_AFTER_PUNCTUATION = false
const val PREF_AUTOSPACE_AFTER_SUGGESTION = true
const val PREF_AUTOSPACE_AFTER_GESTURE_TYPING = true
const val PREF_AUTOSPACE_BEFORE_GESTURE_TYPING = true
const val PREF_SHIFT_REMOVES_AUTOSPACE = false
const val PREF_ALWAYS_INCOGNITO_MODE = false
const val PREF_BIGRAM_PREDICTIONS = true
const val PREF_SUGGEST_CLIPBOARD_CONTENT = true
@ -123,6 +128,7 @@ object Defaults {
const val PREF_POPUP_KEYS_ORDER = POPUP_KEYS_ORDER_DEFAULT
const val PREF_POPUP_KEYS_LABELS_ORDER = POPUP_KEYS_LABEL_DEFAULT
const val PREF_SHOW_POPUP_HINTS = false
const val PREF_SHOW_TLD_POPUP_KEYS = true
const val PREF_MORE_POPUP_KEYS = "main"
const val PREF_SPACE_TO_CHANGE_LANG = true
const val PREF_LANGUAGE_SWIPE_DISTANCE = 5
@ -145,15 +151,15 @@ object Defaults {
const val PREF_ABC_AFTER_EMOJI = false
const val PREF_ABC_AFTER_CLIP = false
const val PREF_ABC_AFTER_SYMBOL_SPACE = true
const val PREF_ABC_AFTER_NUMPAD_SPACE = false
const val PREF_REMOVE_REDUNDANT_POPUPS = false
const val PREF_SPACE_BAR_TEXT = ""
const val PREF_TIMESTAMP_FORMAT = "yyyy-MM-dd HH:mm:ss"
@JvmField
val PREF_EMOJI_MAX_SDK = Build.VERSION.SDK_INT
const val PREF_EMOJI_RECENT_KEYS = ""
const val PREF_LAST_SHOWN_EMOJI_CATEGORY_PAGE_ID = 0
const val PREF_PINNED_CLIPS = ""
@JvmField
val PREF_LIBRARY_CHECKSUM: String = JniUtils.expectedDefaultChecksum()
const val PREF_SHOW_DEBUG_SETTINGS = false
val PREF_DEBUG_MODE = BuildConfig.DEBUG
const val PREF_SHOW_SUGGESTION_INFOS = false

View file

@ -71,9 +71,11 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
public static final String PREF_MORE_AUTO_CORRECTION = "more_auto_correction";
public static final String PREF_AUTO_CORRECT_THRESHOLD = "auto_correct_threshold";
public static final String PREF_AUTOCORRECT_SHORTCUTS = "autocorrect_shortcuts";
public static final String PREF_BACKSPACE_REVERTS_AUTOCORRECT = "backspace_reverts_autocorrect";
public static final String PREF_CENTER_SUGGESTION_TEXT_TO_ENTER = "center_suggestion_text_to_enter";
public static final String PREF_SHOW_SUGGESTIONS = "show_suggestions";
public static final String PREF_ALWAYS_SHOW_SUGGESTIONS = "always_show_suggestions";
public static final String PREF_ALWAYS_SHOW_SUGGESTIONS_EXCEPT_WEB_TEXT = "always_show_suggestions_except_web_text";
public static final String PREF_KEY_USE_PERSONALIZED_DICTS = "use_personalized_dicts";
public static final String PREF_KEY_USE_DOUBLE_SPACE_PERIOD = "use_double_space_period";
public static final String PREF_BLOCK_POTENTIALLY_OFFENSIVE = "block_potentially_offensive";
@ -97,6 +99,10 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
public static final String PREF_SPACE_VERTICAL_SWIPE = "vertical_space_swipe";
public static final String PREF_DELETE_SWIPE = "delete_swipe";
public static final String PREF_AUTOSPACE_AFTER_PUNCTUATION = "autospace_after_punctuation";
public static final String PREF_AUTOSPACE_AFTER_SUGGESTION = "autospace_after_suggestion";
public static final String PREF_AUTOSPACE_AFTER_GESTURE_TYPING = "autospace_after_gesture_typing";
public static final String PREF_AUTOSPACE_BEFORE_GESTURE_TYPING = "autospace_before_gesture_typing";
public static final String PREF_SHIFT_REMOVES_AUTOSPACE = "shift_removes_autospace";
public static final String PREF_ALWAYS_INCOGNITO_MODE = "always_incognito_mode";
public static final String PREF_BIGRAM_PREDICTIONS = "next_word_prediction";
public static final String PREF_SUGGEST_CLIPBOARD_CONTENT = "suggest_clipboard_content";
@ -131,6 +137,7 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
public static final String PREF_POPUP_KEYS_LABELS_ORDER = "popup_keys_labels_order";
public static final String PREF_SHOW_POPUP_HINTS = "show_popup_hints";
public static final String PREF_MORE_POPUP_KEYS = "more_popup_keys";
public static final String PREF_SHOW_TLD_POPUP_KEYS = "show_tld_popup_keys";
public static final String PREF_SPACE_TO_CHANGE_LANG = "prefs_long_press_keyboard_to_change_lang";
public static final String PREF_LANGUAGE_SWIPE_DISTANCE = "language_swipe_distance";
@ -154,8 +161,10 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
public static final String PREF_ABC_AFTER_EMOJI = "abc_after_emoji";
public static final String PREF_ABC_AFTER_CLIP = "abc_after_clip";
public static final String PREF_ABC_AFTER_SYMBOL_SPACE = "abc_after_symbol_space";
public static final String PREF_ABC_AFTER_NUMPAD_SPACE = "abc_after_numpad_space";
public static final String PREF_REMOVE_REDUNDANT_POPUPS = "remove_redundant_popups";
public static final String PREF_SPACE_BAR_TEXT = "space_bar_text";
public static final String PREF_TIMESTAMP_FORMAT = "timestamp_format";
// Emoji
public static final String PREF_EMOJI_MAX_SDK = "emoji_max_sdk";

View file

@ -11,6 +11,7 @@ import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.text.InputType;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodSubtype;
@ -65,6 +66,7 @@ public class SettingsValues {
public final boolean mShowNumberRowHints;
public final boolean mShowsHints;
public final boolean mShowsPopupHints;
public final boolean mShowTldPopupKeys;
public final boolean mSpaceForLangChange;
public final boolean mShowsEmojiKey;
public final boolean mVarToolbarDirection;
@ -75,7 +77,11 @@ public class SettingsValues {
public final int mSpaceSwipeVertical;
public final int mLanguageSwipeDistance;
public final boolean mDeleteSwipeEnabled;
public final boolean mAutospaceAfterPunctuationEnabled;
public final boolean mAutospaceAfterPunctuation;
public final boolean mAutospaceAfterSuggestion;
public final boolean mAutospaceAfterGestureTyping;
public final boolean mAutospaceBeforeGestureTyping;
public final boolean mShiftRemovesAutospace;
public final boolean mClipboardHistoryEnabled;
public final long mClipboardHistoryRetentionTime;
public final boolean mOneHandedModeEnabled;
@ -113,6 +119,7 @@ public class SettingsValues {
public final boolean mAlphaAfterEmojiInEmojiView;
public final boolean mAlphaAfterClipHistoryEntry;
public final boolean mAlphaAfterSymbolAndSpace;
public final boolean mAlphaAfterNumpadAndSpace;
public final boolean mRemoveRedundantPopups;
public final String mSpaceBarText;
public final float mFontSizeMultiplier;
@ -128,6 +135,7 @@ public class SettingsValues {
public final boolean mAutoCorrectionEnabledPerUserSettings;
public final boolean mAutoCorrectEnabled;
public final float mAutoCorrectionThreshold;
public final boolean mBackspaceRevertsAutocorrect;
public final int mScoreLimitForAutocorrect;
public final boolean mAutoCorrectShortcuts;
private final boolean mSuggestionsEnabledPerUserSettings;
@ -172,6 +180,7 @@ public class SettingsValues {
mShowNumberRowHints = prefs.getBoolean(Settings.PREF_SHOW_NUMBER_ROW_HINTS, Defaults.PREF_SHOW_NUMBER_ROW_HINTS);
mShowsHints = prefs.getBoolean(Settings.PREF_SHOW_HINTS, Defaults.PREF_SHOW_HINTS);
mShowsPopupHints = prefs.getBoolean(Settings.PREF_SHOW_POPUP_HINTS, Defaults.PREF_SHOW_POPUP_HINTS);
mShowTldPopupKeys = prefs.getBoolean(Settings.PREF_SHOW_TLD_POPUP_KEYS, Defaults.PREF_SHOW_TLD_POPUP_KEYS);
mSpaceForLangChange = prefs.getBoolean(Settings.PREF_SPACE_TO_CHANGE_LANG, Defaults.PREF_SPACE_TO_CHANGE_LANG);
mShowsEmojiKey = prefs.getBoolean(Settings.PREF_SHOW_EMOJI_KEY, Defaults.PREF_SHOW_EMOJI_KEY);
mVarToolbarDirection = prefs.getBoolean(Settings.PREF_VARIABLE_TOOLBAR_DIRECTION, Defaults.PREF_VARIABLE_TOOLBAR_DIRECTION);
@ -191,6 +200,7 @@ public class SettingsValues {
mScoreLimitForAutocorrect = (mAutoCorrectionThreshold < 0) ? 600000 // very aggressive
: (mAutoCorrectionThreshold < 0.07 ? 800000 : 950000); // aggressive or modest
mAutoCorrectShortcuts = prefs.getBoolean(Settings.PREF_AUTOCORRECT_SHORTCUTS, Defaults.PREF_AUTOCORRECT_SHORTCUTS);
mBackspaceRevertsAutocorrect = prefs.getBoolean(Settings.PREF_BACKSPACE_REVERTS_AUTOCORRECT, Defaults.PREF_BACKSPACE_REVERTS_AUTOCORRECT);
mBigramPredictionEnabled = prefs.getBoolean(Settings.PREF_BIGRAM_PREDICTIONS, Defaults.PREF_BIGRAM_PREDICTIONS);
mSuggestClipboardContent = prefs.getBoolean(Settings.PREF_SUGGEST_CLIPBOARD_CONTENT, Defaults.PREF_SUGGEST_CLIPBOARD_CONTENT);
mDoubleSpacePeriodTimeout = 1100; // ms
@ -218,7 +228,10 @@ public class SettingsValues {
mGestureFastTypingCooldown = prefs.getInt(Settings.PREF_GESTURE_FAST_TYPING_COOLDOWN, Defaults.PREF_GESTURE_FAST_TYPING_COOLDOWN);
mGestureTrailFadeoutDuration = prefs.getInt(Settings.PREF_GESTURE_TRAIL_FADEOUT_DURATION, Defaults.PREF_GESTURE_TRAIL_FADEOUT_DURATION);
mAccount = null; // remove? or can it be useful somewhere?
mOverrideShowingSuggestions = mInputAttributes.mMayOverrideShowingSuggestions && prefs.getBoolean(Settings.PREF_ALWAYS_SHOW_SUGGESTIONS, Defaults.PREF_ALWAYS_SHOW_SUGGESTIONS);
mOverrideShowingSuggestions = mInputAttributes.mMayOverrideShowingSuggestions
&& prefs.getBoolean(Settings.PREF_ALWAYS_SHOW_SUGGESTIONS, Defaults.PREF_ALWAYS_SHOW_SUGGESTIONS)
&& ((inputAttributes.mInputType & InputType.TYPE_MASK_VARIATION) != InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT
|| !prefs.getBoolean(Settings.PREF_ALWAYS_SHOW_SUGGESTIONS_EXCEPT_WEB_TEXT, Defaults.PREF_ALWAYS_SHOW_SUGGESTIONS_EXCEPT_WEB_TEXT));
final boolean suggestionsEnabled = prefs.getBoolean(Settings.PREF_SHOW_SUGGESTIONS, Defaults.PREF_SHOW_SUGGESTIONS);
mSuggestionsEnabledPerUserSettings = (mInputAttributes.mShouldShowSuggestions && suggestionsEnabled)
|| mOverrideShowingSuggestions;
@ -229,7 +242,11 @@ public class SettingsValues {
mSpaceSwipeVertical = Settings.readVerticalSpaceSwipe(prefs);
mLanguageSwipeDistance = prefs.getInt(Settings.PREF_LANGUAGE_SWIPE_DISTANCE, Defaults.PREF_LANGUAGE_SWIPE_DISTANCE);
mDeleteSwipeEnabled = prefs.getBoolean(Settings.PREF_DELETE_SWIPE, Defaults.PREF_DELETE_SWIPE);
mAutospaceAfterPunctuationEnabled = prefs.getBoolean(Settings.PREF_AUTOSPACE_AFTER_PUNCTUATION, Defaults.PREF_AUTOSPACE_AFTER_PUNCTUATION);
mAutospaceAfterPunctuation = prefs.getBoolean(Settings.PREF_AUTOSPACE_AFTER_PUNCTUATION, Defaults.PREF_AUTOSPACE_AFTER_PUNCTUATION);
mAutospaceAfterSuggestion = prefs.getBoolean(Settings.PREF_AUTOSPACE_AFTER_SUGGESTION, Defaults.PREF_AUTOSPACE_AFTER_SUGGESTION);
mAutospaceAfterGestureTyping = prefs.getBoolean(Settings.PREF_AUTOSPACE_AFTER_GESTURE_TYPING, Defaults.PREF_AUTOSPACE_AFTER_GESTURE_TYPING);
mAutospaceBeforeGestureTyping = prefs.getBoolean(Settings.PREF_AUTOSPACE_BEFORE_GESTURE_TYPING, Defaults.PREF_AUTOSPACE_BEFORE_GESTURE_TYPING);
mShiftRemovesAutospace = prefs.getBoolean(Settings.PREF_SHIFT_REMOVES_AUTOSPACE, Defaults.PREF_SHIFT_REMOVES_AUTOSPACE);
mClipboardHistoryEnabled = prefs.getBoolean(Settings.PREF_ENABLE_CLIPBOARD_HISTORY, Defaults.PREF_ENABLE_CLIPBOARD_HISTORY);
mClipboardHistoryRetentionTime = prefs.getInt(Settings.PREF_CLIPBOARD_HISTORY_RETENTION_TIME, Defaults.PREF_CLIPBOARD_HISTORY_RETENTION_TIME);
@ -266,6 +283,7 @@ public class SettingsValues {
mAlphaAfterEmojiInEmojiView = prefs.getBoolean(Settings.PREF_ABC_AFTER_EMOJI, Defaults.PREF_ABC_AFTER_EMOJI);
mAlphaAfterClipHistoryEntry = prefs.getBoolean(Settings.PREF_ABC_AFTER_CLIP, Defaults.PREF_ABC_AFTER_CLIP);
mAlphaAfterSymbolAndSpace = prefs.getBoolean(Settings.PREF_ABC_AFTER_SYMBOL_SPACE, Defaults.PREF_ABC_AFTER_SYMBOL_SPACE);
mAlphaAfterNumpadAndSpace = prefs.getBoolean(Settings.PREF_ABC_AFTER_NUMPAD_SPACE, Defaults.PREF_ABC_AFTER_NUMPAD_SPACE);
mRemoveRedundantPopups = prefs.getBoolean(Settings.PREF_REMOVE_REDUNDANT_POPUPS, Defaults.PREF_REMOVE_REDUNDANT_POPUPS);
mSpaceBarText = prefs.getString(Settings.PREF_SPACE_BAR_TEXT, Defaults.PREF_SPACE_BAR_TEXT);
mEmojiMaxSdk = prefs.getInt(Settings.PREF_EMOJI_MAX_SDK, Defaults.PREF_EMOJI_MAX_SDK);

View file

@ -1,7 +1,7 @@
package helium314.keyboard.latin.utils
import android.content.Context
import androidx.appcompat.view.ContextThemeWrapper
import android.view.ContextThemeWrapper
import helium314.keyboard.latin.R
// todo: ideally the custom InputMethodPicker would be removed / replaced with compose dialog, then this can be removed

View file

@ -2,6 +2,7 @@
package helium314.keyboard.latin.utils
import android.app.AlertDialog
import android.os.IBinder
import android.text.Spannable
import android.text.SpannableString
@ -10,7 +11,6 @@ import android.text.style.RelativeSizeSpan
import android.view.WindowManager
import android.view.inputmethod.InputMethodInfo
import android.view.inputmethod.InputMethodSubtype
import androidx.appcompat.app.AlertDialog
import helium314.keyboard.latin.LatinIME
import helium314.keyboard.latin.R
import helium314.keyboard.latin.RichInputMethodManager

View file

@ -13,7 +13,6 @@ import android.text.TextUtils;
import helium314.keyboard.latin.App;
import helium314.keyboard.latin.BuildConfig;
import helium314.keyboard.latin.settings.Defaults;
import helium314.keyboard.latin.settings.Settings;
import java.io.File;
@ -63,7 +62,7 @@ public final class JniUtils {
// we want the default preferences, because storing the checksum in device protected storage is discouraged
// see https://developer.android.com/reference/android/content/Context#createDeviceProtectedStorageContext()
// if device is locked, this will throw an IllegalStateException
wantedChecksum = KtxKt.protectedPrefs(app).getString(Settings.PREF_LIBRARY_CHECKSUM, Defaults.PREF_LIBRARY_CHECKSUM);
wantedChecksum = KtxKt.protectedPrefs(app).getString(Settings.PREF_LIBRARY_CHECKSUM, expectedDefaultChecksum());
}
final FileInputStream libStream = new FileInputStream(userSuppliedLibrary);
final String checksum = ChecksumCalculator.INSTANCE.checksum(libStream);

View file

@ -162,7 +162,7 @@ object ScriptUtils {
return SCRIPT_LATIN
}
return when (language) {
"ar", "ur", "fa" -> SCRIPT_ARABIC
"ar", "ckb", "ur", "fa" -> SCRIPT_ARABIC
"hy" -> SCRIPT_ARMENIAN
"bn" -> SCRIPT_BENGALI
"sr", "mk", "ru", "uk", "mn", "be", "kk", "ky", "bg", "xdq", "cv", "mhr", "mns", "dru" -> SCRIPT_CYRILLIC

View file

@ -0,0 +1,17 @@
// SPDX-License-Identifier: GPL-3.0-only
package helium314.keyboard.latin.utils
import android.content.Context
import helium314.keyboard.latin.settings.Defaults
import helium314.keyboard.latin.settings.Settings
import java.text.SimpleDateFormat
import java.util.Calendar
fun getTimestamp(context: Context): String {
val format = context.prefs().getString(Settings.PREF_TIMESTAMP_FORMAT, Defaults.PREF_TIMESTAMP_FORMAT)
val formatter = runCatching { SimpleDateFormat(format, Settings.getValues().mLocale) }.getOrNull()
?: SimpleDateFormat(Defaults.PREF_TIMESTAMP_FORMAT, Settings.getValues().mLocale)
return formatter.format(Calendar.getInstance().time)
}
fun checkTimestampFormat(format: String) = runCatching { SimpleDateFormat(format, Settings.getValues().mLocale) }.isSuccess

View file

@ -1,13 +1,18 @@
// SPDX-License-Identifier: GPL-3.0-only
package helium314.keyboard.settings
import android.graphics.drawable.VectorDrawable
import androidx.annotation.DrawableRes
import androidx.compose.foundation.Image
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
@ -17,8 +22,15 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.style.TextDirection
import androidx.compose.ui.unit.dp
import androidx.core.content.ContextCompat
import androidx.core.graphics.drawable.toBitmap
import androidx.core.util.TypedValueCompat
@Composable
fun WithSmallTitle(
@ -31,6 +43,19 @@ fun WithSmallTitle(
}
}
/** Icon if resource is a vector image, (bitmap) Image otherwise */
@Composable
fun IconOrImage(@DrawableRes resId: Int, name: String?, sizeDp: Float) {
val ctx = LocalContext.current
val drawable = ContextCompat.getDrawable(ctx, resId)
if (drawable is VectorDrawable)
Icon(painterResource(resId), name, Modifier.size(sizeDp.dp))
else {
val px = TypedValueCompat.dpToPx(sizeDp, ctx.resources.displayMetrics).toInt()
Image(drawable!!.toBitmap(px, px).asImageBitmap(), name)
}
}
@Composable
fun <T>DropDownField(
items: List<T>,
@ -67,3 +92,5 @@ fun <T>DropDownField(
}
}
}
val contentTextDirectionStyle = TextStyle(textDirection = TextDirection.Content)

View file

@ -103,6 +103,7 @@ fun <T: Any?> SearchScreen(
title: @Composable () -> Unit,
filteredItems: (String) -> List<T>,
itemContent: @Composable (T) -> Unit,
icon: @Composable (() -> Unit)? = null,
menu: List<Pair<String, () -> Unit>>? = null,
content: @Composable (ColumnScope.() -> Unit)? = null,
) {
@ -137,8 +138,10 @@ fun <T: Any?> SearchScreen(
}
},
actions = {
IconButton(onClick = { setShowSearch(!showSearch) })
{ SearchIcon() }
if (icon == null)
IconButton(onClick = { setShowSearch(!showSearch) }) { SearchIcon() }
else
icon()
if (menu != null)
Box {
var showMenu by remember { mutableStateOf(false) }
@ -227,7 +230,8 @@ fun ExpandableSearchField(
else onSearchChange(TextFieldValue())
}) { CloseIcon(android.R.string.cancel) } },
singleLine = true,
colors = colors
colors = colors,
textStyle = contentTextDirectionStyle
)
}
}

View file

@ -1,16 +1,22 @@
// SPDX-License-Identifier: GPL-3.0-only
package helium314.keyboard.settings
import android.provider.Settings
import android.provider.Settings.Global
import androidx.compose.animation.core.tween
import androidx.compose.animation.slideInHorizontally
import androidx.compose.animation.slideOutHorizontally
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.LayoutDirection
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import helium314.keyboard.latin.common.LocaleUtils.constructLocale
import helium314.keyboard.latin.settings.SettingsSubtype.Companion.toSettingsSubtype
import helium314.keyboard.settings.screens.AboutScreen
import helium314.keyboard.settings.screens.AdvancedSettingsScreen
import helium314.keyboard.settings.screens.AppearanceScreen
@ -24,6 +30,7 @@ import helium314.keyboard.settings.screens.PersonalDictionariesScreen
import helium314.keyboard.settings.screens.PersonalDictionaryScreen
import helium314.keyboard.settings.screens.PreferencesScreen
import helium314.keyboard.settings.screens.SecondaryLayoutScreen
import helium314.keyboard.settings.screens.SubtypeScreen
import helium314.keyboard.settings.screens.TextCorrectionScreen
import helium314.keyboard.settings.screens.ToolbarScreen
import kotlinx.coroutines.CoroutineScope
@ -41,6 +48,10 @@ fun SettingsNavHost(
val dir = if (LocalLayoutDirection.current == LayoutDirection.Ltr) 1 else -1
val target = SettingsDestination.navTarget.collectAsState()
// duration does not change when system setting changes, but that's rare enough to not care
val duration = (250 * Settings.System.getFloat(LocalContext.current.contentResolver, Global.TRANSITION_ANIMATION_SCALE, 1f)).toInt()
val animation = tween<IntOffset>(durationMillis = duration)
fun goBack() {
if (!navController.popBackStack()) onClickBack()
}
@ -48,10 +59,10 @@ fun SettingsNavHost(
NavHost(
navController = navController,
startDestination = startDestination ?: SettingsDestination.Settings,
enterTransition = { slideInHorizontally(initialOffsetX = { +it * dir }) },
exitTransition = { slideOutHorizontally(targetOffsetX = { -it * dir }) },
popEnterTransition = { slideInHorizontally(initialOffsetX = { -it * dir }) },
popExitTransition = { slideOutHorizontally(targetOffsetX = { +it * dir }) }
enterTransition = { slideInHorizontally(initialOffsetX = { +it * dir }, animationSpec = animation) },
exitTransition = { slideOutHorizontally(targetOffsetX = { -it * dir }, animationSpec = animation) },
popEnterTransition = { slideInHorizontally(initialOffsetX = { -it * dir }, animationSpec = animation) },
popExitTransition = { slideOutHorizontally(targetOffsetX = { +it * dir }, animationSpec = animation) }
) {
composable(SettingsDestination.Settings) {
MainSettingsScreen(
@ -117,6 +128,9 @@ fun SettingsNavHost(
composable(SettingsDestination.ColorsNight + "{theme}") {
ColorsScreen(isNight = true, theme = it.arguments?.getString("theme"), onClickBack = ::goBack)
}
composable(SettingsDestination.Subtype + "{subtype}") {
SubtypeScreen(initialSubtype = it.arguments?.getString("subtype")!!.toSettingsSubtype(), onClickBack = ::goBack)
}
}
if (target.value != SettingsDestination.Settings/* && target.value != navController.currentBackStackEntry?.destination?.route*/)
navController.navigate(route = target.value)
@ -137,6 +151,7 @@ object SettingsDestination {
const val PersonalDictionaries = "personal_dictionaries"
const val PersonalDictionary = "personal_dictionary/"
const val Languages = "languages"
const val Subtype = "subtype/"
const val Layouts = "layouts"
const val Dictionaries = "dictionaries"
val navTarget = MutableStateFlow(Settings)

View file

@ -7,6 +7,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
@ -24,6 +25,7 @@ import androidx.compose.ui.graphics.PaintingStyle
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.text.TextRange
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.tooling.preview.Preview
@ -109,8 +111,12 @@ fun ColorPickerDialog(
)
TextField(
value = textValue,
// todo: KeyboardType.Password is a crappy way of avoiding suggestions... is there really no way in compose?
keyboardOptions = KeyboardOptions(autoCorrectEnabled = false, keyboardType = KeyboardType.Password),
keyboardOptions = KeyboardOptions(
autoCorrectEnabled = false,
keyboardType = KeyboardType.Password, // todo: KeyboardType.Password is a crappy way of avoiding suggestions... is there really no way in compose?
imeAction = ImeAction.Done,
),
keyboardActions = KeyboardActions(onDone = { onDismissRequest(); onConfirmed(controller.selectedColor.value.toArgb()) }),
onValueChange = {
textValue = it
val androidColor = runCatching { android.graphics.Color.parseColor("#${it.text}") }.getOrNull()

View file

@ -60,6 +60,7 @@ import helium314.keyboard.settings.Theme
import helium314.keyboard.settings.filePicker
import helium314.keyboard.settings.previewDark
import helium314.keyboard.settings.screens.SaveThoseColors
import helium314.keyboard.settings.contentTextDirectionStyle
import kotlinx.coroutines.launch
import kotlinx.serialization.SerializationException
import kotlinx.serialization.json.Json
@ -187,7 +188,8 @@ private fun AddColorRow(onDismissRequest: () -> Unit, userColors: Collection<Str
onValueChange = { textValue = it },
modifier = Modifier.weight(1f),
singleLine = true,
label = label
label = label,
textStyle = contentTextDirectionStyle,
)
EditButton(currentName.isNotBlank() && currentName !in userColors) {
onDismissRequest()

View file

@ -29,6 +29,7 @@ import helium314.keyboard.latin.utils.getStringResourceOrName
import helium314.keyboard.settings.CloseIcon
import helium314.keyboard.settings.SettingsActivity
import helium314.keyboard.settings.Theme
import helium314.keyboard.settings.contentTextDirectionStyle
import helium314.keyboard.settings.initPreview
import helium314.keyboard.settings.previewDark
import kotlinx.coroutines.Job
@ -92,6 +93,7 @@ fun LayoutEditDialog(
isError = !nameValid,
supportingText = { if (!nameValid) Text(stringResource(R.string.name_invalid)) },
trailingIcon = { if (!nameValid) CloseIcon(R.string.name_invalid) },
textStyle = contentTextDirectionStyle,
)
},
checkTextValid = { text ->

View file

@ -50,6 +50,7 @@ import helium314.keyboard.settings.EditButton
import helium314.keyboard.settings.Setting
import helium314.keyboard.settings.SettingsActivity
import helium314.keyboard.settings.Theme
import helium314.keyboard.settings.contentTextDirectionStyle
import helium314.keyboard.settings.layoutFilePicker
import helium314.keyboard.settings.layoutIntent
import helium314.keyboard.settings.previewDark
@ -140,7 +141,8 @@ private fun AddLayoutRow(onNewLayout: (String) -> Unit, layoutType: LayoutType,
value = textValue,
onValueChange = { textValue = it },
modifier = Modifier.weight(1f),
singleLine = true
singleLine = true,
textStyle = contentTextDirectionStyle,
)
EditButton(textValue.text.isNotEmpty() && LayoutUtilsCustom.getLayoutName(textValue.text, layoutType) !in userLayouts) {
onNewLayout(textValue.text)

View file

@ -22,6 +22,7 @@ import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.window.DialogProperties
import helium314.keyboard.settings.Theme
import helium314.keyboard.settings.contentTextDirectionStyle
import helium314.keyboard.settings.previewDark
// mostly taken from StreetComplete / SCEE
@ -76,7 +77,8 @@ fun TextInputDialog(
.focusRequester(focusRequester),
label = textInputLabel,
keyboardOptions = KeyboardOptions(keyboardType = keyboardType),
singleLine = singleLine
singleLine = singleLine,
textStyle = contentTextDirectionStyle,
)
},
properties = properties,

View file

@ -35,10 +35,13 @@ fun LoadGestureLibPreference(setting: Setting) {
val abi = Build.SUPPORTED_ABIS[0]
val libFile = File(ctx.filesDir?.absolutePath + File.separator + JniUtils.JNI_LIB_IMPORT_FILE_NAME)
fun renameToLibFileAndRestart(file: File, checksum: String) {
libFile.setWritable(true)
libFile.delete()
// store checksum in default preferences (soo JniUtils)
// store checksum in default preferences (see JniUtils)
prefs.edit().putString(Settings.PREF_LIBRARY_CHECKSUM, checksum).commit()
file.renameTo(libFile)
file.copyTo(libFile)
libFile.setReadOnly()
file.delete()
Runtime.getRuntime().exit(0) // exit will restart the app, so library will be loaded
}
var tempFilePath: String? by rememberSaveable { mutableStateOf(null) }

View file

@ -10,7 +10,6 @@ import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.LocalContentColor
@ -29,6 +28,7 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import helium314.keyboard.latin.R
import helium314.keyboard.settings.IconOrImage
import helium314.keyboard.settings.Theme
import helium314.keyboard.settings.previewDark
@ -64,12 +64,12 @@ fun Preference(
.fillMaxWidth()
.clickable { onClick() }
.heightIn(min = 44.dp)
.padding(12.dp),
.padding(vertical = 10.dp, horizontal = 12.dp),
horizontalArrangement = Arrangement.spacedBy(12.dp),
verticalAlignment = Alignment.CenterVertically
) {
if (icon != null)
Icon(painterResource(icon), name, modifier = Modifier.size(36.dp))
IconOrImage(icon, name, 32f)
Column(modifier = Modifier.weight(1f)) {
Text(text = name, style = MaterialTheme.typography.bodyLarge)
if (description != null) {

View file

@ -0,0 +1,37 @@
// SPDX-License-Identifier: GPL-3.0-only
package helium314.keyboard.settings.preferences
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.platform.LocalContext
import helium314.keyboard.keyboard.KeyboardSwitcher
import helium314.keyboard.latin.utils.prefs
import helium314.keyboard.settings.Setting
import helium314.keyboard.settings.dialogs.TextInputDialog
@Composable
fun TextInputPreference(setting: Setting, default: String, checkTextValid: (String) -> Boolean = { true }) {
var showDialog by rememberSaveable { mutableStateOf(false) }
val prefs = LocalContext.current.prefs()
Preference(
name = setting.title,
onClick = { showDialog = true },
description = prefs.getString(setting.key, default)?.takeIf { it.isNotEmpty() }
)
if (showDialog) {
TextInputDialog(
onDismissRequest = { showDialog = false },
onConfirmed = {
prefs.edit().putString(setting.key, it).apply()
KeyboardSwitcher.getInstance().setThemeNeedsReload()
},
initialText = prefs.getString(setting.key, default) ?: "",
title = { Text(setting.title) },
checkTextValid = checkTextValid
)
}
}

View file

@ -2,6 +2,7 @@
package helium314.keyboard.settings.screens
import android.app.Activity
import android.app.AlertDialog
import android.content.Context
import android.content.Intent
import android.text.method.LinkMovementMethod
@ -10,7 +11,6 @@ import android.widget.TextView
import android.widget.Toast
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AlertDialog
import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
@ -69,7 +69,7 @@ fun createAboutSettings(context: Context) = listOf(
name = it.title,
description = it.description,
onClick = { },
icon = R.drawable.ic_launcher_foreground // use the bitmap trick here if we really want the colored icon
icon = R.mipmap.ic_launcher_round
)
},
Setting(context, SettingsWithoutKey.VERSION, R.string.version) {

View file

@ -29,6 +29,7 @@ import helium314.keyboard.latin.common.splitOnWhitespace
import helium314.keyboard.latin.settings.DebugSettings
import helium314.keyboard.latin.settings.Defaults
import helium314.keyboard.latin.settings.Settings
import helium314.keyboard.latin.utils.checkTimestampFormat
import helium314.keyboard.latin.utils.prefs
import helium314.keyboard.settings.NextScreenIcon
import helium314.keyboard.settings.SettingsContainer
@ -45,6 +46,7 @@ import helium314.keyboard.settings.Theme
import helium314.keyboard.settings.dialogs.TextInputDialog
import helium314.keyboard.settings.preferences.BackupRestorePreference
import helium314.keyboard.settings.preferences.LoadGestureLibPreference
import helium314.keyboard.settings.preferences.TextInputPreference
import helium314.keyboard.settings.previewDark
@Composable
@ -66,10 +68,12 @@ fun AdvancedSettingsScreen(
Settings.PREF_ENABLE_EMOJI_ALT_PHYSICAL_KEY,
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) Settings.PREF_SHOW_SETUP_WIZARD_ICON else null,
Settings.PREF_ABC_AFTER_SYMBOL_SPACE,
Settings.PREF_ABC_AFTER_NUMPAD_SPACE,
Settings.PREF_ABC_AFTER_EMOJI,
Settings.PREF_ABC_AFTER_CLIP,
Settings.PREF_CUSTOM_CURRENCY_KEY,
Settings.PREF_MORE_POPUP_KEYS,
Settings.PREF_TIMESTAMP_FORMAT,
SettingsWithoutKey.BACKUP_RESTORE,
if (BuildConfig.DEBUG || prefs.getBoolean(DebugSettings.PREF_SHOW_DEBUG_SETTINGS, Defaults.PREF_SHOW_DEBUG_SETTINGS))
SettingsWithoutKey.DEBUG_SETTINGS else null,
@ -154,6 +158,11 @@ fun createAdvancedSettings(context: Context) = listOf(
{
SwitchPreference(it, Defaults.PREF_ABC_AFTER_SYMBOL_SPACE)
},
Setting(context, Settings.PREF_ABC_AFTER_NUMPAD_SPACE,
R.string.switch_keyboard_after, R.string.after_numpad_and_space)
{
SwitchPreference(it, Defaults.PREF_ABC_AFTER_NUMPAD_SPACE)
},
Setting(context, Settings.PREF_ABC_AFTER_EMOJI, R.string.switch_keyboard_after, R.string.after_emoji) {
SwitchPreference(it, Defaults.PREF_ABC_AFTER_EMOJI)
},
@ -189,6 +198,9 @@ fun createAdvancedSettings(context: Context) = listOf(
Setting(context, SettingsWithoutKey.BACKUP_RESTORE, R.string.backup_restore_title) {
BackupRestorePreference(it)
},
Setting(context, Settings.PREF_TIMESTAMP_FORMAT, R.string.timestamp_format_title) {
TextInputPreference(it, Defaults.PREF_TIMESTAMP_FORMAT) { checkTimestampFormat(it) }
},
Setting(context, SettingsWithoutKey.DEBUG_SETTINGS, R.string.debug_settings_title) {
Preference(
name = it.title,

View file

@ -21,6 +21,7 @@ import helium314.keyboard.latin.R
import helium314.keyboard.latin.settings.Defaults
import helium314.keyboard.latin.settings.Settings
import helium314.keyboard.latin.utils.Log
import helium314.keyboard.latin.utils.checkTimestampFormat
import helium314.keyboard.latin.utils.getActivity
import helium314.keyboard.latin.utils.getStringResourceOrName
import helium314.keyboard.latin.utils.prefs
@ -39,6 +40,7 @@ import helium314.keyboard.settings.dialogs.TextInputDialog
import helium314.keyboard.settings.initPreview
import helium314.keyboard.settings.preferences.BackgroundImagePref
import helium314.keyboard.settings.preferences.CustomFontPreference
import helium314.keyboard.settings.preferences.TextInputPreference
import helium314.keyboard.settings.previewDark
@Composable
@ -263,26 +265,8 @@ fun createAppearanceSettings(context: Context) = listOf(
description = { "${(100 * it).toInt()}%" }
) { KeyboardSwitcher.getInstance().setThemeNeedsReload() }
},
Setting(context, Settings.PREF_SPACE_BAR_TEXT, R.string.prefs_space_bar_text) { setting ->
var showDialog by rememberSaveable { mutableStateOf(false) }
val prefs = LocalContext.current.prefs()
Preference(
name = setting.title,
onClick = { showDialog = true },
description = prefs.getString(setting.key, Defaults.PREF_SPACE_BAR_TEXT)?.takeIf { it.isNotEmpty() }
)
if (showDialog) {
TextInputDialog(
onDismissRequest = { showDialog = false },
onConfirmed = {
prefs.edit().putString(setting.key, it).apply()
KeyboardSwitcher.getInstance().setThemeNeedsReload()
},
initialText = prefs.getString(setting.key, Defaults.PREF_SPACE_BAR_TEXT) ?: "",
title = { Text(setting.title) },
checkTextValid = { true }
)
}
Setting(context, Settings.PREF_SPACE_BAR_TEXT, R.string.prefs_space_bar_text) {
TextInputPreference(it, Defaults.PREF_SPACE_BAR_TEXT)
},
Setting(context, SettingsWithoutKey.CUSTOM_FONT, R.string.custom_font) {
CustomFontPreference(it)

View file

@ -58,6 +58,7 @@ import helium314.keyboard.settings.CloseIcon
import helium314.keyboard.settings.SearchScreen
import helium314.keyboard.settings.SettingsActivity
import helium314.keyboard.settings.Theme
import helium314.keyboard.settings.contentTextDirectionStyle
import helium314.keyboard.settings.dialogs.ColorPickerDialog
import helium314.keyboard.settings.previewDark
import kotlinx.serialization.Serializable
@ -70,6 +71,14 @@ fun ColorsScreen(
onClickBack: () -> Unit
) {
val ctx = LocalContext.current
val prefs = ctx.prefs()
val b = (ctx.getActivity() as? SettingsActivity)?.prefChanged?.collectAsState()
if ((b?.value ?: 0) < 0)
Log.v("irrelevant", "stupid way to trigger recomposition on preference change")
val themeName = theme ?: if (isNight) prefs.getString(Settings.PREF_THEME_COLORS_NIGHT, Defaults.PREF_THEME_COLORS_NIGHT)!!
else prefs.getString(Settings.PREF_THEME_COLORS, Defaults.PREF_THEME_COLORS)!!
var newThemeName by rememberSaveable(stateSaver = TextFieldValue.Saver) { mutableStateOf(TextFieldValue(themeName)) }
// is there really no better way of only setting forceOpposite while the screen is shown (and not paused)?
// lifecycle stuff is weird, there is no pause and similar when activity is paused
@ -82,21 +91,14 @@ fun ColorsScreen(
val lifecycleState by lifecycleOwner.lifecycle.currentStateFlow.collectAsState()
LaunchedEffect(lifecycleState) {
if (lifecycleState == Lifecycle.State.RESUMED) {
(ctx.getActivity() as? SettingsActivity)?.setForceTheme(theme, isNight)
(ctx.getActivity() as? SettingsActivity)?.setForceTheme(newThemeName.text, isNight)
}
}
val prefs = ctx.prefs()
val b = (ctx.getActivity() as? SettingsActivity)?.prefChanged?.collectAsState()
if ((b?.value ?: 0) < 0)
Log.v("irrelevant", "stupid way to trigger recomposition on preference change")
val themeName = theme ?: if (isNight) prefs.getString(Settings.PREF_THEME_COLORS_NIGHT, Defaults.PREF_THEME_COLORS_NIGHT)!!
else prefs.getString(Settings.PREF_THEME_COLORS, Defaults.PREF_THEME_COLORS)!!
val moreColors = KeyboardTheme.readUserMoreColors(prefs, themeName)
val userColors = KeyboardTheme.readUserColors(prefs, themeName)
val moreColors = KeyboardTheme.readUserMoreColors(prefs, newThemeName.text)
val userColors = KeyboardTheme.readUserColors(prefs, newThemeName.text)
val shownColors = if (moreColors == 2) {
val allColors = KeyboardTheme.readUserAllColors(prefs, themeName)
val allColors = KeyboardTheme.readUserAllColors(prefs, newThemeName.text)
ColorType.entries.map {
ColorSetting(it.name, null, allColors[it] ?: it.default())
}
@ -113,12 +115,11 @@ fun ColorsScreen(
fun ColorSetting.displayColor() = if (auto == true) KeyboardTheme.determineUserColor(userColors, ctx, name, isNight)
else color ?: KeyboardTheme.determineUserColor(userColors, ctx, name, isNight)
var newThemeName by rememberSaveable(stateSaver = TextFieldValue.Saver) { mutableStateOf(TextFieldValue(themeName)) }
var chosenColorString: String by rememberSaveable { mutableStateOf("") }
val chosenColor = runCatching { Json.decodeFromString<ColorSetting?>(chosenColorString) }.getOrNull()
val saveLauncher = rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) {
if (it.resultCode != Activity.RESULT_OK) return@rememberLauncherForActivityResult
val uri = it.data?.data ?: return@rememberLauncherForActivityResult
val saveLauncher = rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode != Activity.RESULT_OK) return@rememberLauncherForActivityResult
val uri = result.data?.data ?: return@rememberLauncherForActivityResult
ctx.getActivity()?.contentResolver?.openOutputStream(uri)?.writer()?.use { it.write(getColorString(prefs, newThemeName.text)) }
}
SearchScreen(
@ -129,14 +130,17 @@ fun ColorsScreen(
value = nameField,
onValueChange = {
nameValid = KeyboardTheme.renameUserColors(newThemeName.text, it.text, prefs)
if (nameValid)
if (nameValid) {
newThemeName = it
SettingsActivity.forceTheme = newThemeName.text
}
nameField = it
},
isError = !nameValid,
// supportingText = { if (!nameValid) Text(stringResource(R.string.name_invalid)) } // todo: this is cutting off bottom half of the actual text...
trailingIcon = { if (!nameValid) CloseIcon(R.string.name_invalid) },
singleLine = true,
textStyle = contentTextDirectionStyle,
)
},
menu = listOf(
@ -193,11 +197,11 @@ fun ColorsScreen(
}
}
if (colorSetting.auto != null)
Switch(colorSetting.auto, onCheckedChange = {
val oldUserColors = KeyboardTheme.readUserColors(prefs, themeName)
val newUserColors = (oldUserColors + ColorSetting(colorSetting.name, it, colorSetting.color))
Switch(colorSetting.auto, onCheckedChange = { checked ->
val oldUserColors = KeyboardTheme.readUserColors(prefs, newThemeName.text)
val newUserColors = (oldUserColors + ColorSetting(colorSetting.name, checked, colorSetting.color))
.reversed().distinctBy { it.displayName }
KeyboardTheme.writeUserColors(prefs, themeName, newUserColors)
KeyboardTheme.writeUserColors(prefs, newThemeName.text, newUserColors)
})
}
}
@ -207,16 +211,16 @@ fun ColorsScreen(
onDismissRequest = { chosenColorString = "" },
initialColor = chosenColor.displayColor(),
title = chosenColor.displayName,
) {
) { color ->
if (moreColors == 2) {
val oldColors = KeyboardTheme.readUserAllColors(prefs, themeName)
oldColors[ColorType.valueOf(chosenColor.name)] = it
KeyboardTheme.writeUserAllColors(prefs, themeName, oldColors)
val oldColors = KeyboardTheme.readUserAllColors(prefs, newThemeName.text)
oldColors[ColorType.valueOf(chosenColor.name)] = color
KeyboardTheme.writeUserAllColors(prefs, newThemeName.text, oldColors)
} else {
val oldUserColors = KeyboardTheme.readUserColors(prefs, themeName)
val newUserColors = (oldUserColors + ColorSetting(chosenColor.name, false, it))
val oldUserColors = KeyboardTheme.readUserColors(prefs, newThemeName.text)
val newUserColors = (oldUserColors + ColorSetting(chosenColor.name, false, color))
.reversed().distinctBy { it.displayName }
KeyboardTheme.writeUserColors(prefs, themeName, newUserColors)
KeyboardTheme.writeUserColors(prefs, newThemeName.text, newUserColors)
}
}
}

View file

@ -18,7 +18,6 @@ import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@ -39,15 +38,14 @@ import helium314.keyboard.latin.utils.Log
import helium314.keyboard.latin.utils.MissingDictionaryDialog
import helium314.keyboard.latin.utils.SubtypeLocaleUtils
import helium314.keyboard.latin.utils.SubtypeSettings
import helium314.keyboard.latin.utils.SubtypeUtilsAdditional
import helium314.keyboard.latin.utils.displayName
import helium314.keyboard.latin.utils.getActivity
import helium314.keyboard.latin.utils.locale
import helium314.keyboard.latin.utils.prefs
import helium314.keyboard.settings.SearchScreen
import helium314.keyboard.settings.SettingsActivity
import helium314.keyboard.settings.SettingsDestination
import helium314.keyboard.settings.Theme
import helium314.keyboard.settings.dialogs.SubtypeDialog
import helium314.keyboard.settings.initPreview
import helium314.keyboard.settings.previewDark
import java.util.Locale
@ -57,12 +55,11 @@ fun LanguageScreen(
onClickBack: () -> Unit,
) {
val ctx = LocalContext.current
var sortedSubtypes by remember { mutableStateOf(getSortedSubtypes(ctx)) }
val sortedSubtypes by remember { mutableStateOf(getSortedSubtypes(ctx)) }
val prefs = ctx.prefs()
val b = (LocalContext.current.getActivity() as? SettingsActivity)?.prefChanged?.collectAsState()
if ((b?.value ?: 0) < 0)
Log.v("irrelevant", "stupid way to trigger recomposition on preference change")
var selectedSubtype: String? by rememberSaveable { mutableStateOf(null) }
val enabledSubtypes = SubtypeSettings.getEnabledSubtypes()
SearchScreen(
onClickBack = onClickBack,
@ -87,7 +84,9 @@ fun LanguageScreen(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.fillMaxWidth()
.clickable { selectedSubtype = item.toSettingsSubtype().toPref() }
.clickable {
SettingsDestination.navigateTo(SettingsDestination.Subtype + item.toSettingsSubtype().toPref())
}
.padding(vertical = 6.dp, horizontal = 16.dp)
) {
var showNoDictDialog by remember { mutableStateOf(false) }
@ -119,19 +118,6 @@ fun LanguageScreen(
}
}
)
if (selectedSubtype != null) {
val oldSubtype = selectedSubtype!!.toSettingsSubtype()
SubtypeDialog(
onDismissRequest = {
selectedSubtype = null
sortedSubtypes = getSortedSubtypes(ctx)
},
onConfirmed = {
SubtypeUtilsAdditional.changeAdditionalSubtype(oldSubtype, it, ctx)
},
initialSubtype = oldSubtype
)
}
}
private fun dictsAvailable(locale: Locale, context: Context): Boolean {

View file

@ -46,6 +46,7 @@ fun PreferencesScreen(
Settings.PREF_POPUP_KEYS_LABELS_ORDER else null,
Settings.PREF_POPUP_KEYS_ORDER,
Settings.PREF_SHOW_POPUP_HINTS,
Settings.PREF_SHOW_TLD_POPUP_KEYS,
Settings.PREF_POPUP_ON,
if (AudioAndHapticFeedbackManager.getInstance().hasVibrator())
Settings.PREF_VIBRATE_ON else null,
@ -89,6 +90,12 @@ fun createPreferencesSettings(context: Context) = listOf(
Setting(context, Settings.PREF_POPUP_KEYS_ORDER, R.string.popup_order) {
ReorderSwitchPreference(it, Defaults.PREF_POPUP_KEYS_ORDER)
},
Setting(
context, Settings.PREF_SHOW_TLD_POPUP_KEYS, R.string.show_tld_popup_keys,
R.string.show_tld_popup_keys_summary
) {
SwitchPreference(it, Defaults.PREF_SHOW_TLD_POPUP_KEYS) { KeyboardSwitcher.getInstance().setThemeNeedsReload() }
},
Setting(context, Settings.PREF_SHOW_POPUP_HINTS, R.string.show_popup_hints, R.string.show_popup_hints_summary) {
SwitchPreference(it, Defaults.PREF_SHOW_POPUP_HINTS) { KeyboardSwitcher.getInstance().setThemeNeedsReload() }
},
@ -149,10 +156,10 @@ fun createPreferencesSettings(context: Context) = listOf(
key = setting.key,
default = Defaults.PREF_CLIPBOARD_HISTORY_RETENTION_TIME,
description = {
if (it < 0) stringResource(R.string.settings_no_limit)
if (it > 120) stringResource(R.string.settings_no_limit)
else stringResource(R.string.abbreviation_unit_minutes, it.toString())
},
range = -1f..120f,
range = 1f..121f,
)
},
Setting(context, Settings.PREF_VIBRATION_DURATION_SETTINGS, R.string.prefs_keypress_vibration_duration_settings) { setting ->

View file

@ -1,5 +1,4 @@
// SPDX-License-Identifier: GPL-3.0-only
package helium314.keyboard.settings.dialogs
package helium314.keyboard.settings.screens
import android.content.Context
import androidx.compose.foundation.clickable
@ -14,6 +13,7 @@ import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Switch
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
@ -68,22 +68,32 @@ import helium314.keyboard.latin.utils.getStringResourceOrName
import helium314.keyboard.latin.utils.mainLayoutName
import helium314.keyboard.latin.utils.prefs
import helium314.keyboard.settings.DefaultButton
import helium314.keyboard.settings.DeleteButton
import helium314.keyboard.settings.DropDownField
import helium314.keyboard.settings.SearchScreen
import helium314.keyboard.settings.SettingsActivity
import helium314.keyboard.settings.Theme
import helium314.keyboard.settings.WithSmallTitle
import helium314.keyboard.settings.dialogs.ConfirmationDialog
import helium314.keyboard.settings.dialogs.LayoutEditDialog
import helium314.keyboard.settings.dialogs.ListPickerDialog
import helium314.keyboard.settings.dialogs.MultiListPickerDialog
import helium314.keyboard.settings.dialogs.ReorderDialog
import helium314.keyboard.settings.initPreview
import helium314.keyboard.settings.layoutFilePicker
import helium314.keyboard.settings.layoutIntent
import helium314.keyboard.settings.previewDark
import helium314.keyboard.settings.screens.GetIcon
import java.util.Locale
// todo:
// dropdowns are weird
// at very least too wide and too high
// also too wide left (anchor should be icon)
// title shows only the layout name
@Composable
fun SubtypeDialog(
onDismissRequest: () -> Unit,
fun SubtypeScreen(
initialSubtype: SettingsSubtype,
onConfirmed: (SettingsSubtype) -> Unit,
onClickBack: () -> Unit,
) {
val ctx = LocalContext.current
val prefs = ctx.prefs()
@ -92,7 +102,10 @@ fun SubtypeDialog(
Log.v("irrelevant", "stupid way to trigger recomposition on preference change")
var currentSubtypeString by rememberSaveable { mutableStateOf(initialSubtype.toPref()) }
val currentSubtype = currentSubtypeString.toSettingsSubtype()
fun setCurrentSubtype(subtype: SettingsSubtype) { currentSubtypeString = subtype.toPref() }
fun setCurrentSubtype(subtype: SettingsSubtype) {
SubtypeUtilsAdditional.changeAdditionalSubtype(currentSubtype, subtype, ctx)
currentSubtypeString = subtype.toPref()
}
LaunchedEffect(currentSubtypeString) {
if (ScriptUtils.scriptSupportsUppercase(currentSubtype.locale)) return@LaunchedEffect
// update the noShiftKey extra value
@ -120,120 +133,119 @@ fun SubtypeDialog(
var showMorePopupsDialog by remember { mutableStateOf(false) }
val scrollState = rememberScrollState()
val customMainLayouts = LayoutUtilsCustom.getLayoutFiles(LayoutType.MAIN, ctx, currentSubtype.locale).map { it.name }
ThreeButtonAlertDialog(
onDismissRequest = onDismissRequest,
onConfirmed = { onConfirmed(currentSubtype) },
neutralButtonText = if (initialSubtype.isAdditionalSubtype(prefs)) stringResource(R.string.delete) else null,
onNeutral = {
SubtypeUtilsAdditional.removeAdditionalSubtype(ctx, initialSubtype.toAdditionalSubtype())
SubtypeSettings.removeEnabledSubtype(ctx, initialSubtype.toAdditionalSubtype())
onDismissRequest()
},
SearchScreen(
onClickBack = onClickBack,
icon = { if (currentSubtype.isAdditionalSubtype(prefs)) DeleteButton {
SubtypeUtilsAdditional.removeAdditionalSubtype(ctx, currentSubtype.toAdditionalSubtype())
SubtypeSettings.removeEnabledSubtype(ctx, currentSubtype.toAdditionalSubtype())
onClickBack()
} },
title = {
val mainLayout = initialSubtype.mainLayoutName() ?: SubtypeLocaleUtils.QWERTY
Text(SubtypeLocaleUtils.getDisplayNameInSystemLocale(mainLayout, initialSubtype.locale))
val mainLayout = currentSubtype.mainLayoutName() ?: SubtypeLocaleUtils.QWERTY
Text(SubtypeLocaleUtils.getDisplayNameInSystemLocale(mainLayout, currentSubtype.locale))
},
content = {
Column(
modifier = Modifier.verticalScroll(scrollState),
verticalArrangement = Arrangement.spacedBy(8.dp),
) {
MainLayoutRow(initialSubtype, currentSubtype, customMainLayouts) { setCurrentSubtype(it) }
if (availableLocalesForScript.size > 1) {
WithSmallTitle(stringResource(R.string.secondary_locale)) {
TextButton(onClick = { showSecondaryLocaleDialog = true }) {
val text = getSecondaryLocales(currentSubtype.extraValues).joinToString(", ") {
it.localizedDisplayName(ctx)
}.ifEmpty { stringResource(R.string.action_none) }
Text(text, Modifier.fillMaxWidth(), style = MaterialTheme.typography.bodyLarge)
}
itemContent = { },
filteredItems = { emptyList<String>() }
) {
Column(
modifier = Modifier.verticalScroll(scrollState).padding(horizontal = 12.dp),
verticalArrangement = Arrangement.spacedBy(8.dp),
) {
MainLayoutRow(currentSubtype, customMainLayouts) { setCurrentSubtype(it) }
if (availableLocalesForScript.size > 1) {
WithSmallTitle(stringResource(R.string.secondary_locale)) {
TextButton(onClick = { showSecondaryLocaleDialog = true }) {
val text = getSecondaryLocales(currentSubtype.extraValues).joinToString(", ") {
it.localizedDisplayName(ctx)
}.ifEmpty { stringResource(R.string.action_none) }
Text(text, Modifier.fillMaxWidth())
}
}
Row {
TextButton(onClick = { showKeyOrderDialog = true }, Modifier.weight(1f))
{ Text(stringResource(R.string.popup_order), style = MaterialTheme.typography.bodyLarge) }
DefaultButton(currentSubtype.getExtraValueOf(ExtraValue.POPUP_ORDER) == null) {
setCurrentSubtype(currentSubtype.without(ExtraValue.POPUP_ORDER))
}
}
Row {
TextButton(onClick = { showKeyOrderDialog = true }, Modifier.weight(1f))
{ Text(stringResource(R.string.popup_order)) }
DefaultButton(currentSubtype.getExtraValueOf(ExtraValue.POPUP_ORDER) == null) {
setCurrentSubtype(currentSubtype.without(ExtraValue.POPUP_ORDER))
}
Row {
TextButton(onClick = { showHintOrderDialog = true }, Modifier.weight(1f))
{ Text(stringResource(R.string.hint_source), style = MaterialTheme.typography.bodyLarge) }
DefaultButton(currentSubtype.getExtraValueOf(ExtraValue.HINT_ORDER) == null) {
setCurrentSubtype(currentSubtype.without(ExtraValue.HINT_ORDER))
}
}
Row {
TextButton(onClick = { showHintOrderDialog = true }, Modifier.weight(1f))
{ Text(stringResource(R.string.hint_source)) }
DefaultButton(currentSubtype.getExtraValueOf(ExtraValue.HINT_ORDER) == null) {
setCurrentSubtype(currentSubtype.without(ExtraValue.HINT_ORDER))
}
if (currentSubtype.locale.script() == ScriptUtils.SCRIPT_LATIN) {
WithSmallTitle(stringResource(R.string.show_popup_keys_title)) {
val explicitValue = currentSubtype.getExtraValueOf(ExtraValue.MORE_POPUPS)
val value = explicitValue ?: prefs.getString(Settings.PREF_MORE_POPUP_KEYS, Defaults.PREF_MORE_POPUP_KEYS)!!
Row {
TextButton(onClick = { showMorePopupsDialog = true }, Modifier.weight(1f))
{ Text(stringResource(morePopupKeysResId(value))) }
DefaultButton(explicitValue == null) {
setCurrentSubtype(currentSubtype.without(ExtraValue.MORE_POPUPS))
}
}
}
}
if (hasLocalizedNumberRow(currentSubtype.locale, ctx)) {
Row(verticalAlignment = Alignment.CenterVertically) {
val checked = currentSubtype.getExtraValueOf(ExtraValue.LOCALIZED_NUMBER_ROW)?.toBoolean()
Text(stringResource(R.string.localized_number_row), Modifier.weight(1f))
Switch(
checked = checked ?: prefs.getBoolean(Settings.PREF_LOCALIZED_NUMBER_ROW, Defaults.PREF_LOCALIZED_NUMBER_ROW),
onCheckedChange = {
setCurrentSubtype(currentSubtype.with(ExtraValue.LOCALIZED_NUMBER_ROW, it.toString()))
}
)
DefaultButton(checked == null) {
setCurrentSubtype(currentSubtype.without(ExtraValue.LOCALIZED_NUMBER_ROW))
}
}
}
HorizontalDivider()
Text(stringResource(R.string.settings_screen_secondary_layouts), style = MaterialTheme.typography.titleMedium)
LayoutType.entries.forEach { type ->
if (type == LayoutType.MAIN) return@forEach
WithSmallTitle(stringResource(type.displayNameId)) {
val explicitLayout = currentSubtype.layoutName(type)
val layout = explicitLayout ?: Settings.readDefaultLayoutName(type, prefs)
val defaultLayouts = LayoutUtils.getAvailableLayouts(type, ctx)
val customLayouts = LayoutUtilsCustom.getLayoutFiles(type, ctx).map { it.name }
DropDownField(
items = defaultLayouts + customLayouts,
selectedItem = layout,
onSelected = {
setCurrentSubtype(currentSubtype.withLayout(type, it))
},
extraButton = { DefaultButton(explicitLayout == null) {
setCurrentSubtype(currentSubtype.withoutLayout(type))
} },
) {
val displayName = if (LayoutUtilsCustom.isCustomLayout(it)) LayoutUtilsCustom.getDisplayName(it)
else it.getStringResourceOrName("layout_", ctx)
var showLayoutEditDialog by remember { mutableStateOf(false) }
Row(
horizontalArrangement = Arrangement.SpaceBetween,
modifier = Modifier.fillMaxWidth()
) {
Text(displayName, Modifier.padding(end = 8.dp))
if (LayoutUtilsCustom.isCustomLayout(it))
Icon(painterResource(R.drawable.ic_edit), stringResource(R.string.edit_layout), Modifier.clickable { showLayoutEditDialog = true })
}
if (showLayoutEditDialog)
LayoutEditDialog(
onDismissRequest = { showLayoutEditDialog = false },
layoutType = type,
initialLayoutName = it,
isNameValid = null
)
}
if (currentSubtype.locale.script() == ScriptUtils.SCRIPT_LATIN) {
WithSmallTitle(stringResource(R.string.show_popup_keys_title)) {
val explicitValue = currentSubtype.getExtraValueOf(ExtraValue.MORE_POPUPS)
val value = explicitValue ?: prefs.getString(Settings.PREF_MORE_POPUP_KEYS, Defaults.PREF_MORE_POPUP_KEYS)!!
Row {
TextButton(onClick = { showMorePopupsDialog = true }, Modifier.weight(1f))
{ Text(stringResource(morePopupKeysResId(value))) }
DefaultButton(explicitValue == null) {
setCurrentSubtype(currentSubtype.without(ExtraValue.MORE_POPUPS))
}
}
}
}
if (hasLocalizedNumberRow(currentSubtype.locale, ctx)) {
Row(verticalAlignment = Alignment.CenterVertically) {
val checked = currentSubtype.getExtraValueOf(ExtraValue.LOCALIZED_NUMBER_ROW)?.toBoolean()
Text(stringResource(R.string.localized_number_row), Modifier.weight(1f))
Switch(
checked = checked ?: prefs.getBoolean(Settings.PREF_LOCALIZED_NUMBER_ROW, Defaults.PREF_LOCALIZED_NUMBER_ROW),
onCheckedChange = {
setCurrentSubtype(currentSubtype.with(ExtraValue.LOCALIZED_NUMBER_ROW, it.toString()))
}
)
DefaultButton(checked == null) {
setCurrentSubtype(currentSubtype.without(ExtraValue.LOCALIZED_NUMBER_ROW))
}
}
}
HorizontalDivider()
Text(stringResource(R.string.settings_screen_secondary_layouts), style = MaterialTheme.typography.titleMedium)
LayoutType.entries.forEach { type ->
if (type == LayoutType.MAIN) return@forEach
WithSmallTitle(stringResource(type.displayNameId)) {
val explicitLayout = currentSubtype.layoutName(type)
val layout = explicitLayout ?: Settings.readDefaultLayoutName(type, prefs)
val defaultLayouts = LayoutUtils.getAvailableLayouts(type, ctx)
val customLayouts = LayoutUtilsCustom.getLayoutFiles(type, ctx).map { it.name }
DropDownField(
items = defaultLayouts + customLayouts,
selectedItem = layout,
onSelected = {
setCurrentSubtype(currentSubtype.withLayout(type, it))
},
extraButton = { DefaultButton(explicitLayout == null) {
setCurrentSubtype(currentSubtype.withoutLayout(type))
} },
) {
val displayName = if (LayoutUtilsCustom.isCustomLayout(it)) LayoutUtilsCustom.getDisplayName(it)
else it.getStringResourceOrName("layout_", ctx)
var showLayoutEditDialog by remember { mutableStateOf(false) }
Row(
horizontalArrangement = Arrangement.SpaceBetween,
modifier = Modifier.fillMaxWidth()
) {
Text(displayName, Modifier.padding(end = 8.dp))
if (LayoutUtilsCustom.isCustomLayout(it))
Icon(painterResource(R.drawable.ic_edit), stringResource(R.string.edit_layout), Modifier.clickable { showLayoutEditDialog = true })
}
if (showLayoutEditDialog)
LayoutEditDialog(
onDismissRequest = { showLayoutEditDialog = false },
layoutType = type,
initialLayoutName = it,
isNameValid = null
)
}
}
}
}
)
}
if (showSecondaryLocaleDialog)
MultiListPickerDialog(
onDismissRequest = { showSecondaryLocaleDialog = false },
@ -294,6 +306,7 @@ fun SubtypeDialog(
}
}
// from ReorderSwitchPreference
@Composable
private fun PopupOrderDialog(
@ -336,7 +349,6 @@ private fun PopupOrderDialog(
@Composable
private fun MainLayoutRow(
initialSubtype: SettingsSubtype,
currentSubtype: SettingsSubtype,
customLayouts: List<String>,
setCurrentSubtype: (SettingsSubtype) -> Unit,
@ -369,13 +381,13 @@ private fun MainLayoutRow(
Text(SubtypeLocaleUtils.getDisplayNameInSystemLocale(it, currentSubtype.locale))
Row (verticalAlignment = Alignment.CenterVertically) {
Icon(painterResource(R.drawable.ic_edit), stringResource(R.string.edit_layout), Modifier.clickable { showLayoutEditDialog = it to null })
if (it in customLayouts && initialSubtype.mainLayoutName() != it) // don't allow current main layout
if (it in customLayouts && currentSubtype.mainLayoutName() != it) // don't allow current main layout // todo: this was initialSubtype, maybe needs adjustment now
Icon(painterResource(R.drawable.ic_bin), stringResource(R.string.delete), Modifier.clickable { showLayoutDeleteDialog = true })
}
}
if (showLayoutDeleteDialog) {
val others = SubtypeSettings.getAdditionalSubtypes().filter { st -> st.mainLayoutName() == it }
.any { it.toSettingsSubtype() != initialSubtype }
.any { it.toSettingsSubtype() != currentSubtype } // todo: this was initialSubtype, maybe needs adjustment now
ConfirmationDialog(
onDismissRequest = { showLayoutDeleteDialog = false },
confirmButtonText = stringResource(R.string.delete),
@ -442,11 +454,14 @@ private fun MainLayoutRow(
private fun getAvailableSecondaryLocales(context: Context, mainLocale: Locale): List<Locale> =
getDictionaryLocales(context).filter { it != mainLocale && it.script() == mainLocale.script() }
@Preview
@Composable
private fun Preview() {
initPreview(LocalContext.current)
Theme(previewDark) {
SubtypeDialog({}, SettingsSubtype(Locale.ENGLISH, "")) { }
Surface {
SubtypeScreen(SettingsSubtype(Locale.ENGLISH, "")) { }
}
}
}

View file

@ -22,6 +22,7 @@ import helium314.keyboard.latin.R
import helium314.keyboard.latin.permissions.PermissionsUtil
import helium314.keyboard.latin.settings.Defaults
import helium314.keyboard.latin.settings.Settings
import helium314.keyboard.latin.utils.JniUtils
import helium314.keyboard.latin.utils.Log
import helium314.keyboard.latin.utils.getActivity
import helium314.keyboard.latin.utils.prefs
@ -49,6 +50,7 @@ fun TextCorrectionScreen(
Log.v("irrelevant", "stupid way to trigger recomposition on preference change")
val autocorrectEnabled = prefs.getBoolean(Settings.PREF_AUTO_CORRECTION, Defaults.PREF_AUTO_CORRECTION)
val suggestionsEnabled = prefs.getBoolean(Settings.PREF_SHOW_SUGGESTIONS, Defaults.PREF_SHOW_SUGGESTIONS)
val gestureEnabled = JniUtils.sHaveGestureLib && prefs.getBoolean(Settings.PREF_GESTURE_INPUT, Defaults.PREF_GESTURE_INPUT)
val items = listOf(
SettingsWithoutKey.EDIT_PERSONAL_DICTIONARY,
R.string.settings_category_correction,
@ -57,12 +59,20 @@ fun TextCorrectionScreen(
if (autocorrectEnabled) Settings.PREF_MORE_AUTO_CORRECTION else null,
if (autocorrectEnabled) Settings.PREF_AUTOCORRECT_SHORTCUTS else null,
if (autocorrectEnabled) Settings.PREF_AUTO_CORRECT_THRESHOLD else null,
if (autocorrectEnabled) Settings.PREF_BACKSPACE_REVERTS_AUTOCORRECT else null,
Settings.PREF_AUTO_CAP,
R.string.settings_category_space,
Settings.PREF_KEY_USE_DOUBLE_SPACE_PERIOD,
Settings.PREF_AUTOSPACE_AFTER_PUNCTUATION,
Settings.PREF_AUTOSPACE_AFTER_SUGGESTION,
if (gestureEnabled) Settings.PREF_AUTOSPACE_BEFORE_GESTURE_TYPING else null,
if (gestureEnabled) Settings.PREF_AUTOSPACE_AFTER_GESTURE_TYPING else null,
Settings.PREF_SHIFT_REMOVES_AUTOSPACE,
R.string.settings_category_suggestions,
Settings.PREF_SHOW_SUGGESTIONS,
if (suggestionsEnabled) Settings.PREF_ALWAYS_SHOW_SUGGESTIONS else null,
if (suggestionsEnabled && prefs.getBoolean(Settings.PREF_ALWAYS_SHOW_SUGGESTIONS, Defaults.PREF_ALWAYS_SHOW_SUGGESTIONS))
Settings.PREF_ALWAYS_SHOW_SUGGESTIONS_EXCEPT_WEB_TEXT else null,
if (suggestionsEnabled) Settings.PREF_CENTER_SUGGESTION_TEXT_TO_ENTER else null,
Settings.PREF_KEY_USE_PERSONALIZED_DICTS,
Settings.PREF_BIGRAM_PREDICTIONS,
@ -114,6 +124,9 @@ fun createCorrectionSettings(context: Context) = listOf(
// todo: consider making it a slider, and maybe somehow adjust range so we can show %
ListPreference(it, items, Defaults.PREF_AUTO_CORRECT_THRESHOLD)
},
Setting(context, Settings.PREF_BACKSPACE_REVERTS_AUTOCORRECT, R.string.backspace_reverts_autocorrect) {
SwitchPreference(it, Defaults.PREF_BACKSPACE_REVERTS_AUTOCORRECT)
},
Setting(context, Settings.PREF_AUTO_CAP,
R.string.auto_cap, R.string.auto_cap_summary
) {
@ -129,6 +142,18 @@ fun createCorrectionSettings(context: Context) = listOf(
) {
SwitchPreference(it, Defaults.PREF_AUTOSPACE_AFTER_PUNCTUATION)
},
Setting(context, Settings.PREF_AUTOSPACE_AFTER_SUGGESTION, R.string.autospace_after_suggestion) {
SwitchPreference(it, Defaults.PREF_AUTOSPACE_AFTER_SUGGESTION)
},
Setting(context, Settings.PREF_AUTOSPACE_AFTER_GESTURE_TYPING, R.string.autospace_after_gesture_typing) {
SwitchPreference(it, Defaults.PREF_AUTOSPACE_AFTER_GESTURE_TYPING)
},
Setting(context, Settings.PREF_AUTOSPACE_BEFORE_GESTURE_TYPING, R.string.autospace_before_gesture_typing) {
SwitchPreference(it, Defaults.PREF_AUTOSPACE_BEFORE_GESTURE_TYPING)
},
Setting(context, Settings.PREF_SHIFT_REMOVES_AUTOSPACE, R.string.shift_removes_autospace, R.string.shift_removes_autospace_summary) {
SwitchPreference(it, Defaults.PREF_SHIFT_REMOVES_AUTOSPACE)
},
Setting(context, Settings.PREF_SHOW_SUGGESTIONS,
R.string.prefs_show_suggestions, R.string.prefs_show_suggestions_summary
) {
@ -139,6 +164,11 @@ fun createCorrectionSettings(context: Context) = listOf(
) {
SwitchPreference(it, Defaults.PREF_ALWAYS_SHOW_SUGGESTIONS)
},
Setting(context, Settings.PREF_ALWAYS_SHOW_SUGGESTIONS_EXCEPT_WEB_TEXT,
R.string.prefs_always_show_suggestions_except_web_text, R.string.prefs_always_show_suggestions_except_web_text_summary
) {
SwitchPreference(it, Defaults.PREF_ALWAYS_SHOW_SUGGESTIONS_EXCEPT_WEB_TEXT)
},
Setting(context, Settings.PREF_KEY_USE_PERSONALIZED_DICTS,
R.string.use_personalized_dicts, R.string.use_personalized_dicts_summary
) { setting ->

View file

@ -8,8 +8,7 @@
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?attr/colorControlNormal">
android:viewportHeight="960">
<path android:fillColor="#FFF"
android:pathData="M200,840Q167,840 143.5,816.5Q120,793 120,760L120,200Q120,167 143.5,143.5Q167,120 200,120L367,120Q378,85 410,62.5Q442,40 480,40Q520,40 551.5,62.5Q583,85 594,120L760,120Q793,120 816.5,143.5Q840,167 840,200L840,760Q840,793 816.5,816.5Q793,840 760,840L200,840ZM200,760L760,760Q760,760 760,760Q760,760 760,760L760,200Q760,200 760,200Q760,200 760,200L680,200L680,280Q680,297 668.5,308.5Q657,320 640,320L320,320Q303,320 291.5,308.5Q280,297 280,280L280,200L200,200Q200,200 200,200Q200,200 200,200L200,760Q200,760 200,760Q200,760 200,760ZM480,200Q497,200 508.5,188.5Q520,177 520,160Q520,143 508.5,131.5Q497,120 480,120Q463,120 451.5,131.5Q440,143 440,160Q440,177 451.5,188.5Q463,200 480,200Z"/>
</vector>

View file

@ -75,16 +75,16 @@
<string name="prefs_enable_emoji_alt_physical_key">"الرموز التعبيرية للوحة مفاتيح فعلية"</string>
<string name="prefs_enable_emoji_alt_physical_key_summary">"‏مفتاح Alt الفعلي يعرض لوحة الرموز التعبيرية"</string>
<string name="button_default">"التلقائية"</string>
<string name="setup_welcome_title">مرحبًا بكم في<xliff:g id="APPLICATION_NAME" مثال="لوحة مفاتيح أندرويد">%s</xliff:g></string>
<string name="setup_welcome_title">مرحبًا بكم في <xliff:g id="APPLICATION_NAME" مثال="لوحة مفاتيح أندرويد">%s</xliff:g></string>
<string name="setup_welcome_additional_description">مع الكتابة بالإيماءة</string>
<string name="setup_start_action">"بدء الاستخدام"</string>
<string name="setup_next_action">"الخطوة التالية"</string>
<string name="setup_steps_title">قيد الإعداد<xliff:g id="APPLICATION_NAME" مثال="لوحة مفاتيح أندرويد">%s</xliff:g></string>
<string name="setup_step1_title">مكِّن<xliff:g id="APPLICATION_NAME" مثال="لوحة مفاتيح أندرويد">%s</xliff:g></string>
<string name="setup_steps_title">قيد الإعداد <xliff:g id="APPLICATION_NAME" مثال="لوحة مفاتيح أندرويد">%s</xliff:g></string>
<string name="setup_step1_title">مكِّن <xliff:g id="APPLICATION_NAME" مثال="لوحة مفاتيح أندرويد">%s</xliff:g></string>
<string name="setup_step1_instruction">يرجى التحقق من \\<xliff:g id="APPLICATION_NAME" مثال="لوحة مفاتيح أندرويد">%s</xliff:g>\" في إعدادات الإدخال واللغات. سيؤدي ذلك إلى تمكين لوحة المفاتيح على جهازك.\"</string>
<string name="setup_step1_finished_instruction">&lt;xliff:g id=\"APPLICATION_NAME\" مثال=\"لوحة مفاتيح أندرويد\"&gt;%s&lt;/xliff:g&gt; ممكّن بالفعل في إعدادات اللغات &amp;amp؛ إعدادات الإدخال، لذا فقد تم الانتهاء من هذه الخطوة. إلى الخطوة التالية!\"</string>
<string name="setup_step1_action">"تفعيل في الإعدادات"</string>
<string name="setup_step2_title">قم بالتبديل إلى<xliff:g id="APPLICATION_NAME" مثال="لوحة مفاتيح أندرويد">%s</xliff:g></string>
<string name="setup_step2_title">بدّل إلى <xliff:g id="APPLICATION_NAME" مثال="لوحة مفاتيح أندرويد">%s</xliff:g></string>
<string name="setup_step2_instruction">بعد ذلك، اختر \\&lt;&lt;xliff:g id=\"APPLICATION_NAME\" مثال=\"لوحة مفاتيح أندرويد\"&gt;%s&lt;/xliff:g&gt;” كطريقة إدخال النص النشط.“</string>
<string name="setup_step2_action">"تبديل أساليب الإدخال"</string>
<string name="setup_step3_title">تهانينا ، لقد انتهيت من الإعداد!</string>
@ -247,10 +247,10 @@
<string name="layout_symbols" tools:keep="@string/layout_symbols">الرموز</string>
<string name="layout_symbols_arabic" tools:keep="@string/layout_symbols_arabic">الرموز(العربية)</string>
<string name="layout_number" tools:keep="@string/layout_number">ارقام</string>
<string name="layout_numpad" tools:keep="@string/layout_numpad">لوحة ارقام</string>
<string name="layout_numpad" tools:keep="@string/layout_numpad">لوحة الأرقام</string>
<string name="layout_phone" tools:keep="@string/layout_phone">الهاتف</string>
<string name="layout_phone_symbols" tools:keep="@string/layout_phone_symbols">رموز الهاتف</string>
<string name="layout_numpad_landscape" tools:keep="@string/layout_numpad_landscape">لوحة رقمية (أفقي)</string>
<string name="layout_numpad_landscape" tools:keep="@string/layout_numpad_landscape">لوحة الأرقام (أفقي)</string>
<string name="remove_dictionary_message">هل تريد حقًا إزالة القاموس الذي أضافه المستخدم \"%s\"؟</string>
<string name="dictionary_file_error">خطأ: الملف المحدد ليس ملف قاموس صالح</string>
<string name="theme_name_black" tools:keep="@string/theme_name_black">اسود</string>
@ -472,4 +472,9 @@
<string name="locales_with_dict">اللغات مع القواميس</string>
<string name="get_layouts_message">يمكنك العثور على المخططات ومشاركتها في %s.</string>
<string name="discussion_section_link">قسم المناقشة</string>
<string name="custom_subtype">نوع فرعي مخصّص</string>
<string name="subtype_baishakhi_bn_IN"><xliff:g id="LANGUAGE_NAME" example="Bengali">%s</xliff:g> (Baishakhi)</string>
<string name="show_tld_popup_keys">أظهِر مفاتيح TLD المنبثقة</string>
<string name="show_tld_popup_keys_summary">استبدل مفتاح الفترة المنبثقة مع مجالات المستوى الأعلى عند كتابة عناوين URL وعناوين البريد الإلكتروني</string>
<string name="after_numpad_and_space">الضغط على إدخال أو مساحة بعد مفاتيح أخرى في لوحة الأرقام</string>
</resources>

View file

@ -370,5 +370,64 @@
<string name="space_swipe_toggle_numpad_entry">Пераключыць лічбавую клавіятуру</string>
<string name="show_popup_keys_main">Дадаць самыя распаўсюджаныя варыянты (па змаўчанні)</string>
<string name="remove_redundant_popups">Выдаліць лішнія ўсплывальныя вокны</string>
<string name="remove_redundant_popups_summary">Прыбраць усплывальныя клавішы, якія прысутнічаюць у базавай раскладцы</string>
<string name="remove_redundant_popups_summary">Прыбраць усплывальныя клавішы, якія ўжо прысутнічаюць у базавай раскладцы</string>
<string name="gesture_floating_preview_static">Плаваючы прадпрагляд</string>
<string name="gesture_floating_preview_static_summary">Бачыць прапанаванае слова падчас набору жэстамі</string>
<string name="split" tools:keep="@string/split">Раздзельная клавіятура</string>
<string name="vibrate_in_dnd_mode">Вібрацыя ў рэжыме «Не турбаваць»</string>
<string name="enable_split_keyboard_landscape">Уключыць падзеленую клавіятуру (альбомная)</string>
<string name="split_spacer_scale_landscape">Адлегласць падзелу (альбомная)</string>
<string name="gesture_floating_preview_dynamic_summary">Перамяшчаць прадпрагляд падчас набору жэстамі</string>
<string name="gesture_trail_fadeout_duration">Час жыцця следа жэста</string>
<string name="auto_correct_shortcuts">Аўтакарэкцыя спалучэнняў клавіш</string>
<string name="auto_correct_shortcuts_summary">Калі ўключана, спалучэнні клавіш могуць быць пашыраны з дапамогай аўтакарэкцыі</string>
<string name="prefs_bottom_padding_scale_landscape">Маштаб ніжняга водступу (альбомная)</string>
<string name="prefs_side_padding_scale">Маштаб бакавога водступу</string>
<string name="number_row_hints">Паказваць падказкі ў шэрагу з лічбамі</string>
<string name="locales_with_dict">Мовы са слоўнікамі</string>
<string name="custom_subtype">Карыстацкі падтып</string>
<string name="layout_emoji_bottom_row" tools:keep="@string/layout_emoji_bottom_row">Радок эмодзі ўнізе</string>
<string name="layout_clip_bottom_row" tools:keep="@string/layout_clip_bottom_row">Радок буфера абмену ўнізе</string>
<string name="layout_in_use">Папярэджанне: раскладка ў дадзены момант выкарыстоўваецца</string>
<string name="customize_icons">Наладзіць значкі</string>
<string name="customize_icons_reset_message">Сапраўды скінуць усе настроеныя значкі?</string>
<string name="layout_number_row" tools:keep="@string/layout_number_row">Шэраг з лічбамі</string>
<string name="customize_background_image_landscape">Усталяваць фонавы малюнак (альбомная)</string>
<string name="prefs_key_emoji_max_sdk">Перавызначыць версію эмодзі</string>
<string name="subtype_dru">Даргінскі (Урахі)</string>
<string name="subtype_with_layout_dru" tools:keep="@string/subtype_with_layout_dru">Урахінскі (<xliff:g id="KEYBOARD_LAYOUT" example="QWERTY">%s</xliff:g>)</string>
<string name="key_code">Код клавішы</string>
<string name="delete_confirmation">Сапраўды выдаліць %s?</string>
<string name="custom_font">Усталяваць карыстацкі шрыфт з файла</string>
<string name="summary_customize_background_image_landscape">Калі не ўстаноўлена, будзе выкарыстоўвацца партрэтны малюнак</string>
<string name="label_zwnj_key" tools:keep="@string/label_zwnj_key">Раз\'яднальнік нулявой шырыні</string>
<string name="customize_toolbar_key_code_reset_message">Вы сапраўды хочаце выдаліць усе настроеныя коды клавіш?</string>
<string name="settings_screen_secondary_layouts">Дадатковыя раскладкі</string>
<string name="layout_functional_keys_tablet" tools:keep="@string/layout_functional_keys_tablet">Функцыянальныя клавішы (вялікі экран)</string>
<string name="icon_style">Стыль значкоў</string>
<string name="label_zwj_key" tools:keep="@string/label_zwj_key">Злучальнік нулявой шырыні</string>
<string name="label_bin" tools:keep="@string/label_bin">Сметніца</string>
<string name="name_invalid">Недапушчальнае імя</string>
<string name="label_delete_key" tools:keep="@string/label_delete_key">Выдаліць</string>
<string name="label_enter_key" tools:keep="@string/label_enter_key">Увод</string>
<string name="label_shift_key" tools:keep="@string/label_shift_key">Shift</string>
<string name="label_tab_key" tools:keep="@string/label_tab_key">Табуляцыя</string>
<string name="label_shift_key_shifted" tools:keep="@string/label_shift_key_shifted">Shift (націснута)</string>
<string name="prefs_font_scale">Маштаб шрыфта клавіятуры</string>
<string name="prefs_emoji_font_scale">Маштаб шрыфта адлюстравання эмодзі</string>
<string name="prefs_side_padding_scale_landscape">Маштаб бакавога водступу (альбомная)</string>
<string name="long_press_code">Код доўгага націску</string>
<string name="prefs_language_swipe_distance">Адлегласць змахвання для пераключэння мовы</string>
<string name="customize_toolbar_key_codes">Наладзіць коды клавіш панэлі інструментаў</string>
<string name="prefs_space_bar_text">Карыстацкі тэкст на клавішы прабела</string>
<string name="label_space_key_for_number_layout" tools:keep="@string/label_space_key_for_number_layout">Прабел (раскладка лічбаў)</string>
<string name="label_switch_onehanded_key" tools:keep="@string/label_switch_onehanded_key">Пераключыць бок рэжыму адной рукой</string>
<string name="get_colors_message">Знайсці і падзяліцца колерамі ў %s.</string>
<string name="get_layouts_message">Знайсці і падзяліцца раскладкамі ў %s.</string>
<string name="discussion_section_link">абмеркавання</string>
<string name="label_shift_key_locked" tools:keep="@string/label_shift_key_locked">Caps lock</string>
<string name="label_stop_onehanded_mode_key" tools:keep="@string/label_stop_onehanded_mode_key">Завяршыць рэжым адной рукой</string>
<string name="label_resize_onehanded_key" tools:keep="@string/label_resize_onehanded_key">Змяніць памер у рэжыме адной рукой</string>
<string name="label_shortcut_key_disabled" tools:keep="@string/label_shortcut_key_disabled">Галасавы ўвод адключаны</string>
<string name="label_toolbar_key" tools:keep="@string/label_toolbar_key">Паказаць / схаваць панэль інструментаў</string>
</resources>

View file

@ -467,4 +467,10 @@
<string name="get_colors_message">Можете да намирате и споделяте цветове в %s.</string>
<string name="custom_subtype">Персонализиран подтип</string>
<string name="subtype_baishakhi_bn_IN"><xliff:g id="LANGUAGE_NAME" example="Бенгалски">%s</xliff:g> (Байсахи)</string>
<string name="show_tld_popup_keys">Показване на TLD изскачащи клавиши</string>
<string name="show_tld_popup_keys_summary">Заместване на изскачащите прозорци с клавиши за период с домейни от първо ниво при въвеждане на URL и имейл адреси</string>
<string name="after_numpad_and_space">Натискане на въвеждане или интервал след други клавиши в цифровата клавиатура</string>
<string name="prefs_always_show_suggestions_except_web_text">Не винаги показвай предложения за полета за уеб редактиране</string>
<string name="prefs_always_show_suggestions_except_web_text_summary">Полетата за уеб редактиране (най-вече в браузърите) са много честа причина за проблеми с настройката за винаги показване на предложения</string>
<string name="layout_number_row_basic" tools:keep="@string/layout_number_row_basic">Числов ред (основен)</string>
</resources>

File diff suppressed because one or more lines are too long

View file

@ -430,4 +430,10 @@
<string name="get_colors_message">Podeu trobar i compartir colors a %s.</string>
<string name="get_layouts_message">Podeu trobar i compartir disposicions a %s.</string>
<string name="discussion_section_link">secció de discussió</string>
<string name="show_tld_popup_keys_summary">Substituir les finestres emergents de la tecla punt per dominis de primer nivell en escriure URLs i adreces de correu electrònic</string>
<string name="show_tld_popup_keys">Mostra tecles emergents de TLD</string>
<string name="after_numpad_and_space">Prement Intro o espai després d\'altres tecles del teclat numèric</string>
<string name="prefs_always_show_suggestions_except_web_text_summary">Els camps d\'edició web (sobretot que es troben als navegadors) són una causa molt freqüent de problemes amb la configuració Mostrar sempre suggeriments</string>
<string name="layout_number_row_basic" tools:keep="@string/layout_number_row_basic">Fila de nombres (bàsic)</string>
<string name="prefs_always_show_suggestions_except_web_text">No mostrar sempre suggeriments per als camps d\'edició web</string>
</resources>

View file

@ -432,4 +432,11 @@
<string name="delete_confirmation">%s wirklich löschen?</string>
<string name="name_invalid">Ungültiger Name</string>
<string name="custom_subtype">Benutzerdefinierter Subtyp</string>
<string name="subtype_baishakhi_bn_IN"><xliff:g id="LANGUAGE_NAME" example="Bengalisch">%s</xliff:g> (Baisakhi)</string>
<string name="show_tld_popup_keys">Zeige TLD-Popup-Tasten</string>
<string name="show_tld_popup_keys_summary">Ersetze Punkt-Tastenpopups mit Top-Level-Domains wenn URLs und Mailadressen eingegeben werden</string>
<string name="prefs_always_show_suggestions_except_web_text">Nicht immer Vorschläge für Web-Editierfelder anzeigen</string>
<string name="layout_number_row_basic" tools:keep="@string/layout_number_row_basic">Zahlenreihe (Basis)</string>
<string name="prefs_always_show_suggestions_except_web_text_summary">Web-Eingabefelder (meist in Browsern) sind eine häufige Ursache für Probleme mit der Einstellung \"Immer Vorschläge anzeigen\"</string>
<string name="after_numpad_and_space">Drücken der Eingabetaste oder der Leertaste nach anderen Tasten im Ziffernblock</string>
</resources>

View file

@ -467,4 +467,10 @@
<string name="get_colors_message">Uusi värve võid leida ja jagada %s.</string>
<string name="custom_subtype">Sinu loodud alamtüüp</string>
<string name="subtype_baishakhi_bn_IN"><xliff:g id="LANGUAGE_NAME" example="Bengali">%s</xliff:g> (Baishakhi)</string>
<string name="show_tld_popup_keys">Näita tippdomeenide hüpikklahve</string>
<string name="show_tld_popup_keys_summary">Võrgu- ja e-posti aadresside kirjutamisel asenda punktuatsiooni hüpikaknad tipptaseme domeenide omadega</string>
<string name="after_numpad_and_space">Vajutades numbriklahvistikus peale muud sisestust tühiku- või sisestusklahvi</string>
<string name="layout_number_row_basic" tools:keep="@string/layout_number_row_basic">Numbririda (lihtne)</string>
<string name="prefs_always_show_suggestions_except_web_text">Ära alati näita sisestuse soovitusi täites veebivormide välju</string>
<string name="prefs_always_show_suggestions_except_web_text_summary">Kui alati näitad sisestuse soovitusi veebivormide väljadel (nii nagu sa neid veebibrauseris näed), siis võib sellest tekkida probleeme</string>
</resources>

View file

@ -437,4 +437,10 @@ Nouveau dictionnaire:
<string name="get_colors_message">Vous pouvez trouver et partager des couleurs dans le %s.</string>
<string name="get_layouts_message">Vous pouvez trouver et partager des dispositions dans le %s.</string>
<string name="discussion_section_link">Section de discussion</string>
<string name="show_tld_popup_keys">Afficher les suggestions de domaines (TLD)</string>
<string name="show_tld_popup_keys_summary">Remplacer les suggestions de la touche point par des extensions de domaine (TLD) lors de la saisie dURL ou dadresses e-mail</string>
<string name="after_numpad_and_space">Appuyer sur Entrée ou sur la barre d\'espace après d\'autres touches du pavé numérique</string>
<string name="prefs_always_show_suggestions_except_web_text_summary">Les champs d\'édition Web (principalement présents dans les navigateurs) sont une cause très courante de problèmes avec le paramètre « Toujours afficher les suggestions »</string>
<string name="layout_number_row_basic" tools:keep="@string/layout_number_row_basic">Rangée numérique (standard)</string>
<string name="prefs_always_show_suggestions_except_web_text">Ne pas forcer l\'affichage des suggestions pour les champs de saisie web</string>
</resources>

View file

@ -434,4 +434,16 @@
<string name="discussion_section_link">zona de conversa</string>
<string name="get_layouts_message">Podes atopar e compartir disposicións na %s.</string>
<string name="subtype_baishakhi_bn_IN"><xliff:g id="LANGUAGE_NAME" example="Bengali">%s</xliff:g> (Baishakhi)</string>
<string name="custom_subtype">Subtipo personalizado</string>
<string name="prefs_always_show_suggestions_except_web_text">Non mostrar sempre suxestións para os campos texto nas webs</string>
<string name="prefs_always_show_suggestions_except_web_text_summary">Os campos de texto nas webs (principalmente no navegador) son causa frecuente de problemas coas suxestións automáticas</string>
<string name="layout_number_row_basic" tools:keep="@string/layout_number_row_basic">Fila de números (básica)</string>
<string name="show_tld_popup_keys_summary">Substitúe na emerxente da tecla do punto con dominios de alto nivel ao escribir URL e enderezos de correo</string>
<string name="show_tld_popup_keys">Mostrar teclas emerxentes TLD</string>
<string name="after_numpad_and_space">Ao premer enter ou espazo após escribir no teclado numérico</string>
<string name="label_zwnj_key" tools:keep="@string/label_zwnj_key">caracter separador ancho cero</string>
<string name="delete_confirmation">Eliminar %s?</string>
<string name="customize_toolbar_key_code_reset_message">Tes certeza de querer limpar todos os códigos personalizados?</string>
<string name="name_invalid">Nome non válido</string>
<string name="prefs_language_swipe_distance">Distancia de desprazamento cambio de idioma</string>
</resources>

View file

@ -104,7 +104,7 @@
<string name="user_dict_settings_add_shortcut_option_name">"Scorciatoia:"</string>
<string name="user_dict_settings_add_locale_option_name">"Lingua:"</string>
<string name="user_dict_settings_add_word_hint">"Digita una parola"</string>
<string name="user_dict_settings_add_shortcut_hint">"Scorciatoia facoltativa"</string>
<string name="user_dict_settings_add_shortcut_hint">Scorciatoia (opzionale)</string>
<string name="user_dict_settings_edit_dialog_title">"Modifica parola"</string>
<string name="user_dict_settings_empty_text">Il dizionario utente è vuoto. Premi \'Aggiungi\' (+) per aggiungere manualmente una parola.</string>
<string name="user_dict_settings_all_languages">"Per tutte le lingue"</string>
@ -304,7 +304,7 @@
<string name="dictionary_file_wrong_locale">Il dizionario è stato creato per la lingua %1$s, ma lo stai aggiungendo a %2$s. Confermi?</string>
<string name="dialog_close">Chiudi</string>
<string name="select_color_gesture">Traccia dell\'input gestuale</string>
<string name="text_tap_languages">Tocca la lingua per aprire le impostazioni</string>
<string name="text_tap_languages">Lingua: tap → impostazioni</string>
<string name="save_log">Salva log</string>
<string name="theme_name_holo_white" tools:keep="@string/theme_name_holo_white">Holo bianco</string>
<string name="internal_dictionary_summary">Dizionario interno principale</string>
@ -432,4 +432,17 @@
<string name="auto_correct_shortcuts">Scorciatoie correzione</string>
<string name="name_invalid">Nome non valido</string>
<string name="prefs_language_swipe_distance">Distanza del trascinamento per il cambio lingua</string>
<string name="custom_subtype">Sotto-tipo personalizzato</string>
<string name="subtype_baishakhi_bn_IN"><xliff:g id="LANGUAGE_NAME" example="Bengalese">%s</xliff:g> (Baishakhi)</string>
<string name="layout_in_use">Attenzione: il layout è in uso</string>
<string name="locales_with_dict">Lingue con dizionari</string>
<string name="discussion_section_link">discussione dedicata</string>
<string name="get_layouts_message">Scopri nuovi layout o condividi quelli che hai creato nella %s.</string>
<string name="get_colors_message">Scopri nuove combinazioni di colori o condividi le tue nella %s.</string>
<string name="show_tld_popup_keys">Mostra popup con TLD</string>
<string name="show_tld_popup_keys_summary">Sostituisce il popup standard del tasto . (punto) con desinenze TLD internazionali durante la digitazione di URL e email</string>
<string name="after_numpad_and_space">Dopo uno spazio o la pressione di ⏎ (invio) dal tastierino numerico</string>
<string name="prefs_always_show_suggestions_except_web_text">Non forzare i suggerimenti in tutti i campi di testo</string>
<string name="prefs_always_show_suggestions_except_web_text_summary">I campi di testo Web (specie all\'interno dei browser) sono una causa ricorrente di problemi con i suggerimenti sempre attivi</string>
<string name="layout_number_row_basic" tools:keep="@string/layout_number_row_basic">Barra dei numeri (base)</string>
</resources>

View file

@ -208,7 +208,7 @@
<string name="toolbar_keys">בחירת כפתורי סרגל הכלים</string>
<string name="prefs_narrow_key_gaps">מרווחי קלידים צרים</string>
<string name="localized_number_row">תרגום number row</string>
<string name="popup_keys_number" tools:keep="@string/popup_keys_number">שורת המספרים</string>
<string name="popup_keys_number" tools:keep="@string/popup_keys_number">שורת מספרים</string>
<string name="popup_keys_language" tools:keep="@string/popup_keys_language">שפה</string>
<string name="popup_keys_language_priority" tools:keep="@string/popup_keys_language_priority">שפה (עדיפות)</string>
<string name="popup_keys_layout" tools:keep="@string/popup_keys_layout">פריסה</string>
@ -439,4 +439,10 @@
<string name="get_colors_message">באפשרותך למצוא ולשתף צבעים ב %s.</string>
<string name="get_layouts_message">באפשרותך למצוא ולשתף פריסות ב %s.</string>
<string name="discussion_section_link">מקטע הדיונים</string>
<string name="show_tld_popup_keys">הצגת חלון צץ של סיומות אינטרנט</string>
<string name="show_tld_popup_keys_summary">החלפת חלון צץ של מקש נקודה ברשימת סיומות אינטרנט נפוצות בעת הקלדת כתובות אינטרנט ודוא\"ל</string>
<string name="after_numpad_and_space">לאחר לחיצת Enter או רווח לאחר מקשים אחרים במקלדת המספרים</string>
<string name="prefs_always_show_suggestions_except_web_text">לא תמיד להציג הצעות לשדות עריכה ב-Web</string>
<string name="prefs_always_show_suggestions_except_web_text_summary">שדות עריכה ב-Web (בדר\"כ יוצגו בדפדפן) הם גורם נפוץ מאד לבעיות בהגדרה \'הצגת הצעות תמיד\'</string>
<string name="layout_number_row_basic" tools:keep="@string/layout_number_row_basic">שורת המספרים (פריסת בסיס)</string>
</resources>

View file

@ -476,4 +476,10 @@
<string name="get_layouts_message">Je kunt lay-outs zoeken en delen in de %s.</string>
<string name="discussion_section_link">discussiesectie</string>
<string name="subtype_baishakhi_bn_IN"><xliff:g id="LANGUAGE_NAME" example="Bengali">%s</xliff:g> (Baishakhi)</string>
<string name="show_tld_popup_keys">TLD-opties weergeven</string>
<string name="show_tld_popup_keys_summary">Vervang pop-ups met interpunctie door topleveldomeinen bij het typen van URL\'s en e-mailadressen</string>
<string name="after_numpad_and_space">Druk op enter of spatie na andere toetsen in het numpad</string>
<string name="layout_number_row_basic" tools:keep="@string/layout_number_row_basic">Cijferregel (basis)</string>
<string name="prefs_always_show_suggestions_except_web_text">Suggesties voor webbewerkingsvelden niet altijd weergeven</string>
<string name="prefs_always_show_suggestions_except_web_text_summary">Webbewerkingsvelden (meestal te vinden in browsers) zijn een veel voorkomende oorzaak van problemen met de instelling Altijd suggesties weergeven</string>
</resources>

View file

@ -94,7 +94,7 @@
<string name="show_setup_wizard_icon">"Pokaż ikonę aplikacji"</string>
<string name="show_setup_wizard_icon_summary">"Wyświetlaj ikonę aplikacji w programie uruchamiającym"</string>
<string name="dictionary_settings_title">"Słowniki dodatkowe"</string>
<string name="dictionary_available">"Słownik dostępny"</string>
<string name="dictionary_available">Dostępny słownik</string>
<string name="no_dictionaries_available">"Brak słowników"</string>
<string name="last_update">"Ostatnia aktualizacja"</string>
<string name="settings">"Ustawienia"</string>
@ -174,13 +174,13 @@
<string name="restore_error">Błąd podczas przywracania kopii zapasowej: %s</string>
<string name="theme_colors">Kolory</string>
<string name="select_color_functional_key_background">Tło klawiszy funkcyjnych</string>
<string name="subtype_generic_sebeolsik_390"><xliff:g id="LANGUAGE_NAME" example="Koreański">%s</xliff:g> (Sebeolsik 390)</string>
<string name="subtype_generic_sebeolsik_390"><xliff:g id="LANGUAGE_NAME" example="koreański">%s</xliff:g> (Sebeolsik 390)</string>
<string name="add_to_personal_dictionary_summary">Używaj słownika osobistego do przechowywania nauczonych słów</string>
<string name="user_dict_word_already_present">To słowo znajduje się już w słowniku: %s. Wpisz inne.</string>
<string name="style_name_Rounded" tools:keep="@string/style_name_Rounded">Zaokrąglony</string>
<string name="button_backup">Kopia</string>
<string name="theme_name_black" tools:keep="@string/theme_name_black">Czarne</string>
<string name="subtype_generic_sebeolsik_final"><xliff:g id="LANGUAGE_NAME" example="Koreański">%s</xliff:g> (Sebeolsik Final)</string>
<string name="subtype_generic_sebeolsik_final"><xliff:g id="LANGUAGE_NAME" example="koreański">%s</xliff:g> (Sebeolsik Final)</string>
<string name="theme_name_chocolate" tools:keep="@string/theme_name_chocolate">Czekoladowe</string>
<string name="remove_dictionary_message">Na pewno usunąć słownik \"%s\" dodany przez użytkownika?</string>
<string name="theme_name_cloudy" tools:keep="@string/theme_name_cloudy">Pochmurne</string>
@ -195,7 +195,7 @@
<string name="theme_name_pink" tools:keep="@string/theme_name_pink">Różowe</string>
<string name="language_and_layouts_title">Języki i układy</string>
<string name="file_read_error">Nie można odczytać pliku</string>
<string name="dictionary_link_text">stąd</string>
<string name="dictionary_link_text">tutaj</string>
<string name="dictionary_file_error">Błąd: wybrany plik nie jest prawidłowym plikiem słownika</string>
<string name="hidden_features_text">chronionej pamięci urządzenia</string>
<string name="theme_navbar">Koloruj pasek nawigacyjny</string>
@ -360,7 +360,7 @@
<string name="show_vertical_space_swipe">Spacja - przesuwanie pionowe</string>
<string name="show_horizontal_space_swipe">Spacja - przesuwanie poziome</string>
<string name="space_swipe_move_cursor_entry">Przesuń kursor</string>
<string name="action_none">Brak przesuwania</string>
<string name="action_none">Brak</string>
<string name="var_toolbar_direction_summary">Odwróć kierunek po wybraniu układu klawiatury od prawej do lewej</string>
<string name="var_toolbar_direction">Zmienny kierunek paska narzędzi</string>
<string name="subtype_probhat_bn_BD"><xliff:g id="LANGUAGE_NAME" example="bengalski">%s</xliff:g> (Probhat)</string>
@ -392,7 +392,7 @@
<string name="emoji" tools:keep="@string/emoji">Emotikony</string>
<string name="customize_currencies_detail">Ustaw główny i do 6 drugorzędnych symboli waluty, oddzielonych spacją</string>
<string name="customize_currencies">Dostosuj waluty</string>
<string name="load">Załaduj</string>
<string name="load">Dodaj</string>
<string name="copy_to_clipboard">Skopiuj do schowka</string>
<string name="load_will_overwrite">Ładowanie spowoduje zastąpienie bieżącego motywu</string>
<string name="button_save_file">Zapisz do pliku</string>
@ -471,9 +471,13 @@
<string name="name_invalid">Nieprawidłowa nazwa</string>
<string name="locales_with_dict">Języki ze słownikami</string>
<string name="layout_in_use">Ostrzeżenie: ten układ jest aktualnie używany</string>
<string name="get_colors_message">Motywy możesz znaleźć i udostępnić w %s .</string>
<string name="get_layouts_message">Układy możesz znaleźć i udostępnić w %s .</string>
<string name="get_colors_message">Motywy możesz znaleźć i udostępnić w %s.</string>
<string name="get_layouts_message">Układy możesz znaleźć i udostępnić w %s.</string>
<string name="discussion_section_link">sekcji dyskusji</string>
<string name="custom_subtype">Własny podtyp</string>
<string name="custom_subtype">Własny układ</string>
<string name="subtype_baishakhi_bn_IN"><xliff:g id="LANGUAGE_NAME" example="bengalski">%s</xliff:g> (Baishakhi)</string>
<string name="show_tld_popup_keys">Pokaż wyskakujące okienka TLD</string>
<string name="show_tld_popup_keys_summary">Zastąp wyskakujące okienka klawisza kropki domenami najwyższego poziomu podczas wpisywania adresów URL i adresów e-mail</string>
<string name="after_numpad_and_space">Naciśnięciu enter lub spacji po innych klawiszach w klawiaturze numerycznej</string>
<string name="layout_number_row_basic" tools:keep="@string/layout_number_row_basic">Rząd numeryczny (podstawowy)</string>
</resources>

View file

@ -439,4 +439,10 @@
<string name="discussion_section_link">seção de discussão</string>
<string name="custom_subtype">Subtipo customizado</string>
<string name="subtype_baishakhi_bn_IN"><xliff:g id="LANGUAGE_NAME" example="Bengali">%s</xliff:g> (Baishakhi)</string>
<string name="show_tld_popup_keys">Mostrar teclas de TLD</string>
<string name="show_tld_popup_keys_summary">Substituir os pop-ups da tecla de ponto com domínios de topo ao digitar URLs e endereços de e-mail</string>
<string name="after_numpad_and_space">Pressionando enter ou espaço após outras teclas no teclado de números</string>
<string name="layout_number_row_basic" tools:keep="@string/layout_number_row_basic">Linha de números (básica)</string>
<string name="prefs_always_show_suggestions_except_web_text">Não mostrar sugestões para campos de edição da web sempre</string>
<string name="prefs_always_show_suggestions_except_web_text_summary">Campos de edição da web (encontrados normalmente em navegadores) são uma causa comum de problemas com a configuração de sempre mostrar sugestões</string>
</resources>

View file

@ -399,4 +399,35 @@
<string name="label_shortcut_key_disabled" tools:keep="@string/label_shortcut_key_disabled">Introducerea vocală este dezactivată</string>
<string name="label_toolbar_key" tools:keep="@string/label_toolbar_key">Afișează/ascunde bara de instrumente</string>
<string name="customize_icons_reset_message">Resetezi cu adevărat toate pictogramele personalizate?</string>
<string name="custom_subtype">Subtip personalizat</string>
<string name="name_invalid">Nume greșit</string>
<string name="subtype_baishakhi_bn_IN"><xliff:g id="LANGUAGE_NAME" example="Bengali">%s</xliff:g> (Baishakhi)</string>
<string name="locales_with_dict">Limbi cu dicționare</string>
<string name="split" tools:keep="@string/split">Tastatură împărțită</string>
<string name="layout_in_use">AVERTIZARE: Aspectul este utilizat în prezent</string>
<string name="customize_background_image_landscape">Setează imaginea de fundal (peisaj)</string>
<string name="summary_customize_background_image_landscape">Dacă nu este setat, se va folosi imaginea portret</string>
<string name="get_layouts_message">Poți găsi și împărtăși aspecte în %s.</string>
<string name="label_zwj_key" tools:keep="@string/label_zwj_key">Conectorul lățimii zero</string>
<string name="customize_toolbar_key_code_reset_message">Ștergi cu adevărat toate codurile cheie personalizate?</string>
<string name="split_spacer_scale_landscape">Distanța divizării (peisaj)</string>
<string name="enable_split_keyboard_landscape">Activează tastatura divizată (peisaj)</string>
<string name="gesture_fast_typing_cooldown">Timp de restabilire a tastării rapide</string>
<string name="auto_correct_shortcuts">Comenzi rapide corectare automată</string>
<string name="auto_correct_shortcuts_summary">Dacă este activat, comenzile rapide pot fi extinse prin corecție automată</string>
<string name="delete_confirmation">Chiar ștergi %s?</string>
<string name="custom_font">Setează font personalizat din fișier</string>
<string name="remove_redundant_popups_summary">Suprimă tastele pop-up care sunt deja prezente pe aspectul de bază</string>
<string name="layout_functional_keys_tablet" tools:keep="@string/layout_functional_keys_tablet">Taste funcționale (ecran mare)</string>
<string name="settings_screen_secondary_layouts">Aspecte secundare</string>
<string name="prefs_bottom_padding_scale_landscape">Scală umplutură inferioară (peisaj)</string>
<string name="prefs_font_scale">Scală font la tastatură</string>
<string name="prefs_emoji_font_scale">Scală font vizualizare emoji</string>
<string name="label_bin" tools:keep="@string/label_bin">Coș de reciclare</string>
<string name="prefs_side_padding_scale_landscape">Scală umplutură laterală (peisaj)</string>
<string name="prefs_side_padding_scale">Scală umplutură laterală</string>
<string name="number_row_hints">Afișează indicii pe rândul cu numere</string>
<string name="prefs_language_swipe_distance">Distanța de deplasare pentru comutarea limbii</string>
<string name="get_colors_message">Poți găsi și împărtăși culori în %s.</string>
<string name="discussion_section_link">secțiunea de discuții</string>
</resources>

View file

@ -285,7 +285,7 @@
<string name="theme_name_holo_white" tools:keep="@string/theme_name_holo_white">Holo Белая</string>
<string name="language_switch_key_switch_both">Смена обоих</string>
<string name="up" tools:keep="@string/up">Вверх</string>
<string name="remove_dictionary_message">Удалить пользовательский словарь \"%s\"?</string>
<string name="remove_dictionary_message">Удалить пользовательский словарь «%s»?</string>
<string name="file_read_error">Не получается прочитать файл</string>
<string name="dictionary_link_text">здесь</string>
<string name="add_dictionary">Выберите для добавления словаря. Словари в формате .dict можно скачать %s.</string>
@ -307,7 +307,7 @@
<string name="dictionary_file_wrong_locale_ok">Всё ещё используется</string>
<string name="dictionary_file_wrong_locale">Выбранный файл предназначен для %1$s, но ожидался %2$s. Всё ещё используете его для %2$s?</string>
<string name="dictionary_file_error">Ошибка: выбранный файл не является корректным словарем</string>
<string name="no_dictionary_message">"Без словаря вы будете получать предложения только для введенного ранее текста.&lt;br&gt;\n Вы можете загрузить словари %1$s или проверить, можно ли загрузить словарь для \"%2$s\" напрямую %3$s."</string>
<string name="no_dictionary_message">"Без словаря вы будете получать предложения только для введенного ранее текста.&lt;br&gt;\n Вы можете загрузить словари %1$s или проверить, можно ли загрузить словарь для «%2$s» напрямую %3$s."</string>
<string name="available_dictionary_experimental">%s (экспериментальный)</string>
<string name="layout_symbols" tools:keep="@string/layout_symbols">Символы</string>
<string name="layout_symbols_arabic" tools:keep="@string/layout_symbols_arabic">Символы (арабские)</string>
@ -425,7 +425,7 @@
<string name="label_shift_key" tools:keep="@string/label_shift_key">Shift</string>
<string name="label_shift_key_shifted" tools:keep="@string/label_shift_key_shifted">Shift (нажат)</string>
<string name="label_shift_key_locked" tools:keep="@string/label_shift_key_locked">Caps lock</string>
<string name="label_shortcut_key_disabled" tools:keep="@string/label_shortcut_key_disabled">Голосовой ввод отключен</string>
<string name="label_shortcut_key_disabled" tools:keep="@string/label_shortcut_key_disabled">Голосовой ввод отключён</string>
<string name="label_toolbar_key" tools:keep="@string/label_toolbar_key">Показать / скрыть панель инструментов</string>
<string name="label_zwj_key" tools:keep="@string/label_zwj_key">Соединитель нулевой ширины</string>
<string name="customize_toolbar_key_codes">Настроить коды клавиш панели инструментов</string>
@ -435,8 +435,8 @@
<string name="label_zwnj_key" tools:keep="@string/label_zwnj_key">Разъединитель нулевой ширины</string>
<string name="label_stop_onehanded_mode_key" tools:keep="@string/label_stop_onehanded_mode_key">Выход из режима работы одной рукой</string>
<string name="customize_icons_reset_message">Действительно сбросить все настроенные иконки?</string>
<string name="label_bin" tools:keep="@string/label_bin">Bin</string>
<string name="vibrate_in_dnd_mode">Вибрировать в режиме Не беспокоить</string>
<string name="label_bin" tools:keep="@string/label_bin">Корзина</string>
<string name="vibrate_in_dnd_mode">Вибрация в режиме «Не беспокоить»</string>
<string name="subtype_generic_phonetic"><xliff:g id="LANGUAGE_NAME" example="Хинди">%s</xliff:g> (Фонетика)</string>
<string name="auto_correct_shortcuts">Автокоррекция сочетаний клавиш</string>
<string name="custom_font">Установить пользовательский шрифт из файла</string>
@ -450,7 +450,7 @@
<string name="prefs_key_emoji_max_sdk">Переопределить версию эмодзи</string>
<string name="summary_customize_background_image_landscape">Если не установлено, будет использоваться портретное изображение</string>
<string name="customize_background_image_landscape">Установить фоновое изображение (ландшафт)</string>
<string name="number_row_hints">Показывать подсказки в ряде с цифрами</string>
<string name="number_row_hints">Показывать подсказки в ряду с цифрами</string>
<string name="prefs_language_swipe_distance">Расстояние смахивания для переключения языка</string>
<string name="split_spacer_scale_landscape">Расстояние разделения (ландшафт)</string>
<string name="enable_split_keyboard_landscape">Включить разделение клавиатуры (ландшафт)</string>
@ -466,4 +466,10 @@
<string name="get_layouts_message">Найти и поделиться раскладками в %s.</string>
<string name="discussion_section_link">обсуждения</string>
<string name="name_invalid">Недопустимое имя</string>
<string name="show_tld_popup_keys">Показать всплывающие клавиши TLD</string>
<string name="show_tld_popup_keys_summary">При вводе URL и адресов электронной почты отображать домены верхнего уровня вместо всплывающих меню клавиши точки</string>
<string name="after_numpad_and_space">Нажатие Enter или пробела после других клавиш на цифровой клавиатуре</string>
<string name="prefs_always_show_suggestions_except_web_text_summary">Поля ввода на веб-страницах (в основном в браузерах) часто вызывают проблемы с настройкой постоянного отображения подсказок</string>
<string name="layout_number_row_basic" tools:keep="@string/layout_number_row_basic">Ряд с цифрами (основной)</string>
<string name="prefs_always_show_suggestions_except_web_text">Не всегда показывать подсказки для полей ввода на веб-страницах</string>
</resources>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2014 The Android Open Source Project
modified
SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-only
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<style name="AlertDialogTheme" parent="@android:style/Theme.Material.Dialog.Alert">
<item name="android:colorAccent">@color/accent</item>
<item name="android:background">@color/action_bar_color</item>
<item name="android:textColor">@color/foreground</item>
<item name="android:textColorAlertDialogListItem">@color/foreground</item>
<item name="android:colorForeground">@color/foreground</item>
<item name="android:dialogCornerRadius">10dp</item>
</style>
</resources>

View file

@ -5,12 +5,11 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<style name="platformActivityTheme" parent="Theme.AppCompat.DayNight.NoActionBar">
<style name="platformActivityTheme" parent="@android:style/Theme.Material.NoActionBar">
<!-- Some items are duplicated from the original platform-theme file to ensure that the
"android/system_accent_*" or "android/system_neutral_*" colors are used. -->
<item name="android:colorAccent">@color/accent</item>
<item name="colorAccent">@color/accent</item>
<item name="android:statusBarColor">@color/action_bar_color</item>
<item name="android:navigationBarColor">@color/setup_background</item>
@ -19,7 +18,6 @@
<item name="android:windowBackground">@color/setup_background</item>
<item name="android:alertDialogTheme">@style/AlertDialogTheme</item>
<item name="alertDialogTheme">@style/AlertDialogTheme</item>
<item name="android:buttonCornerRadius">50dp</item>
@ -27,11 +25,9 @@
<item name="android:itemBackground">@color/drop_down_menu_background</item>
</style>
<style name="AlertDialogTheme" parent="ThemeOverlay.AppCompat.Dialog.Alert">
<style name="AlertDialogTheme" parent="@android:style/Theme.Material.Dialog.Alert">
<item name="android:colorBackgroundFloating">@color/dialog_background</item>
<item name="colorBackgroundFloating">@color/dialog_background</item>
<item name="android:dialogCornerRadius">28dp</item>
<item name="dialogCornerRadius">28dp</item>
</style>
</resources>

View file

@ -320,7 +320,7 @@
<string name="switch_keyboard_after">切换到主键盘后…</string>
<string name="after_emoji">在表情符号视图中选择表情符号</string>
<string name="after_clip">选择剪贴板历史条目</string>
<string name="after_symbol_and_space">在符号视图按回车键或空格键</string>
<string name="after_symbol_and_space">在符号视图输入内容后按回车键或空格键</string>
<string name="add_new_dictionary_title">从文件添加词典</string>
<string name="quick_pin_toolbar_keys_summary">这将禁用未固定工具栏键的其他长按操作</string>
<string name="show_popup_keys_main">添加非常常见的变体(默认)</string>
@ -433,4 +433,10 @@
<string name="get_colors_message">您可以在 %s 中查找和分享颜色。</string>
<string name="custom_subtype">自定义子类型</string>
<string name="subtype_baishakhi_bn_IN"><xliff:g id="LANGUAGE_NAME" example="Bengali">%s</xliff:g> (Baishakhi)</string>
<string name="show_tld_popup_keys_summary">输入 URL 和电子邮件地址时,用顶级域替换句点键弹出</string>
<string name="show_tld_popup_keys">显示顶级域弹出键</string>
<string name="after_numpad_and_space">在数字键盘输入内容后按回车键或空格键</string>
<string name="layout_number_row_basic" tools:keep="@string/layout_number_row_basic">数字行(基本)</string>
<string name="prefs_always_show_suggestions_except_web_text_summary">Web 编辑字段(主要存在于浏览器中)是导致“始终显示建议”设置出现问题的一个非常常见的原因</string>
<string name="prefs_always_show_suggestions_except_web_text">不要总是显示对 Web 编辑字段的建议</string>
</resources>

View file

@ -6,11 +6,21 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<style name="platformActivityTheme" parent="Theme.AppCompat.DayNight.NoActionBar">
<style name="platformActivityTheme" parent="@android:style/Theme.Material.NoActionBar">
<item name="android:colorAccent">@color/accent</item>
<item name="colorAccent">@color/accent</item>
<item name="android:statusBarColor">@color/action_bar_color</item>
<item name="android:navigationBarColor">@color/navigation_bar_color</item>
<item name="android:colorBackground">@color/setup_background</item>
<item name="android:colorForeground">@color/foreground</item>
<item name="android:alertDialogTheme">@style/AlertDialogTheme</item>
</style>
<style name="AlertDialogTheme" parent="@android:style/Theme.Material.Dialog.Alert">
<item name="android:colorAccent">@color/accent</item>
<item name="android:background">@color/action_bar_color</item>
<item name="android:textColor">@color/foreground</item>
<item name="android:textColorAlertDialogListItem">@color/foreground</item>
<item name="android:colorForeground">@color/foreground</item>
</style>
</resources>

View file

@ -38,6 +38,8 @@
<string name="settings_category_clipboard_history">Clipboard history</string>
<!-- Settings category title for Text correction/Corrections -->
<string name="settings_category_correction">Corrections</string>
<!-- Settings category title for Text correction/Space -->
<string name="settings_category_space">Space</string>
<!-- Settings category title for Text correction/Suggestions -->
<string name="settings_category_suggestions">Suggestions</string>
<!-- Settings category title for Advanced/Experimental -->
@ -104,6 +106,10 @@
<string name="prefs_always_show_suggestions">Always show suggestions</string>
<!-- Description for override app flag to not show suggestions -->
<string name="prefs_always_show_suggestions_summary">Ignore other apps request to disable suggestions (may cause issues)</string>
<!-- Option to not override the above flags for InputType.WEB_EDIT_TEXT -->
<string name="prefs_always_show_suggestions_except_web_text">Dont always show suggestions for web edit fields</string>
<!-- Description for prefs_always_show_suggestions_except_web_text -->
<string name="prefs_always_show_suggestions_except_web_text_summary">Web edit fields (mostly found in browsers) are a very common cause for issues with the always show suggestions setting</string>
<!-- Option to block potentially offensive words to be shown -->
<string name="prefs_block_potentially_offensive_title">Block offensive words</string>
<!-- Summary for option to block potentially offensive words to be shown -->
@ -122,6 +128,8 @@
<string name="auto_correct_shortcuts">Auto-correct shortcuts</string>
<!-- Description for auto_correct_shortcuts -->
<string name="auto_correct_shortcuts_summary">When enabled shortcuts might be expanded by autocorrect</string>
<!-- Option to undo auto correction with backspace -->
<string name="backspace_reverts_autocorrect">Backspace reverts autocorrect</string>
<!-- Option to disable auto correction. -->
<string name="auto_correction_threshold_mode_off">Off</string>
<!-- Option to suggest auto correction suggestions modestly. Auto-corrects only to a word which has small edit distance from typed word. -->
@ -188,6 +196,8 @@
<string name="button_backup">Backup</string>
<!-- restore button -->
<string name="button_restore">Restore</string>
<!-- Preferences item for format for timestamp keycode -->
<string name="timestamp_format_title">Format for timestamp key</string>
<!-- Preferences item for choosing secondary language -->
<string name="secondary_locale">Multilingual typing</string>
<!-- Clarification which locales are available for multilingual typing -->
@ -205,10 +215,20 @@
<string name="load_gesture_library_button_load">Load library</string>
<!-- Button text for deleting gesture library -->
<string name="load_gesture_library_button_delete">Delete library</string>
<!-- Preferences item for enabling inserting more spaces key -->
<!-- Preferences item for inserting space after punctuation -->
<string name="autospace_after_punctuation">Autospace after punctuation</string>
<!-- Description for "insert_more_spaces" option. -->
<!-- Description for "autospace_after_punctuation" setting -->
<string name="autospace_after_punctuation_summary">Automatically insert space after punctuation when typing a new word</string>
<!-- Preferences item for inserting space after manualle picking a suggestion -->
<string name="autospace_after_suggestion">Autospace after picking a suggestion</string>
<!-- Preferences item for inserting space before entering a word using gesture typing -->
<string name="autospace_before_gesture_typing">Autospace before gesture typing a word</string>
<!-- Preferences item for inserting space after entering a word using gesture typing -->
<string name="autospace_after_gesture_typing">Autospace after gesture typing a word</string>
<!-- Preferences item for avoiding automatic space insertion by pressing shift -->
<string name="shift_removes_autospace">No autospace when pressing shift</string>
<!-- Description for "autospace_after_punctuation" setting -->
<string name="shift_removes_autospace_summary">Shift removes pending autospace</string>
<!-- Preferences item for showing popup keys in long-press popup -->
<string name="show_popup_keys_title">Show more letters with diacritics in popup</string>
<!-- Option for showing only letters defined in the current language file in long-press popup -->
@ -249,6 +269,10 @@
<string name="hint_source">Select hint source</string>
<!-- Title of the setting to set popup key order -->
<string name="popup_order">Select popup key order</string>
<!-- Title of the setting to show TLD popup keys -->
<string name="show_tld_popup_keys">Show TLD popup keys</string>
<!-- Description of the setting to show TLD popup keys -->
<string name="show_tld_popup_keys_summary">Replace period key popups with top level domains when typing URLs and email addresses</string>
<!-- Names of the popup key classes -->
<string name="popup_keys_number" tools:keep="@string/popup_keys_number">Number row</string>
<string name="popup_keys_language" tools:keep="@string/popup_keys_language">Language</string>
@ -555,6 +579,8 @@ disposition rather than other common dispositions for Latin languages. -->
<string name="layout_numpad_landscape" tools:keep="@string/layout_numpad_landscape">Numpad (landscape)</string>
<!-- Name for number row layout -->
<string name="layout_number_row" tools:keep="@string/layout_number_row">Number row</string>
<!-- Name for number row basic layout -->
<string name="layout_number_row_basic" tools:keep="@string/layout_number_row_basic">Number row (basic)</string>
<!-- Name for bottom row layout in emoji view -->
<string name="layout_emoji_bottom_row" tools:keep="@string/layout_emoji_bottom_row">Emoji bottom row</string>
<!-- Name for bottom row layout in clipboard view -->
@ -577,6 +603,8 @@ disposition rather than other common dispositions for Latin languages. -->
<string name="after_clip">Selecting clipboard history entry</string>
<!-- Switch to main keyboard after entering a symbol in symbols layout and then pressing space or enter -->
<string name="after_symbol_and_space">Pressing enter or space after other keys in symbols view</string>
<!-- Switch to main keyboard after entering something in numpad layout and then pressing space or enter -->
<string name="after_numpad_and_space">Pressing enter or space after other keys in numpad</string>
<!-- Message for selecting day or night background image -->
<string name="day_or_night_image">Set image for day or night mode?</string>
<!-- Button for selecting day -->

View file

@ -23,6 +23,7 @@
bn_IN: Bengali (India)/bengali_inscript
bn_IN: Bengali (India)/Baishakhi
ca: Catalan/qwerty+
ckb: Central Kurdish/central_kurdish
cs: Czech/qwertz
cv: Chuvash/chuvash
da: Danish/qwerty+
@ -90,6 +91,7 @@
pt_PT: Portuguese (Portugal)/qwerty
ro: Romanian/qwerty
ru: Russian/russian
ru: Russian (Extended)/russian_extended
ru: Russian (Student)/russian_student
si_LK: Sinhala (Sri Lanka)/sinhala # This is a preliminary keyboard layout.
sk: Slovak/qwerty
@ -107,6 +109,7 @@
tr: Turkish/turkish
ur_PK: Urdu Pakistan
uk: Ukrainian/ukrainian
uk: Ukrainian (Extended)/ukrainian_extended
uz_UZ: Uzbek (Uzbekistan)/uzbek # This is a preliminary keyboard layout.
vi: Vietnamese/qwerty
zu: Zulu/qwerty
@ -287,6 +290,15 @@
android:imeSubtypeExtraValue="KeyboardLayoutSet=MAIN:qwerty+,AsciiCapable,EmojiCapable"
android:isAsciiCapable="true"
/>
<subtype android:icon="@drawable/ic_ime_switcher"
android:label="@string/subtype_generic"
android:subtypeId="0xf40a175b"
android:imeSubtypeLocale="ckb"
android:languageTag="ckb"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="KeyboardLayoutSet=MAIN:central_kurdish|SYMBOLS:symbols_arabic,NoShiftKey,SupportTouchPositionCorrection,EmojiCapable"
android:isAsciiCapable="false"
/>
<subtype android:icon="@drawable/ic_ime_switcher"
android:label="@string/subtype_generic"
android:subtypeId="0x2d3d2ed0"
@ -912,6 +924,16 @@
android:imeSubtypeExtraValue="KeyboardLayoutSet=MAIN:russian,SupportTouchPositionCorrection,EmojiCapable"
android:isAsciiCapable="false"
/>
<subtype android:icon="@drawable/ic_ime_switcher"
android:label="@string/subtype_generic_extended"
android:subtypeId="0x91f35a0b"
android:imeSubtypeLocale="ru"
android:languageTag="ru"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="KeyboardLayoutSet=MAIN:russian_extended,SupportTouchPositionCorrection,EmojiCapable"
android:isAsciiCapable="false"
/>
<subtype android:icon="@drawable/ic_ime_switcher"
android:label="@string/subtype_generic_student"
android:subtypeId="0x1bc335d0"
@ -1064,6 +1086,15 @@
android:imeSubtypeExtraValue="KeyboardLayoutSet=MAIN:ukrainian,EmojiCapable"
android:isAsciiCapable="false"
/>
<subtype android:icon="@drawable/ic_ime_switcher"
android:label="@string/subtype_generic_extended"
android:subtypeId="0x49dc95e4"
android:imeSubtypeLocale="uk"
android:languageTag="uk"
android:imeSubtypeMode="keyboard"
android:imeSubtypeExtraValue="KeyboardLayoutSet=MAIN:ukrainian_extended,EmojiCapable"
android:isAsciiCapable="false"
/>
<subtype android:icon="@drawable/ic_ime_switcher"
android:label="@string/subtype_generic"
android:subtypeId="0x1e8349fc"

View file

@ -23,6 +23,7 @@ import helium314.keyboard.latin.inputlogic.InputLogic
import helium314.keyboard.latin.inputlogic.SpaceState
import helium314.keyboard.latin.settings.Settings
import helium314.keyboard.latin.utils.ScriptUtils
import helium314.keyboard.latin.utils.getTimestamp
import helium314.keyboard.latin.utils.prefs
import org.junit.runner.RunWith
import org.mockito.Mockito
@ -203,13 +204,7 @@ class InputLogicTest {
assertEquals("example.net", composingText)
}
// fails because
// period is not handled with handleSeparatorEvent in this case
// pickSuggestion sets phantom space state
// insertAutomaticSpaceIfOptionsAndTextAllow allows the space
// todo: fix it either in some of those functions, or by finally improving URL detection in a reasonable (and performant) way
@Test fun noAutospaceInUrlFieldWhenPickingSuggestion() {
if (BuildConfig.BUILD_TYPE == "runTests") return
reset()
setInputType(InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_URI)
chainInput("exam")
@ -262,6 +257,7 @@ class InputLogicTest {
reset()
latinIME.prefs().edit { putBoolean(Settings.PREF_URL_DETECTION, true) }
latinIME.prefs().edit { putBoolean(Settings.PREF_AUTOSPACE_AFTER_PUNCTUATION, true) }
latinIME.prefs().edit { putBoolean(Settings.PREF_SHIFT_REMOVES_AUTOSPACE, true) }
input("bla")
input('.')
functionalKeyPress(KeyCode.SHIFT) // should remove the phantom space (in addition to normal effect)
@ -644,13 +640,20 @@ class InputLogicTest {
@Test fun `revert autocorrect on delete`() {
reset()
setInputType(InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_AUTO_CORRECT)
chainInput("hullo")
getAutocorrectedWithSpaceAfter("hello", "hullo")
assertEquals("hello ", text)
functionalKeyPress(KeyCode.DELETE)
assertEquals("hullo", text)
// todo: now we want some way to disable revert on backspace, either per setting or something else
// need to avoid getting into the mLastComposedWord.canRevertCommit() part of handleBackspaceEvent
reset()
setInputType(InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_AUTO_CORRECT)
latinIME.prefs().edit { putBoolean(Settings.PREF_BACKSPACE_REVERTS_AUTOCORRECT, false) }
chainInput("hullo")
getAutocorrectedWithSpaceAfter("hello", "hullo")
functionalKeyPress(KeyCode.DELETE)
assertEquals("hello", text)
}
@Test fun `remove glide typing word on delete`() {
@ -664,6 +667,13 @@ class InputLogicTest {
// need to avoid getting into the mWordComposer.isBatchMode() part of handleBackspaceEvent
}
@Test fun timestamp() {
reset()
chainInput("hello")
functionalKeyPress(KeyCode.TIMESTAMP)
assertEquals("hello" + getTimestamp(latinIME), text)
}
// ------- helper functions ---------
// should be called before every test, so the same state is guaranteed
@ -808,7 +818,7 @@ class InputLogicTest {
val info = SuggestedWordInfo(suggestion, "", 0, 0, null, 0, 0)
val typedInfo = SuggestedWordInfo(typedWord, "", 0, 0, null, 0, 0)
val sw = SuggestedWords(ArrayList(listOf(typedInfo, info)), null, typedInfo, false, true, false, 0, 0)
latinIME.mInputLogic.setSuggestedWords(sw)
latinIME.mInputLogic.setSuggestedWords(sw) // this prepares for autocorrect
input(' ')
checkConnectionConsistency()
}

View file

@ -1,12 +1,23 @@
// SPDX-License-Identifier: GPL-3.0-only
package helium314.keyboard.latin
import androidx.test.core.app.ApplicationProvider
import helium314.keyboard.ShadowInputMethodManager2
import helium314.keyboard.latin.common.StringUtils
import helium314.keyboard.latin.common.getFullEmojiAtEnd
import helium314.keyboard.latin.common.nonWordCodePointAndNoSpaceBeforeCursor
import helium314.keyboard.latin.settings.SpacingAndPunctuations
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
import kotlin.test.Test
import kotlin.test.assertEquals
// todo: actually this test could/should be significantly expanded...
@RunWith(RobolectricTestRunner::class)
@Config(shadows = [
ShadowInputMethodManager2::class,
])
class StringUtilsTest {
@Test fun `not inside double quotes without quotes`() {
assert(!StringUtils.isInsideDoubleQuoteOrAfterDigit("hello yes"))
@ -41,6 +52,14 @@ class StringUtilsTest {
assert(StringUtils.isInsideDoubleQuoteOrAfterDigit("hello \"yes\", \"h"))
}
@Test fun `non-word codepoints and no space`() {
val sp = SpacingAndPunctuations(ApplicationProvider.getApplicationContext<App>().resources, false)
assert(!nonWordCodePointAndNoSpaceBeforeCursor("this is", sp))
assert(!nonWordCodePointAndNoSpaceBeforeCursor("this ", sp))
assert(!nonWordCodePointAndNoSpaceBeforeCursor("th.is ", sp))
assert(nonWordCodePointAndNoSpaceBeforeCursor("th.is", sp))
}
@Test fun detectEmojisAtEnd() {
assertEquals("", getFullEmojiAtEnd("\uD83C\uDF83 "))
assertEquals("", getFullEmojiAtEnd("a"))

View file

@ -1,4 +1,4 @@
হেলিবোর্ড গোপনীয়তা-সচেতন ওপেন সোর্স কিবোর্ড যার উৎস অ্যান্ড্রয়েড ওপেন সোর্স প্রজেক্ট এবং ওপেনবোর্ড। বাংলা (বাংলাদেশ) ভাষার জন্য এতে ইউনিজয় লেআউট যুক্ত আছে।
হেলিবোর্ড গোপনীয়তা-সচেতন ওপেন সোর্স কিবোর্ড যার উৎস অ্যান্ড্রয়েড ওপেন সোর্স প্রজেক্ট এবং ওপেনবোর্ড। বাংলা ভাষার জন্য এতে ইউনিজয়, প্রভাত, অক্ষর, ইনস্ক্রিপ্ট, বৈশাখী লেআউট যুক্ত আছে।
এটি ইন্টারনেটের অনুমতি ব্যবহার করে না, তাই ১০০% অফলাইন।
সুবিধা:

View file

@ -89,7 +89,7 @@ Usually the label is what is displayed on the key. However, there are some speci
* _symbol_alpha_: toggle alpha / symbol keyboard
* _numpad_: toggle numpad layout
* _emoji_: switch to emoji view
* _com_: display common TLDs (.com and similar, currently not localized)
* _com_: display common TLDs (.com and similar, localized)
* _language_switch_: language switch key
* _action_: the action (enter) key
* _delete_: delete key
@ -103,7 +103,7 @@ Usually the label is what is displayed on the key. However, there are some speci
* In case a label clashes with text you want to add, put a `\` in front of the text you want, e.g. `\space` will write the label `space` instead of adding a space bar.
* Note that you need to escape the `\` in json files by adding a second `\`.
* If you want different key label and input text, set the label to [label]|[text], e.g. `aa|bb` will show `aa`, but pressing the key will input `bb`.
You can also specify special key codes like `a|!code/key_action_previous`, but it's cleaner to use a json layout and specify the code explicitly. Note that when specifying a code in the label, and a code in a json layout, the code in the label will be ignored.
You can also specify special key codes like `a|!code/key_action_previous` or `abc|!code/-10043`, but it's cleaner to use a json layout and specify the code explicitly. Note that when specifying a code in the label, and a code in a json layout, the code in the label will be ignored.
* It's also possible to specify an icon, like `!icon/previous_key|!code/key_action_previous`.
* You can find available icon names in [KeyboardIconsSet](/app/src/main/java/helium314/keyboard/keyboard/internal/KeyboardIconsSet.kt). You can also use toolbar key icons using the uppercase name of the [toolbar key](/app/src/main/java/helium314/keyboard/latin/utils/ToolbarUtils.kt#L109), e.g. `!icon/redo`