1
0
Fork 0

Command palette (#528)

* added a command palette hotkey;

* removed the Settings, Add Word and Change Keyboard hotkeys

* added a compact command palette at the bottom

* big refactoring: cleaned up the IME module, added UiHandler and cleaned up the MainViews

* documentation update
This commit is contained in:
Dimo Karaivanov 2024-05-30 10:01:43 +03:00 committed by GitHub
parent 458f3d106d
commit b5d58f5720
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
42 changed files with 721 additions and 486 deletions

View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:tools="http://schemas.android.com/tools"
android:versionCode="543"
android:versionName="32.0"
android:versionCode="548"
android:versionName="32.5"
xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/> <!-- allows displaying notifications on Android >= 13 -->

View file

@ -24,10 +24,11 @@ abstract public class AbstractHandler extends InputMethodService {
// UI
abstract protected void createSuggestionBar(View mainView);
abstract protected void forceShowWindow();
abstract protected void renderMainView();
abstract protected void setStatusIcon(InputMode mode);
abstract protected void setStatusText(String status);
abstract protected boolean shouldBeVisible();
abstract protected InputMode getInputMode();
abstract protected int getInputModeId();
abstract protected SuggestionOps getSuggestionOps();
abstract protected boolean shouldBeOff();
abstract protected TraditionalT9 getFinalContext();
}

View file

@ -0,0 +1,176 @@
package io.github.sspanak.tt9.ime;
import io.github.sspanak.tt9.R;
import io.github.sspanak.tt9.db.DictionaryLoader;
import io.github.sspanak.tt9.ime.modes.InputMode;
import io.github.sspanak.tt9.ime.modes.ModeABC;
import io.github.sspanak.tt9.languages.LanguageCollection;
import io.github.sspanak.tt9.ui.UI;
import io.github.sspanak.tt9.ui.dialogs.AddWordDialog;
abstract class CommandHandler extends TypingHandler {
@Override
protected boolean onBack() {
if (mainView.isCommandPaletteShown()) {
mainView.hideCommandPalette();
statusBar.setText(mInputMode);
return true;
}
return false;
}
@Override
public boolean onBackspace() {
if (mainView.isCommandPaletteShown()) {
return false;
}
return super.onBackspace();
}
@Override
public boolean onHotkey(int keyCode, boolean repeat, boolean validateOnly) {
return mainView.isCommandPaletteShown();
}
@Override
protected boolean onNumber(int key, boolean hold, int repeat) {
if (!shouldBeOff() && mainView.isCommandPaletteShown()) {
onCommand(key);
return true;
}
return super.onNumber(key, hold, repeat);
}
@Override
public boolean onOK() {
return mainView.isCommandPaletteShown();
}
private void onCommand(int key) {
switch (key) {
case 0:
changeKeyboard();
break;
case 1:
showSettings();
break;
case 2:
mainView.hideCommandPalette();
statusBar.setText(mInputMode);
addWord();
break;
}
}
public void addWord() {
if (mInputMode.isNumeric()) {
return;
}
if (DictionaryLoader.getInstance(this).isRunning()) {
UI.toastShortSingle(this, R.string.dictionary_loading_please_wait);
return;
}
suggestionOps.cancelDelayedAccept();
mInputMode.onAcceptSuggestion(suggestionOps.acceptIncomplete());
String word = textField.getSurroundingWord(mLanguage);
if (word.isEmpty()) {
UI.toastLong(this, R.string.add_word_no_selection);
} else {
AddWordDialog.show(this, mLanguage.getId(), word);
}
}
public void changeKeyboard() {
suggestionOps.cancelDelayedAccept();
UI.showChangeKeyboardDialog(this);
}
protected void nextInputMode() {
if (mInputMode.isPassthrough()) {
return;
} else if (allowedInputModes.size() == 1 && allowedInputModes.contains(InputMode.MODE_123)) {
mInputMode = !mInputMode.is123() ? InputMode.getInstance(settings, mLanguage, inputType, InputMode.MODE_123) : mInputMode;
}
// when typing a word or viewing scrolling the suggestions, only change the case
else if (!suggestionOps.isEmpty()) {
nextTextCase();
}
// make "abc" and "ABC" separate modes from user perspective
else if (mInputMode instanceof ModeABC && mLanguage.hasUpperCase() && mInputMode.getTextCase() == InputMode.CASE_LOWER) {
mInputMode.nextTextCase();
} else {
int nextModeIndex = (allowedInputModes.indexOf(mInputMode.getId()) + 1) % allowedInputModes.size();
mInputMode = InputMode.getInstance(settings, mLanguage, inputType, allowedInputModes.get(nextModeIndex));
mInputMode.setTextFieldCase(inputType.determineTextCase());
mInputMode.determineNextWordTextCase(textField.getStringBeforeCursor());
resetKeyRepeat();
}
// save the settings for the next time
settings.saveInputMode(mInputMode.getId());
settings.saveTextCase(mInputMode.getTextCase());
statusBar.setText(mInputMode);
}
protected void nextLang() {
// select the next language
int previous = mEnabledLanguages.indexOf(mLanguage.getId());
int next = (previous + 1) % mEnabledLanguages.size();
mLanguage = LanguageCollection.getLanguage(getApplicationContext(), mEnabledLanguages.get(next));
// validate and save it for the next time
validateLanguages();
}
protected void nextTextCase() {
String currentSuggestionBefore = suggestionOps.getCurrent();
int currentSuggestionIndex = suggestionOps.getCurrentIndex();
// When we are in AUTO mode and the dictionary word is in uppercase,
// the mode would switch to UPPERCASE, but visually, the word would not change.
// This is why we retry, until there is a visual change.
for (int retries = 0; retries < 2 && mInputMode.nextTextCase(); retries++) {
String currentSuggestionAfter = mInputMode.getSuggestions().size() >= suggestionOps.getCurrentIndex() ? mInputMode.getSuggestions().get(suggestionOps.getCurrentIndex()) : "";
// If the suggestions are special characters, changing the text case means selecting the
// next character group. Hence, "before" and "after" are different. Also, if the new suggestion
// list is shorter, the "before" index may be invalid, so "after" would be empty.
// In these cases, we scroll to the first one, for consistency.
if (currentSuggestionAfter.isEmpty() || !currentSuggestionBefore.equalsIgnoreCase(currentSuggestionAfter)) {
currentSuggestionIndex = 0;
break;
}
// the suggestion list is the same and the text case is different, so let's use it
if (!currentSuggestionBefore.equals(currentSuggestionAfter)) {
break;
}
}
suggestionOps.set(mInputMode.getSuggestions(), currentSuggestionIndex);
textField.setComposingText(suggestionOps.getCurrent());
}
public void showSettings() {
suggestionOps.cancelDelayedAccept();
UI.showSettingsScreen(this);
}
}

View file

@ -7,21 +7,19 @@ import android.view.inputmethod.InputConnection;
import io.github.sspanak.tt9.R;
import io.github.sspanak.tt9.db.DictionaryLoader;
import io.github.sspanak.tt9.ime.helpers.TextField;
import io.github.sspanak.tt9.ime.modes.InputMode;
import io.github.sspanak.tt9.ime.modes.ModeABC;
import io.github.sspanak.tt9.ime.modes.ModePredictive;
import io.github.sspanak.tt9.languages.LanguageCollection;
import io.github.sspanak.tt9.languages.LanguageKind;
import io.github.sspanak.tt9.preferences.helpers.Hotkeys;
import io.github.sspanak.tt9.ui.UI;
import io.github.sspanak.tt9.ui.dialogs.AddWordDialog;
public abstract class HotkeyHandler extends TypingHandler {
public abstract class HotkeyHandler extends CommandHandler {
private boolean isSystemRTL;
@Override
protected void onInit() {
super.onInit();
if (settings.areHotkeysInitialized()) {
Hotkeys.setDefault(settings);
}
@ -35,12 +33,17 @@ public abstract class HotkeyHandler extends TypingHandler {
}
@Override public boolean onBack() {
return settings.isMainLayoutNumpad();
@Override
public boolean onBack() {
return super.onBack() || settings.isMainLayoutNumpad();
}
@Override public boolean onOK() {
if (super.onOK()) {
return true;
}
suggestionOps.cancelDelayedAccept();
if (!suggestionOps.isEmpty()) {
@ -63,16 +66,16 @@ public abstract class HotkeyHandler extends TypingHandler {
public boolean onHotkey(int keyCode, boolean repeat, boolean validateOnly) {
if (super.onHotkey(keyCode, repeat, validateOnly)) {
return true;
}
if (keyCode == KeyEvent.KEYCODE_UNKNOWN) {
return false;
}
if (keyCode == settings.getKeyAddWord()) {
return onKeyAddWord(validateOnly);
}
if (keyCode == settings.getKeyChangeKeyboard()) {
return onKeyChangeKeyboard(validateOnly);
if (keyCode == settings.getKeyCommandPalette()) {
return onKeyCommandPalette(validateOnly);
}
if (keyCode == settings.getKeyFilterClear()) {
@ -99,55 +102,10 @@ public abstract class HotkeyHandler extends TypingHandler {
return onKeyScrollSuggestion(validateOnly, false);
}
if (keyCode == settings.getKeyShowSettings()) {
return onKeyShowSettings(validateOnly);
}
return false;
}
public boolean onKeyAddWord(boolean validateOnly) {
if (shouldBeOff() || mInputMode.isNumeric()) {
return false;
}
if (validateOnly) {
return true;
}
if (DictionaryLoader.getInstance(this).isRunning()) {
UI.toastShortSingle(this, R.string.dictionary_loading_please_wait);
return true;
}
suggestionOps.cancelDelayedAccept();
mInputMode.onAcceptSuggestion(suggestionOps.acceptIncomplete());
String word = textField.getSurroundingWord(mLanguage);
if (word.isEmpty()) {
UI.toastLong(this, R.string.add_word_no_selection);
} else {
AddWordDialog.show(this, mLanguage.getId(), word);
}
return true;
}
public boolean onKeyChangeKeyboard(boolean validateOnly) {
if (shouldBeOff()) {
return false;
}
if (!validateOnly) {
UI.showChangeKeyboardDialog(this);
}
return true;
}
public boolean onKeyFilterClear(boolean validateOnly) {
if (suggestionOps.isEmpty()) {
return false;
@ -230,8 +188,8 @@ public abstract class HotkeyHandler extends TypingHandler {
mInputMode.clearWordStem();
getSuggestions();
setStatusText(mInputMode.toString());
renderMainView();
statusBar.setText(mInputMode);
mainView.render();
if (!suggestionOps.isEmpty() || settings.isMainLayoutStealth()) {
UI.toastShortSingle(this, mInputMode.getClass().getSimpleName(), mInputMode.toString());
}
@ -256,7 +214,7 @@ public abstract class HotkeyHandler extends TypingHandler {
suggestionOps.scheduleDelayedAccept(mInputMode.getAutoAcceptTimeout()); // restart the timer
nextInputMode();
renderMainView();
mainView.render();
if (settings.isMainLayoutStealth()) {
UI.toastShortSingle(this, mInputMode.getClass().getSimpleName(), mInputMode.toString());
@ -267,86 +225,21 @@ public abstract class HotkeyHandler extends TypingHandler {
}
public boolean onKeyShowSettings(boolean validateOnly) {
public boolean onKeyCommandPalette(boolean validateOnly) {
if (shouldBeOff()) {
return false;
}
if (!validateOnly) {
suggestionOps.cancelDelayedAccept();
UI.showSettingsScreen(this);
suggestionOps.acceptIncomplete();
mInputMode.reset();
mainView.showCommandPalette();
statusBar.setText(getString(R.string.commands_select_command));
forceShowWindow();
}
return true;
}
private void nextInputMode() {
if (mInputMode.isPassthrough()) {
return;
} else if (allowedInputModes.size() == 1 && allowedInputModes.contains(InputMode.MODE_123)) {
mInputMode = !mInputMode.is123() ? InputMode.getInstance(settings, mLanguage, inputType, InputMode.MODE_123) : mInputMode;
}
// when typing a word or viewing scrolling the suggestions, only change the case
else if (!suggestionOps.isEmpty()) {
nextTextCase();
}
// make "abc" and "ABC" separate modes from user perspective
else if (mInputMode instanceof ModeABC && mLanguage.hasUpperCase() && mInputMode.getTextCase() == InputMode.CASE_LOWER) {
mInputMode.nextTextCase();
} else {
int nextModeIndex = (allowedInputModes.indexOf(mInputMode.getId()) + 1) % allowedInputModes.size();
mInputMode = InputMode.getInstance(settings, mLanguage, inputType, allowedInputModes.get(nextModeIndex));
mInputMode.setTextFieldCase(inputType.determineTextCase());
mInputMode.determineNextWordTextCase(textField.getStringBeforeCursor());
resetKeyRepeat();
}
// save the settings for the next time
settings.saveInputMode(mInputMode.getId());
settings.saveTextCase(mInputMode.getTextCase());
setStatusText(mInputMode.toString());
}
protected void nextLang() {
// select the next language
int previous = mEnabledLanguages.indexOf(mLanguage.getId());
int next = (previous + 1) % mEnabledLanguages.size();
mLanguage = LanguageCollection.getLanguage(getApplicationContext(), mEnabledLanguages.get(next));
// validate and save it for the next time
validateLanguages();
}
private void nextTextCase() {
String currentSuggestionBefore = suggestionOps.getCurrent();
int currentSuggestionIndex = suggestionOps.getCurrentIndex();
// When we are in AUTO mode and the dictionary word is in uppercase,
// the mode would switch to UPPERCASE, but visually, the word would not change.
// This is why we retry, until there is a visual change.
for (int retries = 0; retries < 2 && mInputMode.nextTextCase(); retries++) {
String currentSuggestionAfter = mInputMode.getSuggestions().size() >= suggestionOps.getCurrentIndex() ? mInputMode.getSuggestions().get(suggestionOps.getCurrentIndex()) : "";
// If the suggestions are special characters, changing the text case means selecting the
// next character group. Hence, "before" and "after" are different. Also, if the new suggestion
// list is shorter, the "before" index may be invalid, so "after" would be empty.
// In these cases, we scroll to the first one, for consistency.
if (currentSuggestionAfter.isEmpty() || !currentSuggestionBefore.equalsIgnoreCase(currentSuggestionAfter)) {
currentSuggestionIndex = 0;
break;
}
// the suggestion list is the same and the text case is different, so let's use it
if (!currentSuggestionBefore.equals(currentSuggestionAfter)) {
break;
}
}
suggestionOps.set(mInputMode.getSuggestions(), currentSuggestionIndex);
textField.setComposingText(suggestionOps.getCurrent());
}
}

View file

@ -8,9 +8,7 @@ import io.github.sspanak.tt9.preferences.settings.SettingsStore;
import io.github.sspanak.tt9.util.Timer;
abstract class KeyPadHandler extends AbstractHandler {
protected SettingsStore settings;
abstract class KeyPadHandler extends UiHandler {
// debounce handling
private final static String DEBOUNCE_TIMER = "debounce_";

View file

@ -1,35 +1,26 @@
package io.github.sspanak.tt9.ime;
import android.content.Intent;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
import androidx.annotation.NonNull;
import io.github.sspanak.tt9.R;
import io.github.sspanak.tt9.db.DictionaryLoader;
import io.github.sspanak.tt9.db.WordStoreAsync;
import io.github.sspanak.tt9.hacks.DeviceInfo;
import io.github.sspanak.tt9.hacks.InputType;
import io.github.sspanak.tt9.ime.modes.InputMode;
import io.github.sspanak.tt9.ime.modes.ModePredictive;
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
import io.github.sspanak.tt9.ui.UI;
import io.github.sspanak.tt9.ui.dialogs.PopupDialog;
import io.github.sspanak.tt9.ui.main.MainView;
import io.github.sspanak.tt9.ui.tray.StatusBar;
import io.github.sspanak.tt9.util.Logger;
public class TraditionalT9 extends MainViewOps {
@NonNull
private final Handler normalizationHandler = new Handler(Looper.getMainLooper());
private MainView mainView = null;
private StatusBar statusBar = null;
@Override
@ -46,14 +37,12 @@ public class TraditionalT9 extends MainViewOps {
}
// Some devices have their own super.onCreateXxxView(), which does some magic allowing our MainView to remain visible.
// This is why we must call the super method, instead of returning null, as in the AOSP code.
@Override
public View onCreateInputView() {
mainView.forceCreateView();
mainView.forceCreateInputView();
initTray();
setDarkTheme();
setStatusText(mInputMode.toString());
statusBar.setText(mInputMode);
suggestionOps.set(mInputMode.getSuggestions());
return mainView.getView();
@ -120,47 +109,11 @@ public class TraditionalT9 extends MainViewOps {
@Override
protected void onInit() {
Logger.setLevel(settings.getLogLevel());
WordStoreAsync.init(this);
if (mainView == null) {
mainView = new MainView(this);
initTray();
}
super.onInit();
}
private void initTray() {
setInputView(mainView.getView());
createSuggestionBar(mainView.getView());
statusBar = new StatusBar(mainView.getView());
}
private void setDarkTheme() {
mainView.setDarkTheme(settings.getDarkTheme());
statusBar.setDarkTheme(settings.getDarkTheme());
suggestionOps.setDarkTheme(settings.getDarkTheme());
}
private void initUi() {
if (mainView.createView()) {
initTray();
}
setStatusIcon(mInputMode);
setStatusText(mInputMode.toString());
setDarkTheme();
mainView.render();
if (!isInputViewShown()) {
updateInputViewShown();
}
}
@Override
protected boolean onStart(InputConnection connection, EditorInfo field) {
if (!super.onStart(connection, field)) {
@ -189,7 +142,7 @@ public class TraditionalT9 extends MainViewOps {
onFinishTyping();
suggestionOps.clear();
setStatusIcon(mInputMode);
setStatusText(mInputMode.toString());
statusBar.setText(mInputMode);
if (isInputViewShown()) {
updateInputViewShown();
@ -212,61 +165,8 @@ public class TraditionalT9 extends MainViewOps {
}
/**
* Populates the UI elements with strings and icons
*/
@Override
protected void renderMainView() {
mainView.render();
}
/**
* forceShowWindow
* Some applications may hide our window and it remains invisible until the screen is touched or OK is pressed.
* This is fine for touchscreen keyboards, but the hardware keyboard allows typing even when the window and the suggestions
* are invisible. This function forces the InputMethodManager to show our window.
* WARNING! Calling this may cause a restart, which will cause InputMode to be recreated. Depending
* on how much time the restart takes, this may erase the current user input.
*/
@Override
protected void forceShowWindow() {
if (isInputViewShown() || !shouldBeVisible()) {
return;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
requestShowSelf(DeviceInfo.isSonimGen2(getApplicationContext()) ? 0 : InputMethodManager.SHOW_IMPLICIT);
} else {
showWindow(true);
}
}
@Override
protected void setStatusIcon(InputMode mode) {
if (!mode.isPassthrough() && settings.isStatusIconEnabled()) {
showStatusIcon(R.drawable.ic_status);
} else {
hideStatusIcon();
}
}
@Override
protected void setStatusText(String status) {
statusBar.setText(status);
}
@Override
protected boolean shouldBeVisible() {
return getInputModeId() != InputMode.MODE_PASSTHROUGH && !settings.isMainLayoutStealth();
}
@Override
protected boolean shouldBeOff() {
return currentInputConnection == null || mInputMode.isPassthrough();
protected TraditionalT9 getFinalContext() {
return this;
}
}

View file

@ -39,11 +39,16 @@ public abstract class TypingHandler extends KeyPadHandler {
protected ArrayList<Integer> mEnabledLanguages;
protected Language mLanguage;
@Override
protected void createSuggestionBar(View mainView) {
suggestionOps = new SuggestionOps(settings, mainView, this::onAcceptSuggestionsDelayed, this::onOK);
}
protected boolean shouldBeOff() {
return currentInputConnection == null || mInputMode.isPassthrough();
}
@Override
protected boolean onStart(InputConnection connection, EditorInfo field) {
boolean restart = textField.equals(connection, field);
@ -302,6 +307,10 @@ public abstract class TypingHandler extends KeyPadHandler {
}
@Override
public SuggestionOps getSuggestionOps() {
return suggestionOps;
}
protected void getSuggestions() {
if (mInputMode instanceof ModePredictive && DictionaryLoader.getInstance(this).isRunning()) {

View file

@ -0,0 +1,91 @@
package io.github.sspanak.tt9.ime;
import android.os.Build;
import android.view.inputmethod.InputMethodManager;
import io.github.sspanak.tt9.R;
import io.github.sspanak.tt9.hacks.DeviceInfo;
import io.github.sspanak.tt9.ime.modes.InputMode;
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
import io.github.sspanak.tt9.ui.main.MainView;
import io.github.sspanak.tt9.ui.tray.StatusBar;
abstract class UiHandler extends AbstractHandler {
protected SettingsStore settings;
protected MainView mainView = null;
protected StatusBar statusBar = null;
@Override
protected void onInit() {
if (mainView == null) {
mainView = new MainView(getFinalContext());
initTray();
}
}
protected void initTray() {
setInputView(mainView.getView());
createSuggestionBar(mainView.getView());
statusBar = new StatusBar(mainView.getView());
}
protected void initUi() {
if (mainView.createInputView()) {
initTray();
}
setDarkTheme();
setStatusIcon(getInputMode());
statusBar.setText(getInputMode());
mainView.hideCommandPalette();
mainView.render();
if (!isInputViewShown()) {
updateInputViewShown();
}
}
protected void setDarkTheme() {
mainView.setDarkTheme(settings.getDarkTheme());
statusBar.setDarkTheme(settings.getDarkTheme());
getSuggestionOps().setDarkTheme(settings.getDarkTheme());
}
protected void setStatusIcon(InputMode mode) {
if (!mode.isPassthrough() && settings.isStatusIconEnabled()) {
showStatusIcon(R.drawable.ic_status);
} else {
hideStatusIcon();
}
}
protected boolean shouldBeVisible() {
return getInputModeId() != InputMode.MODE_PASSTHROUGH && !settings.isMainLayoutStealth();
}
/**
* forceShowWindow
* Some applications may hide our window and it remains invisible until the screen is touched or OK is pressed.
* This is fine for touchscreen keyboards, but the hardware keyboard allows typing even when the window and the suggestions
* are invisible. This function forces the InputMethodManager to show our window.
* WARNING! Calling this may cause a restart, which will cause InputMode to be recreated. Depending
* on how much time the restart takes, this may erase the current user input.
*/
protected void forceShowWindow() {
if (isInputViewShown() || !shouldBeVisible()) {
return;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
requestShowSelf(DeviceInfo.isSonimGen2(getApplicationContext()) ? 0 : InputMethodManager.SHOW_IMPLICIT);
} else {
showWindow(true);
}
}
}

View file

@ -37,16 +37,14 @@ public class Key {
public static boolean isHotkey(SettingsStore settings, int keyCode) {
return keyCode == settings.getKeyAddWord()
|| keyCode == settings.getKeyBackspace()
|| keyCode == settings.getKeyChangeKeyboard()
return keyCode == settings.getKeyBackspace()
|| keyCode == settings.getKeyCommandPalette()
|| keyCode == settings.getKeyFilterClear()
|| keyCode == settings.getKeyFilterSuggestions()
|| keyCode == settings.getKeyPreviousSuggestion()
|| keyCode == settings.getKeyNextSuggestion()
|| keyCode == settings.getKeyNextInputMode()
|| keyCode == settings.getKeyNextLanguage()
|| keyCode == settings.getKeyShowSettings();
|| keyCode == settings.getKeyNextLanguage();
}

View file

@ -67,16 +67,14 @@ public class Hotkeys {
int previousSuggestion = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_DPAD_LEFT) ? KeyEvent.KEYCODE_DPAD_LEFT : 0;
settings.setDefaultKeys(
KeyEvent.KEYCODE_STAR,
backspace,
0, // "change keyboard" is unassigned by default
KeyEvent.KEYCODE_STAR,
clearFilter,
filter,
previousSuggestion,
nextSuggestion,
KeyEvent.KEYCODE_POUND,
-KeyEvent.KEYCODE_POUND, // negative means "hold"
-KeyEvent.KEYCODE_STAR
-KeyEvent.KEYCODE_POUND // negative means "hold"
);
}

View file

@ -20,16 +20,14 @@ public class HotkeysScreen extends BaseScreenFragment {
@Override
public void onCreate() {
DropDownPreference[] dropDowns = {
findPreference(SectionKeymap.ITEM_ADD_WORD),
findPreference(SectionKeymap.ITEM_BACKSPACE),
findPreference(SectionKeymap.ITEM_CHANGE_KEYBOARD),
findPreference(SectionKeymap.ITEM_COMMAND_PALETTE),
findPreference(SectionKeymap.ITEM_FILTER_CLEAR),
findPreference(SectionKeymap.ITEM_FILTER_SUGGESTIONS),
findPreference(SectionKeymap.ITEM_PREVIOUS_SUGGESTION),
findPreference(SectionKeymap.ITEM_NEXT_SUGGESTION),
findPreference(SectionKeymap.ITEM_NEXT_INPUT_MODE),
findPreference(SectionKeymap.ITEM_NEXT_LANGUAGE),
findPreference(SectionKeymap.ITEM_SHOW_SETTINGS),
};
SectionKeymap section = new SectionKeymap(Arrays.asList(dropDowns), activity);
section.populate().activate();

View file

@ -12,16 +12,14 @@ import io.github.sspanak.tt9.preferences.settings.SettingsStore;
import io.github.sspanak.tt9.util.Logger;
public class SectionKeymap {
public static final String ITEM_ADD_WORD = "key_add_word";
public static final String ITEM_BACKSPACE = "key_backspace";
public static final String ITEM_CHANGE_KEYBOARD = "key_change_keyboard";
public static final String ITEM_COMMAND_PALETTE = "key_command_palette";
public static final String ITEM_FILTER_CLEAR = "key_filter_clear";
public static final String ITEM_FILTER_SUGGESTIONS = "key_filter_suggestions";
public static final String ITEM_PREVIOUS_SUGGESTION = "key_previous_suggestion";
public static final String ITEM_NEXT_SUGGESTION = "key_next_suggestion";
public static final String ITEM_NEXT_INPUT_MODE = "key_next_input_mode";
public static final String ITEM_NEXT_LANGUAGE = "key_next_language";
public static final String ITEM_SHOW_SETTINGS = "key_show_settings";
private final Hotkeys hotkeys;
private final Collection<DropDownPreference> items;
@ -116,7 +114,7 @@ public class SectionKeymap {
private void previewCurrentKey(DropDownPreference dropDown) {
previewCurrentKey(dropDown, dropDown.getValue());
previewCurrentKey(dropDown, dropDown != null ? dropDown.getValue() : null);
}

View file

@ -9,33 +9,29 @@ class SettingsHotkeys extends SettingsHacks {
SettingsHotkeys(Context context) { super(context); }
public boolean areHotkeysInitialized() {
return !prefs.getBoolean("hotkeys_initialized", false);
return !prefs.getBoolean("hotkeys_v2_initialized", false);
}
public void setDefaultKeys(
int addWord,
int backspace,
int changeKeyboard,
int comandPalette,
int filterClear,
int filterSuggestions,
int previousSuggestion,
int nextSuggestion,
int nextInputMode,
int nextLanguage,
int showSettings
int nextLanguage
) {
prefsEditor
.putString(SectionKeymap.ITEM_ADD_WORD, String.valueOf(addWord))
.putString(SectionKeymap.ITEM_BACKSPACE, String.valueOf(backspace))
.putString(SectionKeymap.ITEM_CHANGE_KEYBOARD, String.valueOf(changeKeyboard))
.putString(SectionKeymap.ITEM_COMMAND_PALETTE, String.valueOf(comandPalette))
.putString(SectionKeymap.ITEM_FILTER_CLEAR, String.valueOf(filterClear))
.putString(SectionKeymap.ITEM_FILTER_SUGGESTIONS, String.valueOf(filterSuggestions))
.putString(SectionKeymap.ITEM_PREVIOUS_SUGGESTION, String.valueOf(previousSuggestion))
.putString(SectionKeymap.ITEM_NEXT_SUGGESTION, String.valueOf(nextSuggestion))
.putString(SectionKeymap.ITEM_NEXT_INPUT_MODE, String.valueOf(nextInputMode))
.putString(SectionKeymap.ITEM_NEXT_LANGUAGE, String.valueOf(nextLanguage))
.putString(SectionKeymap.ITEM_SHOW_SETTINGS, String.valueOf(showSettings))
.putBoolean("hotkeys_initialized", true)
.putBoolean("hotkeys_v2_initialized", true)
.apply();
}
@ -45,15 +41,9 @@ class SettingsHotkeys extends SettingsHacks {
}
public int getKeyAddWord() {
return getFunctionKey(SectionKeymap.ITEM_ADD_WORD);
}
public int getKeyBackspace() {
return getFunctionKey(SectionKeymap.ITEM_BACKSPACE);
}
public int getKeyChangeKeyboard() {
return getFunctionKey(SectionKeymap.ITEM_CHANGE_KEYBOARD);
}
public int getKeyFilterClear() {
return getFunctionKey(SectionKeymap.ITEM_FILTER_CLEAR);
}
@ -72,7 +62,7 @@ class SettingsHotkeys extends SettingsHacks {
public int getKeyNextLanguage() {
return getFunctionKey(SectionKeymap.ITEM_NEXT_LANGUAGE);
}
public int getKeyShowSettings() {
return getFunctionKey(SectionKeymap.ITEM_SHOW_SETTINGS);
public int getKeyCommandPalette() {
return getFunctionKey(SectionKeymap.ITEM_COMMAND_PALETTE);
}
}

View file

@ -25,6 +25,13 @@ abstract public class ActivityWithNavigation extends AppCompatActivity {
private int lastKey = KeyEvent.KEYCODE_UNKNOWN;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getSettings();
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) {
super.onCreate(savedInstanceState, persistentState);

View file

@ -15,7 +15,8 @@ abstract class BaseMainLayout {
private final int xml;
protected View view = null;
@NonNull protected ArrayList<SoftKey> keys = new ArrayList<>();
@NonNull protected final ArrayList<SoftKey> keys = new ArrayList<>();
BaseMainLayout(TraditionalT9 tt9, int xml) {
this.tt9 = tt9;
@ -33,24 +34,24 @@ abstract class BaseMainLayout {
* More info:
* <a href="https://stackoverflow.com/questions/72382886/system-applies-night-mode-to-views-added-in-service-type-application-overlay">...</a>
*/
abstract public void setDarkTheme(boolean yes);
/**
* render
* Do all the necessary stuff to display the View.
*/
abstract public void render();
void setDarkTheme(boolean dark) {}
/**
* getKeys
* Returns a list of all the usable Soft Keys.
* Returns a list of all the usable Soft Keys. Useful for attaching click handlers and changing
* the color theme.
*/
abstract protected ArrayList<SoftKey> getKeys();
@NonNull protected ArrayList<SoftKey> getKeys() { return keys; }
/**
* getSeparators
* Returns a list of all the separators in the layout so that they can be themed properly.
*/
protected ArrayList<View> getSeparators() { return new ArrayList<>(); }
public View getView() {
protected View getView() {
if (view == null) {
view = View.inflate(tt9.getApplicationContext(), xml, null);
}
@ -59,7 +60,7 @@ abstract class BaseMainLayout {
}
public void enableClickHandlers() {
protected void enableClickHandlers() {
for (SoftKey key : getKeys()) {
key.setTT9(tt9);
}
@ -80,4 +81,11 @@ abstract class BaseMainLayout {
return keyList;
}
/**
* render
* Do all the necessary stuff to display the View.
*/
abstract void render();
}

View file

@ -3,6 +3,7 @@ package io.github.sspanak.tt9.ui.main;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import java.util.ArrayList;
@ -17,29 +18,38 @@ class MainLayoutNumpad extends BaseMainLayout {
super(tt9, R.layout.main_numpad);
}
private int getBackgroundColor(@NonNull View contextView, boolean dark) {
return ContextCompat.getColor(
contextView.getContext(),
dark ? R.color.dark_numpad_background : R.color.numpad_background
);
}
private int getSeparatorColor(@NonNull View contextView, boolean dark) {
return ContextCompat.getColor(
contextView.getContext(),
dark ? R.color.dark_numpad_separator : R.color.numpad_separator
);
}
@Override
public void setDarkTheme(boolean darkEnabled) {
void setDarkTheme(boolean dark) {
if (view == null) {
return;
}
// background
view.setBackground(ContextCompat.getDrawable(
view.getContext(),
darkEnabled ? R.color.dark_numpad_background : R.color.numpad_background
));
view.setBackgroundColor(getBackgroundColor(view, dark));
// text
for (SoftKey key : getKeys()) {
key.setDarkTheme(darkEnabled);
key.setDarkTheme(dark);
}
// separators
int separatorColor = ContextCompat.getColor(
view.getContext(),
darkEnabled ? R.color.dark_numpad_separator : R.color.numpad_separator
);
int separatorColor = getSeparatorColor(view, dark);
for (View separator : getSeparators()) {
if (separator != null) {
separator.setBackgroundColor(separatorColor);
@ -48,7 +58,7 @@ class MainLayoutNumpad extends BaseMainLayout {
}
@Override
public void render() {
void render() {
getView();
enableClickHandlers();
for (SoftKey key : getKeys()) {
@ -56,6 +66,7 @@ class MainLayoutNumpad extends BaseMainLayout {
}
}
@NonNull
@Override
protected ArrayList<SoftKey> getKeys() {
if (!keys.isEmpty()) {

View file

@ -1,9 +1,9 @@
package io.github.sspanak.tt9.ui.main;
import android.graphics.drawable.Drawable;
import android.view.View;
import android.widget.LinearLayout;
import androidx.core.content.ContextCompat;
import androidx.annotation.NonNull;
import java.util.ArrayList;
@ -23,34 +23,28 @@ class MainLayoutSmall extends MainLayoutTray {
}
}
@NonNull
@Override
protected ArrayList<SoftKey> getKeys() {
if (view != null && keys.isEmpty()) {
keys = getKeysFromContainer(view.findViewById(R.id.main_soft_keys));
super.getKeys();
keys.addAll(getKeysFromContainer(view.findViewById(R.id.main_soft_keys)));
}
return keys;
}
@Override
public void setDarkTheme(boolean darkEnabled) {
if (view == null) {
return;
}
protected ArrayList<View> getSeparators() {
ArrayList<View> separators = super.getSeparators();
separators.add(view.findViewById(R.id.main_separator_left));
separators.add(view.findViewById(R.id.main_separator_right));
super.setDarkTheme(darkEnabled);
return separators;
}
// text
for (SoftKey key : getKeys()) {
key.setDarkTheme(darkEnabled);
}
// separators
Drawable separatorColor = ContextCompat.getDrawable(
view.getContext(),
darkEnabled ? R.drawable.button_separator_dark : R.drawable.button_separator
);
view.findViewById(R.id.main_separator_left).setBackground(separatorColor);
view.findViewById(R.id.main_separator_right).setBackground(separatorColor);
@Override
void setDarkTheme(boolean dark) {
super.setDarkTheme(dark);
view.findViewById(R.id.main_soft_keys).setBackground(getBackgroundColor(view, dark));
}
}

View file

@ -1,15 +1,10 @@
package io.github.sspanak.tt9.ui.main;
import java.util.ArrayList;
import io.github.sspanak.tt9.R;
import io.github.sspanak.tt9.ime.TraditionalT9;
import io.github.sspanak.tt9.ui.main.keys.SoftKey;
class MainLayoutStealth extends BaseMainLayout {
MainLayoutStealth(TraditionalT9 tt9) { super(tt9, R.layout.main_stealth); }
@Override public void render() {}
@Override public void setDarkTheme(boolean y) {}
@Override protected ArrayList<SoftKey> getKeys() { return keys; }
@Override void render() {}
}

View file

@ -1,10 +1,14 @@
package io.github.sspanak.tt9.ui.main;
import android.graphics.drawable.Drawable;
import android.view.View;
import android.widget.LinearLayout;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import java.util.ArrayList;
import java.util.Arrays;
import io.github.sspanak.tt9.R;
import io.github.sspanak.tt9.ime.TraditionalT9;
@ -21,26 +25,61 @@ class MainLayoutTray extends BaseMainLayout {
}
}
@Override
protected ArrayList<SoftKey> getKeys() {
return keys;
void showCommandPalette() {
view.findViewById(R.id.main_command_keys).setVisibility(LinearLayout.VISIBLE);
view.findViewById(R.id.main_soft_keys).setVisibility(LinearLayout.GONE);
}
void hideCommandPalette() {
view.findViewById(R.id.main_command_keys).setVisibility(LinearLayout.GONE);
if (this instanceof MainLayoutSmall) {
view.findViewById(R.id.main_soft_keys).setVisibility(LinearLayout.VISIBLE);
}
}
boolean isCommandPaletteShown() {
return view.findViewById(R.id.main_command_keys).getVisibility() == LinearLayout.VISIBLE;
}
protected Drawable getBackgroundColor(@NonNull View contextView, boolean dark) {
return ContextCompat.getDrawable(
contextView.getContext(),
dark ? R.drawable.button_background_dark : R.drawable.button_background
);
}
protected Drawable getSeparatorColor(@NonNull View contextView, boolean dark) {
return ContextCompat.getDrawable(
contextView.getContext(),
dark ? R.drawable.button_separator_dark : R.drawable.button_separator
);
}
@Override
public void setDarkTheme(boolean darkEnabled) {
void setDarkTheme(boolean dark) {
if (view == null) {
return;
}
// background
view.findViewById(R.id.main_soft_keys).setBackground(ContextCompat.getDrawable(
view.getContext(),
darkEnabled ? R.drawable.button_background_dark : R.drawable.button_background
));
view.findViewById(R.id.main_command_keys).setBackground(getBackgroundColor(view, dark));
// text
for (SoftKey key : getKeys()) {
key.setDarkTheme(dark);
}
// separators
Drawable separatorColor = getSeparatorColor(view, dark);
for (View separator : getSeparators()) {
if (separator != null) {
separator.setBackground(separatorColor);
}
}
}
@Override
public void render() {
void render() {
getView();
enableClickHandlers();
setSoftKeysVisibility();
@ -48,4 +87,23 @@ class MainLayoutTray extends BaseMainLayout {
key.render();
}
}
@NonNull
@Override
protected ArrayList<SoftKey> getKeys() {
if (view != null && keys.isEmpty()) {
keys.addAll(getKeysFromContainer(view.findViewById(R.id.main_command_keys)));
}
return keys;
}
@Override
protected ArrayList<View> getSeparators() {
return new ArrayList<>(Arrays.asList(
view.findViewById(R.id.separator_2_1),
view.findViewById(R.id.separator_2_2),
view.findViewById(R.id.separator_3_1),
view.findViewById(R.id.separator_3_2)
));
}
}

View file

@ -13,10 +13,10 @@ public class MainView {
public MainView(TraditionalT9 tt9) {
this.tt9 = tt9;
forceCreateView();
forceCreateInputView();
}
public boolean createView() {
public boolean createInputView() {
SettingsStore settings = tt9.getSettings();
if (settings.isMainLayoutNumpad() && !(main instanceof MainLayoutNumpad)) {
@ -35,10 +35,9 @@ public class MainView {
return true;
}
public void forceCreateView() {
public void forceCreateInputView() {
main = null;
if (!createView()) {
if (!createInputView()) {
Logger.w(getClass().getSimpleName(), "Invalid MainView setting. Creating default.");
main = new MainLayoutSmall(tt9);
}
@ -55,4 +54,20 @@ public class MainView {
public void setDarkTheme(boolean darkEnabled) {
main.setDarkTheme(darkEnabled);
}
public void showCommandPalette() {
if (main instanceof MainLayoutTray) {
((MainLayoutTray) main).showCommandPalette();
}
}
public void hideCommandPalette() {
if (main instanceof MainLayoutTray) {
((MainLayoutTray) main).hideCommandPalette();
}
}
public boolean isCommandPaletteShown() {
return main != null && main instanceof MainLayoutTray && ((MainLayoutTray) main).isCommandPaletteShown();
}
}

View file

@ -0,0 +1,43 @@
package io.github.sspanak.tt9.ui.main.keys;
import android.content.Context;
import android.util.AttributeSet;
public class SoftCommandKey extends SoftNumberKey {
public SoftCommandKey(Context context) {
super(context);
}
public SoftCommandKey(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SoftCommandKey(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected String getTitle() {
return getNumber(getId()) + "";
}
@Override
protected String getSubTitle() {
int number = getNumber(getId());
switch (number) {
case 0:
return "";
case 1:
return "";
case 2:
return "";
case 3:
return "🎤";
// case 5:
// return "";
}
return null;
}
}

View file

@ -146,13 +146,14 @@ public class SoftKey extends androidx.appcompat.widget.AppCompatButton implement
int keyId = getId();
boolean multiplePress = lastPressedKey == keyId;
if (keyId == R.id.soft_key_add_word) return tt9.onKeyAddWord(false);
if (keyId == R.id.soft_key_add_word) { tt9.addWord(); return true; }
if (keyId == R.id.soft_key_command_palette) return tt9.onKeyCommandPalette(false);
if (keyId == R.id.soft_key_filter_suggestions) return tt9.onKeyFilterSuggestions(false, multiplePress);
if (keyId == R.id.soft_key_clear_filter) return tt9.onKeyFilterClear(false);
if (keyId == R.id.soft_key_left_arrow) return tt9.onKeyScrollSuggestion(false, true);
if (keyId == R.id.soft_key_right_arrow) return tt9.onKeyScrollSuggestion(false, false);
if (keyId == R.id.soft_key_language) return tt9.onKeyNextLanguage(false);
if (keyId == R.id.soft_key_settings) return tt9.onKeyShowSettings(false);
if (keyId == R.id.soft_key_settings) { tt9.showSettings(); return true; }
return false;
}

View file

@ -19,7 +19,13 @@ public class SoftKeyInputMode extends SoftKey {
@Override
protected boolean handleHold() {
preventRepeat();
return validateTT9Handler() && tt9.onKeyChangeKeyboard(false);
if (validateTT9Handler()) {
tt9.changeKeyboard();
return true;
}
return false;
}

View file

@ -131,7 +131,7 @@ public class SoftNumberKey extends SoftKey {
return sb.toString();
}
private int getNumber(int keyId) {
protected int getNumber(int keyId) {
if (keyId == R.id.soft_key_0) return 0;
if (keyId == R.id.soft_key_1) return 1;
if (keyId == R.id.soft_key_2) return 2;
@ -146,7 +146,7 @@ public class SoftNumberKey extends SoftKey {
return -1;
}
private int getUpsideDownNumber(int keyId) {
protected int getUpsideDownNumber(int keyId) {
int number = getNumber(keyId);
if (tt9 != null && tt9.getSettings().getUpsideDownKeys()) {

View file

@ -7,6 +7,7 @@ import android.widget.TextView;
import androidx.core.content.ContextCompat;
import io.github.sspanak.tt9.R;
import io.github.sspanak.tt9.ime.modes.InputMode;
import io.github.sspanak.tt9.util.Logger;
public class StatusBar {
@ -20,11 +21,16 @@ public class StatusBar {
public void setText(String text) {
statusText = "[ " + text + " ]";
statusText = text;
this.render();
}
public void setText(InputMode inputMode) {
setText("[ " + inputMode.toString() + " ]");
}
public void setDarkTheme(boolean darkTheme) {
if (statusView == null) {
return;

View file

@ -127,7 +127,6 @@
<io.github.sspanak.tt9.ui.main.keys.SoftBackspaceKey
style="@android:style/Widget.Holo.Button.Borderless"
android:id="@+id/soft_key_backspace"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="@dimen/numpad_control_key_layout_weight"
@ -203,7 +202,6 @@
tools:ignore="HardcodedText">
<io.github.sspanak.tt9.ui.main.keys.SoftKeyInputMode
android:id="@+id/soft_key_input_mode"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
@ -303,7 +301,6 @@
style="@style/numSeparator" />
<io.github.sspanak.tt9.ui.main.keys.SoftOkKey
android:id="@+id/soft_key_ok"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"

View file

@ -27,7 +27,6 @@
</FrameLayout>
<LinearLayout
android:id="@+id/main_soft_keys"
android:layout_width="match_parent"
@ -37,13 +36,13 @@
tools:ignore="HardcodedText,KeyboardInaccessibleWidget">
<io.github.sspanak.tt9.ui.main.keys.SoftKey
android:id="@+id/soft_key_settings"
android:id="@+id/soft_key_command_palette"
style="@android:style/Widget.Holo.Button.Borderless"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="3"
android:focusable="false"
android:text=""
android:text="🛠"
android:textSize="@dimen/soft_key_icon_size" />
<View
@ -76,4 +75,57 @@
android:textSize="@dimen/soft_key_icon_size" />
</LinearLayout>
<LinearLayout
android:id="@+id/main_command_keys"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:visibility="gone">
<io.github.sspanak.tt9.ui.main.keys.SoftCommandKey
android:id="@+id/soft_key_1"
style="@android:style/Widget.Holo.Button.Borderless"
android:textSize="@dimen/soft_key_icon_size"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<View
android:id="@+id/separator_2_1"
style="@style/numSeparator" />
<io.github.sspanak.tt9.ui.main.keys.SoftCommandKey
android:id="@+id/soft_key_2"
style="@android:style/Widget.Holo.Button.Borderless"
android:textSize="@dimen/soft_key_icon_size"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<View
android:id="@+id/separator_2_2"
style="@style/numSeparator" />
<io.github.sspanak.tt9.ui.main.keys.SoftCommandKey
android:id="@+id/soft_key_3"
style="@android:style/Widget.Holo.Button.Borderless"
android:textSize="@dimen/soft_key_icon_size"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<View
android:id="@+id/separator_3_1"
style="@style/numSeparator" />
<io.github.sspanak.tt9.ui.main.keys.SoftCommandKey
android:id="@+id/soft_key_0"
style="@android:style/Widget.Holo.Button.Borderless"
android:textSize="@dimen/soft_key_icon_size"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
</LinearLayout>
</LinearLayout>

View file

@ -13,6 +13,7 @@
<string name="add_word_invalid_language_x">Не може да се добави дума. Неразпознат език: \"%1$d\".</string>
<string name="add_word_success">„%1$s“ е добавена.</string>
<string name="add_word_title">Добавяне на дума</string>
<string name="commands_select_command">Изберете команда</string>
<string name="pref_category_about">За приложението</string>
<string name="pref_layout_numpad">Цифрова клавиатура (БЕТА)</string>
<string name="pref_layout_small">Функционални клавиши</string>
@ -64,18 +65,16 @@
<string name="dictionary_update_update">Зареди</string>
<string name="donate_title">Дарете</string>
<string name="donate_summary">Ако харесвате %1$s, подкрепете разработката му на: %2$s.</string>
<string name="function_add_word_key">Добавяне на нова дума</string>
<string name="function_backspace_key">Триене на текст</string>
<string name="function_change_keyboard_key">Избор на клавиатура</string>
<string name="function_backspace">Триене на текст</string>
<string name="dictionary_no_notifications">Речникови известия</string>
<string name="dictionary_no_notifications_summary">Получавайте известия за обновления на речника и за прогреса при зареждане.</string>
<string name="function_filter_clear_key">Изчистване на филтър</string>
<string name="function_filter_suggestions_key">Филтриране на думи</string>
<string name="function_previous_suggestion_key">Предишна дума</string>
<string name="function_next_suggestion_key">Следваща дума</string>
<string name="function_next_language_key">Следващ eзик</string>
<string name="function_next_mode_key">Режим на писане</string>
<string name="function_show_settings_key">Настройки</string>
<string name="function_show_command_palette">Списък с команди</string>
<string name="function_filter_clear">Изчистване на филтър</string>
<string name="function_filter_suggestions">Филтриране на думи</string>
<string name="function_previous_suggestion">Предишна дума</string>
<string name="function_next_suggestion">Следваща дума</string>
<string name="function_next_language">Следващ eзик</string>
<string name="function_next_mode">Режим на писане</string>
<string name="function_reset_keys_title">Възстанови стандартните бутони</string>
<string name="function_reset_keys_done">Възстановени са стандартните „бързи“ бутони.</string>
<string name="setup_keyboard_status">Състояние</string>

View file

@ -14,6 +14,7 @@
<string name="add_word_success">\"%1$s\" hinzugefügt.</string>
<string name="add_word_title">Wort hinzufügen</string>
<string name="commands_select_command">Einen Befehl auswählen</string>
<string name="pref_category_about">Über die Anwendung</string>
<string name="pref_layout_numpad">Ziffernblock (BETA)</string>
<string name="pref_layout_small">Funktionstasten</string>
@ -54,8 +55,7 @@
<string name="pref_category_function_keys">Tastenkürzel</string>
<string name="pref_category_keypad">Tastenfeld</string>
<string name="char_space">Leerzeichen</string>
<string name="function_backspace_key">Rücktaste</string>
<string name="function_change_keyboard_key">Tastaturauswahl</string>
<string name="function_backspace">Rücktaste</string>
<string name="setup_keyboard_status">Status</string>
<string name="setup_default_keyboard">Standardtastatur auswählen</string>
<string name="setup_tt9_on">%1$s ist aktiviert</string>
@ -108,4 +108,5 @@
<string name="dictionary_no_notifications_summary">Benachrichtigen über Wörterbuchaktualisierungen und den Ladevorgang.</string>
<string name="pref_font_size">Schriftgröße der Einstellungen</string>
<string name="pref_font_size_default">Standard</string>
<string name="function_show_command_palette">Befehlsliste anzeigen</string>
</resources>

View file

@ -33,8 +33,7 @@
<string name="pref_dark_theme">Tema oscuro</string>
<string name="char_space">Espacio</string>
<string name="dictionary_truncating">Borrando…</string>
<string name="function_add_word_key">Agregar palabra</string>
<string name="function_backspace_key">Retroceso</string>
<string name="function_backspace">Retroceso</string>
<string name="setup_keyboard_status">Estado</string>
<string name="setup_default_keyboard">Selecciona teclado predeterminado</string>
<string name="char_newline">Nueva línea</string>
@ -42,6 +41,7 @@
<string name="dictionary_load_title">Cargar los seleccionados</string>
<string name="dictionary_loading_indeterminate">Cargando diccionario</string>
<string name="dictionary_loading">Cargando diccionario (%1$s)…</string>
<string name="commands_select_command">Seleccionar un comando</string>
<string name="pref_category_about">Acerca de esta aplicación</string>
<string name="dictionary_not_found">Falló al cargar. No se encontró el diccionario para \"%1$s\".</string>
<string name="dictionary_truncate_title">Borrar todos</string>
@ -71,16 +71,15 @@
<string name="pref_upside_down_keys_summary">Habilite la configuración si hay 789 en la primera fila, en lugar de 123.</string>
<string name="pref_category_setup">Configuración inicial</string>
<string name="error">Error</string>
<string name="function_change_keyboard_key">Cambiar el teclado</string>
<string name="dictionary_no_notifications">Notificaciones del diccionario</string>
<string name="dictionary_no_notifications_summary">Recibir notificaciones sobre actualizaciones del diccionario y sobre el progreso de la carga.</string>
<string name="function_filter_clear_key">Limpiar el filtro</string>
<string name="function_filter_suggestions_key">Filtrar sugerencias</string>
<string name="function_previous_suggestion_key">Sugerencia previa</string>
<string name="function_next_suggestion_key">Sugerencia siguiente</string>
<string name="function_next_language_key">Idioma siguiente</string>
<string name="function_next_mode_key">Modo de ingreso</string>
<string name="function_show_settings_key">Mostrar configuración</string>
<string name="function_show_command_palette">Lista de comandos</string>
<string name="function_filter_clear">Limpiar el filtro</string>
<string name="function_filter_suggestions">Filtrar sugerencias</string>
<string name="function_previous_suggestion">Sugerencia previa</string>
<string name="function_next_suggestion">Sugerencia siguiente</string>
<string name="function_next_language">Idioma siguiente</string>
<string name="function_next_mode">Modo de ingreso</string>
<string name="function_reset_keys_title">Restaurar valores de teclas por defecto</string>
<string name="function_reset_keys_done">Valores de teclas por defecto restaurados</string>
<string name="setup_tt9_on">%1$s está habilitado</string>

View file

@ -13,6 +13,7 @@
<string name="add_word_invalid_language_x">Impossible d\'ajouter un mot. Langue inconnue : « %1$d ».</string>
<string name="add_word_success">« %1$s » est ajouté</string>
<string name="add_word_title">Ajouter un mot</string>
<string name="commands_select_command">Sélectionner une commande</string>
<string name="pref_category_about">À propos de l\'application</string>
<string name="pref_layout_numpad">Pavé numérique (BETA)</string>
<string name="pref_layout_small">Touches de fonction</string>
@ -62,18 +63,16 @@
<string name="pref_auto_text_case_summary">Commencer automatiquement les phrases avec une majuscule.</string>
<string name="pref_category_keypad">Clavier</string>
<string name="char_space">Espace</string>
<string name="function_add_word_key">Ajouter un mot</string>
<string name="function_backspace_key">Retour arrière</string>
<string name="function_change_keyboard_key">Changer le clavier</string>
<string name="function_backspace">Retour arrière</string>
<string name="dictionary_no_notifications">Notifications du dictionnaire</string>
<string name="dictionary_no_notifications_summary">Recevoir des notifications sur les mises à jour du dictionnaire et sur la progression du chargement.</string>
<string name="function_filter_clear_key">Supprimer le filtre</string>
<string name="function_filter_suggestions_key">Filtrer les mots</string>
<string name="function_previous_suggestion_key">Mot précédent</string>
<string name="function_next_suggestion_key">Mot suivant</string>
<string name="function_next_language_key">Langue suivante</string>
<string name="function_next_mode_key">Mode de saisie suivant</string>
<string name="function_show_settings_key">Afficher les paramètres</string>
<string name="function_show_command_palette">Liste des commandes</string>
<string name="function_filter_clear">Supprimer le filtre</string>
<string name="function_filter_suggestions">Filtrer les mots</string>
<string name="function_previous_suggestion">Mot précédent</string>
<string name="function_next_suggestion">Mot suivant</string>
<string name="function_next_language">Langue suivante</string>
<string name="function_next_mode">Mode de saisie suivant</string>
<string name="function_reset_keys_title">Restaurer les paramètres par défaut</string>
<string name="function_reset_keys_done">Paramètres par défaut sont restaurés.</string>
<string name="setup_keyboard_status">État</string>

View file

@ -16,6 +16,7 @@
<string name="add_word_success">\"%1$s\" aggiunta.</string>
<string name="add_word_title">Aggiungi parola</string>
<string name="commands_select_command">Selezionare un comando</string>
<string name="pref_category_about">Sull\'applicazione</string>
<string name="pref_layout_numpad">Tastierino numerico (BETA)</string>
<string name="pref_layout_small">Tasti di funzione</string>
@ -56,8 +57,7 @@
<string name="dictionary_load_cancelled">Caricamento annullato.</string>
<string name="pref_category_keypad">Tastiera</string>
<string name="char_space">Spazio</string>
<string name="function_backspace_key">Backspace</string>
<string name="function_change_keyboard_key">Cambia la tastiera</string>
<string name="function_backspace">Backspace</string>
<string name="setup_keyboard_status">Stato</string>
<string name="setup_default_keyboard">Seleziona la tastiera predefinita</string>
<string name="setup_tt9_on">%1$s è abilitato</string>
@ -110,5 +110,6 @@
<string name="dictionary_no_notifications_summary">Ricevere notifiche sugli aggiornamenti del dizionario e sul progresso del caricamento.</string>
<string name="pref_font_size">Dimensione del carattere delle impostazioni</string>
<string name="pref_font_size_default">Predefinita</string>
<string name="function_show_command_palette">Mostra elenco comandi</string>
</resources>

View file

@ -16,6 +16,7 @@
<string name="add_word_success">%1$s נוסף.</string>
<string name="add_word_title">הוסף מילה</string>
<string name="commands_select_command">לבחור פקודה</string>
<string name="pref_category_about">אודות</string>
<string name="pref_category_abc_mode">מצב אבג</string>
<string name="pref_category_custom_words">מילים שהוספו</string>
@ -68,12 +69,9 @@
<string name="dictionary_truncated">המילון נוקה בהצלחה</string>
<string name="dictionary_truncating">המחיקה מתבצעת…</string>
<string name="function_add_word_key">לחצן הוספת מילה</string>
<string name="function_backspace_key">לחצן מחיקה</string>
<string name="function_change_keyboard_key">בחירת מקלדת</string>
<string name="function_next_language_key">לחצן למעבר לשפה הבאה</string>
<string name="function_next_mode_key">לחצן מצב קלט</string>
<string name="function_show_settings_key">לחצן הצגת הגדרות</string>
<string name="function_backspace">לחצן מחיקה</string>
<string name="function_next_language">לחצן למעבר לשפה הבאה</string>
<string name="function_next_mode">לחצן מצב קלט</string>
<string name="function_reset_keys_title">שחזור לחצני ברירת מחדל</string>
<string name="function_reset_keys_done">הגדרות ברירת המחדל שוחזרו.</string>
@ -125,4 +123,5 @@
<string name="dictionary_no_notifications_summary">לקבל התראות על עדכוני המילון ועל התקדמות הטעינה.</string>
<string name="pref_font_size">גודל הגופן בהגדרות</string>
<string name="pref_font_size_default">ברירת מחדל</string>
<string name="function_show_command_palette">הצג רשימת פקודות</string>
</resources>

View file

@ -18,6 +18,7 @@
<string name="add_word_success">Žodis \"%1$s\" pridėtas.</string>
<string name="add_word_title">Pridėti žodį</string>
<string name="commands_select_command">Pasirinkti komandą</string>
<string name="pref_category_about">Apie programėlę</string>
<string name="pref_category_abc_mode">ABC metodas</string>
<string name="pref_category_hacks">Suderinamumas</string>
@ -72,18 +73,16 @@
<string name="dictionary_truncated">Žodynas sėkmingai ištrintas.</string>
<string name="dictionary_truncating">Ištrinama…</string>
<string name="function_add_word_key">Pridėti žodį</string>
<string name="function_backspace_key">Trinti</string>
<string name="function_change_keyboard_key">Keisti klaviatūrą</string>
<string name="function_backspace">Trinti</string>
<string name="dictionary_no_notifications">Žodyno pranešimai</string>
<string name="dictionary_no_notifications_summary">Gaukite pranešimus apie žodynų atnaujinimus ir įkėlimo progresą.</string>
<string name="function_filter_clear_key">Panaikinti filtrą</string>
<string name="function_filter_suggestions_key">Filtruoti pasiūlymus</string>
<string name="function_previous_suggestion_key">Ankstesnis pasiūlytas žodis</string>
<string name="function_next_suggestion_key">Sekantis pasiūlytas žodis</string>
<string name="function_next_language_key">Rašymo kalba</string>
<string name="function_next_mode_key">Rašymo būdas</string>
<string name="function_show_settings_key">Rodyti nustatymus</string>
<string name="function_show_command_palette">Rodyti komandų sąrašą</string>
<string name="function_filter_clear">Panaikinti filtrą</string>
<string name="function_filter_suggestions">Filtruoti pasiūlymus</string>
<string name="function_previous_suggestion">Ankstesnis pasiūlytas žodis</string>
<string name="function_next_suggestion">Sekantis pasiūlytas žodis</string>
<string name="function_next_language">Rašymo kalba</string>
<string name="function_next_mode">Rašymo būdas</string>
<string name="function_reset_keys_title">Atkurti numatytąsias reikšmes</string>
<string name="function_reset_keys_done">Numatytosios reikšmės atkurtos.</string>

View file

@ -13,6 +13,7 @@
<string name="add_word_invalid_language_x">Kan geen woord toevoegen. Onbekende taal: \"%1$d\".</string>
<string name="add_word_success">\"%1$s\" toegevoegd.</string>
<string name="add_word_title">Woord toevoegen</string>
<string name="commands_select_command">Een commando selecteren</string>
<string name="pref_category_about">Over de applicatie</string>
<string name="pref_layout_numpad">Numeriek toetsenbord (BETA)</string>
<string name="pref_layout_small">Functieknoppen</string>
@ -55,8 +56,7 @@
<string name="pref_category_function_keys">Sneltoetsen</string>
<string name="pref_category_keypad">Toetsenbord</string>
<string name="char_space">Spatie</string>
<string name="function_backspace_key">Backspace</string>
<string name="function_change_keyboard_key">Toetsenbordkeuze</string>
<string name="function_backspace">Backspace</string>
<string name="setup_keyboard_status">Status</string>
<string name="setup_default_keyboard">Standaardtoetsenbord selecteren</string>
<string name="setup_tt9_on">%1$s is ingeschakeld</string>
@ -106,4 +106,5 @@
<string name="dictionary_no_notifications_summary">Ontvang meldingen over woordenboekupdates en de voortgang van het laden.</string>
<string name="pref_font_size">Instellingen lettergrootte</string>
<string name="pref_font_size_default">Standaard</string>
<string name="function_show_command_palette">Toon opdrachtenlijst</string>
</resources>

View file

@ -16,6 +16,7 @@
<string name="add_word_success">\"%1$s\" adicionada.</string>
<string name="add_word_title">Adicionar Palavra</string>
<string name="commands_select_command">Selecionar um comando</string>
<string name="pref_category_about">Sobre</string>
<string name="pref_category_abc_mode">Modo ABC</string>
<string name="pref_category_custom_words">Palavras adicionadas</string>
@ -65,12 +66,9 @@
<string name="dictionary_truncate_title">Limpar Dicionário</string>
<string name="dictionary_truncated">Dicionário apagado com sucesso.</string>
<string name="function_add_word_key">Adicionar palavra</string>
<string name="function_backspace_key">Backspace</string>
<string name="function_change_keyboard_key">Mude o teclado</string>
<string name="function_next_language_key">Próximo Idioma</string>
<string name="function_next_mode_key">Modo de Entrada</string>
<string name="function_show_settings_key">Entrar em Configurações</string>
<string name="function_backspace">Backspace</string>
<string name="function_next_language">Próximo Idioma</string>
<string name="function_next_mode">Modo de Entrada</string>
<string name="function_reset_keys_title">Restaurar Atalhos Padrão</string>
<string name="function_reset_keys_done">Atalhos Restaurados.</string>
@ -127,4 +125,5 @@
<string name="dictionary_no_notifications_summary">Receber notificações sobre atualizações do dicionário e sobre o progresso do carregamento.</string>
<string name="pref_font_size">Tamanho da fonte das configurações</string>
<string name="pref_font_size_default">Padrão</string>
<string name="function_show_command_palette">Lista de comandos</string>
</resources>

View file

@ -13,6 +13,7 @@
<string name="add_word_invalid_language_x">Невозможно добавить слово. Неизвестный язык: \"%1$d\".</string>
<string name="add_word_success">« %1$s » добавлено</string>
<string name="add_word_title">Добавить слово</string>
<string name="commands_select_command">Выбрать команду</string>
<string name="pref_category_about">О приложении</string>
<string name="pref_layout_numpad">Цифровая клавиатура (БЕТА)</string>
<string name="pref_layout_small">Функциональные клавиши</string>
@ -61,18 +62,16 @@
<string name="pref_double_zero_char">Символ при двойном нажатии клавиши 0</string>
<string name="pref_hack_fb_messenger">Отправка с «ОК» в Messenger</string>
<string name="dictionary_load_bad_char">Не удалось загрузить словарь. Проблема в слове «%1$s» в строке %2$d для языка «%3$s».</string>
<string name="function_add_word_key">Добавить новое слово</string>
<string name="function_backspace_key">Стереть</string>
<string name="function_change_keyboard_key">Выбор клавиатуры</string>
<string name="function_backspace">Стереть</string>
<string name="dictionary_no_notifications">Уведомления словаря</string>
<string name="dictionary_no_notifications_summary">Получать уведомления о обновлениях словаря и о процессе загрузки.</string>
<string name="function_filter_clear_key">Удалить фильтр</string>
<string name="function_filter_suggestions_key">Фильтровать слова</string>
<string name="function_previous_suggestion_key">Предыдущее слово</string>
<string name="function_next_suggestion_key">Следующее слово</string>
<string name="function_next_language_key">Следующий язык</string>
<string name="function_next_mode_key">Режим ввода</string>
<string name="function_show_settings_key">Настройки</string>
<string name="function_show_command_palette">Список команд</string>
<string name="function_filter_clear">Удалить фильтр</string>
<string name="function_filter_suggestions">Фильтровать слова</string>
<string name="function_previous_suggestion">Предыдущее слово</string>
<string name="function_next_suggestion">Следующее слово</string>
<string name="function_next_language">Следующий язык</string>
<string name="function_next_mode">Режим ввода</string>
<string name="function_reset_keys_title">Вернуть кнопки по умолчанию</string>
<string name="function_reset_keys_done">Настройки кнопок по умолчанию восстановлены.</string>
<string name="setup_keyboard_status">Состояние</string>

View file

@ -14,6 +14,7 @@
<string name="add_word_success">\"%1$s\" başarıyla eklendi.</string>
<string name="add_word_title">Kelime Ekle</string>
<string name="commands_select_command">Bir komut seç</string>
<string name="pref_category_about">Hakkında</string>
<string name="pref_layout_numpad">Sanal Tuş Takımı (BETA)</string>
<string name="pref_layout_small">İşlevsel Tuşlar</string>
@ -56,8 +57,7 @@
<string name="pref_category_function_keys">Klavye Kısayolları</string>
<string name="pref_category_keypad">Tuş Takımı</string>
<string name="char_space">Boşluk</string>
<string name="function_backspace_key">Geri Tuşu</string>
<string name="function_change_keyboard_key">Klavye Seçimi</string>
<string name="function_backspace">Geri Tuşu</string>
<string name="setup_keyboard_status">Durum</string>
<string name="setup_default_keyboard">Varsayılan Klavyeyi Seçin</string>
<string name="setup_tt9_on">%1$s devrede</string>
@ -114,14 +114,13 @@
<string name="pref_upside_down_keys">Tuş Düzenini Tersine Çevir</string>
<string name="pref_upside_down_keys_summary">Eğer ilk satırda 123 yerine 789 kullanıyorsanız bunu aktif edin.</string>
<string name="function_add_word_key">Kelime ekle</string>
<string name="function_filter_clear_key">Filtre Temizle</string>
<string name="function_filter_suggestions_key">Tahminleri Filtrele</string>
<string name="function_previous_suggestion_key">Önceki Tahmin</string>
<string name="function_next_suggestion_key">Sonraki Tahmin</string>
<string name="function_next_language_key">Sonraki Dil</string>
<string name="function_next_mode_key">Giriş Yöntemi</string>
<string name="function_show_settings_key">Ayarları Göster</string>
<string name="function_show_command_palette">Komut listesini göster</string>
<string name="function_filter_clear">Filtre Temizle</string>
<string name="function_filter_suggestions">Tahminleri Filtrele</string>
<string name="function_previous_suggestion">Önceki Tahmin</string>
<string name="function_next_suggestion">Sonraki Tahmin</string>
<string name="function_next_language">Sonraki Dil</string>
<string name="function_next_mode">Giriş Yöntemi</string>
<string name="function_reset_keys_title">Varsayılan Ayarlara Geri Dön</string>
<string name="function_reset_keys_done">Varsayılan tuş ayarlarına dönüldü.</string>
</resources>

View file

@ -18,6 +18,7 @@
<string name="add_word_success">\"%1$s\" додано.</string>
<string name="add_word_title">Додати слово</string>
<string name="commands_select_command">Вибрати команду</string>
<string name="pref_category_about">Про програму</string>
<string name="pref_category_abc_mode">Режим АБВ</string>
<string name="pref_category_custom_words">Додані слова</string>
@ -99,18 +100,16 @@
<string name="donate_title">Підтримати</string>
<string name="donate_summary">Якщо вам подобається %1$s, ви можете підтримати розробку по посиланню: %2$s.</string>
<string name="function_add_word_key">Додати слово</string>
<string name="function_backspace_key">Стерти</string>
<string name="function_change_keyboard_key">Змінити клавіатуру</string>
<string name="function_backspace">Стерти</string>
<string name="dictionary_no_notifications">Сповіщення словника</string>
<string name="dictionary_no_notifications_summary">Отримувати повідомлення про оновлення словника та процес завантаження.</string>
<string name="function_filter_clear_key">Очистити фільтр</string>
<string name="function_filter_suggestions_key">Фільтрувати пропозиції</string>
<string name="function_previous_suggestion_key">Попередня пропозиція</string>
<string name="function_next_suggestion_key">Наступна пропозиція</string>
<string name="function_next_language_key">Наступна мова</string>
<string name="function_next_mode_key">Режим вводу</string>
<string name="function_show_settings_key">Показати налаштування</string>
<string name="function_show_command_palette">Список команд</string>
<string name="function_filter_clear">Очистити фільтр</string>
<string name="function_filter_suggestions">Фільтрувати пропозиції</string>
<string name="function_previous_suggestion">Попередня пропозиція</string>
<string name="function_next_suggestion">Наступна пропозиція</string>
<string name="function_next_language">Наступна мова</string>
<string name="function_next_mode">Режим вводу</string>
<string name="function_reset_keys_title">Відновити стандартні клавіші</string>
<string name="function_reset_keys_done">Стандартні налаштування клавіш відновленно.</string>

View file

@ -21,6 +21,8 @@
<string name="add_word_success">\"%1$s\" added.</string>
<string name="add_word_title">Add Word</string>
<string name="commands_select_command">Select a Command</string>
<string name="pref_category_about">About</string>
<string name="pref_category_abc_mode">ABC Mode</string>
<string name="pref_category_custom_words">Added Words</string>
@ -118,16 +120,14 @@
<string name="donate_url" translatable="false">https://www.buymeacoffee.com/sspanak</string>
<string name="donate_url_short" translatable="false">www.buymeacoffee.com</string>
<string name="function_add_word_key">Add Word</string>
<string name="function_backspace_key">Backspace</string>
<string name="function_change_keyboard_key">Change Keyboard</string>
<string name="function_filter_clear_key">Clear Filter</string>
<string name="function_filter_suggestions_key">Filter Suggestions</string>
<string name="function_previous_suggestion_key">Previous Suggestion</string>
<string name="function_next_suggestion_key">Next Suggestion</string>
<string name="function_next_language_key">Next Language</string>
<string name="function_next_mode_key">Input Mode</string>
<string name="function_show_settings_key">Show Settings</string>
<string name="function_backspace">Backspace</string>
<string name="function_show_command_palette">Show Command List</string>
<string name="function_filter_clear">Clear Filter</string>
<string name="function_filter_suggestions">Filter Suggestions</string>
<string name="function_previous_suggestion">Previous Suggestion</string>
<string name="function_next_suggestion">Next Suggestion</string>
<string name="function_next_language">Next Language</string>
<string name="function_next_mode">Input Mode</string>
<string name="function_reset_keys_title">Restore Default Keys</string>
<string name="function_reset_keys_done">Default key settings restored.</string>

View file

@ -3,44 +3,36 @@
app:orderingFromXml="true">
<DropDownPreference
app:key="key_add_word"
app:title="@string/function_add_word_key" />
app:key="key_backspace"
app:title="@string/function_backspace" />
<DropDownPreference
app:key="key_backspace"
app:title="@string/function_backspace_key" />
app:key="key_command_palette"
app:title="@string/function_show_command_palette" />
<DropDownPreference
app:key="key_filter_clear"
app:title="@string/function_filter_clear_key" />
app:title="@string/function_filter_clear" />
<DropDownPreference
app:key="key_filter_suggestions"
app:title="@string/function_filter_suggestions_key" />
app:title="@string/function_filter_suggestions" />
<DropDownPreference
app:key="key_previous_suggestion"
app:title="@string/function_previous_suggestion_key" />
app:title="@string/function_previous_suggestion" />
<DropDownPreference
app:key="key_next_suggestion"
app:title="@string/function_next_suggestion_key" />
app:title="@string/function_next_suggestion" />
<DropDownPreference
app:key="key_next_language"
app:title="@string/function_next_language_key" />
app:title="@string/function_next_language" />
<DropDownPreference
app:key="key_next_input_mode"
app:title="@string/function_next_mode_key" />
<DropDownPreference
app:key="key_change_keyboard"
app:title="@string/function_change_keyboard_key" />
<DropDownPreference
app:key="key_show_settings"
app:title="@string/function_show_settings_key" />
app:title="@string/function_next_mode" />
<Preference
app:key="reset_keys"