1
0
Fork 0

added support for languages with one text case

This commit is contained in:
sspanak 2023-03-01 14:41:49 +02:00 committed by Dimo Karaivanov
parent e82ae8eaed
commit ca15ff230b
9 changed files with 123 additions and 91 deletions

View file

@ -57,7 +57,8 @@ To support a new language one needs to:
- `name` is the native name of the language (e.g. "English", "Deutsch", "Українська"). - `name` is the native name of the language (e.g. "English", "Deutsch", "Українська").
- `locale` contains the language and the country codes (e.g. "en-US", "es-AR", "it-IT"). Refer to the list of [supported locales in Java](https://www.oracle.com/java/technologies/javase/jdk8-jre8-suported-locales.html#util-text). - `locale` contains the language and the country codes (e.g. "en-US", "es-AR", "it-IT"). Refer to the list of [supported locales in Java](https://www.oracle.com/java/technologies/javase/jdk8-jre8-suported-locales.html#util-text).
- `dictionaryFile` is the name of the dictionary in `assets/` folder. - `dictionaryFile` is the name of the dictionary in `assets/` folder.
- `icon`, `abcLowerCaseIcon` and `abcUpperCaseIcon` are the respective status icons for Predictive mode, ABC (lowercase) and ABC (uppercase). - `icon` is the status icon for Predictive mode.
- `abcLowerCaseIcon` and `abcUpperCaseIcon` are the respective status icons for ABC (non-predictive) modes. Note that, you must not set `abcUpperCaseIcon`, if your language has no uppercase and lowercase letters (like Arabic, Asian scripts and Hebrew).
- Set `isPunctuationPartOfWords` to `true`, if the dictionary contains words with apostrophes or dashes, such as: `it's`, `you'll`, `a'tje` or `п'ят`. This will allow using 1-key for typing them (they will appear as suggestions). `false` will enable faster typing when apostrophes or other punctuation are not part of the words (no such words will be suggested). - Set `isPunctuationPartOfWords` to `true`, if the dictionary contains words with apostrophes or dashes, such as: `it's`, `you'll`, `a'tje` or `п'ят`. This will allow using 1-key for typing them (they will appear as suggestions). `false` will enable faster typing when apostrophes or other punctuation are not part of the words (no such words will be suggested).
- `characterMap` contains the letters and punctuation marks associated with each key. - `characterMap` contains the letters and punctuation marks associated with each key.
- Finally, add the new language to the list in `LanguageCollection.java`. You only need to add it in one place, in the constructor. Please, be nice and maintain the alphabetical order. - Finally, add the new language to the list in `LanguageCollection.java`. You only need to add it in one place, in the constructor. Please, be nice and maintain the alphabetical order.

View file

@ -51,7 +51,7 @@ public class TraditionalT9 extends KeyPadHandler {
private void loadSettings() { private void loadSettings() {
mLanguage = LanguageCollection.getLanguage(settings.getInputLanguage()); mLanguage = LanguageCollection.getLanguage(settings.getInputLanguage());
mEnabledLanguages = settings.getEnabledLanguageIds(); mEnabledLanguages = settings.getEnabledLanguageIds();
mInputMode = InputMode.getInstance(settings, settings.getInputMode()); mInputMode = InputMode.getInstance(settings, mLanguage, settings.getInputMode());
mInputMode.setTextCase(settings.getTextCase()); mInputMode.setTextCase(settings.getTextCase());
} }
@ -96,9 +96,10 @@ public class TraditionalT9 extends KeyPadHandler {
// some input fields support only numbers or are not suited for predictions (e.g. password fields) // some input fields support only numbers or are not suited for predictions (e.g. password fields)
determineAllowedInputModes(); determineAllowedInputModes();
mInputMode = InputModeValidator.validateMode(settings, mInputMode, allowedInputModes); int modeId = InputModeValidator.validateMode(settings, mInputMode, allowedInputModes);
mInputMode = InputMode.getInstance(settings, mLanguage, modeId);
mInputMode.setTextFieldCase(textField.determineTextCase(inputType)); mInputMode.setTextFieldCase(textField.determineTextCase(inputType));
// Some modes may want to change the default text case based on grammar rules. // Some modes may want to change the default text case based on grammar rules.
determineNextTextCase(); determineNextTextCase();
InputModeValidator.validateTextCase(settings, mInputMode, settings.getTextCase()); InputModeValidator.validateTextCase(settings, mInputMode, settings.getTextCase());
@ -197,7 +198,7 @@ public class TraditionalT9 extends KeyPadHandler {
String word = mSuggestionView.getCurrentSuggestion(); String word = mSuggestionView.getCurrentSuggestion();
mInputMode.onAcceptSuggestion(mLanguage, word); mInputMode.onAcceptSuggestion(word);
commitCurrentSuggestion(); commitCurrentSuggestion();
autoCorrectSpace(word, true, -1, false, false); autoCorrectSpace(word, true, -1, false, false);
resetKeyRepeat(); resetKeyRepeat();
@ -208,7 +209,7 @@ public class TraditionalT9 extends KeyPadHandler {
protected boolean onUp() { protected boolean onUp() {
if (previousSuggestion()) { if (previousSuggestion()) {
mInputMode.setWordStem(mLanguage, mSuggestionView.getCurrentSuggestion(), true); mInputMode.setWordStem(mSuggestionView.getCurrentSuggestion(), true);
textField.setComposingTextWithHighlightedStem(mSuggestionView.getCurrentSuggestion(), mInputMode); textField.setComposingTextWithHighlightedStem(mSuggestionView.getCurrentSuggestion(), mInputMode);
return true; return true;
} }
@ -219,7 +220,7 @@ public class TraditionalT9 extends KeyPadHandler {
protected boolean onDown() { protected boolean onDown() {
if (nextSuggestion()) { if (nextSuggestion()) {
mInputMode.setWordStem(mLanguage, mSuggestionView.getCurrentSuggestion(), true); mInputMode.setWordStem(mSuggestionView.getCurrentSuggestion(), true);
textField.setComposingTextWithHighlightedStem(mSuggestionView.getCurrentSuggestion(), mInputMode); textField.setComposingTextWithHighlightedStem(mSuggestionView.getCurrentSuggestion(), mInputMode);
return true; return true;
} }
@ -230,7 +231,7 @@ public class TraditionalT9 extends KeyPadHandler {
protected boolean onLeft() { protected boolean onLeft() {
if (mInputMode.clearWordStem()) { if (mInputMode.clearWordStem()) {
mInputMode.loadSuggestions(handleSuggestionsAsync, mLanguage, getComposingText()); mInputMode.loadSuggestions(handleSuggestionsAsync, getComposingText());
} else { } else {
jumpBeforeComposingText(); jumpBeforeComposingText();
} }
@ -247,8 +248,8 @@ public class TraditionalT9 extends KeyPadHandler {
filter = getComposingText(); filter = getComposingText();
} }
if (mInputMode.setWordStem(mLanguage, filter, repeat)) { if (mInputMode.setWordStem(filter, repeat)) {
mInputMode.loadSuggestions(handleSuggestionsAsync, mLanguage, filter); mInputMode.loadSuggestions(handleSuggestionsAsync, filter);
} else if (filter.length() == 0) { } else if (filter.length() == 0) {
mInputMode.reset(); mInputMode.reset();
} }
@ -270,8 +271,8 @@ public class TraditionalT9 extends KeyPadHandler {
// Automatically accept the current word, when the next one is a space or whatnot, // Automatically accept the current word, when the next one is a space or whatnot,
// instead of requiring "OK" before that. // instead of requiring "OK" before that.
if (mInputMode.shouldAcceptCurrentSuggestion(mLanguage, key, hold, repeat > 0)) { if (mInputMode.shouldAcceptCurrentSuggestion(key, hold, repeat > 0)) {
mInputMode.onAcceptSuggestion(mLanguage, currentWord); mInputMode.onAcceptSuggestion(currentWord);
commitCurrentSuggestion(false); commitCurrentSuggestion(false);
autoCorrectSpace(currentWord, false, key, hold, repeat > 0); autoCorrectSpace(currentWord, false, key, hold, repeat > 0);
currentWord = ""; currentWord = "";
@ -283,7 +284,7 @@ public class TraditionalT9 extends KeyPadHandler {
determineNextTextCase(); determineNextTextCase();
} }
if (!mInputMode.onNumber(mLanguage, key, hold, repeat)) { if (!mInputMode.onNumber(key, hold, repeat)) {
return false; return false;
} }
@ -295,7 +296,7 @@ public class TraditionalT9 extends KeyPadHandler {
if (mInputMode.getWord() != null) { if (mInputMode.getWord() != null) {
currentWord = mInputMode.getWord(); currentWord = mInputMode.getWord();
mInputMode.onAcceptSuggestion(mLanguage, currentWord); mInputMode.onAcceptSuggestion(currentWord);
textField.setText(currentWord); textField.setText(currentWord);
clearSuggestions(); clearSuggestions();
autoCorrectSpace(currentWord, true, key, hold, repeat > 0); autoCorrectSpace(currentWord, true, key, hold, repeat > 0);
@ -333,6 +334,7 @@ public class TraditionalT9 extends KeyPadHandler {
protected boolean onKeyNextLanguage() { protected boolean onKeyNextLanguage() {
if (nextLang()) { if (nextLang()) {
commitCurrentSuggestion(false); commitCurrentSuggestion(false);
mInputMode.changeLanguage(mLanguage);
mInputMode.reset(); mInputMode.reset();
resetKeyRepeat(); resetKeyRepeat();
clearSuggestions(); clearSuggestions();
@ -430,14 +432,14 @@ public class TraditionalT9 extends KeyPadHandler {
private void getSuggestions() { private void getSuggestions() {
if (!mInputMode.loadSuggestions(handleSuggestionsAsync, mLanguage, mSuggestionView.getCurrentSuggestion())) { if (!mInputMode.loadSuggestions(handleSuggestionsAsync, mSuggestionView.getCurrentSuggestion())) {
handleSuggestions(); handleSuggestions();
} }
} }
private void handleSuggestions() { private void handleSuggestions() {
setSuggestions(mInputMode.getSuggestions(mLanguage)); setSuggestions(mInputMode.getSuggestions());
// Put the first suggestion in the text field, // Put the first suggestion in the text field,
// but cut it off to the length of the sequence (how many keys were pressed), // but cut it off to the length of the sequence (how many keys were pressed),
@ -489,7 +491,7 @@ public class TraditionalT9 extends KeyPadHandler {
private void nextInputMode() { private void nextInputMode() {
if (mEditing == EDITING_STRICT_NUMERIC || mEditing == EDITING_DIALER) { if (mEditing == EDITING_STRICT_NUMERIC || mEditing == EDITING_DIALER) {
mInputMode = !mInputMode.is123() ? InputMode.getInstance(settings, InputMode.MODE_123) : mInputMode; mInputMode = !mInputMode.is123() ? InputMode.getInstance(settings, mLanguage, InputMode.MODE_123) : mInputMode;
} }
// when typing a word or viewing scrolling the suggestions, only change the case // when typing a word or viewing scrolling the suggestions, only change the case
else if (!isSuggestionViewHidden()) { else if (!isSuggestionViewHidden()) {
@ -498,9 +500,9 @@ public class TraditionalT9 extends KeyPadHandler {
// When we are in AUTO mode and the dictionary word is in uppercase, // 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. // the mode would switch to UPPERCASE, but visually, the word would not change.
// This is why we retry, until there is a visual change. // This is why we retry, until there is a visual change.
for (int retries = 0; retries < 2; retries++) { for (int retries = 0; retries < 2 && mLanguage.hasUpperCase(); retries++) {
mInputMode.nextTextCase(); mInputMode.nextTextCase();
setSuggestions(mInputMode.getSuggestions(mLanguage), mSuggestionView.getCurrentIndex()); setSuggestions(mInputMode.getSuggestions(), mSuggestionView.getCurrentIndex());
refreshComposingText(); refreshComposingText();
if (!currentSuggestionBefore.equals(getComposingText())) { if (!currentSuggestionBefore.equals(getComposingText())) {
@ -509,17 +511,17 @@ public class TraditionalT9 extends KeyPadHandler {
} }
} }
// make "abc" and "ABC" separate modes from user perspective // make "abc" and "ABC" separate modes from user perspective
else if (mInputMode.isABC() && mInputMode.getTextCase() == InputMode.CASE_LOWER) { else if (mInputMode.isABC() && mInputMode.getTextCase() == InputMode.CASE_LOWER && mLanguage.hasUpperCase()) {
mInputMode.nextTextCase(); mInputMode.nextTextCase();
} else { } else {
int modeIndex = (allowedInputModes.indexOf(mInputMode.getId()) + 1) % allowedInputModes.size(); int modeIndex = (allowedInputModes.indexOf(mInputMode.getId()) + 1) % allowedInputModes.size();
mInputMode = InputMode.getInstance(settings, allowedInputModes.get(modeIndex)); mInputMode = InputMode.getInstance(settings, mLanguage, allowedInputModes.get(modeIndex));
mInputMode.defaultTextCase(); mInputMode.defaultTextCase();
} }
// save the settings for the next time // save the settings for the next time
settings.saveInputMode(mInputMode); settings.saveInputMode(mInputMode.getId());
settings.saveTextCase(mInputMode.getTextCase()); settings.saveTextCase(mInputMode.getTextCase());
UI.updateStatusIcon(this, mLanguage, mInputMode); UI.updateStatusIcon(this, mLanguage, mInputMode);
@ -558,7 +560,7 @@ public class TraditionalT9 extends KeyPadHandler {
textField.setComposingText(word, 0); textField.setComposingText(word, 0);
textField.finishComposingText(); textField.finishComposingText();
mInputMode.onAcceptSuggestion(mLanguage, word); mInputMode.onAcceptSuggestion(word);
mInputMode.reset(); mInputMode.reset();
setSuggestions(null); setSuggestions(null);
} }
@ -569,11 +571,11 @@ public class TraditionalT9 extends KeyPadHandler {
int lastInputModeId = settings.getInputMode(); int lastInputModeId = settings.getInputMode();
if (allowedInputModes.contains(lastInputModeId)) { if (allowedInputModes.contains(lastInputModeId)) {
mInputMode = InputMode.getInstance(settings, lastInputModeId); mInputMode = InputMode.getInstance(settings, mLanguage, lastInputModeId);
} else if (allowedInputModes.contains(InputMode.MODE_ABC)) { } else if (allowedInputModes.contains(InputMode.MODE_ABC)) {
mInputMode = InputMode.getInstance(settings, InputMode.MODE_ABC); mInputMode = InputMode.getInstance(settings, mLanguage, InputMode.MODE_ABC);
} else { } else {
mInputMode = InputMode.getInstance(settings, allowedInputModes.get(0)); mInputMode = InputMode.getInstance(settings, mLanguage, allowedInputModes.get(0));
} }
if (inputType.isDialer()) { if (inputType.isDialer()) {

View file

@ -41,23 +41,19 @@ public class InputModeValidator {
return validLanguage; return validLanguage;
} }
public static InputMode validateMode(SettingsStore settings, InputMode inputMode, ArrayList<Integer> allowedModes) { public static int validateMode(SettingsStore settings, InputMode inputMode, ArrayList<Integer> allowedModes) {
if (allowedModes.size() > 0 && allowedModes.contains(inputMode.getId())) { if (allowedModes.size() > 0 && allowedModes.contains(inputMode.getId())) {
inputMode.reset(); return inputMode.getId();
return inputMode;
} }
InputMode newMode = InputMode.getInstance( int newModeId = allowedModes.size() > 0 ? allowedModes.get(0) : InputMode.MODE_123;
settings, settings.saveInputMode(newModeId);
allowedModes.size() > 0 ? allowedModes.get(0) : InputMode.MODE_123
);
settings.saveInputMode(newMode);
if (newMode.getId() != inputMode.getId()) { if (newModeId != inputMode.getId()) {
Logger.w("tt9/validateMode", "Invalid input mode: " + inputMode.getId() + " Enforcing: " + newMode.getId()); Logger.w("tt9/validateMode", "Invalid input mode: " + inputMode.getId() + " Enforcing: " + newModeId);
} }
return newMode; return newModeId;
} }
public static void validateTextCase(SettingsStore settings, InputMode inputMode, int newTextCase) { public static void validateTextCase(SettingsStore settings, InputMode inputMode, int newTextCase) {

View file

@ -27,16 +27,17 @@ abstract public class InputMode {
protected int textFieldTextCase = CASE_UNDEFINED; protected int textFieldTextCase = CASE_UNDEFINED;
// data // data
protected Language language;
protected ArrayList<String> suggestions = new ArrayList<>(); protected ArrayList<String> suggestions = new ArrayList<>();
protected String word = null; protected String word = null;
public static InputMode getInstance(SettingsStore settings, int mode) { public static InputMode getInstance(SettingsStore settings, Language language, int mode) {
switch (mode) { switch (mode) {
case MODE_PREDICTIVE: case MODE_PREDICTIVE:
return new ModePredictive(settings); return new ModePredictive(settings, language);
case MODE_ABC: case MODE_ABC:
return new ModeABC(); return new ModeABC(language);
default: default:
Logger.w("tt9/InputMode", "Defaulting to mode: " + Mode123.class.getName() + " for unknown InputMode: " + mode); Logger.w("tt9/InputMode", "Defaulting to mode: " + Mode123.class.getName() + " for unknown InputMode: " + mode);
case MODE_123: case MODE_123:
@ -46,17 +47,17 @@ abstract public class InputMode {
// Key handlers. Return "true" when handling the key or "false", when is nothing to do. // Key handlers. Return "true" when handling the key or "false", when is nothing to do.
public boolean onBackspace() { return false; } public boolean onBackspace() { return false; }
abstract public boolean onNumber(Language language, int key, boolean hold, int repeat); abstract public boolean onNumber(int key, boolean hold, int repeat);
// Suggestions // Suggestions
public void onAcceptSuggestion(Language language, String suggestion) {} public void onAcceptSuggestion(String suggestion) {}
protected void onSuggestionsUpdated(Handler handler) { handler.sendEmptyMessage(0); } protected void onSuggestionsUpdated(Handler handler) { handler.sendEmptyMessage(0); }
public boolean loadSuggestions(Handler handler, Language language, String currentWord) { return false; } public boolean loadSuggestions(Handler handler, String currentWord) { return false; }
public ArrayList<String> getSuggestions(Language language) { public ArrayList<String> getSuggestions() {
ArrayList<String> newSuggestions = new ArrayList<>(); ArrayList<String> newSuggestions = new ArrayList<>();
for (String s : suggestions) { for (String s : suggestions) {
newSuggestions.add(adjustSuggestionTextCase(s, textCase, language)); newSuggestions.add(adjustSuggestionTextCase(s, textCase));
} }
return newSuggestions; return newSuggestions;
@ -73,9 +74,14 @@ abstract public class InputMode {
// Utility // Utility
abstract public int getId(); abstract public int getId();
abstract public int getSequenceLength(); // The number of key presses for the current word. abstract public int getSequenceLength(); // The number of key presses for the current word.
public void changeLanguage(Language newLanguage) {
if (newLanguage != null) {
language = newLanguage;
}
}
// Interaction with the IME. Return "true" if it should perform the respective action. // Interaction with the IME. Return "true" if it should perform the respective action.
public boolean shouldAcceptCurrentSuggestion(Language language, int key, boolean hold, boolean repeat) { return false; } public boolean shouldAcceptCurrentSuggestion(int key, boolean hold, boolean repeat) { return false; }
public boolean shouldAddAutoSpace(InputType inputType, TextField textField, boolean isWordAcceptedManually, int incomingKey, boolean hold, boolean repeat) { return false; } public boolean shouldAddAutoSpace(InputType inputType, TextField textField, boolean isWordAcceptedManually, int incomingKey, boolean hold, boolean repeat) { return false; }
public boolean shouldDeletePrecedingSpace(InputType inputType) { return false; } public boolean shouldDeletePrecedingSpace(InputType inputType) { return false; }
public boolean shouldSelectNextSuggestion() { return false; } public boolean shouldSelectNextSuggestion() { return false; }
@ -116,12 +122,12 @@ abstract public class InputMode {
public void determineNextWordTextCase(SettingsStore settings, boolean isThereText, String textBeforeCursor) {} public void determineNextWordTextCase(SettingsStore settings, boolean isThereText, String textBeforeCursor) {}
// Based on the internal logic of the mode (punctuation or grammar rules), re-adjust the text case for when getSuggestions() is called. // Based on the internal logic of the mode (punctuation or grammar rules), re-adjust the text case for when getSuggestions() is called.
protected String adjustSuggestionTextCase(String word, int newTextCase, Language language) { return word; } protected String adjustSuggestionTextCase(String word, int newTextCase) { return word; }
// Stem filtering. // Stem filtering.
// Where applicable, return "true" if the mode supports it and the operation was possible. // Where applicable, return "true" if the mode supports it and the operation was possible.
public boolean clearWordStem() { return false; } public boolean clearWordStem() { return false; }
public boolean isStemFilterFuzzy() { return false; } public boolean isStemFilterFuzzy() { return false; }
public String getWordStem() { return ""; } public String getWordStem() { return ""; }
public boolean setWordStem(Language language, String stem, boolean exact) { return false; } public boolean setWordStem(String stem, boolean exact) { return false; }
} }

View file

@ -2,8 +2,6 @@ package io.github.sspanak.tt9.ime.modes;
import java.util.ArrayList; import java.util.ArrayList;
import io.github.sspanak.tt9.languages.Language;
public class Mode123 extends InputMode { public class Mode123 extends InputMode {
public int getId() { return MODE_123; } public int getId() { return MODE_123; }
@ -12,7 +10,7 @@ public class Mode123 extends InputMode {
} }
public boolean onNumber(Language l, int key, boolean hold, int repeat) { public boolean onNumber(int key, boolean hold, int repeat) {
if (key != 0) { if (key != 0) {
return false; return false;
} }

View file

@ -9,13 +9,13 @@ public class ModeABC extends InputMode {
private boolean shouldSelectNextLetter = false; private boolean shouldSelectNextLetter = false;
ModeABC() { ModeABC(Language lang) {
allowedTextCases.add(CASE_LOWER); changeLanguage(lang);
allowedTextCases.add(CASE_UPPER);
} }
public boolean onNumber(Language language, int key, boolean hold, int repeat) { @Override
public boolean onNumber(int key, boolean hold, int repeat) {
shouldSelectNextLetter = false; shouldSelectNextLetter = false;
suggestions = language.getKeyCharacters(key); suggestions = language.getKeyCharacters(key);
word = null; word = null;
@ -31,18 +31,29 @@ public class ModeABC extends InputMode {
} }
protected String adjustSuggestionTextCase(String word, int newTextCase, Language language) { @Override
protected String adjustSuggestionTextCase(String word, int newTextCase) {
return newTextCase == CASE_UPPER ? word.toUpperCase(language.getLocale()) : word.toLowerCase(language.getLocale()); return newTextCase == CASE_UPPER ? word.toUpperCase(language.getLocale()) : word.toLowerCase(language.getLocale());
} }
@Override
public void changeLanguage(Language language) {
super.changeLanguage(language);
final public boolean isABC() { return true; } allowedTextCases.clear();
public int getSequenceLength() { return 1; } allowedTextCases.add(CASE_LOWER);
if (language.hasUpperCase()) {
allowedTextCases.add(CASE_UPPER);
}
}
public boolean shouldAcceptCurrentSuggestion(Language l, int key, boolean hold, boolean repeat) { return hold || !repeat; } @Override final public boolean isABC() { return true; }
public boolean shouldTrackUpDown() { return true; } @Override public int getSequenceLength() { return 1; }
public boolean shouldTrackLeftRight() { return true; }
public boolean shouldSelectNextSuggestion() { @Override public boolean shouldAcceptCurrentSuggestion(int key, boolean hold, boolean repeat) { return hold || !repeat; }
@Override public boolean shouldTrackUpDown() { return true; }
@Override public boolean shouldTrackLeftRight() { return true; }
@Override public boolean shouldSelectNextSuggestion() {
return shouldSelectNextLetter; return shouldSelectNextLetter;
} }
} }

View file

@ -32,7 +32,6 @@ public class ModePredictive extends InputMode {
private String stem = ""; private String stem = "";
// async suggestion handling // async suggestion handling
private Language currentLanguage = null;
private String currentInputFieldWord = ""; private String currentInputFieldWord = "";
private static Handler handleSuggestionsExternal; private static Handler handleSuggestionsExternal;
@ -44,10 +43,8 @@ public class ModePredictive extends InputMode {
private final String maxEmojiSequence; private final String maxEmojiSequence;
ModePredictive(SettingsStore settings) { ModePredictive(SettingsStore settings, Language lang) {
allowedTextCases.add(CASE_LOWER); changeLanguage(lang);
allowedTextCases.add(CASE_CAPITALIZE);
allowedTextCases.add(CASE_UPPER);
emptyDbWarning = new EmptyDatabaseWarning(settings); emptyDbWarning = new EmptyDatabaseWarning(settings);
this.settings = settings; this.settings = settings;
@ -81,13 +78,13 @@ public class ModePredictive extends InputMode {
@Override @Override
public boolean onNumber(Language language, int key, boolean hold, int repeat) { public boolean onNumber(int key, boolean hold, int repeat) {
if (hold) { if (hold) {
// hold to type any digit // hold to type any digit
reset(); reset();
word = String.valueOf(key); word = String.valueOf(key);
} else if (key == 0 && repeat > 0) { } else if (key == 0 && repeat > 0) {
onDouble0(language); onDouble0();
} else { } else {
// words // words
super.reset(); super.reset();
@ -102,7 +99,7 @@ public class ModePredictive extends InputMode {
* onDouble0 * onDouble0
* Double "0" is a shortcut for the preferred character. * Double "0" is a shortcut for the preferred character.
*/ */
private void onDouble0(Language language) { private void onDouble0() {
try { try {
reset(); reset();
word = settings.getDoubleZeroChar(); word = settings.getDoubleZeroChar();
@ -115,6 +112,19 @@ public class ModePredictive extends InputMode {
} }
@Override
public void changeLanguage(Language language) {
super.changeLanguage(language);
allowedTextCases.clear();
allowedTextCases.add(CASE_LOWER);
if (language.hasUpperCase()) {
allowedTextCases.add(CASE_CAPITALIZE);
allowedTextCases.add(CASE_UPPER);
}
}
@Override @Override
public void reset() { public void reset() {
super.reset(); super.reset();
@ -156,7 +166,7 @@ public class ModePredictive extends InputMode {
* Note that you need to manually get the suggestions again to obtain a filtered list. * Note that you need to manually get the suggestions again to obtain a filtered list.
*/ */
@Override @Override
public boolean setWordStem(Language language, String wordStem, boolean exact) { public boolean setWordStem(String wordStem, boolean exact) {
if (language == null || wordStem == null || wordStem.length() < 1) { if (language == null || wordStem == null || wordStem.length() < 1) {
return false; return false;
} }
@ -202,7 +212,7 @@ public class ModePredictive extends InputMode {
* Similar to "loadSuggestions()", but loads suggestions that are not in the database. * Similar to "loadSuggestions()", but loads suggestions that are not in the database.
* Returns "false", when there are no static suggestions for the current digitSequence. * Returns "false", when there are no static suggestions for the current digitSequence.
*/ */
private boolean loadStaticSuggestions(Language language) { private boolean loadStaticSuggestions() {
if (digitSequence.equals("0")) { if (digitSequence.equals("0")) {
stem = ""; stem = "";
suggestions = language.getKeyCharacters(0, false); suggestions = language.getKeyCharacters(0, false);
@ -231,8 +241,8 @@ public class ModePredictive extends InputMode {
* See: generatePossibleCompletions() * See: generatePossibleCompletions()
*/ */
@Override @Override
public boolean loadSuggestions(Handler handler, Language language, String currentWord) { public boolean loadSuggestions(Handler handler, String currentWord) {
if (loadStaticSuggestions(language)) { if (loadStaticSuggestions()) {
super.onSuggestionsUpdated(handler); super.onSuggestionsUpdated(handler);
return true; return true;
} }
@ -244,7 +254,6 @@ public class ModePredictive extends InputMode {
handleSuggestionsExternal = handler; handleSuggestionsExternal = handler;
currentInputFieldWord = currentWord.toLowerCase(language.getLocale()); currentInputFieldWord = currentWord.toLowerCase(language.getLocale());
currentLanguage = language;
super.reset(); super.reset();
DictionaryDb.getSuggestions( DictionaryDb.getSuggestions(
@ -272,13 +281,13 @@ public class ModePredictive extends InputMode {
dbSuggestions = dbSuggestions == null ? new ArrayList<>() : dbSuggestions; dbSuggestions = dbSuggestions == null ? new ArrayList<>() : dbSuggestions;
if (dbSuggestions.size() == 0 && digitSequence.length() > 0) { if (dbSuggestions.size() == 0 && digitSequence.length() > 0) {
emptyDbWarning.emitOnce(currentLanguage); emptyDbWarning.emitOnce(language);
dbSuggestions = generatePossibleCompletions(currentLanguage, currentInputFieldWord); dbSuggestions = generatePossibleCompletions(currentInputFieldWord);
} }
suggestions.clear(); suggestions.clear();
suggestStem(); suggestStem();
suggestions.addAll(generatePossibleStemVariations(currentLanguage, dbSuggestions)); suggestions.addAll(generatePossibleStemVariations(dbSuggestions));
suggestMoreWords(dbSuggestions); suggestMoreWords(dbSuggestions);
ModePredictive.super.onSuggestionsUpdated(handleSuggestionsExternal); ModePredictive.super.onSuggestionsUpdated(handleSuggestionsExternal);
@ -295,7 +304,7 @@ public class ModePredictive extends InputMode {
* For example, if the word is "missin_" and the last pressed key is "4", the results would be: * For example, if the word is "missin_" and the last pressed key is "4", the results would be:
* | missing | missinh | missini | * | missing | missinh | missini |
*/ */
private ArrayList<String> generatePossibleCompletions(Language language, String baseWord) { private ArrayList<String> generatePossibleCompletions(String baseWord) {
ArrayList<String> generatedWords = new ArrayList<>(); ArrayList<String> generatedWords = new ArrayList<>();
// Make sure the displayed word and the digit sequence, we will be generating suggestions from, // Make sure the displayed word and the digit sequence, we will be generating suggestions from,
@ -334,14 +343,14 @@ public class ModePredictive extends InputMode {
* generate: "extrb" and "extrc". This is useful for typing an unknown word, that is similar to * generate: "extrb" and "extrc". This is useful for typing an unknown word, that is similar to
* the ones in the dictionary. * the ones in the dictionary.
*/ */
private ArrayList<String> generatePossibleStemVariations(Language language, ArrayList<String> dbSuggestions) { private ArrayList<String> generatePossibleStemVariations(ArrayList<String> dbSuggestions) {
ArrayList<String> variations = new ArrayList<>(); ArrayList<String> variations = new ArrayList<>();
if (stem.length() == 0) { if (stem.length() == 0) {
return variations; return variations;
} }
if (isStemFuzzy && stem.length() == digitSequence.length() - 1) { if (isStemFuzzy && stem.length() == digitSequence.length() - 1) {
ArrayList<String> allPossibleVariations = generatePossibleCompletions(language, stem); ArrayList<String> allPossibleVariations = generatePossibleCompletions(stem);
// first add the known words, because it makes more sense to see them first // first add the known words, because it makes more sense to see them first
for (String word : allPossibleVariations) { for (String word : allPossibleVariations) {
@ -391,7 +400,7 @@ public class ModePredictive extends InputMode {
* Bring this word up in the suggestions list next time. * Bring this word up in the suggestions list next time.
*/ */
@Override @Override
public void onAcceptSuggestion(Language language, String currentWord) { public void onAcceptSuggestion(String currentWord) {
lastAcceptedWord = currentWord; lastAcceptedWord = currentWord;
lastAcceptedSequence = digitSequence; lastAcceptedSequence = digitSequence;
reset(); reset();
@ -425,7 +434,7 @@ public class ModePredictive extends InputMode {
* or Dutch words such as: "'s-Hertogenbosch". * or Dutch words such as: "'s-Hertogenbosch".
*/ */
@Override @Override
protected String adjustSuggestionTextCase(String word, int newTextCase, Language language) { protected String adjustSuggestionTextCase(String word, int newTextCase) {
switch (newTextCase) { switch (newTextCase) {
case CASE_UPPER: case CASE_UPPER:
return word.toUpperCase(language.getLocale()); return word.toUpperCase(language.getLocale());
@ -492,7 +501,7 @@ public class ModePredictive extends InputMode {
* we also increase its' priority. This function determines whether we want to do all this or not. * we also increase its' priority. This function determines whether we want to do all this or not.
*/ */
@Override @Override
public boolean shouldAcceptCurrentSuggestion(Language language, int key, boolean hold, boolean repeat) { public boolean shouldAcceptCurrentSuggestion(int key, boolean hold, boolean repeat) {
return return
hold hold
// Quickly accept suggestions using "space" instead of pressing "ok" then "space" // Quickly accept suggestions using "space" instead of pressing "ok" then "space"

View file

@ -68,6 +68,11 @@ public class Language {
final public boolean isPunctuationPartOfWords() { return isPunctuationPartOfWords; } final public boolean isPunctuationPartOfWords() { return isPunctuationPartOfWords; }
final public boolean hasUpperCase() {
return abcUpperCaseIcon != 0;
}
/* ************ utility ************ */ /* ************ utility ************ */
/** /**

View file

@ -140,15 +140,19 @@ public class SettingsStore {
return prefs.getInt("pref_input_mode", InputMode.MODE_PREDICTIVE); return prefs.getInt("pref_input_mode", InputMode.MODE_PREDICTIVE);
} }
public void saveInputMode(InputMode mode) { public void saveInputMode(int mode) {
if (mode == null) { boolean isModeValid = isIntInList(
Logger.w("tt9/saveInputMode", "Not saving NULL input mode"); mode,
return; new ArrayList<>(Arrays.asList(InputMode.MODE_123, InputMode.MODE_PREDICTIVE, InputMode.MODE_ABC)),
} "tt9/saveInputMode",
"Not saving invalid input mode: " + mode
);
prefsEditor.putInt("pref_input_mode", mode.getId()); if (isModeValid) {
prefsEditor.putInt("pref_input_mode", mode);
prefsEditor.apply(); prefsEditor.apply();
} }
}
/************* function key settings *************/ /************* function key settings *************/