* dictionary exporting
* removed unnecessary passing of DictionaryLoader and DictionaryLoadingBar between the preference fragments
This commit is contained in:
parent
f4c425516e
commit
29b2ac2cb6
30 changed files with 953 additions and 203 deletions
|
|
@ -1,10 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest
|
||||
android:versionCode="383"
|
||||
android:versionName="28.0"
|
||||
android:versionCode="395"
|
||||
android:versionName="28.12"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
|
||||
<!-- required for words exporting on Android < 10 -->
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
|
||||
<application
|
||||
android:allowBackup="false"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,149 @@
|
|||
package io.github.sspanak.tt9.db.exporter;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.ContentValues;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.media.MediaScannerConnection;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Environment;
|
||||
import android.provider.MediaStore;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import io.github.sspanak.tt9.ConsumerCompat;
|
||||
|
||||
public abstract class AbstractExporter {
|
||||
final protected static String FILE_EXTENSION = ".csv";
|
||||
final protected static String MIME_TYPE = "text/csv";
|
||||
|
||||
protected Runnable failureHandler;
|
||||
protected ConsumerCompat<String> successHandler;
|
||||
protected Thread processThread;
|
||||
private String outputFile;
|
||||
|
||||
|
||||
public static AbstractExporter getInstance() {
|
||||
throw new RuntimeException("Not Implemented");
|
||||
}
|
||||
|
||||
|
||||
private void writeAndroid10(Activity activity) throws Exception {
|
||||
final String fileName = generateFileName();
|
||||
outputFile = getOutputDir() + File.pathSeparator + fileName;
|
||||
|
||||
final ContentValues file = new ContentValues();
|
||||
file.put(MediaStore.MediaColumns.DISPLAY_NAME, fileName);
|
||||
file.put(MediaStore.MediaColumns.MIME_TYPE, MIME_TYPE);
|
||||
file.put(MediaStore.MediaColumns.RELATIVE_PATH, getOutputDir());
|
||||
|
||||
final ContentResolver resolver = activity.getContentResolver();
|
||||
Uri uri = null;
|
||||
|
||||
try {
|
||||
uri = resolver.insert(MediaStore.Files.getContentUri("external"), file);
|
||||
if (uri == null) {
|
||||
throw new IOException("Failed to create new MediaStore entry.");
|
||||
}
|
||||
|
||||
try (OutputStream stream = resolver.openOutputStream(uri)) {
|
||||
if (stream == null) {
|
||||
throw new IOException("Failed to open output stream.");
|
||||
}
|
||||
stream.write(getWords(activity));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
if (uri != null) {
|
||||
resolver.delete(uri, null, null);
|
||||
}
|
||||
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void writeLegacy(Activity activity) throws Exception {
|
||||
if (
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
|
||||
&& activity.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
activity.requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 0);
|
||||
}
|
||||
|
||||
final String exportDir = Environment.getExternalStoragePublicDirectory(getOutputDir()).getAbsolutePath();
|
||||
final String fileName = generateFileName();
|
||||
outputFile = getOutputDir() + File.pathSeparator + fileName;
|
||||
|
||||
final File file = new File(exportDir, fileName);
|
||||
if (!file.createNewFile()) {
|
||||
throw new IOException("Failed to create a new file.");
|
||||
}
|
||||
|
||||
try (OutputStream stream = new FileOutputStream(file)) {
|
||||
stream.write(getWords(activity));
|
||||
}
|
||||
|
||||
MediaScannerConnection.scanFile(activity, new String[]{file.getAbsolutePath()}, new String[]{MIME_TYPE}, null);
|
||||
}
|
||||
|
||||
|
||||
protected void write(Activity activity) throws Exception {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
writeAndroid10(activity);
|
||||
} else {
|
||||
writeLegacy(activity);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected String getOutputFile() {
|
||||
return outputFile;
|
||||
}
|
||||
|
||||
|
||||
public String getOutputDir() {
|
||||
// on some older phones, files may not be visible in the DOCUMENTS directory, so we use DOWNLOADS
|
||||
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q ? Environment.DIRECTORY_DOCUMENTS : Environment.DIRECTORY_DOWNLOADS;
|
||||
}
|
||||
|
||||
|
||||
protected void sendSuccess() {
|
||||
if (successHandler != null) {
|
||||
successHandler.accept(outputFile);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void sendFailure() {
|
||||
if (failureHandler != null) {
|
||||
failureHandler.run();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public boolean isRunning() {
|
||||
return processThread != null && processThread.isAlive();
|
||||
}
|
||||
|
||||
|
||||
public void setSuccessHandler(ConsumerCompat<String> handler) {
|
||||
successHandler = handler;
|
||||
}
|
||||
|
||||
|
||||
public void setFailureHandler(Runnable handler) {
|
||||
failureHandler = handler;
|
||||
}
|
||||
|
||||
|
||||
@NonNull abstract protected String generateFileName();
|
||||
@NonNull abstract protected byte[] getWords(Activity activity) throws Exception;
|
||||
abstract public boolean export(Activity activity);
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
package io.github.sspanak.tt9.db.exporter;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import io.github.sspanak.tt9.db.sqlite.ReadOps;
|
||||
import io.github.sspanak.tt9.db.sqlite.SQLiteOpener;
|
||||
|
||||
public class CustomWordsExporter extends AbstractExporter {
|
||||
private static CustomWordsExporter customWordsExporterSelf;
|
||||
|
||||
public static final String LOG_TAG = "dictionary_export";
|
||||
private static final String BASE_FILE_NAME = "tt9-added-words-export-";
|
||||
|
||||
public static CustomWordsExporter getInstance() {
|
||||
if (customWordsExporterSelf == null) {
|
||||
customWordsExporterSelf = new CustomWordsExporter();
|
||||
}
|
||||
|
||||
return customWordsExporterSelf;
|
||||
}
|
||||
|
||||
public boolean export(Activity activity) {
|
||||
if (isRunning()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
processThread = new Thread(() -> {
|
||||
try {
|
||||
write(activity);
|
||||
sendSuccess();
|
||||
} catch (Exception e) {
|
||||
sendFailure();
|
||||
}
|
||||
});
|
||||
|
||||
processThread.start();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
protected String generateFileName() {
|
||||
return BASE_FILE_NAME + "-" + System.currentTimeMillis() + FILE_EXTENSION;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected byte[] getWords(Activity activity) throws Exception {
|
||||
SQLiteDatabase db = SQLiteOpener.getInstance(activity).getDb();
|
||||
if (db == null) {
|
||||
throw new Exception("Could not open database");
|
||||
}
|
||||
|
||||
return new ReadOps().getWords(db, null, true).getBytes();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
package io.github.sspanak.tt9.db.exporter;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import io.github.sspanak.tt9.Logger;
|
||||
import io.github.sspanak.tt9.db.sqlite.ReadOps;
|
||||
import io.github.sspanak.tt9.db.sqlite.SQLiteOpener;
|
||||
import io.github.sspanak.tt9.languages.Language;
|
||||
|
||||
public class DictionaryExporter extends AbstractExporter {
|
||||
private static DictionaryExporter self;
|
||||
|
||||
public static final String LOG_TAG = "dictionary_export";
|
||||
private static final String BASE_FILE_NAME = "tt9-dictionary-export-";
|
||||
private ArrayList<Language> languages;
|
||||
private Language currentLanguage;
|
||||
|
||||
public static DictionaryExporter getInstance() {
|
||||
if (self == null) {
|
||||
self = new DictionaryExporter();
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
public boolean export(Activity activity) {
|
||||
if (isRunning()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (languages == null || languages.isEmpty()) {
|
||||
Logger.d(LOG_TAG, "Nothing to do");
|
||||
return true;
|
||||
}
|
||||
|
||||
processThread = new Thread(() -> { for (Language l : languages) exportLanguage(activity, l); });
|
||||
processThread.start();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public DictionaryExporter setLanguages(ArrayList<Language> languages) {
|
||||
this.languages = languages;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
protected String generateFileName() {
|
||||
return BASE_FILE_NAME + currentLanguage.getLocale().getLanguage() + "-" + System.currentTimeMillis() + FILE_EXTENSION;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
protected byte[] getWords(Activity activity) throws Exception {
|
||||
SQLiteDatabase db = SQLiteOpener.getInstance(activity).getDb();
|
||||
if (db == null) {
|
||||
throw new Exception("Could not open database");
|
||||
}
|
||||
|
||||
return new ReadOps().getWords(db, currentLanguage, false).getBytes();
|
||||
}
|
||||
|
||||
private void exportLanguage(Activity activity, Language language) {
|
||||
currentLanguage = language;
|
||||
if (currentLanguage == null) {
|
||||
Logger.e(LOG_TAG, "Cannot export dictionary for null language");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
long start = System.currentTimeMillis();
|
||||
write(activity);
|
||||
sendSuccess();
|
||||
Logger.d(LOG_TAG, "All words for language: " + currentLanguage.getName() + " loaded. Time: " + (System.currentTimeMillis() - start) + "ms");
|
||||
} catch (Exception e) {
|
||||
sendFailure();
|
||||
Logger.e(LOG_TAG, "Failed exporting dictionary for " + currentLanguage.getName() + " to: " + getOutputFile() + ". " + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -62,6 +62,31 @@ public class ReadOps {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets all words as a ready-to-export CSV string. If the language is null or customWords is true,
|
||||
* only custom words are returned.
|
||||
*/
|
||||
@NonNull
|
||||
public String getWords(@NonNull SQLiteDatabase db, Language language, boolean customWords) {
|
||||
StringBuilder words = new StringBuilder();
|
||||
|
||||
String table = customWords || language == null ? Tables.CUSTOM_WORDS : Tables.getWords(language.getId());
|
||||
String[] columns = customWords || language == null ? new String[]{"word", "langId"} : new String[]{"word", "frequency"};
|
||||
|
||||
try (Cursor cursor = db.query(table, columns, null, null, null, null, null)) {
|
||||
while (cursor.moveToNext()) {
|
||||
words
|
||||
.append(cursor.getString(0))
|
||||
.append("\t")
|
||||
.append(cursor.getInt(1))
|
||||
.append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
return words.toString();
|
||||
}
|
||||
|
||||
|
||||
@NonNull
|
||||
public WordList getWords(@NonNull SQLiteDatabase db, @NonNull Language language, @NonNull String positions, String filter, int maximumWords, boolean fullOutput) {
|
||||
if (positions.isEmpty()) {
|
||||
|
|
@ -69,7 +94,6 @@ public class ReadOps {
|
|||
return new WordList();
|
||||
}
|
||||
|
||||
|
||||
String wordsQuery = getWordsQuery(language, positions, filter, maximumWords, fullOutput);
|
||||
if (wordsQuery.isEmpty()) {
|
||||
return new WordList();
|
||||
|
|
@ -139,7 +163,6 @@ public class ReadOps {
|
|||
}
|
||||
|
||||
|
||||
|
||||
@NonNull private String getCustomWordPositions(@NonNull SQLiteDatabase db, Language language, String sequence, int generations) {
|
||||
try (Cursor cursor = db.rawQuery(getCustomWordPositionsQuery(language, sequence, generations), null)) {
|
||||
return new WordPositionsStringBuilder().appendFromDbRanges(cursor).toString();
|
||||
|
|
@ -156,7 +179,6 @@ public class ReadOps {
|
|||
}
|
||||
|
||||
|
||||
|
||||
@NonNull private String getFactoryWordPositionsQuery(@NonNull Language language, @NonNull String sequence, int generations) {
|
||||
StringBuilder sql = new StringBuilder("SELECT `start`, `end` FROM ")
|
||||
.append(Tables.getWordPositions(language.getId()))
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import androidx.annotation.Nullable;
|
|||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.app.AppCompatDelegate;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
import androidx.preference.Preference;
|
||||
|
|
@ -16,7 +15,6 @@ import androidx.preference.PreferenceFragmentCompat;
|
|||
|
||||
import io.github.sspanak.tt9.Logger;
|
||||
import io.github.sspanak.tt9.R;
|
||||
import io.github.sspanak.tt9.db.DictionaryLoader;
|
||||
import io.github.sspanak.tt9.db.LegacyDb;
|
||||
import io.github.sspanak.tt9.db.WordStoreAsync;
|
||||
import io.github.sspanak.tt9.ime.helpers.InputModeValidator;
|
||||
|
|
@ -31,7 +29,6 @@ import io.github.sspanak.tt9.preferences.screens.KeyPadScreen;
|
|||
import io.github.sspanak.tt9.preferences.screens.MainSettingsScreen;
|
||||
import io.github.sspanak.tt9.preferences.screens.SetupScreen;
|
||||
import io.github.sspanak.tt9.preferences.screens.UsageStatsScreen;
|
||||
import io.github.sspanak.tt9.ui.DictionaryLoadingBar;
|
||||
|
||||
public class PreferencesActivity extends AppCompatActivity implements PreferenceFragmentCompat.OnPreferenceStartFragmentCallback {
|
||||
public SettingsStore settings;
|
||||
|
|
@ -176,14 +173,4 @@ public class PreferencesActivity extends AppCompatActivity implements Preference
|
|||
Hotkeys.setDefault(settings);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public DictionaryLoadingBar getDictionaryProgressBar() {
|
||||
return DictionaryLoadingBar.getInstance(this);
|
||||
}
|
||||
|
||||
|
||||
public DictionaryLoader getDictionaryLoader() {
|
||||
return DictionaryLoader.getInstance(this);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
package io.github.sspanak.tt9.preferences.items;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import io.github.sspanak.tt9.Logger;
|
||||
import io.github.sspanak.tt9.preferences.SettingsStore;
|
||||
|
|
@ -12,14 +12,43 @@ abstract public class ItemClickable {
|
|||
private long lastClickTime = 0;
|
||||
|
||||
protected final Preference item;
|
||||
private final ArrayList<ItemClickable> otherItems = new ArrayList<>();
|
||||
|
||||
|
||||
public ItemClickable(Preference item) {
|
||||
this.item = item;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static void disableAll(@NonNull ArrayList<ItemClickable> items) {
|
||||
for (ItemClickable i : items) {
|
||||
i.disable();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void enableAll(@NonNull ArrayList<ItemClickable> items) {
|
||||
for (ItemClickable i : items) {
|
||||
i.enable();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void disableOthers(@NonNull ArrayList<ItemClickable> items, @NonNull ItemClickable exclude) {
|
||||
for (ItemClickable i : items) {
|
||||
if (i != exclude) {
|
||||
i.disable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void enableAllClickHandlers(@NonNull ArrayList<ItemClickable> items) {
|
||||
for (ItemClickable i : items) {
|
||||
i.enableClickHandler();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void disable() {
|
||||
item.setEnabled(false);
|
||||
}
|
||||
|
|
@ -35,28 +64,6 @@ abstract public class ItemClickable {
|
|||
}
|
||||
|
||||
|
||||
public ItemClickable setOtherItems(List<ItemClickable> others) {
|
||||
otherItems.clear();
|
||||
otherItems.addAll(others);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
protected void disableOtherItems() {
|
||||
for (ItemClickable i : otherItems) {
|
||||
i.disable();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
protected void enableOtherItems() {
|
||||
for (ItemClickable i : otherItems) {
|
||||
i.enable();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected boolean debounceClick(Preference p) {
|
||||
long now = System.currentTimeMillis();
|
||||
if (now - lastClickTime < SettingsStore.PREFERENCES_CLICK_DEBOUNCE_TIME) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,93 @@
|
|||
package io.github.sspanak.tt9.preferences.items;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import io.github.sspanak.tt9.R;
|
||||
import io.github.sspanak.tt9.db.exporter.AbstractExporter;
|
||||
import io.github.sspanak.tt9.ui.DictionaryNotification;
|
||||
|
||||
abstract public class ItemExportAbstract extends ItemClickable {
|
||||
final protected Activity activity;
|
||||
final private Runnable onStart;
|
||||
final private Runnable onFinish;
|
||||
|
||||
public ItemExportAbstract(Preference item, Activity activity, Runnable onStart, Runnable onFinish) {
|
||||
super(item);
|
||||
this.activity = activity;
|
||||
this.onStart = onStart;
|
||||
this.onFinish = onFinish;
|
||||
|
||||
AbstractExporter exporter = getExporter();
|
||||
exporter.setFailureHandler(() -> onFinishExporting(null));
|
||||
exporter.setSuccessHandler(this::onFinishExporting);
|
||||
refreshStatus();
|
||||
}
|
||||
|
||||
abstract protected AbstractExporter getExporter();
|
||||
|
||||
|
||||
public ItemExportAbstract refreshStatus() {
|
||||
if (item != null) {
|
||||
if (getExporter().isRunning()) {
|
||||
setLoadingStatus();
|
||||
} else {
|
||||
setReadyStatus();
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected boolean onClick(Preference p) {
|
||||
setLoadingStatus();
|
||||
if (!onStartExporting()) {
|
||||
setReadyStatus();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
abstract protected boolean onStartExporting();
|
||||
|
||||
|
||||
protected void onFinishExporting(String outputFile) {
|
||||
activity.runOnUiThread(() -> {
|
||||
setReadyStatus();
|
||||
|
||||
if (outputFile == null) {
|
||||
DictionaryNotification.getInstance(activity).showError(
|
||||
activity.getString(R.string.dictionary_export_failed),
|
||||
activity.getString(R.string.dictionary_export_failed_more_info)
|
||||
);
|
||||
} else {
|
||||
DictionaryNotification.getInstance(activity).showMessage(
|
||||
activity.getString(R.string.dictionary_export_finished),
|
||||
activity.getString(R.string.dictionary_export_finished_more_info, outputFile),
|
||||
activity.getString(R.string.dictionary_export_finished_more_info, outputFile)
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
abstract protected String getLoadingMessage();
|
||||
|
||||
|
||||
protected void setLoadingStatus() {
|
||||
onStart.run();
|
||||
disable();
|
||||
|
||||
String loadingMessage = getLoadingMessage();
|
||||
item.setSummary(loadingMessage);
|
||||
DictionaryNotification.getInstance(activity).showLoadingMessage(loadingMessage, "");
|
||||
}
|
||||
|
||||
|
||||
public void setReadyStatus() {
|
||||
enable();
|
||||
onFinish.run();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
package io.github.sspanak.tt9.preferences.items;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import io.github.sspanak.tt9.R;
|
||||
import io.github.sspanak.tt9.db.exporter.CustomWordsExporter;
|
||||
|
||||
public class ItemExportCustomWords extends ItemExportAbstract {
|
||||
final public static String NAME = "dictionary_export_custom";
|
||||
|
||||
|
||||
public ItemExportCustomWords(Preference item, Activity activity, Runnable onStart, Runnable onFinish) {
|
||||
super(item, activity, onStart, onFinish);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected CustomWordsExporter getExporter() {
|
||||
return CustomWordsExporter.getInstance();
|
||||
}
|
||||
|
||||
|
||||
protected boolean onStartExporting() {
|
||||
return CustomWordsExporter.getInstance().export(activity);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected String getLoadingMessage() {
|
||||
return activity.getString(R.string.dictionary_export_generating_csv);
|
||||
}
|
||||
|
||||
public void setReadyStatus() {
|
||||
super.setReadyStatus();
|
||||
item.setSummary(activity.getString(
|
||||
R.string.dictionary_export_custom_words_summary,
|
||||
CustomWordsExporter.getInstance().getOutputDir()
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
package io.github.sspanak.tt9.preferences.items;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import io.github.sspanak.tt9.Logger;
|
||||
import io.github.sspanak.tt9.R;
|
||||
import io.github.sspanak.tt9.db.exporter.DictionaryExporter;
|
||||
import io.github.sspanak.tt9.languages.Language;
|
||||
import io.github.sspanak.tt9.languages.LanguageCollection;
|
||||
import io.github.sspanak.tt9.preferences.SettingsStore;
|
||||
|
||||
public class ItemExportDictionary extends ItemExportAbstract {
|
||||
final public static String NAME = "dictionary_export";
|
||||
|
||||
protected final SettingsStore settings;
|
||||
|
||||
|
||||
public ItemExportDictionary(Preference item, Activity activity, SettingsStore settings, Runnable onStart, Runnable onFinish) {
|
||||
super(item, activity, onStart, onFinish);
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemExportAbstract refreshStatus() {
|
||||
if (item != null) {
|
||||
item.setVisible(Logger.isDebugLevel());
|
||||
}
|
||||
return super.refreshStatus();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DictionaryExporter getExporter() {
|
||||
return DictionaryExporter.getInstance();
|
||||
}
|
||||
|
||||
|
||||
protected boolean onStartExporting() {
|
||||
return DictionaryExporter.getInstance()
|
||||
.setLanguages(LanguageCollection.getAll(activity, settings.getEnabledLanguageIds()))
|
||||
.export(activity);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getLoadingMessage() {
|
||||
String message = activity.getString(R.string.dictionary_export_generating_csv);
|
||||
|
||||
Language language = LanguageCollection.getLanguage(activity, settings.getInputLanguage());
|
||||
if (language != null) {
|
||||
message = activity.getString(R.string.dictionary_export_generating_csv_for_language, language.getName());
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
|
||||
public void setReadyStatus() {
|
||||
super.setReadyStatus();
|
||||
item.setSummary("");
|
||||
}
|
||||
}
|
||||
|
|
@ -17,21 +17,27 @@ import io.github.sspanak.tt9.ui.UI;
|
|||
|
||||
|
||||
public class ItemLoadDictionary extends ItemClickable {
|
||||
public static final String NAME = "dictionary_load";
|
||||
public final static String NAME = "dictionary_load";
|
||||
|
||||
private final Context context;
|
||||
private final SettingsStore settings;
|
||||
private final Runnable onStart;
|
||||
private final Runnable onFinish;
|
||||
|
||||
private final DictionaryLoader loader;
|
||||
private final DictionaryLoadingBar progressBar;
|
||||
|
||||
|
||||
public ItemLoadDictionary(Preference item, Context context, SettingsStore settings, DictionaryLoader loader, DictionaryLoadingBar progressBar) {
|
||||
public ItemLoadDictionary(Preference item, Context context, SettingsStore settings, Runnable onStart, Runnable onFinish) {
|
||||
super(item);
|
||||
|
||||
this.context = context;
|
||||
this.loader = loader;
|
||||
this.progressBar = progressBar;
|
||||
this.loader = DictionaryLoader.getInstance(context);
|
||||
this.progressBar = DictionaryLoadingBar.getInstance(context);
|
||||
this.settings = settings;
|
||||
this.onStart = onStart;
|
||||
this.onFinish = onFinish;
|
||||
|
||||
|
||||
loader.setOnStatusChange(this::onLoadingStatusChange);
|
||||
refreshStatus();
|
||||
|
|
@ -56,7 +62,7 @@ public class ItemLoadDictionary extends ItemClickable {
|
|||
} else if (progressBar.isFailed()) {
|
||||
setReadyStatus();
|
||||
UI.toastFromAsync(context, progressBar.getMessage());
|
||||
} else if (progressBar.isCompleted()) {
|
||||
} else if (!progressBar.inProgress()) {
|
||||
setReadyStatus();
|
||||
UI.toastFromAsync(context, R.string.dictionary_loaded);
|
||||
}
|
||||
|
|
@ -78,13 +84,13 @@ public class ItemLoadDictionary extends ItemClickable {
|
|||
|
||||
|
||||
private void setLoadingStatus() {
|
||||
disableOtherItems();
|
||||
onStart.run();
|
||||
item.setTitle(context.getString(R.string.dictionary_cancel_load));
|
||||
}
|
||||
|
||||
|
||||
private void setReadyStatus() {
|
||||
enableOtherItems();
|
||||
onFinish.run();
|
||||
item.setTitle(context.getString(R.string.dictionary_load_title));
|
||||
item.setSummary(progressBar.isFailed() || progressBar.isCancelled() ? progressBar.getMessage() : "");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import java.util.ArrayList;
|
|||
|
||||
import io.github.sspanak.tt9.R;
|
||||
import io.github.sspanak.tt9.db.WordStoreAsync;
|
||||
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;
|
||||
|
|
@ -17,22 +16,20 @@ public class ItemTruncateAll extends ItemClickable {
|
|||
public static final String NAME = "dictionary_truncate";
|
||||
|
||||
protected final PreferencesActivity activity;
|
||||
protected final DictionaryLoader loader;
|
||||
private final Runnable onStart;
|
||||
private final Runnable onFinish;
|
||||
|
||||
|
||||
public ItemTruncateAll(Preference item, PreferencesActivity activity, DictionaryLoader loader) {
|
||||
public ItemTruncateAll(Preference item, PreferencesActivity activity, Runnable onStart, Runnable onFinish) {
|
||||
super(item);
|
||||
this.activity = activity;
|
||||
this.loader = loader;
|
||||
this.onStart = onStart;
|
||||
this.onFinish = onFinish;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected boolean onClick(Preference p) {
|
||||
if (loader != null && loader.isRunning()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
onStartDeleting();
|
||||
ArrayList<Integer> languageIds = new ArrayList<>();
|
||||
for (Language lang : LanguageCollection.getAll(activity, false)) {
|
||||
|
|
@ -45,7 +42,7 @@ public class ItemTruncateAll extends ItemClickable {
|
|||
|
||||
|
||||
protected void onStartDeleting() {
|
||||
disableOtherItems();
|
||||
onStart.run();
|
||||
disable();
|
||||
item.setSummary(R.string.dictionary_truncating);
|
||||
}
|
||||
|
|
@ -53,7 +50,7 @@ public class ItemTruncateAll extends ItemClickable {
|
|||
|
||||
protected void onFinishDeleting() {
|
||||
activity.runOnUiThread(() -> {
|
||||
enableOtherItems();
|
||||
onFinish.run();
|
||||
item.setSummary("");
|
||||
enable();
|
||||
UI.toastFromAsync(activity, R.string.dictionary_truncated);
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import androidx.preference.Preference;
|
|||
import java.util.ArrayList;
|
||||
|
||||
import io.github.sspanak.tt9.db.WordStoreAsync;
|
||||
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;
|
||||
|
|
@ -18,19 +17,14 @@ public class ItemTruncateUnselected extends ItemTruncateAll {
|
|||
private final SettingsStore settings;
|
||||
|
||||
|
||||
public ItemTruncateUnselected(Preference item, PreferencesActivity context, SettingsStore settings, DictionaryLoader loader) {
|
||||
super(item, context, loader);
|
||||
public ItemTruncateUnselected(Preference item, PreferencesActivity context, SettingsStore settings, Runnable onStart, Runnable onFinish) {
|
||||
super(item, context, onStart, onFinish);
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
protected boolean onClick(Preference p) {
|
||||
if (loader != null && loader.isRunning()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ArrayList<Integer> unselectedLanguageIds = new ArrayList<>();
|
||||
ArrayList<Integer> selectedLanguageIds = settings.getEnabledLanguageIds();
|
||||
for (Language lang : LanguageCollection.getAll(activity, false)) {
|
||||
|
|
|
|||
|
|
@ -1,18 +1,28 @@
|
|||
package io.github.sspanak.tt9.preferences.screens;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import io.github.sspanak.tt9.R;
|
||||
import io.github.sspanak.tt9.db.DictionaryLoader;
|
||||
import io.github.sspanak.tt9.db.exporter.CustomWordsExporter;
|
||||
import io.github.sspanak.tt9.db.exporter.DictionaryExporter;
|
||||
import io.github.sspanak.tt9.preferences.PreferencesActivity;
|
||||
import io.github.sspanak.tt9.preferences.items.ItemClickable;
|
||||
import io.github.sspanak.tt9.preferences.items.ItemExportCustomWords;
|
||||
import io.github.sspanak.tt9.preferences.items.ItemExportDictionary;
|
||||
import io.github.sspanak.tt9.preferences.items.ItemLoadDictionary;
|
||||
import io.github.sspanak.tt9.preferences.items.ItemSelectLanguage;
|
||||
import io.github.sspanak.tt9.preferences.items.ItemTruncateAll;
|
||||
import io.github.sspanak.tt9.preferences.items.ItemTruncateUnselected;
|
||||
|
||||
public class DictionariesScreen extends BaseScreenFragment {
|
||||
final public static String NAME = "Dictionaries";
|
||||
public static final String NAME = "Dictionaries";
|
||||
|
||||
private final ArrayList<ItemClickable> clickables = new ArrayList<>();
|
||||
|
||||
private ItemLoadDictionary loadItem;
|
||||
private ItemExportDictionary exportDictionaryItem;
|
||||
private ItemExportCustomWords exportCustomWordsItem;
|
||||
|
||||
public DictionariesScreen() { init(); }
|
||||
public DictionariesScreen(PreferencesActivity activity) { init(activity); }
|
||||
|
|
@ -30,35 +40,78 @@ public class DictionariesScreen extends BaseScreenFragment {
|
|||
);
|
||||
multiSelect.populate().enableValidation();
|
||||
|
||||
loadItem = new ItemLoadDictionary(
|
||||
findPreference(ItemLoadDictionary.NAME),
|
||||
loadItem = new ItemLoadDictionary(findPreference(ItemLoadDictionary.NAME),
|
||||
activity,
|
||||
activity.settings,
|
||||
activity.getDictionaryLoader(),
|
||||
activity.getDictionaryProgressBar()
|
||||
() -> ItemClickable.disableOthers(clickables, loadItem),
|
||||
this::onActionFinish
|
||||
);
|
||||
|
||||
ItemTruncateUnselected deleteItem = new ItemTruncateUnselected(
|
||||
exportDictionaryItem = new ItemExportDictionary(findPreference(ItemExportDictionary.NAME),
|
||||
activity,
|
||||
activity.settings,
|
||||
this::onActionStart,
|
||||
this::onActionFinish
|
||||
);
|
||||
|
||||
clickables.add(loadItem);
|
||||
clickables.add(exportDictionaryItem);
|
||||
|
||||
clickables.add(new ItemTruncateUnselected(
|
||||
findPreference(ItemTruncateUnselected.NAME),
|
||||
activity,
|
||||
activity.settings,
|
||||
activity.getDictionaryLoader()
|
||||
);
|
||||
this::onActionStart,
|
||||
this::onActionFinish
|
||||
));
|
||||
|
||||
ItemTruncateAll truncateItem = new ItemTruncateAll(
|
||||
clickables.add(new ItemTruncateAll(
|
||||
findPreference(ItemTruncateAll.NAME),
|
||||
activity,
|
||||
activity.getDictionaryLoader()
|
||||
);
|
||||
this::onActionStart,
|
||||
this::onActionFinish
|
||||
));
|
||||
|
||||
loadItem.setOtherItems(Arrays.asList(truncateItem, deleteItem)).enableClickHandler();
|
||||
deleteItem.setOtherItems(Arrays.asList(truncateItem, loadItem)).enableClickHandler();
|
||||
truncateItem.setOtherItems(Arrays.asList(deleteItem, loadItem)).enableClickHandler();
|
||||
exportCustomWordsItem = new ItemExportCustomWords(
|
||||
findPreference(ItemExportCustomWords.NAME),
|
||||
activity,
|
||||
this::onActionStart,
|
||||
this::onActionFinish);
|
||||
|
||||
clickables.add(exportCustomWordsItem);
|
||||
|
||||
ItemClickable.enableAllClickHandlers(clickables);
|
||||
refreshItems();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
refreshItems();
|
||||
}
|
||||
|
||||
|
||||
private void refreshItems() {
|
||||
loadItem.refreshStatus();
|
||||
exportDictionaryItem.refreshStatus();
|
||||
exportCustomWordsItem.refreshStatus();
|
||||
|
||||
if (DictionaryLoader.getInstance(activity).isRunning()) {
|
||||
loadItem.refreshStatus();
|
||||
ItemClickable.disableOthers(clickables, loadItem);
|
||||
} else if (CustomWordsExporter.getInstance().isRunning() || DictionaryExporter.getInstance().isRunning()) {
|
||||
onActionStart();
|
||||
} else {
|
||||
onActionFinish();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void onActionStart() {
|
||||
ItemClickable.disableAll(clickables);
|
||||
}
|
||||
|
||||
private void onActionFinish() {
|
||||
ItemClickable.enableAll(clickables);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,8 @@
|
|||
package io.github.sspanak.tt9.ui;
|
||||
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.core.app.NotificationCompat;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.Locale;
|
||||
|
|
@ -21,28 +13,15 @@ import io.github.sspanak.tt9.languages.InvalidLanguageCharactersException;
|
|||
import io.github.sspanak.tt9.languages.InvalidLanguageException;
|
||||
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.screens.DictionariesScreen;
|
||||
|
||||
|
||||
public class DictionaryLoadingBar {
|
||||
public class DictionaryLoadingBar extends DictionaryNotification {
|
||||
private static DictionaryLoadingBar self;
|
||||
|
||||
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 boolean isStopped = false;
|
||||
private boolean hasFailed = false;
|
||||
|
||||
private int maxProgress = 0;
|
||||
private int progress = 0;
|
||||
private String title = "";
|
||||
private String message = "";
|
||||
|
||||
|
||||
public static DictionaryLoadingBar getInstance(Context context) {
|
||||
if (self == null) {
|
||||
|
|
@ -54,39 +33,17 @@ public class DictionaryLoadingBar {
|
|||
|
||||
|
||||
private DictionaryLoadingBar(Context context) {
|
||||
resources = context.getResources();
|
||||
|
||||
manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
notificationBuilder = getNotificationBuilderCompat(context);
|
||||
|
||||
notificationBuilder
|
||||
.setContentIntent(createNavigationIntent(context))
|
||||
.setSmallIcon(android.R.drawable.stat_notify_sync)
|
||||
.setCategory(NotificationCompat.CATEGORY_PROGRESS)
|
||||
.setOnlyAlertOnce(true);
|
||||
super(context);
|
||||
}
|
||||
|
||||
|
||||
private PendingIntent createNavigationIntent(Context context) {
|
||||
Intent intent = new Intent(context, PreferencesActivity.class);
|
||||
intent.putExtra("screen", DictionariesScreen.NAME);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||
return PendingIntent.getActivity(context, 0, intent,PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
|
||||
private NotificationCompat.Builder getNotificationBuilderCompat(Context context) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
manager.createNotificationChannel(new NotificationChannel(
|
||||
NOTIFICATION_CHANNEL_ID,
|
||||
"Dictionary Status",
|
||||
NotificationManager.IMPORTANCE_LOW
|
||||
));
|
||||
return new NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID);
|
||||
} else {
|
||||
//noinspection deprecation
|
||||
return new NotificationCompat.Builder(context);
|
||||
}
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -100,26 +57,11 @@ public class DictionaryLoadingBar {
|
|||
}
|
||||
|
||||
|
||||
public boolean isCompleted() {
|
||||
return progress >= maxProgress;
|
||||
}
|
||||
|
||||
|
||||
public boolean isFailed() {
|
||||
return hasFailed;
|
||||
}
|
||||
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
|
||||
public void show(Context context, Bundle data) {
|
||||
String error = data.getString("error", null);
|
||||
int fileCount = data.getInt("fileCount", -1);
|
||||
|
|
@ -185,7 +127,7 @@ public class DictionaryLoadingBar {
|
|||
message = currentFileProgress + "%";
|
||||
}
|
||||
|
||||
renderProgress();
|
||||
renderMessage();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -207,37 +149,4 @@ public class DictionaryLoadingBar {
|
|||
|
||||
renderError();
|
||||
}
|
||||
|
||||
|
||||
private void hide() {
|
||||
progress = maxProgress = 0;
|
||||
manager.cancel(NOTIFICATION_ID);
|
||||
}
|
||||
|
||||
|
||||
private void renderError() {
|
||||
NotificationCompat.BigTextStyle bigMessage = new NotificationCompat.BigTextStyle();
|
||||
bigMessage.setBigContentTitle(title);
|
||||
bigMessage.bigText(message);
|
||||
|
||||
notificationBuilder
|
||||
.setSmallIcon(android.R.drawable.stat_notify_error)
|
||||
.setStyle(bigMessage)
|
||||
.setOngoing(false)
|
||||
.setProgress(maxProgress, progress, false);
|
||||
|
||||
manager.notify(NOTIFICATION_ID, notificationBuilder.build());
|
||||
}
|
||||
|
||||
|
||||
private void renderProgress() {
|
||||
notificationBuilder
|
||||
.setSmallIcon(isCompleted() ? R.drawable.ic_done : android.R.drawable.stat_notify_sync)
|
||||
.setOngoing(!isCompleted())
|
||||
.setProgress(maxProgress, progress, false)
|
||||
.setContentTitle(title)
|
||||
.setContentText(message);
|
||||
|
||||
manager.notify(NOTIFICATION_ID, notificationBuilder.build());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,154 @@
|
|||
package io.github.sspanak.tt9.ui;
|
||||
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Build;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
|
||||
import io.github.sspanak.tt9.R;
|
||||
import io.github.sspanak.tt9.preferences.PreferencesActivity;
|
||||
import io.github.sspanak.tt9.preferences.screens.DictionariesScreen;
|
||||
|
||||
public abstract class DictionaryNotification {
|
||||
private static DictionaryNotification self;
|
||||
private static final int NOTIFICATION_ID = 1;
|
||||
private static final String NOTIFICATION_CHANNEL_ID = "dictionary-notifications";
|
||||
|
||||
private final NotificationManager manager;
|
||||
private final NotificationCompat.Builder notificationBuilder;
|
||||
protected final Resources resources;
|
||||
|
||||
protected int maxProgress = 0;
|
||||
protected int progress = 0;
|
||||
protected boolean indeterminate = false;
|
||||
protected String title = "";
|
||||
protected String message = "";
|
||||
protected String messageLong = "";
|
||||
|
||||
|
||||
protected DictionaryNotification(Context context) {
|
||||
resources = context.getResources();
|
||||
|
||||
manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
notificationBuilder = getNotificationBuilderCompat(context);
|
||||
|
||||
notificationBuilder
|
||||
.setContentIntent(createNavigationIntent(context))
|
||||
.setSmallIcon(android.R.drawable.stat_notify_sync)
|
||||
.setCategory(NotificationCompat.CATEGORY_PROGRESS)
|
||||
.setOnlyAlertOnce(true);
|
||||
}
|
||||
|
||||
|
||||
public static DictionaryNotification getInstance(Context context) {
|
||||
if (self == null) {
|
||||
self = new DictionaryNotification(context) {
|
||||
};
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
private PendingIntent createNavigationIntent(Context context) {
|
||||
Intent intent = new Intent(context, PreferencesActivity.class);
|
||||
intent.putExtra("screen", DictionariesScreen.NAME);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||
return PendingIntent.getActivity(context, 0, intent,PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
|
||||
}
|
||||
|
||||
|
||||
private NotificationCompat.Builder getNotificationBuilderCompat(Context context) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
manager.createNotificationChannel(new NotificationChannel(
|
||||
NOTIFICATION_CHANNEL_ID,
|
||||
"Dictionary Status",
|
||||
NotificationManager.IMPORTANCE_LOW
|
||||
));
|
||||
return new NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID);
|
||||
} else {
|
||||
//noinspection deprecation
|
||||
return new NotificationCompat.Builder(context);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void showMessage(@NonNull String title, @NonNull String message, @NonNull String messageLong) {
|
||||
progress = maxProgress = 0;
|
||||
indeterminate = false;
|
||||
this.title = title;
|
||||
this.message = message;
|
||||
this.messageLong = messageLong;
|
||||
renderMessage();
|
||||
}
|
||||
|
||||
|
||||
public void showLoadingMessage(@NonNull String title, @NonNull String message) {
|
||||
this.title = title;
|
||||
this.message = message;
|
||||
messageLong = "";
|
||||
indeterminate = true;
|
||||
progress = 1;
|
||||
maxProgress = 2;
|
||||
renderMessage();
|
||||
}
|
||||
|
||||
|
||||
public void showError(@NonNull String title, @NonNull String message) {
|
||||
progress = maxProgress = 0;
|
||||
indeterminate = false;
|
||||
this.title = title;
|
||||
this.message = message;
|
||||
renderError();
|
||||
}
|
||||
|
||||
|
||||
protected void hide() {
|
||||
progress = maxProgress = 0;
|
||||
manager.cancel(NOTIFICATION_ID);
|
||||
}
|
||||
|
||||
|
||||
public boolean inProgress() {
|
||||
return progress < maxProgress;
|
||||
}
|
||||
|
||||
|
||||
protected void renderError() {
|
||||
NotificationCompat.BigTextStyle bigMessage = new NotificationCompat.BigTextStyle();
|
||||
bigMessage.setBigContentTitle(title);
|
||||
bigMessage.bigText(message);
|
||||
|
||||
notificationBuilder
|
||||
.setSmallIcon(android.R.drawable.stat_notify_error)
|
||||
.setContentTitle(title)
|
||||
.setContentText(message)
|
||||
.setOngoing(false)
|
||||
.setStyle(bigMessage)
|
||||
.setProgress(maxProgress, progress, false);
|
||||
|
||||
manager.notify(NOTIFICATION_ID, notificationBuilder.build());
|
||||
}
|
||||
|
||||
|
||||
protected void renderMessage() {
|
||||
NotificationCompat.BigTextStyle bigMessage = new NotificationCompat.BigTextStyle();
|
||||
bigMessage.setBigContentTitle(title);
|
||||
bigMessage.bigText(messageLong.isEmpty() ? message : messageLong);
|
||||
|
||||
notificationBuilder
|
||||
.setSmallIcon(inProgress() ? android.R.drawable.stat_notify_sync : R.drawable.ic_done)
|
||||
.setOngoing(inProgress())
|
||||
.setProgress(maxProgress, progress, indeterminate)
|
||||
.setStyle(bigMessage)
|
||||
.setContentTitle(title)
|
||||
.setContentText(message);
|
||||
|
||||
manager.notify(NOTIFICATION_ID, notificationBuilder.build());
|
||||
}
|
||||
}
|
||||
|
|
@ -34,6 +34,11 @@
|
|||
<string name="pref_show_soft_function_keys">Бутони на екрана</string>
|
||||
<string name="key_back">Назад</string>
|
||||
<string name="key_call">Зелена слушалка</string>
|
||||
<string name="dictionary_export">Експортирай избраните</string>
|
||||
<string name="dictionary_export_custom_words_button">Експортирай</string>
|
||||
<string name="dictionary_export_custom_words_summary">Експортиране на CSV с всички добавени думи в: „%1$s“.</string>
|
||||
<string name="dictionary_export_failed">Неуспешно експортиране</string>
|
||||
<string name="dictionary_export_failed_more_info">За повече информация, активирайте режима за отстраняване на грешки и прегледайте журнала.</string>
|
||||
<string name="dictionary_update_message">Налично е обновление на речника за „%1$s“. Искате ли да го заредите?</string>
|
||||
<string name="dictionary_update_update">Зареди</string>
|
||||
<string name="donate_title">Дарете</string>
|
||||
|
|
@ -86,4 +91,8 @@
|
|||
<string name="add_word_confirm">Да се добави ли „%1$s“ към %2$s?</string>
|
||||
<string name="pref_hack_key_pad_debounce_time">Защита от случайно повтарящи бутони</string>
|
||||
<string name="pref_hack_key_pad_debounce_off">Изключена</string>
|
||||
<string name="dictionary_export_finished">Експортирането завърши</string>
|
||||
<string name="dictionary_export_finished_more_info">Думите са експортирани в: „%1$s“.</string>
|
||||
<string name="dictionary_export_generating_csv">Експортиране на CSV…</string>
|
||||
<string name="dictionary_export_generating_csv_for_language">Експортиране на CSV (%1$s)…</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -31,6 +31,11 @@
|
|||
<string name="pref_dark_theme_yes">Ja</string>
|
||||
<string name="pref_dark_theme_no">Nein</string>
|
||||
<string name="pref_dark_theme_auto">Automatisch</string>
|
||||
<string name="dictionary_export">Ausgewählte exportieren</string>
|
||||
<string name="dictionary_export_custom_words_button">Exportieren</string>
|
||||
<string name="dictionary_export_custom_words_summary">Exportiere ein CSV mit allen hinzugefügten Wörtern nach: „%1$s“.</string>
|
||||
<string name="dictionary_export_failed">Export fehlgeschlagen</string>
|
||||
<string name="dictionary_export_failed_more_info">Für weitere Informationen, aktivieren Sie den Debug-Modus und sehen Sie sich die Protokolle an.</string>
|
||||
<string name="dictionary_update_message">" Wörterbuchupdate verfügbar für „%1$s“. Möchten Sie es laden?"</string>
|
||||
<string name="dictionary_update_update">Laden</string>
|
||||
<string name="donate_title">Spenden</string>
|
||||
|
|
@ -39,4 +44,8 @@
|
|||
<string name="pref_hack_google_chat">Nachrichten mit \"OK\" in Google Chat senden</string>
|
||||
<string name="pref_hack_key_pad_debounce_time">Schutz vor versehentlichem Tastenwiederholen</string>
|
||||
<string name="pref_hack_key_pad_debounce_off">Aus</string>
|
||||
<string name="dictionary_export_finished">Export abgeschlossen</string>
|
||||
<string name="dictionary_export_finished_more_info">Wörter exportiert nach: „%1$s“.</string>
|
||||
<string name="dictionary_export_generating_csv">CSV wird exportiert…</string>
|
||||
<string name="dictionary_export_generating_csv_for_language">CSV wird exportiert (%1$s)…</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -74,6 +74,11 @@
|
|||
<string name="pref_dark_theme_yes">Sí</string>
|
||||
<string name="pref_dark_theme_no">No</string>
|
||||
<string name="pref_dark_theme_auto">Automática</string>
|
||||
<string name="dictionary_export">Exportar seleccionados</string>
|
||||
<string name="dictionary_export_custom_words_button">Exportar</string>
|
||||
<string name="dictionary_export_custom_words_summary">Exportar un CSV con todas las palabras añadidas a: \"%1$s\".</string>
|
||||
<string name="dictionary_export_failed">Fallo en la exportación</string>
|
||||
<string name="dictionary_export_failed_more_info">Para obtener más información, habilita el modo de depuración y consulta los registros.</string>
|
||||
<string name="dictionary_update_message">Actualización del diccionario disponible para «%1$s». ¿Te gustaría cargarlo?</string>
|
||||
<string name="dictionary_update_update">Cargar</string>
|
||||
<string name="donate_title">Donar</string>
|
||||
|
|
@ -82,4 +87,8 @@
|
|||
<string name="pref_hack_google_chat">Enviar mensajes con «OK» en Google Chat</string>
|
||||
<string name="pref_hack_key_pad_debounce_time">Protección contra la repetición accidental de teclas</string>
|
||||
<string name="pref_hack_key_pad_debounce_off">Apagado</string>
|
||||
<string name="dictionary_export_finished">" Exportación completada"</string>
|
||||
<string name="dictionary_export_finished_more_info">Palabras exportadas a: \"%1$s\".</string>
|
||||
<string name="dictionary_export_generating_csv">Exportando CSV…</string>
|
||||
<string name="dictionary_export_generating_csv_for_language">Exportando CSV (%1$s)…</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -74,10 +74,19 @@
|
|||
<string name="pref_dark_theme_no">Non</string>
|
||||
<string name="pref_dark_theme_auto">Automatique</string>
|
||||
<string name="add_word_confirm">Ajouter mot « %1$s » à %2$s?</string>
|
||||
<string name="dictionary_export">Exporter les sélectionées</string>
|
||||
<string name="dictionary_export_custom_words_button">Exporter</string>
|
||||
<string name="dictionary_export_custom_words_summary">Exporter un CSV avec tous les mots ajoutés vers : «%1$s».</string>
|
||||
<string name="dictionary_export_failed">Échec de l\'exportation</string>
|
||||
<string name="dictionary_export_failed_more_info">Pour plus d\'informations, activez le mode de débogage et consultez les journaux.</string>
|
||||
<string name="dictionary_update_message">Mise à jour du dictionnaire «%1$s» disponible. Souhaitez-vous le charger ?</string>
|
||||
<string name="dictionary_update_update">Charger</string>
|
||||
<string name="donate_title">Donner</string>
|
||||
<string name="donate_summary">Si vous aimez %1$s vous pouvez soutenir son développement à : %2$s</string>
|
||||
<string name="pref_hack_key_pad_debounce_time">Protection contre la répétition accidentelle des touches</string>
|
||||
<string name="pref_hack_key_pad_debounce_off">Désactivée</string>
|
||||
<string name="dictionary_export_finished">Exportation terminée</string>
|
||||
<string name="dictionary_export_finished_more_info">Mots exportés vers : «%1$s».</string>
|
||||
<string name="dictionary_export_generating_csv">Exportation CSV en cours…</string>
|
||||
<string name="dictionary_export_generating_csv_for_language">Exportation CSV en cours (%1$s)…</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -40,6 +40,11 @@
|
|||
<string name="pref_dark_theme_yes">Si</string>
|
||||
<string name="pref_dark_theme_no">No</string>
|
||||
<string name="pref_dark_theme_auto">Automatica</string>
|
||||
<string name="dictionary_export">Esporta selezionate</string>
|
||||
<string name="dictionary_export_custom_words_button">Esportare</string>
|
||||
<string name="dictionary_export_custom_words_summary">Esporta un CSV con tutte le parole aggiunte su: \"%1$s\".</string>
|
||||
<string name="dictionary_export_failed">Esportazione fallita</string>
|
||||
<string name="dictionary_export_failed_more_info">Per ulteriori informazioni, abilita la modalità di debug e consulta i log.</string>
|
||||
<string name="dictionary_update_message">Aggiornamento del dizionario disponibile per \"%1$s\". Vuoi caricarlo?</string>
|
||||
<string name="dictionary_update_update">Carica</string>
|
||||
<string name="donate_title">Donare</string>
|
||||
|
|
@ -48,5 +53,9 @@
|
|||
<string name="pref_hack_google_chat">Inviare messaggi con \"OK\" su Google Chat</string>
|
||||
<string name="pref_hack_key_pad_debounce_time">Protezione contro la ripetizione accidentale dei tasti</string>
|
||||
<string name="pref_hack_key_pad_debounce_off">Spento</string>
|
||||
<string name="dictionary_export_finished">Esportazione completata</string>
|
||||
<string name="dictionary_export_finished_more_info">Parole esportate su: \"%1$s\".</string>
|
||||
<string name="dictionary_export_generating_csv">CSV in corso…</string>
|
||||
<string name="dictionary_export_generating_csv_for_language">CSV in corso (%1$s)…</string>
|
||||
</resources>
|
||||
|
||||
|
|
|
|||
|
|
@ -67,6 +67,11 @@
|
|||
<string name="pref_dark_theme_yes">כן</string>
|
||||
<string name="pref_dark_theme_no">לא</string>
|
||||
<string name="pref_dark_theme_auto">אוטומטי</string>
|
||||
<string name="dictionary_export">ייצוא שנבחר</string>
|
||||
<string name="dictionary_export_custom_words_button">לְיְצוֹא</string>
|
||||
<string name="dictionary_export_custom_words_summary">ייצוא CSV עם כל המילים שנוספו ל: \"%1$s\".</string>
|
||||
<string name="dictionary_export_failed">נכשל בייצוא</string>
|
||||
<string name="dictionary_export_failed_more_info">"למידע נוסף, הפעל מצב איתור באגים וראה את הלוגים. "</string>
|
||||
<string name="dictionary_update_message">עדכון מילון זמין עבור \"%1$s\". האם תרצה לטעון אותו?</string>
|
||||
<string name="dictionary_update_update">טען</string>
|
||||
<string name="donate_title">לִתְרוֹם</string>
|
||||
|
|
@ -75,4 +80,8 @@
|
|||
<string name="pref_hack_google_chat">שלח הודעות עם \"OK\" ב-Google Chat</string>
|
||||
<string name="pref_hack_key_pad_debounce_time">הגנה מפני חזרת מפתח בשוגג</string>
|
||||
<string name="pref_hack_key_pad_debounce_off">כבוי</string>
|
||||
<string name="dictionary_export_finished">הייצוא הושלם</string>
|
||||
<string name="dictionary_export_finished_more_info">המילים יוצאות ל: \"%1$s\".</string>
|
||||
<string name="dictionary_export_generating_csv">מייצא CSV…</string>
|
||||
<string name="dictionary_export_generating_csv_for_language">מייצא CSV (%1$s)...</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -31,6 +31,11 @@
|
|||
<string name="pref_dark_theme_yes">Ja</string>
|
||||
<string name="pref_dark_theme_no">Nee</string>
|
||||
<string name="pref_dark_theme_auto">Automatisch</string>
|
||||
<string name="dictionary_export">Geselecteerde exporteren</string>
|
||||
<string name="dictionary_export_custom_words_button">Exporteren</string>
|
||||
<string name="dictionary_export_custom_words_summary">Exporteer een CSV met alle toegevoegde woorden naar: \"%1$s\".</string>
|
||||
<string name="dictionary_export_failed">Exporteren mislukt</string>
|
||||
<string name="dictionary_export_failed_more_info">Voor meer informatie, schakel de debug-modus in en bekijk de logs.</string>
|
||||
<string name="dictionary_update_message">Woordenboekupdate beschikbaar voor \"%1$s\". Wil je het laden?</string>
|
||||
<string name="dictionary_update_update">Laden</string>
|
||||
<string name="donate_title">Doneer</string>
|
||||
|
|
@ -39,4 +44,8 @@
|
|||
<string name="pref_hack_google_chat">Stuur berichten met \"OK\" in Google Chat</string>
|
||||
<string name="pref_hack_key_pad_debounce_time">Bescherming tegen het per ongeluk herhalen van toetsen</string>
|
||||
<string name="pref_hack_key_pad_debounce_off">Uit</string>
|
||||
<string name="dictionary_export_finished">Export voltooid</string>
|
||||
<string name="dictionary_export_finished_more_info">Woorden geëxporteerd naar: \"%1$s\".</string>
|
||||
<string name="dictionary_export_generating_csv">CSV exporteren…</string>
|
||||
<string name="dictionary_export_generating_csv_for_language">CSV exporteren (%1$s)…</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -63,6 +63,11 @@
|
|||
<string name="pref_dark_theme_yes">Sim</string>
|
||||
<string name="pref_dark_theme_no">Não</string>
|
||||
<string name="pref_dark_theme_auto">Automático</string>
|
||||
<string name="dictionary_export">Exportar selecionados</string>
|
||||
<string name="dictionary_export_custom_words_button">Exportar</string>
|
||||
<string name="dictionary_export_custom_words_summary">Exportar um CSV com todas as palavras adicionadas para: \"%1$s\".</string>
|
||||
<string name="dictionary_export_failed">Falha na exportação</string>
|
||||
<string name="dictionary_export_failed_more_info">Para mais informações, ative o modo de depuração e veja os registros.</string>
|
||||
<string name="dictionary_update_message">Atualização do dicionário disponível para \"%1$s\". Você gostaria de carregá-lo?</string>
|
||||
<string name="dictionary_update_update">Carregar</string>
|
||||
<string name="donate_title">Doar</string>
|
||||
|
|
@ -71,4 +76,8 @@
|
|||
<string name="pref_hack_google_chat">Enviar mensagens com \"OK\" no Google Chat</string>
|
||||
<string name="pref_hack_key_pad_debounce_time">Proteção contra repetição acidental de teclas</string>
|
||||
<string name="pref_hack_key_pad_debounce_off">Desligado</string>
|
||||
<string name="dictionary_export_finished">Exportação concluída</string>
|
||||
<string name="dictionary_export_finished_more_info">Palavras exportadas para: \"%1$s\".</string>
|
||||
<string name="dictionary_export_generating_csv">Exportando CSV…</string>
|
||||
<string name="dictionary_export_generating_csv_for_language">Exportando CSV (%1$s)…</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -79,6 +79,11 @@
|
|||
<string name="pref_dark_theme_no">Нет</string>
|
||||
<string name="pref_dark_theme_auto">Автоматически</string>
|
||||
<string name="add_word_confirm">Добавить слово «%1$s» в %2$s?</string>
|
||||
<string name="dictionary_export">Экспорт выбранные</string>
|
||||
<string name="dictionary_export_custom_words_button">Экспортировать</string>
|
||||
<string name="dictionary_export_custom_words_summary">Экспорт CSV со всеми добавленными словами в: «%1$s».</string>
|
||||
<string name="dictionary_export_failed">Ошибка экспорта</string>
|
||||
<string name="dictionary_export_failed_more_info">Для получения дополнительной информации включите режим отладки и просмотрите журналы.</string>
|
||||
<string name="dictionary_update_message">Доступно обновление словаря для «%1$s». Хотите загрузить его?</string>
|
||||
<string name="dictionary_update_update">Загрузить</string>
|
||||
<string name="donate_title">Поддержать</string>
|
||||
|
|
@ -86,4 +91,8 @@
|
|||
<string name="pref_hack_google_chat">Отправка сообщения с «ОК» в Google Chat</string>
|
||||
<string name="pref_hack_key_pad_debounce_time">Защита от случайного повторения нажатий</string>
|
||||
<string name="pref_hack_key_pad_debounce_off">Выключена</string>
|
||||
<string name="dictionary_export_finished">Экспорт завершен</string>
|
||||
<string name="dictionary_export_finished_more_info">Слова экспортированы в: «%1$s».</string>
|
||||
<string name="dictionary_export_generating_csv">Экспорт CSV…</string>
|
||||
<string name="dictionary_export_generating_csv_for_language">Экспорт CSV (%1$s)…</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -64,6 +64,11 @@
|
|||
<string name="dictionary_truncated">Словник видалено.</string>
|
||||
<string name="dictionary_truncating">Видаляється…</string>
|
||||
|
||||
<string name="dictionary_export">Експорт вибрані</string>
|
||||
<string name="dictionary_export_custom_words_button">Експортувати</string>
|
||||
<string name="dictionary_export_custom_words_summary">Експорт CSV з усіма доданими словами в: \"%1$s\".</string>
|
||||
<string name="dictionary_export_failed">Помилка експорту</string>
|
||||
<string name="dictionary_export_failed_more_info">Для отримання додаткової інформації увімкніть режим відлагодження та перегляньте журнали.</string>
|
||||
<string name="dictionary_update_message">Доступне оновлення словника для \"%1$s\". Бажаєте його завантажити?</string>
|
||||
<string name="dictionary_update_update">Завантажити</string>
|
||||
|
||||
|
|
@ -97,4 +102,8 @@
|
|||
|
||||
<string name="char_newline">Новий рядок</string>
|
||||
<string name="char_space">Пробіл</string>
|
||||
<string name="dictionary_export_finished">Експорт завершено</string>
|
||||
<string name="dictionary_export_finished_more_info">Слова експортовані в: \" %1$s \".</string>
|
||||
<string name="dictionary_export_generating_csv">Експорт CSV…</string>
|
||||
<string name="dictionary_export_generating_csv_for_language">Експорт CSV (%1$s)…</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
<string name="pref_category_about">About</string>
|
||||
<string name="pref_category_abc_mode">ABC Mode</string>
|
||||
<string name="pref_category_custom_words">Added Words</string>
|
||||
<string name="pref_category_hacks">Compatibility</string>
|
||||
<string name="pref_category_appearance">Appearance</string>
|
||||
<string name="pref_category_debug_options" translatable="false">Debug Options</string>
|
||||
|
|
@ -71,6 +72,16 @@
|
|||
<string name="dictionary_truncated">Dictionary successfully cleared.</string>
|
||||
<string name="dictionary_truncating">Deleting…</string>
|
||||
|
||||
<string name="dictionary_export">Export Selected</string>
|
||||
<string name="dictionary_export_custom_words_button">Export</string>
|
||||
<string name="dictionary_export_custom_words_summary">Export a CSV with all added words in: \"%1$s\".</string>
|
||||
<string name="dictionary_export_failed">Exporting Failed</string>
|
||||
<string name="dictionary_export_failed_more_info">For more info, enable debugging mode and see the logs.</string>
|
||||
<string name="dictionary_export_finished">Exporting Finished</string>
|
||||
<string name="dictionary_export_finished_more_info">Words exported to: \"%1$s\".</string>
|
||||
<string name="dictionary_export_generating_csv">Exporting CSV…</string>
|
||||
<string name="dictionary_export_generating_csv_for_language">Exporting CSV (%1$s)…</string>
|
||||
|
||||
<string name="dictionary_update_message">Dictionary update available for \"%1$s\". Would you like to load it?</string>
|
||||
<string name="dictionary_update_update">Load</string>
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,12 @@
|
|||
app:layout="@layout/pref_text"
|
||||
app:title="@string/dictionary_load_title" />
|
||||
|
||||
<Preference
|
||||
app:key="dictionary_export"
|
||||
app:layout="@layout/pref_text"
|
||||
app:title="@string/dictionary_export"
|
||||
app:isPreferenceVisible="false" />
|
||||
|
||||
<Preference
|
||||
app:key="dictionary_truncate_unselected"
|
||||
app:layout="@layout/pref_text"
|
||||
|
|
@ -21,4 +27,16 @@
|
|||
app:layout="@layout/pref_text"
|
||||
app:title="@string/dictionary_truncate_title" />
|
||||
|
||||
<PreferenceCategory
|
||||
app:title="@string/pref_category_custom_words"
|
||||
app:layout="@layout/pref_category"
|
||||
app:singleLineTitle="true">
|
||||
|
||||
<Preference
|
||||
app:key="dictionary_export_custom"
|
||||
app:layout="@layout/pref_text"
|
||||
app:title="@string/dictionary_export_custom_words_button" />
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
</PreferenceScreen>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue