Suggestion improvements (#93)
* Predictive mode: when automatic text case is selected, capitalized dictionary words are displayed correctly (Dutch and German) * Predictive mode: when generated and dictionary suggestions are displayed together, the dictionary suggestions come first * Removed a nonsense Bulgarian word * Added "it's" and "let's" to English * InputMode now takes care of the text case
This commit is contained in:
parent
10099f1c37
commit
f152232bbe
18 changed files with 223 additions and 155 deletions
|
|
@ -230042,7 +230042,6 @@
|
||||||
домопритежателка
|
домопритежателка
|
||||||
домостроителство
|
домостроителство
|
||||||
домоуправителите
|
домоуправителите
|
||||||
донякогадоникъде
|
|
||||||
дореволюционната
|
дореволюционната
|
||||||
дореволюционните
|
дореволюционните
|
||||||
дореволюционното
|
дореволюционното
|
||||||
|
|
|
||||||
|
|
@ -15658,6 +15658,7 @@ lester
|
||||||
lester's
|
lester's
|
||||||
lestrade
|
lestrade
|
||||||
lestrade's
|
lestrade's
|
||||||
|
let's
|
||||||
leta
|
leta
|
||||||
leta's
|
leta's
|
||||||
letha
|
letha
|
||||||
|
|
@ -93569,6 +93570,7 @@ isthmus's
|
||||||
isthmuses
|
isthmuses
|
||||||
istle
|
istle
|
||||||
it'd
|
it'd
|
||||||
|
it's
|
||||||
it'll
|
it'll
|
||||||
itacolumite
|
itacolumite
|
||||||
italicization
|
italicization
|
||||||
|
|
|
||||||
|
|
@ -58,18 +58,12 @@ public class InputModeValidator {
|
||||||
return newMode;
|
return newMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int validateTextCase(T9Preferences prefs, int textCase, ArrayList<Integer> allowedTextCases) {
|
public static void validateTextCase(T9Preferences prefs, InputMode inputMode, int newTextCase) {
|
||||||
if (allowedTextCases.size() > 0 && allowedTextCases.contains(textCase)) {
|
if (!inputMode.setTextCase(newTextCase)) {
|
||||||
return textCase;
|
inputMode.defaultTextCase();
|
||||||
|
Logger.w("tt9/validateTextCase", "Invalid text case: " + newTextCase + " Enforcing: " + inputMode.getTextCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
int newCase = allowedTextCases.size() > 0 ? allowedTextCases.get(0) : InputMode.CASE_LOWER;
|
prefs.saveTextCase(inputMode.getTextCase());
|
||||||
prefs.saveTextCase(newCase);
|
|
||||||
|
|
||||||
if (textCase != newCase) {
|
|
||||||
Logger.w("tt9/validateTextCase", "Invalid text case: " + textCase + " Enforcing: " + newCase);
|
|
||||||
}
|
|
||||||
|
|
||||||
return newCase;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,10 +25,6 @@ public class TraditionalT9 extends KeyPadHandler {
|
||||||
private ArrayList<Integer> allowedInputModes = new ArrayList<>();
|
private ArrayList<Integer> allowedInputModes = new ArrayList<>();
|
||||||
private InputMode mInputMode;
|
private InputMode mInputMode;
|
||||||
|
|
||||||
// text case
|
|
||||||
private ArrayList<Integer> allowedTextCases = new ArrayList<>();
|
|
||||||
private int mTextCase = InputMode.CASE_LOWER;
|
|
||||||
|
|
||||||
// language
|
// language
|
||||||
protected ArrayList<Integer> mEnabledLanguages;
|
protected ArrayList<Integer> mEnabledLanguages;
|
||||||
protected Language mLanguage;
|
protected Language mLanguage;
|
||||||
|
|
@ -45,21 +41,20 @@ public class TraditionalT9 extends KeyPadHandler {
|
||||||
private void loadPreferences() {
|
private void loadPreferences() {
|
||||||
mLanguage = LanguageCollection.getLanguage(prefs.getInputLanguage());
|
mLanguage = LanguageCollection.getLanguage(prefs.getInputLanguage());
|
||||||
mEnabledLanguages = prefs.getEnabledLanguages();
|
mEnabledLanguages = prefs.getEnabledLanguages();
|
||||||
|
validateLanguages();
|
||||||
|
|
||||||
mInputMode = InputMode.getInstance(prefs.getInputMode());
|
mInputMode = InputMode.getInstance(prefs.getInputMode());
|
||||||
mTextCase = prefs.getTextCase();
|
mInputMode = InputModeValidator.validateMode(prefs, mInputMode, allowedInputModes);
|
||||||
|
|
||||||
|
InputModeValidator.validateTextCase(prefs, mInputMode, prefs.getTextCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void validateLanguages() {
|
private void validateLanguages() {
|
||||||
mEnabledLanguages = InputModeValidator.validateEnabledLanguages(prefs, mEnabledLanguages);
|
mEnabledLanguages = InputModeValidator.validateEnabledLanguages(prefs, mEnabledLanguages);
|
||||||
mLanguage = InputModeValidator.validateLanguage(prefs, mLanguage, mEnabledLanguages);
|
mLanguage = InputModeValidator.validateLanguage(prefs, mLanguage, mEnabledLanguages);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void validatePreferences() {
|
|
||||||
validateLanguages();
|
|
||||||
mInputMode = InputModeValidator.validateMode(prefs, mInputMode, allowedInputModes);
|
|
||||||
mTextCase = InputModeValidator.validateTextCase(prefs, mTextCase, allowedTextCases);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected void onInit() {
|
protected void onInit() {
|
||||||
self = this;
|
self = this;
|
||||||
|
|
@ -74,19 +69,14 @@ public class TraditionalT9 extends KeyPadHandler {
|
||||||
|
|
||||||
|
|
||||||
protected void onRestart(EditorInfo inputField) {
|
protected void onRestart(EditorInfo inputField) {
|
||||||
determineNextTextCase();
|
|
||||||
|
|
||||||
// determine the valid state for the current input field and preferences
|
// determine the valid state for the current input field and preferences
|
||||||
determineAllowedInputModes(inputField);
|
|
||||||
determineAllowedTextCases();
|
|
||||||
mEnabledLanguages = prefs.getEnabledLanguages(); // in case we are back from Preferences screen, update the language list
|
mEnabledLanguages = prefs.getEnabledLanguages(); // in case we are back from Preferences screen, update the language list
|
||||||
|
determineAllowedInputModes(inputField);
|
||||||
// enforce a valid initial state
|
determineNextTextCase(); // Only in some modes. If they support it, let's overwrite the default.
|
||||||
validatePreferences();
|
|
||||||
clearSuggestions();
|
|
||||||
|
|
||||||
// build the UI
|
// build the UI
|
||||||
UI.updateStatusIcon(this, mLanguage, mInputMode, mTextCase);
|
clearSuggestions();
|
||||||
|
UI.updateStatusIcon(this, mLanguage, mInputMode);
|
||||||
softKeyHandler.show();
|
softKeyHandler.show();
|
||||||
if (!isInputViewShown()) {
|
if (!isInputViewShown()) {
|
||||||
showWindow(true);
|
showWindow(true);
|
||||||
|
|
@ -163,7 +153,7 @@ public class TraditionalT9 extends KeyPadHandler {
|
||||||
|
|
||||||
protected boolean onLeft() {
|
protected boolean onLeft() {
|
||||||
if (mInputMode.clearWordStem()) {
|
if (mInputMode.clearWordStem()) {
|
||||||
mInputMode.getSuggestionsAsync(handleSuggestionsAsync, mLanguage, getComposingText());
|
mInputMode.loadSuggestions(handleSuggestionsAsync, mLanguage, getComposingText());
|
||||||
} else {
|
} else {
|
||||||
jumpBeforeComposingText();
|
jumpBeforeComposingText();
|
||||||
}
|
}
|
||||||
|
|
@ -175,7 +165,7 @@ public class TraditionalT9 extends KeyPadHandler {
|
||||||
String filter = repeat ? mSuggestionView.getSuggestion(1) : getComposingText();
|
String filter = repeat ? mSuggestionView.getSuggestion(1) : getComposingText();
|
||||||
|
|
||||||
if (mInputMode.setWordStem(mLanguage, filter, repeat)) {
|
if (mInputMode.setWordStem(mLanguage, filter, repeat)) {
|
||||||
mInputMode.getSuggestionsAsync(handleSuggestionsAsync, mLanguage, filter);
|
mInputMode.loadSuggestions(handleSuggestionsAsync, mLanguage, filter);
|
||||||
} else if (filter.length() == 0) {
|
} else if (filter.length() == 0) {
|
||||||
mInputMode.reset();
|
mInputMode.reset();
|
||||||
}
|
}
|
||||||
|
|
@ -333,14 +323,14 @@ public class TraditionalT9 extends KeyPadHandler {
|
||||||
|
|
||||||
|
|
||||||
private void getSuggestions() {
|
private void getSuggestions() {
|
||||||
if (!mInputMode.getSuggestionsAsync(handleSuggestionsAsync, mLanguage, mSuggestionView.getCurrentSuggestion())) {
|
if (!mInputMode.loadSuggestions(handleSuggestionsAsync, mLanguage, mSuggestionView.getCurrentSuggestion())) {
|
||||||
handleSuggestions(mInputMode.getSuggestions());
|
handleSuggestions();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void handleSuggestions(ArrayList<String> suggestions) {
|
private void handleSuggestions() {
|
||||||
setSuggestions(suggestions);
|
setSuggestions(mInputMode.getSuggestions(mLanguage));
|
||||||
|
|
||||||
// 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),
|
||||||
|
|
@ -353,21 +343,24 @@ public class TraditionalT9 extends KeyPadHandler {
|
||||||
|
|
||||||
private final Handler handleSuggestionsAsync = new Handler(Looper.getMainLooper()) {
|
private final Handler handleSuggestionsAsync = new Handler(Looper.getMainLooper()) {
|
||||||
@Override
|
@Override
|
||||||
public void handleMessage(Message msg) {
|
public void handleMessage(Message m) {
|
||||||
handleSuggestions(msg.getData().getStringArrayList("suggestions"));
|
handleSuggestions();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
private void setSuggestions(List<String> suggestions) {
|
private void setSuggestions(List<String> suggestions) {
|
||||||
|
setSuggestions(suggestions, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setSuggestions(List<String> suggestions, int selectedIndex) {
|
||||||
if (mSuggestionView == null) {
|
if (mSuggestionView == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean show = suggestions != null && suggestions.size() > 0;
|
boolean show = suggestions != null && suggestions.size() > 0;
|
||||||
|
|
||||||
mSuggestionView.setSuggestions(suggestions, 0);
|
mSuggestionView.setSuggestions(suggestions, selectedIndex);
|
||||||
mSuggestionView.changeCase(mTextCase, mLanguage.getLocale());
|
|
||||||
setCandidatesViewShown(show);
|
setCandidatesViewShown(show);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -410,29 +403,27 @@ public class TraditionalT9 extends KeyPadHandler {
|
||||||
}
|
}
|
||||||
// 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()) {
|
||||||
determineAllowedTextCases();
|
mInputMode.nextTextCase();
|
||||||
|
ArrayList<String> switchedSuggestions = mInputMode.getSuggestions(mLanguage);
|
||||||
|
|
||||||
int modeIndex = (allowedTextCases.indexOf(mTextCase) + 1) % allowedTextCases.size();
|
setSuggestions(switchedSuggestions, mSuggestionView.getCurrentIndex());
|
||||||
mTextCase = allowedTextCases.get(modeIndex);
|
|
||||||
|
|
||||||
mSuggestionView.changeCase(mTextCase, mLanguage.getLocale());
|
|
||||||
setComposingText(getComposingText()); // no mistake, this forces the new text case
|
setComposingText(getComposingText()); // no mistake, this forces the new text case
|
||||||
}
|
}
|
||||||
// make "abc" and "ABC" separate modes from user perspective
|
// make "abc" and "ABC" separate modes from user perspective
|
||||||
else if (mInputMode.isABC() && mTextCase == InputMode.CASE_LOWER) {
|
else if (mInputMode.isABC() && mInputMode.getTextCase() == InputMode.CASE_LOWER) {
|
||||||
mTextCase = InputMode.CASE_UPPER;
|
mInputMode.setTextCase(InputMode.CASE_UPPER);
|
||||||
} else {
|
} else {
|
||||||
int modeIndex = (allowedInputModes.indexOf(mInputMode.getId()) + 1) % allowedInputModes.size();
|
int modeIndex = (allowedInputModes.indexOf(mInputMode.getId()) + 1) % allowedInputModes.size();
|
||||||
mInputMode = InputMode.getInstance(allowedInputModes.get(modeIndex));
|
mInputMode = InputMode.getInstance(allowedInputModes.get(modeIndex));
|
||||||
|
|
||||||
mTextCase = mInputMode.isPredictive() ? InputMode.CASE_CAPITALIZE : InputMode.CASE_LOWER;
|
mInputMode.defaultTextCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
// save the settings for the next time
|
// save the settings for the next time
|
||||||
prefs.saveInputMode(mInputMode);
|
prefs.saveInputMode(mInputMode);
|
||||||
prefs.saveTextCase(mTextCase);
|
prefs.saveTextCase(mInputMode.getTextCase());
|
||||||
|
|
||||||
UI.updateStatusIcon(this, mLanguage, mInputMode, mTextCase);
|
UI.updateStatusIcon(this, mLanguage, mInputMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -453,7 +444,7 @@ public class TraditionalT9 extends KeyPadHandler {
|
||||||
// save it for the next time
|
// save it for the next time
|
||||||
prefs.saveInputLanguage(mLanguage.getId());
|
prefs.saveInputLanguage(mLanguage.getId());
|
||||||
|
|
||||||
UI.updateStatusIcon(this, mLanguage, mInputMode, mTextCase);
|
UI.updateStatusIcon(this, mLanguage, mInputMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -490,20 +481,11 @@ public class TraditionalT9 extends KeyPadHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void determineAllowedTextCases() {
|
|
||||||
allowedTextCases = mInputMode.getAllowedTextCases();
|
|
||||||
// @todo: determine the text case of the input and validate using the allowed ones [ https://github.com/sspanak/tt9/issues/48 ]
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void determineNextTextCase() {
|
private void determineNextTextCase() {
|
||||||
int nextTextCase = mInputMode.getNextWordTextCase(
|
mInputMode.determineNextWordTextCase(
|
||||||
mTextCase,
|
|
||||||
InputFieldHelper.isThereText(currentInputConnection),
|
InputFieldHelper.isThereText(currentInputConnection),
|
||||||
(String) currentInputConnection.getTextBeforeCursor(50, 0)
|
(String) currentInputConnection.getTextBeforeCursor(50, 0)
|
||||||
);
|
);
|
||||||
|
|
||||||
mTextCase = nextTextCase != -1 ? nextTextCase : mTextCase;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
package io.github.sspanak.tt9.ime.modes;
|
package io.github.sspanak.tt9.ime.modes;
|
||||||
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Message;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
|
@ -19,7 +17,9 @@ abstract public class InputMode {
|
||||||
public static final int CASE_UPPER = 0;
|
public static final int CASE_UPPER = 0;
|
||||||
public static final int CASE_CAPITALIZE = 1;
|
public static final int CASE_CAPITALIZE = 1;
|
||||||
public static final int CASE_LOWER = 2;
|
public static final int CASE_LOWER = 2;
|
||||||
|
public static final int CASE_DICTIONARY = 3; // do not force it, but use the dictionary word as-is
|
||||||
protected ArrayList<Integer> allowedTextCases = new ArrayList<>();
|
protected ArrayList<Integer> allowedTextCases = new ArrayList<>();
|
||||||
|
protected int textCase = CASE_LOWER;
|
||||||
|
|
||||||
// data
|
// data
|
||||||
protected ArrayList<String> suggestions = new ArrayList<>();
|
protected ArrayList<String> suggestions = new ArrayList<>();
|
||||||
|
|
@ -45,14 +45,16 @@ abstract public class InputMode {
|
||||||
|
|
||||||
// Suggestions
|
// Suggestions
|
||||||
public void onAcceptSuggestion(Language language, String suggestion) {}
|
public void onAcceptSuggestion(Language language, String suggestion) {}
|
||||||
public ArrayList<String> getSuggestions() { return suggestions; }
|
protected void onSuggestionsUpdated(Handler handler) { handler.sendEmptyMessage(0); }
|
||||||
public boolean getSuggestionsAsync(Handler handler, Language language, String lastWord) { return false; }
|
public boolean loadSuggestions(Handler handler, Language language, String lastWord) { return false; }
|
||||||
protected void sendSuggestions(Handler handler, ArrayList<String> suggestions) {
|
|
||||||
Bundle bundle = new Bundle();
|
public ArrayList<String> getSuggestions(Language language) {
|
||||||
bundle.putStringArrayList("suggestions", suggestions);
|
ArrayList<String> newSuggestions = new ArrayList<>();
|
||||||
Message msg = new Message();
|
for (String s : suggestions) {
|
||||||
msg.setData(bundle);
|
newSuggestions.add(adjustSuggestionTextCase(s, textCase, language));
|
||||||
handler.sendMessage(msg);
|
}
|
||||||
|
|
||||||
|
return newSuggestions;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Word
|
// Word
|
||||||
|
|
@ -65,15 +67,38 @@ abstract public class InputMode {
|
||||||
|
|
||||||
// Utility
|
// Utility
|
||||||
abstract public int getId();
|
abstract public int getId();
|
||||||
public ArrayList<Integer> getAllowedTextCases() { return allowedTextCases; }
|
|
||||||
// Perform any special logic to determine the text case of the next word, or return "-1" if there is no need to change it.
|
|
||||||
public int getNextWordTextCase(int currentTextCase, boolean isThereText, String textBeforeCursor) { return -1; }
|
|
||||||
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 reset() {
|
public void reset() {
|
||||||
suggestions = new ArrayList<>();
|
suggestions = new ArrayList<>();
|
||||||
word = null;
|
word = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Text case
|
||||||
|
public int getTextCase() { return textCase; }
|
||||||
|
|
||||||
|
public boolean setTextCase(int newTextCase) {
|
||||||
|
if (!allowedTextCases.contains(newTextCase)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
textCase = newTextCase;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void defaultTextCase() {
|
||||||
|
textCase = allowedTextCases.get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void nextTextCase() {
|
||||||
|
int nextIndex = (allowedTextCases.indexOf(textCase) + 1) % allowedTextCases.size();
|
||||||
|
textCase = allowedTextCases.get(nextIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void determineNextWordTextCase(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.
|
||||||
|
protected String adjustSuggestionTextCase(String word, int newTextCase, Language language) { 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; }
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
package io.github.sspanak.tt9.ime.modes;
|
package io.github.sspanak.tt9.ime.modes;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import io.github.sspanak.tt9.languages.Language;
|
import io.github.sspanak.tt9.languages.Language;
|
||||||
|
|
||||||
public class ModeABC extends InputMode {
|
public class ModeABC extends InputMode {
|
||||||
|
|
@ -19,10 +21,10 @@ public class ModeABC extends InputMode {
|
||||||
word = null;
|
word = null;
|
||||||
|
|
||||||
if (hold) {
|
if (hold) {
|
||||||
suggestions = null;
|
suggestions = new ArrayList<>();
|
||||||
word = String.valueOf(key);
|
word = String.valueOf(key);
|
||||||
} else if (repeat) {
|
} else if (repeat) {
|
||||||
suggestions = null;
|
suggestions = new ArrayList<>();
|
||||||
shouldSelectNextLetter = true;
|
shouldSelectNextLetter = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -30,6 +32,11 @@ public class ModeABC extends InputMode {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected String adjustSuggestionTextCase(String word, int newTextCase, Language language) {
|
||||||
|
return newTextCase == CASE_UPPER ? word.toUpperCase(language.getLocale()) : word.toLowerCase(language.getLocale());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
final public boolean isABC() { return true; }
|
final public boolean isABC() { return true; }
|
||||||
public int getSequenceLength() { return 1; }
|
public int getSequenceLength() { return 1; }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ import android.os.Looper;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import io.github.sspanak.tt9.Logger;
|
import io.github.sspanak.tt9.Logger;
|
||||||
|
|
@ -29,11 +28,14 @@ public class ModePredictive extends InputMode {
|
||||||
private String lastInputFieldWord = "";
|
private String lastInputFieldWord = "";
|
||||||
private static Handler handleSuggestionsExternal;
|
private static Handler handleSuggestionsExternal;
|
||||||
|
|
||||||
|
// auto text case selection
|
||||||
|
private final Pattern endOfSentence = Pattern.compile("(?<!\\.)[.?!]\\s*$");
|
||||||
|
|
||||||
|
|
||||||
ModePredictive() {
|
ModePredictive() {
|
||||||
allowedTextCases.add(CASE_UPPER);
|
|
||||||
allowedTextCases.add(CASE_CAPITALIZE);
|
|
||||||
allowedTextCases.add(CASE_LOWER);
|
allowedTextCases.add(CASE_LOWER);
|
||||||
|
allowedTextCases.add(CASE_CAPITALIZE);
|
||||||
|
allowedTextCases.add(CASE_UPPER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -88,16 +90,6 @@ public class ModePredictive extends InputMode {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
final public boolean isPredictive() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getSequenceLength() { return isEmoji ? 2 : digitSequence.length(); }
|
|
||||||
|
|
||||||
public boolean shouldTrackUpDown() { return true; }
|
|
||||||
public boolean shouldTrackLeftRight() { return true; }
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* shouldAcceptCurrentSuggestion
|
* shouldAcceptCurrentSuggestion
|
||||||
* In this mode, In addition to confirming the suggestion in the input field,
|
* In this mode, In addition to confirming the suggestion in the input field,
|
||||||
|
|
@ -166,20 +158,21 @@ public class ModePredictive extends InputMode {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* getSuggestionsAsync
|
* loadSuggestions
|
||||||
* Queries the dictionary database for a list of suggestions matching the current language and
|
* Queries the dictionary database for a list of suggestions matching the current language and
|
||||||
* sequence. Returns "false" when there is nothing to do.
|
* sequence. Returns "false" when there is nothing to do.
|
||||||
*
|
*
|
||||||
* "lastWord" is used for generating suggestions when there are no results.
|
* "lastWord" is used for generating suggestions when there are no results.
|
||||||
* See: generatePossibleCompletions()
|
* See: generatePossibleCompletions()
|
||||||
*/
|
*/
|
||||||
public boolean getSuggestionsAsync(Handler handler, Language language, String lastWord) {
|
public boolean loadSuggestions(Handler handler, Language language, String lastWord) {
|
||||||
if (isEmoji) {
|
if (isEmoji) {
|
||||||
super.sendSuggestions(handler, suggestions);
|
super.onSuggestionsUpdated(handler);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (digitSequence.length() == 0) {
|
if (digitSequence.length() == 0) {
|
||||||
|
suggestions.clear();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -209,17 +202,19 @@ public class ModePredictive extends InputMode {
|
||||||
private final Handler handleSuggestions = new Handler(Looper.getMainLooper()) {
|
private final Handler handleSuggestions = new Handler(Looper.getMainLooper()) {
|
||||||
@Override
|
@Override
|
||||||
public void handleMessage(Message msg) {
|
public void handleMessage(Message msg) {
|
||||||
ArrayList<String> suggestions = msg.getData().getStringArrayList("suggestions");
|
ArrayList<String> dbSuggestions = msg.getData().getStringArrayList("suggestions");
|
||||||
suggestions = suggestions == null ? new ArrayList<>() : suggestions;
|
dbSuggestions = dbSuggestions == null ? new ArrayList<>() : dbSuggestions;
|
||||||
|
|
||||||
if (suggestions.size() == 0 && digitSequence.length() > 0) {
|
if (dbSuggestions.size() == 0 && digitSequence.length() > 0) {
|
||||||
suggestions = generatePossibleCompletions(currentLanguage, lastInputFieldWord);
|
dbSuggestions = generatePossibleCompletions(currentLanguage, lastInputFieldWord);
|
||||||
}
|
}
|
||||||
|
|
||||||
ArrayList<String> stemVariations = generatePossibleStemVariations(currentLanguage, suggestions);
|
suggestions.clear();
|
||||||
stemVariations.addAll(suggestions);
|
suggestStem();
|
||||||
|
suggestions.addAll(generatePossibleStemVariations(currentLanguage, dbSuggestions));
|
||||||
|
suggestMoreWords(dbSuggestions);
|
||||||
|
|
||||||
ModePredictive.super.sendSuggestions(handleSuggestionsExternal, stemVariations);
|
ModePredictive.super.onSuggestionsUpdated(handleSuggestionsExternal);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -269,22 +264,28 @@ public class ModePredictive extends InputMode {
|
||||||
*
|
*
|
||||||
* For example, if the filter is "extr", the current word is "extr_" and the user has pressed "1",
|
* For example, if the filter is "extr", the current word is "extr_" and the user has pressed "1",
|
||||||
* the database would have returned only "extra", but this function would also
|
* the database would have returned only "extra", but this function would also
|
||||||
* generate: "extrb" and "extrc". This is useful for typing an unknown word, similar to the ones
|
* generate: "extrb" and "extrc". This is useful for typing an unknown word, that is similar to
|
||||||
* in the dictionary.
|
* the ones in the dictionary.
|
||||||
*/
|
*/
|
||||||
private ArrayList<String> generatePossibleStemVariations(Language language, ArrayList<String> currentSuggestions) {
|
private ArrayList<String> generatePossibleStemVariations(Language language, 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 (stem.length() == digitSequence.length() && !currentSuggestions.contains(stem)) {
|
if (isStemFuzzy && stem.length() == digitSequence.length() - 1) {
|
||||||
variations.add(stem);
|
ArrayList<String> allPossibleVariations = generatePossibleCompletions(language, stem);
|
||||||
|
|
||||||
|
// first add the known words, because it makes more sense to see them first
|
||||||
|
for (String word : allPossibleVariations) {
|
||||||
|
if (dbSuggestions.contains(word)) {
|
||||||
|
variations.add(word);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isStemFuzzy && stem.length() == digitSequence.length() - 1) {
|
// then add the unknown ones, so they can be used as possible beginnings of new words.
|
||||||
for (String word : generatePossibleCompletions(language, stem)) {
|
for (String word : allPossibleVariations) {
|
||||||
if (!currentSuggestions.contains(word)) {
|
if (!dbSuggestions.contains(word)) {
|
||||||
variations.add(word);
|
variations.add(word);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -293,6 +294,30 @@ public class ModePredictive extends InputMode {
|
||||||
return variations;
|
return variations;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* suggestStem
|
||||||
|
* Add the current stem filter to the suggestion list, when it has length of X and
|
||||||
|
* the user has pressed X keys.
|
||||||
|
*/
|
||||||
|
public void suggestStem() {
|
||||||
|
if (stem.length() > 0 && stem.length() == digitSequence.length()) {
|
||||||
|
suggestions.add(stem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* suggestMoreWords
|
||||||
|
* Takes a list of words and appends them to the suggestion list, if they are missing.
|
||||||
|
*/
|
||||||
|
public void suggestMoreWords(ArrayList<String> newSuggestions) {
|
||||||
|
for (String word : newSuggestions) {
|
||||||
|
if (!suggestions.contains(word)) {
|
||||||
|
suggestions.add(word);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* onAcceptSuggestion
|
* onAcceptSuggestion
|
||||||
|
|
@ -316,28 +341,61 @@ public class ModePredictive extends InputMode {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* getNextWordTextCase
|
* adjustSuggestionTextCase
|
||||||
* Dynamically determine text case of words as the user types to reduce key presses.
|
* In addition to uppercase/lowercase, here we use the result from determineNextWordTextCase(),
|
||||||
|
* to conveniently start sentences with capitals or whatnot.
|
||||||
|
*
|
||||||
|
* Also, by default we preserve any mixed case words in the dictionary,
|
||||||
|
* for example: "dB", "Mb", proper names, German nouns, that always start with a capital,
|
||||||
|
* or Dutch words such as: "'s-Hertogenbosch".
|
||||||
|
*/
|
||||||
|
protected String adjustSuggestionTextCase(String word, int newTextCase, Language language) {
|
||||||
|
switch (newTextCase) {
|
||||||
|
case CASE_UPPER:
|
||||||
|
return word.toUpperCase(language.getLocale());
|
||||||
|
case CASE_LOWER:
|
||||||
|
return word.toLowerCase(language.getLocale());
|
||||||
|
case CASE_CAPITALIZE:
|
||||||
|
return language.isMixedCaseWord(word) ? word : language.capitalize(word);
|
||||||
|
case CASE_DICTIONARY:
|
||||||
|
return language.isMixedCaseWord(word) ? word : word.toLowerCase(language.getLocale());
|
||||||
|
default:
|
||||||
|
return word;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* determineNextWordTextCase
|
||||||
|
* Dynamically determine text case of words as the user types, to reduce key presses.
|
||||||
* For example, this function will return CASE_LOWER by default, but CASE_UPPER at the beginning
|
* For example, this function will return CASE_LOWER by default, but CASE_UPPER at the beginning
|
||||||
* of a sentence.
|
* of a sentence.
|
||||||
*/
|
*/
|
||||||
public int getNextWordTextCase(int currentTextCase, boolean isThereText, String textBeforeCursor) {
|
public void determineNextWordTextCase(boolean isThereText, String textBeforeCursor) {
|
||||||
// If the user wants to type in uppercase, this must be for a reason, so we better not override it.
|
// If the user wants to type in uppercase, this must be for a reason, so we better not override it.
|
||||||
if (currentTextCase == CASE_UPPER) {
|
if (textCase == CASE_UPPER) {
|
||||||
return -1;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// start of text
|
// start of text
|
||||||
if (!isThereText) {
|
if (!isThereText) {
|
||||||
return CASE_CAPITALIZE;
|
textCase = CASE_CAPITALIZE;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// start of sentence, excluding after "..."
|
// start of sentence, excluding after "..."
|
||||||
Matcher endOfSentenceMatch = Pattern.compile("(?<!\\.)[.?!]\\s*$").matcher(textBeforeCursor);
|
if (endOfSentence.matcher(textBeforeCursor).find()) {
|
||||||
if (endOfSentenceMatch.find()) {
|
textCase = CASE_CAPITALIZE;
|
||||||
return CASE_CAPITALIZE;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return CASE_LOWER;
|
textCase = CASE_DICTIONARY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
final public boolean isPredictive() { return true; }
|
||||||
|
public int getSequenceLength() { return isEmoji ? 2 : digitSequence.length(); }
|
||||||
|
public boolean shouldTrackUpDown() { return true; }
|
||||||
|
public boolean shouldTrackLeftRight() { return true; }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,13 +8,15 @@ public class Language {
|
||||||
protected int id;
|
protected int id;
|
||||||
protected String name;
|
protected String name;
|
||||||
protected Locale locale;
|
protected Locale locale;
|
||||||
protected boolean isPunctuationPartOfWords; // see the getter for more info
|
|
||||||
protected int icon;
|
protected int icon;
|
||||||
protected String dictionaryFile;
|
protected String dictionaryFile;
|
||||||
protected int abcLowerCaseIcon;
|
protected int abcLowerCaseIcon;
|
||||||
protected int abcUpperCaseIcon;
|
protected int abcUpperCaseIcon;
|
||||||
protected ArrayList<ArrayList<String>> characterMap = new ArrayList<>();
|
protected ArrayList<ArrayList<String>> characterMap = new ArrayList<>();
|
||||||
|
|
||||||
|
// settings
|
||||||
|
protected boolean isPunctuationPartOfWords; // see the getter for more info
|
||||||
|
|
||||||
final public int getId() {
|
final public int getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
@ -31,6 +33,15 @@ public class Language {
|
||||||
return icon;
|
return icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final public String getDictionaryFile() {
|
||||||
|
return dictionaryFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
final public int getAbcIcon(boolean lowerCase) {
|
||||||
|
return lowerCase ? abcLowerCaseIcon : abcUpperCaseIcon;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* isPunctuationPartOfWords
|
* isPunctuationPartOfWords
|
||||||
* This plays a role in Predictive mode only.
|
* This plays a role in Predictive mode only.
|
||||||
|
|
@ -49,12 +60,15 @@ public class Language {
|
||||||
*/
|
*/
|
||||||
final public boolean isPunctuationPartOfWords() { return isPunctuationPartOfWords; }
|
final public boolean isPunctuationPartOfWords() { return isPunctuationPartOfWords; }
|
||||||
|
|
||||||
final public String getDictionaryFile() {
|
|
||||||
return dictionaryFile;
|
/************* utility *************/
|
||||||
|
|
||||||
|
public String capitalize(String word) {
|
||||||
|
return word != null ? word.substring(0, 1).toUpperCase(locale) + word.substring(1).toLowerCase(locale) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final public int getAbcIcon(boolean lowerCase) {
|
public boolean isMixedCaseWord(String word) {
|
||||||
return lowerCase ? abcLowerCaseIcon : abcUpperCaseIcon;
|
return word != null && !word.toLowerCase(locale).equals(word) && !word.toUpperCase(locale).equals(word);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ArrayList<String> getKeyCharacters(int key) {
|
public ArrayList<String> getKeyCharacters(int key) {
|
||||||
|
|
|
||||||
|
|
@ -14,11 +14,12 @@ public class Bulgarian extends Language {
|
||||||
name = "български";
|
name = "български";
|
||||||
locale = new Locale("bg","BG");
|
locale = new Locale("bg","BG");
|
||||||
dictionaryFile = "bg-utf8.txt";
|
dictionaryFile = "bg-utf8.txt";
|
||||||
isPunctuationPartOfWords = false;
|
|
||||||
icon = R.drawable.ime_lang_bg;
|
icon = R.drawable.ime_lang_bg;
|
||||||
abcLowerCaseIcon = R.drawable.ime_lang_cyrillic_lower;
|
abcLowerCaseIcon = R.drawable.ime_lang_cyrillic_lower;
|
||||||
abcUpperCaseIcon = R.drawable.ime_lang_cyrillic_upper;
|
abcUpperCaseIcon = R.drawable.ime_lang_cyrillic_upper;
|
||||||
|
|
||||||
|
isPunctuationPartOfWords = false;
|
||||||
|
|
||||||
characterMap = new ArrayList<>(Arrays.asList(
|
characterMap = new ArrayList<>(Arrays.asList(
|
||||||
Punctuation.Secondary, // 0
|
Punctuation.Secondary, // 0
|
||||||
Punctuation.Main, // 1
|
Punctuation.Main, // 1
|
||||||
|
|
|
||||||
|
|
@ -12,10 +12,11 @@ public class Dutch extends English {
|
||||||
id = 8;
|
id = 8;
|
||||||
name = "Nederlands";
|
name = "Nederlands";
|
||||||
locale = new Locale("nl","NL");
|
locale = new Locale("nl","NL");
|
||||||
isPunctuationPartOfWords = true;
|
|
||||||
dictionaryFile = "nl-utf8.txt";
|
dictionaryFile = "nl-utf8.txt";
|
||||||
icon = R.drawable.ime_lang_nl;
|
icon = R.drawable.ime_lang_nl;
|
||||||
|
|
||||||
|
isPunctuationPartOfWords = true;
|
||||||
|
|
||||||
characterMap.get(2).addAll(Arrays.asList("à", "ä", "ç"));
|
characterMap.get(2).addAll(Arrays.asList("à", "ä", "ç"));
|
||||||
characterMap.get(3).addAll(Arrays.asList("é", "è", "ê", "ë"));
|
characterMap.get(3).addAll(Arrays.asList("é", "è", "ê", "ë"));
|
||||||
characterMap.get(4).addAll(Arrays.asList("î", "ï"));
|
characterMap.get(4).addAll(Arrays.asList("î", "ï"));
|
||||||
|
|
|
||||||
|
|
@ -14,11 +14,12 @@ public class English extends Language {
|
||||||
name = "English";
|
name = "English";
|
||||||
locale = Locale.ENGLISH;
|
locale = Locale.ENGLISH;
|
||||||
dictionaryFile = "en-utf8.txt";
|
dictionaryFile = "en-utf8.txt";
|
||||||
isPunctuationPartOfWords = true;
|
|
||||||
icon = R.drawable.ime_lang_en;
|
icon = R.drawable.ime_lang_en;
|
||||||
abcLowerCaseIcon = R.drawable.ime_lang_latin_lower;
|
abcLowerCaseIcon = R.drawable.ime_lang_latin_lower;
|
||||||
abcUpperCaseIcon = R.drawable.ime_lang_latin_upper;
|
abcUpperCaseIcon = R.drawable.ime_lang_latin_upper;
|
||||||
|
|
||||||
|
isPunctuationPartOfWords = true;
|
||||||
|
|
||||||
characterMap = new ArrayList<>(Arrays.asList(
|
characterMap = new ArrayList<>(Arrays.asList(
|
||||||
Punctuation.Secondary, // 0
|
Punctuation.Secondary, // 0
|
||||||
Punctuation.Main, // 1
|
Punctuation.Main, // 1
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ public class French extends English {
|
||||||
locale = Locale.FRENCH;
|
locale = Locale.FRENCH;
|
||||||
dictionaryFile = "fr-utf8.txt";
|
dictionaryFile = "fr-utf8.txt";
|
||||||
icon = R.drawable.ime_lang_fr;
|
icon = R.drawable.ime_lang_fr;
|
||||||
|
|
||||||
isPunctuationPartOfWords = false;
|
isPunctuationPartOfWords = false;
|
||||||
|
|
||||||
characterMap.get(2).addAll(Arrays.asList("à", "â", "æ", "ç"));
|
characterMap.get(2).addAll(Arrays.asList("à", "â", "æ", "ç"));
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ public class German extends English {
|
||||||
locale = Locale.GERMAN;
|
locale = Locale.GERMAN;
|
||||||
dictionaryFile = "de-utf8.txt";
|
dictionaryFile = "de-utf8.txt";
|
||||||
icon = R.drawable.ime_lang_de;
|
icon = R.drawable.ime_lang_de;
|
||||||
|
|
||||||
isPunctuationPartOfWords = false;
|
isPunctuationPartOfWords = false;
|
||||||
|
|
||||||
characterMap.get(2).add("ä");
|
characterMap.get(2).add("ä");
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ public class Italian extends English {
|
||||||
locale = Locale.ITALIAN;
|
locale = Locale.ITALIAN;
|
||||||
dictionaryFile = "it-utf8.txt";
|
dictionaryFile = "it-utf8.txt";
|
||||||
icon = R.drawable.ime_lang_it;
|
icon = R.drawable.ime_lang_it;
|
||||||
|
|
||||||
isPunctuationPartOfWords = false;
|
isPunctuationPartOfWords = false;
|
||||||
|
|
||||||
characterMap.get(2).add("à");
|
characterMap.get(2).add("à");
|
||||||
|
|
|
||||||
|
|
@ -14,11 +14,12 @@ public class Russian extends Language {
|
||||||
name = "русский";
|
name = "русский";
|
||||||
locale = new Locale("ru","RU");
|
locale = new Locale("ru","RU");
|
||||||
dictionaryFile = "ru-utf8.txt";
|
dictionaryFile = "ru-utf8.txt";
|
||||||
isPunctuationPartOfWords = false;
|
|
||||||
icon = R.drawable.ime_lang_ru;
|
icon = R.drawable.ime_lang_ru;
|
||||||
abcLowerCaseIcon = R.drawable.ime_lang_cyrillic_lower;
|
abcLowerCaseIcon = R.drawable.ime_lang_cyrillic_lower;
|
||||||
abcUpperCaseIcon = R.drawable.ime_lang_cyrillic_upper;
|
abcUpperCaseIcon = R.drawable.ime_lang_cyrillic_upper;
|
||||||
|
|
||||||
|
isPunctuationPartOfWords = false;
|
||||||
|
|
||||||
characterMap = new ArrayList<>(Arrays.asList(
|
characterMap = new ArrayList<>(Arrays.asList(
|
||||||
Punctuation.Secondary, // 0
|
Punctuation.Secondary, // 0
|
||||||
Punctuation.Main, // 1
|
Punctuation.Main, // 1
|
||||||
|
|
|
||||||
|
|
@ -14,11 +14,12 @@ public class Ukrainian extends Language {
|
||||||
name = "українська";
|
name = "українська";
|
||||||
locale = new Locale("uk","UA");
|
locale = new Locale("uk","UA");
|
||||||
dictionaryFile = "uk-utf8.txt";
|
dictionaryFile = "uk-utf8.txt";
|
||||||
isPunctuationPartOfWords = true;
|
|
||||||
icon = R.drawable.ime_lang_uk;
|
icon = R.drawable.ime_lang_uk;
|
||||||
abcLowerCaseIcon = R.drawable.ime_lang_cyrillic_lower;
|
abcLowerCaseIcon = R.drawable.ime_lang_cyrillic_lower;
|
||||||
abcUpperCaseIcon = R.drawable.ime_lang_cyrillic_upper;
|
abcUpperCaseIcon = R.drawable.ime_lang_cyrillic_upper;
|
||||||
|
|
||||||
|
isPunctuationPartOfWords = true;
|
||||||
|
|
||||||
characterMap = new ArrayList<>(Arrays.asList(
|
characterMap = new ArrayList<>(Arrays.asList(
|
||||||
Punctuation.Secondary, // 0
|
Punctuation.Secondary, // 0
|
||||||
Punctuation.Main, // 1
|
Punctuation.Main, // 1
|
||||||
|
|
|
||||||
|
|
@ -10,14 +10,12 @@ import android.view.View;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
import io.github.sspanak.tt9.R;
|
import io.github.sspanak.tt9.R;
|
||||||
import io.github.sspanak.tt9.ime.modes.InputMode;
|
|
||||||
|
|
||||||
public class CandidateView extends View {
|
public class CandidateView extends View {
|
||||||
|
|
||||||
private List<String> mSuggestions;
|
private List<String> mSuggestions = new ArrayList<>();
|
||||||
protected int mSelectedIndex;
|
protected int mSelectedIndex;
|
||||||
|
|
||||||
private Drawable mSelectionHighlight;
|
private Drawable mSelectionHighlight;
|
||||||
|
|
@ -32,7 +30,7 @@ public class CandidateView extends View {
|
||||||
|
|
||||||
private static final int X_GAP = 10;
|
private static final int X_GAP = 10;
|
||||||
|
|
||||||
private static final List<String> EMPTY_LIST = new ArrayList<String>();
|
private static final List<String> EMPTY_LIST = new ArrayList<>();
|
||||||
|
|
||||||
private int mColorNormal;
|
private int mColorNormal;
|
||||||
private int mColorRecommended;
|
private int mColorRecommended;
|
||||||
|
|
@ -47,8 +45,6 @@ public class CandidateView extends View {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a CandidateView for showing suggested words for completion.
|
* Construct a CandidateView for showing suggested words for completion.
|
||||||
*
|
|
||||||
* @param context
|
|
||||||
*/
|
*/
|
||||||
public CandidateView(Context context) {
|
public CandidateView(Context context) {
|
||||||
super(context);
|
super(context);
|
||||||
|
|
@ -204,23 +200,6 @@ public class CandidateView extends View {
|
||||||
requestLayout();
|
requestLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void changeCase(int textCase, Locale locale) {
|
|
||||||
ArrayList<String> newSuggestions = new ArrayList<>();
|
|
||||||
|
|
||||||
for (String s : mSuggestions) {
|
|
||||||
if (textCase == InputMode.CASE_LOWER) {
|
|
||||||
newSuggestions.add(s.toLowerCase(locale));
|
|
||||||
} else if (textCase == InputMode.CASE_CAPITALIZE) {
|
|
||||||
String cs = s.substring(0, 1).toUpperCase(locale) + s.substring(1).toLowerCase(locale);
|
|
||||||
newSuggestions.add(cs);
|
|
||||||
} else {
|
|
||||||
newSuggestions.add(s.toUpperCase(locale));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setSuggestions(newSuggestions, mSelectedIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void clear() {
|
protected void clear() {
|
||||||
mSuggestions = EMPTY_LIST;
|
mSuggestions = EMPTY_LIST;
|
||||||
mSelectedIndex = -1;
|
mSelectedIndex = -1;
|
||||||
|
|
|
||||||
|
|
@ -35,9 +35,9 @@ public class UI {
|
||||||
* Set the status icon that is appropriate in current mode (based on
|
* Set the status icon that is appropriate in current mode (based on
|
||||||
* openwmm-legacy)
|
* openwmm-legacy)
|
||||||
*/
|
*/
|
||||||
public static void updateStatusIcon(TraditionalT9 tt9, Language inputLanguage, InputMode inputMode, int textCase) {
|
public static void updateStatusIcon(TraditionalT9 tt9, Language inputLanguage, InputMode inputMode) {
|
||||||
if (inputMode.isABC()) {
|
if (inputMode.isABC()) {
|
||||||
tt9.showStatusIcon(inputLanguage.getAbcIcon(textCase == InputMode.CASE_LOWER));
|
tt9.showStatusIcon(inputLanguage.getAbcIcon(inputMode.getTextCase() == InputMode.CASE_LOWER));
|
||||||
} else if (inputMode.isPredictive()) {
|
} else if (inputMode.isPredictive()) {
|
||||||
tt9.showStatusIcon(inputLanguage.getIcon());
|
tt9.showStatusIcon(inputLanguage.getIcon());
|
||||||
} else if (inputMode.is123()) {
|
} else if (inputMode.is123()) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue