new way of displaying the special chars
This commit is contained in:
parent
c484050678
commit
ce3446c3dd
26 changed files with 313 additions and 178 deletions
|
|
@ -162,7 +162,7 @@ abstract public class CommandHandler extends TextEditingHandler {
|
|||
determineTextCase();
|
||||
}
|
||||
|
||||
// save the settings for the next time
|
||||
suggestionOps.setInputMode(mInputMode);
|
||||
settings.saveInputMode(mInputMode.getId());
|
||||
}
|
||||
|
||||
|
|
@ -206,7 +206,7 @@ abstract public class CommandHandler extends TextEditingHandler {
|
|||
getSuggestions(null);
|
||||
setStatusIcon(mInputMode, mLanguage);
|
||||
statusBar.setText(mInputMode);
|
||||
suggestionOps.setRTL(isLanguageRTL);
|
||||
suggestionOps.setLanguage(mLanguage);
|
||||
mainView.render();
|
||||
if (settings.isMainLayoutStealth() && !settings.isStatusIconEnabled()) {
|
||||
UI.toastShortSingle(this, mInputMode.getClass().getSimpleName(), mInputMode.toString());
|
||||
|
|
|
|||
|
|
@ -36,8 +36,8 @@ public abstract class HotkeyHandler extends CommandHandler {
|
|||
suggestionOps.cancelDelayedAccept();
|
||||
|
||||
if (!suggestionOps.isEmpty()) {
|
||||
if (mInputMode.shouldReplacePreviousSuggestion()) {
|
||||
mInputMode.onReplaceSuggestion(suggestionOps.getCurrent());
|
||||
if (mInputMode.shouldReplacePreviousSuggestion(suggestionOps.getCurrent())) {
|
||||
mInputMode.onReplaceSuggestion(suggestionOps.getCurrentRaw());
|
||||
} else {
|
||||
onAcceptSuggestionManually(suggestionOps.acceptCurrent(), KeyEvent.KEYCODE_ENTER);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ abstract public class TextEditingHandler extends VoiceHandler {
|
|||
protected void initTray() {
|
||||
super.initTray();
|
||||
detectRTL();
|
||||
suggestionOps.setRTL(isLanguageRTL);
|
||||
suggestionOps.setLanguage(LanguageCollection.getLanguage(settings.getInputLanguage()));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@ public abstract class TypingHandler extends KeyPadHandler {
|
|||
mInputMode = determineInputMode();
|
||||
determineTextCase();
|
||||
suggestionOps.set(null);
|
||||
suggestionOps.setInputMode(mInputMode);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -89,6 +90,7 @@ public abstract class TypingHandler extends KeyPadHandler {
|
|||
// changing the TextField and notifying all interested classes is an atomic operation
|
||||
appHacks = new AppHacks(inputType, textField, textSelection);
|
||||
suggestionOps.setTextField(textField);
|
||||
suggestionOps.setInputMode(mInputMode);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,10 @@ import androidx.annotation.Nullable;
|
|||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import io.github.sspanak.tt9.ime.modes.InputMode;
|
||||
import io.github.sspanak.tt9.languages.Language;
|
||||
import io.github.sspanak.tt9.languages.LanguageKind;
|
||||
import io.github.sspanak.tt9.languages.NullLanguage;
|
||||
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
|
||||
import io.github.sspanak.tt9.ui.main.ResizableMainView;
|
||||
import io.github.sspanak.tt9.ui.tray.SuggestionsBar;
|
||||
|
|
@ -18,6 +21,10 @@ import io.github.sspanak.tt9.util.Text;
|
|||
public class SuggestionOps {
|
||||
@NonNull private final Handler delayedAcceptHandler;
|
||||
@NonNull private final ConsumerCompat<String> onDelayedAccept;
|
||||
|
||||
@Nullable private InputMode inputMode;
|
||||
@NonNull private Language language;
|
||||
@Nullable private final SettingsStore settings;
|
||||
@Nullable protected SuggestionsBar suggestionBar;
|
||||
@NonNull private TextField textField;
|
||||
|
||||
|
|
@ -26,16 +33,25 @@ public class SuggestionOps {
|
|||
delayedAcceptHandler = new Handler(Looper.getMainLooper());
|
||||
this.onDelayedAccept = onDelayedAccept != null ? onDelayedAccept : s -> {};
|
||||
|
||||
language = new NullLanguage();
|
||||
this.settings = settings;
|
||||
this.textField = textField != null ? textField : new TextField(null, null, null);
|
||||
|
||||
if (settings != null && mainView != null && onSuggestionClick != null) {
|
||||
suggestionBar = new SuggestionsBar(settings, mainView, onSuggestionClick);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void setRTL(boolean yes) {
|
||||
public void setInputMode(@Nullable InputMode inputMode) {
|
||||
this.inputMode = inputMode;
|
||||
}
|
||||
|
||||
|
||||
public void setLanguage(@Nullable Language language) {
|
||||
this.language = language == null ? new NullLanguage() : language;
|
||||
if (suggestionBar != null) {
|
||||
suggestionBar.setRTL(yes);
|
||||
suggestionBar.setRTL(LanguageKind.isRTL(language));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -154,6 +170,11 @@ public class SuggestionOps {
|
|||
}
|
||||
|
||||
|
||||
public String getCurrentRaw() {
|
||||
return suggestionBar != null ? suggestionBar.getRaw(getCurrentIndex()) : "";
|
||||
}
|
||||
|
||||
|
||||
public String getCurrent(Language language, int maxLength) {
|
||||
if (maxLength == 0 || isEmpty()) {
|
||||
return "";
|
||||
|
|
|
|||
|
|
@ -7,11 +7,14 @@ import java.util.ArrayList;
|
|||
|
||||
import io.github.sspanak.tt9.hacks.InputType;
|
||||
import io.github.sspanak.tt9.ime.helpers.TextField;
|
||||
import io.github.sspanak.tt9.ime.modes.helpers.Sequences;
|
||||
import io.github.sspanak.tt9.languages.Language;
|
||||
import io.github.sspanak.tt9.languages.LanguageKind;
|
||||
import io.github.sspanak.tt9.languages.NullLanguage;
|
||||
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
|
||||
import io.github.sspanak.tt9.ui.tray.SuggestionsBar;
|
||||
import io.github.sspanak.tt9.util.Logger;
|
||||
import io.github.sspanak.tt9.util.chars.Characters;
|
||||
|
||||
abstract public class InputMode {
|
||||
// typing mode
|
||||
|
|
@ -40,6 +43,7 @@ abstract public class InputMode {
|
|||
@NonNull protected final ArrayList<String> suggestions = new ArrayList<>();
|
||||
@NonNull protected Runnable onSuggestionsUpdated = () -> {};
|
||||
protected int specialCharSelectedGroup = 0;
|
||||
@NonNull protected Sequences seq = new Sequences();
|
||||
|
||||
|
||||
protected InputMode(SettingsStore settings, InputType inputType) {
|
||||
|
|
@ -83,7 +87,15 @@ abstract public class InputMode {
|
|||
public void onAcceptSuggestion(@NonNull String word) { onAcceptSuggestion(word, false); }
|
||||
public void onAcceptSuggestion(@NonNull String word, boolean preserveWordList) {}
|
||||
public void onCursorMove(@NonNull String word) { if (!digitSequence.isEmpty()) onAcceptSuggestion(word); }
|
||||
public void onReplaceSuggestion(@NonNull String word) {}
|
||||
public void onReplaceSuggestion(@NonNull String rawWord) {
|
||||
if (SuggestionsBar.SHOW_SPECIAL_CHARS_SUGGESTION.equals(rawWord)) {
|
||||
Logger.d("InputMode", "Loading special characters for: " + seq.SPECIAL_CHAR_SEQUENCE);
|
||||
}
|
||||
|
||||
if (SuggestionsBar.SHOW_CURRENCIES_SUGGESTION.equals(rawWord)) {
|
||||
Logger.d("InputMode", "Loading special characters for: " + seq.CURRENCY_SEQUENCE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* loadSuggestions
|
||||
|
|
@ -140,7 +152,7 @@ abstract public class InputMode {
|
|||
// Interaction with the IME. Return "true" if it should perform the respective action.
|
||||
public boolean shouldAcceptPreviousSuggestion(String unacceptedText) { return false; }
|
||||
public boolean shouldAcceptPreviousSuggestion(int nextKey, boolean hold) { return false; }
|
||||
public boolean shouldReplacePreviousSuggestion() { return false; }
|
||||
public boolean shouldReplacePreviousSuggestion(@Nullable String currentWord) { return Characters.PLACEHOLDER.equals(currentWord); }
|
||||
public boolean shouldAddTrailingSpace(boolean isWordAcceptedManually, int nextKey) { return false; }
|
||||
public boolean shouldAddPrecedingSpace() { return false; }
|
||||
public boolean shouldDeletePrecedingSpace() { return false; }
|
||||
|
|
@ -190,6 +202,14 @@ abstract public class InputMode {
|
|||
protected String adjustSuggestionTextCase(String word, int newTextCase) { return word; }
|
||||
|
||||
|
||||
protected ArrayList<String> getAbbreviatedSpecialChars() {
|
||||
ArrayList<String> special = Characters.getWhitespaces(language);
|
||||
special.add(SuggestionsBar.SHOW_CURRENCIES_SUGGESTION);
|
||||
special.add(SuggestionsBar.SHOW_SPECIAL_CHARS_SUGGESTION);
|
||||
return special;
|
||||
}
|
||||
|
||||
|
||||
protected boolean loadSpecialCharacters() {
|
||||
int key = digitSequence.charAt(0) - '0';
|
||||
ArrayList<String> chars = settings.getOrderedKeyChars(language, key, specialCharSelectedGroup);
|
||||
|
|
@ -218,14 +238,22 @@ abstract public class InputMode {
|
|||
return new ArrayList<>(unordered);
|
||||
}
|
||||
|
||||
return orderSpecialChars(unordered, settings.getOrderedKeyChars(language, key));
|
||||
}
|
||||
|
||||
|
||||
public ArrayList<String> orderSpecialChars(@NonNull ArrayList<String> unordered, @Nullable ArrayList<String> order) {
|
||||
ArrayList<String> ordered = new ArrayList<>();
|
||||
if (unordered.isEmpty() || order == null || order.isEmpty()) {
|
||||
return ordered;
|
||||
}
|
||||
|
||||
if (isEmailMode) {
|
||||
if (unordered.contains("@")) ordered.add("@");
|
||||
if (unordered.contains("_")) ordered.add("_");
|
||||
}
|
||||
|
||||
for (String ch : settings.getOrderedKeyChars(language, key)) {
|
||||
for (String ch : order) {
|
||||
if (isEmailMode && (ch.charAt(0) == '@' || ch.charAt(0) == '_')) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package io.github.sspanak.tt9.ime.modes;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
|
|
@ -28,7 +29,7 @@ class Mode123 extends ModePassthrough {
|
|||
if (inputType.isPhoneNumber()) {
|
||||
setSpecificSpecialCharacters(Characters.Phone, false);
|
||||
} else if (inputType.isNumeric()) {
|
||||
setSpecificSpecialCharacters(Characters.getSpecialForNumbers(inputType.isDecimal(), inputType.isSignedNumber()), false);
|
||||
setSpecificSpecialCharacters(Characters.getAllForDecimal(inputType.isDecimal(), inputType.isSignedNumber()), false);
|
||||
} else if (isEmailMode) {
|
||||
setSpecificSpecialCharacters(Characters.Email, true);
|
||||
} else {
|
||||
|
|
@ -52,16 +53,15 @@ class Mode123 extends ModePassthrough {
|
|||
*/
|
||||
private void setDefaultSpecialCharacters() {
|
||||
Language english = LanguageCollection.getByLocale("en");
|
||||
KEY_CHARACTERS.add(getAbbreviatedSpecialChars());
|
||||
KEY_CHARACTERS.add(
|
||||
TextTools.removeLettersFromList(applyNumericFieldCharacterOrder(settings.getOrderedKeyChars(english, 0)))
|
||||
);
|
||||
KEY_CHARACTERS.add(
|
||||
TextTools.removeLettersFromList(applyNumericFieldCharacterOrder(settings.getOrderedKeyChars(english, 1)))
|
||||
TextTools.removeLettersFromList(orderSpecialChars(settings.getOrderedKeyChars(english, 1), null))
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
protected ArrayList<String> applyNumericFieldCharacterOrder(ArrayList<String> unordered) {
|
||||
@Override
|
||||
public ArrayList<String> orderSpecialChars(@NonNull ArrayList<String> unordered, @Nullable ArrayList<String> o) {
|
||||
ArrayList<String> ordered = new ArrayList<>();
|
||||
|
||||
if (unordered.contains(".")) {
|
||||
|
|
|
|||
|
|
@ -25,6 +25,9 @@ class ModeABC extends InputMode {
|
|||
if (isEmailMode) {
|
||||
KEY_CHARACTERS.add(applyPunctuationOrder(Characters.Email.get(0), 0));
|
||||
KEY_CHARACTERS.add(applyPunctuationOrder(Characters.Email.get(1), 1));
|
||||
} else {
|
||||
KEY_CHARACTERS.add(getAbbreviatedSpecialChars());
|
||||
KEY_CHARACTERS.add(settings.getOrderedKeyChars(language, 1));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -54,7 +57,7 @@ class ModeABC extends InputMode {
|
|||
autoAcceptTimeout = settings.getAbcAutoAcceptTimeout();
|
||||
digitSequence = String.valueOf(number);
|
||||
shouldSelectNextLetter = false;
|
||||
suggestions.addAll(KEY_CHARACTERS.size() > number ? KEY_CHARACTERS.get(number) : settings.getOrderedKeyChars(language, number));
|
||||
suggestions.addAll(KEY_CHARACTERS.size() > number ? KEY_CHARACTERS.get(number) : new ArrayList<>());
|
||||
suggestions.add(language.getKeyNumeral(number));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,20 +4,19 @@ import androidx.annotation.Nullable;
|
|||
|
||||
import io.github.sspanak.tt9.hacks.InputType;
|
||||
import io.github.sspanak.tt9.ime.helpers.TextField;
|
||||
import io.github.sspanak.tt9.ime.modes.helpers.Sequences;
|
||||
import io.github.sspanak.tt9.languages.EmojiLanguage;
|
||||
import io.github.sspanak.tt9.languages.Language;
|
||||
import io.github.sspanak.tt9.languages.LanguageKind;
|
||||
import io.github.sspanak.tt9.languages.NaturalLanguage;
|
||||
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
|
||||
import io.github.sspanak.tt9.util.TextTools;
|
||||
import io.github.sspanak.tt9.util.chars.Characters;
|
||||
|
||||
public class ModeBopomofo extends ModePinyin {
|
||||
private static final String SPECIAL_CHAR_SEQUENCE_PREFIX = "S0";
|
||||
private static final String PUNCTUATION_SEQUENCE_PREFIX = "S1";
|
||||
|
||||
protected ModeBopomofo(SettingsStore settings, Language lang, InputType inputType, TextField textField) {
|
||||
super(settings, lang, inputType, textField);
|
||||
seq = new Sequences("S1", "S0");
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -47,7 +46,7 @@ public class ModeBopomofo extends ModePinyin {
|
|||
*/
|
||||
protected void setCustomSpecialCharacters() {
|
||||
// special
|
||||
KEY_CHARACTERS.add(TextTools.removeLettersFromList(applyPunctuationOrder(Characters.getSpecial(language), 0)));
|
||||
KEY_CHARACTERS.add(getAbbreviatedSpecialChars());
|
||||
KEY_CHARACTERS.get(0).add(0, "0");
|
||||
|
||||
// punctuation
|
||||
|
|
@ -56,20 +55,11 @@ public class ModeBopomofo extends ModePinyin {
|
|||
);
|
||||
}
|
||||
|
||||
|
||||
protected void setSpecialCharacterConstants() {
|
||||
CUSTOM_EMOJI_SEQUENCE = PUNCTUATION_SEQUENCE_PREFIX + EmojiLanguage.CUSTOM_EMOJI_SEQUENCE;
|
||||
EMOJI_SEQUENCE = PUNCTUATION_SEQUENCE_PREFIX + EmojiLanguage.EMOJI_SEQUENCE;
|
||||
PUNCTUATION_SEQUENCE = PUNCTUATION_SEQUENCE_PREFIX + NaturalLanguage.PUNCTUATION_KEY;
|
||||
SPECIAL_CHAR_SEQUENCE = SPECIAL_CHAR_SEQUENCE_PREFIX + NaturalLanguage.SPECIAL_CHAR_KEY;
|
||||
}
|
||||
|
||||
|
||||
/***************************** TYPING *********************************/
|
||||
|
||||
@Override
|
||||
public boolean onBackspace() {
|
||||
if (digitSequence.equals(PUNCTUATION_SEQUENCE) || digitSequence.equals(SPECIAL_CHAR_SEQUENCE)) {
|
||||
if (digitSequence.equals(seq.PUNCTUATION_SEQUENCE) || digitSequence.equals(seq.WHITESPACE_SEQUENCE)) {
|
||||
digitSequence = "";
|
||||
return false;
|
||||
} else {
|
||||
|
|
@ -80,8 +70,8 @@ public class ModeBopomofo extends ModePinyin {
|
|||
|
||||
@Override
|
||||
protected void onNumberPress(int nextNumber) {
|
||||
if (digitSequence.startsWith(PUNCTUATION_SEQUENCE)) {
|
||||
digitSequence = PUNCTUATION_SEQUENCE_PREFIX + EmojiLanguage.validateEmojiSequence(digitSequence.substring(PUNCTUATION_SEQUENCE_PREFIX.length()), nextNumber);
|
||||
if (digitSequence.startsWith(seq.PUNCTUATION_SEQUENCE)) {
|
||||
digitSequence = EmojiLanguage.validateEmojiSequence(seq, digitSequence, nextNumber);
|
||||
} else {
|
||||
digitSequence += String.valueOf(nextNumber);
|
||||
}
|
||||
|
|
@ -92,10 +82,10 @@ public class ModeBopomofo extends ModePinyin {
|
|||
protected void onNumberHold(int number) {
|
||||
if (number == 0) {
|
||||
disablePredictions = false;
|
||||
digitSequence = SPECIAL_CHAR_SEQUENCE;
|
||||
digitSequence = seq.WHITESPACE_SEQUENCE;
|
||||
} else if (number == 1) {
|
||||
disablePredictions = false;
|
||||
digitSequence = PUNCTUATION_SEQUENCE;
|
||||
digitSequence = seq.PUNCTUATION_SEQUENCE;
|
||||
} else {
|
||||
autoAcceptTimeout = 0;
|
||||
suggestions.add(language.getKeyNumeral(number));
|
||||
|
|
@ -112,7 +102,7 @@ public class ModeBopomofo extends ModePinyin {
|
|||
public boolean shouldAcceptPreviousSuggestion(int nextKey, boolean hold) {
|
||||
String newSequence = digitSequence + (char)(nextKey + '0');
|
||||
return hold
|
||||
|| newSequence.startsWith(SPECIAL_CHAR_SEQUENCE)
|
||||
|| (newSequence.startsWith(PUNCTUATION_SEQUENCE) && nextKey != NaturalLanguage.PUNCTUATION_KEY.charAt(0) - '0');
|
||||
|| newSequence.startsWith(seq.WHITESPACE_SEQUENCE)
|
||||
|| (newSequence.startsWith(seq.PUNCTUATION_SEQUENCE) && nextKey != Sequences.PUNCTUATION_KEY);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,13 +9,13 @@ import io.github.sspanak.tt9.hacks.InputType;
|
|||
import io.github.sspanak.tt9.ime.helpers.TextField;
|
||||
import io.github.sspanak.tt9.ime.modes.helpers.AutoSpace;
|
||||
import io.github.sspanak.tt9.ime.modes.helpers.Cheonjiin;
|
||||
import io.github.sspanak.tt9.ime.modes.helpers.Sequences;
|
||||
import io.github.sspanak.tt9.ime.modes.predictions.Predictions;
|
||||
import io.github.sspanak.tt9.ime.modes.predictions.SyllablePredictions;
|
||||
import io.github.sspanak.tt9.languages.EmojiLanguage;
|
||||
import io.github.sspanak.tt9.languages.Language;
|
||||
import io.github.sspanak.tt9.languages.LanguageCollection;
|
||||
import io.github.sspanak.tt9.languages.LanguageKind;
|
||||
import io.github.sspanak.tt9.languages.NaturalLanguage;
|
||||
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
|
||||
import io.github.sspanak.tt9.util.TextTools;
|
||||
import io.github.sspanak.tt9.util.chars.Characters;
|
||||
|
|
@ -26,11 +26,8 @@ class ModeCheonjiin extends InputMode {
|
|||
protected final ArrayList<ArrayList<String>> KEY_CHARACTERS = new ArrayList<>();
|
||||
|
||||
// special chars and emojis
|
||||
private static String SPECIAL_CHAR_SEQUENCE_PREFIX;
|
||||
protected String CUSTOM_EMOJI_SEQUENCE;
|
||||
protected String EMOJI_SEQUENCE;
|
||||
protected String PUNCTUATION_SEQUENCE;
|
||||
protected String SPECIAL_CHAR_SEQUENCE;
|
||||
private final String PUNCTUATION_SEQUENCE_PREFIX = "11";
|
||||
private final String SPECIAL_CHAR_SEQUENCE_PREFIX = "00";
|
||||
|
||||
// predictions
|
||||
protected boolean disablePredictions = false;
|
||||
|
|
@ -46,18 +43,15 @@ class ModeCheonjiin extends InputMode {
|
|||
protected ModeCheonjiin(SettingsStore settings, InputType inputType, TextField textField) {
|
||||
super(settings, inputType);
|
||||
|
||||
SPECIAL_CHAR_SEQUENCE_PREFIX = "11";
|
||||
|
||||
|
||||
autoSpace = new AutoSpace(settings);
|
||||
digitSequence = "";
|
||||
allowedTextCases.add(CASE_LOWER);
|
||||
digitSequence = "";
|
||||
seq = new Sequences(PUNCTUATION_SEQUENCE_PREFIX, SPECIAL_CHAR_SEQUENCE_PREFIX);
|
||||
this.inputType = inputType;
|
||||
this.textField = textField;
|
||||
|
||||
setLanguage(LanguageCollection.getLanguage(LanguageKind.KOREAN));
|
||||
initPredictions();
|
||||
setSpecialCharacterConstants();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -68,7 +62,7 @@ class ModeCheonjiin extends InputMode {
|
|||
*/
|
||||
protected void setCustomSpecialCharacters() {
|
||||
// special
|
||||
KEY_CHARACTERS.add(TextTools.removeLettersFromList(applyPunctuationOrder(Characters.getSpecial(language), 0)));
|
||||
KEY_CHARACTERS.add(getAbbreviatedSpecialChars());
|
||||
KEY_CHARACTERS.get(0).add(0, "0");
|
||||
|
||||
// punctuation
|
||||
|
|
@ -94,14 +88,6 @@ class ModeCheonjiin extends InputMode {
|
|||
}
|
||||
|
||||
|
||||
protected void setSpecialCharacterConstants() {
|
||||
CUSTOM_EMOJI_SEQUENCE = SPECIAL_CHAR_SEQUENCE_PREFIX + EmojiLanguage.CUSTOM_EMOJI_SEQUENCE;
|
||||
EMOJI_SEQUENCE = SPECIAL_CHAR_SEQUENCE_PREFIX + EmojiLanguage.EMOJI_SEQUENCE;
|
||||
PUNCTUATION_SEQUENCE = SPECIAL_CHAR_SEQUENCE_PREFIX + NaturalLanguage.PUNCTUATION_KEY;
|
||||
SPECIAL_CHAR_SEQUENCE = "000";
|
||||
}
|
||||
|
||||
|
||||
protected void initPredictions() {
|
||||
predictions = new SyllablePredictions(settings);
|
||||
predictions
|
||||
|
|
@ -113,9 +99,9 @@ class ModeCheonjiin extends InputMode {
|
|||
|
||||
@Override
|
||||
public boolean onBackspace() {
|
||||
if (digitSequence.equals(PUNCTUATION_SEQUENCE)) {
|
||||
if (digitSequence.equals(seq.PUNCTUATION_SEQUENCE)) {
|
||||
digitSequence = "";
|
||||
} else if (digitSequence.equals(SPECIAL_CHAR_SEQUENCE) || (!digitSequence.startsWith(PUNCTUATION_SEQUENCE) && Cheonjiin.isSingleJamo(digitSequence))) {
|
||||
} else if (digitSequence.equals(seq.WHITESPACE_SEQUENCE) || (!digitSequence.startsWith(seq.PUNCTUATION_SEQUENCE) && Cheonjiin.isSingleJamo(digitSequence))) {
|
||||
digitSequence = "";
|
||||
} else if (!digitSequence.isEmpty()) {
|
||||
digitSequence = digitSequence.substring(0, digitSequence.length() - 1);
|
||||
|
|
@ -145,10 +131,10 @@ class ModeCheonjiin extends InputMode {
|
|||
protected void onNumberHold(int number) {
|
||||
if (number == 0) {
|
||||
disablePredictions = false;
|
||||
digitSequence = SPECIAL_CHAR_SEQUENCE;
|
||||
digitSequence = seq.WHITESPACE_SEQUENCE;
|
||||
} else if (number == 1) {
|
||||
disablePredictions = false;
|
||||
digitSequence = PUNCTUATION_SEQUENCE;
|
||||
digitSequence = seq.PUNCTUATION_SEQUENCE;
|
||||
} else {
|
||||
autoAcceptTimeout = 0;
|
||||
suggestions.add(language.getKeyNumeral(number));
|
||||
|
|
@ -162,8 +148,8 @@ class ModeCheonjiin extends InputMode {
|
|||
digitSequence = digitSequence.substring(0, digitSequence.length() - rewindAmount);
|
||||
}
|
||||
|
||||
if (digitSequence.startsWith(PUNCTUATION_SEQUENCE)) {
|
||||
digitSequence = SPECIAL_CHAR_SEQUENCE_PREFIX + EmojiLanguage.validateEmojiSequence(digitSequence.substring(SPECIAL_CHAR_SEQUENCE_PREFIX.length()), nextNumber);
|
||||
if (digitSequence.startsWith(seq.PUNCTUATION_SEQUENCE)) {
|
||||
digitSequence = EmojiLanguage.validateEmojiSequence(seq, digitSequence, nextNumber);
|
||||
} else {
|
||||
digitSequence += String.valueOf(nextNumber);
|
||||
}
|
||||
|
|
@ -175,8 +161,8 @@ class ModeCheonjiin extends InputMode {
|
|||
final int repeatingDigits = digitSequence.length() > 1 && digitSequence.charAt(digitSequence.length() - 1) == nextChar ? Cheonjiin.getRepeatingEndingDigits(digitSequence) : 0;
|
||||
final int keyCharsCount = nextNumber == 0 ? 2 : language.getKeyCharacters(nextNumber).size();
|
||||
|
||||
if (SPECIAL_CHAR_SEQUENCE.equals(digitSequence)) {
|
||||
return SPECIAL_CHAR_SEQUENCE.length();
|
||||
if (seq.WHITESPACE_SEQUENCE.equals(digitSequence)) {
|
||||
return seq.WHITESPACE_SEQUENCE.length();
|
||||
}
|
||||
|
||||
if (repeatingDigits == 0 || keyCharsCount < 2) {
|
||||
|
|
@ -214,16 +200,16 @@ class ModeCheonjiin extends InputMode {
|
|||
return;
|
||||
}
|
||||
|
||||
String seq = digitSequence;
|
||||
String currentSeq = digitSequence;
|
||||
if (shouldDisplayCustomEmojis()) {
|
||||
seq = digitSequence.substring(SPECIAL_CHAR_SEQUENCE_PREFIX.length());
|
||||
currentSeq = digitSequence.substring(PUNCTUATION_SEQUENCE_PREFIX.length());
|
||||
} else if (!previousJamoSequence.isEmpty()) {
|
||||
seq = previousJamoSequence;
|
||||
currentSeq = previousJamoSequence;
|
||||
}
|
||||
|
||||
predictions
|
||||
.setLanguage(shouldDisplayCustomEmojis() ? new EmojiLanguage() : language)
|
||||
.setDigitSequence(seq)
|
||||
.setLanguage(shouldDisplayCustomEmojis() ? new EmojiLanguage(seq) : language)
|
||||
.setDigitSequence(currentSeq)
|
||||
.load();
|
||||
}
|
||||
|
||||
|
|
@ -231,7 +217,7 @@ class ModeCheonjiin extends InputMode {
|
|||
protected boolean loadEmojis() {
|
||||
if (shouldDisplayEmojis()) {
|
||||
suggestions.clear();
|
||||
suggestions.addAll(new EmojiLanguage().getKeyCharacters(digitSequence.charAt(digitSequence.length() - 1) - '0', getEmojiGroup()));
|
||||
suggestions.addAll(new EmojiLanguage(seq).getKeyCharacters(digitSequence.charAt(digitSequence.length() - 1) - '0', getEmojiGroup()));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -240,17 +226,17 @@ class ModeCheonjiin extends InputMode {
|
|||
|
||||
|
||||
protected int getEmojiGroup() {
|
||||
return digitSequence.length() - EMOJI_SEQUENCE.length();
|
||||
return digitSequence.length() - seq.EMOJI_SEQUENCE.length();
|
||||
}
|
||||
|
||||
|
||||
protected boolean shouldDisplayEmojis() {
|
||||
return !isEmailMode && digitSequence.startsWith(EMOJI_SEQUENCE) && !digitSequence.equals(CUSTOM_EMOJI_SEQUENCE);
|
||||
return !isEmailMode && digitSequence.startsWith(seq.EMOJI_SEQUENCE) && !digitSequence.equals(seq.CUSTOM_EMOJI_SEQUENCE);
|
||||
}
|
||||
|
||||
|
||||
protected boolean shouldDisplayCustomEmojis() {
|
||||
return !isEmailMode && digitSequence.equals(CUSTOM_EMOJI_SEQUENCE);
|
||||
return !isEmailMode && digitSequence.equals(seq.CUSTOM_EMOJI_SEQUENCE);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -285,7 +271,7 @@ class ModeCheonjiin extends InputMode {
|
|||
|
||||
|
||||
protected boolean shouldDisplaySpecialCharacters() {
|
||||
return digitSequence.equals(PUNCTUATION_SEQUENCE) || digitSequence.equals(SPECIAL_CHAR_SEQUENCE);
|
||||
return digitSequence.equals(seq.PUNCTUATION_SEQUENCE) || digitSequence.equals(seq.WHITESPACE_SEQUENCE);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -295,8 +281,8 @@ class ModeCheonjiin extends InputMode {
|
|||
*/
|
||||
protected void onPredictions() {
|
||||
// in case the user hasn't added any custom emoji, do not allow advancing to the empty character group
|
||||
if (predictions.getList().isEmpty() && digitSequence.startsWith(EMOJI_SEQUENCE)) {
|
||||
digitSequence = EMOJI_SEQUENCE;
|
||||
if (predictions.getList().isEmpty() && digitSequence.startsWith(seq.EMOJI_SEQUENCE)) {
|
||||
digitSequence = seq.EMOJI_SEQUENCE;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -351,8 +337,8 @@ class ModeCheonjiin extends InputMode {
|
|||
public boolean shouldAcceptPreviousSuggestion(int nextKey, boolean hold) {
|
||||
return
|
||||
(hold && !digitSequence.isEmpty())
|
||||
|| (digitSequence.equals(SPECIAL_CHAR_SEQUENCE) && nextKey != 0)
|
||||
|| (digitSequence.startsWith(PUNCTUATION_SEQUENCE) && nextKey != 1);
|
||||
|| (digitSequence.equals(seq.WHITESPACE_SEQUENCE) && nextKey != 0)
|
||||
|| (digitSequence.startsWith(seq.PUNCTUATION_SEQUENCE) && nextKey != 1);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ public class ModeHiragana extends ModeKanji {
|
|||
|
||||
@Override
|
||||
protected void initPredictions() {
|
||||
predictions = new KanaPredictions(settings, textField, false);
|
||||
predictions = new KanaPredictions(settings, textField, seq, false);
|
||||
predictions.setWordsChangedHandler(this::onPredictions);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ public class ModeIdeograms extends ModeWords {
|
|||
|
||||
@Override
|
||||
protected void initPredictions() {
|
||||
predictions = new IdeogramPredictions(settings, textField);
|
||||
predictions = new IdeogramPredictions(settings, textField, seq);
|
||||
predictions.setWordsChangedHandler(this::onPredictions);
|
||||
}
|
||||
|
||||
|
|
@ -117,7 +117,7 @@ public class ModeIdeograms extends ModeWords {
|
|||
boolean lastDigitBelongsToNewWord = preserveWords && initialLength >= 2;
|
||||
|
||||
try {
|
||||
if (!digitSequence.equals(SPECIAL_CHAR_SEQUENCE) && !digitSequence.equals(PUNCTUATION_SEQUENCE)) {
|
||||
if (!digitSequence.equals(seq.WHITESPACE_SEQUENCE) && !digitSequence.equals(seq.PUNCTUATION_SEQUENCE)) {
|
||||
lastAcceptedWord = currentWord;
|
||||
lastAcceptedSequence = lastDigitBelongsToNewWord ? digitSequence.substring(0, initialLength - 1) : digitSequence;
|
||||
|
||||
|
|
@ -143,9 +143,9 @@ public class ModeIdeograms extends ModeWords {
|
|||
return
|
||||
digitSequence.length() > 1
|
||||
&& predictions.noDbWords()
|
||||
&& !digitSequence.equals(EMOJI_SEQUENCE)
|
||||
&& !digitSequence.equals(PUNCTUATION_SEQUENCE)
|
||||
&& !digitSequence.equals(SPECIAL_CHAR_SEQUENCE);
|
||||
&& !digitSequence.equals(seq.EMOJI_SEQUENCE)
|
||||
&& !digitSequence.equals(seq.PUNCTUATION_SEQUENCE)
|
||||
&& !digitSequence.equals(seq.WHITESPACE_SEQUENCE);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -164,8 +164,8 @@ public class ModeIdeograms extends ModeWords {
|
|||
return
|
||||
TextTools.containsOtherThan1(nextSequence)
|
||||
&& (
|
||||
nextSequence.endsWith(EMOJI_SEQUENCE) || nextSequence.startsWith(EMOJI_SEQUENCE) ||
|
||||
nextSequence.endsWith(PUNCTUATION_SEQUENCE) || nextSequence.startsWith(PUNCTUATION_SEQUENCE)
|
||||
nextSequence.endsWith(seq.EMOJI_SEQUENCE) || nextSequence.startsWith(seq.EMOJI_SEQUENCE) ||
|
||||
nextSequence.endsWith(seq.PUNCTUATION_SEQUENCE) || nextSequence.startsWith(seq.PUNCTUATION_SEQUENCE)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -196,8 +196,8 @@ public class ModeIdeograms extends ModeWords {
|
|||
* accept it.
|
||||
*/
|
||||
@Override
|
||||
public boolean shouldReplacePreviousSuggestion() {
|
||||
return isFiltering;
|
||||
public boolean shouldReplacePreviousSuggestion(@Nullable String word) {
|
||||
return isFiltering || super.shouldReplacePreviousSuggestion(word);
|
||||
}
|
||||
|
||||
/********************************* FILTERING *********************************/
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ public class ModeKanji extends ModePinyin {
|
|||
}
|
||||
|
||||
String nextSequence = digitSequence + (char)(nextKey + '0');
|
||||
if (nextSequence.endsWith(PUNCTUATION_SEQUENCE) && !predictions.noDbWords()) {
|
||||
if (nextSequence.endsWith(seq.PUNCTUATION_SEQUENCE) && !predictions.noDbWords()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ public class ModeKatakana extends ModeHiragana {
|
|||
|
||||
@Override
|
||||
protected void initPredictions() {
|
||||
predictions = new KanaPredictions(settings, textField, true);
|
||||
predictions = new KanaPredictions(settings, textField, seq, true);
|
||||
predictions.setWordsChangedHandler(this::onPredictions);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,14 +4,13 @@ import androidx.annotation.Nullable;
|
|||
|
||||
import io.github.sspanak.tt9.hacks.InputType;
|
||||
import io.github.sspanak.tt9.ime.helpers.TextField;
|
||||
import io.github.sspanak.tt9.ime.modes.helpers.Sequences;
|
||||
import io.github.sspanak.tt9.languages.Language;
|
||||
import io.github.sspanak.tt9.languages.LanguageKind;
|
||||
import io.github.sspanak.tt9.languages.NaturalLanguage;
|
||||
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
|
||||
import io.github.sspanak.tt9.util.chars.Characters;
|
||||
|
||||
public class ModePinyin extends ModeIdeograms {
|
||||
private final int SPECIAL_CHAR_KEY = NaturalLanguage.SPECIAL_CHAR_KEY.charAt(0) - '0';
|
||||
private boolean ignoreNextSpace = false;
|
||||
|
||||
|
||||
|
|
@ -44,7 +43,7 @@ public class ModePinyin extends ModeIdeograms {
|
|||
|
||||
@Override
|
||||
protected void onNumberPress(int number) {
|
||||
if (ignoreNextSpace && number == SPECIAL_CHAR_KEY) {
|
||||
if (ignoreNextSpace && number == Sequences.SPECIAL_CHAR_KEY) {
|
||||
ignoreNextSpace = false;
|
||||
return;
|
||||
}
|
||||
|
|
@ -66,7 +65,7 @@ public class ModePinyin extends ModeIdeograms {
|
|||
// In East Asian languages, Space must accept the current word, or type a space when there is no word.
|
||||
// Here, we handle the case when 0-key is Space, unlike the Space hotkey in HotkeyHandler,
|
||||
// which could be a different key, assigned by the user.
|
||||
if (!digitSequence.isEmpty() && !digitSequence.endsWith(SPECIAL_CHAR_SEQUENCE) && nextKey == SPECIAL_CHAR_KEY) {
|
||||
if (!digitSequence.isEmpty() && !digitSequence.endsWith(seq.WHITESPACE_SEQUENCE) && nextKey == Sequences.SPECIAL_CHAR_KEY) {
|
||||
ignoreNextSpace = true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,11 +9,11 @@ import java.util.List;
|
|||
import io.github.sspanak.tt9.hacks.InputType;
|
||||
import io.github.sspanak.tt9.ime.helpers.TextField;
|
||||
import io.github.sspanak.tt9.ime.modes.helpers.AutoTextCase;
|
||||
import io.github.sspanak.tt9.ime.modes.helpers.Sequences;
|
||||
import io.github.sspanak.tt9.ime.modes.predictions.WordPredictions;
|
||||
import io.github.sspanak.tt9.languages.EmojiLanguage;
|
||||
import io.github.sspanak.tt9.languages.Language;
|
||||
import io.github.sspanak.tt9.languages.LanguageKind;
|
||||
import io.github.sspanak.tt9.languages.NaturalLanguage;
|
||||
import io.github.sspanak.tt9.languages.exceptions.InvalidLanguageCharactersException;
|
||||
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
|
||||
import io.github.sspanak.tt9.util.Logger;
|
||||
|
|
@ -39,6 +39,7 @@ class ModeWords extends ModeCheonjiin {
|
|||
super(settings, inputType, textField);
|
||||
|
||||
autoTextCase = new AutoTextCase(settings, inputType);
|
||||
seq = new Sequences();
|
||||
|
||||
changeLanguage(lang);
|
||||
defaultTextCase();
|
||||
|
|
@ -46,20 +47,14 @@ class ModeWords extends ModeCheonjiin {
|
|||
}
|
||||
|
||||
|
||||
@Override protected void setCustomSpecialCharacters() {} // we use the default ones
|
||||
|
||||
|
||||
protected void setSpecialCharacterConstants() {
|
||||
PUNCTUATION_SEQUENCE = NaturalLanguage.PUNCTUATION_KEY;
|
||||
EMOJI_SEQUENCE = EmojiLanguage.EMOJI_SEQUENCE;
|
||||
CUSTOM_EMOJI_SEQUENCE = EmojiLanguage.CUSTOM_EMOJI_SEQUENCE;
|
||||
SPECIAL_CHAR_SEQUENCE = NaturalLanguage.SPECIAL_CHAR_KEY;
|
||||
@Override protected void setCustomSpecialCharacters() {
|
||||
KEY_CHARACTERS.add(getAbbreviatedSpecialChars()); // special
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void initPredictions() {
|
||||
predictions = new WordPredictions(settings, textField);
|
||||
predictions = new WordPredictions(settings, textField, seq);
|
||||
predictions.setWordsChangedHandler(this::onPredictions);
|
||||
}
|
||||
|
||||
|
|
@ -100,9 +95,9 @@ class ModeWords extends ModeCheonjiin {
|
|||
|
||||
@Override
|
||||
protected void onNumberPress(int number) {
|
||||
digitSequence = EmojiLanguage.validateEmojiSequence(digitSequence, number);
|
||||
digitSequence = EmojiLanguage.validateEmojiSequence(seq, digitSequence, number);
|
||||
|
||||
if (digitSequence.equals(NaturalLanguage.PREFERRED_CHAR_SEQUENCE)) {
|
||||
if (digitSequence.equals(seq.PREFERRED_CHAR_SEQUENCE)) {
|
||||
autoAcceptTimeout = 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -286,13 +281,13 @@ class ModeWords extends ModeCheonjiin {
|
|||
.setIsStemFuzzy(isStemFuzzy)
|
||||
.setStem(stem)
|
||||
.setDigitSequence(digitSequence)
|
||||
.setLanguage(shouldDisplayCustomEmojis() ? new EmojiLanguage() : language)
|
||||
.setLanguage(shouldDisplayCustomEmojis() ? new EmojiLanguage(seq) : language)
|
||||
.load();
|
||||
}
|
||||
|
||||
|
||||
protected boolean loadPreferredChar() {
|
||||
if (digitSequence.startsWith(NaturalLanguage.PREFERRED_CHAR_SEQUENCE)) {
|
||||
if (digitSequence.startsWith(seq.PREFERRED_CHAR_SEQUENCE)) {
|
||||
suggestions.clear();
|
||||
suggestions.add(getPreferredChar());
|
||||
return true;
|
||||
|
|
@ -334,13 +329,13 @@ class ModeWords extends ModeCheonjiin {
|
|||
|
||||
try {
|
||||
// special chars are not in the database, no need to run queries on them
|
||||
String digitSequence = language.getDigitSequenceForWord(currentWord);
|
||||
if (digitSequence.equals(SPECIAL_CHAR_SEQUENCE) || digitSequence.equals(PUNCTUATION_SEQUENCE)) {
|
||||
String currentWordSeq = language.getDigitSequenceForWord(currentWord);
|
||||
if (seq.isAnySpecialCharSequence(currentWordSeq)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// increment the frequency of the given word
|
||||
predictions.onAccept(currentWord, digitSequence);
|
||||
predictions.onAccept(currentWord, currentWordSeq);
|
||||
} catch (Exception e) {
|
||||
Logger.e(LOG_TAG, "Failed incrementing priority of word: '" + currentWord + "'. " + e.getMessage());
|
||||
}
|
||||
|
|
@ -382,8 +377,7 @@ class ModeWords extends ModeCheonjiin {
|
|||
changed = super.nextTextCase();
|
||||
}
|
||||
|
||||
boolean onlySpecialChars = digitSequence.startsWith(PUNCTUATION_SEQUENCE) || digitSequence.startsWith(SPECIAL_CHAR_SEQUENCE) || digitSequence.startsWith(EMOJI_SEQUENCE);
|
||||
if (onlySpecialChars && textCase == CASE_CAPITALIZE) {
|
||||
if (seq.startsWithAnySpecialCharSequence(digitSequence) && textCase == CASE_CAPITALIZE) {
|
||||
super.nextTextCase();
|
||||
}
|
||||
|
||||
|
|
@ -411,20 +405,17 @@ class ModeWords extends ModeCheonjiin {
|
|||
return true;
|
||||
}
|
||||
|
||||
final char SPECIAL_CHAR_KEY_CODE = SPECIAL_CHAR_SEQUENCE.charAt(SPECIAL_CHAR_SEQUENCE.length() - 1);
|
||||
final int SPECIAL_CHAR_KEY = SPECIAL_CHAR_KEY_CODE - '0';
|
||||
|
||||
// Prevent typing the preferred character when the user has scrolled the special char suggestions.
|
||||
// For example, it makes more sense to allow typing "+ " with 0 + scroll + 0, instead of clearing
|
||||
// the "+" and replacing it with the preferred character.
|
||||
if (!stem.isEmpty() && nextKey == SPECIAL_CHAR_KEY && digitSequence.charAt(0) == SPECIAL_CHAR_KEY_CODE) {
|
||||
if (!stem.isEmpty() && nextKey == Sequences.SPECIAL_CHAR_KEY && digitSequence.charAt(0) == Sequences.SPECIAL_CHAR_CODE) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return
|
||||
!digitSequence.isEmpty() && (
|
||||
(nextKey == SPECIAL_CHAR_KEY && digitSequence.charAt(digitSequence.length() - 1) != SPECIAL_CHAR_KEY_CODE)
|
||||
|| (nextKey != SPECIAL_CHAR_KEY && digitSequence.charAt(digitSequence.length() - 1) == SPECIAL_CHAR_KEY_CODE)
|
||||
(nextKey == Sequences.SPECIAL_CHAR_KEY && digitSequence.charAt(digitSequence.length() - 1) != Sequences.SPECIAL_CHAR_CODE)
|
||||
|| (nextKey != Sequences.SPECIAL_CHAR_KEY && digitSequence.charAt(digitSequence.length() - 1) == Sequences.SPECIAL_CHAR_CODE)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -448,8 +439,8 @@ class ModeWords extends ModeCheonjiin {
|
|||
return
|
||||
!digitSequence.isEmpty()
|
||||
&& predictions.noDbWords()
|
||||
&& digitSequence.contains(PUNCTUATION_SEQUENCE)
|
||||
&& !digitSequence.startsWith(EMOJI_SEQUENCE)
|
||||
&& digitSequence.contains(seq.PUNCTUATION_SEQUENCE)
|
||||
&& !digitSequence.startsWith(seq.EMOJI_SEQUENCE)
|
||||
&& Text.containsOtherThan1(digitSequence);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,70 @@
|
|||
package io.github.sspanak.tt9.ime.modes.helpers;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
public class Sequences {
|
||||
public static final int SPECIAL_CHAR_KEY = 0;
|
||||
public static final int SPECIAL_CHAR_CODE = SPECIAL_CHAR_KEY + '0';
|
||||
public static final int PUNCTUATION_KEY = 1;
|
||||
public static final int CUSTOM_EMOJI_KEY = 3;
|
||||
|
||||
public final int PUNCTUATION_PREFIX_LENGTH;
|
||||
|
||||
@NonNull public final String PUNCTUATION_SEQUENCE;
|
||||
@NonNull public final String EMOJI_SEQUENCE;
|
||||
@NonNull public final String CUSTOM_EMOJI_SEQUENCE;
|
||||
|
||||
@NonNull public final String CURRENCY_SEQUENCE;
|
||||
@NonNull public final String PREFERRED_CHAR_SEQUENCE;
|
||||
@NonNull public final String SPECIAL_CHAR_SEQUENCE;
|
||||
@NonNull public final String WHITESPACE_SEQUENCE;
|
||||
|
||||
public Sequences() {
|
||||
this(null, null);
|
||||
}
|
||||
|
||||
public Sequences(@Nullable String punctuationPrefix, @Nullable String specialCharPrefix) {
|
||||
final String PUNCTUATION_PREFIX = punctuationPrefix != null ? punctuationPrefix : "";
|
||||
final String SPECIAL_CHAR_PREFIX = specialCharPrefix != null ? specialCharPrefix : "";
|
||||
|
||||
PUNCTUATION_SEQUENCE = PUNCTUATION_PREFIX + PUNCTUATION_KEY;
|
||||
PUNCTUATION_PREFIX_LENGTH = PUNCTUATION_PREFIX.length();
|
||||
|
||||
EMOJI_SEQUENCE = PUNCTUATION_SEQUENCE + PUNCTUATION_KEY;
|
||||
CUSTOM_EMOJI_SEQUENCE = EMOJI_SEQUENCE + CUSTOM_EMOJI_KEY;
|
||||
|
||||
WHITESPACE_SEQUENCE = SPECIAL_CHAR_PREFIX + SPECIAL_CHAR_KEY;
|
||||
PREFERRED_CHAR_SEQUENCE = WHITESPACE_SEQUENCE + SPECIAL_CHAR_KEY;
|
||||
SPECIAL_CHAR_SEQUENCE = SPECIAL_CHAR_PREFIX + SPECIAL_CHAR_KEY + SPECIAL_CHAR_KEY + SPECIAL_CHAR_KEY;
|
||||
CURRENCY_SEQUENCE = SPECIAL_CHAR_SEQUENCE + SPECIAL_CHAR_KEY;
|
||||
}
|
||||
|
||||
public boolean isAnySpecialCharSequence(String sequence) {
|
||||
if (sequence == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return
|
||||
sequence.equals(PUNCTUATION_SEQUENCE)
|
||||
|| sequence.equals(WHITESPACE_SEQUENCE)
|
||||
|| sequence.equals(EMOJI_SEQUENCE)
|
||||
|| sequence.equals(PREFERRED_CHAR_SEQUENCE)
|
||||
|| sequence.equals(SPECIAL_CHAR_SEQUENCE)
|
||||
|| sequence.equals(CURRENCY_SEQUENCE);
|
||||
}
|
||||
|
||||
public boolean startsWithAnySpecialCharSequence(String sequence) {
|
||||
if (sequence == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return
|
||||
sequence.startsWith(PUNCTUATION_SEQUENCE)
|
||||
|| sequence.startsWith(WHITESPACE_SEQUENCE)
|
||||
|| sequence.startsWith(EMOJI_SEQUENCE)
|
||||
|| sequence.startsWith(PREFERRED_CHAR_SEQUENCE)
|
||||
|| sequence.startsWith(SPECIAL_CHAR_SEQUENCE)
|
||||
|| sequence.startsWith(CURRENCY_SEQUENCE);
|
||||
}
|
||||
}
|
||||
|
|
@ -8,6 +8,7 @@ import java.util.HashSet;
|
|||
|
||||
import io.github.sspanak.tt9.db.DataStore;
|
||||
import io.github.sspanak.tt9.ime.helpers.TextField;
|
||||
import io.github.sspanak.tt9.ime.modes.helpers.Sequences;
|
||||
import io.github.sspanak.tt9.languages.Language;
|
||||
import io.github.sspanak.tt9.languages.exceptions.InvalidLanguageCharactersException;
|
||||
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
|
||||
|
|
@ -20,8 +21,8 @@ public class IdeogramPredictions extends WordPredictions {
|
|||
@NonNull protected ArrayList<String> lastTranscriptions = new ArrayList<>();
|
||||
|
||||
|
||||
public IdeogramPredictions(SettingsStore settings, TextField textField) {
|
||||
super(settings, textField);
|
||||
public IdeogramPredictions(SettingsStore settings, TextField textField, Sequences sequences) {
|
||||
super(settings, textField, sequences);
|
||||
minWords = 1;
|
||||
onlyExactMatches = true;
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import androidx.annotation.NonNull;
|
|||
import java.util.ArrayList;
|
||||
|
||||
import io.github.sspanak.tt9.ime.helpers.TextField;
|
||||
import io.github.sspanak.tt9.ime.modes.helpers.Sequences;
|
||||
import io.github.sspanak.tt9.languages.exceptions.InvalidLanguageCharactersException;
|
||||
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
|
||||
|
||||
|
|
@ -13,8 +14,8 @@ public class KanaPredictions extends IdeogramPredictions {
|
|||
@NonNull private final String STEM_PREFIX;
|
||||
private final int STEM_PREFIX_LENGTH;
|
||||
|
||||
public KanaPredictions(SettingsStore settings, TextField textField, boolean isKatakana) {
|
||||
super(settings, textField);
|
||||
public KanaPredictions(SettingsStore settings, TextField textField, Sequences sequences, boolean isKatakana) {
|
||||
super(settings, textField, sequences);
|
||||
|
||||
SEQUENCE_PREFIX = isKatakana ? '1' : '0';
|
||||
STEM_PREFIX = isKatakana ? "Qk" : "Qh";
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import java.util.ArrayList;
|
|||
|
||||
import io.github.sspanak.tt9.db.DataStore;
|
||||
import io.github.sspanak.tt9.ime.helpers.TextField;
|
||||
import io.github.sspanak.tt9.languages.EmojiLanguage;
|
||||
import io.github.sspanak.tt9.ime.modes.helpers.Sequences;
|
||||
import io.github.sspanak.tt9.languages.Language;
|
||||
import io.github.sspanak.tt9.languages.LanguageKind;
|
||||
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
|
||||
|
|
@ -17,6 +17,7 @@ import io.github.sspanak.tt9.util.chars.Characters;
|
|||
public class WordPredictions extends Predictions {
|
||||
protected final TextField textField;
|
||||
private LocaleWordsSorter localeWordsSorter;
|
||||
private final Sequences seq;
|
||||
|
||||
private String inputWord;
|
||||
private boolean isStemFuzzy;
|
||||
|
|
@ -25,11 +26,12 @@ public class WordPredictions extends Predictions {
|
|||
protected String penultimateWord;
|
||||
|
||||
|
||||
public WordPredictions(SettingsStore settings, TextField textField) {
|
||||
public WordPredictions(SettingsStore settings, TextField textField, Sequences sequences) {
|
||||
super(settings);
|
||||
lastEnforcedTopWord = "";
|
||||
localeWordsSorter = new LocaleWordsSorter(null);
|
||||
penultimateWord = "";
|
||||
seq = sequences;
|
||||
stem = "";
|
||||
this.textField = textField;
|
||||
}
|
||||
|
|
@ -92,7 +94,7 @@ public class WordPredictions extends Predictions {
|
|||
|
||||
@Override
|
||||
protected boolean isRetryAllowed() {
|
||||
return !EmojiLanguage.CUSTOM_EMOJI_SEQUENCE.equals(digitSequence);
|
||||
return !seq.CUSTOM_EMOJI_SEQUENCE.equals(digitSequence);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -113,7 +115,7 @@ public class WordPredictions extends Predictions {
|
|||
}
|
||||
|
||||
words.clear();
|
||||
if (digitSequence.equals(EmojiLanguage.CUSTOM_EMOJI_SEQUENCE)) {
|
||||
if (digitSequence.equals(seq.CUSTOM_EMOJI_SEQUENCE)) {
|
||||
words.addAll(dbWords);
|
||||
} else {
|
||||
suggestStem();
|
||||
|
|
|
|||
|
|
@ -5,27 +5,31 @@ import androidx.annotation.NonNull;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Locale;
|
||||
|
||||
import io.github.sspanak.tt9.ime.modes.helpers.Sequences;
|
||||
import io.github.sspanak.tt9.util.TextTools;
|
||||
import io.github.sspanak.tt9.util.chars.Characters;
|
||||
|
||||
public class EmojiLanguage extends Language {
|
||||
final public static String EMOJI_SEQUENCE = "11";
|
||||
final private static int CUSTOM_EMOJI_KEY = 3;
|
||||
final public static String CUSTOM_EMOJI_SEQUENCE = EMOJI_SEQUENCE + CUSTOM_EMOJI_KEY;
|
||||
private final Sequences seq;
|
||||
|
||||
public EmojiLanguage() {
|
||||
id = Integer.parseInt(EMOJI_SEQUENCE);
|
||||
this(null);
|
||||
}
|
||||
|
||||
public EmojiLanguage(Sequences sequences) {
|
||||
id = Integer.parseInt(new Sequences().EMOJI_SEQUENCE); // always use the unprefixed sequence for ID
|
||||
locale = Locale.ROOT;
|
||||
abcString = "emoji";
|
||||
code = "emj";
|
||||
currency = "";
|
||||
name = "Emoji";
|
||||
seq = sequences == null ? new Sequences() : sequences;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getDigitSequenceForWord(String word) {
|
||||
return TextTools.isGraphic(word) ? CUSTOM_EMOJI_SEQUENCE : "";
|
||||
return isValidWord(word) ? seq.EMOJI_SEQUENCE : "";
|
||||
}
|
||||
|
||||
@NonNull
|
||||
|
|
@ -39,10 +43,10 @@ public class EmojiLanguage extends Language {
|
|||
return TextTools.isGraphic(word);
|
||||
}
|
||||
|
||||
public static String validateEmojiSequence(@NonNull String sequence, int next) {
|
||||
if (sequence.startsWith(CUSTOM_EMOJI_SEQUENCE) || (sequence.equals(EMOJI_SEQUENCE) && next == CUSTOM_EMOJI_KEY)) {
|
||||
return CUSTOM_EMOJI_SEQUENCE;
|
||||
} else if (sequence.startsWith(EMOJI_SEQUENCE) && (next > 1 || sequence.length() == Characters.getMaxEmojiLevel() + 1)) {
|
||||
public static String validateEmojiSequence(@NonNull Sequences seq, @NonNull String sequence, int next) {
|
||||
if (sequence.startsWith(seq.CUSTOM_EMOJI_SEQUENCE) || (sequence.equals(seq.EMOJI_SEQUENCE) && next == Sequences.CUSTOM_EMOJI_KEY)) {
|
||||
return seq.CUSTOM_EMOJI_SEQUENCE;
|
||||
} else if (sequence.startsWith(seq.EMOJI_SEQUENCE) && (next > 1 || sequence.length() - seq.PUNCTUATION_PREFIX_LENGTH == Characters.getMaxEmojiLevel() + 1)) {
|
||||
return sequence;
|
||||
} else {
|
||||
return sequence + next;
|
||||
|
|
|
|||
|
|
@ -14,11 +14,6 @@ import io.github.sspanak.tt9.util.chars.Characters;
|
|||
|
||||
|
||||
public class NaturalLanguage extends TranscribedLanguage {
|
||||
final public static String SPECIAL_CHAR_KEY = "0";
|
||||
final public static String PUNCTUATION_KEY = "1";
|
||||
final public static String PREFERRED_CHAR_SEQUENCE = "00";
|
||||
|
||||
|
||||
protected final ArrayList<ArrayList<String>> layout = new ArrayList<>();
|
||||
private final HashMap<Character, String> characterKeyMap = new HashMap<>();
|
||||
@NonNull private HashMap<Integer, String> numerals = new HashMap<>();
|
||||
|
|
@ -86,7 +81,7 @@ public class NaturalLanguage extends TranscribedLanguage {
|
|||
final String PUNCTUATION_PLACEHOLDER = "PUNCTUATION";
|
||||
|
||||
final Map<String, List<String>> specialChars = new HashMap<>();
|
||||
specialChars.put(SPECIAL_CHARS_PLACEHOLDER, Characters.getSpecial(this));
|
||||
specialChars.put(SPECIAL_CHARS_PLACEHOLDER, new ArrayList<>(Characters.Special));
|
||||
specialChars.put(PUNCTUATION_PLACEHOLDER, Characters.PunctuationEnglish);
|
||||
specialChars.put(PUNCTUATION_PLACEHOLDER + "_AR", Characters.PunctuationArabic);
|
||||
specialChars.put(PUNCTUATION_PLACEHOLDER + "_BP", Characters.PunctuationChineseBopomofo);
|
||||
|
|
@ -222,17 +217,7 @@ public class NaturalLanguage extends TranscribedLanguage {
|
|||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
ArrayList<String> chars = layout.get(key);
|
||||
if (key == 0) {
|
||||
if (characterGroup > 1) {
|
||||
chars = new ArrayList<>();
|
||||
} else if (characterGroup == 1) {
|
||||
chars = new ArrayList<>(Characters.Currency);
|
||||
if (!currency.isEmpty()) chars.add(2, currency);
|
||||
}
|
||||
}
|
||||
|
||||
return chars;
|
||||
return layout.get(key);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import androidx.annotation.NonNull;
|
|||
import java.util.ArrayList;
|
||||
|
||||
import io.github.sspanak.tt9.languages.Language;
|
||||
import io.github.sspanak.tt9.util.chars.Characters;
|
||||
|
||||
class SettingsPunctuation extends SettingsInput {
|
||||
private final static String KEY_PREFIX_PUNCTUATION = "pref_punctuation_";
|
||||
|
|
@ -27,7 +28,9 @@ class SettingsPunctuation extends SettingsInput {
|
|||
|
||||
|
||||
public void saveSpecialChars(@NonNull Language language, @NonNull String specialChars) {
|
||||
String safeChars = specialChars.replace("\n", "⏎");
|
||||
String safeChars = specialChars
|
||||
.replace("\n", "⏎")
|
||||
.replace("\t", Characters.TAB);
|
||||
prefsEditor.putString(KEY_PREFIX_SPECIAL + language.getId(), safeChars);
|
||||
prefsEditor.apply();
|
||||
}
|
||||
|
|
@ -65,7 +68,7 @@ class SettingsPunctuation extends SettingsInput {
|
|||
String safeChars = prefs.getString(KEY_PREFIX_SPECIAL + language.getId(), null);
|
||||
|
||||
return getCharsAsList(
|
||||
safeChars == null ? null : safeChars.replace("⏎", "\n"),
|
||||
safeChars == null ? null : safeChars.replace("⏎", "\n").replace(Characters.TAB, "\t"),
|
||||
language.getKeyCharacters(0)
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -109,10 +109,10 @@ public class SoftKeyNumber2to9 extends SoftKeyNumber {
|
|||
*/
|
||||
private String abbreviateCharList(String chars, String abbreviationSign, Locale locale, boolean isUppercase) {
|
||||
String firstLetter = chars.substring(0, 1);
|
||||
firstLetter = TextTools.isCombining(firstLetter) ? Characters.COMBINING_ZERO_BASE + firstLetter : firstLetter;
|
||||
firstLetter = TextTools.isCombining(firstLetter) ? Characters.PLACEHOLDER + firstLetter : firstLetter;
|
||||
|
||||
String lastLetter = chars.substring(chars.length() - 1);
|
||||
lastLetter = TextTools.isCombining(lastLetter) ? Characters.COMBINING_ZERO_BASE + lastLetter : lastLetter;
|
||||
lastLetter = TextTools.isCombining(lastLetter) ? Characters.PLACEHOLDER + lastLetter : lastLetter;
|
||||
|
||||
String list = firstLetter + abbreviationSign + lastLetter;
|
||||
return isUppercase ? list.toUpperCase(locale) : list;
|
||||
|
|
|
|||
|
|
@ -27,6 +27,9 @@ import io.github.sspanak.tt9.util.TextTools;
|
|||
import io.github.sspanak.tt9.util.chars.Characters;
|
||||
|
||||
public class SuggestionsBar {
|
||||
public static final String SHOW_SPECIAL_CHARS_SUGGESTION = "(@#*…)";
|
||||
public static final String SHOW_CURRENCIES_SUGGESTION = "($€£…)";
|
||||
|
||||
private final String SHOW_MORE_SUGGESTION = "(...)";
|
||||
private final String STEM_SUFFIX = "… +";
|
||||
private final String STEM_VARIATION_PREFIX = "…";
|
||||
|
|
@ -140,15 +143,16 @@ public class SuggestionsBar {
|
|||
|
||||
@NonNull
|
||||
public String get(int id) {
|
||||
if (id < 0 || id >= visibleSuggestions.size()) {
|
||||
return "";
|
||||
String suggestion = getRaw(id);
|
||||
|
||||
// show more...
|
||||
if (suggestion.equals(SHOW_MORE_SUGGESTION) || suggestion.equals(SHOW_CURRENCIES_SUGGESTION) || suggestion.equals(SHOW_SPECIAL_CHARS_SUGGESTION)) {
|
||||
return Characters.PLACEHOLDER;
|
||||
}
|
||||
|
||||
String suggestion = visibleSuggestions.get(id);
|
||||
|
||||
// single char
|
||||
if (suggestion.equals(SHOW_MORE_SUGGESTION)) return Characters.COMBINING_ZERO_BASE;
|
||||
if (suggestion.equals(Characters.NEW_LINE)) return "\n";
|
||||
if (suggestion.equals(Characters.TAB)) return "\t";
|
||||
|
||||
suggestion = suggestion.replace(Characters.ZWNJ_GRAPHIC, Characters.ZWNJ);
|
||||
suggestion = suggestion.replace(Characters.ZWJ_GRAPHIC, Characters.ZWJ);
|
||||
|
|
@ -161,7 +165,7 @@ public class SuggestionsBar {
|
|||
|
||||
// "..." prefix
|
||||
int startIndex = 0;
|
||||
String[] prefixes = {STEM_VARIATION_PREFIX, STEM_PUNCTUATION_VARIATION_PREFIX, Characters.COMBINING_ZERO_BASE};
|
||||
String[] prefixes = {STEM_VARIATION_PREFIX, STEM_PUNCTUATION_VARIATION_PREFIX, Characters.PLACEHOLDER};
|
||||
for (String prefix : prefixes) {
|
||||
int prefixIndex = suggestion.indexOf(prefix) + 1;
|
||||
if (prefixIndex < endIndex) { // do not match the prefix chars when they are part of STEM_SUFFIX
|
||||
|
|
@ -177,6 +181,16 @@ public class SuggestionsBar {
|
|||
}
|
||||
|
||||
|
||||
@NonNull
|
||||
public String getRaw(int id) {
|
||||
if (id < 0 || id >= visibleSuggestions.size()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return visibleSuggestions.get(id);
|
||||
}
|
||||
|
||||
|
||||
public void setRTL(boolean yes) {
|
||||
if (mView != null) {
|
||||
mView.setLayoutDirection(yes ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR);
|
||||
|
|
@ -310,11 +324,12 @@ public class SuggestionsBar {
|
|||
|
||||
private String formatUnreadableSuggestion(String suggestion) {
|
||||
if (TextTools.isCombining(suggestion)) {
|
||||
return Characters.COMBINING_ZERO_BASE + suggestion;
|
||||
return Characters.PLACEHOLDER + suggestion;
|
||||
}
|
||||
|
||||
return switch (suggestion) {
|
||||
case "\n" -> Characters.NEW_LINE;
|
||||
case "\t" -> Characters.TAB;
|
||||
case Characters.ZWJ -> Characters.ZWJ_GRAPHIC;
|
||||
case Characters.ZWNJ -> Characters.ZWNJ_GRAPHIC;
|
||||
default -> suggestion;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
package io.github.sspanak.tt9.util.chars;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
|
|
@ -7,51 +9,79 @@ import io.github.sspanak.tt9.languages.Language;
|
|||
import io.github.sspanak.tt9.languages.LanguageKind;
|
||||
|
||||
public class Characters extends Emoji {
|
||||
public static final String COMBINING_ZERO_BASE = "◌";
|
||||
public static final String PLACEHOLDER = "◌";
|
||||
public static final String IDEOGRAPHIC_SPACE = " ";
|
||||
public static final String TAB = "↹";
|
||||
|
||||
final public static ArrayList<String> Currency = new ArrayList<>(Arrays.asList(
|
||||
|
||||
public static final ArrayList<String> Currency = new ArrayList<>(Arrays.asList(
|
||||
"$", "€", "₿", "¢", "¤", "₱", "¥", "£"
|
||||
));
|
||||
|
||||
|
||||
/**
|
||||
* The English punctuation filtered to contain only valid email characters.
|
||||
*/
|
||||
final public static ArrayList<ArrayList<String>> Email = new ArrayList<>(Arrays.asList(
|
||||
public static final ArrayList<ArrayList<String>> Email = new ArrayList<>(Arrays.asList(
|
||||
new ArrayList<>(Arrays.asList("@", "_", " ", "#", "%", "{", "}", "|", "^", "/", "=", "*", "+")),
|
||||
new ArrayList<>(Arrays.asList(".", "-", "&", "~", "`", "'", "!", "?"))
|
||||
));
|
||||
|
||||
|
||||
/**
|
||||
* Special characters for phone number fields, including both characters for conveniently typing a phone number: "()-",
|
||||
* as well as command characters such as "," = "slight pause" and ";" = "wait" used in Japan and some other countries.
|
||||
*/
|
||||
final public static ArrayList<ArrayList<String>> Phone = new ArrayList<>(Arrays.asList(
|
||||
public static final ArrayList<ArrayList<String>> Phone = new ArrayList<>(Arrays.asList(
|
||||
new ArrayList<>(Arrays.asList("+", " ")),
|
||||
new ArrayList<>(Arrays.asList("-", "(", ")", ".", ";", ","))
|
||||
));
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Commonly used special and math characters.
|
||||
*/
|
||||
public static final ArrayList<String> Special = new ArrayList<>(Arrays.asList(
|
||||
"@", "_", "#", "%", "[", "]", "{", "}", "§", "|", "^", "<", ">", "\\", "/", "=", "*", "+"
|
||||
));
|
||||
|
||||
|
||||
/**
|
||||
* Returns a language-specific currency list.
|
||||
*/
|
||||
public static ArrayList<String> getCurrencies(@Nullable Language language) {
|
||||
ArrayList<String> chars = new ArrayList<>(Characters.Currency);
|
||||
if (language != null && !language.getCurrency().isEmpty()) {
|
||||
chars.add(2, language.getCurrency());
|
||||
}
|
||||
return chars;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the language-specific space character.
|
||||
*/
|
||||
public static String getSpace(Language language) {
|
||||
public static String getSpace(@Nullable Language language) {
|
||||
return LanguageKind.isChinese(language) || LanguageKind.isJapanese(language) ? IDEOGRAPHIC_SPACE : " ";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Standard special characters with automatic Space selection based on the language. Useful for
|
||||
* text fields.
|
||||
* Whitespace characters with language-specific Space. Useful for text fields.
|
||||
*/
|
||||
public static ArrayList<String> getSpecial(Language language) {
|
||||
public static ArrayList<String> getWhitespaces(@Nullable Language language) {
|
||||
return new ArrayList<>(Arrays.asList(
|
||||
getSpace(language), "\n", "@", "_", "#", "%", "[", "]", "{", "}", "§", "|", "^", "<", ">", "\\", "/", "=", "*", "+"
|
||||
getSpace(language), "\n", "\t"
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Special characters for all kinds of numeric fields: integer, decimal with +/- included as necessary.
|
||||
* Special and punctuation characters for all kinds of numeric fields: integer, decimal with +/-,
|
||||
* included as necessary.
|
||||
*/
|
||||
public static ArrayList<ArrayList<String>> getSpecialForNumbers(boolean decimal, boolean signed) {
|
||||
public static ArrayList<ArrayList<String>> getAllForDecimal(boolean decimal, boolean signed) {
|
||||
ArrayList<ArrayList<String>> keyCharacters = new ArrayList<>();
|
||||
keyCharacters.add(signed ? new ArrayList<>(Arrays.asList("-", "+")) : new ArrayList<>());
|
||||
if (decimal) {
|
||||
|
|
@ -60,14 +90,18 @@ public class Characters extends Emoji {
|
|||
return keyCharacters;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static boolean isCurrency(Language language, String c) {
|
||||
return Currency.contains(c) || (language != null && language.getCurrency().equals(c));
|
||||
}
|
||||
|
||||
|
||||
public static boolean isFathatan(char ch) {
|
||||
return ch == 0x064B;
|
||||
}
|
||||
|
||||
|
||||
public static boolean isOm(char ch) {
|
||||
return
|
||||
ch == 0x0950 // Devanagari
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue