1
0
Fork 0

YAML language definitions (#292)

This commit is contained in:
Dimo Karaivanov 2023-06-26 15:14:22 +03:00 committed by GitHub
parent 241a4125b0
commit 6756de4466
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
89 changed files with 689 additions and 522 deletions

View file

@ -1,25 +1,41 @@
package io.github.sspanak.tt9.db.migrations;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.room.migration.Migration;
import androidx.sqlite.db.SupportSQLiteDatabase;
import java.util.Locale;
import io.github.sspanak.tt9.Logger;
import io.github.sspanak.tt9.languages.definitions.Dutch;
import io.github.sspanak.tt9.languages.definitions.English;
import io.github.sspanak.tt9.languages.Language;
import io.github.sspanak.tt9.languages.LanguageCollection;
public class DB11 {
public static final Migration MIGRATION = new Migration(10, 11) {
private Context ctx;
public Migration getMigration(Context context) {
ctx = context;
return MIGRATION;
}
private final Migration MIGRATION = new Migration(10, 11) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
final String enWords = "'I''d','I''m','d''annunzio','I''ll','I''ve','prud''hon','an''t','bo''s''n','bo''s''ns','bo''sun','bo''suns','bos''n','bos''ns','br''er','ca''canny','could''ve','d''arezzo','d''estaing','e''en','e''er','fo''c''s''le','fo''c''s''les','fo''c''sle','fo''c''sles','ha''penny','he''d','he''ll','how''d','how''re','howe''er','it''d','it''ll','might''ve','must''ve','n''importe','ne''er','nor''easter','nor''wester','o''er','rec''d','sec''y','she''d','she''ll','should''ve','sou''wester','ta''en','that''d','that''ll','they''d','they''ll','they''re','they''ve','we''d','we''ll','we''re','we''ve','whate''er','whatsoe''er','whene''er','where''er','who''d','who''ll','who''re','who''ve','why''d','would''ve','you''d','you''ll','you''re','you''ve','Ch''in','L''Amour','L''Enfant','L''Oreal','L''Ouverture','T''ang','Xi''an'";
final String nlWords = "'''s-Graveland','''s-Gravendeel','''s-Gravenhaags','''s-Gravenhage','''s-Gravenhagenaar','''s-Gravenmoer','''s-Gravenzande','''s-Gravenzander','''s-Gravenzands','''s-Hertogenbosch','''t','A.D.','az.','chin.','d.v.','h.k.h.','h.m.','l.b.','mgr.','n.b.','n.h.','n.n.','n.o.','n.v.','n.w.','ned.','o.l.v.','openoffice.org','r.i.p.','st.-eustatius','st.-maarten','stct.','w.','w.v.str.','z.h.','z.k.h.','a.d.h.v.','a.g.v.','a.h.w.','a.j.b.','a.m.','a.s.','a.u.b.','aanw.','afb.','afd.','afz.','an.','arr.','b.d.','b.g.g.','b.v.d.','bc.','bett.','bijl.','bijv.','blz.','bv.','bw.','c.q.','c.s.','ca.','d.d.','d.i.','d.m.v.','d.w.z.','dd.','dhr.','div.','dr.','dra.','drs.','drs.-titel','ds.','e.a.','e.d.','e.e.a.','e.o.','e.v.','e.v.a.','enz.','etc.','evt.','excl.','fa.','fam.','fig.','fr.','g.g.d.','geb.','gem.','get.','i.c.','i.c.m.','i.e.','i.h.a.','i.h.b.','i.m.','i.o.','i.o.v.','i.p.v.','i.s.m.','i.t.t.','i.v.m.','i.z.g.st.','incl.','ing.','ir.','jhr.','jkvr.','jl.','jr.','k.k.','lic.','m.','m.a.w.','m.b.t.','m.b.v.','m.i.','m.i.v.','m.m.','m.m.v.','m.n.','m.u.v.','max.','mevr.','min.','mld.','mln.','mr.','mw.','n.a.v.','n.o.t.k.','n.v.t.','nl.','nl.openoffice.org','no.','nr.','nrs.','o.a.','o.b.v.','o.i.','o.i.d.','o.m.','o.t.t.','o.v.t.','o.v.v.','ong.','p.','p.a.','p.m.','p.o.','p.p.','p.w.','pag.','plm.','plv.','prof.','q.e.d.','q.q.','r.-k.','red.','resp.','s.j.','s.v.p.','sr.','t.a.v.','t.b.v.','t.g.v.','t.h.t.','t.h.v.','t.n.v.','t.o.v.','t.w.','t.w.v.','t.z.t.','v.','v.chr.','v.d.','v.h.','v.l.n.r.','v.r.n.l.','v.t.t.','v.v.','v.v.t.','v.w.b.','verg.','vgl.','vnl.','vnw.','voorz.','vs.','w.o.','w.v.t.t.k.','ww.','z.g.','z.g.a.n.','z.i.','z.o.z.','z.s.m.','zgn.'";
try {
Language English = LanguageCollection.getByLocale(ctx, Locale.ENGLISH.toString());
Language Dutch = LanguageCollection.getByLocale(ctx, "nl_NL");
assert English != null;
assert Dutch != null;
database.beginTransaction();
database.execSQL(getDeleteEnglishSwordsQuery());
database.execSQL(getDeleteWordsQuery(new English().getId(), enWords));
database.execSQL(getDeleteWordsQuery(new Dutch().getId(), nlWords));
database.execSQL(getDeleteEnglishSwordsQuery(English));
database.execSQL(getDeleteWordsQuery(English.getId(), enWords));
database.execSQL(getDeleteWordsQuery(Dutch.getId(), nlWords));
database.setTransactionSuccessful();
} catch (Exception e) {
Logger.e("Migrate to DB11", "Migration failed. " + e.getMessage());
@ -29,11 +45,11 @@ public class DB11 {
}
};
private static String getDeleteEnglishSwordsQuery() {
return "DELETE FROM words WHERE lang=" + new English().getId() + " AND word LIKE '%''s'";
private String getDeleteEnglishSwordsQuery(Language English) {
return "DELETE FROM words WHERE lang=" + English.getId() + " AND word LIKE '%''s'";
}
private static String getDeleteWordsQuery(int langId, String wordList) {
private String getDeleteWordsQuery(int langId, String wordList) {
return "DELETE FROM words WHERE lang=" + langId + " AND word IN(" + wordList + ")";
}
}

View file

@ -7,16 +7,10 @@ import androidx.room.migration.Migration;
import androidx.sqlite.db.SupportSQLiteDatabase;
import java.util.ArrayList;
import java.util.Locale;
import io.github.sspanak.tt9.languages.definitions.Bulgarian;
import io.github.sspanak.tt9.languages.definitions.Dutch;
import io.github.sspanak.tt9.languages.definitions.English;
import io.github.sspanak.tt9.languages.definitions.French;
import io.github.sspanak.tt9.languages.definitions.German;
import io.github.sspanak.tt9.languages.definitions.Italian;
import io.github.sspanak.tt9.languages.definitions.Russian;
import io.github.sspanak.tt9.languages.definitions.Spanish;
import io.github.sspanak.tt9.languages.definitions.Ukrainian;
import io.github.sspanak.tt9.languages.Language;
import io.github.sspanak.tt9.languages.LanguageCollection;
import io.github.sspanak.tt9.preferences.SettingsStore;
public class DB7 {
@ -28,28 +22,41 @@ public class DB7 {
}
private int getNewLanguageId(int oldId) {
Language language;
switch (oldId) {
default:
return oldId;
case 1:
return new English().getId();
language = LanguageCollection.getByLocale(ctx, Locale.ENGLISH.toString());
break;
case 2:
return new Russian().getId();
language = LanguageCollection.getByLocale(ctx, "ru_RU");
break;
case 3:
return new German().getId();
language = LanguageCollection.getByLocale(ctx, Locale.GERMAN.toString());
break;
case 4:
return new French().getId();
language = LanguageCollection.getByLocale(ctx, Locale.FRENCH.toString());
break;
case 5:
return new Italian().getId();
language = LanguageCollection.getByLocale(ctx, Locale.ITALIAN.toString());
break;
case 6:
return new Ukrainian().getId();
language = LanguageCollection.getByLocale(ctx, "uk_UA");
break;
case 7:
return new Bulgarian().getId();
language = LanguageCollection.getByLocale(ctx, "bg_BG");
break;
case 8:
return new Dutch().getId();
language = LanguageCollection.getByLocale(ctx, "nl_NL");
break;
case 9:
return new Spanish().getId();
language = LanguageCollection.getByLocale(ctx, "es_ES");
break;
}
return language != null ? language.getId() : -1;
}
private final Migration migration = new Migration(6, 7) {

View file

@ -27,7 +27,7 @@ public abstract class TT9Room extends RoomDatabase {
DB8.MIGRATION,
DB9.MIGRATION,
DB10.MIGRATION,
DB11.MIGRATION
new DB11().getMigration(context)
)
.build();
}

View file

@ -21,7 +21,7 @@ public class EmptyDatabaseWarning {
public EmptyDatabaseWarning(SettingsStore settings) {
WARNING_INTERVAL = settings.getDictionaryMissingWarningInterval();
for (Language lang : LanguageCollection.getAll()) {
for (Language lang : LanguageCollection.getAll(context)) {
if (!warningDisplayedTime.containsKey(lang.getId())) {
warningDisplayedTime.put(lang.getId(), 0L);
}

View file

@ -69,7 +69,7 @@ public class TraditionalT9 extends KeyPadHandler {
private void loadSettings() {
mLanguage = LanguageCollection.getLanguage(settings.getInputLanguage());
mLanguage = LanguageCollection.getLanguage(getMainContext(), settings.getInputLanguage());
mEnabledLanguages = settings.getEnabledLanguageIds();
validateLanguages();
@ -79,8 +79,8 @@ public class TraditionalT9 extends KeyPadHandler {
private void validateLanguages() {
mEnabledLanguages = InputModeValidator.validateEnabledLanguages(mEnabledLanguages);
mLanguage = InputModeValidator.validateLanguage(mLanguage, mEnabledLanguages);
mEnabledLanguages = InputModeValidator.validateEnabledLanguages(getMainContext(), mEnabledLanguages);
mLanguage = InputModeValidator.validateLanguage(getMainContext(), mLanguage, mEnabledLanguages);
settings.saveEnabledLanguageIds(mEnabledLanguages);
settings.saveInputLanguage(mLanguage.getId());
@ -689,7 +689,7 @@ public class TraditionalT9 extends KeyPadHandler {
// select the next language
int previous = mEnabledLanguages.indexOf(mLanguage.getId());
int next = (previous + 1) % mEnabledLanguages.size();
mLanguage = LanguageCollection.getLanguage(mEnabledLanguages.get(next));
mLanguage = LanguageCollection.getLanguage(getMainContext(), mEnabledLanguages.get(next));
validateLanguages();

View file

@ -1,5 +1,7 @@
package io.github.sspanak.tt9.ime.helpers;
import android.content.Context;
import java.util.ArrayList;
import io.github.sspanak.tt9.Logger;
@ -8,29 +10,29 @@ import io.github.sspanak.tt9.languages.Language;
import io.github.sspanak.tt9.languages.LanguageCollection;
public class InputModeValidator {
public static ArrayList<Integer> validateEnabledLanguages(ArrayList<Integer> enabledLanguageIds) {
ArrayList<Language> validLanguages = LanguageCollection.getAll(enabledLanguageIds);
public static ArrayList<Integer> validateEnabledLanguages(Context context, ArrayList<Integer> enabledLanguageIds) {
ArrayList<Language> validLanguages = LanguageCollection.getAll(context, enabledLanguageIds);
ArrayList<Integer> validLanguageIds = new ArrayList<>();
for (Language lang : validLanguages) {
validLanguageIds.add(lang.getId());
}
if (validLanguageIds.size() == 0) {
validLanguageIds.add(LanguageCollection.getDefault().getId());
validLanguageIds.add(LanguageCollection.getDefault(context).getId());
Logger.e("tt9/validateEnabledLanguages", "The language list seems to be corrupted. Resetting to first language only.");
}
return validLanguageIds;
}
public static Language validateLanguage(Language language, ArrayList<Integer> validLanguageIds) {
public static Language validateLanguage(Context context, Language language, ArrayList<Integer> validLanguageIds) {
if (language != null && validLanguageIds.contains(language.getId())) {
return language;
}
String error = language != null ? "Language: " + language.getId() + " is not enabled." : "Invalid language.";
Language validLanguage = LanguageCollection.getLanguage(validLanguageIds.get(0));
validLanguage = validLanguage != null ? validLanguage : LanguageCollection.getDefault();
Language validLanguage = LanguageCollection.getLanguage(context, validLanguageIds.get(0));
validLanguage = validLanguage != null ? validLanguage : LanguageCollection.getDefault(context);
Logger.w("tt9/validateLanguage", error + " Enforcing language: " + validLanguage.getId());

View file

@ -91,7 +91,8 @@ public class ModeABC extends InputMode {
}
String langCode = language.getLocale().getCountry();
langCode = langCode.length() == 0 ? language.getLocale().getLanguage() : langCode;
langCode = langCode.isEmpty() ? language.getLocale().getLanguage() : langCode;
langCode = langCode.isEmpty() ? language.getName() : langCode;
String modeString = language.getAbcString() + " / " + langCode.toUpperCase();

View file

@ -13,12 +13,82 @@ public class Language {
protected Locale locale;
protected String dictionaryFile;
protected String abcString;
protected ArrayList<ArrayList<String>> characterMap = new ArrayList<>();
private final HashMap<Character, String> reverseCharacterMap = new HashMap<>();
protected final ArrayList<ArrayList<String>> layout = new ArrayList<>();
private final HashMap<Character, String> characterKeyMap = new HashMap<>();
// settings
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;
switch (definition.locale) {
case "de":
definitionLocale = Locale.GERMAN;
break;
case "en":
definitionLocale = Locale.ENGLISH;
break;
case "fr":
definitionLocale = Locale.FRENCH;
break;
case "it":
definitionLocale = Locale.ITALIAN;
break;
default:
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() ? lang.abcString : 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) {
final String defaultCharsPlaceholder = "DEFAULT";
if (key > 1 || !definitionChars.contains(defaultCharsPlaceholder)) {
return definitionChars;
}
ArrayList<String> keyChars = new ArrayList<>();
for (String defChar : definitionChars) {
if (defChar.equals(defaultCharsPlaceholder)) {
keyChars.addAll(key == 0 ? Characters.Special : Characters.Sentence);
} else {
keyChars.add(defChar);
}
}
return keyChars;
}
final public int getId() {
if (id == 0) {
id = generateId();
@ -95,11 +165,11 @@ public class Language {
return idInt;
}
private void generateReverseCharacterMap() {
reverseCharacterMap.clear();
private void generateCharacterKeyMap() {
characterKeyMap.clear();
for (int digit = 0; digit <= 9; digit++) {
for (String keyChar : getKeyCharacters(digit)) {
reverseCharacterMap.put(keyChar.charAt(0), String.valueOf(digit));
characterKeyMap.put(keyChar.charAt(0), String.valueOf(digit));
}
}
}
@ -131,11 +201,11 @@ public class Language {
}
public ArrayList<String> getKeyCharacters(int key, boolean includeDigit) {
if (key < 0 || key >= characterMap.size()) {
if (key < 0 || key >= layout.size()) {
return new ArrayList<>();
}
ArrayList<String> chars = new ArrayList<>(characterMap.get(key));
ArrayList<String> chars = new ArrayList<>(layout.get(key));
if (includeDigit && chars.size() > 0) {
chars.add(String.valueOf(key));
}
@ -151,17 +221,17 @@ public class Language {
StringBuilder sequence = new StringBuilder();
String lowerCaseWord = word.toLowerCase(locale);
if (reverseCharacterMap.isEmpty()) {
generateReverseCharacterMap();
if (characterKeyMap.isEmpty()) {
generateCharacterKeyMap();
}
for (int i = 0; i < lowerCaseWord.length(); i++) {
char letter = lowerCaseWord.charAt(i);
if (!reverseCharacterMap.containsKey(letter)) {
if (!characterKeyMap.containsKey(letter)) {
throw new InvalidLanguageCharactersException(this, "Failed generating digit sequence for word: '" + word);
}
sequence.append(reverseCharacterMap.get(letter));
sequence.append(characterKeyMap.get(letter));
}
return sequence.toString();

View file

@ -1,84 +1,70 @@
package io.github.sspanak.tt9.languages;
import android.content.Context;
import android.os.Build;
import androidx.annotation.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import io.github.sspanak.tt9.Logger;
import io.github.sspanak.tt9.languages.definitions.*;
public class LanguageCollection {
private static LanguageCollection self;
private final Language defaultLanguage = new English();
private final HashMap<Integer, Language> languages = new HashMap<>();
private LanguageCollection() {
List<Class<? extends Language>> languageList = Arrays.asList(
// Add languages here, to enable them in the UI and
// please, maintain the alphabetical order.
BrazilianPortuguese.class,
Bulgarian.class,
Dutch.class,
English.class,
Finnish.class,
French.class,
German.class,
Hebrew.class,
Indonesian.class,
Italian.class,
Norwegian.class,
Polish.class,
Russian.class,
Spanish.class,
Swedish.class,
Ukrainian.class,
Yiddish.class
);
// initialize the language objects from the class list above
for (Class<? extends Language> languageClass : languageList) {
private LanguageCollection(Context context) {
for (String file : LanguageDefinition.getAllFiles(context.getAssets())) {
try {
Language lang = languageClass.newInstance();
if (languages.containsKey(lang.getId())) {
throw new Exception("Duplicate language ID: " + lang.getId() + " for language: " + lang.getName());
}
Language lang = Language.fromDefinition(LanguageDefinition.fromFile(context.getAssets(), file));
languages.put(lang.getId(), lang);
} catch (Exception e) {
Logger.e("tt9.LanguageCollection", "Skipping an invalid language. " + e.getMessage());
Logger.e("tt9.LanguageCollection", "Skipping invalid language: '" + file + "'. " + e.getMessage());
}
}
}
public static LanguageCollection getInstance() {
public static LanguageCollection getInstance(Context context) {
if (self == null) {
self = new LanguageCollection();
self = new LanguageCollection(context);
}
return self;
}
public static Language getLanguage(int langId) {
if (getInstance().languages.containsKey(langId)) {
return getInstance().languages.get(langId);
public static Language getLanguage(Context context, int langId) {
if (getInstance(context).languages.containsKey(langId)) {
return getInstance(context).languages.get(langId);
}
return null;
}
public static Language getDefault() {
return getInstance().defaultLanguage;
public static Language getDefault(Context context) {
Language language = getByLocale(context, "en");
return language == null ? new NullLanguage(context) : language;
}
public static ArrayList<Language> getAll(ArrayList<Integer> languageIds, boolean sort) {
@Nullable
public static Language getByLocale(Context context, String locale) {
for (Language lang : getInstance(context).languages.values()) {
if (lang.getLocale().toString().equals(locale)) {
return lang;
}
}
return null;
}
public static ArrayList<Language> getAll(Context context, ArrayList<Integer> languageIds, boolean sort) {
ArrayList<Language> langList = new ArrayList<>();
for (int languageId : languageIds) {
Language lang = getLanguage(languageId);
Language lang = getLanguage(context, languageId);
if (lang != null) {
langList.add(lang);
}
@ -91,12 +77,12 @@ public class LanguageCollection {
return langList;
}
public static ArrayList<Language> getAll(ArrayList<Integer> languageIds) {
return getAll(languageIds, false);
public static ArrayList<Language> getAll(Context context, ArrayList<Integer> languageIds) {
return getAll(context, languageIds, false);
}
public static ArrayList<Language> getAll(boolean sort) {
ArrayList<Language> langList = new ArrayList<>(getInstance().languages.values());
public static ArrayList<Language> getAll(Context context, boolean sort) {
ArrayList<Language> langList = new ArrayList<>(getInstance(context).languages.values());
if (sort && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
langList.sort(Comparator.comparing(l -> l.getLocale().toString()));
@ -105,8 +91,8 @@ public class LanguageCollection {
return langList;
}
public static ArrayList<Language> getAll() {
return getAll(false);
public static ArrayList<Language> getAll(Context context) {
return getAll(context,false);
}

View file

@ -0,0 +1,47 @@
package io.github.sspanak.tt9.languages;
import android.content.res.AssetManager;
import org.yaml.snakeyaml.Yaml;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import io.github.sspanak.tt9.Logger;
public class LanguageDefinition {
private static final String languagesDir = "languages";
private static final String definitionsDir = languagesDir + "/definitions";
public String abcString = "";
public String dictionaryFile = "";
public boolean hasUpperCase = true;
public ArrayList<ArrayList<String>> layout = new ArrayList<>();
public String locale = "";
public String name = "";
public static ArrayList<String> getAllFiles(AssetManager assets) {
ArrayList<String> files = new ArrayList<>();
try {
for (String file : assets.list(definitionsDir)) {
files.add(definitionsDir + "/" + file);
}
} catch (IOException e) {
Logger.e("tt9.LanguageDefinition", "Failed reading language definitions from: '" + definitionsDir + "'. " + e.getMessage());
}
return files;
}
public static LanguageDefinition fromFile(AssetManager assets, String definitionFile) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(assets.open(definitionFile), StandardCharsets.UTF_8));
return new Yaml().loadAs(reader, LanguageDefinition.class);
}
public String getDictionaryFile() {
return languagesDir + "/dictionaries/" + dictionaryFile;
}
}

View file

@ -0,0 +1,15 @@
package io.github.sspanak.tt9.languages;
import android.content.Context;
import java.util.Locale;
import io.github.sspanak.tt9.R;
public class NullLanguage extends Language {
public NullLanguage(Context context) {
locale = Locale.ROOT;
name = context.getString(R.string.no_language);
abcString = "abc";
}
}

View file

@ -1,20 +0,0 @@
package io.github.sspanak.tt9.languages.definitions;
import java.util.Arrays;
import java.util.Locale;
public class BrazilianPortuguese extends English {
public BrazilianPortuguese() {
super();
name = "Português brasileiro";
locale = new Locale("pt","BR");
dictionaryFile = "pt-BR-utf8.csv";
characterMap.get(2).addAll(Arrays.asList("ç", "á", "â", "ã", "à"));
characterMap.get(3).addAll(Arrays.asList("é", "ê", "è"));
characterMap.get(4).add("í");
characterMap.get(6).addAll(Arrays.asList("ó", "ô", "õ"));
characterMap.get(8).add("ú");
}
}

View file

@ -1,28 +0,0 @@
package io.github.sspanak.tt9.languages.definitions;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Locale;
import io.github.sspanak.tt9.languages.Language;
import io.github.sspanak.tt9.languages.Characters;
public class Bulgarian extends Language {
public Bulgarian() {
locale = new Locale("bg","BG");
dictionaryFile = "bg-utf8.csv";
characterMap = new ArrayList<>(Arrays.asList(
Characters.Special, // 0
Characters.Sentence, // 1
new ArrayList<>(Arrays.asList("а", "б", "в", "г")), // 2
new ArrayList<>(Arrays.asList("д", "е", "ж", "з")), // 3
new ArrayList<>(Arrays.asList("и", "й", "к", "л", "ѝ")), // 4
new ArrayList<>(Arrays.asList("м", "н", "о", "п")), // 5
new ArrayList<>(Arrays.asList("р", "с", "т", "у")), // 6
new ArrayList<>(Arrays.asList("ф", "х", "ц", "ч")), // 7
new ArrayList<>(Arrays.asList("ш", "щ", "ъ")), // 8
new ArrayList<>(Arrays.asList("ь", "ю", "я")) // 9
));
}
}

View file

@ -1,19 +0,0 @@
package io.github.sspanak.tt9.languages.definitions;
import java.util.Arrays;
import java.util.Locale;
public class Dutch extends English {
public Dutch() {
super();
locale = new Locale("nl","NL");
dictionaryFile = "nl-utf8.csv";
characterMap.get(2).addAll(Arrays.asList("à", "ä", "ç"));
characterMap.get(3).addAll(Arrays.asList("é", "è", "ê", "ë"));
characterMap.get(4).addAll(Arrays.asList("î", "ï"));
characterMap.get(6).add("ö");
characterMap.get(8).addAll(Arrays.asList("û", "ü"));
}
}

View file

@ -1,28 +0,0 @@
package io.github.sspanak.tt9.languages.definitions;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Locale;
import io.github.sspanak.tt9.languages.Characters;
import io.github.sspanak.tt9.languages.Language;
public class English extends Language {
public English() {
locale = Locale.ENGLISH;
dictionaryFile = "en-utf8.csv";
characterMap = new ArrayList<>(Arrays.asList(
Characters.Special, // 0
Characters.Sentence, // 1
new ArrayList<>(Arrays.asList("a", "b", "c")), // 2
new ArrayList<>(Arrays.asList("d", "e", "f")), // 3
new ArrayList<>(Arrays.asList("g", "h", "i")), // 4
new ArrayList<>(Arrays.asList("j", "k", "l")), // 5
new ArrayList<>(Arrays.asList("m", "n", "o")), // 6
new ArrayList<>(Arrays.asList("p", "q", "r", "s")), // 7
new ArrayList<>(Arrays.asList("t", "u", "v")), // 8
new ArrayList<>(Arrays.asList("w", "x", "y", "z")) // 9
));
}
}

View file

@ -1,16 +0,0 @@
package io.github.sspanak.tt9.languages.definitions;
import java.util.Arrays;
import java.util.Locale;
public class Finnish extends English {
public Finnish() {
super();
locale = new Locale("fi","FI");
dictionaryFile = "fi-utf8.csv";
characterMap.get(2).addAll(Arrays.asList("ä", "å"));
characterMap.get(6).add("ö");
}
}

View file

@ -1,20 +0,0 @@
package io.github.sspanak.tt9.languages.definitions;
import java.util.Arrays;
import java.util.Locale;
public class French extends English {
public French() {
super();
locale = Locale.FRENCH;
dictionaryFile = "fr-utf8.csv";
characterMap.get(2).addAll(Arrays.asList("à", "â", "æ", "ç"));
characterMap.get(3).addAll(Arrays.asList("é", "è", "ê", "ë"));
characterMap.get(4).addAll(Arrays.asList("î", "ï"));
characterMap.get(6).addAll(Arrays.asList("ô", "œ"));
characterMap.get(8).addAll(Arrays.asList("ù", "û", "ü"));
characterMap.get(9).add("ÿ");
}
}

View file

@ -1,17 +0,0 @@
package io.github.sspanak.tt9.languages.definitions;
import java.util.Locale;
public class German extends English {
public German() {
super();
locale = Locale.GERMAN;
dictionaryFile = "de-utf8.csv";
characterMap.get(2).add("ä");
characterMap.get(6).add("ö");
characterMap.get(7).add("ß");
characterMap.get(8).add("ü");
}
}

View file

@ -1,31 +0,0 @@
package io.github.sspanak.tt9.languages.definitions;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Locale;
import io.github.sspanak.tt9.languages.Characters;
import io.github.sspanak.tt9.languages.Language;
public class Hebrew extends Language {
public Hebrew() {
locale = new Locale("iw","IL");
dictionaryFile = "he-utf8.csv";
abcString = "אבג";
hasUpperCase = false;
characterMap = new ArrayList<>(Arrays.asList(
Characters.Special, // 0
Characters.Sentence, // 1
new ArrayList<>(Arrays.asList("ד", "ה", "ו")), // 2
new ArrayList<>(Arrays.asList("א", "ב", "ג")), // 3
new ArrayList<>(Arrays.asList("מ", "ם", "נ", "ן")), // 4
new ArrayList<>(Arrays.asList("י", "כ", "ך", "ל")), // 5
new ArrayList<>(Arrays.asList("ז", "ח", "ט")), // 6
new ArrayList<>(Arrays.asList("ר", "ש", "ת")), // 7
new ArrayList<>(Arrays.asList("צ", "ץ", "ק")), // 8
new ArrayList<>(Arrays.asList("ס", "ע", "פ", "ף")) // 9
));
}
}

View file

@ -1,13 +0,0 @@
package io.github.sspanak.tt9.languages.definitions;
import java.util.Locale;
public class Indonesian extends English {
public Indonesian() {
super();
name = "Bahasa Indonesia";
locale = new Locale("in", "ID");
dictionaryFile = "id-utf8.csv";
}
}

View file

@ -1,19 +0,0 @@
package io.github.sspanak.tt9.languages.definitions;
import java.util.Arrays;
import java.util.Locale;
public class Italian extends English {
public Italian() {
super();
locale = Locale.ITALIAN;
dictionaryFile = "it-utf8.csv";
characterMap.get(2).add("à");
characterMap.get(3).addAll(Arrays.asList("é", "è"));
characterMap.get(4).addAll(Arrays.asList("ì", "í", "î"));
characterMap.get(6).addAll(Arrays.asList("ò", "ó"));
characterMap.get(8).addAll(Arrays.asList("ù", "ú"));
}
}

View file

@ -1,18 +0,0 @@
package io.github.sspanak.tt9.languages.definitions;
import java.util.Arrays;
import java.util.Locale;
public class Norwegian extends English {
public Norwegian() {
super();
locale = new Locale("nb","NO");
dictionaryFile = "nb-utf8.csv";
characterMap.get(2).addAll(Arrays.asList("æ", "å"));
characterMap.get(3).addAll(Arrays.asList("é", "è"));
characterMap.get(6).addAll(Arrays.asList("ø", "ó", "ò", "ô"));
characterMap.get(8).add("ü");
}
}

View file

@ -1,20 +0,0 @@
package io.github.sspanak.tt9.languages.definitions;
import java.util.Arrays;
import java.util.Locale;
public class Polish extends English {
public Polish() {
super();
locale = new Locale("pl","PL");
dictionaryFile = "pl-utf8.csv";
characterMap.get(2).addAll(Arrays.asList("ą", "ć"));
characterMap.get(3).add("ę");
characterMap.get(5).add("ł");
characterMap.get(6).addAll(Arrays.asList("ó", "ń"));
characterMap.get(7).add("ś");
characterMap.get(9).addAll(Arrays.asList("ź", "ż"));
}
}

View file

@ -1,28 +0,0 @@
package io.github.sspanak.tt9.languages.definitions;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Locale;
import io.github.sspanak.tt9.languages.Characters;
import io.github.sspanak.tt9.languages.Language;
public class Russian extends Language {
public Russian() {
locale = new Locale("ru","RU");
dictionaryFile = "ru-utf8.csv";
characterMap = new ArrayList<>(Arrays.asList(
Characters.Special, // 0
Characters.Sentence, // 1
new ArrayList<>(Arrays.asList("а", "б", "в", "г")), // 2
new ArrayList<>(Arrays.asList("д", "е", "ё", "ж", "з")), // 3
new ArrayList<>(Arrays.asList("и", "й", "к", "л")), // 4
new ArrayList<>(Arrays.asList("м", "н", "о", "п")), // 5
new ArrayList<>(Arrays.asList("р", "с", "т", "у")), // 6
new ArrayList<>(Arrays.asList("ф", "х", "ц", "ч")), // 7
new ArrayList<>(Arrays.asList("ш", "щ", "ъ", "ы")), // 8
new ArrayList<>(Arrays.asList("ь", "э", "ю", "я")) // 9
));
}
}

View file

@ -1,25 +0,0 @@
package io.github.sspanak.tt9.languages.definitions;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Locale;
import io.github.sspanak.tt9.languages.Characters;
public class Spanish extends English {
public Spanish() {
super();
locale = new Locale("es", "ES");
dictionaryFile = "es-utf8.csv";
characterMap.set(1, new ArrayList<>(Characters.Sentence));
characterMap.get(1).addAll(Arrays.asList("¡", "¿"));
characterMap.get(2).add("á");
characterMap.get(3).add("é");
characterMap.get(4).add("í");
characterMap.set(6, new ArrayList<>(Arrays.asList("m", "n", "ñ", "o", "ó")));
characterMap.get(8).addAll(Arrays.asList("ú", "ü"));
}
}

View file

@ -1,17 +0,0 @@
package io.github.sspanak.tt9.languages.definitions;
import java.util.Arrays;
import java.util.Locale;
public class Swedish extends English {
public Swedish() {
super();
locale = new Locale("sv","SE");
dictionaryFile = "sv-utf8.csv";
characterMap.get(2).addAll(Arrays.asList("å", "ä"));
characterMap.get(3).add("é");
characterMap.get(6).add("ö");
}
}

View file

@ -1,28 +0,0 @@
package io.github.sspanak.tt9.languages.definitions;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Locale;
import io.github.sspanak.tt9.languages.Characters;
import io.github.sspanak.tt9.languages.Language;
public class Ukrainian extends Language {
public Ukrainian() {
locale = new Locale("uk","UA");
dictionaryFile = "uk-utf8.csv";
characterMap = new ArrayList<>(Arrays.asList(
Characters.Special, // 0
Characters.Sentence, // 1
new ArrayList<>(Arrays.asList("а", "б", "в", "г", "ґ")), // 2
new ArrayList<>(Arrays.asList("д", "е", "є", "ж", "з")), // 3
new ArrayList<>(Arrays.asList("и", "і", "ї", "й", "к", "л")), // 4
new ArrayList<>(Arrays.asList("м", "н", "о", "п")), // 5
new ArrayList<>(Arrays.asList("р", "с", "т", "у")), // 6
new ArrayList<>(Arrays.asList("ф", "х", "ц", "ч")), // 7
new ArrayList<>(Arrays.asList("ш", "щ")), // 8
new ArrayList<>(Arrays.asList("ь", "ю", "я")) // 9
));
}
}

View file

@ -1,12 +0,0 @@
package io.github.sspanak.tt9.languages.definitions;
import java.util.Locale;
public class Yiddish extends Hebrew {
public Yiddish() {
super();
locale = new Locale("ji","JI");
dictionaryFile = "ji-utf8.csv";
}
}

View file

@ -41,7 +41,7 @@ public class PreferencesActivity extends AppCompatActivity implements Preference
DictionaryDb.init(this);
DictionaryDb.normalizeWordFrequencies(settings);
InputModeValidator.validateEnabledLanguages(settings.getEnabledLanguageIds());
InputModeValidator.validateEnabledLanguages(this, settings.getEnabledLanguageIds());
validateFunctionKeys();
super.onCreate(savedInstanceState);

View file

@ -19,11 +19,13 @@ import io.github.sspanak.tt9.preferences.items.SectionKeymap;
public class SettingsStore {
private final Context context;
private final SharedPreferences prefs;
private final SharedPreferences.Editor prefsEditor;
public SettingsStore(Context context) {
this.context = context;
prefs = PreferenceManager.getDefaultSharedPreferences(context);
prefsEditor = prefs.edit();
}
@ -32,7 +34,7 @@ public class SettingsStore {
/************* validators *************/
private boolean doesLanguageExist(int langId) {
return LanguageCollection.getLanguage(langId) != null;
return LanguageCollection.getLanguage(context, langId) != null;
}
private boolean validateSavedLanguage(int langId, String logTag) {
@ -70,7 +72,7 @@ public class SettingsStore {
public Set<String> getEnabledLanguagesIdsAsStrings() {
return prefs.getStringSet("pref_languages", new HashSet<>(Collections.singletonList(
String.valueOf(LanguageCollection.getDefault().getId())
String.valueOf(LanguageCollection.getDefault(context).getId())
)));
}
@ -124,7 +126,7 @@ public class SettingsStore {
public int getInputLanguage() {
return prefs.getInt("pref_input_language", LanguageCollection.getDefault().getId());
return prefs.getInt("pref_input_language", LanguageCollection.getDefault(context).getId());
}
public void saveInputLanguage(int language) {

View file

@ -38,7 +38,7 @@ abstract class ItemClickable {
*
* My smashed Qin F21 Pro+ occasionally does this, if I press the keys hard.
* There were reports the same happens on Kyocera KYF31, causing absolutely undesirable side effects.
* @see: <a href="https://github.com/sspanak/tt9/issues/117">...</a>
* See: <a href="https://github.com/sspanak/tt9/issues/117">...</a>
*/
protected boolean debounceClick(Preference p) {
long now = System.currentTimeMillis();

View file

@ -45,7 +45,7 @@ public class ItemLoadDictionary extends ItemClickable {
private void onLoadingStatusChange(Bundle status) {
progressBar.show(status);
progressBar.show(context, status);
item.setSummary(progressBar.getTitle() + " " + progressBar.getMessage());
if (progressBar.isCancelled()) {
@ -62,7 +62,7 @@ public class ItemLoadDictionary extends ItemClickable {
@Override
protected boolean onClick(Preference p) {
ArrayList<Language> languages = LanguageCollection.getAll(settings.getEnabledLanguageIds());
ArrayList<Language> languages = LanguageCollection.getAll(context, settings.getEnabledLanguageIds());
try {
loader.load(languages);

View file

@ -1,21 +1,27 @@
package io.github.sspanak.tt9.preferences.items;
import android.content.Context;
import androidx.preference.MultiSelectListPreference;
import java.util.ArrayList;
import java.util.HashSet;
import io.github.sspanak.tt9.R;
import io.github.sspanak.tt9.languages.Language;
import io.github.sspanak.tt9.languages.LanguageCollection;
import io.github.sspanak.tt9.preferences.SettingsStore;
import io.github.sspanak.tt9.ui.UI;
public class ItemSelectLanguage {
public static final String NAME = "pref_languages";
private final Context context;
private final SettingsStore settings;
private final MultiSelectListPreference item;
public ItemSelectLanguage(MultiSelectListPreference multiSelect, SettingsStore settings) {
public ItemSelectLanguage(Context context, MultiSelectListPreference multiSelect, SettingsStore settings) {
this.context = context;
this.item = multiSelect;
this.settings = settings;
}
@ -25,7 +31,11 @@ public class ItemSelectLanguage {
return this;
}
ArrayList<Language> languages = LanguageCollection.getAll(true);
ArrayList<Language> languages = LanguageCollection.getAll(context, true);
if (languages.isEmpty()) {
UI.alert(context, R.string.error, R.string.failed_loading_language_definitions);
// do not return, the MultiSelect component requires arrays, even if empty, otherwise it crashes
}
ArrayList<CharSequence> values = new ArrayList<>();
for (Language l : languages) {
@ -70,7 +80,7 @@ public class ItemSelectLanguage {
private void previewSelection() {
item.setSummary(
LanguageCollection.toString(LanguageCollection.getAll(settings.getEnabledLanguageIds(), true))
LanguageCollection.toString(LanguageCollection.getAll(context, settings.getEnabledLanguageIds(), true))
);
}
}

View file

@ -39,7 +39,7 @@ public class ItemTruncateUnselected extends ItemTruncateAll {
ArrayList<Integer> unselectedLanguageIds = new ArrayList<>();
ArrayList<Integer> selectedLanguageIds = settings.getEnabledLanguageIds();
for (Language lang : LanguageCollection.getAll(false)) {
for (Language lang : LanguageCollection.getAll(activity, false)) {
if (!selectedLanguageIds.contains(lang.getId())) {
unselectedLanguageIds.add(lang.getId());
}

View file

@ -17,6 +17,7 @@ public class DictionariesScreen extends BaseScreenFragment {
@Override
protected void onCreate() {
ItemSelectLanguage multiSelect = new ItemSelectLanguage(
activity,
findPreference(ItemSelectLanguage.NAME),
activity.settings
);

View file

@ -75,7 +75,7 @@ public class AddWordAct extends AppCompatActivity {
word = ((EditText) main.findViewById(R.id.add_word_text)).getText().toString();
Logger.d("addWord", "Attempting to add word: '" + word + "'...");
DictionaryDb.insertWord(this::onAddedWord, LanguageCollection.getLanguage(lang), word);
DictionaryDb.insertWord(this::onAddedWord, LanguageCollection.getLanguage(this, lang), word);
} catch (InsertBlankWordException e) {
Logger.e("AddWordAct.addWord", e.getMessage());
UI.toastLong(this, R.string.add_word_blank);

View file

@ -103,13 +103,14 @@ public class DictionaryLoadingBar {
}
public void show(Bundle data) {
public void show(Context context, Bundle data) {
String error = data.getString("error", null);
int fileCount = data.getInt("fileCount", -1);
if (error != null) {
hasFailed = true;
showError(
context,
error,
data.getInt("languageId", -1),
data.getLong("fileLine", -1),
@ -120,6 +121,7 @@ public class DictionaryLoadingBar {
} else {
hasFailed = false;
showProgress(
context,
data.getLong("time", 0),
data.getInt("currentFile", 0),
data.getInt("progress", 0),
@ -129,8 +131,8 @@ public class DictionaryLoadingBar {
}
private String generateTitle(int languageId) {
Language lang = LanguageCollection.getLanguage(languageId);
private String generateTitle(Context context, int languageId) {
Language lang = LanguageCollection.getLanguage(context, languageId);
if (lang != null) {
return resources.getString(R.string.dictionary_loading, lang.getName());
@ -140,7 +142,7 @@ public class DictionaryLoadingBar {
}
private void showProgress(long time, int currentFile, int currentFileProgress, int languageId) {
private void showProgress(Context context, long time, int currentFile, int currentFileProgress, int languageId) {
if (currentFileProgress < 0) {
hide();
isStopped = true;
@ -154,12 +156,12 @@ public class DictionaryLoadingBar {
if (progress >= maxProgress) {
progress = maxProgress = 0;
title = generateTitle(-1);
title = generateTitle(context, -1);
String timeFormat = time > 60000 ? " (%1.0fs)" : " (%1.1fs)";
message = resources.getString(R.string.completed) + String.format(Locale.ENGLISH, timeFormat, time / 1000.0);
} else {
title = generateTitle(languageId);
title = generateTitle(context, languageId);
message = currentFileProgress + "%";
}
@ -167,8 +169,8 @@ public class DictionaryLoadingBar {
}
private void showError(String errorType, int langId, long line, String word) {
Language lang = LanguageCollection.getLanguage(langId);
private void showError(Context context, String errorType, int langId, long line, String word) {
Language lang = LanguageCollection.getLanguage(context, langId);
if (lang == null || errorType.equals(InvalidLanguageException.class.getSimpleName())) {
message = resources.getString(R.string.add_word_invalid_language);
@ -180,7 +182,7 @@ public class DictionaryLoadingBar {
message = resources.getString(R.string.dictionary_load_error, lang.getName(), errorType);
}
title = generateTitle(-1);
title = generateTitle(context, -1);
progress = maxProgress = 0;
renderError();

View file

@ -1,5 +1,6 @@
package io.github.sspanak.tt9.ui;
import android.app.AlertDialog;
import android.content.Context;
import android.content.Intent;
import android.os.Looper;
@ -27,6 +28,15 @@ public class UI {
tt9.startActivity(prefIntent);
}
public static void alert(Context context, int titleResource, int messageResource) {
new AlertDialog.Builder(context)
.setTitle(titleResource)
.setMessage(messageResource)
.setCancelable(false)
.setPositiveButton(android.R.string.ok, (dialog, which) -> dialog.cancel())
.show();
}
public static void toast(Context context, CharSequence msg) {
Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();
}

View file

@ -89,7 +89,7 @@ public class SoftNumberKey extends SoftKey {
}
// 2-9
Language language = LanguageCollection.getLanguage(tt9.getSettings().getInputLanguage());
Language language = LanguageCollection.getLanguage(tt9.getApplicationContext(), tt9.getSettings().getInputLanguage());
if (language == null) {
Logger.d("SoftNumberKey.getLabel", "Cannot generate a label when the language is NULL.");
return "";