diff --git a/res/drawable-anydpi-v24/ic_notification.xml b/res/drawable-anydpi-v24/ic_notification.xml
new file mode 100644
index 00000000..0b078c79
--- /dev/null
+++ b/res/drawable-anydpi-v24/ic_notification.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/drawable-hdpi/ic_notification.png b/res/drawable-hdpi/ic_notification.png
new file mode 100644
index 00000000..599f02e3
Binary files /dev/null and b/res/drawable-hdpi/ic_notification.png differ
diff --git a/res/drawable-mdpi/ic_notification.png b/res/drawable-mdpi/ic_notification.png
new file mode 100644
index 00000000..aeb07b78
Binary files /dev/null and b/res/drawable-mdpi/ic_notification.png differ
diff --git a/res/drawable-xhdpi/ic_notification.png b/res/drawable-xhdpi/ic_notification.png
new file mode 100644
index 00000000..832d3ad4
Binary files /dev/null and b/res/drawable-xhdpi/ic_notification.png differ
diff --git a/res/drawable-xxhdpi/ic_notification.png b/res/drawable-xxhdpi/ic_notification.png
new file mode 100644
index 00000000..1b3ff500
Binary files /dev/null and b/res/drawable-xxhdpi/ic_notification.png differ
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index aeb90a02..1fbe753c 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -18,10 +18,13 @@
Изтрий речник
Неуспешно зареждане. Невалидна дума \"%1$s\" на ред %2$d за език \"%3$s\".
+ Зареждането на речник е отменено.
Несупешно зареждане на речник за език \"%1$s\" (%2$s).
+ Готово
Зареждане на речник (%1$s)…
Зареждане на вашия речник…
Зареждане на речник
Неуспешно зареждане. Липсва речник за \"%1$s\".
- Речникът е изтрит успешно
+ Речникът е изтрит успешно.
+
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index a21f5175..037731c0 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -17,6 +17,8 @@
Supprimer le dictionaire
Echec du chargement de dictionnaire pour langue «%1$s» (%2$s).
+ Chargement du dictionnaire annulée.
+ Terminé
Chargement du dictionnaire (%1$s)…
Chargement du dictionnaire utilisateur…
Charger le dictionnaire
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index 95ad9410..a3c4ca2a 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -16,6 +16,8 @@
Carica dizionario utente
Eliminare il dizionario
+ Caricamento dizionario annullato.
+ Terminato
Caricamento dizionario (%1$s)…
Caricamento dizionario utente…
Caricamento dizionario
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index 7104d296..f9105524 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -15,7 +15,7 @@
Woordenboek laden
Gebruikerswoordenboek laden
Woordenboek wissen
- Woordenboek laden…
+ Woordenboek laden (%1$s)…
Gebruikerswoordenboek laden…
Woordenboek laden
Laden mislukt. Woordenboek voor %1$s niet gevonden.
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index 544169f8..47941b2a 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -17,7 +17,9 @@
Загрузить свой словарь
Очистить словарь
+ Загрузка словаря отменена.
Ошибка загрузки словаря для языка «%1$s» (%2$s).
+ Завершена
Загрузка словаря (%1$s)…
Загрузка пользовательского словаря…
Загрузить словарь
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index 6a0a1190..3b8b9080 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -16,7 +16,9 @@
Завантажити свій словник
Очистити словник
+ Завантаження словника скасовано.
Помилка завантаження словника для мови «%1$s» (%2$s).
+ Завершено
Завантаження словника (%1$s)…
Завантаження словника користувача…
Завантажити словник
diff --git a/res/values/strings.xml b/res/values/strings.xml
index c3634f30..e05a1639 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -22,7 +22,9 @@
Clear dictionary
Loading failed. Invalid word \"%1$s\" on line %2$d of language \"%3$s\".
+ Dictionary import cancelled.
Failed importing dictionary for language \"%1$s\" (%2$s).
+ Done
Loading dictionary (%1$s)…
Loading user dictionary…
Load dictionary
diff --git a/src/io/github/sspanak/tt9/db/DictionaryImportAlreadyRunningException.java b/src/io/github/sspanak/tt9/db/DictionaryImportAlreadyRunningException.java
new file mode 100644
index 00000000..a50b5b33
--- /dev/null
+++ b/src/io/github/sspanak/tt9/db/DictionaryImportAlreadyRunningException.java
@@ -0,0 +1,7 @@
+package io.github.sspanak.tt9.db;
+
+public class DictionaryImportAlreadyRunningException extends Exception{
+ public DictionaryImportAlreadyRunningException() {
+ super("Dictionary import is already running.");
+ }
+}
diff --git a/src/io/github/sspanak/tt9/db/DictionaryLoader.java b/src/io/github/sspanak/tt9/db/DictionaryLoader.java
index a0d2ceda..311ba18d 100644
--- a/src/io/github/sspanak/tt9/db/DictionaryLoader.java
+++ b/src/io/github/sspanak/tt9/db/DictionaryLoader.java
@@ -23,11 +23,12 @@ public class DictionaryLoader {
private final AssetManager assets;
private final T9Preferences prefs;
- private boolean isStopped = true;
+ private final Pattern containsPunctuation = Pattern.compile("\\p{Punct}(? languages) {
- new Thread() {
+ public void load(Handler handler, ArrayList languages) throws DictionaryImportAlreadyRunningException {
+ if (isRunning()) {
+ throw new DictionaryImportAlreadyRunningException();
+ }
+
+ loadThread = new Thread() {
@Override
public void run() {
currentFile = 0;
- isStopped = false;
// SQLite does not support parallel queries, so let's import them one by one
for (Language lang : languages) {
- if (isStopped) {
+ if (isInterrupted()) {
break;
}
importAll(handler, lang);
currentFile++;
}
}
- }.start();
+ };
+
+ loadThread.start();
}
public void stop() {
- isStopped = true;
+ loadThread.interrupt();
+ }
+
+
+ public boolean isRunning() {
+ return loadThread != null && loadThread.isAlive();
}
@@ -160,9 +171,9 @@ public class DictionaryLoader {
sendProgressMessage(handler, language, 0, 0);
for (String word; (word = br.readLine()) != null; line++) {
- if (isStopped) {
+ if (loadThread.isInterrupted()) {
br.close();
- sendProgressMessage(handler, language, 0, 0);
+ sendProgressMessage(handler, language, -1, 0);
throw new DictionaryImportAbortedException();
}
diff --git a/src/io/github/sspanak/tt9/preferences/T9Preferences.java b/src/io/github/sspanak/tt9/preferences/T9Preferences.java
index 7f1f7643..cc599544 100644
--- a/src/io/github/sspanak/tt9/preferences/T9Preferences.java
+++ b/src/io/github/sspanak/tt9/preferences/T9Preferences.java
@@ -162,7 +162,7 @@ public class T9Preferences {
/************* internal settings *************/
- public int getDictionaryImportProgressUpdateInterval() { return 100; /* ms */ }
+ public int getDictionaryImportProgressUpdateInterval() { return 250; /* ms */ }
public int getDictionaryImportWordChunkSize() { return 1000; /* words */ }
public int getSuggestionsMax() { return 20; }
public int getSuggestionsMin() { return 8; }
diff --git a/src/io/github/sspanak/tt9/ui/DictionaryLoadingBar.java b/src/io/github/sspanak/tt9/ui/DictionaryLoadingBar.java
new file mode 100644
index 00000000..38ce4c71
--- /dev/null
+++ b/src/io/github/sspanak/tt9/ui/DictionaryLoadingBar.java
@@ -0,0 +1,92 @@
+package io.github.sspanak.tt9.ui;
+
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.content.res.Resources;
+import android.os.Build;
+
+import androidx.core.app.NotificationCompat;
+
+import io.github.sspanak.tt9.R;
+import io.github.sspanak.tt9.languages.Language;
+import io.github.sspanak.tt9.languages.LanguageCollection;
+
+public class DictionaryLoadingBar {
+ private static final int NOTIFICATION_ID = 1;
+ private static final String NOTIFICATION_CHANNEL_ID = "loading-notifications";
+
+ private final NotificationManager manager;
+ private final NotificationCompat.Builder notificationBuilder;
+ private final Resources resources;
+
+ private int maxProgress = 0;
+
+
+ DictionaryLoadingBar(Context context) {
+ resources = context.getResources();
+
+ manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ manager.createNotificationChannel(new NotificationChannel(
+ NOTIFICATION_CHANNEL_ID,
+ "Dictionary Loading Channel",
+ NotificationManager.IMPORTANCE_LOW
+ ));
+ notificationBuilder = new NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID);
+ } else {
+ notificationBuilder = new NotificationCompat.Builder(context);
+ }
+
+ notificationBuilder
+ .setSmallIcon(R.drawable.ic_notification)
+ .setCategory(NotificationCompat.CATEGORY_PROGRESS)
+ .setOnlyAlertOnce(true);
+ }
+
+
+ private String generateTitle(int languageId) {
+ Language lang = LanguageCollection.getLanguage(languageId);
+
+ if (lang != null) {
+ return resources.getString(R.string.dictionary_loading, lang.getName());
+ }
+
+ return resources.getString(R.string.dictionary_load_title);
+ }
+
+
+ public void show(int currentFile, int currentFileProgress, int languageId) {
+ int totalProgress = 100 * currentFile + currentFileProgress;
+
+ if (currentFileProgress < 0) {
+ hide();
+ return;
+ } else if (totalProgress >= maxProgress) {
+ notificationBuilder
+ .setContentTitle(generateTitle(-1))
+ .setContentText(resources.getString(R.string.dictionary_loaded))
+ .setOngoing(false)
+ .setProgress(0, 0, false);
+ } else {
+ notificationBuilder
+ .setContentTitle(generateTitle(languageId))
+ .setContentText(currentFileProgress + "%")
+ .setOngoing(true)
+ .setProgress(maxProgress, totalProgress, false);
+ }
+
+ manager.notify(NOTIFICATION_ID, notificationBuilder.build());
+ }
+
+
+ public void hide() {
+ manager.cancel(NOTIFICATION_ID);
+ }
+
+
+ public void setFileCount(int count) {
+ maxProgress = count * 100;
+ }
+}
diff --git a/src/io/github/sspanak/tt9/ui/TraditionalT9Settings.java b/src/io/github/sspanak/tt9/ui/TraditionalT9Settings.java
index 1543bc9d..9693cc68 100644
--- a/src/io/github/sspanak/tt9/ui/TraditionalT9Settings.java
+++ b/src/io/github/sspanak/tt9/ui/TraditionalT9Settings.java
@@ -2,7 +2,6 @@ package io.github.sspanak.tt9.ui;
import android.app.AlertDialog;
import android.app.ListActivity;
-import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
@@ -21,6 +20,7 @@ import java.util.ArrayList;
import io.github.sspanak.tt9.R;
import io.github.sspanak.tt9.db.DictionaryDb;
+import io.github.sspanak.tt9.db.DictionaryImportAlreadyRunningException;
import io.github.sspanak.tt9.db.DictionaryImportException;
import io.github.sspanak.tt9.db.DictionaryLoader;
import io.github.sspanak.tt9.languages.InvalidLanguageCharactersException;
@@ -35,7 +35,7 @@ import io.github.sspanak.tt9.settings_legacy.SettingAdapter;
public class TraditionalT9Settings extends ListActivity implements DialogInterface.OnCancelListener {
private DictionaryLoader loader;
- ProgressDialog progressDialog;
+ DictionaryLoadingBar progressBar;
Context mContext = null;
@@ -43,8 +43,7 @@ public class TraditionalT9Settings extends ListActivity implements DialogInterfa
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- // maybe need this?
- // http://stackoverflow.com/questions/7645880/listview-with-onitemclicklistener-android
+ progressBar = new DictionaryLoadingBar(this);
// get settings
T9Preferences prefs = new T9Preferences(getApplicationContext());
@@ -98,18 +97,22 @@ public class TraditionalT9Settings extends ListActivity implements DialogInterfa
}
private void truncateWords() {
- Handler afterTruncate = new Handler(Looper.getMainLooper()) {
- @Override
- public void handleMessage(Message msg) {
- UI.toast(mContext, R.string.dictionary_truncated);
- }
- };
- DictionaryDb.truncateWords(afterTruncate);
+ if (loader != null && loader.isRunning()) {
+ loader.stop();
+ }
+
+ Handler afterTruncate = new Handler(Looper.getMainLooper()) {
+ @Override
+ public void handleMessage(Message msg) {
+ UI.toast(mContext, R.string.dictionary_truncated);
+ }
+ };
+ DictionaryDb.truncateWords(afterTruncate);
}
private void loadDictionaries() {
ArrayList languages = LanguageCollection.getAll(T9Preferences.getInstance().getEnabledLanguages());
- initProgress(100 * languages.size());
+ progressBar.setFileCount(languages.size());
Handler loadHandler = new Handler(Looper.getMainLooper()) {
@Override
@@ -117,7 +120,7 @@ public class TraditionalT9Settings extends ListActivity implements DialogInterfa
String error = msg.getData().getString("error", null);
if (error != null) {
- hideProgress();
+ progressBar.hide();
handleError(
error,
msg.getData().getInt("languageId", -1),
@@ -125,58 +128,24 @@ public class TraditionalT9Settings extends ListActivity implements DialogInterfa
msg.getData().getString("word", "")
);
} else {
- int langId = msg.getData().getInt("languageId", -1);
- Language lang = LanguageCollection.getLanguage(langId);
- String langName = lang != null ? lang.getName() : "???";
-
- String title = getResources().getString(R.string.dictionary_loading, langName);
- showProgress(
+ progressBar.show(
msg.getData().getInt("currentFile", 0),
msg.getData().getInt("progress", 0),
- title
+ msg.getData().getInt("languageId", -1)
);
}
}
};
- loader = new DictionaryLoader(this);
- loader.load(loadHandler, languages);
- }
-
-
- private void initProgress(int max) {
- if (progressDialog == null) {
- progressDialog = new ProgressDialog(this);
- progressDialog.setOnCancelListener(TraditionalT9Settings.this);
- progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
+ if (loader == null) {
+ loader = new DictionaryLoader(this);
}
- progressDialog.setMax(max);
- }
-
- private void showProgress(int currentFile, int currentFileProgress, String title) {
- if (progressDialog == null) {
- return;
- }
-
- if (title != null) {
- progressDialog.setMessage(title);
- }
-
- int totalProgress = 100 * currentFile + currentFileProgress;
- if (totalProgress <= 0 || totalProgress >= progressDialog.getMax()) {
- progressDialog.dismiss();
- } else {
- progressDialog.setProgress(totalProgress);
- if (!progressDialog.isShowing()) {
- progressDialog.show();
- }
- }
- }
-
- private void hideProgress() {
- if (progressDialog != null) {
- progressDialog.dismiss();
+ try {
+ loader.load(loadHandler, languages);
+ } catch (DictionaryImportAlreadyRunningException e) {
+ loader.stop();
+ UI.toast(this, getString(R.string.dictionary_import_cancelled));
}
}