Improved db operations and db feedback (#279)
* prevented crashing when database indexes are missing, they are now permanent instead of being created on-the-fly when loading a dictionary * code style fixes in DictionaryDb.java * removed some unused code * counting the dictionaries to be loaded is no longer responsibility of the Load Button, but of the DictionaryLoader * delete dictionary buttons are now being locked while deleting is in progress; also, a status message is displayed for better UX * updated translations and documentation
This commit is contained in:
parent
f92ad96827
commit
c63d054422
19 changed files with 202 additions and 180 deletions
|
|
@ -23,19 +23,19 @@ _If you don't do the above, there will be no suggestions when typing in Predicti
|
|||
### Dictionary Tips
|
||||
|
||||
#### Loading a Dictionary
|
||||
Once a dictionary is loaded, it will stay there until you use one of the "clear" options. This means you can enable and disable languages without reloading their dictionaries every time. Just do it once, only the first time.
|
||||
Once a dictionary is loaded, it will stay there until you use one of the "delete" options. This means you can enable and disable languages without reloading their dictionaries every time. Just do it once, only the first time.
|
||||
|
||||
It also means that if you need to start using language X, you can safely disable all other languages, load only dictionary X (and save time!), then re-enable all languages you used before.
|
||||
|
||||
Have in mind reloading a dictionary will reset the suggestion popularity to the factory defaults _(your custom added words will not be affected)_. However, there should be nothing to worry about. For the most part, you will see little to no difference in the suggestion order, unless you oftenly use uncommon words.
|
||||
|
||||
#### Clearing a Dictionary
|
||||
#### Deleting a Dictionary
|
||||
|
||||
If you have stopped using languages X or Y, you could disable them and also use "Clear Unselected", to delete their dictionaries and free some memory.
|
||||
If you have stopped using languages X or Y, you could disable them and also use "Delete Unselected", to remove their dictionaries and free some memory.
|
||||
|
||||
To delete everything, regardless of the selection, use "Clear All".
|
||||
To delete everything, regardless of the selection, use "Delete All".
|
||||
|
||||
In all cases, clearing a dictionary deletes both all factory and all custom added words.
|
||||
In all cases, deleting a dictionary removes both all factory and all custom added words.
|
||||
|
||||
## Hotkeys
|
||||
|
||||
|
|
|
|||
|
|
@ -64,4 +64,5 @@
|
|||
<string name="pref_show_soft_numpad">Цифрова клавиатура на екрана</string>
|
||||
<string name="key_volume_down">Намаляне на звук</string>
|
||||
<string name="key_volume_up">Усилване на звук</string>
|
||||
<string name="dictionary_truncating">Изтриване…</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
<string name="pref_help">Aide</string>
|
||||
<string name="pref_dark_theme">Thème sombre</string>
|
||||
<string name="pref_choose_languages">Langues</string>
|
||||
<string name="dictionary_truncate_title">Vider tous</string>
|
||||
<string name="dictionary_truncate_title">Supprimer tous</string>
|
||||
|
||||
<string name="dictionary_cancel_load">Annuler le chargement</string>
|
||||
<string name="dictionary_load_error">Echec du chargement de dictionnaire pour langue «%1$s» (%2$s).</string>
|
||||
|
|
@ -25,7 +25,7 @@
|
|||
<string name="pref_category_function_keys">Raccourcis clavier</string>
|
||||
<string name="pref_category_appearance">Apparance</string>
|
||||
<string name="dictionary_load_bad_char">Echec du chargement. Mot inadmissible «%1$s» à la ligne %2$d de langue «%3$s».</string>
|
||||
<string name="dictionary_truncated">Le dictionaire est vidé avec succès.</string>
|
||||
<string name="dictionary_truncated">Le dictionaire est supprimé avec succès.</string>
|
||||
<string name="pref_show_soft_function_keys">Boutons à l\'écran</string>
|
||||
<string name="dictionary_loading_indeterminate">Chargement du dictionnaire</string>
|
||||
<string name="dictionary_load_cancelled">Chargement est annulé.</string>
|
||||
|
|
@ -47,7 +47,8 @@
|
|||
<string name="add_word_field_placeholder">Tapez un mot…</string>
|
||||
<string name="pref_upside_down_keys">Inverser l\'ordre des clés</string>
|
||||
<string name="pref_upside_down_keys_summary">Activez le paramètre s\'il y a 7–8–9 sur le premier rang, au lieu de 1–2–3.</string>
|
||||
<string name="dictionary_truncate_unselected">Vider les non sélectionnés</string>
|
||||
<string name="dictionary_truncate_unselected">Supprimer les non sélectionnés</string>
|
||||
<string name="pref_category_setup">Configuration initiale</string>
|
||||
<string name="pref_show_soft_numpad">Pavé numérique à l\'écran</string>
|
||||
<string name="dictionary_truncating">Suppression…</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -20,4 +20,5 @@
|
|||
<string name="char_space">Spatie</string>
|
||||
<string name="char_newline">Nieuwe regel</string>
|
||||
<string name="pref_category_setup">Initiële setup</string>
|
||||
<string name="dictionary_truncating">Verwijderen…</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
<string name="pref_help">Помощь</string>
|
||||
<string name="pref_dark_theme">Темная тема</string>
|
||||
<string name="pref_choose_languages">Языки</string>
|
||||
<string name="dictionary_truncate_title">Очистить все</string>
|
||||
<string name="dictionary_truncate_title">Удалить все</string>
|
||||
|
||||
<string name="dictionary_cancel_load">Отменить загрузку</string>
|
||||
<string name="dictionary_load_error">Ошибка загрузки словаря для языка «%1$s» (%2$s).</string>
|
||||
|
|
@ -21,7 +21,7 @@
|
|||
<string name="dictionary_loading">Загрузка словаря (%1$s)…</string>
|
||||
<string name="dictionary_load_title">Загрузить словарь</string>
|
||||
<string name="dictionary_not_found">Ошибка загрузки. Словарь «%1$s» не найден.</string>
|
||||
<string name="dictionary_truncated">Словарь успешно очищен.</string>
|
||||
<string name="dictionary_truncated">Словарь успешно удален.</string>
|
||||
<string name="dictionary_loading_indeterminate">Загрузка словаря</string>
|
||||
<string name="dictionary_load_cancelled">Загрузка отменена.</string>
|
||||
<string name="pref_category_predictive_mode">Режим подсказки</string>
|
||||
|
|
@ -59,9 +59,10 @@
|
|||
<string name="add_word_field_placeholder">Введите слово…</string>
|
||||
<string name="pref_upside_down_keys">Перевернутая клавиатура</string>
|
||||
<string name="pref_upside_down_keys_summary">Используйте настройку, если в первом ряду 7–8–9 вместо 1–2–3.</string>
|
||||
<string name="dictionary_truncate_unselected">Очистить невыбранные</string>
|
||||
<string name="dictionary_truncate_unselected">Удалить невыбранные</string>
|
||||
<string name="pref_category_setup">Начальная настройка</string>
|
||||
<string name="pref_show_soft_numpad">Экранная цифровая клавиатура</string>
|
||||
<string name="key_volume_down">Уменьшить громкости</string>
|
||||
<string name="key_volume_up">Увеличить громкости</string>
|
||||
<string name="dictionary_truncating">Удаление…</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
<string name="pref_help">Допомога</string>
|
||||
<string name="pref_dark_theme">Темна тема</string>
|
||||
<string name="pref_choose_languages">Мови</string>
|
||||
<string name="dictionary_truncate_title">Очистіть усі</string>
|
||||
<string name="dictionary_truncate_title">Видалити усі</string>
|
||||
|
||||
<string name="dictionary_cancel_load">Скасувати завантаження</string>
|
||||
<string name="dictionary_load_error">Помилка завантаження словника для мови «%1$s» (%2$s).</string>
|
||||
|
|
@ -53,15 +53,16 @@
|
|||
<string name="function_show_settings_key">Налаштування</string>
|
||||
<string name="function_reset_keys_done">Налаштування кнопок за замовчуванням відновлено</string>
|
||||
<string name="function_reset_keys_title">Повернути кнопки за замовчуванням</string>
|
||||
<string name="dictionary_truncated">Словник успішно очищено.</string>
|
||||
<string name="dictionary_truncated">Словник успішно видалено.</string>
|
||||
<string name="dictionary_missing_go_load_it">Немає словника для мови «%1$s». Перейдіть до Налаштувань, щоб завантажити його.</string>
|
||||
<string name="dictionary_load_bad_char">Помилка завантаження. Недійсне слово «%1$s» в рядку %2$d мови «%3$s».</string>
|
||||
<string name="add_word_field_placeholder">Введіть слово…</string>
|
||||
<string name="pref_upside_down_keys">Зворотна клавіатура</string>
|
||||
<string name="pref_upside_down_keys_summary">Використовуйте налаштування, якщо 7–8–9 у першому рядку замість 1–2–3.</string>
|
||||
<string name="dictionary_truncate_unselected">Очистіть невибрані</string>
|
||||
<string name="dictionary_truncate_unselected">Видалити невибрані</string>
|
||||
<string name="pref_category_setup">Початкове налаштування</string>
|
||||
<string name="pref_show_soft_numpad">Екранна цифрова клавіатура</string>
|
||||
<string name="key_volume_up">Збільшення гучності</string>
|
||||
<string name="key_volume_down">Зменшення гучності</string>
|
||||
<string name="dictionary_truncating">Видалення…</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -49,9 +49,10 @@
|
|||
<string name="dictionary_load_title">Load Dictionary</string>
|
||||
<string name="dictionary_missing_go_load_it">No dictionary for language \"%1$s\". Go to Settings to load it.</string>
|
||||
<string name="dictionary_not_found">Loading failed. Dictionary for \"%1$s\" not found.</string>
|
||||
<string name="dictionary_truncate_title">Clear All</string>
|
||||
<string name="dictionary_truncate_unselected">Clear Unselected</string>
|
||||
<string name="dictionary_truncate_title">Delete All</string>
|
||||
<string name="dictionary_truncate_unselected">Delete Unselected</string>
|
||||
<string name="dictionary_truncated">Dictionary successfully cleared.</string>
|
||||
<string name="dictionary_truncating">Deleting…</string>
|
||||
|
||||
<string name="function_add_word_key">Add Word key</string>
|
||||
<string name="function_backspace_key">Backspace key</string>
|
||||
|
|
|
|||
|
|
@ -70,23 +70,6 @@ public class DictionaryDb {
|
|||
}
|
||||
|
||||
|
||||
public static void createShortWordIndexSync() {
|
||||
getInstance().wordsDao().rawQuery(TT9Room.createShortWordsIndexQuery());
|
||||
}
|
||||
|
||||
public static void createLongWordIndexSync() {
|
||||
getInstance().wordsDao().rawQuery(TT9Room.createLongWordsIndexQuery());
|
||||
}
|
||||
|
||||
public static void dropShortWordIndexSync() {
|
||||
getInstance().wordsDao().rawQuery(TT9Room.dropShortWordsIndexQuery());
|
||||
}
|
||||
|
||||
public static void dropLongWordIndexSync() {
|
||||
getInstance().wordsDao().rawQuery(TT9Room.dropLongWordsIndexQuery());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* normalizeWordFrequencies
|
||||
* Normalizes the word frequencies for all languages that have reached the maximum, as defined in
|
||||
|
|
@ -95,28 +78,26 @@ public class DictionaryDb {
|
|||
*/
|
||||
public static void normalizeWordFrequencies(SettingsStore settings) {
|
||||
new Thread(() -> {
|
||||
long time = System.currentTimeMillis();
|
||||
long time = System.currentTimeMillis();
|
||||
|
||||
int affectedRows = getInstance().wordsDao().normalizeFrequencies(
|
||||
settings.getWordFrequencyNormalizationDivider(),
|
||||
settings.getWordFrequencyMax()
|
||||
);
|
||||
int affectedRows = getInstance().wordsDao().normalizeFrequencies(
|
||||
settings.getWordFrequencyNormalizationDivider(),
|
||||
settings.getWordFrequencyMax()
|
||||
);
|
||||
|
||||
Logger.d(
|
||||
"db.normalizeWordFrequencies",
|
||||
"Normalized " + affectedRows + " words in: " + (System.currentTimeMillis() - time) + " ms"
|
||||
);
|
||||
}
|
||||
).start();
|
||||
Logger.d(
|
||||
"db.normalizeWordFrequencies",
|
||||
"Normalized " + affectedRows + " words in: " + (System.currentTimeMillis() - time) + " ms"
|
||||
);
|
||||
}).start();
|
||||
}
|
||||
|
||||
|
||||
public static void areThereWords(ConsumerCompat<Boolean> notification, Language language) {
|
||||
new Thread(() -> {
|
||||
int langId = language != null ? language.getId() : -1;
|
||||
notification.accept(getInstance().wordsDao().count(langId) > 0);
|
||||
}
|
||||
).start();
|
||||
int langId = language != null ? language.getId() : -1;
|
||||
notification.accept(getInstance().wordsDao().count(langId) > 0);
|
||||
}).start();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -136,14 +117,13 @@ public class DictionaryDb {
|
|||
|
||||
public static void deleteWords(Runnable notification, ArrayList<Integer> languageIds) {
|
||||
new Thread(() -> {
|
||||
if (languageIds == null) {
|
||||
getInstance().clearAllTables();
|
||||
} else if (languageIds.size() > 0) {
|
||||
getInstance().wordsDao().deleteByLanguage(languageIds);
|
||||
}
|
||||
notification.run();
|
||||
if (languageIds == null) {
|
||||
getInstance().clearAllTables();
|
||||
} else if (languageIds.size() > 0) {
|
||||
getInstance().wordsDao().deleteByLanguage(languageIds);
|
||||
}
|
||||
).start();
|
||||
notification.run();
|
||||
}).start();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -164,22 +144,21 @@ public class DictionaryDb {
|
|||
dbWord.frequency = 1;
|
||||
|
||||
new Thread(() -> {
|
||||
try {
|
||||
getInstance().wordsDao().insert(dbWord);
|
||||
getInstance().wordsDao().incrementFrequency(dbWord.langId, dbWord.word, dbWord.sequence);
|
||||
statusHandler.accept(0);
|
||||
} catch (SQLiteConstraintException e) {
|
||||
String msg = "Constraint violation when inserting a word: '" + dbWord.word + "' / sequence: '" + dbWord.sequence + "', for language: " + dbWord.langId
|
||||
+ ". " + e.getMessage();
|
||||
Logger.e("tt9/insertWord", msg);
|
||||
statusHandler.accept(1);
|
||||
} catch (Exception e) {
|
||||
String msg = "Failed inserting word: '" + dbWord.word + "' / sequence: '" + dbWord.sequence + "', for language: " + dbWord.langId + ". " + e.getMessage();
|
||||
Logger.e("tt9/insertWord", msg);
|
||||
statusHandler.accept(2);
|
||||
}
|
||||
try {
|
||||
getInstance().wordsDao().insert(dbWord);
|
||||
getInstance().wordsDao().incrementFrequency(dbWord.langId, dbWord.word, dbWord.sequence);
|
||||
statusHandler.accept(0);
|
||||
} catch (SQLiteConstraintException e) {
|
||||
String msg = "Constraint violation when inserting a word: '" + dbWord.word + "' / sequence: '" + dbWord.sequence + "', for language: " + dbWord.langId
|
||||
+ ". " + e.getMessage();
|
||||
Logger.e("tt9/insertWord", msg);
|
||||
statusHandler.accept(1);
|
||||
} catch (Exception e) {
|
||||
String msg = "Failed inserting word: '" + dbWord.word + "' / sequence: '" + dbWord.sequence + "', for language: " + dbWord.langId + ". " + e.getMessage();
|
||||
Logger.e("tt9/insertWord", msg);
|
||||
statusHandler.accept(2);
|
||||
}
|
||||
).start();
|
||||
}).start();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -207,38 +186,37 @@ public class DictionaryDb {
|
|||
}
|
||||
|
||||
new Thread(() -> {
|
||||
try {
|
||||
int affectedRows = getInstance().wordsDao().incrementFrequency(language.getId(), word, sequence);
|
||||
try {
|
||||
int affectedRows = getInstance().wordsDao().incrementFrequency(language.getId(), word, sequence);
|
||||
|
||||
// In case the user has changed the text case, there would be no match.
|
||||
// Try again with the lowercase equivalent.
|
||||
String lowercaseWord = "";
|
||||
if (affectedRows == 0) {
|
||||
lowercaseWord = word.toLowerCase(language.getLocale());
|
||||
affectedRows = getInstance().wordsDao().incrementFrequency(language.getId(), lowercaseWord, sequence);
|
||||
// In case the user has changed the text case, there would be no match.
|
||||
// Try again with the lowercase equivalent.
|
||||
String lowercaseWord = "";
|
||||
if (affectedRows == 0) {
|
||||
lowercaseWord = word.toLowerCase(language.getLocale());
|
||||
affectedRows = getInstance().wordsDao().incrementFrequency(language.getId(), lowercaseWord, sequence);
|
||||
|
||||
Logger.d("incrementWordFrequency", "Attempting to increment frequency for lowercase variant: " + lowercaseWord);
|
||||
}
|
||||
|
||||
// Some languages permit appending the punctuation to the end of the words, like so: "try,".
|
||||
// But there are no such words in the dictionary, so try without the punctuation mark.
|
||||
if (affectedRows == 0 && language.isPunctuationPartOfWords() && sequence.endsWith("1")) {
|
||||
String truncatedWord = lowercaseWord.substring(0, word.length() - 1);
|
||||
String truncatedSequence = sequence.substring(0, sequence.length() - 1);
|
||||
affectedRows = getInstance().wordsDao().incrementFrequency(language.getId(), truncatedWord, truncatedSequence);
|
||||
|
||||
Logger.d("incrementWordFrequency", "Attempting to increment frequency with stripped punctuation: " + truncatedWord);
|
||||
}
|
||||
|
||||
Logger.d("incrementWordFrequency", "Affected rows: " + affectedRows);
|
||||
} catch (Exception e) {
|
||||
Logger.e(
|
||||
DictionaryDb.class.getName(),
|
||||
"Failed incrementing word frequency. Word: " + word + " | Sequence: " + sequence + ". " + e.getMessage()
|
||||
);
|
||||
Logger.d("incrementWordFrequency", "Attempting to increment frequency for lowercase variant: " + lowercaseWord);
|
||||
}
|
||||
|
||||
// Some languages permit appending the punctuation to the end of the words, like so: "try,".
|
||||
// But there are no such words in the dictionary, so try without the punctuation mark.
|
||||
if (affectedRows == 0 && language.isPunctuationPartOfWords() && sequence.endsWith("1")) {
|
||||
String truncatedWord = lowercaseWord.substring(0, word.length() - 1);
|
||||
String truncatedSequence = sequence.substring(0, sequence.length() - 1);
|
||||
affectedRows = getInstance().wordsDao().incrementFrequency(language.getId(), truncatedWord, truncatedSequence);
|
||||
|
||||
Logger.d("incrementWordFrequency", "Attempting to increment frequency with stripped punctuation: " + truncatedWord);
|
||||
}
|
||||
|
||||
Logger.d("incrementWordFrequency", "Affected rows: " + affectedRows);
|
||||
} catch (Exception e) {
|
||||
Logger.e(
|
||||
DictionaryDb.class.getName(),
|
||||
"Failed incrementing word frequency. Word: " + word + " | Sequence: " + sequence + ". " + e.getMessage()
|
||||
);
|
||||
}
|
||||
).start();
|
||||
}).start();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -320,14 +298,13 @@ public class DictionaryDb {
|
|||
}
|
||||
|
||||
new Thread(() -> {
|
||||
wordList.addAll(loadWordsExact(language, sequence, filter, maxWords));
|
||||
wordList.addAll(loadWordsExact(language, sequence, filter, maxWords));
|
||||
|
||||
if (sequence.length() > 1 && wordList.size() < minWords) {
|
||||
wordList.addAll(loadWordsFuzzy(language, sequence, filter, minWords - wordList.size()));
|
||||
}
|
||||
|
||||
sendWords(dataHandler, wordList);
|
||||
if (sequence.length() > 1 && wordList.size() < minWords) {
|
||||
wordList.addAll(loadWordsFuzzy(language, sequence, filter, minWords - wordList.size()));
|
||||
}
|
||||
).start();
|
||||
|
||||
sendWords(dataHandler, wordList);
|
||||
}).start();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,7 +47,6 @@ public class DictionaryLoader {
|
|||
}
|
||||
|
||||
|
||||
|
||||
public DictionaryLoader(Context context) {
|
||||
assets = context.getAssets();
|
||||
settings = new SettingsStore(context);
|
||||
|
|
@ -80,7 +79,7 @@ public class DictionaryLoader {
|
|||
currentFile = 0;
|
||||
importStartTime = System.currentTimeMillis();
|
||||
|
||||
dropIndexes();
|
||||
sendFileCount(languages.size());
|
||||
|
||||
// SQLite does not support parallel queries, so let's import them one by one
|
||||
for (Language lang : languages) {
|
||||
|
|
@ -90,8 +89,6 @@ public class DictionaryLoader {
|
|||
importAll(lang);
|
||||
currentFile++;
|
||||
}
|
||||
|
||||
createIndexes();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -168,28 +165,6 @@ public class DictionaryLoader {
|
|||
}
|
||||
|
||||
|
||||
private void dropIndexes() {
|
||||
long start = System.currentTimeMillis();
|
||||
DictionaryDb.dropLongWordIndexSync();
|
||||
Logger.d("dropIndexes", "Index 1: " + (System.currentTimeMillis() - start) + " ms");
|
||||
|
||||
start = System.currentTimeMillis();
|
||||
DictionaryDb.dropShortWordIndexSync();
|
||||
Logger.d("dropIndexes", "Index 2: " + (System.currentTimeMillis() - start) + " ms");
|
||||
}
|
||||
|
||||
|
||||
private void createIndexes() {
|
||||
long start = System.currentTimeMillis();
|
||||
DictionaryDb.createLongWordIndexSync();
|
||||
Logger.d("createIndexes", "Index 1: " + (System.currentTimeMillis() - start) + " ms");
|
||||
|
||||
start = System.currentTimeMillis();
|
||||
DictionaryDb.createShortWordIndexSync();
|
||||
Logger.d("createIndexes", "Index 2: " + (System.currentTimeMillis() - start) + " ms");
|
||||
}
|
||||
|
||||
|
||||
private void importLetters(Language language) {
|
||||
ArrayList<Word> letters = new ArrayList<>();
|
||||
|
||||
|
|
@ -315,6 +290,20 @@ public class DictionaryLoader {
|
|||
}
|
||||
|
||||
|
||||
private void sendFileCount(int fileCount) {
|
||||
if (onStatusChange == null) {
|
||||
Logger.w(
|
||||
"tt9/DictionaryLoader.sendFileCount",
|
||||
"Cannot send file count without a status Handler. Ignoring message.");
|
||||
return;
|
||||
}
|
||||
|
||||
Bundle progressMsg = new Bundle();
|
||||
progressMsg.putInt("fileCount", fileCount);
|
||||
asyncHandler.post(() -> onStatusChange.accept(progressMsg));
|
||||
}
|
||||
|
||||
|
||||
private void sendProgressMessage(Language language, int progress, int progressUpdateInterval) {
|
||||
if (onStatusChange == null) {
|
||||
Logger.w(
|
||||
|
|
|
|||
26
src/io/github/sspanak/tt9/db/migrations/DB10.java
Normal file
26
src/io/github/sspanak/tt9/db/migrations/DB10.java
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
package io.github.sspanak.tt9.db.migrations;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.room.migration.Migration;
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase;
|
||||
|
||||
import io.github.sspanak.tt9.Logger;
|
||||
import io.github.sspanak.tt9.db.room.TT9Room;
|
||||
|
||||
public class DB10 {
|
||||
public static final Migration MIGRATION = new Migration(9, 10) {
|
||||
@Override
|
||||
public void migrate(@NonNull SupportSQLiteDatabase database) {
|
||||
try {
|
||||
database.beginTransaction();
|
||||
database.execSQL(TT9Room.createShortWordsIndexQuery().getSql());
|
||||
database.execSQL(TT9Room.createLongWordsIndexQuery().getSql());
|
||||
database.setTransactionSuccessful();
|
||||
} catch (Exception e) {
|
||||
Logger.e("Migrate to DB10", "Migration failed. " + e.getMessage());
|
||||
} finally {
|
||||
database.endTransaction();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -7,12 +7,13 @@ import androidx.room.Room;
|
|||
import androidx.room.RoomDatabase;
|
||||
import androidx.sqlite.db.SimpleSQLiteQuery;
|
||||
|
||||
import io.github.sspanak.tt9.db.migrations.DB10;
|
||||
import io.github.sspanak.tt9.db.migrations.DB6;
|
||||
import io.github.sspanak.tt9.db.migrations.DB7;
|
||||
import io.github.sspanak.tt9.db.migrations.DB8;
|
||||
import io.github.sspanak.tt9.db.migrations.DB9;
|
||||
|
||||
@Database(version = 9, entities = Word.class, exportSchema = false)
|
||||
@Database(version = 10, entities = Word.class, exportSchema = false)
|
||||
public abstract class TT9Room extends RoomDatabase {
|
||||
public abstract WordsDao wordsDao();
|
||||
|
||||
|
|
@ -23,7 +24,8 @@ public abstract class TT9Room extends RoomDatabase {
|
|||
DB6.MIGRATION,
|
||||
new DB7().getMigration(context),
|
||||
DB8.MIGRATION,
|
||||
DB9.MIGRATION
|
||||
DB9.MIGRATION,
|
||||
DB10.MIGRATION
|
||||
)
|
||||
.build();
|
||||
}
|
||||
|
|
@ -50,18 +52,10 @@ public abstract class TT9Room extends RoomDatabase {
|
|||
}
|
||||
|
||||
public static SimpleSQLiteQuery createShortWordsIndexQuery() {
|
||||
return new SimpleSQLiteQuery("CREATE INDEX " + WordsDao.indexShortWords + " ON words (lang ASC, len ASC, seq ASC)");
|
||||
return new SimpleSQLiteQuery("CREATE INDEX IF NOT EXISTS " + WordsDao.indexShortWords + " ON words (lang ASC, len ASC, seq ASC)");
|
||||
}
|
||||
|
||||
public static SimpleSQLiteQuery createLongWordsIndexQuery() {
|
||||
return new SimpleSQLiteQuery("CREATE INDEX " + WordsDao.indexLongWords + " ON words (lang ASC, seq ASC, freq DESC)");
|
||||
}
|
||||
|
||||
public static SimpleSQLiteQuery dropShortWordsIndexQuery() {
|
||||
return new SimpleSQLiteQuery("DROP INDEX IF EXISTS " + WordsDao.indexShortWords);
|
||||
}
|
||||
|
||||
public static SimpleSQLiteQuery dropLongWordsIndexQuery() {
|
||||
return new SimpleSQLiteQuery("DROP INDEX IF EXISTS " + WordsDao.indexLongWords);
|
||||
return new SimpleSQLiteQuery("CREATE INDEX IF NOT EXISTS " + WordsDao.indexLongWords + " ON words (lang ASC, seq ASC, freq DESC)");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,10 +6,6 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
|
||||
public class WordList extends ArrayList<Word> {
|
||||
public WordList() {
|
||||
super();
|
||||
}
|
||||
|
||||
public WordList(List<Word> words) {
|
||||
addAll(words);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,9 +15,6 @@ public interface WordsDao {
|
|||
String indexLongWords = "index_words_lang_seq_freq";
|
||||
String indexShortWords = "index_words_lang_len_seq";
|
||||
|
||||
@RawQuery()
|
||||
Object rawQuery(SimpleSQLiteQuery sql);
|
||||
|
||||
@Query("SELECT COUNT(id) FROM words WHERE :langId < 0 OR lang = :langId")
|
||||
int count(int langId);
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,16 @@ abstract class ItemClickable {
|
|||
}
|
||||
|
||||
|
||||
public void disable() {
|
||||
item.setEnabled(false);
|
||||
}
|
||||
|
||||
|
||||
public void enable() {
|
||||
item.setEnabled(true);
|
||||
}
|
||||
|
||||
|
||||
public void enableClickHandler() {
|
||||
item.setOnPreferenceClickListener(this::debounceClick);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,7 +63,6 @@ public class ItemLoadDictionary extends ItemClickable {
|
|||
@Override
|
||||
protected boolean onClick(Preference p) {
|
||||
ArrayList<Language> languages = LanguageCollection.getAll(settings.getEnabledLanguageIds());
|
||||
progressBar.setFileCount(languages.size());
|
||||
|
||||
try {
|
||||
loader.load(languages);
|
||||
|
|
|
|||
|
|
@ -1,31 +1,36 @@
|
|||
package io.github.sspanak.tt9.preferences.items;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import io.github.sspanak.tt9.R;
|
||||
import io.github.sspanak.tt9.db.DictionaryDb;
|
||||
import io.github.sspanak.tt9.db.DictionaryLoader;
|
||||
import io.github.sspanak.tt9.preferences.PreferencesActivity;
|
||||
import io.github.sspanak.tt9.ui.UI;
|
||||
|
||||
|
||||
public class ItemTruncateAll extends ItemClickable {
|
||||
public static final String NAME = "dictionary_truncate";
|
||||
|
||||
private final Context context;
|
||||
private final DictionaryLoader loader;
|
||||
private final ItemLoadDictionary loadItem;
|
||||
protected final PreferencesActivity activity;
|
||||
protected final DictionaryLoader loader;
|
||||
protected final ItemLoadDictionary loadItem;
|
||||
protected ItemClickable otherTruncateItem;
|
||||
|
||||
|
||||
public ItemTruncateAll(Preference item, ItemLoadDictionary loadItem, Context context, DictionaryLoader loader) {
|
||||
public ItemTruncateAll(Preference item, ItemLoadDictionary loadItem, PreferencesActivity activity, DictionaryLoader loader) {
|
||||
super(item);
|
||||
this.context = context;
|
||||
this.activity = activity;
|
||||
this.loadItem = loadItem;
|
||||
this.loader = loader;
|
||||
}
|
||||
|
||||
|
||||
public ItemTruncateAll setOtherTruncateItem(ItemTruncateUnselected item) {
|
||||
this.otherTruncateItem = item;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected boolean onClick(Preference p) {
|
||||
if (loader != null && loader.isRunning()) {
|
||||
|
|
@ -33,8 +38,32 @@ public class ItemTruncateAll extends ItemClickable {
|
|||
loadItem.changeToLoadButton();
|
||||
}
|
||||
|
||||
DictionaryDb.deleteWords(() -> UI.toastFromAsync(context, R.string.dictionary_truncated));
|
||||
onStartDeleting();
|
||||
DictionaryDb.deleteWords(this::onFinishDeleting);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
protected void onStartDeleting() {
|
||||
if (otherTruncateItem != null) {
|
||||
otherTruncateItem.disable();
|
||||
}
|
||||
loadItem.disable();
|
||||
disable();
|
||||
item.setSummary(R.string.dictionary_truncating);
|
||||
}
|
||||
|
||||
|
||||
protected void onFinishDeleting() {
|
||||
activity.runOnUiThread(() -> {
|
||||
if (otherTruncateItem != null) {
|
||||
otherTruncateItem.enable();
|
||||
}
|
||||
loadItem.enable();
|
||||
item.setSummary("");
|
||||
enable();
|
||||
UI.toastFromAsync(activity, R.string.dictionary_truncated);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,35 +1,32 @@
|
|||
package io.github.sspanak.tt9.preferences.items;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import io.github.sspanak.tt9.R;
|
||||
import io.github.sspanak.tt9.db.DictionaryDb;
|
||||
import io.github.sspanak.tt9.db.DictionaryLoader;
|
||||
import io.github.sspanak.tt9.languages.Language;
|
||||
import io.github.sspanak.tt9.languages.LanguageCollection;
|
||||
import io.github.sspanak.tt9.preferences.PreferencesActivity;
|
||||
import io.github.sspanak.tt9.preferences.SettingsStore;
|
||||
import io.github.sspanak.tt9.ui.UI;
|
||||
|
||||
|
||||
public class ItemTruncateUnselected extends ItemClickable {
|
||||
public class ItemTruncateUnselected extends ItemTruncateAll {
|
||||
public static final String NAME = "dictionary_truncate_unselected";
|
||||
|
||||
private final Context context;
|
||||
private final DictionaryLoader loader;
|
||||
private final ItemLoadDictionary loadItem;
|
||||
private final SettingsStore settings;
|
||||
|
||||
|
||||
public ItemTruncateUnselected(Preference item, ItemLoadDictionary loadItem, Context context, SettingsStore settings, DictionaryLoader loader) {
|
||||
super(item);
|
||||
this.context = context;
|
||||
this.loadItem = loadItem;
|
||||
public ItemTruncateUnselected(Preference item, ItemLoadDictionary loadItem, PreferencesActivity context, SettingsStore settings, DictionaryLoader loader) {
|
||||
super(item, loadItem, context, loader);
|
||||
this.settings = settings;
|
||||
this.loader = loader;
|
||||
}
|
||||
|
||||
|
||||
public ItemTruncateUnselected setOtherTruncateItem(ItemTruncateAll otherTruncateItem) {
|
||||
this.otherTruncateItem = otherTruncateItem;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -48,10 +45,8 @@ public class ItemTruncateUnselected extends ItemClickable {
|
|||
}
|
||||
}
|
||||
|
||||
DictionaryDb.deleteWords(
|
||||
() -> UI.toastFromAsync(context, R.string.dictionary_truncated),
|
||||
unselectedLanguageIds
|
||||
);
|
||||
onStartDeleting();
|
||||
DictionaryDb.deleteWords(this::onFinishDeleting, unselectedLanguageIds);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,6 @@ public class DictionariesScreen extends BaseScreenFragment {
|
|||
activity,
|
||||
activity.getDictionaryLoader()
|
||||
);
|
||||
truncateItem.enableClickHandler();
|
||||
|
||||
ItemTruncateUnselected truncateSelectedItem = new ItemTruncateUnselected(
|
||||
findPreference(ItemTruncateUnselected.NAME),
|
||||
|
|
@ -46,6 +45,8 @@ public class DictionariesScreen extends BaseScreenFragment {
|
|||
activity.settings,
|
||||
activity.getDictionaryLoader()
|
||||
);
|
||||
truncateSelectedItem.enableClickHandler();
|
||||
|
||||
truncateItem.setOtherTruncateItem(truncateSelectedItem).enableClickHandler();
|
||||
truncateSelectedItem.setOtherTruncateItem(truncateItem).enableClickHandler();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -105,6 +105,7 @@ public class DictionaryLoadingBar {
|
|||
|
||||
public void show(Bundle data) {
|
||||
String error = data.getString("error", null);
|
||||
int fileCount = data.getInt("fileCount", -1);
|
||||
|
||||
if (error != null) {
|
||||
hasFailed = true;
|
||||
|
|
@ -114,7 +115,9 @@ public class DictionaryLoadingBar {
|
|||
data.getLong("fileLine", -1),
|
||||
data.getString("word", "")
|
||||
);
|
||||
} else {
|
||||
} else if (fileCount > -1) {
|
||||
setFileCount(fileCount);
|
||||
} else {
|
||||
hasFailed = false;
|
||||
showProgress(
|
||||
data.getLong("time", 0),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue