1
0
Fork 0

fixed the delete dictionary buttons not staying locked when navigating from and to the Languages screen, while deletion is in progress

This commit is contained in:
sspanak 2025-01-06 17:32:19 +02:00 committed by Dimo Karaivanov
parent fec7d62168
commit f7e11c7445
7 changed files with 152 additions and 59 deletions

View file

@ -11,7 +11,6 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import io.github.sspanak.tt9.db.entities.AddWordResult;
import io.github.sspanak.tt9.db.wordPairs.WordPairStore;
@ -21,7 +20,6 @@ import io.github.sspanak.tt9.languages.Language;
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
import io.github.sspanak.tt9.util.ConsumerCompat;
import io.github.sspanak.tt9.util.Logger;
import io.github.sspanak.tt9.util.Timer;
public class DataStore {
private final static String LOG_TAG = DataStore.class.getSimpleName();
@ -80,27 +78,6 @@ public class DataStore {
}
public static void deleteLanguages(Runnable notification, @NonNull ArrayList<Language> languages) {
Timer.start(LOG_TAG);
AtomicInteger progress = new AtomicInteger(languages.size());
Runnable onDeleted = () -> {
if (progress.decrementAndGet() == 0) {
Logger.d(LOG_TAG, "Deleted " + languages.size() + " languages. Time: " + Timer.stop(LOG_TAG) + " ms");
notification.run();
}
};
for (Language language : languages) {
runInTransaction(
() -> { words.remove(language); pairs.remove(language); },
onDeleted,
"Failed deleting languages."
);
}
}
public static void put(ConsumerCompat<AddWordResult> statusHandler, Language language, String word) {
runInThread(() -> statusHandler.accept(words.put(language, word)));
}

View file

@ -165,17 +165,6 @@ public class WordPairStore extends BaseSyncStore {
}
public void remove(@NonNull Language language) {
if (!checkOrNotify()) {
return;
}
DeleteOps.deleteWordPairs(sqlite.getDb(), language.getId());
slowestLoadTime = 0;
slowestSaveTime = 0;
}
public void remove(@NonNull ArrayList<Language> languages) {
if (!checkOrNotify()) {
return;

View file

@ -0,0 +1,106 @@
package io.github.sspanak.tt9.db.words;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.util.ArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import io.github.sspanak.tt9.db.BaseSyncStore;
import io.github.sspanak.tt9.db.sqlite.DeleteOps;
import io.github.sspanak.tt9.languages.Language;
import io.github.sspanak.tt9.languages.NaturalLanguage;
import io.github.sspanak.tt9.util.Logger;
import io.github.sspanak.tt9.util.Timer;
public class DictionaryDeleter extends BaseSyncStore {
private static final String LOG_TAG = DictionaryDeleter.class.getSimpleName();
private static DictionaryDeleter self;
@NonNull private final ExecutorService executor = Executors.newSingleThreadExecutor();
@Nullable Future<?> deleteTask;
@Nullable private Runnable notification;
protected DictionaryDeleter(Context context) {
super(context);
}
public static DictionaryDeleter getInstance(Context context) {
if (self == null) {
self = new DictionaryDeleter(context);
}
return self;
}
public void deleteLanguages(@NonNull ArrayList<Language> languages) {
if (!checkOrNotify()) {
onFinish();
return;
}
Timer.start(LOG_TAG);
deleteTask = executor.submit(() -> deleteLanguagesSync(languages));
}
private void deleteLanguagesSync(@NonNull ArrayList<Language> languages) {
for (Language language : languages) {
if (!deleteLanguage(language)) {
break;
}
}
deleteTask = null;
if (notification != null) {
notification.run();
}
Logger.d(LOG_TAG, "Deleted " + languages.size() + " languages. Time: " + Timer.stop(LOG_TAG) + " ms");
}
private boolean deleteLanguage(Language language) {
if (!(language instanceof NaturalLanguage)) {
Logger.w(LOG_TAG, "Invalid language type to delete: " + language.getClass().getSimpleName() + ". Skipping.");
return true;
}
try {
sqlite.beginTransaction();
DeleteOps.delete(sqlite.getDb(), language.getId());
DeleteOps.deleteWordPairs(sqlite.getDb(), language.getId());
sqlite.finishTransaction();
} catch (Exception e) {
sqlite.failTransaction();
Logger.e(LOG_TAG, "Failed deleting language: " + language.getId() + ". " + e.getMessage());
return false;
}
return true;
}
private void onFinish() {
if (notification != null) {
notification.run();
}
}
public boolean isRunning() {
return deleteTask != null && !deleteTask.isDone();
}
public void setOnFinish(Runnable notification) {
this.notification = notification;
}
}

View file

@ -118,13 +118,6 @@ public class WordStore extends BaseSyncStore {
}
public void remove(Language language) {
if (checkOrNotify() && readOps.exists(sqlite.getDb(), language.getId())) {
DeleteOps.delete(sqlite.getDb(), language.getId());
}
}
public void removeCustomWord(Language language, String word) {
if (language == null || language instanceof NullLanguage || !checkOrNotify()) {
return;

View file

@ -3,7 +3,7 @@ package io.github.sspanak.tt9.preferences.screens.languages;
import androidx.preference.Preference;
import io.github.sspanak.tt9.R;
import io.github.sspanak.tt9.db.DataStore;
import io.github.sspanak.tt9.db.words.DictionaryDeleter;
import io.github.sspanak.tt9.languages.LanguageCollection;
import io.github.sspanak.tt9.preferences.PreferencesActivity;
import io.github.sspanak.tt9.preferences.items.ItemClickable;
@ -14,6 +14,7 @@ class ItemTruncateAll extends ItemClickable {
public static final String NAME = "dictionary_truncate";
protected final PreferencesActivity activity;
protected final DictionaryDeleter deleter;
private final Runnable onStart;
private final Runnable onFinish;
@ -21,31 +22,49 @@ class ItemTruncateAll extends ItemClickable {
ItemTruncateAll(Preference item, PreferencesActivity activity, Runnable onStart, Runnable onFinish) {
super(item);
this.activity = activity;
this.deleter = DictionaryDeleter.getInstance(activity);
this.onStart = onStart;
this.onFinish = onFinish;
refreshStatus();
}
@Override
protected boolean onClick(Preference p) {
onStartDeleting();
DataStore.deleteLanguages(this::onFinishDeleting, LanguageCollection.getAll(false));
onStart.run();
setBusy();
deleter.deleteLanguages(LanguageCollection.getAll(false));
return true;
}
protected void onStartDeleting() {
onStart.run();
disable();
void refreshStatus() {
if (deleter.isRunning()) {
setBusy();
} else {
enable();
}
}
protected void setBusy() {
deleter.setOnFinish(this::onFinishDeleting);
item.setSummary(R.string.dictionary_truncating);
disable();
}
public void enable() {
super.enable();
item.setSummary("");
}
protected void onFinishDeleting() {
activity.runOnUiThread(() -> {
onFinish.run();
item.setSummary("");
enable();
UI.toastFromAsync(activity, R.string.dictionary_truncated);
});

View file

@ -6,7 +6,6 @@ import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import io.github.sspanak.tt9.db.DataStore;
import io.github.sspanak.tt9.languages.Language;
import io.github.sspanak.tt9.languages.LanguageCollection;
import io.github.sspanak.tt9.preferences.PreferencesActivity;
@ -31,8 +30,9 @@ class ItemTruncateUnselected extends ItemTruncateAll {
}
}
onStartDeleting();
DataStore.deleteLanguages(this::onFinishDeleting, unselectedLanguages);
setBusy();
deleter.setOnFinish(this::onFinishDeleting);
deleter.deleteLanguages(unselectedLanguages);
return true;
}

View file

@ -11,6 +11,7 @@ import io.github.sspanak.tt9.R;
import io.github.sspanak.tt9.db.customWords.CustomWordsExporter;
import io.github.sspanak.tt9.db.customWords.CustomWordsImporter;
import io.github.sspanak.tt9.db.customWords.DictionaryExporter;
import io.github.sspanak.tt9.db.words.DictionaryDeleter;
import io.github.sspanak.tt9.db.words.DictionaryLoader;
import io.github.sspanak.tt9.preferences.PreferencesActivity;
import io.github.sspanak.tt9.preferences.items.ItemClickable;
@ -19,12 +20,14 @@ import io.github.sspanak.tt9.preferences.screens.BaseScreenFragment;
public class LanguagesScreen extends BaseScreenFragment {
public static final String NAME = "Languages";
private final ArrayList<ItemClickable> clickables = new ArrayList<>();
private static final ArrayList<ItemClickable> clickables = new ArrayList<>();
private ItemLoadDictionary loadItem;
private ItemImportCustomWords importCustomWordsItem;
private ItemExportDictionary exportDictionaryItem;
private ItemExportCustomWords exportCustomWordsItem;
private ItemTruncateAll truncateAllItem;
private ItemTruncateUnselected truncateUnselectedItem;
public LanguagesScreen() { init(); }
public LanguagesScreen(PreferencesActivity activity) { init(activity); }
@ -56,22 +59,25 @@ public class LanguagesScreen extends BaseScreenFragment {
this::onActionFinish
);
clickables.add(loadItem);
clickables.add(exportDictionaryItem);
clickables.add(new ItemTruncateUnselected(
truncateUnselectedItem = new ItemTruncateUnselected(
findPreference(ItemTruncateUnselected.NAME),
activity,
this::onActionStart,
this::onActionFinish
));
);
clickables.add(new ItemTruncateAll(
truncateAllItem = new ItemTruncateAll(
findPreference(ItemTruncateAll.NAME),
activity,
this::onActionStart,
this::onActionFinish
));
);
clickables.clear();
clickables.add(loadItem);
clickables.add(exportDictionaryItem);
clickables.add(truncateUnselectedItem);
clickables.add(truncateAllItem);
clickables.add(new ItemDeleteCustomWords(findPreference(ItemDeleteCustomWords.NAME)));
@ -112,6 +118,8 @@ public class LanguagesScreen extends BaseScreenFragment {
exportDictionaryItem.refreshStatus();
exportCustomWordsItem.refreshStatus();
importCustomWordsItem.refreshStatus();
truncateUnselectedItem.refreshStatus();
truncateAllItem.refreshStatus();
if (DictionaryLoader.getInstance(activity).isRunning()) {
loadItem.refreshStatus();
@ -120,6 +128,7 @@ public class LanguagesScreen extends BaseScreenFragment {
CustomWordsExporter.getInstance().isRunning()
|| DictionaryExporter.getInstance().isRunning()
|| CustomWordsImporter.getInstance(activity).isRunning()
|| DictionaryDeleter.getInstance(activity).isRunning()
) {
onActionStart();
} else {