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) * Add and enable emoji dictionaries by default (if available for language)
* Clearer / more intuitive arrangement of settings * Clearer / more intuitive arrangement of settings
* Maybe hide some less used settings by default (similar to color customization) * 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) * [Bug fixes](https://github.com/Helium314/HeliBoard/issues?q=is%3Aissue+is%3Aopen+label%3Abug)
__What will _not_ be added:__ __What will _not_ be added:__

View file

@ -6,15 +6,15 @@ plugins {
} }
android { android {
compileSdk = 34 compileSdk = 35
buildToolsVersion = "34.0.0" buildToolsVersion = "34.0.0"
defaultConfig { defaultConfig {
applicationId = "helium314.keyboard" applicationId = "helium314.keyboard"
minSdk = 21 minSdk = 21
targetSdk = 34 targetSdk = 35
versionCode = 3000 versionCode = 3003
versionName = "3.0-alpha1" versionName = "3.0-alpha3"
ndk { ndk {
abiFilters.clear() abiFilters.clear()
abiFilters.addAll(listOf("armeabi-v7a", "arm64-v8a", "x86", "x86_64")) abiFilters.addAll(listOf("armeabi-v7a", "arm64-v8a", "x86", "x86_64"))
@ -58,7 +58,7 @@ android {
path = File("src/main/jni/Android.mk") path = File("src/main/jni/Android.mk")
} }
} }
ndkVersion = "26.2.11394342" ndkVersion = "28.0.13004108"
packagingOptions { packagingOptions {
jniLibs { jniLibs {
@ -96,9 +96,8 @@ android {
dependencies { dependencies {
// androidx // androidx
implementation("androidx.core:core-ktx:1.13.1") implementation("androidx.core:core-ktx:1.15.0")
implementation("androidx.appcompat:appcompat:1.7.0") implementation("androidx.recyclerview:recyclerview:1.4.0")
implementation("androidx.recyclerview:recyclerview:1.3.2")
implementation("androidx.autofill:autofill:1.1.0") implementation("androidx.autofill:autofill:1.1.0")
// kotlin // kotlin
@ -118,7 +117,7 @@ dependencies {
testImplementation(kotlin("test")) testImplementation(kotlin("test"))
testImplementation("junit:junit:4.13.2") testImplementation("junit:junit:4.13.2")
testImplementation("org.mockito:mockito-core:5.15.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:runner:1.6.2")
testImplementation("androidx.test:core:1.6.1") 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", "emojiKeyEnabled": { "$": "keyboard_state_selector", "alphabet": { "label": "emoji" }}},
{ "$": "keyboard_state_selector", "symbols": { "label": "numpad" }}, { "$": "keyboard_state_selector", "symbols": { "label": "numpad" }},
{ "label": "space" }, { "label": "space" },
{ "label": "period", "labelFlags": 1073741824 }, { "label": "period" },
{ "label": "action", "width": 0.15 } { "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 ⁷ ⅞ 7 ⁷ ⅞
8 ⁸ 8 ⁸
9 ⁹ 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] [popup_keys]
е ё е ё е́ ѣ
ь ъ ф ѳ
ы ы́
а а́
о о́
я я́
и и́
ь ъ ы
ю ю́
' '
" ” „ “ » « " ” „ “ » «
і ы
є э э́
[labels] [labels]
alphabet: АБВ alphabet: АБВ

View file

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

View file

@ -24,6 +24,7 @@ import helium314.keyboard.latin.common.StringUtils;
import helium314.keyboard.latin.utils.PopupKeysUtilsKt; import helium314.keyboard.latin.utils.PopupKeysUtilsKt;
import helium314.keyboard.latin.utils.ToolbarKey; import helium314.keyboard.latin.utils.ToolbarKey;
import helium314.keyboard.latin.utils.ToolbarUtilsKt; import helium314.keyboard.latin.utils.ToolbarUtilsKt;
import kotlin.collections.ArraysKt;
import java.util.Arrays; import java.util.Arrays;
import java.util.Locale; import java.util.Locale;
@ -919,7 +920,7 @@ public class Key implements Comparable<Key> {
@NonNull final Drawable spacebarBackground, @NonNull final Drawable spacebarBackground,
@NonNull final Drawable actionKeyBackground) { @NonNull final Drawable actionKeyBackground) {
final Drawable background; final Drawable background;
if (isAccentColored()) { if (hasActionKeyBackground()) {
background = actionKeyBackground; background = actionKeyBackground;
} else if (hasFunctionalBackground()) { } else if (hasFunctionalBackground()) {
background = functionalKeyBackground; background = functionalKeyBackground;
@ -933,17 +934,10 @@ public class Key implements Comparable<Key> {
return background; return background;
} }
public final boolean isAccentColored() { public final boolean hasActionKeyPopups() {
if (hasActionKeyBackground()) return true; if (!hasActionKeyBackground()) return false;
final String iconName = getIconName(); // only use the special action key popups for action colored keys, and only for icon popups
if (iconName == null) return false; return ArraysKt.none(getPopupKeys(), (key) -> key.mIconName == null);
// 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 boolean hasFunctionalBackground() { public boolean hasFunctionalBackground() {

View file

@ -1,5 +1,6 @@
package helium314.keyboard.keyboard package helium314.keyboard.keyboard
import android.text.InputType
import android.view.KeyEvent import android.view.KeyEvent
import android.view.inputmethod.InputMethodSubtype import android.view.inputmethod.InputMethodSubtype
import helium314.keyboard.keyboard.internal.keyboard_parser.floris.KeyCode import helium314.keyboard.keyboard.internal.keyboard_parser.floris.KeyCode
@ -211,13 +212,24 @@ class KeyboardActionListenerImpl(private val latinIME: LatinIME, private val inp
return true 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 // 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 val newPosition = inputLogic.mConnection.expectedSelectionStart + moveSteps
inputLogic.mConnection.setSelection(newPosition, newPosition) inputLogic.mConnection.setSelection(newPosition, newPosition)
return true return true
} }
inputLogic.finishInput() inputLogic.finishInput()
val newPosition = inputLogic.mConnection.expectedSelectionStart + moveSteps val newPosition = inputLogic.mConnection.expectedSelectionStart + moveSteps
inputLogic.mConnection.setSelection(newPosition, newPosition) 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 { fun getUnusedThemeName(initialName: String, prefs: SharedPreferences): String {
val existingNames = prefs.all.keys.mapNotNull { val existingNames = getExistingThemeNames(prefs)
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()
if (initialName !in existingNames) return initialName if (initialName !in existingNames) return initialName
var i = 1 var i = 1
while ("$initialName$i" in existingNames) while ("$initialName$i" in existingNames)
@ -420,11 +413,8 @@ private constructor(val themeId: Int, @JvmField val mStyleId: Int) {
return "$initialName$i" return "$initialName$i"
} }
// returns false if not renamed due to invalid name or collision private fun getExistingThemeNames(prefs: SharedPreferences) =
fun renameUserColors(from: String, to: String, prefs: SharedPreferences): Boolean { prefs.all.keys.mapNotNull {
if (to.isBlank()) return false // don't want that
if (to == from) return true // nothing to do
val existingNames = prefs.all.keys.mapNotNull {
when { when {
it.startsWith(Settings.PREF_USER_COLORS_PREFIX) -> it.substringAfter(Settings.PREF_USER_COLORS_PREFIX) 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_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 else -> null
} }
}.toSortedSet() }.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 if (to in existingNames) return false
// all good, now rename // all good, now rename
prefs.edit { prefs.edit {

View file

@ -27,6 +27,7 @@ import android.view.View;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import helium314.keyboard.keyboard.emoji.EmojiPageKeyboardView;
import helium314.keyboard.keyboard.internal.KeyDrawParams; import helium314.keyboard.keyboard.internal.KeyDrawParams;
import helium314.keyboard.keyboard.internal.KeyVisualAttributes; import helium314.keyboard.keyboard.internal.KeyVisualAttributes;
import helium314.keyboard.keyboard.internal.keyboard_parser.floris.KeyCode; 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.ColorType;
import helium314.keyboard.latin.common.Colors; import helium314.keyboard.latin.common.Colors;
import helium314.keyboard.latin.common.Constants; 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.settings.Settings;
import helium314.keyboard.latin.suggestions.MoreSuggestions; import helium314.keyboard.latin.suggestions.MoreSuggestions;
import helium314.keyboard.latin.suggestions.PopupSuggestionsView; import helium314.keyboard.latin.suggestions.PopupSuggestionsView;
@ -423,10 +424,14 @@ public class KeyboardView extends View {
} }
if (key.isEnabled()) { 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) 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()) else if (key.hasActionKeyBackground())
paint.setColor(mColors.get(ColorType.ACTION_KEY_ICON)); 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 else
paint.setColor(key.selectTextColor(params)); paint.setColor(key.selectTextColor(params));
// Set a drop shadow for the text if the shadow radius is positive value. // 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) { private void setKeyIconColor(Key key, Drawable icon, Keyboard keyboard) {
if (key.isAccentColored()) { if (key.hasActionKeyBackground()) {
mColors.setColor(icon, ColorType.ACTION_KEY_ICON); mColors.setColor(icon, ColorType.ACTION_KEY_ICON);
} else if (key.isShift() && keyboard != null) { } else if (key.isShift() && keyboard != null) {
if (keyboard.mId.mElementId == KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED 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.Paint.Align;
import android.graphics.Typeface; import android.graphics.Typeface;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.View; import android.view.View;
@ -25,7 +26,6 @@ import android.view.ViewGroup;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.appcompat.view.ContextThemeWrapper;
import helium314.keyboard.accessibility.AccessibilityUtils; import helium314.keyboard.accessibility.AccessibilityUtils;
import helium314.keyboard.accessibility.MainKeyboardAccessibilityDelegate; import helium314.keyboard.accessibility.MainKeyboardAccessibilityDelegate;
@ -505,7 +505,7 @@ public final class MainKeyboardView extends KeyboardView implements DrawingProxy
mPopupKeysKeyboardCache.put(key, popupKeysKeyboard); mPopupKeysKeyboardCache.put(key, popupKeysKeyboard);
} }
final View container = key.hasActionKeyBackground() ? mPopupKeysKeyboardForActionContainer final View container = key.hasActionKeyPopups() ? mPopupKeysKeyboardForActionContainer
: mPopupKeysKeyboardContainer; : mPopupKeysKeyboardContainer;
final PopupKeysKeyboardView popupKeysKeyboardView = final PopupKeysKeyboardView popupKeysKeyboardView =
container.findViewById(R.id.popup_keys_keyboard_view); 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 PopupKeysKeyboardParams params = mParams;
final int popupKeyFlags = mParentKey.getPopupKeyLabelFlags(); final int popupKeyFlags = mParentKey.getPopupKeyLabelFlags();
final PopupKeySpec[] popupKeys = mParentKey.getPopupKeys(); 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++) { for (int n = 0; n < popupKeys.length; n++) {
final PopupKeySpec popupKeySpec = popupKeys[n]; final PopupKeySpec popupKeySpec = popupKeys[n];
final int row = n / params.mNumColumns; final int row = n / params.mNumColumns;
final int x = params.getX(n, row); final int x = params.getX(n, row);
final int y = params.getY(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.markAsEdgeKey(key, row);
params.onAddKey(key); params.onAddKey(key);

View file

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

View file

@ -15,8 +15,7 @@ import android.text.TextUtils;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.util.TypedValue; import android.util.TypedValue;
import android.view.Gravity; import android.view.Gravity;
import android.widget.TextView;
import androidx.appcompat.widget.AppCompatTextView;
import helium314.keyboard.keyboard.Key; import helium314.keyboard.keyboard.Key;
import helium314.keyboard.latin.R; import helium314.keyboard.latin.R;
@ -25,10 +24,9 @@ import helium314.keyboard.latin.settings.Settings;
import java.util.HashSet; import java.util.HashSet;
/** /** The pop up key preview view. */
* 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 class KeyPreviewView extends AppCompatTextView {
public static final int POSITION_MIDDLE = 0; public static final int POSITION_MIDDLE = 0;
public static final int POSITION_LEFT = 1; public static final int POSITION_LEFT = 1;
public static final int POSITION_RIGHT = 2; 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 // when? -> hasShiftedLetterHint and isShiftedLetterActivated -> both are label flags
mShiftedLetterHintActivatedColor = keyAttr.getColor( mShiftedLetterHintActivatedColor = keyAttr.getColor(
R.styleable.Keyboard_Key_keyShiftedLetterHintActivatedColor, 0); R.styleable.Keyboard_Key_keyShiftedLetterHintActivatedColor, 0);
mPreviewTextColor = colors.get(ColorType.KEY_TEXT); mPreviewTextColor = colors.get(ColorType.KEY_PREVIEW_TEXT);
mHintLabelVerticalAdjustment = ResourceUtils.getFraction(keyAttr, mHintLabelVerticalAdjustment = ResourceUtils.getFraction(keyAttr,
R.styleable.Keyboard_Key_keyHintLabelVerticalAdjustment, 0.0f); 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_BEGIN = 1;
private static final int SWITCH_STATE_SYMBOL = 2; private static final int SWITCH_STATE_SYMBOL = 2;
private static final int SWITCH_STATE_NUMPAD = 3; 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_ALPHA_AND_SYMBOL = 4;
private static final int SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE = 5; private static final int SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE = 5;
private static final int SWITCH_STATE_MOMENTARY_ALPHA_SHIFT = 6; private static final int SWITCH_STATE_MOMENTARY_ALPHA_SHIFT = 6;
@ -403,7 +404,7 @@ public final class KeyboardState {
mMode = MODE_NUMPAD; mMode = MODE_NUMPAD;
mRecapitalizeMode = RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE; mRecapitalizeMode = RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE;
mSwitchActions.setNumpadKeyboard(); 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, public void toggleNumpad(final boolean withSliding, final int autoCapsFlags, final int recapitalizeMode,
@ -789,6 +790,17 @@ public final class KeyboardState {
mPrevSymbolsKeyboardWasShifted = false; mPrevSymbolsKeyboardWasShifted = false;
} }
break; 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. // 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_SYMBOL_AND_MORE -> "MOMENTARY-SYMBOL-MORE";
case SWITCH_STATE_MOMENTARY_ALPHA_SHIFT -> "MOMENTARY-ALPHA_SHIFT"; case SWITCH_STATE_MOMENTARY_ALPHA_SHIFT -> "MOMENTARY-ALPHA_SHIFT";
case SWITCH_STATE_NUMPAD -> "NUMPAD"; 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_TO_NUMPAD -> "MOMENTARY-TO-NUMPAD";
case SWITCH_STATE_MOMENTARY_FROM_NUMPAD -> "MOMENTARY-FROM-NUMPAD"; case SWITCH_STATE_MOMENTARY_FROM_NUMPAD -> "MOMENTARY-FROM-NUMPAD";
default -> null; default -> null;

View file

@ -68,11 +68,9 @@ public final class PopupKeySpec {
} }
@NonNull @NonNull
public Key buildKey(final int x, final int y, final int labelFlags, public Key buildKey(final int x, final int y, final int labelFlags, final int background, @NonNull final KeyboardParams params) {
@NonNull final KeyboardParams params) { return new Key(mLabel, mIconName, mCode, mOutputText, null, labelFlags, background, x, y,
return new Key(mLabel, mIconName, mCode, mOutputText, null /* hintLabel */, labelFlags, params.mDefaultAbsoluteKeyWidth, params.mDefaultAbsoluteRowHeight, params.mHorizontalGap, params.mVerticalGap);
Key.BACKGROUND_TYPE_NORMAL, x, y, params.mDefaultAbsoluteKeyWidth, params.mDefaultAbsoluteRowHeight,
params.mHorizontalGap, params.mVerticalGap);
} }
@Override @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}, { it.label == KeyLabel.PERIOD || it.groupId == KeyData.GROUP_PERIOD},
{ baseKeys.last()[1].copy(newGroupId = 2, newType = baseKeys.last()[1].type ?: it.type) } { 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 // 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 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 "mns" -> Key.LABEL_FLAGS_FOLLOW_KEY_LETTER_RATIO
else -> 0 else -> 0
} }
val tlds = getLocaleTlds(locale) // todo: USE IT val tlds = getLocaleTlds(locale)
init { init {
readStream(dataStream, false, true) 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) */ /** Pair(extraKeysLeft, extraKeysRight) */
fun getTabletExtraKeys(elementId: Int): Pair<List<KeyData>, List<KeyData>> { fun getTabletExtraKeys(elementId: Int): Pair<List<KeyData>, List<KeyData>> {
val flags = Key.LABEL_FLAGS_FONT_DEFAULT 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 if (locale == params.mId.locale) return@forEach
lkt.addFile(getStreamForLocale(locale, context), true) lkt.addFile(getStreamForLocale(locale, context), true)
} }
lkt.addDefaultTlds(params.mId.locale)
when (popupKeysSetting) { when (popupKeysSetting) {
POPUP_KEYS_MAIN -> lkt.addFile(context.assets.open("$LOCALE_TEXTS_FOLDER/more_popups_main.txt"), false) 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) 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> { private fun getLocaleTlds(locale: Locale): LinkedHashSet<String> {
val tlds = getDefaultTlds(locale)
val ccLower = locale.country.lowercase() val ccLower = locale.country.lowercase()
val tlds = LinkedHashSet<String>()
if (ccLower.isEmpty() || locale.language == SubtypeLocaleUtils.NO_LANGUAGE) if (ccLower.isEmpty() || locale.language == SubtypeLocaleUtils.NO_LANGUAGE)
return tlds return tlds
specialCountryTlds.forEach { specialCountryTlds.forEach {
if (ccLower != it.first) return@forEach if (ccLower != it.first) return@forEach
tlds.addAll(it.second.splitOnWhitespace()) tlds.addAll(it.second.splitOnWhitespace())
return tlds return@getLocaleTlds tlds
} }
tlds.add(".$ccLower") tlds.add(".$ccLower")
return tlds 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() fun clearCache() = localeKeyboardInfosCache.clear()
// cache the texts, so they don't need to be read over and over // 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 BACK = -10040
const val SELECT_LEFT = -10041 const val SELECT_LEFT = -10041
const val SELECT_RIGHT = -10042 const val SELECT_RIGHT = -10042
const val TIMESTAMP = -10043
/** to make sure a FlorisBoard code works when reading a JSON layout */ /** to make sure a FlorisBoard code works when reading a JSON layout */
fun Int.checkAndConvertCode(): Int = if (this > 0) this else when (this) { 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, 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, 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, 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 -> this
// conversion // conversion
@ -194,8 +196,12 @@ object KeyCode {
else -> throw IllegalStateException("key code $this not yet supported") 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 // 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 */ /**
* 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) fun Int.toKeyEventCode(): Int = if (this > 0)
when (this.toChar().uppercaseChar()) { when (this.toChar().uppercaseChar()) {
'/' -> KeyEvent.KEYCODE_SLASH '/' -> 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.settings.Settings
import helium314.keyboard.latin.spellcheck.AndroidSpellCheckerService import helium314.keyboard.latin.spellcheck.AndroidSpellCheckerService
import helium314.keyboard.latin.utils.InputTypeUtils import helium314.keyboard.latin.utils.InputTypeUtils
import helium314.keyboard.latin.utils.LayoutType
import helium314.keyboard.latin.utils.Log import helium314.keyboard.latin.utils.Log
import helium314.keyboard.latin.utils.ToolbarKey import helium314.keyboard.latin.utils.ToolbarKey
import helium314.keyboard.latin.utils.getCodeForToolbarKey import helium314.keyboard.latin.utils.getCodeForToolbarKey
@ -482,8 +483,7 @@ sealed interface KeyData : AbstractKeyData {
KeyLabel.DELETE -> "!icon/delete_key|!code/key_delete" KeyLabel.DELETE -> "!icon/delete_key|!code/key_delete"
KeyLabel.SHIFT -> "${getShiftLabel(params)}|!code/key_shift" KeyLabel.SHIFT -> "${getShiftLabel(params)}|!code/key_shift"
// KeyLabel.EMOJI -> "!icon/emoji_normal_key|!code/key_emoji" // 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 -> params.mLocaleKeyboardInfos.tlds.first()
KeyLabel.COM -> ".com"
KeyLabel.LANGUAGE_SWITCH -> "!icon/language_switch_key|!code/key_language_switch" KeyLabel.LANGUAGE_SWITCH -> "!icon/language_switch_key|!code/key_language_switch"
KeyLabel.ZWNJ -> "!icon/zwnj_key|\u200C" KeyLabel.ZWNJ -> "!icon/zwnj_key|\u200C"
KeyLabel.CURRENCY -> params.mLocaleKeyboardInfos.currencyKey.first KeyLabel.CURRENCY -> params.mLocaleKeyboardInfos.currencyKey.first
@ -526,8 +526,11 @@ sealed interface KeyData : AbstractKeyData {
return when (label) { return when (label) {
KeyLabel.ALPHA, KeyLabel.SYMBOL_ALPHA, KeyLabel.SYMBOL -> Key.LABEL_FLAGS_PRESERVE_CASE or Key.LABEL_FLAGS_FOLLOW_FUNCTIONAL_TEXT_COLOR 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 KeyLabel.COMMA -> Key.LABEL_FLAGS_HAS_POPUP_HINT
// essentially this only changes the appearance of the armenian period key in holo theme // 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 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 -> { KeyLabel.ACTION -> {
Key.LABEL_FLAGS_PRESERVE_CASE or Key.LABEL_FLAGS_AUTO_X_SCALE or 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 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>? { private fun getAdditionalPopupKeys(params: KeyboardParams): PopupSet<AbstractKeyData>? {
if (groupId == GROUP_COMMA) return SimplePopups(getCommaPopupKeys(params)) 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_ENTER) return getActionKeyPopupKeys(params)
if (groupId == GROUP_NO_DEFAULT_POPUP) return null if (groupId == GROUP_NO_DEFAULT_POPUP) return null
return when (label) { return when (label) {
KeyLabel.COMMA -> SimplePopups(getCommaPopupKeys(params)) KeyLabel.COMMA -> SimplePopups(getCommaPopupKeys(params))
KeyLabel.PERIOD -> SimplePopups(getPunctuationPopupKeys(params)) KeyLabel.PERIOD -> getPeriodPopups(params)
KeyLabel.ACTION -> getActionKeyPopupKeys(params) KeyLabel.ACTION -> getActionKeyPopupKeys(params)
KeyLabel.SHIFT -> { KeyLabel.SHIFT -> {
if (params.mId.isAlphabetKeyboard) SimplePopups( if (params.mId.isAlphabetKeyboard) SimplePopups(
@ -561,13 +564,27 @@ sealed interface KeyData : AbstractKeyData {
) )
) else null // why the alphabet popup keys actually? ) 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")) KeyLabel.ZWNJ -> SimplePopups(listOf("!icon/zwj_key|\u200D"))
// only add currency popups if there are none defined on the key // only add currency popups if there are none defined on the key
KeyLabel.CURRENCY -> if (popup.isEmpty()) SimplePopups(params.mLocaleKeyboardInfos.currencyKey.second) else null KeyLabel.CURRENCY -> if (popup.isEmpty()) SimplePopups(params.mLocaleKeyboardInfos.currencyKey.second) else null
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) KeyboardTheme.writeUserMoreColors(prefs, themeNameNight, moreColorsNight)
} }
if (prefs.contains("theme_dark_color_all_colors")) { 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() prefs.edit().remove("theme_dark_color_all_colors").apply()
KeyboardTheme.writeUserAllColors(prefs, themeNameNight, allColorsNight) 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() prefs.edit().remove("auto_correction_confidence").putFloat(Settings.PREF_AUTO_CORRECT_THRESHOLD, value).apply()
} }
} }
if (oldVersion <= 2310) { if (oldVersion <= 2310) {
listOf( listOf(
Settings.PREF_ENABLED_SUBTYPES, Settings.PREF_ENABLED_SUBTYPES,
Settings.PREF_SELECTED_SUBTYPE, Settings.PREF_SELECTED_SUBTYPE,
Settings.PREF_ADDITIONAL_SUBTYPES Settings.PREF_ADDITIONAL_SUBTYPES
).forEach { key -> ).forEach { key ->
val value = prefs.getString(key, "")!! val value = prefs.getString(key, "")!!
if ("bengali," in value) { if ("bengali," in value) {
prefs.edit().putString(key, value.replace("bengali,", "bengali_inscript,")).apply() 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) upgradeToolbarPrefs(prefs)
LayoutUtilsCustom.onLayoutFileChanged() // just to be sure LayoutUtilsCustom.onLayoutFileChanged() // just to be sure
prefs.edit { putInt(Settings.PREF_VERSION_CODE, BuildConfig.VERSION_CODE) } prefs.edit { putInt(Settings.PREF_VERSION_CODE, BuildConfig.VERSION_CODE) }

View file

@ -2,18 +2,12 @@
package helium314.keyboard.latin package helium314.keyboard.latin
import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializable 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 @Serializable
data class ClipboardHistoryEntry ( data class ClipboardHistoryEntry (
var timeStamp: Long, var timeStamp: Long,
@Serializable(with = CharSequenceStringSerializer::class) val content: String,
val content: CharSequence,
var isPinned: Boolean = false var isPinned: Boolean = false
) : Comparable<ClipboardHistoryEntry> { ) : Comparable<ClipboardHistoryEntry> {
override fun compareTo(other: ClipboardHistoryEntry): Int { override fun compareTo(other: ClipboardHistoryEntry): Int {
@ -21,13 +15,3 @@ data class ClipboardHistoryEntry (
return if (result != 0) result else other.timeStamp.compareTo(timeStamp) 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) val content = clipItem.coerceToText(latinIME)
if (TextUtils.isEmpty(content)) return 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) { if (duplicateEntryIndex != -1) {
val existingEntry = historyEntries[duplicateEntryIndex] val existingEntry = historyEntries[duplicateEntryIndex]
if (existingEntry.timeStamp == timeStamp) return // nothing to change (may occur frequently starting with API 30) 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) onHistoryChangeListener?.onClipboardHistoryEntryMoved(duplicateEntryIndex, newIndex)
return 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) historyEntries.add(entry)
sortHistoryEntries() sortHistoryEntries()
val at = historyEntries.indexOf(entry) val at = historyEntries.indexOf(entry)
@ -120,7 +120,7 @@ class ClipboardHistoryManager(
private fun checkClipRetentionElapsed() { private fun checkClipRetentionElapsed() {
val mins = latinIME.mSettings.current.mClipboardHistoryRetentionTime 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 maxClipRetentionTime = mins * 60 * 1000L
val now = System.currentTimeMillis() val now = System.currentTimeMillis()
historyEntries.removeAll { !it.isPinned && (now - it.timeStamp) > maxClipRetentionTime } historyEntries.removeAll { !it.isPinned && (now - it.timeStamp) > maxClipRetentionTime }

View file

@ -7,6 +7,7 @@
package helium314.keyboard.latin; package helium314.keyboard.latin;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
@ -100,7 +101,6 @@ import java.util.concurrent.TimeUnit;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi; import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AlertDialog;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
/** /**
@ -523,6 +523,11 @@ public class LatinIME extends InputMethodService implements
} }
final class SubtypeState { 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 InputMethodSubtype mLastActiveSubtype;
private boolean mCurrentSubtypeHasBeenUsed = true; // starting with true avoids immediate switch private boolean mCurrentSubtypeHasBeenUsed = true; // starting with true avoids immediate switch
@ -530,6 +535,70 @@ public class LatinIME extends InputMethodService implements
mCurrentSubtypeHasBeenUsed = true; 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) { public void switchSubtype(final RichInputMethodManager richImm) {
final InputMethodSubtype currentSubtype = richImm.getCurrentSubtype().getRawSubtype(); final InputMethodSubtype currentSubtype = richImm.getCurrentSubtype().getRawSubtype();
final InputMethodSubtype lastActiveSubtype = mLastActiveSubtype; final InputMethodSubtype lastActiveSubtype = mLastActiveSubtype;
@ -858,6 +927,8 @@ public class LatinIME extends InputMethodService implements
return; return;
} }
InputMethodSubtype oldSubtype = mRichImm.getCurrentSubtype().getRawSubtype(); InputMethodSubtype oldSubtype = mRichImm.getCurrentSubtype().getRawSubtype();
mSubtypeState.onSubtypeChanged(oldSubtype, subtype);
StatsUtils.onSubtypeChanged(oldSubtype, subtype); StatsUtils.onSubtypeChanged(oldSubtype, subtype);
mRichImm.onSubtypeChanged(subtype); mRichImm.onSubtypeChanged(subtype);
mInputLogic.onSubtypeChanged(SubtypeLocaleUtils.getCombiningRulesExtraValue(subtype), mInputLogic.onSubtypeChanged(SubtypeLocaleUtils.getCombiningRulesExtraValue(subtype),
@ -876,20 +947,10 @@ public class LatinIME extends InputMethodService implements
super.onStartInput(editorInfo, restarting); super.onStartInput(editorInfo, restarting);
final List<Locale> hintLocales = EditorInfoCompatUtils.getHintLocales(editorInfo); final List<Locale> hintLocales = EditorInfoCompatUtils.getHintLocales(editorInfo);
if (hintLocales == null) { final InputMethodSubtype subtypeForLocales = mSubtypeState.getSubtypeForLocales(mRichImm, hintLocales);
return; if (subtypeForLocales != null) {
} // found a better subtype using hint locales that we should switch to.
// Try switching to a subtype matching the hint language. mHandler.postSwitchLanguage(subtypeForLocales);
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;
} }
} }

View file

@ -474,6 +474,10 @@ public final class WordComposer {
return mIsBatchMode; return mIsBatchMode;
} }
public void unsetBatchMode() {
mIsBatchMode = false;
}
public void setRejectedBatchModeSuggestion(final String rejectedSuggestion) { public void setRejectedBatchModeSuggestion(final String rejectedSuggestion) {
mRejectedBatchModeSuggestion = 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) { override fun get(color: ColorType): Int = when (color) {
TOOL_BAR_KEY_ENABLED_BACKGROUND, EMOJI_CATEGORY_SELECTED, ACTION_KEY_BACKGROUND, TOOL_BAR_KEY_ENABLED_BACKGROUND, EMOJI_CATEGORY_SELECTED, ACTION_KEY_BACKGROUND,
CLIPBOARD_PIN, SHIFT_KEY_ICON -> accent 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 TOOL_BAR_EXPAND_KEY_BACKGROUND -> if (!isNight) accent else doubleAdjustedBackground
GESTURE_TRAIL -> gesture 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_ICON, ONE_HANDED_MODE_BUTTON, EMOJI_CATEGORY, TOOL_BAR_KEY, FUNCTIONAL_KEY_TEXT -> keyText
KEY_HINT_TEXT -> keyHintText KEY_HINT_TEXT -> keyHintText
SPACE_BAR_TEXT -> spaceBarText 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 EMOJI_CATEGORY_SELECTED, CLIPBOARD_PIN, SHIFT_KEY_ICON -> accentColorFilter
REMOVE_SUGGESTION_ICON, EMOJI_CATEGORY, KEY_TEXT, REMOVE_SUGGESTION_ICON, EMOJI_CATEGORY, KEY_TEXT,
KEY_ICON, ONE_HANDED_MODE_BUTTON, TOOL_BAR_KEY, TOOL_BAR_EXPAND_KEY -> keyTextFilter 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 ACTION_KEY_ICON -> actionKeyIconColorFilter
else -> colorFilter(get(color)) else -> colorFilter(get(color))
} }
@ -336,7 +336,7 @@ class DynamicColors(context: Context, override val themeStyle: String, override
if (view.background == null) if (view.background == null)
view.setBackgroundColor(Color.WHITE) // set white to make the color filters work view.setBackgroundColor(Color.WHITE) // set white to make the color filters work
when (color) { 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) 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) ONE_HANDED_MODE_BUTTON -> setColor(view.background, if (keyboardBackground == null) MAIN_BACKGROUND else STRIP_BACKGROUND)
MORE_SUGGESTIONS_BACKGROUND -> view.background.colorFilter = backgroundFilter MORE_SUGGESTIONS_BACKGROUND -> view.background.colorFilter = backgroundFilter
@ -472,10 +472,11 @@ class DefaultColors (
TOOL_BAR_KEY_ENABLED_BACKGROUND, EMOJI_CATEGORY_SELECTED, ACTION_KEY_BACKGROUND, TOOL_BAR_KEY_ENABLED_BACKGROUND, EMOJI_CATEGORY_SELECTED, ACTION_KEY_BACKGROUND,
CLIPBOARD_PIN, SHIFT_KEY_ICON -> accent CLIPBOARD_PIN, SHIFT_KEY_ICON -> accent
AUTOFILL_BACKGROUND_CHIP -> if (themeStyle == STYLE_MATERIAL && !hasKeyBorders) background else adjustedBackground 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 TOOL_BAR_EXPAND_KEY_BACKGROUND, CLIPBOARD_SUGGESTION_BACKGROUND -> doubleAdjustedBackground
GESTURE_TRAIL -> gesture 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 KEY_HINT_TEXT -> keyHintText
SPACE_BAR_TEXT -> spaceBarText SPACE_BAR_TEXT -> spaceBarText
FUNCTIONAL_KEY_BACKGROUND -> functionalKey FUNCTIONAL_KEY_BACKGROUND -> functionalKey
@ -524,7 +525,7 @@ class DefaultColors (
if (view.background == null) if (view.background == null)
view.setBackgroundColor(Color.WHITE) // set white to make the color filters work view.setBackgroundColor(Color.WHITE) // set white to make the color filters work
when (color) { 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) 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) ONE_HANDED_MODE_BUTTON -> setColor(view.background, if (keyboardBackground == null) MAIN_BACKGROUND else STRIP_BACKGROUND)
MORE_SUGGESTIONS_BACKGROUND -> view.background.colorFilter = backgroundFilter MORE_SUGGESTIONS_BACKGROUND -> view.background.colorFilter = backgroundFilter
@ -547,7 +548,7 @@ class DefaultColors (
EMOJI_CATEGORY_SELECTED, CLIPBOARD_PIN, SHIFT_KEY_ICON -> accentColorFilter EMOJI_CATEGORY_SELECTED, CLIPBOARD_PIN, SHIFT_KEY_ICON -> accentColorFilter
KEY_TEXT, KEY_ICON -> keyTextFilter KEY_TEXT, KEY_ICON -> keyTextFilter
REMOVE_SUGGESTION_ICON, EMOJI_CATEGORY, ONE_HANDED_MODE_BUTTON, TOOL_BAR_KEY, TOOL_BAR_EXPAND_KEY -> suggestionTextFilter 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 ACTION_KEY_ICON -> actionKeyIconColorFilter
else -> colorFilter(get(color)) // create color filter (not great for performance, so the frequently used filters should be stored) 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, CLIPBOARD_PIN,
EMOJI_CATEGORY, EMOJI_CATEGORY,
EMOJI_CATEGORY_SELECTED, EMOJI_CATEGORY_SELECTED,
EMOJI_KEY_TEXT,
FUNCTIONAL_KEY_TEXT, FUNCTIONAL_KEY_TEXT,
FUNCTIONAL_KEY_BACKGROUND, FUNCTIONAL_KEY_BACKGROUND,
GESTURE_TRAIL, GESTURE_TRAIL,
@ -628,11 +630,13 @@ enum class ColorType {
KEY_ICON, KEY_ICON,
KEY_TEXT, KEY_TEXT,
KEY_HINT_TEXT, KEY_HINT_TEXT,
KEY_PREVIEW, KEY_PREVIEW_BACKGROUND,
KEY_PREVIEW_TEXT,
MORE_SUGGESTIONS_HINT, MORE_SUGGESTIONS_HINT,
MORE_SUGGESTIONS_BACKGROUND, MORE_SUGGESTIONS_BACKGROUND,
MORE_SUGGESTIONS_WORD_BACKGROUND, MORE_SUGGESTIONS_WORD_BACKGROUND,
POPUP_KEYS_BACKGROUND, POPUP_KEYS_BACKGROUND,
POPUP_KEY_TEXT,
NAVIGATION_BAR, NAVIGATION_BAR,
SHIFT_KEY_ICON, SHIFT_KEY_ICON,
SPACE_BAR_BACKGROUND, 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.ScriptUtils;
import helium314.keyboard.latin.utils.StatsUtils; import helium314.keyboard.latin.utils.StatsUtils;
import helium314.keyboard.latin.utils.TextRange; import helium314.keyboard.latin.utils.TextRange;
import helium314.keyboard.latin.utils.TimestampKt;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Locale; import java.util.Locale;
@ -323,7 +324,8 @@ public final class InputLogic {
// Don't allow cancellation of manual pick // Don't allow cancellation of manual pick
mLastComposedWord.deactivate(); mLastComposedWord.deactivate();
// Space state must be updated before calling updateShiftState // Space state must be updated before calling updateShiftState
mSpaceState = SpaceState.PHANTOM; if (settingsValues.mAutospaceAfterSuggestion)
mSpaceState = SpaceState.PHANTOM;
inputTransaction.requireShiftUpdate(InputTransaction.SHIFT_UPDATE_NOW); inputTransaction.requireShiftUpdate(InputTransaction.SHIFT_UPDATE_NOW);
// If we're not showing the "Touch again to save", then update the suggestion strip. // 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)) { || settingsValues.isUsuallyFollowedBySpace(codePointBeforeCursor)) {
final boolean autoShiftHasBeenOverriden = keyboardSwitcher.getKeyboardShiftMode() != final boolean autoShiftHasBeenOverriden = keyboardSwitcher.getKeyboardShiftMode() !=
getCurrentAutoCapsState(settingsValues); getCurrentAutoCapsState(settingsValues);
mSpaceState = SpaceState.PHANTOM; if (settingsValues.mAutospaceBeforeGestureTyping)
mSpaceState = SpaceState.PHANTOM;
if (!autoShiftHasBeenOverriden) { if (!autoShiftHasBeenOverriden) {
// When we change the space state, we need to update the shift state of the // 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 // keyboard unless it has been overridden manually. This is happening for example
@ -686,10 +689,7 @@ public final class InputLogic {
if (mSuggestedWords.isPrediction()) { if (mSuggestedWords.isPrediction()) {
inputTransaction.setRequiresUpdateSuggestions(); inputTransaction.setRequiresUpdateSuggestions();
} }
// undo phantom space if it's because after punctuation if (mSpaceState == SpaceState.PHANTOM && inputTransaction.getMSettingsValues().mShiftRemovesAutospace)
// users who want to start a sentence with a lowercase letter may not like it
if (mSpaceState == SpaceState.PHANTOM
&& inputTransaction.getMSettingsValues().isUsuallyFollowedBySpace(mConnection.getCodePointBeforeCursor()))
mSpaceState = SpaceState.NONE; mSpaceState = SpaceState.NONE;
break; break;
case KeyCode.SETTINGS: case KeyCode.SETTINGS:
@ -776,6 +776,9 @@ public final class InputLogic {
case KeyCode.SPLIT_LAYOUT: case KeyCode.SPLIT_LAYOUT:
KeyboardSwitcher.getInstance().toggleSplitKeyboardMode(); KeyboardSwitcher.getInstance().toggleSplitKeyboardMode();
break; break;
case KeyCode.TIMESTAMP:
mLatinIME.onTextInput(TimestampKt.getTimestamp(mLatinIME));
break;
case KeyCode.VOICE_INPUT: case KeyCode.VOICE_INPUT:
// switching to shortcut IME, shift state, keyboard,... is handled by LatinIME, // 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)}. // {@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 // handleNonSpecialCharacterEvent which has the same name as other handle* methods but is
// not the same. // not the same.
boolean isComposingWord = mWordComposer.isComposingWord(); 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 // if we continue directly after a sometimesWordConnector, restart suggestions for the whole word
// (only with URL detection and suggestions enabled) // (only with URL detection and suggestions enabled)
@ -949,7 +953,9 @@ public final class InputLogic {
// TODO: remove isWordConnector() and use isUsuallyFollowedBySpace() instead. // TODO: remove isWordConnector() and use isUsuallyFollowedBySpace() instead.
// See onStartBatchInput() to see how to do it. // See onStartBatchInput() to see how to do it.
if (SpaceState.PHANTOM == inputTransaction.getMSpaceState() if (SpaceState.PHANTOM == inputTransaction.getMSpaceState()
&& !settingsValues.isWordConnector(codePoint)) { && !settingsValues.isWordConnector(codePoint)
&& !settingsValues.isUsuallyFollowedBySpace(codePoint) // only relevant in rare cases
) {
if (isComposingWord) { if (isComposingWord) {
// Sanity check // Sanity check
throw new RuntimeException("Should not be composing here"); 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 behaves like it's usually followed by space if we're inside
// a double quote. // a double quote.
if (wasComposingWord if (wasComposingWord
&& settingsValues.mAutospaceAfterPunctuationEnabled && settingsValues.mAutospaceAfterPunctuation
&& (settingsValues.isUsuallyFollowedBySpace(codePoint) || isInsideDoubleQuoteOrAfterDigit)) { && (settingsValues.isUsuallyFollowedBySpace(codePoint) || isInsideDoubleQuoteOrAfterDigit)) {
mSpaceState = SpaceState.PHANTOM; mSpaceState = SpaceState.PHANTOM;
} }
@ -1196,7 +1202,7 @@ public final class InputLogic {
} }
inputTransaction.setRequiresUpdateSuggestions(); inputTransaction.setRequiresUpdateSuggestions();
} else { } else {
if (mLastComposedWord.canRevertCommit()) { if (mLastComposedWord.canRevertCommit() && inputTransaction.getMSettingsValues().mBackspaceRevertsAutocorrect) {
final String lastComposedWord = mLastComposedWord.mTypedWord; final String lastComposedWord = mLastComposedWord.mTypedWord;
revertCommit(inputTransaction); revertCommit(inputTransaction);
StatsUtils.onRevertAutoCorrect(); StatsUtils.onRevertAutoCorrect();
@ -2168,6 +2174,7 @@ public final class InputLogic {
&& !(mConnection.getCodePointBeforeCursor() == Constants.CODE_PERIOD && mConnection.wordBeforeCursorMayBeEmail()) && !(mConnection.getCodePointBeforeCursor() == Constants.CODE_PERIOD && mConnection.wordBeforeCursorMayBeEmail())
) { ) {
mConnection.commitCodePoint(Constants.CODE_SPACE); mConnection.commitCodePoint(Constants.CODE_SPACE);
// todo: why not remove phantom space state?
} }
} }
@ -2202,12 +2209,14 @@ public final class InputLogic {
mConnection.beginBatchEdit(); mConnection.beginBatchEdit();
if (SpaceState.PHANTOM == mSpaceState) { if (SpaceState.PHANTOM == mSpaceState) {
insertAutomaticSpaceIfOptionsAndTextAllow(settingsValues); insertAutomaticSpaceIfOptionsAndTextAllow(settingsValues);
mSpaceState = SpaceState.NONE;
} }
mWordComposer.setBatchInputWord(batchInputText); mWordComposer.setBatchInputWord(batchInputText);
setComposingTextInternal(batchInputText, 1); setComposingTextInternal(batchInputText, 1);
mConnection.endBatchEdit(); mConnection.endBatchEdit();
// Space state must be updated before calling updateShiftState // Space state must be updated before calling updateShiftState
mSpaceState = SpaceState.PHANTOM; if (settingsValues.mAutospaceAfterGestureTyping)
mSpaceState = SpaceState.PHANTOM;
keyboardSwitcher.requestUpdatingShiftState(getCurrentAutoCapsState(settingsValues), getCurrentRecapitalizeState()); 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.BuildConfig
import helium314.keyboard.latin.common.Constants.Separators import helium314.keyboard.latin.common.Constants.Separators
import helium314.keyboard.latin.common.Constants.Subtype.ExtraValue 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.LayoutType
import helium314.keyboard.latin.utils.POPUP_KEYS_LABEL_DEFAULT import helium314.keyboard.latin.utils.POPUP_KEYS_LABEL_DEFAULT
import helium314.keyboard.latin.utils.POPUP_KEYS_ORDER_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_MORE_AUTO_CORRECTION = false
const val PREF_AUTO_CORRECT_THRESHOLD = 0.185f const val PREF_AUTO_CORRECT_THRESHOLD = 0.185f
const val PREF_AUTOCORRECT_SHORTCUTS = true 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_CENTER_SUGGESTION_TEXT_TO_ENTER = false
const val PREF_SHOW_SUGGESTIONS = true const val PREF_SHOW_SUGGESTIONS = true
const val PREF_ALWAYS_SHOW_SUGGESTIONS = false 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_PERSONALIZED_DICTS = true
const val PREF_KEY_USE_DOUBLE_SPACE_PERIOD = true const val PREF_KEY_USE_DOUBLE_SPACE_PERIOD = true
const val PREF_BLOCK_POTENTIALLY_OFFENSIVE = true const val PREF_BLOCK_POTENTIALLY_OFFENSIVE = true
@ -92,6 +93,10 @@ object Defaults {
const val PREF_SPACE_VERTICAL_SWIPE = "none" const val PREF_SPACE_VERTICAL_SWIPE = "none"
const val PREF_DELETE_SWIPE = true const val PREF_DELETE_SWIPE = true
const val PREF_AUTOSPACE_AFTER_PUNCTUATION = false 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_ALWAYS_INCOGNITO_MODE = false
const val PREF_BIGRAM_PREDICTIONS = true const val PREF_BIGRAM_PREDICTIONS = true
const val PREF_SUGGEST_CLIPBOARD_CONTENT = 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_ORDER = POPUP_KEYS_ORDER_DEFAULT
const val PREF_POPUP_KEYS_LABELS_ORDER = POPUP_KEYS_LABEL_DEFAULT const val PREF_POPUP_KEYS_LABELS_ORDER = POPUP_KEYS_LABEL_DEFAULT
const val PREF_SHOW_POPUP_HINTS = false 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_MORE_POPUP_KEYS = "main"
const val PREF_SPACE_TO_CHANGE_LANG = true const val PREF_SPACE_TO_CHANGE_LANG = true
const val PREF_LANGUAGE_SWIPE_DISTANCE = 5 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_EMOJI = false
const val PREF_ABC_AFTER_CLIP = false const val PREF_ABC_AFTER_CLIP = false
const val PREF_ABC_AFTER_SYMBOL_SPACE = true 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_REMOVE_REDUNDANT_POPUPS = false
const val PREF_SPACE_BAR_TEXT = "" const val PREF_SPACE_BAR_TEXT = ""
const val PREF_TIMESTAMP_FORMAT = "yyyy-MM-dd HH:mm:ss"
@JvmField @JvmField
val PREF_EMOJI_MAX_SDK = Build.VERSION.SDK_INT val PREF_EMOJI_MAX_SDK = Build.VERSION.SDK_INT
const val PREF_EMOJI_RECENT_KEYS = "" const val PREF_EMOJI_RECENT_KEYS = ""
const val PREF_LAST_SHOWN_EMOJI_CATEGORY_PAGE_ID = 0 const val PREF_LAST_SHOWN_EMOJI_CATEGORY_PAGE_ID = 0
const val PREF_PINNED_CLIPS = "" const val PREF_PINNED_CLIPS = ""
@JvmField
val PREF_LIBRARY_CHECKSUM: String = JniUtils.expectedDefaultChecksum()
const val PREF_SHOW_DEBUG_SETTINGS = false const val PREF_SHOW_DEBUG_SETTINGS = false
val PREF_DEBUG_MODE = BuildConfig.DEBUG val PREF_DEBUG_MODE = BuildConfig.DEBUG
const val PREF_SHOW_SUGGESTION_INFOS = false 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_MORE_AUTO_CORRECTION = "more_auto_correction";
public static final String PREF_AUTO_CORRECT_THRESHOLD = "auto_correct_threshold"; 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_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_CENTER_SUGGESTION_TEXT_TO_ENTER = "center_suggestion_text_to_enter";
public static final String PREF_SHOW_SUGGESTIONS = "show_suggestions"; 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 = "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_PERSONALIZED_DICTS = "use_personalized_dicts";
public static final String PREF_KEY_USE_DOUBLE_SPACE_PERIOD = "use_double_space_period"; 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"; 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_SPACE_VERTICAL_SWIPE = "vertical_space_swipe";
public static final String PREF_DELETE_SWIPE = "delete_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_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_ALWAYS_INCOGNITO_MODE = "always_incognito_mode";
public static final String PREF_BIGRAM_PREDICTIONS = "next_word_prediction"; public static final String PREF_BIGRAM_PREDICTIONS = "next_word_prediction";
public static final String PREF_SUGGEST_CLIPBOARD_CONTENT = "suggest_clipboard_content"; 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_POPUP_KEYS_LABELS_ORDER = "popup_keys_labels_order";
public static final String PREF_SHOW_POPUP_HINTS = "show_popup_hints"; 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_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_SPACE_TO_CHANGE_LANG = "prefs_long_press_keyboard_to_change_lang";
public static final String PREF_LANGUAGE_SWIPE_DISTANCE = "language_swipe_distance"; 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_EMOJI = "abc_after_emoji";
public static final String PREF_ABC_AFTER_CLIP = "abc_after_clip"; 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_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_REMOVE_REDUNDANT_POPUPS = "remove_redundant_popups";
public static final String PREF_SPACE_BAR_TEXT = "space_bar_text"; public static final String PREF_SPACE_BAR_TEXT = "space_bar_text";
public static final String PREF_TIMESTAMP_FORMAT = "timestamp_format";
// Emoji // Emoji
public static final String PREF_EMOJI_MAX_SDK = "emoji_max_sdk"; 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.SharedPreferences;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.content.res.Resources; import android.content.res.Resources;
import android.text.InputType;
import android.view.inputmethod.EditorInfo; import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodSubtype; import android.view.inputmethod.InputMethodSubtype;
@ -65,6 +66,7 @@ public class SettingsValues {
public final boolean mShowNumberRowHints; public final boolean mShowNumberRowHints;
public final boolean mShowsHints; public final boolean mShowsHints;
public final boolean mShowsPopupHints; public final boolean mShowsPopupHints;
public final boolean mShowTldPopupKeys;
public final boolean mSpaceForLangChange; public final boolean mSpaceForLangChange;
public final boolean mShowsEmojiKey; public final boolean mShowsEmojiKey;
public final boolean mVarToolbarDirection; public final boolean mVarToolbarDirection;
@ -75,7 +77,11 @@ public class SettingsValues {
public final int mSpaceSwipeVertical; public final int mSpaceSwipeVertical;
public final int mLanguageSwipeDistance; public final int mLanguageSwipeDistance;
public final boolean mDeleteSwipeEnabled; 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 boolean mClipboardHistoryEnabled;
public final long mClipboardHistoryRetentionTime; public final long mClipboardHistoryRetentionTime;
public final boolean mOneHandedModeEnabled; public final boolean mOneHandedModeEnabled;
@ -113,6 +119,7 @@ public class SettingsValues {
public final boolean mAlphaAfterEmojiInEmojiView; public final boolean mAlphaAfterEmojiInEmojiView;
public final boolean mAlphaAfterClipHistoryEntry; public final boolean mAlphaAfterClipHistoryEntry;
public final boolean mAlphaAfterSymbolAndSpace; public final boolean mAlphaAfterSymbolAndSpace;
public final boolean mAlphaAfterNumpadAndSpace;
public final boolean mRemoveRedundantPopups; public final boolean mRemoveRedundantPopups;
public final String mSpaceBarText; public final String mSpaceBarText;
public final float mFontSizeMultiplier; public final float mFontSizeMultiplier;
@ -128,6 +135,7 @@ public class SettingsValues {
public final boolean mAutoCorrectionEnabledPerUserSettings; public final boolean mAutoCorrectionEnabledPerUserSettings;
public final boolean mAutoCorrectEnabled; public final boolean mAutoCorrectEnabled;
public final float mAutoCorrectionThreshold; public final float mAutoCorrectionThreshold;
public final boolean mBackspaceRevertsAutocorrect;
public final int mScoreLimitForAutocorrect; public final int mScoreLimitForAutocorrect;
public final boolean mAutoCorrectShortcuts; public final boolean mAutoCorrectShortcuts;
private final boolean mSuggestionsEnabledPerUserSettings; 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); 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); mShowsHints = prefs.getBoolean(Settings.PREF_SHOW_HINTS, Defaults.PREF_SHOW_HINTS);
mShowsPopupHints = prefs.getBoolean(Settings.PREF_SHOW_POPUP_HINTS, Defaults.PREF_SHOW_POPUP_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); 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); 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); 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 mScoreLimitForAutocorrect = (mAutoCorrectionThreshold < 0) ? 600000 // very aggressive
: (mAutoCorrectionThreshold < 0.07 ? 800000 : 950000); // aggressive or modest : (mAutoCorrectionThreshold < 0.07 ? 800000 : 950000); // aggressive or modest
mAutoCorrectShortcuts = prefs.getBoolean(Settings.PREF_AUTOCORRECT_SHORTCUTS, Defaults.PREF_AUTOCORRECT_SHORTCUTS); 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); mBigramPredictionEnabled = prefs.getBoolean(Settings.PREF_BIGRAM_PREDICTIONS, Defaults.PREF_BIGRAM_PREDICTIONS);
mSuggestClipboardContent = prefs.getBoolean(Settings.PREF_SUGGEST_CLIPBOARD_CONTENT, Defaults.PREF_SUGGEST_CLIPBOARD_CONTENT); mSuggestClipboardContent = prefs.getBoolean(Settings.PREF_SUGGEST_CLIPBOARD_CONTENT, Defaults.PREF_SUGGEST_CLIPBOARD_CONTENT);
mDoubleSpacePeriodTimeout = 1100; // ms 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); 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); mGestureTrailFadeoutDuration = prefs.getInt(Settings.PREF_GESTURE_TRAIL_FADEOUT_DURATION, Defaults.PREF_GESTURE_TRAIL_FADEOUT_DURATION);
mAccount = null; // remove? or can it be useful somewhere? 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); final boolean suggestionsEnabled = prefs.getBoolean(Settings.PREF_SHOW_SUGGESTIONS, Defaults.PREF_SHOW_SUGGESTIONS);
mSuggestionsEnabledPerUserSettings = (mInputAttributes.mShouldShowSuggestions && suggestionsEnabled) mSuggestionsEnabledPerUserSettings = (mInputAttributes.mShouldShowSuggestions && suggestionsEnabled)
|| mOverrideShowingSuggestions; || mOverrideShowingSuggestions;
@ -229,7 +242,11 @@ public class SettingsValues {
mSpaceSwipeVertical = Settings.readVerticalSpaceSwipe(prefs); mSpaceSwipeVertical = Settings.readVerticalSpaceSwipe(prefs);
mLanguageSwipeDistance = prefs.getInt(Settings.PREF_LANGUAGE_SWIPE_DISTANCE, Defaults.PREF_LANGUAGE_SWIPE_DISTANCE); mLanguageSwipeDistance = prefs.getInt(Settings.PREF_LANGUAGE_SWIPE_DISTANCE, Defaults.PREF_LANGUAGE_SWIPE_DISTANCE);
mDeleteSwipeEnabled = prefs.getBoolean(Settings.PREF_DELETE_SWIPE, Defaults.PREF_DELETE_SWIPE); 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); 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); 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); 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); 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); 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); 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); 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); mEmojiMaxSdk = prefs.getInt(Settings.PREF_EMOJI_MAX_SDK, Defaults.PREF_EMOJI_MAX_SDK);

View file

@ -1,7 +1,7 @@
package helium314.keyboard.latin.utils package helium314.keyboard.latin.utils
import android.content.Context import android.content.Context
import androidx.appcompat.view.ContextThemeWrapper import android.view.ContextThemeWrapper
import helium314.keyboard.latin.R import helium314.keyboard.latin.R
// todo: ideally the custom InputMethodPicker would be removed / replaced with compose dialog, then this can be removed // 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 package helium314.keyboard.latin.utils
import android.app.AlertDialog
import android.os.IBinder import android.os.IBinder
import android.text.Spannable import android.text.Spannable
import android.text.SpannableString import android.text.SpannableString
@ -10,7 +11,6 @@ import android.text.style.RelativeSizeSpan
import android.view.WindowManager import android.view.WindowManager
import android.view.inputmethod.InputMethodInfo import android.view.inputmethod.InputMethodInfo
import android.view.inputmethod.InputMethodSubtype import android.view.inputmethod.InputMethodSubtype
import androidx.appcompat.app.AlertDialog
import helium314.keyboard.latin.LatinIME import helium314.keyboard.latin.LatinIME
import helium314.keyboard.latin.R import helium314.keyboard.latin.R
import helium314.keyboard.latin.RichInputMethodManager import helium314.keyboard.latin.RichInputMethodManager

View file

@ -13,7 +13,6 @@ import android.text.TextUtils;
import helium314.keyboard.latin.App; import helium314.keyboard.latin.App;
import helium314.keyboard.latin.BuildConfig; import helium314.keyboard.latin.BuildConfig;
import helium314.keyboard.latin.settings.Defaults;
import helium314.keyboard.latin.settings.Settings; import helium314.keyboard.latin.settings.Settings;
import java.io.File; 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 // 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() // see https://developer.android.com/reference/android/content/Context#createDeviceProtectedStorageContext()
// if device is locked, this will throw an IllegalStateException // 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 FileInputStream libStream = new FileInputStream(userSuppliedLibrary);
final String checksum = ChecksumCalculator.INSTANCE.checksum(libStream); final String checksum = ChecksumCalculator.INSTANCE.checksum(libStream);

View file

@ -162,7 +162,7 @@ object ScriptUtils {
return SCRIPT_LATIN return SCRIPT_LATIN
} }
return when (language) { return when (language) {
"ar", "ur", "fa" -> SCRIPT_ARABIC "ar", "ckb", "ur", "fa" -> SCRIPT_ARABIC
"hy" -> SCRIPT_ARMENIAN "hy" -> SCRIPT_ARMENIAN
"bn" -> SCRIPT_BENGALI "bn" -> SCRIPT_BENGALI
"sr", "mk", "ru", "uk", "mn", "be", "kk", "ky", "bg", "xdq", "cv", "mhr", "mns", "dru" -> SCRIPT_CYRILLIC "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 // SPDX-License-Identifier: GPL-3.0-only
package helium314.keyboard.settings 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.clickable
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@ -17,8 +22,15 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier 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.compose.ui.unit.dp
import androidx.core.content.ContextCompat
import androidx.core.graphics.drawable.toBitmap
import androidx.core.util.TypedValueCompat
@Composable @Composable
fun WithSmallTitle( 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 @Composable
fun <T>DropDownField( fun <T>DropDownField(
items: List<T>, 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, title: @Composable () -> Unit,
filteredItems: (String) -> List<T>, filteredItems: (String) -> List<T>,
itemContent: @Composable (T) -> Unit, itemContent: @Composable (T) -> Unit,
icon: @Composable (() -> Unit)? = null,
menu: List<Pair<String, () -> Unit>>? = null, menu: List<Pair<String, () -> Unit>>? = null,
content: @Composable (ColumnScope.() -> Unit)? = null, content: @Composable (ColumnScope.() -> Unit)? = null,
) { ) {
@ -137,8 +138,10 @@ fun <T: Any?> SearchScreen(
} }
}, },
actions = { actions = {
IconButton(onClick = { setShowSearch(!showSearch) }) if (icon == null)
{ SearchIcon() } IconButton(onClick = { setShowSearch(!showSearch) }) { SearchIcon() }
else
icon()
if (menu != null) if (menu != null)
Box { Box {
var showMenu by remember { mutableStateOf(false) } var showMenu by remember { mutableStateOf(false) }
@ -227,7 +230,8 @@ fun ExpandableSearchField(
else onSearchChange(TextFieldValue()) else onSearchChange(TextFieldValue())
}) { CloseIcon(android.R.string.cancel) } }, }) { CloseIcon(android.R.string.cancel) } },
singleLine = true, singleLine = true,
colors = colors colors = colors,
textStyle = contentTextDirectionStyle
) )
} }
} }

View file

@ -1,16 +1,22 @@
// SPDX-License-Identifier: GPL-3.0-only // SPDX-License-Identifier: GPL-3.0-only
package helium314.keyboard.settings 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.slideInHorizontally
import androidx.compose.animation.slideOutHorizontally import androidx.compose.animation.slideOutHorizontally
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.LayoutDirection
import androidx.navigation.compose.NavHost import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
import helium314.keyboard.latin.common.LocaleUtils.constructLocale 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.AboutScreen
import helium314.keyboard.settings.screens.AdvancedSettingsScreen import helium314.keyboard.settings.screens.AdvancedSettingsScreen
import helium314.keyboard.settings.screens.AppearanceScreen 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.PersonalDictionaryScreen
import helium314.keyboard.settings.screens.PreferencesScreen import helium314.keyboard.settings.screens.PreferencesScreen
import helium314.keyboard.settings.screens.SecondaryLayoutScreen import helium314.keyboard.settings.screens.SecondaryLayoutScreen
import helium314.keyboard.settings.screens.SubtypeScreen
import helium314.keyboard.settings.screens.TextCorrectionScreen import helium314.keyboard.settings.screens.TextCorrectionScreen
import helium314.keyboard.settings.screens.ToolbarScreen import helium314.keyboard.settings.screens.ToolbarScreen
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
@ -41,6 +48,10 @@ fun SettingsNavHost(
val dir = if (LocalLayoutDirection.current == LayoutDirection.Ltr) 1 else -1 val dir = if (LocalLayoutDirection.current == LayoutDirection.Ltr) 1 else -1
val target = SettingsDestination.navTarget.collectAsState() 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() { fun goBack() {
if (!navController.popBackStack()) onClickBack() if (!navController.popBackStack()) onClickBack()
} }
@ -48,10 +59,10 @@ fun SettingsNavHost(
NavHost( NavHost(
navController = navController, navController = navController,
startDestination = startDestination ?: SettingsDestination.Settings, startDestination = startDestination ?: SettingsDestination.Settings,
enterTransition = { slideInHorizontally(initialOffsetX = { +it * dir }) }, enterTransition = { slideInHorizontally(initialOffsetX = { +it * dir }, animationSpec = animation) },
exitTransition = { slideOutHorizontally(targetOffsetX = { -it * dir }) }, exitTransition = { slideOutHorizontally(targetOffsetX = { -it * dir }, animationSpec = animation) },
popEnterTransition = { slideInHorizontally(initialOffsetX = { -it * dir }) }, popEnterTransition = { slideInHorizontally(initialOffsetX = { -it * dir }, animationSpec = animation) },
popExitTransition = { slideOutHorizontally(targetOffsetX = { +it * dir }) } popExitTransition = { slideOutHorizontally(targetOffsetX = { +it * dir }, animationSpec = animation) }
) { ) {
composable(SettingsDestination.Settings) { composable(SettingsDestination.Settings) {
MainSettingsScreen( MainSettingsScreen(
@ -117,6 +128,9 @@ fun SettingsNavHost(
composable(SettingsDestination.ColorsNight + "{theme}") { composable(SettingsDestination.ColorsNight + "{theme}") {
ColorsScreen(isNight = true, theme = it.arguments?.getString("theme"), onClickBack = ::goBack) 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*/) if (target.value != SettingsDestination.Settings/* && target.value != navController.currentBackStackEntry?.destination?.route*/)
navController.navigate(route = target.value) navController.navigate(route = target.value)
@ -137,6 +151,7 @@ object SettingsDestination {
const val PersonalDictionaries = "personal_dictionaries" const val PersonalDictionaries = "personal_dictionaries"
const val PersonalDictionary = "personal_dictionary/" const val PersonalDictionary = "personal_dictionary/"
const val Languages = "languages" const val Languages = "languages"
const val Subtype = "subtype/"
const val Layouts = "layouts" const val Layouts = "layouts"
const val Dictionaries = "dictionaries" const val Dictionaries = "dictionaries"
val navTarget = MutableStateFlow(Settings) 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.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.Surface import androidx.compose.material3.Surface
import androidx.compose.material3.Text 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.graphics.toArgb
import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.text.TextRange 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.KeyboardType
import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
@ -109,8 +111,12 @@ fun ColorPickerDialog(
) )
TextField( TextField(
value = textValue, value = textValue,
// todo: KeyboardType.Password is a crappy way of avoiding suggestions... is there really no way in compose? keyboardOptions = KeyboardOptions(
keyboardOptions = KeyboardOptions(autoCorrectEnabled = false, keyboardType = KeyboardType.Password), 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 = { onValueChange = {
textValue = it textValue = it
val androidColor = runCatching { android.graphics.Color.parseColor("#${it.text}") }.getOrNull() 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.filePicker
import helium314.keyboard.settings.previewDark import helium314.keyboard.settings.previewDark
import helium314.keyboard.settings.screens.SaveThoseColors import helium314.keyboard.settings.screens.SaveThoseColors
import helium314.keyboard.settings.contentTextDirectionStyle
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.serialization.SerializationException import kotlinx.serialization.SerializationException
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
@ -187,7 +188,8 @@ private fun AddColorRow(onDismissRequest: () -> Unit, userColors: Collection<Str
onValueChange = { textValue = it }, onValueChange = { textValue = it },
modifier = Modifier.weight(1f), modifier = Modifier.weight(1f),
singleLine = true, singleLine = true,
label = label label = label,
textStyle = contentTextDirectionStyle,
) )
EditButton(currentName.isNotBlank() && currentName !in userColors) { EditButton(currentName.isNotBlank() && currentName !in userColors) {
onDismissRequest() onDismissRequest()

View file

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

View file

@ -50,6 +50,7 @@ import helium314.keyboard.settings.EditButton
import helium314.keyboard.settings.Setting import helium314.keyboard.settings.Setting
import helium314.keyboard.settings.SettingsActivity import helium314.keyboard.settings.SettingsActivity
import helium314.keyboard.settings.Theme import helium314.keyboard.settings.Theme
import helium314.keyboard.settings.contentTextDirectionStyle
import helium314.keyboard.settings.layoutFilePicker import helium314.keyboard.settings.layoutFilePicker
import helium314.keyboard.settings.layoutIntent import helium314.keyboard.settings.layoutIntent
import helium314.keyboard.settings.previewDark import helium314.keyboard.settings.previewDark
@ -140,7 +141,8 @@ private fun AddLayoutRow(onNewLayout: (String) -> Unit, layoutType: LayoutType,
value = textValue, value = textValue,
onValueChange = { textValue = it }, onValueChange = { textValue = it },
modifier = Modifier.weight(1f), modifier = Modifier.weight(1f),
singleLine = true singleLine = true,
textStyle = contentTextDirectionStyle,
) )
EditButton(textValue.text.isNotEmpty() && LayoutUtilsCustom.getLayoutName(textValue.text, layoutType) !in userLayouts) { EditButton(textValue.text.isNotEmpty() && LayoutUtilsCustom.getLayoutName(textValue.text, layoutType) !in userLayouts) {
onNewLayout(textValue.text) 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.tooling.preview.Preview
import androidx.compose.ui.window.DialogProperties import androidx.compose.ui.window.DialogProperties
import helium314.keyboard.settings.Theme import helium314.keyboard.settings.Theme
import helium314.keyboard.settings.contentTextDirectionStyle
import helium314.keyboard.settings.previewDark import helium314.keyboard.settings.previewDark
// mostly taken from StreetComplete / SCEE // mostly taken from StreetComplete / SCEE
@ -76,7 +77,8 @@ fun TextInputDialog(
.focusRequester(focusRequester), .focusRequester(focusRequester),
label = textInputLabel, label = textInputLabel,
keyboardOptions = KeyboardOptions(keyboardType = keyboardType), keyboardOptions = KeyboardOptions(keyboardType = keyboardType),
singleLine = singleLine singleLine = singleLine,
textStyle = contentTextDirectionStyle,
) )
}, },
properties = properties, properties = properties,

View file

@ -35,10 +35,13 @@ fun LoadGestureLibPreference(setting: Setting) {
val abi = Build.SUPPORTED_ABIS[0] val abi = Build.SUPPORTED_ABIS[0]
val libFile = File(ctx.filesDir?.absolutePath + File.separator + JniUtils.JNI_LIB_IMPORT_FILE_NAME) val libFile = File(ctx.filesDir?.absolutePath + File.separator + JniUtils.JNI_LIB_IMPORT_FILE_NAME)
fun renameToLibFileAndRestart(file: File, checksum: String) { fun renameToLibFileAndRestart(file: File, checksum: String) {
libFile.setWritable(true)
libFile.delete() 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() 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 Runtime.getRuntime().exit(0) // exit will restart the app, so library will be loaded
} }
var tempFilePath: String? by rememberSaveable { mutableStateOf(null) } 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.fillMaxWidth
import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.LocalContentColor 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.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import helium314.keyboard.latin.R import helium314.keyboard.latin.R
import helium314.keyboard.settings.IconOrImage
import helium314.keyboard.settings.Theme import helium314.keyboard.settings.Theme
import helium314.keyboard.settings.previewDark import helium314.keyboard.settings.previewDark
@ -64,12 +64,12 @@ fun Preference(
.fillMaxWidth() .fillMaxWidth()
.clickable { onClick() } .clickable { onClick() }
.heightIn(min = 44.dp) .heightIn(min = 44.dp)
.padding(12.dp), .padding(vertical = 10.dp, horizontal = 12.dp),
horizontalArrangement = Arrangement.spacedBy(12.dp), horizontalArrangement = Arrangement.spacedBy(12.dp),
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
if (icon != null) if (icon != null)
Icon(painterResource(icon), name, modifier = Modifier.size(36.dp)) IconOrImage(icon, name, 32f)
Column(modifier = Modifier.weight(1f)) { Column(modifier = Modifier.weight(1f)) {
Text(text = name, style = MaterialTheme.typography.bodyLarge) Text(text = name, style = MaterialTheme.typography.bodyLarge)
if (description != null) { 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 package helium314.keyboard.settings.screens
import android.app.Activity import android.app.Activity
import android.app.AlertDialog
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.text.method.LinkMovementMethod import android.text.method.LinkMovementMethod
@ -10,7 +11,6 @@ import android.widget.TextView
import android.widget.Toast import android.widget.Toast
import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AlertDialog
import androidx.compose.material3.Surface import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
@ -69,7 +69,7 @@ fun createAboutSettings(context: Context) = listOf(
name = it.title, name = it.title,
description = it.description, description = it.description,
onClick = { }, 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) { 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.DebugSettings
import helium314.keyboard.latin.settings.Defaults import helium314.keyboard.latin.settings.Defaults
import helium314.keyboard.latin.settings.Settings import helium314.keyboard.latin.settings.Settings
import helium314.keyboard.latin.utils.checkTimestampFormat
import helium314.keyboard.latin.utils.prefs import helium314.keyboard.latin.utils.prefs
import helium314.keyboard.settings.NextScreenIcon import helium314.keyboard.settings.NextScreenIcon
import helium314.keyboard.settings.SettingsContainer import helium314.keyboard.settings.SettingsContainer
@ -45,6 +46,7 @@ import helium314.keyboard.settings.Theme
import helium314.keyboard.settings.dialogs.TextInputDialog import helium314.keyboard.settings.dialogs.TextInputDialog
import helium314.keyboard.settings.preferences.BackupRestorePreference import helium314.keyboard.settings.preferences.BackupRestorePreference
import helium314.keyboard.settings.preferences.LoadGestureLibPreference import helium314.keyboard.settings.preferences.LoadGestureLibPreference
import helium314.keyboard.settings.preferences.TextInputPreference
import helium314.keyboard.settings.previewDark import helium314.keyboard.settings.previewDark
@Composable @Composable
@ -66,10 +68,12 @@ fun AdvancedSettingsScreen(
Settings.PREF_ENABLE_EMOJI_ALT_PHYSICAL_KEY, Settings.PREF_ENABLE_EMOJI_ALT_PHYSICAL_KEY,
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) Settings.PREF_SHOW_SETUP_WIZARD_ICON else null, 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_SYMBOL_SPACE,
Settings.PREF_ABC_AFTER_NUMPAD_SPACE,
Settings.PREF_ABC_AFTER_EMOJI, Settings.PREF_ABC_AFTER_EMOJI,
Settings.PREF_ABC_AFTER_CLIP, Settings.PREF_ABC_AFTER_CLIP,
Settings.PREF_CUSTOM_CURRENCY_KEY, Settings.PREF_CUSTOM_CURRENCY_KEY,
Settings.PREF_MORE_POPUP_KEYS, Settings.PREF_MORE_POPUP_KEYS,
Settings.PREF_TIMESTAMP_FORMAT,
SettingsWithoutKey.BACKUP_RESTORE, SettingsWithoutKey.BACKUP_RESTORE,
if (BuildConfig.DEBUG || prefs.getBoolean(DebugSettings.PREF_SHOW_DEBUG_SETTINGS, Defaults.PREF_SHOW_DEBUG_SETTINGS)) if (BuildConfig.DEBUG || prefs.getBoolean(DebugSettings.PREF_SHOW_DEBUG_SETTINGS, Defaults.PREF_SHOW_DEBUG_SETTINGS))
SettingsWithoutKey.DEBUG_SETTINGS else null, SettingsWithoutKey.DEBUG_SETTINGS else null,
@ -154,6 +158,11 @@ fun createAdvancedSettings(context: Context) = listOf(
{ {
SwitchPreference(it, Defaults.PREF_ABC_AFTER_SYMBOL_SPACE) 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) { Setting(context, Settings.PREF_ABC_AFTER_EMOJI, R.string.switch_keyboard_after, R.string.after_emoji) {
SwitchPreference(it, Defaults.PREF_ABC_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) { Setting(context, SettingsWithoutKey.BACKUP_RESTORE, R.string.backup_restore_title) {
BackupRestorePreference(it) 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) { Setting(context, SettingsWithoutKey.DEBUG_SETTINGS, R.string.debug_settings_title) {
Preference( Preference(
name = it.title, 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.Defaults
import helium314.keyboard.latin.settings.Settings import helium314.keyboard.latin.settings.Settings
import helium314.keyboard.latin.utils.Log import helium314.keyboard.latin.utils.Log
import helium314.keyboard.latin.utils.checkTimestampFormat
import helium314.keyboard.latin.utils.getActivity import helium314.keyboard.latin.utils.getActivity
import helium314.keyboard.latin.utils.getStringResourceOrName import helium314.keyboard.latin.utils.getStringResourceOrName
import helium314.keyboard.latin.utils.prefs 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.initPreview
import helium314.keyboard.settings.preferences.BackgroundImagePref import helium314.keyboard.settings.preferences.BackgroundImagePref
import helium314.keyboard.settings.preferences.CustomFontPreference import helium314.keyboard.settings.preferences.CustomFontPreference
import helium314.keyboard.settings.preferences.TextInputPreference
import helium314.keyboard.settings.previewDark import helium314.keyboard.settings.previewDark
@Composable @Composable
@ -263,26 +265,8 @@ fun createAppearanceSettings(context: Context) = listOf(
description = { "${(100 * it).toInt()}%" } description = { "${(100 * it).toInt()}%" }
) { KeyboardSwitcher.getInstance().setThemeNeedsReload() } ) { KeyboardSwitcher.getInstance().setThemeNeedsReload() }
}, },
Setting(context, Settings.PREF_SPACE_BAR_TEXT, R.string.prefs_space_bar_text) { setting -> Setting(context, Settings.PREF_SPACE_BAR_TEXT, R.string.prefs_space_bar_text) {
var showDialog by rememberSaveable { mutableStateOf(false) } TextInputPreference(it, Defaults.PREF_SPACE_BAR_TEXT)
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, SettingsWithoutKey.CUSTOM_FONT, R.string.custom_font) { Setting(context, SettingsWithoutKey.CUSTOM_FONT, R.string.custom_font) {
CustomFontPreference(it) CustomFontPreference(it)

View file

@ -58,6 +58,7 @@ import helium314.keyboard.settings.CloseIcon
import helium314.keyboard.settings.SearchScreen import helium314.keyboard.settings.SearchScreen
import helium314.keyboard.settings.SettingsActivity import helium314.keyboard.settings.SettingsActivity
import helium314.keyboard.settings.Theme import helium314.keyboard.settings.Theme
import helium314.keyboard.settings.contentTextDirectionStyle
import helium314.keyboard.settings.dialogs.ColorPickerDialog import helium314.keyboard.settings.dialogs.ColorPickerDialog
import helium314.keyboard.settings.previewDark import helium314.keyboard.settings.previewDark
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@ -70,6 +71,14 @@ fun ColorsScreen(
onClickBack: () -> Unit onClickBack: () -> Unit
) { ) {
val ctx = LocalContext.current 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)? // 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 // 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() val lifecycleState by lifecycleOwner.lifecycle.currentStateFlow.collectAsState()
LaunchedEffect(lifecycleState) { LaunchedEffect(lifecycleState) {
if (lifecycleState == Lifecycle.State.RESUMED) { 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 moreColors = KeyboardTheme.readUserMoreColors(prefs, newThemeName.text)
val b = (ctx.getActivity() as? SettingsActivity)?.prefChanged?.collectAsState() val userColors = KeyboardTheme.readUserColors(prefs, newThemeName.text)
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 shownColors = if (moreColors == 2) { val shownColors = if (moreColors == 2) {
val allColors = KeyboardTheme.readUserAllColors(prefs, themeName) val allColors = KeyboardTheme.readUserAllColors(prefs, newThemeName.text)
ColorType.entries.map { ColorType.entries.map {
ColorSetting(it.name, null, allColors[it] ?: it.default()) 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) fun ColorSetting.displayColor() = if (auto == true) KeyboardTheme.determineUserColor(userColors, ctx, name, isNight)
else color ?: 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("") } var chosenColorString: String by rememberSaveable { mutableStateOf("") }
val chosenColor = runCatching { Json.decodeFromString<ColorSetting?>(chosenColorString) }.getOrNull() val chosenColor = runCatching { Json.decodeFromString<ColorSetting?>(chosenColorString) }.getOrNull()
val saveLauncher = rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { val saveLauncher = rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (it.resultCode != Activity.RESULT_OK) return@rememberLauncherForActivityResult if (result.resultCode != Activity.RESULT_OK) return@rememberLauncherForActivityResult
val uri = it.data?.data ?: return@rememberLauncherForActivityResult val uri = result.data?.data ?: return@rememberLauncherForActivityResult
ctx.getActivity()?.contentResolver?.openOutputStream(uri)?.writer()?.use { it.write(getColorString(prefs, newThemeName.text)) } ctx.getActivity()?.contentResolver?.openOutputStream(uri)?.writer()?.use { it.write(getColorString(prefs, newThemeName.text)) }
} }
SearchScreen( SearchScreen(
@ -129,14 +130,17 @@ fun ColorsScreen(
value = nameField, value = nameField,
onValueChange = { onValueChange = {
nameValid = KeyboardTheme.renameUserColors(newThemeName.text, it.text, prefs) nameValid = KeyboardTheme.renameUserColors(newThemeName.text, it.text, prefs)
if (nameValid) if (nameValid) {
newThemeName = it newThemeName = it
SettingsActivity.forceTheme = newThemeName.text
}
nameField = it nameField = it
}, },
isError = !nameValid, isError = !nameValid,
// supportingText = { if (!nameValid) Text(stringResource(R.string.name_invalid)) } // todo: this is cutting off bottom half of the actual text... // 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) }, trailingIcon = { if (!nameValid) CloseIcon(R.string.name_invalid) },
singleLine = true, singleLine = true,
textStyle = contentTextDirectionStyle,
) )
}, },
menu = listOf( menu = listOf(
@ -193,11 +197,11 @@ fun ColorsScreen(
} }
} }
if (colorSetting.auto != null) if (colorSetting.auto != null)
Switch(colorSetting.auto, onCheckedChange = { Switch(colorSetting.auto, onCheckedChange = { checked ->
val oldUserColors = KeyboardTheme.readUserColors(prefs, themeName) val oldUserColors = KeyboardTheme.readUserColors(prefs, newThemeName.text)
val newUserColors = (oldUserColors + ColorSetting(colorSetting.name, it, colorSetting.color)) val newUserColors = (oldUserColors + ColorSetting(colorSetting.name, checked, colorSetting.color))
.reversed().distinctBy { it.displayName } .reversed().distinctBy { it.displayName }
KeyboardTheme.writeUserColors(prefs, themeName, newUserColors) KeyboardTheme.writeUserColors(prefs, newThemeName.text, newUserColors)
}) })
} }
} }
@ -207,16 +211,16 @@ fun ColorsScreen(
onDismissRequest = { chosenColorString = "" }, onDismissRequest = { chosenColorString = "" },
initialColor = chosenColor.displayColor(), initialColor = chosenColor.displayColor(),
title = chosenColor.displayName, title = chosenColor.displayName,
) { ) { color ->
if (moreColors == 2) { if (moreColors == 2) {
val oldColors = KeyboardTheme.readUserAllColors(prefs, themeName) val oldColors = KeyboardTheme.readUserAllColors(prefs, newThemeName.text)
oldColors[ColorType.valueOf(chosenColor.name)] = it oldColors[ColorType.valueOf(chosenColor.name)] = color
KeyboardTheme.writeUserAllColors(prefs, themeName, oldColors) KeyboardTheme.writeUserAllColors(prefs, newThemeName.text, oldColors)
} else { } else {
val oldUserColors = KeyboardTheme.readUserColors(prefs, themeName) val oldUserColors = KeyboardTheme.readUserColors(prefs, newThemeName.text)
val newUserColors = (oldUserColors + ColorSetting(chosenColor.name, false, it)) val newUserColors = (oldUserColors + ColorSetting(chosenColor.name, false, color))
.reversed().distinctBy { it.displayName } .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.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier 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.MissingDictionaryDialog
import helium314.keyboard.latin.utils.SubtypeLocaleUtils import helium314.keyboard.latin.utils.SubtypeLocaleUtils
import helium314.keyboard.latin.utils.SubtypeSettings import helium314.keyboard.latin.utils.SubtypeSettings
import helium314.keyboard.latin.utils.SubtypeUtilsAdditional
import helium314.keyboard.latin.utils.displayName import helium314.keyboard.latin.utils.displayName
import helium314.keyboard.latin.utils.getActivity import helium314.keyboard.latin.utils.getActivity
import helium314.keyboard.latin.utils.locale import helium314.keyboard.latin.utils.locale
import helium314.keyboard.latin.utils.prefs import helium314.keyboard.latin.utils.prefs
import helium314.keyboard.settings.SearchScreen import helium314.keyboard.settings.SearchScreen
import helium314.keyboard.settings.SettingsActivity import helium314.keyboard.settings.SettingsActivity
import helium314.keyboard.settings.SettingsDestination
import helium314.keyboard.settings.Theme import helium314.keyboard.settings.Theme
import helium314.keyboard.settings.dialogs.SubtypeDialog
import helium314.keyboard.settings.initPreview import helium314.keyboard.settings.initPreview
import helium314.keyboard.settings.previewDark import helium314.keyboard.settings.previewDark
import java.util.Locale import java.util.Locale
@ -57,12 +55,11 @@ fun LanguageScreen(
onClickBack: () -> Unit, onClickBack: () -> Unit,
) { ) {
val ctx = LocalContext.current val ctx = LocalContext.current
var sortedSubtypes by remember { mutableStateOf(getSortedSubtypes(ctx)) } val sortedSubtypes by remember { mutableStateOf(getSortedSubtypes(ctx)) }
val prefs = ctx.prefs() val prefs = ctx.prefs()
val b = (LocalContext.current.getActivity() as? SettingsActivity)?.prefChanged?.collectAsState() val b = (LocalContext.current.getActivity() as? SettingsActivity)?.prefChanged?.collectAsState()
if ((b?.value ?: 0) < 0) if ((b?.value ?: 0) < 0)
Log.v("irrelevant", "stupid way to trigger recomposition on preference change") Log.v("irrelevant", "stupid way to trigger recomposition on preference change")
var selectedSubtype: String? by rememberSaveable { mutableStateOf(null) }
val enabledSubtypes = SubtypeSettings.getEnabledSubtypes() val enabledSubtypes = SubtypeSettings.getEnabledSubtypes()
SearchScreen( SearchScreen(
onClickBack = onClickBack, onClickBack = onClickBack,
@ -87,7 +84,9 @@ fun LanguageScreen(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.clickable { selectedSubtype = item.toSettingsSubtype().toPref() } .clickable {
SettingsDestination.navigateTo(SettingsDestination.Subtype + item.toSettingsSubtype().toPref())
}
.padding(vertical = 6.dp, horizontal = 16.dp) .padding(vertical = 6.dp, horizontal = 16.dp)
) { ) {
var showNoDictDialog by remember { mutableStateOf(false) } 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 { 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_LABELS_ORDER else null,
Settings.PREF_POPUP_KEYS_ORDER, Settings.PREF_POPUP_KEYS_ORDER,
Settings.PREF_SHOW_POPUP_HINTS, Settings.PREF_SHOW_POPUP_HINTS,
Settings.PREF_SHOW_TLD_POPUP_KEYS,
Settings.PREF_POPUP_ON, Settings.PREF_POPUP_ON,
if (AudioAndHapticFeedbackManager.getInstance().hasVibrator()) if (AudioAndHapticFeedbackManager.getInstance().hasVibrator())
Settings.PREF_VIBRATE_ON else null, 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) { Setting(context, Settings.PREF_POPUP_KEYS_ORDER, R.string.popup_order) {
ReorderSwitchPreference(it, Defaults.PREF_POPUP_KEYS_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) { 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() } SwitchPreference(it, Defaults.PREF_SHOW_POPUP_HINTS) { KeyboardSwitcher.getInstance().setThemeNeedsReload() }
}, },
@ -149,10 +156,10 @@ fun createPreferencesSettings(context: Context) = listOf(
key = setting.key, key = setting.key,
default = Defaults.PREF_CLIPBOARD_HISTORY_RETENTION_TIME, default = Defaults.PREF_CLIPBOARD_HISTORY_RETENTION_TIME,
description = { 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()) 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 -> 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.screens
package helium314.keyboard.settings.dialogs
import android.content.Context import android.content.Context
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
@ -14,6 +13,7 @@ import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Switch import androidx.compose.material3.Switch
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton 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.mainLayoutName
import helium314.keyboard.latin.utils.prefs import helium314.keyboard.latin.utils.prefs
import helium314.keyboard.settings.DefaultButton import helium314.keyboard.settings.DefaultButton
import helium314.keyboard.settings.DeleteButton
import helium314.keyboard.settings.DropDownField import helium314.keyboard.settings.DropDownField
import helium314.keyboard.settings.SearchScreen
import helium314.keyboard.settings.SettingsActivity import helium314.keyboard.settings.SettingsActivity
import helium314.keyboard.settings.Theme import helium314.keyboard.settings.Theme
import helium314.keyboard.settings.WithSmallTitle 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.initPreview
import helium314.keyboard.settings.layoutFilePicker import helium314.keyboard.settings.layoutFilePicker
import helium314.keyboard.settings.layoutIntent import helium314.keyboard.settings.layoutIntent
import helium314.keyboard.settings.previewDark import helium314.keyboard.settings.previewDark
import helium314.keyboard.settings.screens.GetIcon
import java.util.Locale 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 @Composable
fun SubtypeDialog( fun SubtypeScreen(
onDismissRequest: () -> Unit,
initialSubtype: SettingsSubtype, initialSubtype: SettingsSubtype,
onConfirmed: (SettingsSubtype) -> Unit, onClickBack: () -> Unit,
) { ) {
val ctx = LocalContext.current val ctx = LocalContext.current
val prefs = ctx.prefs() val prefs = ctx.prefs()
@ -92,7 +102,10 @@ fun SubtypeDialog(
Log.v("irrelevant", "stupid way to trigger recomposition on preference change") Log.v("irrelevant", "stupid way to trigger recomposition on preference change")
var currentSubtypeString by rememberSaveable { mutableStateOf(initialSubtype.toPref()) } var currentSubtypeString by rememberSaveable { mutableStateOf(initialSubtype.toPref()) }
val currentSubtype = currentSubtypeString.toSettingsSubtype() 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) { LaunchedEffect(currentSubtypeString) {
if (ScriptUtils.scriptSupportsUppercase(currentSubtype.locale)) return@LaunchedEffect if (ScriptUtils.scriptSupportsUppercase(currentSubtype.locale)) return@LaunchedEffect
// update the noShiftKey extra value // update the noShiftKey extra value
@ -120,120 +133,119 @@ fun SubtypeDialog(
var showMorePopupsDialog by remember { mutableStateOf(false) } var showMorePopupsDialog by remember { mutableStateOf(false) }
val scrollState = rememberScrollState() val scrollState = rememberScrollState()
val customMainLayouts = LayoutUtilsCustom.getLayoutFiles(LayoutType.MAIN, ctx, currentSubtype.locale).map { it.name } val customMainLayouts = LayoutUtilsCustom.getLayoutFiles(LayoutType.MAIN, ctx, currentSubtype.locale).map { it.name }
ThreeButtonAlertDialog( SearchScreen(
onDismissRequest = onDismissRequest, onClickBack = onClickBack,
onConfirmed = { onConfirmed(currentSubtype) }, icon = { if (currentSubtype.isAdditionalSubtype(prefs)) DeleteButton {
neutralButtonText = if (initialSubtype.isAdditionalSubtype(prefs)) stringResource(R.string.delete) else null, SubtypeUtilsAdditional.removeAdditionalSubtype(ctx, currentSubtype.toAdditionalSubtype())
onNeutral = { SubtypeSettings.removeEnabledSubtype(ctx, currentSubtype.toAdditionalSubtype())
SubtypeUtilsAdditional.removeAdditionalSubtype(ctx, initialSubtype.toAdditionalSubtype()) onClickBack()
SubtypeSettings.removeEnabledSubtype(ctx, initialSubtype.toAdditionalSubtype()) } },
onDismissRequest()
},
title = { title = {
val mainLayout = initialSubtype.mainLayoutName() ?: SubtypeLocaleUtils.QWERTY val mainLayout = currentSubtype.mainLayoutName() ?: SubtypeLocaleUtils.QWERTY
Text(SubtypeLocaleUtils.getDisplayNameInSystemLocale(mainLayout, initialSubtype.locale)) Text(SubtypeLocaleUtils.getDisplayNameInSystemLocale(mainLayout, currentSubtype.locale))
}, },
content = { itemContent = { },
Column( filteredItems = { emptyList<String>() }
modifier = Modifier.verticalScroll(scrollState), ) {
verticalArrangement = Arrangement.spacedBy(8.dp), Column(
) { modifier = Modifier.verticalScroll(scrollState).padding(horizontal = 12.dp),
MainLayoutRow(initialSubtype, currentSubtype, customMainLayouts) { setCurrentSubtype(it) } verticalArrangement = Arrangement.spacedBy(8.dp),
if (availableLocalesForScript.size > 1) { ) {
WithSmallTitle(stringResource(R.string.secondary_locale)) { MainLayoutRow(currentSubtype, customMainLayouts) { setCurrentSubtype(it) }
TextButton(onClick = { showSecondaryLocaleDialog = true }) { if (availableLocalesForScript.size > 1) {
val text = getSecondaryLocales(currentSubtype.extraValues).joinToString(", ") { WithSmallTitle(stringResource(R.string.secondary_locale)) {
it.localizedDisplayName(ctx) TextButton(onClick = { showSecondaryLocaleDialog = true }) {
}.ifEmpty { stringResource(R.string.action_none) } val text = getSecondaryLocales(currentSubtype.extraValues).joinToString(", ") {
Text(text, Modifier.fillMaxWidth(), style = MaterialTheme.typography.bodyLarge) it.localizedDisplayName(ctx)
} }.ifEmpty { stringResource(R.string.action_none) }
Text(text, Modifier.fillMaxWidth())
} }
} }
Row { }
TextButton(onClick = { showKeyOrderDialog = true }, Modifier.weight(1f)) Row {
{ Text(stringResource(R.string.popup_order), style = MaterialTheme.typography.bodyLarge) } TextButton(onClick = { showKeyOrderDialog = true }, Modifier.weight(1f))
DefaultButton(currentSubtype.getExtraValueOf(ExtraValue.POPUP_ORDER) == null) { { Text(stringResource(R.string.popup_order)) }
setCurrentSubtype(currentSubtype.without(ExtraValue.POPUP_ORDER)) DefaultButton(currentSubtype.getExtraValueOf(ExtraValue.POPUP_ORDER) == null) {
} setCurrentSubtype(currentSubtype.without(ExtraValue.POPUP_ORDER))
} }
Row { }
TextButton(onClick = { showHintOrderDialog = true }, Modifier.weight(1f)) Row {
{ Text(stringResource(R.string.hint_source), style = MaterialTheme.typography.bodyLarge) } TextButton(onClick = { showHintOrderDialog = true }, Modifier.weight(1f))
DefaultButton(currentSubtype.getExtraValueOf(ExtraValue.HINT_ORDER) == null) { { Text(stringResource(R.string.hint_source)) }
setCurrentSubtype(currentSubtype.without(ExtraValue.HINT_ORDER)) 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)) { if (currentSubtype.locale.script() == ScriptUtils.SCRIPT_LATIN) {
val explicitValue = currentSubtype.getExtraValueOf(ExtraValue.MORE_POPUPS) WithSmallTitle(stringResource(R.string.show_popup_keys_title)) {
val value = explicitValue ?: prefs.getString(Settings.PREF_MORE_POPUP_KEYS, Defaults.PREF_MORE_POPUP_KEYS)!! val explicitValue = currentSubtype.getExtraValueOf(ExtraValue.MORE_POPUPS)
Row { val value = explicitValue ?: prefs.getString(Settings.PREF_MORE_POPUP_KEYS, Defaults.PREF_MORE_POPUP_KEYS)!!
TextButton(onClick = { showMorePopupsDialog = true }, Modifier.weight(1f)) Row {
{ Text(stringResource(morePopupKeysResId(value))) } TextButton(onClick = { showMorePopupsDialog = true }, Modifier.weight(1f))
DefaultButton(explicitValue == null) { { Text(stringResource(morePopupKeysResId(value))) }
setCurrentSubtype(currentSubtype.without(ExtraValue.MORE_POPUPS)) 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 (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) if (showSecondaryLocaleDialog)
MultiListPickerDialog( MultiListPickerDialog(
onDismissRequest = { showSecondaryLocaleDialog = false }, onDismissRequest = { showSecondaryLocaleDialog = false },
@ -294,6 +306,7 @@ fun SubtypeDialog(
} }
} }
// from ReorderSwitchPreference // from ReorderSwitchPreference
@Composable @Composable
private fun PopupOrderDialog( private fun PopupOrderDialog(
@ -336,7 +349,6 @@ private fun PopupOrderDialog(
@Composable @Composable
private fun MainLayoutRow( private fun MainLayoutRow(
initialSubtype: SettingsSubtype,
currentSubtype: SettingsSubtype, currentSubtype: SettingsSubtype,
customLayouts: List<String>, customLayouts: List<String>,
setCurrentSubtype: (SettingsSubtype) -> Unit, setCurrentSubtype: (SettingsSubtype) -> Unit,
@ -369,13 +381,13 @@ private fun MainLayoutRow(
Text(SubtypeLocaleUtils.getDisplayNameInSystemLocale(it, currentSubtype.locale)) Text(SubtypeLocaleUtils.getDisplayNameInSystemLocale(it, currentSubtype.locale))
Row (verticalAlignment = Alignment.CenterVertically) { Row (verticalAlignment = Alignment.CenterVertically) {
Icon(painterResource(R.drawable.ic_edit), stringResource(R.string.edit_layout), Modifier.clickable { showLayoutEditDialog = it to null }) 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 }) Icon(painterResource(R.drawable.ic_bin), stringResource(R.string.delete), Modifier.clickable { showLayoutDeleteDialog = true })
} }
} }
if (showLayoutDeleteDialog) { if (showLayoutDeleteDialog) {
val others = SubtypeSettings.getAdditionalSubtypes().filter { st -> st.mainLayoutName() == it } 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( ConfirmationDialog(
onDismissRequest = { showLayoutDeleteDialog = false }, onDismissRequest = { showLayoutDeleteDialog = false },
confirmButtonText = stringResource(R.string.delete), confirmButtonText = stringResource(R.string.delete),
@ -442,11 +454,14 @@ private fun MainLayoutRow(
private fun getAvailableSecondaryLocales(context: Context, mainLocale: Locale): List<Locale> = private fun getAvailableSecondaryLocales(context: Context, mainLocale: Locale): List<Locale> =
getDictionaryLocales(context).filter { it != mainLocale && it.script() == mainLocale.script() } getDictionaryLocales(context).filter { it != mainLocale && it.script() == mainLocale.script() }
@Preview @Preview
@Composable @Composable
private fun Preview() { private fun Preview() {
initPreview(LocalContext.current) initPreview(LocalContext.current)
Theme(previewDark) { 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.permissions.PermissionsUtil
import helium314.keyboard.latin.settings.Defaults import helium314.keyboard.latin.settings.Defaults
import helium314.keyboard.latin.settings.Settings import helium314.keyboard.latin.settings.Settings
import helium314.keyboard.latin.utils.JniUtils
import helium314.keyboard.latin.utils.Log import helium314.keyboard.latin.utils.Log
import helium314.keyboard.latin.utils.getActivity import helium314.keyboard.latin.utils.getActivity
import helium314.keyboard.latin.utils.prefs import helium314.keyboard.latin.utils.prefs
@ -49,6 +50,7 @@ fun TextCorrectionScreen(
Log.v("irrelevant", "stupid way to trigger recomposition on preference change") Log.v("irrelevant", "stupid way to trigger recomposition on preference change")
val autocorrectEnabled = prefs.getBoolean(Settings.PREF_AUTO_CORRECTION, Defaults.PREF_AUTO_CORRECTION) 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 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( val items = listOf(
SettingsWithoutKey.EDIT_PERSONAL_DICTIONARY, SettingsWithoutKey.EDIT_PERSONAL_DICTIONARY,
R.string.settings_category_correction, R.string.settings_category_correction,
@ -57,12 +59,20 @@ fun TextCorrectionScreen(
if (autocorrectEnabled) Settings.PREF_MORE_AUTO_CORRECTION else null, if (autocorrectEnabled) Settings.PREF_MORE_AUTO_CORRECTION else null,
if (autocorrectEnabled) Settings.PREF_AUTOCORRECT_SHORTCUTS else null, if (autocorrectEnabled) Settings.PREF_AUTOCORRECT_SHORTCUTS else null,
if (autocorrectEnabled) Settings.PREF_AUTO_CORRECT_THRESHOLD else null, if (autocorrectEnabled) Settings.PREF_AUTO_CORRECT_THRESHOLD else null,
if (autocorrectEnabled) Settings.PREF_BACKSPACE_REVERTS_AUTOCORRECT else null,
Settings.PREF_AUTO_CAP, Settings.PREF_AUTO_CAP,
R.string.settings_category_space,
Settings.PREF_KEY_USE_DOUBLE_SPACE_PERIOD, Settings.PREF_KEY_USE_DOUBLE_SPACE_PERIOD,
Settings.PREF_AUTOSPACE_AFTER_PUNCTUATION, 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, R.string.settings_category_suggestions,
Settings.PREF_SHOW_SUGGESTIONS, Settings.PREF_SHOW_SUGGESTIONS,
if (suggestionsEnabled) Settings.PREF_ALWAYS_SHOW_SUGGESTIONS else null, 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, if (suggestionsEnabled) Settings.PREF_CENTER_SUGGESTION_TEXT_TO_ENTER else null,
Settings.PREF_KEY_USE_PERSONALIZED_DICTS, Settings.PREF_KEY_USE_PERSONALIZED_DICTS,
Settings.PREF_BIGRAM_PREDICTIONS, 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 % // todo: consider making it a slider, and maybe somehow adjust range so we can show %
ListPreference(it, items, Defaults.PREF_AUTO_CORRECT_THRESHOLD) 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, Setting(context, Settings.PREF_AUTO_CAP,
R.string.auto_cap, R.string.auto_cap_summary 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) 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, Setting(context, Settings.PREF_SHOW_SUGGESTIONS,
R.string.prefs_show_suggestions, R.string.prefs_show_suggestions_summary 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) 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, Setting(context, Settings.PREF_KEY_USE_PERSONALIZED_DICTS,
R.string.use_personalized_dicts, R.string.use_personalized_dicts_summary R.string.use_personalized_dicts, R.string.use_personalized_dicts_summary
) { setting -> ) { setting ->

View file

@ -8,8 +8,7 @@
android:width="24dp" android:width="24dp"
android:height="24dp" android:height="24dp"
android:viewportWidth="960" android:viewportWidth="960"
android:viewportHeight="960" android:viewportHeight="960">
android:tint="?attr/colorControlNormal">
<path android:fillColor="#FFF" <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"/> 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> </vector>

View file

@ -75,16 +75,16 @@
<string name="prefs_enable_emoji_alt_physical_key">"الرموز التعبيرية للوحة مفاتيح فعلية"</string> <string name="prefs_enable_emoji_alt_physical_key">"الرموز التعبيرية للوحة مفاتيح فعلية"</string>
<string name="prefs_enable_emoji_alt_physical_key_summary">"‏مفتاح Alt الفعلي يعرض لوحة الرموز التعبيرية"</string> <string name="prefs_enable_emoji_alt_physical_key_summary">"‏مفتاح Alt الفعلي يعرض لوحة الرموز التعبيرية"</string>
<string name="button_default">"التلقائية"</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_welcome_additional_description">مع الكتابة بالإيماءة</string>
<string name="setup_start_action">"بدء الاستخدام"</string> <string name="setup_start_action">"بدء الاستخدام"</string>
<string name="setup_next_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_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_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_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_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_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_instruction">بعد ذلك، اختر \\&lt;&lt;xliff:g id=\"APPLICATION_NAME\" مثال=\"لوحة مفاتيح أندرويد\"&gt;%s&lt;/xliff:g&gt;” كطريقة إدخال النص النشط.“</string>
<string name="setup_step2_action">"تبديل أساليب الإدخال"</string> <string name="setup_step2_action">"تبديل أساليب الإدخال"</string>
<string name="setup_step3_title">تهانينا ، لقد انتهيت من الإعداد!</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" tools:keep="@string/layout_symbols">الرموز</string>
<string name="layout_symbols_arabic" tools:keep="@string/layout_symbols_arabic">الرموز(العربية)</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_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" tools:keep="@string/layout_phone">الهاتف</string>
<string name="layout_phone_symbols" tools:keep="@string/layout_phone_symbols">رموز الهاتف</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="remove_dictionary_message">هل تريد حقًا إزالة القاموس الذي أضافه المستخدم \"%s\"؟</string>
<string name="dictionary_file_error">خطأ: الملف المحدد ليس ملف قاموس صالح</string> <string name="dictionary_file_error">خطأ: الملف المحدد ليس ملف قاموس صالح</string>
<string name="theme_name_black" tools:keep="@string/theme_name_black">اسود</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="locales_with_dict">اللغات مع القواميس</string>
<string name="get_layouts_message">يمكنك العثور على المخططات ومشاركتها في %s.</string> <string name="get_layouts_message">يمكنك العثور على المخططات ومشاركتها في %s.</string>
<string name="discussion_section_link">قسم المناقشة</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> </resources>

View file

@ -370,5 +370,64 @@
<string name="space_swipe_toggle_numpad_entry">Пераключыць лічбавую клавіятуру</string> <string name="space_swipe_toggle_numpad_entry">Пераключыць лічбавую клавіятуру</string>
<string name="show_popup_keys_main">Дадаць самыя распаўсюджаныя варыянты (па змаўчанні)</string> <string name="show_popup_keys_main">Дадаць самыя распаўсюджаныя варыянты (па змаўчанні)</string>
<string name="remove_redundant_popups">Выдаліць лішнія ўсплывальныя вокны</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> </resources>

View file

@ -467,4 +467,10 @@
<string name="get_colors_message">Можете да намирате и споделяте цветове в %s.</string> <string name="get_colors_message">Можете да намирате и споделяте цветове в %s.</string>
<string name="custom_subtype">Персонализиран подтип</string> <string name="custom_subtype">Персонализиран подтип</string>
<string name="subtype_baishakhi_bn_IN"><xliff:g id="LANGUAGE_NAME" example="Бенгалски">%s</xliff:g> (Байсахи)</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> </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_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="get_layouts_message">Podeu trobar i compartir disposicions a %s.</string>
<string name="discussion_section_link">secció de discussió</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> </resources>

View file

@ -432,4 +432,11 @@
<string name="delete_confirmation">%s wirklich löschen?</string> <string name="delete_confirmation">%s wirklich löschen?</string>
<string name="name_invalid">Ungültiger Name</string> <string name="name_invalid">Ungültiger Name</string>
<string name="custom_subtype">Benutzerdefinierter Subtyp</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> </resources>

View file

@ -467,4 +467,10 @@
<string name="get_colors_message">Uusi värve võid leida ja jagada %s.</string> <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="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="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> </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_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="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="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> </resources>

View file

@ -434,4 +434,16 @@
<string name="discussion_section_link">zona de conversa</string> <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="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="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> </resources>

View file

@ -104,7 +104,7 @@
<string name="user_dict_settings_add_shortcut_option_name">"Scorciatoia:"</string> <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_locale_option_name">"Lingua:"</string>
<string name="user_dict_settings_add_word_hint">"Digita una parola"</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_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_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> <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="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="dialog_close">Chiudi</string>
<string name="select_color_gesture">Traccia dell\'input gestuale</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="save_log">Salva log</string>
<string name="theme_name_holo_white" tools:keep="@string/theme_name_holo_white">Holo bianco</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> <string name="internal_dictionary_summary">Dizionario interno principale</string>
@ -432,4 +432,17 @@
<string name="auto_correct_shortcuts">Scorciatoie correzione</string> <string name="auto_correct_shortcuts">Scorciatoie correzione</string>
<string name="name_invalid">Nome non valido</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="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> </resources>

View file

@ -208,7 +208,7 @@
<string name="toolbar_keys">בחירת כפתורי סרגל הכלים</string> <string name="toolbar_keys">בחירת כפתורי סרגל הכלים</string>
<string name="prefs_narrow_key_gaps">מרווחי קלידים צרים</string> <string name="prefs_narrow_key_gaps">מרווחי קלידים צרים</string>
<string name="localized_number_row">תרגום number row</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" 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_language_priority" tools:keep="@string/popup_keys_language_priority">שפה (עדיפות)</string>
<string name="popup_keys_layout" tools:keep="@string/popup_keys_layout">פריסה</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_colors_message">באפשרותך למצוא ולשתף צבעים ב %s.</string>
<string name="get_layouts_message">באפשרותך למצוא ולשתף פריסות ב %s.</string> <string name="get_layouts_message">באפשרותך למצוא ולשתף פריסות ב %s.</string>
<string name="discussion_section_link">מקטע הדיונים</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> </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="get_layouts_message">Je kunt lay-outs zoeken en delen in de %s.</string>
<string name="discussion_section_link">discussiesectie</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="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> </resources>

View file

@ -94,7 +94,7 @@
<string name="show_setup_wizard_icon">"Pokaż ikonę aplikacji"</string> <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="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_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="no_dictionaries_available">"Brak słowników"</string>
<string name="last_update">"Ostatnia aktualizacja"</string> <string name="last_update">"Ostatnia aktualizacja"</string>
<string name="settings">"Ustawienia"</string> <string name="settings">"Ustawienia"</string>
@ -174,13 +174,13 @@
<string name="restore_error">Błąd podczas przywracania kopii zapasowej: %s</string> <string name="restore_error">Błąd podczas przywracania kopii zapasowej: %s</string>
<string name="theme_colors">Kolory</string> <string name="theme_colors">Kolory</string>
<string name="select_color_functional_key_background">Tło klawiszy funkcyjnych</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="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="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="style_name_Rounded" tools:keep="@string/style_name_Rounded">Zaokrąglony</string>
<string name="button_backup">Kopia</string> <string name="button_backup">Kopia</string>
<string name="theme_name_black" tools:keep="@string/theme_name_black">Czarne</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="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="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> <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="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="language_and_layouts_title">Języki i układy</string>
<string name="file_read_error">Nie można odczytać pliku</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="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="hidden_features_text">chronionej pamięci urządzenia</string>
<string name="theme_navbar">Koloruj pasek nawigacyjny</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_vertical_space_swipe">Spacja - przesuwanie pionowe</string>
<string name="show_horizontal_space_swipe">Spacja - przesuwanie poziome</string> <string name="show_horizontal_space_swipe">Spacja - przesuwanie poziome</string>
<string name="space_swipe_move_cursor_entry">Przesuń kursor</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_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="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> <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="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_detail">Ustaw główny i do 6 drugorzędnych symboli waluty, oddzielonych spacją</string>
<string name="customize_currencies">Dostosuj waluty</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="copy_to_clipboard">Skopiuj do schowka</string>
<string name="load_will_overwrite">Ładowanie spowoduje zastąpienie bieżącego motywu</string> <string name="load_will_overwrite">Ładowanie spowoduje zastąpienie bieżącego motywu</string>
<string name="button_save_file">Zapisz do pliku</string> <string name="button_save_file">Zapisz do pliku</string>
@ -471,9 +471,13 @@
<string name="name_invalid">Nieprawidłowa nazwa</string> <string name="name_invalid">Nieprawidłowa nazwa</string>
<string name="locales_with_dict">Języki ze słownikami</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="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_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_layouts_message">Układy możesz znaleźć i udostępnić w %s.</string>
<string name="discussion_section_link">sekcji dyskusji</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="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> </resources>

View file

@ -439,4 +439,10 @@
<string name="discussion_section_link">seção de discussão</string> <string name="discussion_section_link">seção de discussão</string>
<string name="custom_subtype">Subtipo customizado</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="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> </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_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="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="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> </resources>

View file

@ -285,7 +285,7 @@
<string name="theme_name_holo_white" tools:keep="@string/theme_name_holo_white">Holo Белая</string> <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="language_switch_key_switch_both">Смена обоих</string>
<string name="up" tools:keep="@string/up">Вверх</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="file_read_error">Не получается прочитать файл</string>
<string name="dictionary_link_text">здесь</string> <string name="dictionary_link_text">здесь</string>
<string name="add_dictionary">Выберите для добавления словаря. Словари в формате .dict можно скачать %s.</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_ok">Всё ещё используется</string>
<string name="dictionary_file_wrong_locale">Выбранный файл предназначен для %1$s, но ожидался %2$s. Всё ещё используете его для %2$s?</string> <string name="dictionary_file_wrong_locale">Выбранный файл предназначен для %1$s, но ожидался %2$s. Всё ещё используете его для %2$s?</string>
<string name="dictionary_file_error">Ошибка: выбранный файл не является корректным словарем</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="available_dictionary_experimental">%s (экспериментальный)</string>
<string name="layout_symbols" tools:keep="@string/layout_symbols">Символы</string> <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_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" 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_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_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_toolbar_key" tools:keep="@string/label_toolbar_key">Показать / скрыть панель инструментов</string>
<string name="label_zwj_key" tools:keep="@string/label_zwj_key">Соединитель нулевой ширины</string> <string name="label_zwj_key" tools:keep="@string/label_zwj_key">Соединитель нулевой ширины</string>
<string name="customize_toolbar_key_codes">Настроить коды клавиш панели инструментов</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_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="label_stop_onehanded_mode_key" tools:keep="@string/label_stop_onehanded_mode_key">Выход из режима работы одной рукой</string>
<string name="customize_icons_reset_message">Действительно сбросить все настроенные иконки?</string> <string name="customize_icons_reset_message">Действительно сбросить все настроенные иконки?</string>
<string name="label_bin" tools:keep="@string/label_bin">Bin</string> <string name="label_bin" tools:keep="@string/label_bin">Корзина</string>
<string name="vibrate_in_dnd_mode">Вибрировать в режиме Не беспокоить</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="subtype_generic_phonetic"><xliff:g id="LANGUAGE_NAME" example="Хинди">%s</xliff:g> (Фонетика)</string>
<string name="auto_correct_shortcuts">Автокоррекция сочетаний клавиш</string> <string name="auto_correct_shortcuts">Автокоррекция сочетаний клавиш</string>
<string name="custom_font">Установить пользовательский шрифт из файла</string> <string name="custom_font">Установить пользовательский шрифт из файла</string>
@ -450,7 +450,7 @@
<string name="prefs_key_emoji_max_sdk">Переопределить версию эмодзи</string> <string name="prefs_key_emoji_max_sdk">Переопределить версию эмодзи</string>
<string name="summary_customize_background_image_landscape">Если не установлено, будет использоваться портретное изображение</string> <string name="summary_customize_background_image_landscape">Если не установлено, будет использоваться портретное изображение</string>
<string name="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="prefs_language_swipe_distance">Расстояние смахивания для переключения языка</string>
<string name="split_spacer_scale_landscape">Расстояние разделения (ландшафт)</string> <string name="split_spacer_scale_landscape">Расстояние разделения (ландшафт)</string>
<string name="enable_split_keyboard_landscape">Включить разделение клавиатуры (ландшафт)</string> <string name="enable_split_keyboard_landscape">Включить разделение клавиатуры (ландшафт)</string>
@ -466,4 +466,10 @@
<string name="get_layouts_message">Найти и поделиться раскладками в %s.</string> <string name="get_layouts_message">Найти и поделиться раскладками в %s.</string>
<string name="discussion_section_link">обсуждения</string> <string name="discussion_section_link">обсуждения</string>
<string name="name_invalid">Недопустимое имя</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> </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"> <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 <!-- Some items are duplicated from the original platform-theme file to ensure that the
"android/system_accent_*" or "android/system_neutral_*" colors are used. --> "android/system_accent_*" or "android/system_neutral_*" colors are used. -->
<item name="android:colorAccent">@color/accent</item> <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:statusBarColor">@color/action_bar_color</item>
<item name="android:navigationBarColor">@color/setup_background</item> <item name="android:navigationBarColor">@color/setup_background</item>
@ -19,7 +18,6 @@
<item name="android:windowBackground">@color/setup_background</item> <item name="android:windowBackground">@color/setup_background</item>
<item name="android:alertDialogTheme">@style/AlertDialogTheme</item> <item name="android:alertDialogTheme">@style/AlertDialogTheme</item>
<item name="alertDialogTheme">@style/AlertDialogTheme</item>
<item name="android:buttonCornerRadius">50dp</item> <item name="android:buttonCornerRadius">50dp</item>
@ -27,11 +25,9 @@
<item name="android:itemBackground">@color/drop_down_menu_background</item> <item name="android:itemBackground">@color/drop_down_menu_background</item>
</style> </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="android:colorBackgroundFloating">@color/dialog_background</item>
<item name="colorBackgroundFloating">@color/dialog_background</item>
<item name="android:dialogCornerRadius">28dp</item> <item name="android:dialogCornerRadius">28dp</item>
<item name="dialogCornerRadius">28dp</item>
</style> </style>
</resources> </resources>

View file

@ -320,7 +320,7 @@
<string name="switch_keyboard_after">切换到主键盘后…</string> <string name="switch_keyboard_after">切换到主键盘后…</string>
<string name="after_emoji">在表情符号视图中选择表情符号</string> <string name="after_emoji">在表情符号视图中选择表情符号</string>
<string name="after_clip">选择剪贴板历史条目</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="add_new_dictionary_title">从文件添加词典</string>
<string name="quick_pin_toolbar_keys_summary">这将禁用未固定工具栏键的其他长按操作</string> <string name="quick_pin_toolbar_keys_summary">这将禁用未固定工具栏键的其他长按操作</string>
<string name="show_popup_keys_main">添加非常常见的变体(默认)</string> <string name="show_popup_keys_main">添加非常常见的变体(默认)</string>
@ -433,4 +433,10 @@
<string name="get_colors_message">您可以在 %s 中查找和分享颜色。</string> <string name="get_colors_message">您可以在 %s 中查找和分享颜色。</string>
<string name="custom_subtype">自定义子类型</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="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> </resources>

View file

@ -6,11 +6,21 @@
--> -->
<resources xmlns:android="http://schemas.android.com/apk/res/android"> <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="android:colorAccent">@color/accent</item>
<item name="colorAccent">@color/accent</item>
<item name="android:statusBarColor">@color/action_bar_color</item> <item name="android:statusBarColor">@color/action_bar_color</item>
<item name="android:navigationBarColor">@color/navigation_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> </style>
</resources> </resources>

View file

@ -38,6 +38,8 @@
<string name="settings_category_clipboard_history">Clipboard history</string> <string name="settings_category_clipboard_history">Clipboard history</string>
<!-- Settings category title for Text correction/Corrections --> <!-- Settings category title for Text correction/Corrections -->
<string name="settings_category_correction">Corrections</string> <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 --> <!-- Settings category title for Text correction/Suggestions -->
<string name="settings_category_suggestions">Suggestions</string> <string name="settings_category_suggestions">Suggestions</string>
<!-- Settings category title for Advanced/Experimental --> <!-- Settings category title for Advanced/Experimental -->
@ -104,6 +106,10 @@
<string name="prefs_always_show_suggestions">Always show suggestions</string> <string name="prefs_always_show_suggestions">Always show suggestions</string>
<!-- Description for override app flag to not show suggestions --> <!-- 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> <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 --> <!-- Option to block potentially offensive words to be shown -->
<string name="prefs_block_potentially_offensive_title">Block offensive words</string> <string name="prefs_block_potentially_offensive_title">Block offensive words</string>
<!-- Summary for option to block potentially offensive words to be shown --> <!-- Summary for option to block potentially offensive words to be shown -->
@ -122,6 +128,8 @@
<string name="auto_correct_shortcuts">Auto-correct shortcuts</string> <string name="auto_correct_shortcuts">Auto-correct shortcuts</string>
<!-- Description for auto_correct_shortcuts --> <!-- Description for auto_correct_shortcuts -->
<string name="auto_correct_shortcuts_summary">When enabled shortcuts might be expanded by autocorrect</string> <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. --> <!-- Option to disable auto correction. -->
<string name="auto_correction_threshold_mode_off">Off</string> <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. --> <!-- 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> <string name="button_backup">Backup</string>
<!-- restore button --> <!-- restore button -->
<string name="button_restore">Restore</string> <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 --> <!-- Preferences item for choosing secondary language -->
<string name="secondary_locale">Multilingual typing</string> <string name="secondary_locale">Multilingual typing</string>
<!-- Clarification which locales are available for multilingual typing --> <!-- Clarification which locales are available for multilingual typing -->
@ -205,10 +215,20 @@
<string name="load_gesture_library_button_load">Load library</string> <string name="load_gesture_library_button_load">Load library</string>
<!-- Button text for deleting gesture library --> <!-- Button text for deleting gesture library -->
<string name="load_gesture_library_button_delete">Delete library</string> <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> <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> <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 --> <!-- Preferences item for showing popup keys in long-press popup -->
<string name="show_popup_keys_title">Show more letters with diacritics in popup</string> <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 --> <!-- 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> <string name="hint_source">Select hint source</string>
<!-- Title of the setting to set popup key order --> <!-- Title of the setting to set popup key order -->
<string name="popup_order">Select popup key order</string> <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 --> <!-- Names of the popup key classes -->
<string name="popup_keys_number" tools:keep="@string/popup_keys_number">Number row</string> <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> <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> <string name="layout_numpad_landscape" tools:keep="@string/layout_numpad_landscape">Numpad (landscape)</string>
<!-- Name for number row layout --> <!-- Name for number row layout -->
<string name="layout_number_row" tools:keep="@string/layout_number_row">Number row</string> <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 --> <!-- 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> <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 --> <!-- 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> <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 --> <!-- 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> <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 --> <!-- Message for selecting day or night background image -->
<string name="day_or_night_image">Set image for day or night mode?</string> <string name="day_or_night_image">Set image for day or night mode?</string>
<!-- Button for selecting day --> <!-- Button for selecting day -->

View file

@ -23,6 +23,7 @@
bn_IN: Bengali (India)/bengali_inscript bn_IN: Bengali (India)/bengali_inscript
bn_IN: Bengali (India)/Baishakhi bn_IN: Bengali (India)/Baishakhi
ca: Catalan/qwerty+ ca: Catalan/qwerty+
ckb: Central Kurdish/central_kurdish
cs: Czech/qwertz cs: Czech/qwertz
cv: Chuvash/chuvash cv: Chuvash/chuvash
da: Danish/qwerty+ da: Danish/qwerty+
@ -90,6 +91,7 @@
pt_PT: Portuguese (Portugal)/qwerty pt_PT: Portuguese (Portugal)/qwerty
ro: Romanian/qwerty ro: Romanian/qwerty
ru: Russian/russian ru: Russian/russian
ru: Russian (Extended)/russian_extended
ru: Russian (Student)/russian_student ru: Russian (Student)/russian_student
si_LK: Sinhala (Sri Lanka)/sinhala # This is a preliminary keyboard layout. si_LK: Sinhala (Sri Lanka)/sinhala # This is a preliminary keyboard layout.
sk: Slovak/qwerty sk: Slovak/qwerty
@ -107,6 +109,7 @@
tr: Turkish/turkish tr: Turkish/turkish
ur_PK: Urdu Pakistan ur_PK: Urdu Pakistan
uk: Ukrainian/ukrainian uk: Ukrainian/ukrainian
uk: Ukrainian (Extended)/ukrainian_extended
uz_UZ: Uzbek (Uzbekistan)/uzbek # This is a preliminary keyboard layout. uz_UZ: Uzbek (Uzbekistan)/uzbek # This is a preliminary keyboard layout.
vi: Vietnamese/qwerty vi: Vietnamese/qwerty
zu: Zulu/qwerty zu: Zulu/qwerty
@ -287,6 +290,15 @@
android:imeSubtypeExtraValue="KeyboardLayoutSet=MAIN:qwerty+,AsciiCapable,EmojiCapable" android:imeSubtypeExtraValue="KeyboardLayoutSet=MAIN:qwerty+,AsciiCapable,EmojiCapable"
android:isAsciiCapable="true" 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" <subtype android:icon="@drawable/ic_ime_switcher"
android:label="@string/subtype_generic" android:label="@string/subtype_generic"
android:subtypeId="0x2d3d2ed0" android:subtypeId="0x2d3d2ed0"
@ -912,6 +924,16 @@
android:imeSubtypeExtraValue="KeyboardLayoutSet=MAIN:russian,SupportTouchPositionCorrection,EmojiCapable" android:imeSubtypeExtraValue="KeyboardLayoutSet=MAIN:russian,SupportTouchPositionCorrection,EmojiCapable"
android:isAsciiCapable="false" 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" <subtype android:icon="@drawable/ic_ime_switcher"
android:label="@string/subtype_generic_student" android:label="@string/subtype_generic_student"
android:subtypeId="0x1bc335d0" android:subtypeId="0x1bc335d0"
@ -1064,6 +1086,15 @@
android:imeSubtypeExtraValue="KeyboardLayoutSet=MAIN:ukrainian,EmojiCapable" android:imeSubtypeExtraValue="KeyboardLayoutSet=MAIN:ukrainian,EmojiCapable"
android:isAsciiCapable="false" 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" <subtype android:icon="@drawable/ic_ime_switcher"
android:label="@string/subtype_generic" android:label="@string/subtype_generic"
android:subtypeId="0x1e8349fc" 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.inputlogic.SpaceState
import helium314.keyboard.latin.settings.Settings import helium314.keyboard.latin.settings.Settings
import helium314.keyboard.latin.utils.ScriptUtils import helium314.keyboard.latin.utils.ScriptUtils
import helium314.keyboard.latin.utils.getTimestamp
import helium314.keyboard.latin.utils.prefs import helium314.keyboard.latin.utils.prefs
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.mockito.Mockito import org.mockito.Mockito
@ -203,13 +204,7 @@ class InputLogicTest {
assertEquals("example.net", composingText) 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() { @Test fun noAutospaceInUrlFieldWhenPickingSuggestion() {
if (BuildConfig.BUILD_TYPE == "runTests") return
reset() reset()
setInputType(InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_URI) setInputType(InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_URI)
chainInput("exam") chainInput("exam")
@ -262,6 +257,7 @@ class InputLogicTest {
reset() reset()
latinIME.prefs().edit { putBoolean(Settings.PREF_URL_DETECTION, true) } 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_AUTOSPACE_AFTER_PUNCTUATION, true) }
latinIME.prefs().edit { putBoolean(Settings.PREF_SHIFT_REMOVES_AUTOSPACE, true) }
input("bla") input("bla")
input('.') input('.')
functionalKeyPress(KeyCode.SHIFT) // should remove the phantom space (in addition to normal effect) 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`() { @Test fun `revert autocorrect on delete`() {
reset() reset()
setInputType(InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_AUTO_CORRECT)
chainInput("hullo") chainInput("hullo")
getAutocorrectedWithSpaceAfter("hello", "hullo") getAutocorrectedWithSpaceAfter("hello", "hullo")
assertEquals("hello ", text)
functionalKeyPress(KeyCode.DELETE) functionalKeyPress(KeyCode.DELETE)
assertEquals("hullo", text) assertEquals("hullo", text)
// todo: now we want some way to disable revert on backspace, either per setting or something else reset()
// need to avoid getting into the mLastComposedWord.canRevertCommit() part of handleBackspaceEvent 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`() { @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 // 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 --------- // ------- helper functions ---------
// should be called before every test, so the same state is guaranteed // 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 info = SuggestedWordInfo(suggestion, "", 0, 0, null, 0, 0)
val typedInfo = SuggestedWordInfo(typedWord, "", 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) 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(' ') input(' ')
checkConnectionConsistency() checkConnectionConsistency()
} }

View file

@ -1,12 +1,23 @@
// SPDX-License-Identifier: GPL-3.0-only // SPDX-License-Identifier: GPL-3.0-only
package helium314.keyboard.latin 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.StringUtils
import helium314.keyboard.latin.common.getFullEmojiAtEnd 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.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
// todo: actually this test could/should be significantly expanded... // todo: actually this test could/should be significantly expanded...
@RunWith(RobolectricTestRunner::class)
@Config(shadows = [
ShadowInputMethodManager2::class,
])
class StringUtilsTest { class StringUtilsTest {
@Test fun `not inside double quotes without quotes`() { @Test fun `not inside double quotes without quotes`() {
assert(!StringUtils.isInsideDoubleQuoteOrAfterDigit("hello yes")) assert(!StringUtils.isInsideDoubleQuoteOrAfterDigit("hello yes"))
@ -41,6 +52,14 @@ class StringUtilsTest {
assert(StringUtils.isInsideDoubleQuoteOrAfterDigit("hello \"yes\", \"h")) 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() { @Test fun detectEmojisAtEnd() {
assertEquals("", getFullEmojiAtEnd("\uD83C\uDF83 ")) assertEquals("", getFullEmojiAtEnd("\uD83C\uDF83 "))
assertEquals("", getFullEmojiAtEnd("a")) 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 * _symbol_alpha_: toggle alpha / symbol keyboard
* _numpad_: toggle numpad layout * _numpad_: toggle numpad layout
* _emoji_: switch to emoji view * _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 * _language_switch_: language switch key
* _action_: the action (enter) key * _action_: the action (enter) key
* _delete_: delete 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. * 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 `\`. * 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`. * 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`. * 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` * 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`