From 6756de44662ad31947dc4ba193401cdf94b8bb7c Mon Sep 17 00:00:00 2001 From: Dimo Karaivanov Date: Mon, 26 Jun 2023 15:14:22 +0300 Subject: [PATCH] YAML language definitions (#292) --- .github/workflows/build.yml | 2 +- CONTRIBUTING.md | 12 +- README.md | 4 +- .../definitions/BrazilianPortuguese.yml | 15 +++ assets/languages/definitions/Bulgarian.yml | 14 ++ assets/languages/definitions/Dutch.yml | 14 ++ assets/languages/definitions/English.yml | 14 ++ assets/languages/definitions/Finnish.yml | 14 ++ assets/languages/definitions/French.yml | 14 ++ assets/languages/definitions/German.yml | 14 ++ assets/languages/definitions/Hebrew.yml | 16 +++ assets/languages/definitions/Indonesian.yml | 15 +++ assets/languages/definitions/Italian.yml | 14 ++ assets/languages/definitions/Norwegian.yml | 14 ++ assets/languages/definitions/Polish.yml | 14 ++ assets/languages/definitions/Russian.yml | 14 ++ assets/languages/definitions/Spanish.yml | 14 ++ assets/languages/definitions/Swedish.yml | 14 ++ assets/languages/definitions/Ukrainian.yml | 14 ++ assets/languages/definitions/Yiddish.yml | 16 +++ .../{ => languages/dictionaries}/bg-utf8.csv | 0 .../{ => languages/dictionaries}/de-utf8.csv | 0 .../{ => languages/dictionaries}/en-utf8.csv | 0 .../{ => languages/dictionaries}/es-utf8.csv | 0 .../{ => languages/dictionaries}/fi-utf8.csv | 0 .../{ => languages/dictionaries}/fr-utf8.csv | 0 .../{ => languages/dictionaries}/he-utf8.csv | 0 .../{ => languages/dictionaries}/id-utf8.csv | 0 .../{ => languages/dictionaries}/it-utf8.csv | 0 .../{ => languages/dictionaries}/ji-utf8.csv | 0 .../{ => languages/dictionaries}/nb-utf8.csv | 0 .../{ => languages/dictionaries}/nl-utf8.csv | 0 .../{ => languages/dictionaries}/pl-utf8.csv | 0 .../dictionaries}/pt-BR-utf8.csv | 0 .../{ => languages/dictionaries}/ru-utf8.csv | 0 .../{ => languages/dictionaries}/sv-utf8.csv | 0 .../{ => languages/dictionaries}/uk-utf8.csv | 0 build.gradle | 123 +++++++++++++++--- proguard-project.txt | 14 +- res/values-bg/strings.xml | 6 +- res/values-de/strings.xml | 2 + res/values-es/strings.xml | 2 + res/values-fr/strings.xml | 6 +- res/values-it/strings.xml | 2 + res/values-iw/strings.xml | 2 + res/values-nl/strings.xml | 2 + res/values-pt-rBR/strings.xml | 2 + res/values-ru/strings.xml | 6 +- res/values-uk/strings.xml | 6 +- res/values/strings.xml | 4 + .../sspanak/tt9/db/migrations/DB11.java | 34 +++-- .../github/sspanak/tt9/db/migrations/DB7.java | 43 +++--- .../github/sspanak/tt9/db/room/TT9Room.java | 2 +- .../sspanak/tt9/ime/EmptyDatabaseWarning.java | 2 +- .../github/sspanak/tt9/ime/TraditionalT9.java | 8 +- .../tt9/ime/helpers/InputModeValidator.java | 14 +- .../github/sspanak/tt9/ime/modes/ModeABC.java | 3 +- .../sspanak/tt9/languages/Language.java | 92 +++++++++++-- .../tt9/languages/LanguageCollection.java | 84 +++++------- .../tt9/languages/LanguageDefinition.java | 47 +++++++ .../sspanak/tt9/languages/NullLanguage.java | 15 +++ .../definitions/BrazilianPortuguese.java | 20 --- .../tt9/languages/definitions/Bulgarian.java | 28 ---- .../tt9/languages/definitions/Dutch.java | 19 --- .../tt9/languages/definitions/English.java | 28 ---- .../tt9/languages/definitions/Finnish.java | 16 --- .../tt9/languages/definitions/French.java | 20 --- .../tt9/languages/definitions/German.java | 17 --- .../tt9/languages/definitions/Hebrew.java | 31 ----- .../tt9/languages/definitions/Indonesian.java | 13 -- .../tt9/languages/definitions/Italian.java | 19 --- .../tt9/languages/definitions/Norwegian.java | 18 --- .../tt9/languages/definitions/Polish.java | 20 --- .../tt9/languages/definitions/Russian.java | 28 ---- .../tt9/languages/definitions/Spanish.java | 25 ---- .../tt9/languages/definitions/Swedish.java | 17 --- .../tt9/languages/definitions/Ukrainian.java | 28 ---- .../tt9/languages/definitions/Yiddish.java | 12 -- .../tt9/preferences/PreferencesActivity.java | 2 +- .../tt9/preferences/SettingsStore.java | 8 +- .../tt9/preferences/items/ItemClickable.java | 2 +- .../preferences/items/ItemLoadDictionary.java | 4 +- .../preferences/items/ItemSelectLanguage.java | 16 ++- .../items/ItemTruncateUnselected.java | 2 +- .../screens/DictionariesScreen.java | 1 + src/io/github/sspanak/tt9/ui/AddWordAct.java | 2 +- .../sspanak/tt9/ui/DictionaryLoadingBar.java | 20 +-- src/io/github/sspanak/tt9/ui/UI.java | 10 ++ .../tt9/ui/main/keys/SoftNumberKey.java | 2 +- 89 files changed, 689 insertions(+), 522 deletions(-) create mode 100644 assets/languages/definitions/BrazilianPortuguese.yml create mode 100644 assets/languages/definitions/Bulgarian.yml create mode 100644 assets/languages/definitions/Dutch.yml create mode 100644 assets/languages/definitions/English.yml create mode 100644 assets/languages/definitions/Finnish.yml create mode 100644 assets/languages/definitions/French.yml create mode 100644 assets/languages/definitions/German.yml create mode 100644 assets/languages/definitions/Hebrew.yml create mode 100644 assets/languages/definitions/Indonesian.yml create mode 100644 assets/languages/definitions/Italian.yml create mode 100644 assets/languages/definitions/Norwegian.yml create mode 100644 assets/languages/definitions/Polish.yml create mode 100644 assets/languages/definitions/Russian.yml create mode 100644 assets/languages/definitions/Spanish.yml create mode 100644 assets/languages/definitions/Swedish.yml create mode 100644 assets/languages/definitions/Ukrainian.yml create mode 100644 assets/languages/definitions/Yiddish.yml rename assets/{ => languages/dictionaries}/bg-utf8.csv (100%) rename assets/{ => languages/dictionaries}/de-utf8.csv (100%) rename assets/{ => languages/dictionaries}/en-utf8.csv (100%) rename assets/{ => languages/dictionaries}/es-utf8.csv (100%) rename assets/{ => languages/dictionaries}/fi-utf8.csv (100%) rename assets/{ => languages/dictionaries}/fr-utf8.csv (100%) rename assets/{ => languages/dictionaries}/he-utf8.csv (100%) rename assets/{ => languages/dictionaries}/id-utf8.csv (100%) rename assets/{ => languages/dictionaries}/it-utf8.csv (100%) rename assets/{ => languages/dictionaries}/ji-utf8.csv (100%) rename assets/{ => languages/dictionaries}/nb-utf8.csv (100%) rename assets/{ => languages/dictionaries}/nl-utf8.csv (100%) rename assets/{ => languages/dictionaries}/pl-utf8.csv (100%) rename assets/{ => languages/dictionaries}/pt-BR-utf8.csv (100%) rename assets/{ => languages/dictionaries}/ru-utf8.csv (100%) rename assets/{ => languages/dictionaries}/sv-utf8.csv (100%) rename assets/{ => languages/dictionaries}/uk-utf8.csv (100%) create mode 100644 src/io/github/sspanak/tt9/languages/LanguageDefinition.java create mode 100644 src/io/github/sspanak/tt9/languages/NullLanguage.java delete mode 100644 src/io/github/sspanak/tt9/languages/definitions/BrazilianPortuguese.java delete mode 100644 src/io/github/sspanak/tt9/languages/definitions/Bulgarian.java delete mode 100644 src/io/github/sspanak/tt9/languages/definitions/Dutch.java delete mode 100644 src/io/github/sspanak/tt9/languages/definitions/English.java delete mode 100644 src/io/github/sspanak/tt9/languages/definitions/Finnish.java delete mode 100644 src/io/github/sspanak/tt9/languages/definitions/French.java delete mode 100644 src/io/github/sspanak/tt9/languages/definitions/German.java delete mode 100644 src/io/github/sspanak/tt9/languages/definitions/Hebrew.java delete mode 100644 src/io/github/sspanak/tt9/languages/definitions/Indonesian.java delete mode 100644 src/io/github/sspanak/tt9/languages/definitions/Italian.java delete mode 100644 src/io/github/sspanak/tt9/languages/definitions/Norwegian.java delete mode 100644 src/io/github/sspanak/tt9/languages/definitions/Polish.java delete mode 100644 src/io/github/sspanak/tt9/languages/definitions/Russian.java delete mode 100644 src/io/github/sspanak/tt9/languages/definitions/Spanish.java delete mode 100644 src/io/github/sspanak/tt9/languages/definitions/Swedish.java delete mode 100644 src/io/github/sspanak/tt9/languages/definitions/Ukrainian.java delete mode 100644 src/io/github/sspanak/tt9/languages/definitions/Yiddish.java diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 08e81b4e..15f3a86a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -25,7 +25,7 @@ jobs: # validation - name: Validate Dictionaries - run: ./gradlew validateDictionaries + run: ./gradlew validateLanguages - name: Lint run: ./gradlew lint - name: Build Release APK diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c9496c2f..4e461ad3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -48,17 +48,15 @@ Make sure you have a signing key. If you don't have one, follow the [official ma ## Adding a New Language To support a new language one needs to: -- Find a suitable dictionary and add it to the `assets/` folder. Two file formats are supported, [see below](#dictionary-formats). +- Find a suitable dictionary and add it to the `assets/languages/dictionaries/` folder. Two file formats are supported, [see below](#dictionary-formats). - Do not forget to include the dictionary license (or readme) file in the `docs/` folder. -- Create a new language class in `languages/definitions/` and define its properties. +- Create a new `.yml` file in `assets/languages/definitions/` and define the language properties. - `locale` contains the language and the country codes (e.g. "en-US", "es-AR", "it-IT"). Refer to the list of [supported locales in Java](https://www.oracle.com/java/technologies/javase/jdk8-jre8-suported-locales.html#util-text). - - `dictionaryFile` is the name of the dictionary in `assets/` folder. - - `characterMap` contains the letters and punctuation marks associated with each key. + - `dictionaryFile` is the name of the dictionary in `assets/languages/dictionaries/` folder. + - `layout` contains the letters and punctuation marks associated with each key. For 0-key and 1-key using `[DEFAULT]`, will be fine for most languages. However, if the language has extra punctuation marks, like Spanish, you could complement the list: `[DEFAULT, ¡, ¿]` - `abcString` _(optional)_. A custom string to display in ABC mode. By default, the first three letters on 2-key are used (e.g. "ABC" or "АБВ"). Set this if the first letters of the alphabet are _not_ on 2-key, like in Hebrew, or if a different string makes more sense. - - `hasUpperCase` _(optional)_ set to `false` when the language has no upper- and lowercase letters. For example: Arabic, Hebrew, East Asian languages, and so on. The default is `true`. + - `hasUpperCase` _(optional)_ set to `no` when the language has no upper- and lowercase letters. For example: Arabic, Hebrew, East Asian languages, and so on. The default is `yes`. - `name` _(optional)_ is automatically generated and equals the native name of the language (e.g. "English", "Deutsch", "Українська"). However, sometimes, the automatically selected name may be ambiguous. For example, both Portuguese in Portugal and Brazil will default to "Português", so assigning "Português brasileiro" would make it clear it's the language used in Brazil. -- Finally, add the new language to the list in `LanguageCollection.java`. You only need to add it in one place, in the constructor. Please, be nice and maintain the alphabetical order. - ### Dictionary Formats diff --git a/README.md b/README.md index 65ccc47f..6302c841 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # Traditional T9 -TT9 is an IME (Input Method Editor) for Android devices with a hardware keypad. It supports [multiple languages](src/io/github/sspanak/tt9/languages/definitions) and predictive text typing. +TT9 is an IME (Input Method Editor) for Android devices with a hardware keypad. It supports [multiple languages](assets/languages/definitions) and predictive text typing. This is an updated version of the [original project](https://github.com/Clam-/TraditionalT9) by Clam-. @@ -36,7 +36,7 @@ If you like Traditional T9, buy me a beer. Donations are currently accepted on [ ## License - The source code, the logo image and the icons are licensed under the conditions described in [LICENSE.txt](LICENSE.txt). -- The dictionaries are licensed under the licenses provided in the [respective readme files](docs/dictionaries/), where applicable. Detailed information about the dictionaries is also available there. +- The dictionaries are licensed under the licenses provided in the [respective readme files](docs/dictionaries), where applicable. Detailed information about the dictionaries is also available there. - [Silver foil photo created by rawpixel.com - www.freepik.com](https://www.freepik.com/photos/silver-foil) - "Negotiate" and "Vibrocentric" fonts are under [The Fontspring Desktop/Ebook Font End User License](docs/desktop-ebook-EULA-1.8.txt). diff --git a/assets/languages/definitions/BrazilianPortuguese.yml b/assets/languages/definitions/BrazilianPortuguese.yml new file mode 100644 index 00000000..53d1e464 --- /dev/null +++ b/assets/languages/definitions/BrazilianPortuguese.yml @@ -0,0 +1,15 @@ +--- +locale: pt-BR +dictionaryFile: pt-BR-utf8.csv +name: Português brasileiro +layout: + - [DEFAULT] # 0 + - [DEFAULT] # 1 + - [a, b, c, ç, á, â, ã, à] # 2 + - [d, e, f, é, ê, è] # 3 + - [g, h, i, í] # 4 + - [j, k, l] # 5 + - [m, n, o, ó, ô, õ] # 6 + - [p, q, r, s] # 7 + - [t, u, v, ú] # 8 + - [w, x, y, z] # 9 \ No newline at end of file diff --git a/assets/languages/definitions/Bulgarian.yml b/assets/languages/definitions/Bulgarian.yml new file mode 100644 index 00000000..3b22414e --- /dev/null +++ b/assets/languages/definitions/Bulgarian.yml @@ -0,0 +1,14 @@ +--- +locale: bg-BG +dictionaryFile: bg-utf8.csv +layout: + - [DEFAULT] # 0 + - [DEFAULT] # 1 + - [а, б, в, г] # 2 + - [д, е, ж, з] # 3 + - [и, й, к, л, ѝ] # 4 + - [м, н, о, п] # 5 + - [р, с, т, у] # 6 + - [ф, х, ц, ч] # 7 + - [ш, щ, ъ] # 8 + - [ь, ю, я] # 9 \ No newline at end of file diff --git a/assets/languages/definitions/Dutch.yml b/assets/languages/definitions/Dutch.yml new file mode 100644 index 00000000..e64ae6a5 --- /dev/null +++ b/assets/languages/definitions/Dutch.yml @@ -0,0 +1,14 @@ +--- +locale: nl-NL +dictionaryFile: nl-utf8.csv +layout: + - [DEFAULT] # 0 + - [DEFAULT] # 1 + - [a, b, c, à, ä, ç] # 2 + - [d, e, f, é, è, ê, ë] # 3 + - [g, h, i, î, ï] # 4 + - [j, k, l] # 5 + - [m, n, o, ö] # 6 + - [p, q, r, s] # 7 + - [t, u, v, û, ü] # 8 + - [w, x, y, z] # 9 \ No newline at end of file diff --git a/assets/languages/definitions/English.yml b/assets/languages/definitions/English.yml new file mode 100644 index 00000000..c5644254 --- /dev/null +++ b/assets/languages/definitions/English.yml @@ -0,0 +1,14 @@ +--- +locale: en +dictionaryFile: en-utf8.csv +layout: + - [DEFAULT] # 0 + - [DEFAULT] # 1 + - [a, b, c] # 2 + - [d, e, f] # 3 + - [g, h, i] # 4 + - [j, k, l] # 5 + - [m, n, o] # 6 + - [p, q, r, s] # 7 + - [t, u, v] # 8 + - [w, x, y, z] # 9 \ No newline at end of file diff --git a/assets/languages/definitions/Finnish.yml b/assets/languages/definitions/Finnish.yml new file mode 100644 index 00000000..c84c0b38 --- /dev/null +++ b/assets/languages/definitions/Finnish.yml @@ -0,0 +1,14 @@ +--- +locale: fi-FI +dictionaryFile: fi-utf8.csv +layout: + - [DEFAULT] # 0 + - [DEFAULT] # 1 + - [a, b, c, ä, å] # 2 + - [d, e, f] # 3 + - [g, h, i] # 4 + - [j, k, l] # 5 + - [m, n, o, ö] # 6 + - [p, q, r, s] # 7 + - [t, u, v] # 8 + - [w, x, y, z] # 9 \ No newline at end of file diff --git a/assets/languages/definitions/French.yml b/assets/languages/definitions/French.yml new file mode 100644 index 00000000..af3fbdfb --- /dev/null +++ b/assets/languages/definitions/French.yml @@ -0,0 +1,14 @@ +--- +locale: fr +dictionaryFile: fr-utf8.csv +layout: + - [DEFAULT] # 0 + - [DEFAULT] # 1 + - [a, b, c, à, â, æ, ç] # 2 + - [d, e, f, é, è, ê, ë] # 3 + - [g, h, i, î, ï] # 4 + - [j, k, l] # 5 + - [m, n, o, ô, œ] # 6 + - [p, q, r, s] # 7 + - [t, u, v, ù, û, ü] # 8 + - [w, x, y, z, ÿ] # 9 \ No newline at end of file diff --git a/assets/languages/definitions/German.yml b/assets/languages/definitions/German.yml new file mode 100644 index 00000000..6cc4eb2b --- /dev/null +++ b/assets/languages/definitions/German.yml @@ -0,0 +1,14 @@ +--- +locale: de +dictionaryFile: de-utf8.csv +layout: + - [DEFAULT] # 0 + - [DEFAULT] # 1 + - [a, b, c, ä] # 2 + - [d, e, f] # 3 + - [g, h, i] # 4 + - [j, k, l] # 5 + - [m, n, o, ö] # 6 + - [p, q, r, s, ß] # 7 + - [t, u, v, ü] # 8 + - [w, x, y, z] # 9 \ No newline at end of file diff --git a/assets/languages/definitions/Hebrew.yml b/assets/languages/definitions/Hebrew.yml new file mode 100644 index 00000000..950b0f97 --- /dev/null +++ b/assets/languages/definitions/Hebrew.yml @@ -0,0 +1,16 @@ +--- +locale: iw-IL +dictionaryFile: he-utf8.csv +abcString: אבג +hasUpperCase: no +layout: + - [DEFAULT] # 0 + - [DEFAULT] # 1 + - [ד, ה, ו] # 2 + - [א, ב, ג] # 3 + - [מ, ם, נ, ן] # 4 + - [י, כ, ך, ל] # 5 + - [ז, ח, ט] # 6 + - [ר, ש, ת] # 7 + - [צ, ץ, ק] # 8 + - [ס, ע, פ, ף] # 9 \ No newline at end of file diff --git a/assets/languages/definitions/Indonesian.yml b/assets/languages/definitions/Indonesian.yml new file mode 100644 index 00000000..218e8ded --- /dev/null +++ b/assets/languages/definitions/Indonesian.yml @@ -0,0 +1,15 @@ +--- +locale: in-ID +dictionaryFile: id-utf8.csv +name: Bahasa Indonesia +layout: + - [DEFAULT] # 0 + - [DEFAULT] # 1 + - [a, b, c] # 2 + - [d, e, f] # 3 + - [g, h, i] # 4 + - [j, k, l] # 5 + - [m, n, o] # 6 + - [p, q, r, s] # 7 + - [t, u, v] # 8 + - [w, x, y, z] # 9 \ No newline at end of file diff --git a/assets/languages/definitions/Italian.yml b/assets/languages/definitions/Italian.yml new file mode 100644 index 00000000..ee3c8cab --- /dev/null +++ b/assets/languages/definitions/Italian.yml @@ -0,0 +1,14 @@ +--- +locale: it +dictionaryFile: it-utf8.csv +layout: + - [DEFAULT] # 0 + - [DEFAULT] # 1 + - [a, b, c, à] # 2 + - [d, e, f, é, è] # 3 + - [g, h, i, ì, í, î] # 4 + - [j, k, l] # 5 + - [m, n, o, ò, ó] # 6 + - [p, q, r, s] # 7 + - [t, u, v, ù, ú] # 8 + - [w, x, y, z] # 9 \ No newline at end of file diff --git a/assets/languages/definitions/Norwegian.yml b/assets/languages/definitions/Norwegian.yml new file mode 100644 index 00000000..51f6c187 --- /dev/null +++ b/assets/languages/definitions/Norwegian.yml @@ -0,0 +1,14 @@ +--- +locale: nb-NO +dictionaryFile: nb-utf8.csv +layout: + - [DEFAULT] # 0 + - [DEFAULT] # 1 + - [a, b, c, æ, å] # 2 + - [d, e, f, é, è] # 3 + - [g, h, i] # 4 + - [j, k, l] # 5 + - [m, n, o, ø, ó, ò, ô] # 6 + - [p, q, r, s] # 7 + - [t, u, v, ü] # 8 + - [w, x, y, z] # 9 \ No newline at end of file diff --git a/assets/languages/definitions/Polish.yml b/assets/languages/definitions/Polish.yml new file mode 100644 index 00000000..f11f5ff1 --- /dev/null +++ b/assets/languages/definitions/Polish.yml @@ -0,0 +1,14 @@ +--- +locale: pl-PL +dictionaryFile: pl-utf8.csv +layout: + - [DEFAULT] # 0 + - [DEFAULT] # 1 + - [a, b, c, ą, ć] # 2 + - [d, e, f, ę] # 3 + - [g, h, i] # 4 + - [j, k, l, ł] # 5 + - [m, n, o, ó, ń] # 6 + - [p, q, r, s, ś] # 7 + - [t, u, v] # 8 + - [w, x, y, z, ź, ż] # 9 \ No newline at end of file diff --git a/assets/languages/definitions/Russian.yml b/assets/languages/definitions/Russian.yml new file mode 100644 index 00000000..3b649e2f --- /dev/null +++ b/assets/languages/definitions/Russian.yml @@ -0,0 +1,14 @@ +--- +locale: ru-RU +dictionaryFile: ru-utf8.csv +layout: + - [DEFAULT] # 0 + - [DEFAULT] # 1 + - [а, б, в, г] # 2 + - [д, е, ё, ж, з] # 3 + - [и, й, к, л] # 4 + - [м, н, о, п] # 5 + - [р, с, т, у] # 6 + - [ф, х, ц, ч] # 7 + - [ш, щ, ъ, ы] # 8 + - [ь, э, ю, я] # 9 \ No newline at end of file diff --git a/assets/languages/definitions/Spanish.yml b/assets/languages/definitions/Spanish.yml new file mode 100644 index 00000000..e817e599 --- /dev/null +++ b/assets/languages/definitions/Spanish.yml @@ -0,0 +1,14 @@ +--- +locale: es-ES +dictionaryFile: es-utf8.csv +layout: + - [DEFAULT] # 0 + - [DEFAULT, ¡, ¿] # 1 + - [a, b, c, á] # 2 + - [d, e, f, é] # 3 + - [g, h, i, í] # 4 + - [j, k, l] # 5 + - [m, n, ñ, o, ó] # 6 + - [p, q, r, s] # 7 + - [t, u, v, ú, ü] # 8 + - [w, x, y, z] # 9 \ No newline at end of file diff --git a/assets/languages/definitions/Swedish.yml b/assets/languages/definitions/Swedish.yml new file mode 100644 index 00000000..9a498f71 --- /dev/null +++ b/assets/languages/definitions/Swedish.yml @@ -0,0 +1,14 @@ +--- +locale: sv-SE +dictionaryFile: sv-utf8.csv +layout: + - [DEFAULT] # 0 + - [DEFAULT] # 1 + - [a, b, c, å, ä] # 2 + - [d, e, f, é] # 3 + - [g, h, i] # 4 + - [j, k, l] # 5 + - [m, n, o, ö] # 6 + - [p, q, r, s] # 7 + - [t, u, v] # 8 + - [w, x, y, z] # 9 \ No newline at end of file diff --git a/assets/languages/definitions/Ukrainian.yml b/assets/languages/definitions/Ukrainian.yml new file mode 100644 index 00000000..5531d3a6 --- /dev/null +++ b/assets/languages/definitions/Ukrainian.yml @@ -0,0 +1,14 @@ +--- +locale: uk-UA +dictionaryFile: uk-utf8.csv +layout: + - [DEFAULT] # 0 + - [DEFAULT] # 1 + - [а, б, в, г, ґ] # 2 + - [д, е, є, ж, з] # 3 + - [и, і, ї, й, к, л] # 4 + - [м, н, о, п] # 5 + - [р, с, т, у] # 6 + - [ф, х, ц, ч] # 7 + - [ш, щ] # 8 + - [ь, ю, я] # 9 \ No newline at end of file diff --git a/assets/languages/definitions/Yiddish.yml b/assets/languages/definitions/Yiddish.yml new file mode 100644 index 00000000..f3eddf8a --- /dev/null +++ b/assets/languages/definitions/Yiddish.yml @@ -0,0 +1,16 @@ +--- +locale: ji-JI +dictionaryFile: ji-utf8.csv +abcString: אבג +hasUpperCase: no +layout: + - [DEFAULT] # 0 + - [DEFAULT] # 1 + - [ד, ה, ו] # 2 + - [א, ב, ג] # 3 + - [מ, ם, נ, ן] # 4 + - [י, כ, ך, ל] # 5 + - [ז, ח, ט] # 6 + - [ר, ש, ת] # 7 + - [צ, ץ, ק] # 8 + - [ס, ע, פ, ף] # 9 \ No newline at end of file diff --git a/assets/bg-utf8.csv b/assets/languages/dictionaries/bg-utf8.csv similarity index 100% rename from assets/bg-utf8.csv rename to assets/languages/dictionaries/bg-utf8.csv diff --git a/assets/de-utf8.csv b/assets/languages/dictionaries/de-utf8.csv similarity index 100% rename from assets/de-utf8.csv rename to assets/languages/dictionaries/de-utf8.csv diff --git a/assets/en-utf8.csv b/assets/languages/dictionaries/en-utf8.csv similarity index 100% rename from assets/en-utf8.csv rename to assets/languages/dictionaries/en-utf8.csv diff --git a/assets/es-utf8.csv b/assets/languages/dictionaries/es-utf8.csv similarity index 100% rename from assets/es-utf8.csv rename to assets/languages/dictionaries/es-utf8.csv diff --git a/assets/fi-utf8.csv b/assets/languages/dictionaries/fi-utf8.csv similarity index 100% rename from assets/fi-utf8.csv rename to assets/languages/dictionaries/fi-utf8.csv diff --git a/assets/fr-utf8.csv b/assets/languages/dictionaries/fr-utf8.csv similarity index 100% rename from assets/fr-utf8.csv rename to assets/languages/dictionaries/fr-utf8.csv diff --git a/assets/he-utf8.csv b/assets/languages/dictionaries/he-utf8.csv similarity index 100% rename from assets/he-utf8.csv rename to assets/languages/dictionaries/he-utf8.csv diff --git a/assets/id-utf8.csv b/assets/languages/dictionaries/id-utf8.csv similarity index 100% rename from assets/id-utf8.csv rename to assets/languages/dictionaries/id-utf8.csv diff --git a/assets/it-utf8.csv b/assets/languages/dictionaries/it-utf8.csv similarity index 100% rename from assets/it-utf8.csv rename to assets/languages/dictionaries/it-utf8.csv diff --git a/assets/ji-utf8.csv b/assets/languages/dictionaries/ji-utf8.csv similarity index 100% rename from assets/ji-utf8.csv rename to assets/languages/dictionaries/ji-utf8.csv diff --git a/assets/nb-utf8.csv b/assets/languages/dictionaries/nb-utf8.csv similarity index 100% rename from assets/nb-utf8.csv rename to assets/languages/dictionaries/nb-utf8.csv diff --git a/assets/nl-utf8.csv b/assets/languages/dictionaries/nl-utf8.csv similarity index 100% rename from assets/nl-utf8.csv rename to assets/languages/dictionaries/nl-utf8.csv diff --git a/assets/pl-utf8.csv b/assets/languages/dictionaries/pl-utf8.csv similarity index 100% rename from assets/pl-utf8.csv rename to assets/languages/dictionaries/pl-utf8.csv diff --git a/assets/pt-BR-utf8.csv b/assets/languages/dictionaries/pt-BR-utf8.csv similarity index 100% rename from assets/pt-BR-utf8.csv rename to assets/languages/dictionaries/pt-BR-utf8.csv diff --git a/assets/ru-utf8.csv b/assets/languages/dictionaries/ru-utf8.csv similarity index 100% rename from assets/ru-utf8.csv rename to assets/languages/dictionaries/ru-utf8.csv diff --git a/assets/sv-utf8.csv b/assets/languages/dictionaries/sv-utf8.csv similarity index 100% rename from assets/sv-utf8.csv rename to assets/languages/dictionaries/sv-utf8.csv diff --git a/assets/uk-utf8.csv b/assets/languages/dictionaries/uk-utf8.csv similarity index 100% rename from assets/uk-utf8.csv rename to assets/languages/dictionaries/uk-utf8.csv diff --git a/build.gradle b/build.gradle index 6ef5bcdd..e259efb8 100644 --- a/build.gradle +++ b/build.gradle @@ -2,17 +2,26 @@ buildscript { repositories { mavenCentral() google() + maven { + url "https://plugins.gradle.org/m2/" + } } dependencies { classpath 'com.android.tools.build:gradle:8.0.2' + classpath 'gradle.plugin.at.zierler:yaml-validator-plugin:1.5.0' } } apply plugin: 'com.android.application' +apply plugin: 'at.zierler.yamlvalidator' configurations.all { // fixes 'duplicate class error', when using these combine: androidx.core:1.10.1, androidx.preference:1.2.0 and androidx.room:2.5.1 // see: https://stackoverflow.com/questions/75274720/a-failure-occurred-while-executing-appcheckdebugduplicateclasses/75315276#75315276 exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib-jdk8' + + yamlValidator { + searchPaths = ['assets/languages/definitions'] + } } dependencies { @@ -20,11 +29,15 @@ dependencies { implementation 'androidx.preference:preference:1.2.0' implementation 'androidx.room:room-runtime:2.5.1' annotationProcessor 'androidx.room:room-compiler:2.5.1' + implementation 'org.yaml:snakeyaml:2.0' } repositories { mavenCentral() google() + maven { + url "https://plugins.gradle.org/m2/" + } } def execThing ( String cmdStr ) { @@ -86,9 +99,13 @@ def getReleaseVersion = { -> return "${getVersionName()} (${getCurrentGitHash()})" } -task validateDictionaries { - inputs.dir fileTree(dir:'assets', excludes:['dict.properties']) - outputs.file "${project.buildDir}/dict.validation.txt" +task validateLanguages { + final baseDir = "${project.rootDir}/assets/languages" + final definitionsDir = "${baseDir}/definitions" + final dictionariesDir = "${baseDir}/dictionaries" + + inputs.dir fileTree(dir:baseDir, excludes:['dict.properties']) + outputs.file "${project.buildDir}/lang.validation.txt" doLast { final String CSV_DELIMITER = ' ' // TAB @@ -100,19 +117,86 @@ task validateDictionaries { outputs.files.singleFile.text = "" - inputs.getFiles().each {File file -> + fileTree(definitionsDir).getFiles().each { File languageFile -> if (errorCount >= MAX_ERRORS) { return } - println "Validating dictionary: " + file.name + println "Validating language: ${languageFile.name}" - def uniqueWords = [:] - - int lineNumber = 0 boolean isFileValid = true - file.eachLine {line -> + boolean hasLayout = false + boolean isLocaleValid = false + def localeString = '' + def dictionaryFileName = '' + + languageFile.eachLine { line -> + if ( + line.matches("^[a-zA-Z].*") + && !line.startsWith("abcString") + && !line.startsWith("dictionaryFile") + && !line.startsWith("hasUpperCase") + && !line.startsWith("layout") + && !line.startsWith("locale") + && !line.startsWith("name") + ) { + isFileValid = false + def parts = line.split(":") + def property = parts.length > 0 ? parts[0] : line + + errorCount++ + errors += "Language '${languageFile.name}' is invalid. Found unknown property: '${property}'.\n" + } + + if (line.startsWith("hasUpperCase") && !line.endsWith("yes") && !line.endsWith("no")) { + def invalidVal = line.replace("hasUpperCase:", "").trim() + isFileValid = false + errorCount++ + errors += "Language '${languageFile.name}' is invalid. Unrecognized 'hasUpperCase' value: '${invalidVal}'. Only 'yes' and 'no' are allowed.\n" + } + + if (line.startsWith("layout")) { + hasLayout = true + } + + if (line.startsWith("locale")) { + localeString = line.replace("locale:", "").trim() + isLocaleValid = line.matches("^locale:\\s*[a-z]{2}(?:-[A-Z]{2})?") + } + + if (line.startsWith("dictionaryFile")) { + dictionaryFileName = line.replace("dictionaryFile:", "").trim() + } + } + + if (!hasLayout) { + isFileValid = false + errorCount++ + errors += "Language '${languageFile.name}' is invalid. Missing 'layout' property.\n" + } + + if (!isLocaleValid) { + isFileValid = false + errorCount++ + def msg = localeString.isEmpty() ? "Missing 'locale' property." : "Unrecognized locale format: '${localeString}'" + errors += "Language '${languageFile.name}' is invalid. ${msg}\n" + } + + def dictionaryFile = new File("$dictionariesDir/${dictionaryFileName}") + if (dictionaryFileName.isEmpty() || !dictionaryFile.exists()) { + errorCount++ + errors += "Could not find dictionary file: '${dictionaryFileName}' in: '${dictionariesDir}'. Make sure 'dictionaryFile' is set correctly in: '${languageFile.name}'.\n" + + outputs.files.singleFile.text += "${languageFile.name} INVALID \n" + return + } + + + def uniqueWords = [:] + int lineNumber = 0 + + dictionaryFile.eachLine {line -> if (errorCount >= MAX_ERRORS) { return } @@ -122,14 +206,14 @@ task validateDictionaries { if (line == "") { isFileValid = false errorCount++ - errors += "Dictionary '" + file.name + "' is invalid. There is no word on line " + lineNumber + ". Remove all empty lines.\n" + errors += "Dictionary '${dictionaryFile.name}' is invalid. There is no word on line ${lineNumber}. Remove all empty lines.\n" return } if (line.contains(" ")) { isFileValid = false errorCount++ - errors += "Dictionary '" + file.name + "' is invalid. Found space on line " + lineNumber + ". Make sure each word is on a new line. Phrases are not allowed.\n" + errors += "Dictionary '${dictionaryFile.name}' is invalid. Found space on line ${lineNumber}. Make sure each word is on a new line. Phrases are not allowed.\n" return } @@ -140,32 +224,32 @@ task validateDictionaries { if (frequency.length() > 0 && !frequency.matches("^\\d+\$")) { isFileValid = false errorCount++ - errors += "Dictionary '" + file.name + "' is invalid. Found out-of-range word frequency: '" + frequency + "' on line " + lineNumber + ". Frequency must be a non-negative integer.\n" + errors += "Dictionary '${dictionaryFile.name}' is invalid. Found out-of-range word frequency: '${frequency}' on line ${lineNumber}. Frequency must be a non-negative integer.\n" } if (word.matches("(\\d.+?|.+?\\d|\\d)")) { isFileValid = false errorCount++ - errors += "Dictionary '" + file.name + "' is invalid. Found numbers on line " + lineNumber + ". Remove all numbers.\n" + errors += "Dictionary '${dictionaryFile.name}' is invalid. Found numbers on line ${lineNumber}. Remove all numbers.\n" } if (word.matches("^\\P{L}+\$")) { isFileValid = false errorCount++ - errors += "Dictionary '" + file.name + "' is invalid. Found a garbage word: '" + word + "' on line " + lineNumber + ".\n" + errors += "Dictionary '${dictionaryFile.name}' is invalid. Found a garbage word: '${word}' on line ${lineNumber}.\n" } if (word.matches("^.\$") && !Character.isUpperCase(word.charAt(0))) { isFileValid = false errorCount++ - errors += "Dictionary '" + file.name + "' is invalid. Found a single letter: '" + word + "' on line " + lineNumber + ". Only uppercase single letters are allowed. The rest of the alphabet will be added automatically.\n" + errors += "Dictionary '${dictionaryFile.name}' is invalid. Found a single letter: '${word}' on line ${lineNumber}. Only uppercase single letters are allowed. The rest of the alphabet will be added automatically.\n" } String uniqueWordKey = word ==~ GEOGRAPHICAL_NAME ? word : word.toLowerCase() if (uniqueWords[uniqueWordKey] != null && uniqueWords[uniqueWordKey] == true) { isFileValid = false errorCount++ - errors += "Dictionary '" + file.name + "' is invalid. Found a repeating word: '" + word + "' on line " + lineNumber + ". Ensure all words appear only once.\n" + errors += "Dictionary '${dictionaryFile.name}' is invalid. Found a repeating word: '${word}' on line ${lineNumber}. Ensure all words appear only once.\n" } else { uniqueWords[uniqueWordKey] = true } @@ -175,7 +259,7 @@ task validateDictionaries { } } - outputs.files.singleFile.text += file.name + " " + (isFileValid ? "OK" : "INVALID") + "\n" + outputs.files.singleFile.text += "${languageFile.name} ${isFileValid ? 'OK' : 'INVALID'}\n" } if (errors != "") { @@ -239,7 +323,10 @@ android { aidl true } + applicationVariants.all { variant -> - tasks["merge${variant.name.capitalize()}Assets"].dependsOn(validateDictionaries) + tasks["merge${variant.name.capitalize()}Assets"] + .dependsOn(validateYaml) + .dependsOn(validateLanguages) } } diff --git a/proguard-project.txt b/proguard-project.txt index 6bc351c9..3d09f0ca 100644 --- a/proguard-project.txt +++ b/proguard-project.txt @@ -19,4 +19,16 @@ # public *; #} --keep class io.github.sspanak.tt9.languages.definitions.** { *; } +# LanguageDefinition properties must be preserved so that SnakeYAML can map them +# to the language YAMLs. +-keepclassmembers class io.github.sspanak.tt9.languages.LanguageDefinition { + public *; +} + +# SnakeYAML shall not complain. As resolved by Mozilla: +# https://github.com/mozilla-mobile/focus-android/blob/main/app/proguard-rules.pro +-dontwarn java.beans.BeanInfo +-dontwarn java.beans.FeatureDescriptor +-dontwarn java.beans.IntrospectionException +-dontwarn java.beans.Introspector +-dontwarn java.beans.PropertyDescriptor diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml index 7c83eb12..6105842a 100644 --- a/res/values-bg/strings.xml +++ b/res/values-bg/strings.xml @@ -2,19 +2,18 @@ Настройки на TT9 Завършено + Няма език Възникна неочаквана грешка. - + Не може да се заредят езиковите дефиниции. Добави Не може да се въведе празна дума. Думата „%1$s“ е вече речника. Добавяне на дума - За приложението Помощ Тъмен облик Езици Изтрий всички - Отмени зареждането Неуспешно зареждане. Невалидна дума „%1$s“ на ред %2$d за език „%3$s“. Несупешно зареждане на речник за език „%1$s“ (%2$s). @@ -69,4 +68,5 @@ Намаляне на звук Усилване на звук Изтриване… + Грешка diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml index 31a922f8..67dafde0 100644 --- a/res/values-de/strings.xml +++ b/res/values-de/strings.xml @@ -1,6 +1,7 @@ TT9 Einstellungen + Keine Sprache Unerwarteter Fehler aufgetreten. Hinzufügen @@ -21,4 +22,5 @@ Leerzeichen Neue Zeile Ersteinrichtung + Fehler diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml index 295920e1..b2a1fa5e 100644 --- a/res/values-es/strings.xml +++ b/res/values-es/strings.xml @@ -5,6 +5,7 @@ Palabra en blanco no agregada. Ayuda Acabado + Sin idioma Ocurrió un error inesperado. La palabra \"%1$s\" ya esta en el diccionario. Agregar palabra @@ -35,4 +36,5 @@ Habilite la configuración si hay 7–8–9 en la primera fila, en lugar de 1–2–3. Configuración inicial Teclado numérico en pantalla + Error diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml index 6b27ab22..97b5f294 100644 --- a/res/values-fr/strings.xml +++ b/res/values-fr/strings.xml @@ -2,19 +2,18 @@ Paramètres de TT9 Fini + Aucun langue Une erreur inattendue s\'est produite. - + Impossible de charger aucune définition de langue Ajouter Mot vide non ajouté. Le mot «%1$s» est déjà dans le dictionnaire. Ajouter un mot - À propos de l\'application Aide Thème sombre Langues Supprimer tous - Annuler le chargement Echec du chargement de dictionnaire pour langue «%1$s» (%2$s). Chargement du dictionnaire terminé. @@ -64,4 +63,5 @@ Configuration initiale Pavé numérique à l\'écran Suppression… + Erreur diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml index f9de5706..3f02c29f 100644 --- a/res/values-it/strings.xml +++ b/res/values-it/strings.xml @@ -2,6 +2,7 @@ TT9 Impostazioni Completato + Nessuna lingua Si è verificato un errore imprevisto. Aggiungere @@ -30,5 +31,6 @@ Invertire l\'ordine delle chiavi Abilita l\'impostazione se ci sono 7–8–9 sulla prima riga, invece di 1–2–3. Configurazione iniziale + Errore diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml index 4e9e7040..03a7c3fd 100644 --- a/res/values-iw/strings.xml +++ b/res/values-iw/strings.xml @@ -2,6 +2,7 @@ TT9 הגדרות הסתיים + אין שפה אירעה שגיאה לא צפויה. הוסף @@ -53,4 +54,5 @@ שורה חדשה רווח + טעות diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml index ac487c57..f86ebca5 100644 --- a/res/values-nl/strings.xml +++ b/res/values-nl/strings.xml @@ -1,6 +1,7 @@ TT9 Opties + Geen taal Er is een onverwachte fout opgetreden. Toevoegen @@ -21,4 +22,5 @@ Nieuwe regel Initiële setup Verwijderen… + Fout diff --git a/res/values-pt-rBR/strings.xml b/res/values-pt-rBR/strings.xml index 12166200..95f729d2 100644 --- a/res/values-pt-rBR/strings.xml +++ b/res/values-pt-rBR/strings.xml @@ -2,6 +2,7 @@ Configurações do Teclado Concluído + Sem idioma Um erro inesperado aconteceu. Adicionar @@ -56,4 +57,5 @@ Utilize essa opção se você possuir as teclas 7–8–9 na linha de cima, ao invés de 1–2–3. Inverter Ordem das Teclas Limpar Não Selecionados + Erro diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml index 59fc9283..af911e78 100644 --- a/res/values-ru/strings.xml +++ b/res/values-ru/strings.xml @@ -2,19 +2,18 @@ TT9 настройки Выполнено + Нет языка Произошла непредвиденная ошибка. - + Не удалось загрузить какое-либо определение языка. Добавить Невозможно добавить слово. Слово «%1$s» уже есть в словаре. Добавить слово - О приложении Помощь Темная тема Языки Удалить все - Отменить загрузку Ошибка загрузки словаря для языка «%1$s» (%2$s). Загрузка словаря завершена. @@ -69,4 +68,5 @@ Уменьшить громкости Увеличить громкости Удаление… + Ошибка diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml index 1ae92200..8ce64ed6 100644 --- a/res/values-uk/strings.xml +++ b/res/values-uk/strings.xml @@ -2,19 +2,18 @@ Налаштування TT9 Зроблено + Немає мови Сталася неочікувана помилка. - + Не вдалося завантажити всі визначення мови. Додати Неможливо додати слово. Слово «%1$s» вже є в словнику. Додати слово - Про додаток Допомога Темна тема Мови Видалити усі - Скасувати завантаження Помилка завантаження словника для мови «%1$s» (%2$s). Завантаження словника завершено. @@ -69,4 +68,5 @@ Збільшення гучності Зменшення гучності Видалення… + Помилка diff --git a/res/values/strings.xml b/res/values/strings.xml index c506fbc6..56659433 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -5,7 +5,11 @@ TT9 TT9 Settings Completed + Error + No Language + Unexpected error occurred. + Failed loading all language definitions. Add Blank word not added. diff --git a/src/io/github/sspanak/tt9/db/migrations/DB11.java b/src/io/github/sspanak/tt9/db/migrations/DB11.java index 3c0f9421..040efcfe 100644 --- a/src/io/github/sspanak/tt9/db/migrations/DB11.java +++ b/src/io/github/sspanak/tt9/db/migrations/DB11.java @@ -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 + ")"; } } diff --git a/src/io/github/sspanak/tt9/db/migrations/DB7.java b/src/io/github/sspanak/tt9/db/migrations/DB7.java index 36b1a5e4..c5b6cc0b 100644 --- a/src/io/github/sspanak/tt9/db/migrations/DB7.java +++ b/src/io/github/sspanak/tt9/db/migrations/DB7.java @@ -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) { diff --git a/src/io/github/sspanak/tt9/db/room/TT9Room.java b/src/io/github/sspanak/tt9/db/room/TT9Room.java index 6f17246d..e3a36212 100644 --- a/src/io/github/sspanak/tt9/db/room/TT9Room.java +++ b/src/io/github/sspanak/tt9/db/room/TT9Room.java @@ -27,7 +27,7 @@ public abstract class TT9Room extends RoomDatabase { DB8.MIGRATION, DB9.MIGRATION, DB10.MIGRATION, - DB11.MIGRATION + new DB11().getMigration(context) ) .build(); } diff --git a/src/io/github/sspanak/tt9/ime/EmptyDatabaseWarning.java b/src/io/github/sspanak/tt9/ime/EmptyDatabaseWarning.java index fbd99392..b2febcf0 100644 --- a/src/io/github/sspanak/tt9/ime/EmptyDatabaseWarning.java +++ b/src/io/github/sspanak/tt9/ime/EmptyDatabaseWarning.java @@ -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); } diff --git a/src/io/github/sspanak/tt9/ime/TraditionalT9.java b/src/io/github/sspanak/tt9/ime/TraditionalT9.java index cf2fa45b..2384b877 100644 --- a/src/io/github/sspanak/tt9/ime/TraditionalT9.java +++ b/src/io/github/sspanak/tt9/ime/TraditionalT9.java @@ -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(); diff --git a/src/io/github/sspanak/tt9/ime/helpers/InputModeValidator.java b/src/io/github/sspanak/tt9/ime/helpers/InputModeValidator.java index 695a279e..55381f61 100644 --- a/src/io/github/sspanak/tt9/ime/helpers/InputModeValidator.java +++ b/src/io/github/sspanak/tt9/ime/helpers/InputModeValidator.java @@ -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 validateEnabledLanguages(ArrayList enabledLanguageIds) { - ArrayList validLanguages = LanguageCollection.getAll(enabledLanguageIds); + public static ArrayList validateEnabledLanguages(Context context, ArrayList enabledLanguageIds) { + ArrayList validLanguages = LanguageCollection.getAll(context, enabledLanguageIds); ArrayList 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 validLanguageIds) { + public static Language validateLanguage(Context context, Language language, ArrayList 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()); diff --git a/src/io/github/sspanak/tt9/ime/modes/ModeABC.java b/src/io/github/sspanak/tt9/ime/modes/ModeABC.java index 26dbced1..1819ec17 100644 --- a/src/io/github/sspanak/tt9/ime/modes/ModeABC.java +++ b/src/io/github/sspanak/tt9/ime/modes/ModeABC.java @@ -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(); diff --git a/src/io/github/sspanak/tt9/languages/Language.java b/src/io/github/sspanak/tt9/languages/Language.java index 7dd8dc46..05400d96 100644 --- a/src/io/github/sspanak/tt9/languages/Language.java +++ b/src/io/github/sspanak/tt9/languages/Language.java @@ -13,12 +13,82 @@ public class Language { protected Locale locale; protected String dictionaryFile; protected String abcString; - protected ArrayList> characterMap = new ArrayList<>(); - private final HashMap reverseCharacterMap = new HashMap<>(); + protected final ArrayList> layout = new ArrayList<>(); + private final HashMap 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 keyCharsFromDefinition(int key, ArrayList definitionChars) { + final String defaultCharsPlaceholder = "DEFAULT"; + + if (key > 1 || !definitionChars.contains(defaultCharsPlaceholder)) { + return definitionChars; + } + + ArrayList 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 getKeyCharacters(int key, boolean includeDigit) { - if (key < 0 || key >= characterMap.size()) { + if (key < 0 || key >= layout.size()) { return new ArrayList<>(); } - ArrayList chars = new ArrayList<>(characterMap.get(key)); + ArrayList 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(); diff --git a/src/io/github/sspanak/tt9/languages/LanguageCollection.java b/src/io/github/sspanak/tt9/languages/LanguageCollection.java index 65193737..dd3feb07 100644 --- a/src/io/github/sspanak/tt9/languages/LanguageCollection.java +++ b/src/io/github/sspanak/tt9/languages/LanguageCollection.java @@ -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 languages = new HashMap<>(); - private LanguageCollection() { - List> 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 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 getAll(ArrayList 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 getAll(Context context, ArrayList languageIds, boolean sort) { ArrayList 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 getAll(ArrayList languageIds) { - return getAll(languageIds, false); + public static ArrayList getAll(Context context, ArrayList languageIds) { + return getAll(context, languageIds, false); } - public static ArrayList getAll(boolean sort) { - ArrayList langList = new ArrayList<>(getInstance().languages.values()); + public static ArrayList getAll(Context context, boolean sort) { + ArrayList 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 getAll() { - return getAll(false); + public static ArrayList getAll(Context context) { + return getAll(context,false); } diff --git a/src/io/github/sspanak/tt9/languages/LanguageDefinition.java b/src/io/github/sspanak/tt9/languages/LanguageDefinition.java new file mode 100644 index 00000000..7606be3a --- /dev/null +++ b/src/io/github/sspanak/tt9/languages/LanguageDefinition.java @@ -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> layout = new ArrayList<>(); + public String locale = ""; + public String name = ""; + + public static ArrayList getAllFiles(AssetManager assets) { + ArrayList 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; + } +} diff --git a/src/io/github/sspanak/tt9/languages/NullLanguage.java b/src/io/github/sspanak/tt9/languages/NullLanguage.java new file mode 100644 index 00000000..0d8cc43f --- /dev/null +++ b/src/io/github/sspanak/tt9/languages/NullLanguage.java @@ -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"; + } +} diff --git a/src/io/github/sspanak/tt9/languages/definitions/BrazilianPortuguese.java b/src/io/github/sspanak/tt9/languages/definitions/BrazilianPortuguese.java deleted file mode 100644 index c57e5373..00000000 --- a/src/io/github/sspanak/tt9/languages/definitions/BrazilianPortuguese.java +++ /dev/null @@ -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("ú"); - } -} diff --git a/src/io/github/sspanak/tt9/languages/definitions/Bulgarian.java b/src/io/github/sspanak/tt9/languages/definitions/Bulgarian.java deleted file mode 100644 index 8be9506a..00000000 --- a/src/io/github/sspanak/tt9/languages/definitions/Bulgarian.java +++ /dev/null @@ -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 - )); - } -} diff --git a/src/io/github/sspanak/tt9/languages/definitions/Dutch.java b/src/io/github/sspanak/tt9/languages/definitions/Dutch.java deleted file mode 100644 index d93e0df1..00000000 --- a/src/io/github/sspanak/tt9/languages/definitions/Dutch.java +++ /dev/null @@ -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("û", "ü")); - } -} diff --git a/src/io/github/sspanak/tt9/languages/definitions/English.java b/src/io/github/sspanak/tt9/languages/definitions/English.java deleted file mode 100644 index cbeeb55f..00000000 --- a/src/io/github/sspanak/tt9/languages/definitions/English.java +++ /dev/null @@ -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 - )); - } -} diff --git a/src/io/github/sspanak/tt9/languages/definitions/Finnish.java b/src/io/github/sspanak/tt9/languages/definitions/Finnish.java deleted file mode 100644 index 2fde36b2..00000000 --- a/src/io/github/sspanak/tt9/languages/definitions/Finnish.java +++ /dev/null @@ -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("ö"); - } -} diff --git a/src/io/github/sspanak/tt9/languages/definitions/French.java b/src/io/github/sspanak/tt9/languages/definitions/French.java deleted file mode 100644 index 50d5918d..00000000 --- a/src/io/github/sspanak/tt9/languages/definitions/French.java +++ /dev/null @@ -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("ÿ"); - } -} diff --git a/src/io/github/sspanak/tt9/languages/definitions/German.java b/src/io/github/sspanak/tt9/languages/definitions/German.java deleted file mode 100644 index 4e30b3e5..00000000 --- a/src/io/github/sspanak/tt9/languages/definitions/German.java +++ /dev/null @@ -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("ü"); - } -} diff --git a/src/io/github/sspanak/tt9/languages/definitions/Hebrew.java b/src/io/github/sspanak/tt9/languages/definitions/Hebrew.java deleted file mode 100644 index 886dcd6f..00000000 --- a/src/io/github/sspanak/tt9/languages/definitions/Hebrew.java +++ /dev/null @@ -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 - )); - } -} diff --git a/src/io/github/sspanak/tt9/languages/definitions/Indonesian.java b/src/io/github/sspanak/tt9/languages/definitions/Indonesian.java deleted file mode 100644 index 45fb772d..00000000 --- a/src/io/github/sspanak/tt9/languages/definitions/Indonesian.java +++ /dev/null @@ -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"; - } -} diff --git a/src/io/github/sspanak/tt9/languages/definitions/Italian.java b/src/io/github/sspanak/tt9/languages/definitions/Italian.java deleted file mode 100644 index 8b77fc46..00000000 --- a/src/io/github/sspanak/tt9/languages/definitions/Italian.java +++ /dev/null @@ -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("ù", "ú")); - } -} diff --git a/src/io/github/sspanak/tt9/languages/definitions/Norwegian.java b/src/io/github/sspanak/tt9/languages/definitions/Norwegian.java deleted file mode 100644 index 84b718e6..00000000 --- a/src/io/github/sspanak/tt9/languages/definitions/Norwegian.java +++ /dev/null @@ -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("ü"); - } -} diff --git a/src/io/github/sspanak/tt9/languages/definitions/Polish.java b/src/io/github/sspanak/tt9/languages/definitions/Polish.java deleted file mode 100644 index 5c26abfa..00000000 --- a/src/io/github/sspanak/tt9/languages/definitions/Polish.java +++ /dev/null @@ -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("ź", "ż")); - } -} diff --git a/src/io/github/sspanak/tt9/languages/definitions/Russian.java b/src/io/github/sspanak/tt9/languages/definitions/Russian.java deleted file mode 100644 index 17c3bb62..00000000 --- a/src/io/github/sspanak/tt9/languages/definitions/Russian.java +++ /dev/null @@ -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 - )); - } -} diff --git a/src/io/github/sspanak/tt9/languages/definitions/Spanish.java b/src/io/github/sspanak/tt9/languages/definitions/Spanish.java deleted file mode 100644 index 9b6ab04f..00000000 --- a/src/io/github/sspanak/tt9/languages/definitions/Spanish.java +++ /dev/null @@ -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("ú", "ü")); - } -} diff --git a/src/io/github/sspanak/tt9/languages/definitions/Swedish.java b/src/io/github/sspanak/tt9/languages/definitions/Swedish.java deleted file mode 100644 index 48bd64ca..00000000 --- a/src/io/github/sspanak/tt9/languages/definitions/Swedish.java +++ /dev/null @@ -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("ö"); - } -} diff --git a/src/io/github/sspanak/tt9/languages/definitions/Ukrainian.java b/src/io/github/sspanak/tt9/languages/definitions/Ukrainian.java deleted file mode 100644 index 2bf14c1e..00000000 --- a/src/io/github/sspanak/tt9/languages/definitions/Ukrainian.java +++ /dev/null @@ -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 - )); - } -} diff --git a/src/io/github/sspanak/tt9/languages/definitions/Yiddish.java b/src/io/github/sspanak/tt9/languages/definitions/Yiddish.java deleted file mode 100644 index 93ba3167..00000000 --- a/src/io/github/sspanak/tt9/languages/definitions/Yiddish.java +++ /dev/null @@ -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"; - } -} diff --git a/src/io/github/sspanak/tt9/preferences/PreferencesActivity.java b/src/io/github/sspanak/tt9/preferences/PreferencesActivity.java index cdb94337..d57b4ca6 100644 --- a/src/io/github/sspanak/tt9/preferences/PreferencesActivity.java +++ b/src/io/github/sspanak/tt9/preferences/PreferencesActivity.java @@ -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); diff --git a/src/io/github/sspanak/tt9/preferences/SettingsStore.java b/src/io/github/sspanak/tt9/preferences/SettingsStore.java index 877e602e..bf7ff4ac 100644 --- a/src/io/github/sspanak/tt9/preferences/SettingsStore.java +++ b/src/io/github/sspanak/tt9/preferences/SettingsStore.java @@ -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 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) { diff --git a/src/io/github/sspanak/tt9/preferences/items/ItemClickable.java b/src/io/github/sspanak/tt9/preferences/items/ItemClickable.java index 38620dde..96c244c9 100644 --- a/src/io/github/sspanak/tt9/preferences/items/ItemClickable.java +++ b/src/io/github/sspanak/tt9/preferences/items/ItemClickable.java @@ -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: ... + * See: ... */ protected boolean debounceClick(Preference p) { long now = System.currentTimeMillis(); diff --git a/src/io/github/sspanak/tt9/preferences/items/ItemLoadDictionary.java b/src/io/github/sspanak/tt9/preferences/items/ItemLoadDictionary.java index 9225a986..7f89a881 100644 --- a/src/io/github/sspanak/tt9/preferences/items/ItemLoadDictionary.java +++ b/src/io/github/sspanak/tt9/preferences/items/ItemLoadDictionary.java @@ -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 languages = LanguageCollection.getAll(settings.getEnabledLanguageIds()); + ArrayList languages = LanguageCollection.getAll(context, settings.getEnabledLanguageIds()); try { loader.load(languages); diff --git a/src/io/github/sspanak/tt9/preferences/items/ItemSelectLanguage.java b/src/io/github/sspanak/tt9/preferences/items/ItemSelectLanguage.java index 56471fb1..169c59d7 100644 --- a/src/io/github/sspanak/tt9/preferences/items/ItemSelectLanguage.java +++ b/src/io/github/sspanak/tt9/preferences/items/ItemSelectLanguage.java @@ -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 languages = LanguageCollection.getAll(true); + ArrayList 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 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)) ); } } diff --git a/src/io/github/sspanak/tt9/preferences/items/ItemTruncateUnselected.java b/src/io/github/sspanak/tt9/preferences/items/ItemTruncateUnselected.java index cd94ef33..366333a9 100644 --- a/src/io/github/sspanak/tt9/preferences/items/ItemTruncateUnselected.java +++ b/src/io/github/sspanak/tt9/preferences/items/ItemTruncateUnselected.java @@ -39,7 +39,7 @@ public class ItemTruncateUnselected extends ItemTruncateAll { ArrayList unselectedLanguageIds = new ArrayList<>(); ArrayList 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()); } diff --git a/src/io/github/sspanak/tt9/preferences/screens/DictionariesScreen.java b/src/io/github/sspanak/tt9/preferences/screens/DictionariesScreen.java index a22bee85..a174d47a 100644 --- a/src/io/github/sspanak/tt9/preferences/screens/DictionariesScreen.java +++ b/src/io/github/sspanak/tt9/preferences/screens/DictionariesScreen.java @@ -17,6 +17,7 @@ public class DictionariesScreen extends BaseScreenFragment { @Override protected void onCreate() { ItemSelectLanguage multiSelect = new ItemSelectLanguage( + activity, findPreference(ItemSelectLanguage.NAME), activity.settings ); diff --git a/src/io/github/sspanak/tt9/ui/AddWordAct.java b/src/io/github/sspanak/tt9/ui/AddWordAct.java index 5357f907..d381701b 100644 --- a/src/io/github/sspanak/tt9/ui/AddWordAct.java +++ b/src/io/github/sspanak/tt9/ui/AddWordAct.java @@ -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); diff --git a/src/io/github/sspanak/tt9/ui/DictionaryLoadingBar.java b/src/io/github/sspanak/tt9/ui/DictionaryLoadingBar.java index fdbd9e4f..2fbec224 100644 --- a/src/io/github/sspanak/tt9/ui/DictionaryLoadingBar.java +++ b/src/io/github/sspanak/tt9/ui/DictionaryLoadingBar.java @@ -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(); diff --git a/src/io/github/sspanak/tt9/ui/UI.java b/src/io/github/sspanak/tt9/ui/UI.java index acb996b1..96a54bd7 100644 --- a/src/io/github/sspanak/tt9/ui/UI.java +++ b/src/io/github/sspanak/tt9/ui/UI.java @@ -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(); } diff --git a/src/io/github/sspanak/tt9/ui/main/keys/SoftNumberKey.java b/src/io/github/sspanak/tt9/ui/main/keys/SoftNumberKey.java index 8c5f9796..ad19c292 100644 --- a/src/io/github/sspanak/tt9/ui/main/keys/SoftNumberKey.java +++ b/src/io/github/sspanak/tt9/ui/main/keys/SoftNumberKey.java @@ -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 "";