separated the Language class into smaller files and reorganized the languages package
This commit is contained in:
parent
25657d12a8
commit
58f5123bdb
61 changed files with 456 additions and 387 deletions
|
|
@ -10,9 +10,9 @@ import java.util.ArrayList;
|
|||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
|
||||
import io.github.sspanak.tt9.ConsumerCompat;
|
||||
import io.github.sspanak.tt9.Logger;
|
||||
import io.github.sspanak.tt9.Timer;
|
||||
import io.github.sspanak.tt9.util.ConsumerCompat;
|
||||
import io.github.sspanak.tt9.util.Logger;
|
||||
import io.github.sspanak.tt9.util.Timer;
|
||||
import io.github.sspanak.tt9.db.entities.WordBatch;
|
||||
import io.github.sspanak.tt9.db.entities.WordFile;
|
||||
import io.github.sspanak.tt9.db.exceptions.DictionaryImportAbortedException;
|
||||
|
|
@ -23,8 +23,8 @@ import io.github.sspanak.tt9.db.sqlite.SQLiteOpener;
|
|||
import io.github.sspanak.tt9.db.sqlite.Tables;
|
||||
import io.github.sspanak.tt9.ime.TraditionalT9;
|
||||
import io.github.sspanak.tt9.languages.EmojiLanguage;
|
||||
import io.github.sspanak.tt9.languages.InvalidLanguageCharactersException;
|
||||
import io.github.sspanak.tt9.languages.InvalidLanguageException;
|
||||
import io.github.sspanak.tt9.languages.exceptions.InvalidLanguageCharactersException;
|
||||
import io.github.sspanak.tt9.languages.exceptions.InvalidLanguageException;
|
||||
import io.github.sspanak.tt9.languages.Language;
|
||||
import io.github.sspanak.tt9.preferences.SettingsStore;
|
||||
import io.github.sspanak.tt9.ui.DictionaryLoadingBar;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import android.app.Activity;
|
|||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
|
||||
import io.github.sspanak.tt9.Logger;
|
||||
import io.github.sspanak.tt9.util.Logger;
|
||||
|
||||
public class LegacyDb extends SQLiteOpenHelper {
|
||||
private final String LOG_TAG = getClass().getSimpleName();
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@ package io.github.sspanak.tt9.db;
|
|||
|
||||
import java.util.HashMap;
|
||||
|
||||
import io.github.sspanak.tt9.Logger;
|
||||
import io.github.sspanak.tt9.util.Logger;
|
||||
import io.github.sspanak.tt9.languages.Language;
|
||||
import io.github.sspanak.tt9.languages.TextTools;
|
||||
import io.github.sspanak.tt9.util.TextTools;
|
||||
import io.github.sspanak.tt9.preferences.SettingsStore;
|
||||
|
||||
public class SlowQueryStats {
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ import androidx.annotation.NonNull;
|
|||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import io.github.sspanak.tt9.Logger;
|
||||
import io.github.sspanak.tt9.Timer;
|
||||
import io.github.sspanak.tt9.util.Logger;
|
||||
import io.github.sspanak.tt9.util.Timer;
|
||||
import io.github.sspanak.tt9.db.entities.Word;
|
||||
import io.github.sspanak.tt9.db.entities.WordList;
|
||||
import io.github.sspanak.tt9.db.sqlite.DeleteOps;
|
||||
|
|
@ -18,7 +18,8 @@ import io.github.sspanak.tt9.db.sqlite.UpdateOps;
|
|||
import io.github.sspanak.tt9.ime.TraditionalT9;
|
||||
import io.github.sspanak.tt9.languages.EmojiLanguage;
|
||||
import io.github.sspanak.tt9.languages.Language;
|
||||
import io.github.sspanak.tt9.languages.Text;
|
||||
import io.github.sspanak.tt9.languages.NullLanguage;
|
||||
import io.github.sspanak.tt9.util.Text;
|
||||
import io.github.sspanak.tt9.preferences.SettingsStore;
|
||||
import io.github.sspanak.tt9.ui.dialogs.AddWordDialog;
|
||||
|
||||
|
|
@ -68,7 +69,7 @@ public class WordStore {
|
|||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
if (language == null) {
|
||||
if (language == null || language instanceof NullLanguage) {
|
||||
Logger.w(LOG_TAG, "Attempting to get words for NULL language.");
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
|
@ -93,12 +94,12 @@ public class WordStore {
|
|||
|
||||
|
||||
@NonNull public ArrayList<String> getSimilarCustom(Language language, String wordFilter) {
|
||||
return language != null && checkOrNotify() ? readOps.getCustomWords(sqlite.getDb(), language, wordFilter) : new ArrayList<>();
|
||||
return language != null && !(language instanceof NullLanguage) && checkOrNotify() ? readOps.getCustomWords(sqlite.getDb(), language, wordFilter) : new ArrayList<>();
|
||||
}
|
||||
|
||||
|
||||
@NonNull public String getLanguageFileHash(Language language) {
|
||||
return language != null && checkOrNotify() ? readOps.getLanguageFileHash(sqlite.getDb(), language.getId()) : "";
|
||||
return language != null && !(language instanceof NullLanguage) && checkOrNotify() ? readOps.getLanguageFileHash(sqlite.getDb(), language.getId()) : "";
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -126,7 +127,7 @@ public class WordStore {
|
|||
|
||||
|
||||
public void removeCustomWord(Language language, String word) {
|
||||
if (language == null || !checkOrNotify()) {
|
||||
if (language == null || language instanceof NullLanguage || !checkOrNotify()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -148,7 +149,7 @@ public class WordStore {
|
|||
return AddWordDialog.CODE_BLANK_WORD;
|
||||
}
|
||||
|
||||
if (language == null) {
|
||||
if (language == null || language instanceof NullLanguage) {
|
||||
return AddWordDialog.CODE_INVALID_LANGUAGE;
|
||||
}
|
||||
|
||||
|
|
@ -191,7 +192,7 @@ public class WordStore {
|
|||
|
||||
|
||||
public void makeTopWord(@NonNull Language language, @NonNull String word, @NonNull String sequence) {
|
||||
if (!checkOrNotify() || word.isEmpty() || sequence.isEmpty()) {
|
||||
if (!checkOrNotify() || word.isEmpty() || sequence.isEmpty() || language instanceof NullLanguage) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -258,7 +259,7 @@ public class WordStore {
|
|||
|
||||
|
||||
public void scheduleNormalization(Language language) {
|
||||
if (language != null && checkOrNotify()) {
|
||||
if (language != null && !(language instanceof NullLanguage) && checkOrNotify()) {
|
||||
UpdateOps.scheduleNormalization(sqlite.getDb(), language);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import androidx.annotation.NonNull;
|
|||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import io.github.sspanak.tt9.ConsumerCompat;
|
||||
import io.github.sspanak.tt9.util.ConsumerCompat;
|
||||
import io.github.sspanak.tt9.languages.Language;
|
||||
|
||||
public class WordStoreAsync {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import androidx.annotation.NonNull;
|
|||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import io.github.sspanak.tt9.languages.InvalidLanguageCharactersException;
|
||||
import io.github.sspanak.tt9.languages.exceptions.InvalidLanguageCharactersException;
|
||||
import io.github.sspanak.tt9.languages.Language;
|
||||
|
||||
public class WordBatch {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import java.io.IOException;
|
|||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import io.github.sspanak.tt9.Logger;
|
||||
import io.github.sspanak.tt9.util.Logger;
|
||||
|
||||
public class WordFile {
|
||||
private static final String LOG_TAG = WordFile.class.getSimpleName();
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ import java.io.FileOutputStream;
|
|||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import io.github.sspanak.tt9.ConsumerCompat;
|
||||
import io.github.sspanak.tt9.util.ConsumerCompat;
|
||||
|
||||
public abstract class AbstractExporter {
|
||||
final protected static String FILE_EXTENSION = ".csv";
|
||||
|
|
|
|||
|
|
@ -7,9 +7,9 @@ import androidx.annotation.NonNull;
|
|||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import io.github.sspanak.tt9.Logger;
|
||||
import io.github.sspanak.tt9.util.Logger;
|
||||
import io.github.sspanak.tt9.R;
|
||||
import io.github.sspanak.tt9.Timer;
|
||||
import io.github.sspanak.tt9.util.Timer;
|
||||
import io.github.sspanak.tt9.db.sqlite.ReadOps;
|
||||
import io.github.sspanak.tt9.db.sqlite.SQLiteOpener;
|
||||
import io.github.sspanak.tt9.languages.Language;
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import androidx.annotation.NonNull;
|
|||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import io.github.sspanak.tt9.Logger;
|
||||
import io.github.sspanak.tt9.util.Logger;
|
||||
import io.github.sspanak.tt9.db.SlowQueryStats;
|
||||
import io.github.sspanak.tt9.db.entities.WordList;
|
||||
import io.github.sspanak.tt9.db.entities.WordPositionsStringBuilder;
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import android.database.sqlite.SQLiteOpenHelper;
|
|||
import java.util.ArrayList;
|
||||
|
||||
import io.github.sspanak.tt9.BuildConfig;
|
||||
import io.github.sspanak.tt9.Logger;
|
||||
import io.github.sspanak.tt9.util.Logger;
|
||||
import io.github.sspanak.tt9.languages.EmojiLanguage;
|
||||
import io.github.sspanak.tt9.languages.Language;
|
||||
import io.github.sspanak.tt9.languages.LanguageCollection;
|
||||
|
|
|
|||
|
|
@ -5,9 +5,9 @@ import android.database.sqlite.SQLiteStatement;
|
|||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import io.github.sspanak.tt9.Logger;
|
||||
import io.github.sspanak.tt9.util.Logger;
|
||||
import io.github.sspanak.tt9.languages.Language;
|
||||
import io.github.sspanak.tt9.languages.Text;
|
||||
import io.github.sspanak.tt9.util.Text;
|
||||
import io.github.sspanak.tt9.preferences.SettingsStore;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ import android.view.View;
|
|||
import android.view.inputmethod.EditorInfo;
|
||||
import android.view.inputmethod.InputConnection;
|
||||
|
||||
import io.github.sspanak.tt9.Logger;
|
||||
import io.github.sspanak.tt9.Timer;
|
||||
import io.github.sspanak.tt9.util.Logger;
|
||||
import io.github.sspanak.tt9.util.Timer;
|
||||
import io.github.sspanak.tt9.ime.helpers.Key;
|
||||
import io.github.sspanak.tt9.preferences.SettingsStore;
|
||||
import io.github.sspanak.tt9.preferences.screens.debug.ItemInputHandlingMode;
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ import androidx.annotation.NonNull;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import io.github.sspanak.tt9.Logger;
|
||||
import io.github.sspanak.tt9.R;
|
||||
import io.github.sspanak.tt9.db.DictionaryLoader;
|
||||
import io.github.sspanak.tt9.db.WordStoreAsync;
|
||||
|
|
@ -30,7 +29,7 @@ import io.github.sspanak.tt9.ime.modes.ModePassthrough;
|
|||
import io.github.sspanak.tt9.ime.modes.ModePredictive;
|
||||
import io.github.sspanak.tt9.languages.Language;
|
||||
import io.github.sspanak.tt9.languages.LanguageCollection;
|
||||
import io.github.sspanak.tt9.languages.Text;
|
||||
import io.github.sspanak.tt9.languages.LanguageKind;
|
||||
import io.github.sspanak.tt9.preferences.SettingsStore;
|
||||
import io.github.sspanak.tt9.preferences.helpers.Hotkeys;
|
||||
import io.github.sspanak.tt9.ui.PopupDialogActivity;
|
||||
|
|
@ -38,6 +37,8 @@ import io.github.sspanak.tt9.ui.UI;
|
|||
import io.github.sspanak.tt9.ui.main.MainView;
|
||||
import io.github.sspanak.tt9.ui.tray.StatusBar;
|
||||
import io.github.sspanak.tt9.ui.tray.SuggestionsBar;
|
||||
import io.github.sspanak.tt9.util.Logger;
|
||||
import io.github.sspanak.tt9.util.Text;
|
||||
|
||||
public class TraditionalT9 extends KeyPadHandler {
|
||||
private InputConnection currentInputConnection = null;
|
||||
|
|
@ -469,7 +470,7 @@ public class TraditionalT9 extends KeyPadHandler {
|
|||
}
|
||||
|
||||
cancelAutoAccept();
|
||||
backward = systemLanguage.isRTL() != backward;
|
||||
backward = LanguageKind.isRTL(systemLanguage) != backward;
|
||||
suggestionBar.scrollToSuggestion(backward ? -1 : 1);
|
||||
mInputMode.setWordStem(suggestionBar.getCurrentSuggestion(), true);
|
||||
setComposingTextWithHighlightedStem(suggestionBar.getCurrentSuggestion());
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import android.content.Context;
|
|||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import io.github.sspanak.tt9.Logger;
|
||||
import io.github.sspanak.tt9.util.Logger;
|
||||
import io.github.sspanak.tt9.ime.modes.InputMode;
|
||||
import io.github.sspanak.tt9.languages.Language;
|
||||
import io.github.sspanak.tt9.languages.LanguageCollection;
|
||||
|
|
|
|||
|
|
@ -14,10 +14,11 @@ import androidx.annotation.NonNull;
|
|||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import io.github.sspanak.tt9.Logger;
|
||||
import io.github.sspanak.tt9.ime.modes.InputMode;
|
||||
import io.github.sspanak.tt9.languages.Language;
|
||||
import io.github.sspanak.tt9.languages.Text;
|
||||
import io.github.sspanak.tt9.languages.LanguageKind;
|
||||
import io.github.sspanak.tt9.util.Logger;
|
||||
import io.github.sspanak.tt9.util.Text;
|
||||
|
||||
public class TextField {
|
||||
public static final int IME_ACTION_ENTER = EditorInfo.IME_MASK_ACTION + 1;
|
||||
|
|
@ -191,8 +192,8 @@ public class TextField {
|
|||
boolean keepQuote = false;
|
||||
if (language != null) {
|
||||
// Hebrew and Ukrainian use the respective special characters as letters
|
||||
keepApostrophe = language.isHebrew() || language.isUkrainian();
|
||||
keepQuote = language.isHebrew();
|
||||
keepApostrophe = LanguageKind.isHebrew(language) || LanguageKind.isUkrainian(language);
|
||||
keepQuote = LanguageKind.isHebrew(language);
|
||||
}
|
||||
|
||||
return before.subStringEndingWord(keepApostrophe, keepQuote) + after.subStringStartingWord(keepApostrophe, keepQuote);
|
||||
|
|
|
|||
|
|
@ -4,10 +4,11 @@ import androidx.annotation.NonNull;
|
|||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import io.github.sspanak.tt9.Logger;
|
||||
import io.github.sspanak.tt9.util.Logger;
|
||||
import io.github.sspanak.tt9.ime.helpers.InputType;
|
||||
import io.github.sspanak.tt9.ime.helpers.TextField;
|
||||
import io.github.sspanak.tt9.languages.Language;
|
||||
import io.github.sspanak.tt9.languages.NaturalLanguage;
|
||||
import io.github.sspanak.tt9.preferences.SettingsStore;
|
||||
|
||||
abstract public class InputMode {
|
||||
|
|
@ -133,7 +134,7 @@ abstract public class InputMode {
|
|||
return true;
|
||||
}
|
||||
|
||||
if (!language.hasUpperCase() || digitSequence.startsWith(Language.PUNCTUATION_KEY) || digitSequence.startsWith(Language.SPECIAL_CHARS_KEY)) {
|
||||
if (!language.hasUpperCase() || digitSequence.startsWith(NaturalLanguage.PUNCTUATION_KEY) || digitSequence.startsWith(NaturalLanguage.SPECIAL_CHARS_KEY)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,8 +7,9 @@ import java.util.Arrays;
|
|||
import java.util.Collections;
|
||||
|
||||
import io.github.sspanak.tt9.ime.helpers.InputType;
|
||||
import io.github.sspanak.tt9.languages.Characters;
|
||||
import io.github.sspanak.tt9.util.Characters;
|
||||
import io.github.sspanak.tt9.languages.Language;
|
||||
import io.github.sspanak.tt9.languages.NaturalLanguage;
|
||||
|
||||
public class Mode123 extends ModePassthrough {
|
||||
@Override public int getId() { return MODE_123; }
|
||||
|
|
@ -82,7 +83,7 @@ public class Mode123 extends ModePassthrough {
|
|||
}
|
||||
|
||||
@Override protected boolean nextSpecialCharacters() {
|
||||
return digitSequence.equals(Language.SPECIAL_CHARS_KEY) && super.nextSpecialCharacters();
|
||||
return digitSequence.equals(NaturalLanguage.SPECIAL_CHARS_KEY) && super.nextSpecialCharacters();
|
||||
}
|
||||
|
||||
@Override public boolean onNumber(int number, boolean hold, int repeat) {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ package io.github.sspanak.tt9.ime.modes;
|
|||
import androidx.annotation.NonNull;
|
||||
|
||||
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.SettingsStore;
|
||||
|
||||
public class ModeABC extends InputMode {
|
||||
|
|
@ -61,7 +63,7 @@ public class ModeABC extends InputMode {
|
|||
|
||||
@Override
|
||||
protected boolean nextSpecialCharacters() {
|
||||
if (digitSequence.equals(Language.SPECIAL_CHARS_KEY) && super.nextSpecialCharacters()) {
|
||||
if (digitSequence.equals(NaturalLanguage.SPECIAL_CHARS_KEY) && super.nextSpecialCharacters()) {
|
||||
suggestions.add(language.getKeyNumber(digitSequence.charAt(0) - '0'));
|
||||
return true;
|
||||
}
|
||||
|
|
@ -102,7 +104,7 @@ public class ModeABC extends InputMode {
|
|||
}
|
||||
|
||||
String langCode = "";
|
||||
if (language.isLatinBased() || language.isCyrillic()) {
|
||||
if (LanguageKind.isLatinBased(language) || LanguageKind.isCyrillic(language)) {
|
||||
// There are many languages written using the same alphabet, so if the user has enabled multiple,
|
||||
// make it clear which one is it, by appending the country code to "ABC" or "АБВ".
|
||||
langCode = language.getLocale().getCountry();
|
||||
|
|
@ -110,7 +112,7 @@ public class ModeABC extends InputMode {
|
|||
langCode = langCode.isEmpty() ? language.getName() : langCode;
|
||||
langCode = " / " + langCode;
|
||||
}
|
||||
String modeString = language.getAbcString() + langCode.toUpperCase();
|
||||
String modeString = language.getAbcString() + langCode.toUpperCase();
|
||||
|
||||
return (textCase == CASE_LOWER) ? modeString.toLowerCase(language.getLocale()) : modeString.toUpperCase(language.getLocale());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import androidx.annotation.NonNull;
|
|||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import io.github.sspanak.tt9.Logger;
|
||||
import io.github.sspanak.tt9.db.WordStoreAsync;
|
||||
import io.github.sspanak.tt9.ime.helpers.InputType;
|
||||
import io.github.sspanak.tt9.ime.helpers.TextField;
|
||||
|
|
@ -13,8 +12,11 @@ import io.github.sspanak.tt9.ime.modes.helpers.AutoTextCase;
|
|||
import io.github.sspanak.tt9.ime.modes.helpers.Predictions;
|
||||
import io.github.sspanak.tt9.languages.EmojiLanguage;
|
||||
import io.github.sspanak.tt9.languages.Language;
|
||||
import io.github.sspanak.tt9.languages.Text;
|
||||
import io.github.sspanak.tt9.languages.LanguageKind;
|
||||
import io.github.sspanak.tt9.languages.NaturalLanguage;
|
||||
import io.github.sspanak.tt9.preferences.SettingsStore;
|
||||
import io.github.sspanak.tt9.util.Logger;
|
||||
import io.github.sspanak.tt9.util.Text;
|
||||
|
||||
public class ModePredictive extends InputMode {
|
||||
private final String LOG_TAG = getClass().getSimpleName();
|
||||
|
|
@ -91,7 +93,7 @@ public class ModePredictive extends InputMode {
|
|||
digitSequence = EmojiLanguage.validateEmojiSequence(digitSequence, number);
|
||||
disablePredictions = false;
|
||||
|
||||
if (digitSequence.equals(Language.PREFERRED_CHAR_SEQUENCE)) {
|
||||
if (digitSequence.equals(NaturalLanguage.PREFERRED_CHAR_SEQUENCE)) {
|
||||
autoAcceptTimeout = 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -248,7 +250,7 @@ public class ModePredictive extends InputMode {
|
|||
* options for the current digitSequence.
|
||||
*/
|
||||
private boolean loadStaticSuggestions(Runnable onLoad) {
|
||||
if (digitSequence.equals(Language.PUNCTUATION_KEY) || digitSequence.equals(Language.SPECIAL_CHARS_KEY)) {
|
||||
if (digitSequence.equals(NaturalLanguage.PUNCTUATION_KEY) || digitSequence.equals(NaturalLanguage.SPECIAL_CHARS_KEY)) {
|
||||
super.loadSpecialCharacters(language);
|
||||
onLoad.run();
|
||||
return true;
|
||||
|
|
@ -257,7 +259,7 @@ public class ModePredictive extends InputMode {
|
|||
suggestions.addAll(new EmojiLanguage().getKeyCharacters(digitSequence.charAt(0) - '0', digitSequence.length() - 2));
|
||||
onLoad.run();
|
||||
return true;
|
||||
} else if (digitSequence.startsWith(Language.PREFERRED_CHAR_SEQUENCE)) {
|
||||
} else if (digitSequence.startsWith(NaturalLanguage.PREFERRED_CHAR_SEQUENCE)) {
|
||||
suggestions.clear();
|
||||
suggestions.add(settings.getDoubleZeroChar());
|
||||
onLoad.run();
|
||||
|
|
@ -313,7 +315,7 @@ public class ModePredictive extends InputMode {
|
|||
|
||||
// emoji and punctuation are not in the database, so there is no point in
|
||||
// running queries that would update nothing
|
||||
if (!sequence.startsWith(Language.PUNCTUATION_KEY) && !sequence.startsWith(Language.SPECIAL_CHARS_KEY)) {
|
||||
if (!sequence.startsWith(NaturalLanguage.PUNCTUATION_KEY) && !sequence.startsWith(NaturalLanguage.SPECIAL_CHARS_KEY)) {
|
||||
WordStoreAsync.makeTopWord(language, currentWord, sequence);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
|
@ -340,7 +342,7 @@ public class ModePredictive extends InputMode {
|
|||
|
||||
@Override
|
||||
protected boolean nextSpecialCharacters() {
|
||||
return digitSequence.equals(Language.SPECIAL_CHARS_KEY) && super.nextSpecialCharacters();
|
||||
return digitSequence.equals(NaturalLanguage.SPECIAL_CHARS_KEY) && super.nextSpecialCharacters();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -379,22 +381,22 @@ public class ModePredictive extends InputMode {
|
|||
}
|
||||
|
||||
// special characters always break words
|
||||
if (autoAcceptTimeout == 0 && !digitSequence.startsWith(Language.SPECIAL_CHARS_KEY)) {
|
||||
if (autoAcceptTimeout == 0 && !digitSequence.startsWith(NaturalLanguage.SPECIAL_CHARS_KEY)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// allow apostrophes in the middle or at the end of Hebrew and Ukrainian words
|
||||
if (language.isHebrew() || language.isUkrainian()) {
|
||||
if (LanguageKind.isHebrew(language) || LanguageKind.isUkrainian(language)) {
|
||||
return
|
||||
predictions.noDbWords()
|
||||
&& digitSequence.equals(Language.PUNCTUATION_KEY);
|
||||
&& digitSequence.equals(NaturalLanguage.PUNCTUATION_KEY);
|
||||
}
|
||||
|
||||
// punctuation breaks words, unless there are database matches ('s, qu', по-, etc...)
|
||||
return
|
||||
!digitSequence.isEmpty()
|
||||
&& predictions.noDbWords()
|
||||
&& digitSequence.contains(Language.PUNCTUATION_KEY)
|
||||
&& digitSequence.contains(NaturalLanguage.PUNCTUATION_KEY)
|
||||
&& !digitSequence.startsWith(EmojiLanguage.EMOJI_SEQUENCE)
|
||||
&& Text.containsOtherThan1(digitSequence);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ package io.github.sspanak.tt9.ime.modes.helpers;
|
|||
|
||||
import io.github.sspanak.tt9.ime.helpers.InputType;
|
||||
import io.github.sspanak.tt9.ime.helpers.TextField;
|
||||
import io.github.sspanak.tt9.languages.Text;
|
||||
import io.github.sspanak.tt9.util.Text;
|
||||
import io.github.sspanak.tt9.preferences.SettingsStore;
|
||||
|
||||
public class AutoSpace {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
package io.github.sspanak.tt9.ime.modes.helpers;
|
||||
|
||||
import io.github.sspanak.tt9.languages.Text;
|
||||
import io.github.sspanak.tt9.util.Text;
|
||||
import io.github.sspanak.tt9.ime.modes.InputMode;
|
||||
import io.github.sspanak.tt9.preferences.SettingsStore;
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,9 @@ import androidx.annotation.NonNull;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Locale;
|
||||
|
||||
import io.github.sspanak.tt9.util.Characters;
|
||||
import io.github.sspanak.tt9.util.TextTools;
|
||||
|
||||
public class EmojiLanguage extends Language {
|
||||
final public static String EMOJI_SEQUENCE = "11";
|
||||
final private static int CUSTOM_EMOJI_KEY = 3;
|
||||
|
|
@ -17,14 +20,21 @@ public class EmojiLanguage extends Language {
|
|||
name = "Emoji";
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getDigitSequenceForWord(String word) {
|
||||
return TextTools.isGraphic(word) ? CUSTOM_EMOJI_SEQUENCE : null;
|
||||
return TextTools.isGraphic(word) ? CUSTOM_EMOJI_SEQUENCE : "";
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ArrayList<String> getKeyCharacters(int key, int characterGroup) {
|
||||
return key == 1 && characterGroup >= 0 ? Characters.getEmoji(characterGroup) : new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArrayList<String> getKeyCharacters(int key, int characterGroup) {
|
||||
return key == 1 && characterGroup >= 0 ? new ArrayList<>(Characters.getEmoji(characterGroup)) : super.getKeyCharacters(key, characterGroup);
|
||||
public boolean isValidWord(String word) {
|
||||
return TextTools.isGraphic(word);
|
||||
}
|
||||
|
||||
public static String validateEmojiSequence(@NonNull String sequence, int next) {
|
||||
|
|
|
|||
|
|
@ -3,303 +3,73 @@ package io.github.sspanak.tt9.languages;
|
|||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
|
||||
import io.github.sspanak.tt9.languages.exceptions.InvalidLanguageCharactersException;
|
||||
|
||||
public class Language implements Comparable<Language> {
|
||||
final public static String SPECIAL_CHARS_KEY = "0";
|
||||
final public static String PUNCTUATION_KEY = "1";
|
||||
final public static String PREFERRED_CHAR_SEQUENCE = "00";
|
||||
|
||||
abstract public class Language {
|
||||
protected int id;
|
||||
protected String name;
|
||||
protected Locale locale;
|
||||
protected String dictionaryFile;
|
||||
protected boolean hasUpperCase = true;
|
||||
protected String abcString;
|
||||
protected final ArrayList<ArrayList<String>> layout = new ArrayList<>();
|
||||
private final HashMap<Character, String> characterKeyMap = new HashMap<>();
|
||||
protected String dictionaryFile;
|
||||
protected Locale locale = Locale.ROOT;
|
||||
protected String name;
|
||||
protected boolean hasUpperCase = true;
|
||||
|
||||
|
||||
public static Language fromDefinition(LanguageDefinition definition) throws Exception {
|
||||
if (definition.dictionaryFile.isEmpty()) {
|
||||
throw new Exception("Invalid definition. Dictionary file must be set.");
|
||||
}
|
||||
|
||||
if (definition.locale.isEmpty()) {
|
||||
throw new Exception("Invalid definition. Locale cannot be empty.");
|
||||
}
|
||||
|
||||
Locale definitionLocale;
|
||||
if (definition.locale.equals("en")) {
|
||||
definitionLocale = Locale.ENGLISH;
|
||||
} else {
|
||||
String[] parts = definition.locale.split("-", 2);
|
||||
if (parts.length == 2) {
|
||||
definitionLocale = new Locale(parts[0], parts[1]);
|
||||
} else if (parts.length == 1) {
|
||||
definitionLocale = new Locale(parts[0]);
|
||||
} else {
|
||||
throw new Exception("Unrecognized locale format: '" + definition.locale + "'.");
|
||||
}
|
||||
}
|
||||
|
||||
Language lang = new Language();
|
||||
lang.abcString = definition.abcString.isEmpty() ? null : definition.abcString;
|
||||
lang.dictionaryFile = definition.getDictionaryFile();
|
||||
lang.hasUpperCase = definition.hasUpperCase;
|
||||
lang.locale = definitionLocale;
|
||||
lang.name = definition.name.isEmpty() ? lang.name : definition.name;
|
||||
|
||||
for (int key = 0; key <= 9 && key < definition.layout.size(); key++) {
|
||||
lang.layout.add(keyCharsFromDefinition(key, definition.layout.get(key)));
|
||||
}
|
||||
|
||||
return lang;
|
||||
}
|
||||
|
||||
|
||||
private static ArrayList<String> keyCharsFromDefinition(int key, ArrayList<String> definitionChars) {
|
||||
if (key > 1) {
|
||||
return definitionChars;
|
||||
}
|
||||
|
||||
final String specialCharsPlaceholder = "SPECIAL";
|
||||
final String punctuationPlaceholder = "PUNCTUATION";
|
||||
final String arabicStylePlaceholder = punctuationPlaceholder + "_AR";
|
||||
final String germanStylePlaceholder = punctuationPlaceholder + "_DE";
|
||||
final String frenchStylePlaceholder = punctuationPlaceholder + "_FR";
|
||||
|
||||
ArrayList<String> keyChars = new ArrayList<>();
|
||||
for (String defChar : definitionChars) {
|
||||
switch (defChar) {
|
||||
case specialCharsPlaceholder:
|
||||
keyChars.addAll(Characters.Special);
|
||||
break;
|
||||
case punctuationPlaceholder:
|
||||
keyChars.addAll(Characters.PunctuationEnglish);
|
||||
break;
|
||||
case arabicStylePlaceholder:
|
||||
keyChars.addAll(Characters.PunctuationArabic);
|
||||
break;
|
||||
case germanStylePlaceholder:
|
||||
keyChars.addAll(Characters.PunctuationGerman);
|
||||
break;
|
||||
case frenchStylePlaceholder:
|
||||
keyChars.addAll(Characters.PunctuationFrench);
|
||||
break;
|
||||
default:
|
||||
keyChars.add(defChar);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return keyChars;
|
||||
}
|
||||
|
||||
final public int getId() {
|
||||
if (id == 0) {
|
||||
id = generateId();
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
final public Locale getLocale() {
|
||||
return locale;
|
||||
}
|
||||
|
||||
final public String getName() {
|
||||
if (name == null) {
|
||||
name = new Text(this, locale.getDisplayLanguage(locale)).capitalize();
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
final public String getDictionaryFile() {
|
||||
return dictionaryFile;
|
||||
}
|
||||
|
||||
final public String getAbcString() {
|
||||
if (abcString == null) {
|
||||
ArrayList<String> lettersList = getKeyCharacters(2);
|
||||
|
||||
abcString = "";
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < lettersList.size() && i < 3; i++) {
|
||||
sb.append(lettersList.get(i));
|
||||
}
|
||||
abcString = sb.toString();
|
||||
}
|
||||
|
||||
@NonNull public String getAbcString() {
|
||||
return abcString;
|
||||
}
|
||||
|
||||
@NonNull final public String getDictionaryFile() {
|
||||
return dictionaryFile;
|
||||
}
|
||||
|
||||
public boolean hasUpperCase() {
|
||||
return hasUpperCase;
|
||||
@NonNull final public Locale getLocale() {
|
||||
return locale;
|
||||
}
|
||||
|
||||
/**
|
||||
* isLatinBased
|
||||
* Returns "true" when the language is based on the Latin alphabet or "false" otherwise.
|
||||
* Returns the characters that the key would type in ABC or Predictive mode. For example,
|
||||
* the key 2 in English would return A-B-C.
|
||||
* Keys that have special characters assigned, may have more than one group assigned. The specific
|
||||
* group is selected by the characterGroup parameter. By default, group 0 is returned.
|
||||
*/
|
||||
public boolean isLatinBased() {
|
||||
return getKeyCharacters(2).contains("a");
|
||||
}
|
||||
|
||||
public boolean isCyrillic() {
|
||||
return getKeyCharacters(2).contains("а");
|
||||
}
|
||||
|
||||
public boolean isRTL() {
|
||||
return isArabic() || isHebrew();
|
||||
}
|
||||
|
||||
public boolean isGreek() {
|
||||
return getKeyCharacters(2).contains("α");
|
||||
}
|
||||
|
||||
public boolean isArabic() {
|
||||
return getKeyCharacters(3).contains("ا");
|
||||
}
|
||||
|
||||
public boolean isUkrainian() {
|
||||
return getKeyCharacters(3).contains("є");
|
||||
}
|
||||
|
||||
public boolean isHebrew() {
|
||||
return getKeyCharacters(3).contains("א");
|
||||
}
|
||||
|
||||
/* ************ utility ************ */
|
||||
|
||||
/**
|
||||
* generateId
|
||||
* Uses the letters of the Locale to generate an ID for the language.
|
||||
* Each letter is converted to uppercase and used as a 5-bit integer. Then the 5-bits
|
||||
* are packed to form a 10-bit or a 20-bit integer, depending on the Locale length.
|
||||
*
|
||||
* Example (2-letter Locale)
|
||||
* "en"
|
||||
* -> "E" | "N"
|
||||
* -> 5 | 448 (shift the 2nd number by 5 bits, so its bits would not overlap with the 1st one)
|
||||
* -> 543
|
||||
*
|
||||
* Example (4-letter Locale)
|
||||
* "bg-BG"
|
||||
* -> "B" | "G" | "B" | "G"
|
||||
* -> 2 | 224 | 2048 | 229376 (shift each 5-bit number, not overlap with the previous ones)
|
||||
* -> 231650
|
||||
*
|
||||
* Minimum ID: "aa" -> 33
|
||||
* Maximum ID: "zz-ZZ" -> 879450
|
||||
*/
|
||||
private int generateId() {
|
||||
String idString = (locale.getLanguage() + locale.getCountry()).toUpperCase();
|
||||
int idInt = 0;
|
||||
for (int i = 0; i < idString.length(); i++) {
|
||||
idInt |= ((idString.codePointAt(i) & 31) << (i * 5));
|
||||
}
|
||||
|
||||
return idInt;
|
||||
}
|
||||
|
||||
private void generateCharacterKeyMap() {
|
||||
characterKeyMap.clear();
|
||||
for (int digit = 0; digit <= 9; digit++) {
|
||||
for (String keyChar : getKeyCharacters(digit)) {
|
||||
characterKeyMap.put(keyChar.charAt(0), String.valueOf(digit));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ArrayList<String> getKeyCharacters(int key, int characterGroup) {
|
||||
if (key < 0 || key >= layout.size()) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
return chars;
|
||||
}
|
||||
|
||||
public ArrayList<String> getKeyCharacters(int key) {
|
||||
@NonNull abstract public ArrayList<String> getKeyCharacters(int key, int characterGroup);
|
||||
@NonNull public ArrayList<String> getKeyCharacters(int key) {
|
||||
return getKeyCharacters(key, 0);
|
||||
}
|
||||
|
||||
public String getKeyNumber(int key) {
|
||||
if (key > 10 || key < 0) {
|
||||
return null;
|
||||
} else {
|
||||
return isArabic() ? Characters.ArabicNumbers.get(key) : String.valueOf(key);
|
||||
}
|
||||
@NonNull public String getKeyNumber(int key) {
|
||||
return String.valueOf(key);
|
||||
}
|
||||
|
||||
public String getDigitSequenceForWord(String word) throws InvalidLanguageCharactersException {
|
||||
StringBuilder sequence = new StringBuilder();
|
||||
String lowerCaseWord = word.toLowerCase(locale);
|
||||
@NonNull public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
if (characterKeyMap.isEmpty()) {
|
||||
generateCharacterKeyMap();
|
||||
}
|
||||
final public boolean hasUpperCase() {
|
||||
return hasUpperCase;
|
||||
}
|
||||
|
||||
for (int i = 0; i < lowerCaseWord.length(); i++) {
|
||||
char letter = lowerCaseWord.charAt(i);
|
||||
if (!characterKeyMap.containsKey(letter)) {
|
||||
throw new InvalidLanguageCharactersException(this, "Failed generating digit sequence for word: '" + word);
|
||||
}
|
||||
|
||||
sequence.append(characterKeyMap.get(letter));
|
||||
}
|
||||
|
||||
return sequence.toString();
|
||||
@NonNull
|
||||
@Override
|
||||
final public String toString() {
|
||||
return getName();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks whether the given word contains characters outside of the language alphabet.
|
||||
*/
|
||||
public boolean isValidWord(String word) {
|
||||
if (word == null || word.isEmpty() || (word.length() == 1 && Character.isDigit(word.charAt(0)))) {
|
||||
return true;
|
||||
}
|
||||
abstract public boolean isValidWord(String word);
|
||||
|
||||
String lowerCaseWord = word.toLowerCase(locale);
|
||||
if (characterKeyMap.isEmpty()) {
|
||||
generateCharacterKeyMap();
|
||||
}
|
||||
|
||||
for (int i = 0; i < lowerCaseWord.length(); i++) {
|
||||
if (!characterKeyMap.containsKey(lowerCaseWord.charAt(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return getName();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int compareTo(Language other) {
|
||||
String key = getName().equals("Suomi") ? "su" : getLocale().toString();
|
||||
String otherKey = other.getName().equals("Suomi") ? "su" : other.getLocale().toString();
|
||||
return key.compareTo(otherKey);
|
||||
}
|
||||
/**
|
||||
* Converts a word to a sequence of digits based on the language's keyboard layout.
|
||||
* For example: "food" -> "3663"
|
||||
*/
|
||||
@NonNull abstract public String getDigitSequenceForWord(String word) throws InvalidLanguageCharactersException;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,18 +9,18 @@ import java.util.ArrayList;
|
|||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
|
||||
import io.github.sspanak.tt9.Logger;
|
||||
import io.github.sspanak.tt9.util.Logger;
|
||||
import io.github.sspanak.tt9.ime.helpers.SystemSettings;
|
||||
|
||||
public class LanguageCollection {
|
||||
private static LanguageCollection self;
|
||||
|
||||
private final HashMap<Integer, Language> languages = new HashMap<>();
|
||||
private final HashMap<Integer, NaturalLanguage> languages = new HashMap<>();
|
||||
|
||||
private LanguageCollection(Context context) {
|
||||
for (String file : LanguageDefinition.getAllFiles(context.getAssets())) {
|
||||
try {
|
||||
Language lang = Language.fromDefinition(LanguageDefinition.fromFile(context.getAssets(), file));
|
||||
NaturalLanguage lang = NaturalLanguage.fromDefinition(LanguageDefinition.fromFile(context.getAssets(), file));
|
||||
languages.put(lang.getId(), lang);
|
||||
} catch (Exception e) {
|
||||
Logger.e("tt9.LanguageCollection", "Skipping invalid language: '" + file + "'. " + e.getMessage());
|
||||
|
|
@ -38,7 +38,7 @@ public class LanguageCollection {
|
|||
}
|
||||
|
||||
@Nullable
|
||||
public static Language getLanguage(Context context, int langId) {
|
||||
public static NaturalLanguage getLanguage(Context context, int langId) {
|
||||
if (getInstance(context).languages.containsKey(langId)) {
|
||||
return getInstance(context).languages.get(langId);
|
||||
}
|
||||
|
|
@ -53,8 +53,8 @@ public class LanguageCollection {
|
|||
}
|
||||
|
||||
@Nullable
|
||||
public static Language getByLocale(Context context, String locale) {
|
||||
for (Language lang : getInstance(context).languages.values()) {
|
||||
public static NaturalLanguage getByLocale(Context context, String locale) {
|
||||
for (NaturalLanguage lang : getInstance(context).languages.values()) {
|
||||
if (lang.getLocale().toString().equals(locale)) {
|
||||
return lang;
|
||||
}
|
||||
|
|
@ -64,14 +64,13 @@ public class LanguageCollection {
|
|||
}
|
||||
|
||||
public static ArrayList<Language> getAll(Context context, ArrayList<Integer> languageIds, boolean sort) {
|
||||
ArrayList<Language> langList = new ArrayList<>();
|
||||
|
||||
if (languageIds == null) {
|
||||
return langList;
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
ArrayList<NaturalLanguage> langList = new ArrayList<>();
|
||||
for (int languageId : languageIds) {
|
||||
Language lang = getLanguage(context, languageId);
|
||||
NaturalLanguage lang = getLanguage(context, languageId);
|
||||
if (lang != null) {
|
||||
langList.add(lang);
|
||||
}
|
||||
|
|
@ -81,8 +80,7 @@ public class LanguageCollection {
|
|||
Collections.sort(langList);
|
||||
}
|
||||
|
||||
|
||||
return langList;
|
||||
return new ArrayList<>(langList);
|
||||
}
|
||||
|
||||
public static ArrayList<Language> getAll(Context context, ArrayList<Integer> languageIds) {
|
||||
|
|
@ -90,13 +88,13 @@ public class LanguageCollection {
|
|||
}
|
||||
|
||||
public static ArrayList<Language> getAll(Context context, boolean sort) {
|
||||
ArrayList<Language> langList = new ArrayList<>(getInstance(context).languages.values());
|
||||
ArrayList<NaturalLanguage> langList = new ArrayList<>(getInstance(context).languages.values());
|
||||
|
||||
if (sort) {
|
||||
Collections.sort(langList);
|
||||
}
|
||||
|
||||
return langList;
|
||||
return new ArrayList<>(langList);
|
||||
}
|
||||
|
||||
public static ArrayList<Language> getAll(Context context) {
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import java.nio.charset.StandardCharsets;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
import io.github.sspanak.tt9.Logger;
|
||||
import io.github.sspanak.tt9.util.Logger;
|
||||
|
||||
public class LanguageDefinition {
|
||||
private static final String languagesDir = "languages";
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
package io.github.sspanak.tt9.languages;
|
||||
|
||||
public class LanguageKind {
|
||||
public static boolean isArabic(Language language) { return language != null && language.getKeyCharacters(3).contains("ا"); }
|
||||
public static boolean isCyrillic(Language language) { return language != null && language.getKeyCharacters(2).contains("а"); }
|
||||
public static boolean isHebrew(Language language) { return language != null && language.getKeyCharacters(3).contains("א"); }
|
||||
public static boolean isGreek(Language language) { return language != null && language.getKeyCharacters(2).contains("α"); }
|
||||
public static boolean isLatinBased(Language language) { return language != null && language.getKeyCharacters(2).contains("a"); }
|
||||
public static boolean isRTL(Language language) { return isArabic(language) || isHebrew(language); }
|
||||
public static boolean isUkrainian(Language language) { return language != null && language.getKeyCharacters(3).contains("є"); }
|
||||
}
|
||||
|
|
@ -0,0 +1,247 @@
|
|||
package io.github.sspanak.tt9.languages;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
|
||||
import io.github.sspanak.tt9.languages.exceptions.InvalidLanguageCharactersException;
|
||||
import io.github.sspanak.tt9.util.Characters;
|
||||
import io.github.sspanak.tt9.util.Text;
|
||||
|
||||
|
||||
public class NaturalLanguage extends Language implements Comparable<NaturalLanguage> {
|
||||
final public static String SPECIAL_CHARS_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<>();
|
||||
|
||||
|
||||
public static NaturalLanguage fromDefinition(LanguageDefinition definition) throws Exception {
|
||||
if (definition.dictionaryFile.isEmpty()) {
|
||||
throw new Exception("Invalid definition. Dictionary file must be set.");
|
||||
}
|
||||
|
||||
NaturalLanguage lang = new NaturalLanguage();
|
||||
lang.abcString = definition.abcString.isEmpty() ? null : definition.abcString;
|
||||
lang.dictionaryFile = definition.getDictionaryFile();
|
||||
lang.hasUpperCase = definition.hasUpperCase;
|
||||
lang.name = definition.name.isEmpty() ? lang.name : definition.name;
|
||||
lang.setLocale(definition);
|
||||
lang.setLayout(definition);
|
||||
|
||||
return lang;
|
||||
}
|
||||
|
||||
|
||||
private void setLocale(LanguageDefinition definition) throws Exception {
|
||||
if (definition.locale.isEmpty()) {
|
||||
throw new Exception("Invalid definition. Locale cannot be empty.");
|
||||
}
|
||||
|
||||
if (definition.locale.equals("en")) {
|
||||
locale = Locale.ENGLISH;
|
||||
} else {
|
||||
String[] parts = definition.locale.split("-", 2);
|
||||
if (parts.length == 2) {
|
||||
locale = new Locale(parts[0], parts[1]);
|
||||
} else if (parts.length == 1) {
|
||||
locale = new Locale(parts[0]);
|
||||
} else {
|
||||
throw new Exception("Unrecognized locale format: '" + definition.locale + "'.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void setLayout(LanguageDefinition definition) {
|
||||
for (int key = 0; key <= 9 && key < definition.layout.size(); key++) {
|
||||
layout.add(
|
||||
key,
|
||||
key > 1 ? definition.layout.get(key) : generateSpecialChars(definition.layout.get(key))
|
||||
);
|
||||
}
|
||||
|
||||
generateCharacterKeyMap();
|
||||
}
|
||||
|
||||
|
||||
private ArrayList<String> generateSpecialChars(ArrayList<String> definitionChars) {
|
||||
final String SPECIAL_CHARS_PLACEHOLDER = "SPECIAL";
|
||||
final String PUNCTUATION_PLACEHOLDER = "PUNCTUATION";
|
||||
final String ARABIC_PUNCTUATION_STYLE = PUNCTUATION_PLACEHOLDER + "_AR";
|
||||
final String GERMAN_PUNCTUATION_STYLE = PUNCTUATION_PLACEHOLDER + "_DE";
|
||||
final String FRENCH_PUNCTUATION_STYLE = PUNCTUATION_PLACEHOLDER + "_FR";
|
||||
|
||||
ArrayList<String> keyChars = new ArrayList<>();
|
||||
for (String defChar : definitionChars) {
|
||||
switch (defChar) {
|
||||
case SPECIAL_CHARS_PLACEHOLDER:
|
||||
keyChars.addAll(Characters.Special);
|
||||
break;
|
||||
case PUNCTUATION_PLACEHOLDER:
|
||||
keyChars.addAll(Characters.PunctuationEnglish);
|
||||
break;
|
||||
case ARABIC_PUNCTUATION_STYLE:
|
||||
keyChars.addAll(Characters.PunctuationArabic);
|
||||
break;
|
||||
case GERMAN_PUNCTUATION_STYLE:
|
||||
keyChars.addAll(Characters.PunctuationGerman);
|
||||
break;
|
||||
case FRENCH_PUNCTUATION_STYLE:
|
||||
keyChars.addAll(Characters.PunctuationFrench);
|
||||
break;
|
||||
default:
|
||||
keyChars.add(defChar);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return keyChars;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* generateId
|
||||
* Uses the letters of the Locale to generate an ID for the language.
|
||||
* Each letter is converted to uppercase and used as a 5-bit integer. Then the 5-bits
|
||||
* are packed to form a 10-bit or a 20-bit integer, depending on the Locale length.
|
||||
*
|
||||
* Example (2-letter Locale)
|
||||
* "en"
|
||||
* -> "E" | "N"
|
||||
* -> 5 | 448 (shift the 2nd number by 5 bits, so its bits would not overlap with the 1st one)
|
||||
* -> 543
|
||||
*
|
||||
* Example (4-letter Locale)
|
||||
* "bg-BG"
|
||||
* -> "B" | "G" | "B" | "G"
|
||||
* -> 2 | 224 | 2048 | 229376 (shift each 5-bit number, not overlap with the previous ones)
|
||||
* -> 231650
|
||||
*
|
||||
* Minimum ID: "aa" -> 33
|
||||
* Maximum ID: "zz-ZZ" -> 879450
|
||||
*/
|
||||
@Override
|
||||
public int getId() {
|
||||
if (id == 0) {
|
||||
String idString = (locale.getLanguage() + locale.getCountry()).toUpperCase();
|
||||
for (int i = 0; i < idString.length(); i++) {
|
||||
id |= (idString.codePointAt(i) & 31) << (i * 5);
|
||||
}
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getAbcString() {
|
||||
if (abcString == null) {
|
||||
ArrayList<String> lettersList = getKeyCharacters(2);
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < lettersList.size() && i < 3; i++) {
|
||||
sb.append(lettersList.get(i));
|
||||
}
|
||||
|
||||
abcString = sb.toString();
|
||||
}
|
||||
|
||||
return abcString;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getName() {
|
||||
if (name == null) {
|
||||
name = new Text(this, locale.getDisplayLanguage(locale)).capitalize();
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
private void generateCharacterKeyMap() {
|
||||
characterKeyMap.clear();
|
||||
for (int digit = 0; digit <= 9; digit++) {
|
||||
for (String keyChar : getKeyCharacters(digit)) {
|
||||
characterKeyMap.put(keyChar.charAt(0), String.valueOf(digit));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@NonNull
|
||||
public ArrayList<String> getKeyCharacters(int key, int characterGroup) {
|
||||
if (key < 0 || key >= layout.size()) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
return chars;
|
||||
}
|
||||
|
||||
|
||||
@NonNull
|
||||
public String getKeyNumber(int key) {
|
||||
return key >= 0 && key < 10 && LanguageKind.isArabic(this) ? Characters.ArabicNumbers.get(key) : super.getKeyNumber(key);
|
||||
}
|
||||
|
||||
|
||||
@NonNull
|
||||
public String getDigitSequenceForWord(String word) throws InvalidLanguageCharactersException {
|
||||
StringBuilder sequence = new StringBuilder();
|
||||
String lowerCaseWord = word.toLowerCase(locale);
|
||||
|
||||
for (int i = 0; i < lowerCaseWord.length(); i++) {
|
||||
char letter = lowerCaseWord.charAt(i);
|
||||
if (!characterKeyMap.containsKey(letter)) {
|
||||
throw new InvalidLanguageCharactersException(this, "Failed generating digit sequence for word: '" + word);
|
||||
}
|
||||
|
||||
sequence.append(characterKeyMap.get(letter));
|
||||
}
|
||||
|
||||
return sequence.toString();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public boolean isValidWord(String word) {
|
||||
if (word == null || word.isEmpty() || (word.length() == 1 && Character.isDigit(word.charAt(0)))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
String lowerCaseWord = word.toLowerCase(locale);
|
||||
|
||||
for (int i = 0; i < lowerCaseWord.length(); i++) {
|
||||
if (!characterKeyMap.containsKey(lowerCaseWord.charAt(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int compareTo(NaturalLanguage other) {
|
||||
String key = getName().equals("Suomi") ? "su" : getLocale().toString();
|
||||
String otherKey = other.getName().equals("Suomi") ? "su" : other.getLocale().toString();
|
||||
return key.compareTo(otherKey);
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,9 @@ package io.github.sspanak.tt9.languages;
|
|||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Locale;
|
||||
|
||||
import io.github.sspanak.tt9.R;
|
||||
|
|
@ -10,6 +13,24 @@ public class NullLanguage extends Language {
|
|||
public NullLanguage(Context context) {
|
||||
locale = Locale.ROOT;
|
||||
name = context.getString(R.string.no_language);
|
||||
abcString = "abc";
|
||||
abcString = "ABC";
|
||||
hasUpperCase = false;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ArrayList<String> getKeyCharacters(int key, int characterGroup) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidWord(String word) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getDigitSequenceForWord(String word) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
package io.github.sspanak.tt9.languages;
|
||||
package io.github.sspanak.tt9.languages.exceptions;
|
||||
|
||||
import io.github.sspanak.tt9.languages.Language;
|
||||
|
||||
public class InvalidLanguageCharactersException extends Exception {
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package io.github.sspanak.tt9.languages;
|
||||
package io.github.sspanak.tt9.languages.exceptions;
|
||||
|
||||
public class InvalidLanguageException extends Exception {
|
||||
public InvalidLanguageException() { super("Invalid Language"); }
|
||||
|
|
@ -13,7 +13,7 @@ import androidx.fragment.app.FragmentTransaction;
|
|||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceFragmentCompat;
|
||||
|
||||
import io.github.sspanak.tt9.Logger;
|
||||
import io.github.sspanak.tt9.util.Logger;
|
||||
import io.github.sspanak.tt9.R;
|
||||
import io.github.sspanak.tt9.db.LegacyDb;
|
||||
import io.github.sspanak.tt9.db.WordStoreAsync;
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import java.util.Collections;
|
|||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import io.github.sspanak.tt9.Logger;
|
||||
import io.github.sspanak.tt9.util.Logger;
|
||||
import io.github.sspanak.tt9.ime.modes.InputMode;
|
||||
import io.github.sspanak.tt9.languages.LanguageCollection;
|
||||
import io.github.sspanak.tt9.preferences.screens.debug.ItemInputHandlingMode;
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import androidx.preference.Preference;
|
|||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import io.github.sspanak.tt9.Logger;
|
||||
import io.github.sspanak.tt9.util.Logger;
|
||||
import io.github.sspanak.tt9.preferences.SettingsStore;
|
||||
|
||||
abstract public class ItemClickable {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import androidx.preference.Preference;
|
|||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
import io.github.sspanak.tt9.Logger;
|
||||
import io.github.sspanak.tt9.util.Logger;
|
||||
|
||||
public class ItemDropDown {
|
||||
private final DropDownPreference item;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import android.view.MenuItem;
|
|||
import androidx.annotation.NonNull;
|
||||
import androidx.preference.PreferenceFragmentCompat;
|
||||
|
||||
import io.github.sspanak.tt9.Logger;
|
||||
import io.github.sspanak.tt9.util.Logger;
|
||||
import io.github.sspanak.tt9.preferences.PreferencesActivity;
|
||||
|
||||
abstract public class BaseScreenFragment extends PreferenceFragmentCompat {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import java.util.Arrays;
|
|||
import java.util.regex.Pattern;
|
||||
|
||||
import io.github.sspanak.tt9.BuildConfig;
|
||||
import io.github.sspanak.tt9.Logger;
|
||||
import io.github.sspanak.tt9.util.Logger;
|
||||
import io.github.sspanak.tt9.R;
|
||||
import io.github.sspanak.tt9.ime.helpers.SystemSettings;
|
||||
import io.github.sspanak.tt9.preferences.PreferencesActivity;
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import java.io.BufferedReader;
|
|||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
|
||||
import io.github.sspanak.tt9.Logger;
|
||||
import io.github.sspanak.tt9.util.Logger;
|
||||
import io.github.sspanak.tt9.R;
|
||||
import io.github.sspanak.tt9.preferences.PreferencesActivity;
|
||||
import io.github.sspanak.tt9.preferences.screens.BaseScreenFragment;
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import androidx.preference.Preference;
|
|||
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
import io.github.sspanak.tt9.Logger;
|
||||
import io.github.sspanak.tt9.util.Logger;
|
||||
import io.github.sspanak.tt9.preferences.items.ItemDropDown;
|
||||
|
||||
class ItemLogLevel extends ItemDropDown {
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@ import androidx.preference.PreferenceViewHolder;
|
|||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import io.github.sspanak.tt9.ConsumerCompat;
|
||||
import io.github.sspanak.tt9.Logger;
|
||||
import io.github.sspanak.tt9.util.ConsumerCompat;
|
||||
import io.github.sspanak.tt9.util.Logger;
|
||||
import io.github.sspanak.tt9.R;
|
||||
import io.github.sspanak.tt9.db.WordStoreAsync;
|
||||
import io.github.sspanak.tt9.languages.Language;
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import android.text.TextWatcher;
|
|||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import io.github.sspanak.tt9.ConsumerCompat;
|
||||
import io.github.sspanak.tt9.util.ConsumerCompat;
|
||||
import io.github.sspanak.tt9.preferences.SettingsStore;
|
||||
|
||||
class TextChangeListener implements TextWatcher {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
package io.github.sspanak.tt9.preferences.screens.hotkeys;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import io.github.sspanak.tt9.R;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import java.util.ArrayList;
|
|||
import java.util.Collection;
|
||||
import java.util.Objects;
|
||||
|
||||
import io.github.sspanak.tt9.Logger;
|
||||
import io.github.sspanak.tt9.util.Logger;
|
||||
import io.github.sspanak.tt9.preferences.PreferencesActivity;
|
||||
import io.github.sspanak.tt9.preferences.SettingsStore;
|
||||
import io.github.sspanak.tt9.preferences.helpers.Hotkeys;
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import androidx.preference.DropDownPreference;
|
|||
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
import io.github.sspanak.tt9.Logger;
|
||||
import io.github.sspanak.tt9.util.Logger;
|
||||
import io.github.sspanak.tt9.R;
|
||||
|
||||
class ItemSelectZeroKeyCharacter {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ package io.github.sspanak.tt9.preferences.screens.languages;
|
|||
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import io.github.sspanak.tt9.Logger;
|
||||
import io.github.sspanak.tt9.util.Logger;
|
||||
import io.github.sspanak.tt9.db.exporter.DictionaryExporter;
|
||||
import io.github.sspanak.tt9.languages.LanguageCollection;
|
||||
import io.github.sspanak.tt9.preferences.PreferencesActivity;
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@ import java.util.Locale;
|
|||
|
||||
import io.github.sspanak.tt9.R;
|
||||
import io.github.sspanak.tt9.db.exceptions.DictionaryImportException;
|
||||
import io.github.sspanak.tt9.languages.InvalidLanguageCharactersException;
|
||||
import io.github.sspanak.tt9.languages.InvalidLanguageException;
|
||||
import io.github.sspanak.tt9.languages.exceptions.InvalidLanguageCharactersException;
|
||||
import io.github.sspanak.tt9.languages.exceptions.InvalidLanguageException;
|
||||
import io.github.sspanak.tt9.languages.Language;
|
||||
import io.github.sspanak.tt9.languages.LanguageCollection;
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import android.os.Bundle;
|
|||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import io.github.sspanak.tt9.Logger;
|
||||
import io.github.sspanak.tt9.util.Logger;
|
||||
import io.github.sspanak.tt9.ime.TraditionalT9;
|
||||
import io.github.sspanak.tt9.ui.dialogs.AddWordDialog;
|
||||
import io.github.sspanak.tt9.ui.dialogs.ConfirmDictionaryUpdateDialog;
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import android.content.Intent;
|
|||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import io.github.sspanak.tt9.ConsumerCompat;
|
||||
import io.github.sspanak.tt9.util.ConsumerCompat;
|
||||
import io.github.sspanak.tt9.R;
|
||||
import io.github.sspanak.tt9.db.WordStoreAsync;
|
||||
import io.github.sspanak.tt9.languages.Language;
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import android.content.Intent;
|
|||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import io.github.sspanak.tt9.ConsumerCompat;
|
||||
import io.github.sspanak.tt9.util.ConsumerCompat;
|
||||
import io.github.sspanak.tt9.R;
|
||||
import io.github.sspanak.tt9.db.DictionaryLoader;
|
||||
import io.github.sspanak.tt9.languages.Language;
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import android.content.Intent;
|
|||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import io.github.sspanak.tt9.ConsumerCompat;
|
||||
import io.github.sspanak.tt9.util.ConsumerCompat;
|
||||
import io.github.sspanak.tt9.ui.UI;
|
||||
|
||||
abstract public class PopupDialog {
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ package io.github.sspanak.tt9.ui.main.keys;
|
|||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import io.github.sspanak.tt9.languages.Characters;
|
||||
import io.github.sspanak.tt9.languages.Language;
|
||||
import io.github.sspanak.tt9.languages.LanguageKind;
|
||||
import io.github.sspanak.tt9.util.Characters;
|
||||
|
||||
public class SoftBackspaceKey extends SoftKey {
|
||||
|
||||
|
|
@ -41,7 +41,6 @@ public class SoftBackspaceKey extends SoftKey {
|
|||
return "Del";
|
||||
}
|
||||
|
||||
Language language = getCurrentLanguage();
|
||||
return language != null && language.isRTL() ? "⌦" : "⌫";
|
||||
return LanguageKind.isRTL(getCurrentLanguage()) ? "⌦" : "⌫";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import android.view.View;
|
|||
import androidx.annotation.Nullable;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import io.github.sspanak.tt9.Logger;
|
||||
import io.github.sspanak.tt9.util.Logger;
|
||||
import io.github.sspanak.tt9.R;
|
||||
import io.github.sspanak.tt9.ime.TraditionalT9;
|
||||
import io.github.sspanak.tt9.languages.Language;
|
||||
|
|
|
|||
|
|
@ -6,12 +6,13 @@ import android.view.KeyEvent;
|
|||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import io.github.sspanak.tt9.Logger;
|
||||
import io.github.sspanak.tt9.R;
|
||||
import io.github.sspanak.tt9.ime.helpers.Key;
|
||||
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.preferences.SettingsStore;
|
||||
import io.github.sspanak.tt9.util.Logger;
|
||||
|
||||
public class SoftNumberKey extends SoftKey {
|
||||
public SoftNumberKey(Context context) {
|
||||
|
|
@ -58,7 +59,7 @@ public class SoftNumberKey extends SoftKey {
|
|||
int number = getNumber(getId());
|
||||
|
||||
Language language = getCurrentLanguage();
|
||||
if (language != null && language.isArabic() && tt9 != null && !tt9.isInputModeNumeric()) {
|
||||
if (LanguageKind.isArabic(language) && tt9 != null && !tt9.isInputModeNumeric()) {
|
||||
complexLabelTitleSize = SettingsStore.SOFT_KEY_COMPLEX_LABEL_ARABIC_TITLE_SIZE;
|
||||
return language.getKeyNumber(number);
|
||||
} else {
|
||||
|
|
@ -106,8 +107,8 @@ public class SoftNumberKey extends SoftKey {
|
|||
return "";
|
||||
}
|
||||
|
||||
boolean isLatinBased = language.isLatinBased();
|
||||
boolean isGreekBased = language.isGreek();
|
||||
boolean isLatinBased = LanguageKind.isLatinBased(language);
|
||||
boolean isGreekBased = LanguageKind.isGreek(language);
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
ArrayList<String> chars = language.getKeyCharacters(number);
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import android.content.Context;
|
|||
import android.util.AttributeSet;
|
||||
|
||||
import io.github.sspanak.tt9.R;
|
||||
import io.github.sspanak.tt9.languages.Language;
|
||||
import io.github.sspanak.tt9.languages.LanguageKind;
|
||||
|
||||
public class SoftPunctuationKey extends SoftKey {
|
||||
public SoftPunctuationKey(Context context) {
|
||||
|
|
@ -52,8 +52,7 @@ public class SoftPunctuationKey extends SoftKey {
|
|||
} else {
|
||||
if (keyId == R.id.soft_key_punctuation_1) return "!";
|
||||
if (keyId == R.id.soft_key_punctuation_2) {
|
||||
Language language = getCurrentLanguage();
|
||||
return language != null && language.isArabic() ? "؟" : "?";
|
||||
return LanguageKind.isArabic(getCurrentLanguage()) ? "؟" : "?";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import android.widget.TextView;
|
|||
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import io.github.sspanak.tt9.Logger;
|
||||
import io.github.sspanak.tt9.util.Logger;
|
||||
import io.github.sspanak.tt9.R;
|
||||
|
||||
public class StatusBar {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package io.github.sspanak.tt9.languages;
|
||||
package io.github.sspanak.tt9.util;
|
||||
|
||||
import android.graphics.Paint;
|
||||
import android.os.Build;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package io.github.sspanak.tt9;
|
||||
package io.github.sspanak.tt9.util;
|
||||
|
||||
/**
|
||||
* ConsumerCompat
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
package io.github.sspanak.tt9;
|
||||
package io.github.sspanak.tt9.util;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import io.github.sspanak.tt9.BuildConfig;
|
||||
|
||||
public class Logger {
|
||||
public static final String TAG_PREFIX = "tt9/";
|
||||
public static int LEVEL = BuildConfig.DEBUG ? Log.DEBUG : Log.ERROR;
|
||||
|
|
@ -1,9 +1,11 @@
|
|||
package io.github.sspanak.tt9.languages;
|
||||
package io.github.sspanak.tt9.util;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import io.github.sspanak.tt9.languages.Language;
|
||||
|
||||
public class Text extends TextTools {
|
||||
private final Language language;
|
||||
private final String text;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package io.github.sspanak.tt9.languages;
|
||||
package io.github.sspanak.tt9.util;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package io.github.sspanak.tt9;
|
||||
package io.github.sspanak.tt9.util;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue