From 322774ab45bdb3c1776bd9464f934c7bd107b860 Mon Sep 17 00:00:00 2001 From: sspanak Date: Thu, 7 Mar 2024 11:52:18 +0200 Subject: [PATCH] added a new screen, in the Settings, for deleting added words --- .../sspanak/tt9/db/DictionaryLoader.java | 4 +- .../io/github/sspanak/tt9/db/WordStore.java | 26 +++++- .../github/sspanak/tt9/db/WordStoreAsync.java | 19 ++++- .../sspanak/tt9/db/sqlite/DeleteOps.java | 13 ++- .../github/sspanak/tt9/db/sqlite/ReadOps.java | 24 ++++++ .../tt9/preferences/PreferencesActivity.java | 3 + .../tt9/preferences/SettingsStore.java | 2 +- .../deleteWords/DeletableWordsList.java | 58 +++++++++++++ .../deleteWords/DeleteWordsScreen.java | 30 +++++++ .../deleteWords/PreferenceDeletableWord.java | 72 +++++++++++++++++ .../deleteWords/PreferenceSearchWords.java | 81 +++++++++++++++++++ .../deleteWords/TextChangeListener.java | 39 +++++++++ .../languages/ItemDeleteCustomWords.java | 11 +++ .../screens/languages/ItemLoadDictionary.java | 3 +- .../screens/languages/LanguagesScreen.java | 2 + .../main/res/layout/pref_deletable_word.xml | 28 +++++++ app/src/main/res/layout/pref_input_text.xml | 33 ++++++++ app/src/main/res/values-bg/strings.xml | 2 +- app/src/main/res/values-de/strings.xml | 2 +- app/src/main/res/values-es/strings.xml | 2 +- app/src/main/res/values-fr/strings.xml | 2 +- app/src/main/res/values-it/strings.xml | 2 +- app/src/main/res/values-iw/strings.xml | 2 +- app/src/main/res/values-nl/strings.xml | 2 +- app/src/main/res/values-pt-rBR/strings.xml | 2 +- app/src/main/res/values-ru/strings.xml | 2 +- app/src/main/res/values-uk/strings.xml | 2 +- app/src/main/res/values/strings.xml | 13 ++- .../res/xml/prefs_screen_delete_words.xml | 13 +++ .../main/res/xml/prefs_screen_languages.xml | 9 ++- 30 files changed, 477 insertions(+), 26 deletions(-) create mode 100644 app/src/main/java/io/github/sspanak/tt9/preferences/screens/deleteWords/DeletableWordsList.java create mode 100644 app/src/main/java/io/github/sspanak/tt9/preferences/screens/deleteWords/DeleteWordsScreen.java create mode 100644 app/src/main/java/io/github/sspanak/tt9/preferences/screens/deleteWords/PreferenceDeletableWord.java create mode 100644 app/src/main/java/io/github/sspanak/tt9/preferences/screens/deleteWords/PreferenceSearchWords.java create mode 100644 app/src/main/java/io/github/sspanak/tt9/preferences/screens/deleteWords/TextChangeListener.java create mode 100644 app/src/main/java/io/github/sspanak/tt9/preferences/screens/languages/ItemDeleteCustomWords.java create mode 100644 app/src/main/res/layout/pref_deletable_word.xml create mode 100644 app/src/main/res/layout/pref_input_text.xml create mode 100644 app/src/main/res/xml/prefs_screen_delete_words.xml diff --git a/app/src/main/java/io/github/sspanak/tt9/db/DictionaryLoader.java b/app/src/main/java/io/github/sspanak/tt9/db/DictionaryLoader.java index a7b10808..433a933c 100644 --- a/app/src/main/java/io/github/sspanak/tt9/db/DictionaryLoader.java +++ b/app/src/main/java/io/github/sspanak/tt9/db/DictionaryLoader.java @@ -170,8 +170,8 @@ public class DictionaryLoader { logLoadingStep("Indexes dropped", language, start); start = System.currentTimeMillis(); - DeleteOps.delete(sqlite, language.getId()); - DeleteOps.delete(sqlite, new EmojiLanguage().getId()); + DeleteOps.delete(sqlite.getDb(), language.getId()); + DeleteOps.delete(sqlite.getDb(), new EmojiLanguage().getId()); sendProgressMessage(language, ++progress, SettingsStore.DICTIONARY_IMPORT_PROGRESS_UPDATE_TIME); logLoadingStep("Storage cleared", language, start); diff --git a/app/src/main/java/io/github/sspanak/tt9/db/WordStore.java b/app/src/main/java/io/github/sspanak/tt9/db/WordStore.java index 286f70ad..b3fa67c9 100644 --- a/app/src/main/java/io/github/sspanak/tt9/db/WordStore.java +++ b/app/src/main/java/io/github/sspanak/tt9/db/WordStore.java @@ -62,7 +62,7 @@ public class WordStore { return new ArrayList<>(); } - if (sequence == null || sequence.length() == 0) { + if (sequence == null || sequence.isEmpty()) { Logger.w(LOG_TAG, "Attempting to get words for an empty sequence."); return new ArrayList<>(); } @@ -91,6 +91,11 @@ public class WordStore { } + @NonNull public ArrayList getSimilarCustom(Language language, String wordFilter) { + return language != null && checkOrNotify() ? readOps.getCustomWords(sqlite.getDb(), language, wordFilter) : new ArrayList<>(); + } + + @NonNull public String getLanguageFileHash(Language language) { return language != null && checkOrNotify() ? readOps.getLanguageFileHash(sqlite.getDb(), language.getId()) : ""; } @@ -111,7 +116,7 @@ public class WordStore { sqlite.beginTransaction(); for (int langId : languageIds) { if (readOps.exists(sqlite.getDb(), langId)) { - DeleteOps.delete(sqlite, langId); + DeleteOps.delete(sqlite.getDb(), langId); } } sqlite.finishTransaction(); @@ -124,6 +129,23 @@ public class WordStore { } + public void removeCustomWord(Language language, String word) { + if (language == null || !checkOrNotify()) { + return; + } + + try { + sqlite.beginTransaction(); + DeleteOps.deleteCustomWord(sqlite.getDb(), language.getId(), word); + sqlite.finishTransaction(); + } catch (Exception e) { + sqlite.failTransaction(); + Logger.e(LOG_TAG, "Failed deleting custom word: '" + word + "' for language: " + language.getId() + ". " + e.getMessage()); + } + } + + + public int put(Language language, String word) { if (word == null || word.isEmpty()) { return AddWordDialog.CODE_BLANK_WORD; diff --git a/app/src/main/java/io/github/sspanak/tt9/db/WordStoreAsync.java b/app/src/main/java/io/github/sspanak/tt9/db/WordStoreAsync.java index bbec4339..46fc61ed 100644 --- a/app/src/main/java/io/github/sspanak/tt9/db/WordStoreAsync.java +++ b/app/src/main/java/io/github/sspanak/tt9/db/WordStoreAsync.java @@ -35,15 +35,19 @@ public class WordStoreAsync { } - public static void areThereWords(ConsumerCompat notification, Language language) { - new Thread(() -> notification.accept(getStore().exists(language))).start(); - } - public static void getLastLanguageUpdateTime(ConsumerCompat notification, Language language) { new Thread(() -> notification.accept(getStore().getLanguageFileHash(language))).start(); } + public static void deleteCustomWord(Runnable notification, Language language, String word) { + new Thread(() -> { + getStore().removeCustomWord(language, word); + notification.run(); + }).start(); + } + + public static void deleteWords(Runnable notification, @NonNull ArrayList languageIds) { new Thread(() -> { getStore().remove(languageIds); @@ -67,4 +71,11 @@ public class WordStoreAsync { getStore().getSimilar(language, sequence, filter, minWords, maxWords))) ).start(); } + + + public static void getCustomWords(ConsumerCompat> dataHandler, Language language, String wordFilter) { + new Thread(() -> asyncHandler.post(() -> dataHandler.accept( + getStore().getSimilarCustom(language, wordFilter))) + ).start(); + } } diff --git a/app/src/main/java/io/github/sspanak/tt9/db/sqlite/DeleteOps.java b/app/src/main/java/io/github/sspanak/tt9/db/sqlite/DeleteOps.java index d8941238..be21f9fe 100644 --- a/app/src/main/java/io/github/sspanak/tt9/db/sqlite/DeleteOps.java +++ b/app/src/main/java/io/github/sspanak/tt9/db/sqlite/DeleteOps.java @@ -1,10 +1,17 @@ package io.github.sspanak.tt9.db.sqlite; +import android.database.sqlite.SQLiteDatabase; + import androidx.annotation.NonNull; public class DeleteOps { - public static void delete(@NonNull SQLiteOpener sqlite, int languageId) { - sqlite.getDb().delete(Tables.getWords(languageId), null, null); - sqlite.getDb().delete(Tables.getWordPositions(languageId), null, null); + public static void delete(@NonNull SQLiteDatabase db, int languageId) { + db.delete(Tables.getWords(languageId), null, null); + db.delete(Tables.getWordPositions(languageId), null, null); + } + + public static void deleteCustomWord(@NonNull SQLiteDatabase db, int languageId, String word) { + db.delete(Tables.getWords(languageId), "word = ?", new String[] { word }); + db.delete(Tables.CUSTOM_WORDS, "word = ?", new String[] { word }); } } diff --git a/app/src/main/java/io/github/sspanak/tt9/db/sqlite/ReadOps.java b/app/src/main/java/io/github/sspanak/tt9/db/sqlite/ReadOps.java index 6202ae50..6128b81f 100644 --- a/app/src/main/java/io/github/sspanak/tt9/db/sqlite/ReadOps.java +++ b/app/src/main/java/io/github/sspanak/tt9/db/sqlite/ReadOps.java @@ -7,10 +7,13 @@ import android.database.sqlite.SQLiteStatement; import androidx.annotation.NonNull; +import java.util.ArrayList; + import io.github.sspanak.tt9.Logger; import io.github.sspanak.tt9.db.SlowQueryStats; import io.github.sspanak.tt9.db.entities.WordList; import io.github.sspanak.tt9.db.entities.WordPositionsStringBuilder; +import io.github.sspanak.tt9.languages.EmojiLanguage; import io.github.sspanak.tt9.languages.Language; public class ReadOps { @@ -62,6 +65,27 @@ public class ReadOps { } + public ArrayList getCustomWords(@NonNull SQLiteDatabase db, @NonNull Language language, @NonNull String wordFilter) { + ArrayList words = new ArrayList<>(); + + String[] select = new String[]{"word"}; + String where = "word LIKE ? AND (langId = ? OR langId = ?)"; + String[] whereArgs = new String[] { + wordFilter + "%", + String.valueOf(language.getId()), + String.valueOf(new EmojiLanguage().getId()) + }; + + try (Cursor cursor = db.query(Tables.CUSTOM_WORDS, select, where, whereArgs, null, null, "word")) { + while (cursor.moveToNext()) { + words.add(cursor.getString(0)); + } + } + + return words; + } + + /** * Gets all words as a ready-to-export CSV string. If the language is null or customWords is true, * only custom words are returned. diff --git a/app/src/main/java/io/github/sspanak/tt9/preferences/PreferencesActivity.java b/app/src/main/java/io/github/sspanak/tt9/preferences/PreferencesActivity.java index 3bfcea98..d98d32dd 100644 --- a/app/src/main/java/io/github/sspanak/tt9/preferences/PreferencesActivity.java +++ b/app/src/main/java/io/github/sspanak/tt9/preferences/PreferencesActivity.java @@ -25,6 +25,7 @@ import io.github.sspanak.tt9.preferences.screens.MainSettingsScreen; import io.github.sspanak.tt9.preferences.screens.UsageStatsScreen; import io.github.sspanak.tt9.preferences.screens.appearance.AppearanceScreen; import io.github.sspanak.tt9.preferences.screens.debug.DebugScreen; +import io.github.sspanak.tt9.preferences.screens.deleteWords.DeleteWordsScreen; import io.github.sspanak.tt9.preferences.screens.hotkeys.HotkeysScreen; import io.github.sspanak.tt9.preferences.screens.keypad.KeyPadScreen; import io.github.sspanak.tt9.preferences.screens.languages.LanguagesScreen; @@ -110,6 +111,8 @@ public class PreferencesActivity extends AppCompatActivity implements Preference return new AppearanceScreen(this); case DebugScreen.NAME: return new DebugScreen(this); + case DeleteWordsScreen.NAME: + return new DeleteWordsScreen(this); case HotkeysScreen.NAME: return new HotkeysScreen(this); case KeyPadScreen.NAME: diff --git a/app/src/main/java/io/github/sspanak/tt9/preferences/SettingsStore.java b/app/src/main/java/io/github/sspanak/tt9/preferences/SettingsStore.java index e6f78c19..cf3e8544 100644 --- a/app/src/main/java/io/github/sspanak/tt9/preferences/SettingsStore.java +++ b/app/src/main/java/io/github/sspanak/tt9/preferences/SettingsStore.java @@ -278,6 +278,7 @@ public class SettingsStore { } } + public final static int DELETE_WORDS_SEARCH_DELAY = 500; // ms public final static int DICTIONARY_AUTO_LOAD_COOLDOWN_TIME = 120000; // ms public final static int DICTIONARY_IMPORT_BATCH_SIZE = 5000; // words public final static int DICTIONARY_IMPORT_PROGRESS_UPDATE_TIME = 250; // ms @@ -286,7 +287,6 @@ public class SettingsStore { public final static float SOFT_KEY_COMPLEX_LABEL_TITLE_SIZE = 0.55f; public final static float SOFT_KEY_COMPLEX_LABEL_ARABIC_TITLE_SIZE = 0.72f; public final static float SOFT_KEY_COMPLEX_LABEL_SUB_TITLE_SIZE = 0.8f; - public final static int SUGGESTIONS_MAX = 20; public final static int SUGGESTIONS_MIN = 8; public final static int SUGGESTIONS_SELECT_ANIMATION_DURATION = 66; diff --git a/app/src/main/java/io/github/sspanak/tt9/preferences/screens/deleteWords/DeletableWordsList.java b/app/src/main/java/io/github/sspanak/tt9/preferences/screens/deleteWords/DeletableWordsList.java new file mode 100644 index 00000000..dc4bfdef --- /dev/null +++ b/app/src/main/java/io/github/sspanak/tt9/preferences/screens/deleteWords/DeletableWordsList.java @@ -0,0 +1,58 @@ +package io.github.sspanak.tt9.preferences.screens.deleteWords; + +import androidx.annotation.NonNull; +import androidx.preference.Preference; +import androidx.preference.PreferenceCategory; + +import java.util.ArrayList; + +import io.github.sspanak.tt9.R; + +class DeletableWordsList { + static final String NAME = "delete_words_list"; + + private final PreferenceCategory item; + + DeletableWordsList(Preference preference) { + item = preference instanceof PreferenceCategory ? (PreferenceCategory) preference : null; + } + + private void clear() { + if (item != null) { + item.removeAll(); + } + } + + private void addWord(String word) { + if (item != null) { + PreferenceDeletableWord pref = new PreferenceDeletableWord(item.getContext()); + pref.setWord(word); + pref.setLayoutResource(R.layout.pref_deletable_word); + item.addPreference(pref); + } + } + + void addWords(ArrayList words) { + for (String word : words) { + addWord(word); + } + } + + void addNoResult(boolean noSearchTerm) { + if (item != null) { + Preference pref = new Preference(item.getContext()); + pref.setSummary(noSearchTerm ? "--" : item.getContext().getString(R.string.delete_words_no_result)); + pref.setLayoutResource(R.layout.pref_text); + item.addPreference(pref); + } + } + + void setResult(@NonNull String searchTerm, ArrayList words) { + clear(); + if (words == null || words.isEmpty()) { + addNoResult(searchTerm.isEmpty()); + } else { + addWords(words); + } + } +} diff --git a/app/src/main/java/io/github/sspanak/tt9/preferences/screens/deleteWords/DeleteWordsScreen.java b/app/src/main/java/io/github/sspanak/tt9/preferences/screens/deleteWords/DeleteWordsScreen.java new file mode 100644 index 00000000..4104106f --- /dev/null +++ b/app/src/main/java/io/github/sspanak/tt9/preferences/screens/deleteWords/DeleteWordsScreen.java @@ -0,0 +1,30 @@ +package io.github.sspanak.tt9.preferences.screens.deleteWords; + +import io.github.sspanak.tt9.R; +import io.github.sspanak.tt9.preferences.PreferencesActivity; +import io.github.sspanak.tt9.preferences.screens.BaseScreenFragment; + +public class DeleteWordsScreen extends BaseScreenFragment { + final public static String NAME = "DeleteWords"; + + public DeleteWordsScreen() { init(); } + public DeleteWordsScreen(PreferencesActivity activity) { init(activity); } + + @Override public String getName() { return NAME; } + @Override protected int getTitle() { return R.string.pref_category_delete_words; } + @Override protected int getXml() { return R.xml.prefs_screen_delete_words; } + + @Override protected void onCreate() { + createPage(); + } + + private void createPage() { + DeletableWordsList searchResultsList = new DeletableWordsList(findPreference(DeletableWordsList.NAME)); + searchResultsList.setResult("", null); + + PreferenceSearchWords searchWords = findPreference(PreferenceSearchWords.NAME); + if (searchWords != null) { + searchWords.setOnWordsHandler((words) -> searchResultsList.setResult(searchWords.getLastSearchTerm(), words)); + } + } +} diff --git a/app/src/main/java/io/github/sspanak/tt9/preferences/screens/deleteWords/PreferenceDeletableWord.java b/app/src/main/java/io/github/sspanak/tt9/preferences/screens/deleteWords/PreferenceDeletableWord.java new file mode 100644 index 00000000..0ae0e315 --- /dev/null +++ b/app/src/main/java/io/github/sspanak/tt9/preferences/screens/deleteWords/PreferenceDeletableWord.java @@ -0,0 +1,72 @@ +package io.github.sspanak.tt9.preferences.screens.deleteWords; + +import android.app.Activity; +import android.content.Context; +import android.util.AttributeSet; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.preference.Preference; +import androidx.preference.PreferenceCategory; +import androidx.preference.PreferenceViewHolder; + +import io.github.sspanak.tt9.R; +import io.github.sspanak.tt9.db.WordStoreAsync; +import io.github.sspanak.tt9.languages.LanguageCollection; +import io.github.sspanak.tt9.preferences.SettingsStore; +import io.github.sspanak.tt9.ui.UI; + +public class PreferenceDeletableWord extends Preference { + private String word; + + + public PreferenceDeletableWord(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } + public PreferenceDeletableWord(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } + public PreferenceDeletableWord(@NonNull Context context, @Nullable AttributeSet attrs) { super(context, attrs); } + public PreferenceDeletableWord(@NonNull Context context) { super(context); } + + + public void setWord(String word) { + this.word = word; + setTitle(word); + } + + + @Override + protected void onClick() { + super.onClick(); + + Context context = getContext(); + + UI.confirm( + context, + context.getString(R.string.delete_words_deleted_confirm_deletion_title), + context.getString(R.string.delete_words_deleted_confirm_deletion_question, word), + context.getString(R.string.delete_words_deleted_confirm_deletion_yes), + this::onDeletionConfirmed, + null + ); + } + + + private void onDeletionConfirmed() { + SettingsStore settings = new SettingsStore(getContext()); + WordStoreAsync.deleteCustomWord( + this::onWordDeleted, + LanguageCollection.getLanguage(getContext(), settings.getInputLanguage()), + word + ); + } + + + private void onWordDeleted() { + if (getParent() instanceof PreferenceCategory) { + getParent().removePreference(this); + } + + Activity activity = (Activity) getContext(); + activity.runOnUiThread( + () -> UI.toastFromAsync(getContext(), activity.getString(R.string.delete_words_deleted_x, word)) + ); + } +} diff --git a/app/src/main/java/io/github/sspanak/tt9/preferences/screens/deleteWords/PreferenceSearchWords.java b/app/src/main/java/io/github/sspanak/tt9/preferences/screens/deleteWords/PreferenceSearchWords.java new file mode 100644 index 00000000..0e3bb47c --- /dev/null +++ b/app/src/main/java/io/github/sspanak/tt9/preferences/screens/deleteWords/PreferenceSearchWords.java @@ -0,0 +1,81 @@ +package io.github.sspanak.tt9.preferences.screens.deleteWords; + +import android.content.Context; +import android.util.AttributeSet; +import android.widget.EditText; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.preference.Preference; +import androidx.preference.PreferenceViewHolder; + +import java.util.ArrayList; + +import io.github.sspanak.tt9.ConsumerCompat; +import io.github.sspanak.tt9.Logger; +import io.github.sspanak.tt9.R; +import io.github.sspanak.tt9.db.WordStoreAsync; +import io.github.sspanak.tt9.languages.Language; +import io.github.sspanak.tt9.languages.LanguageCollection; +import io.github.sspanak.tt9.preferences.SettingsStore; + +public class PreferenceSearchWords extends Preference { + public static final String NAME = "dictionary_delete_words_search"; + private static final String LOG_TAG = PreferenceSearchWords.class.getSimpleName(); + + private ConsumerCompat> onWords; + private SettingsStore settings; + @NonNull private String lastSearchTerm = ""; + + + public PreferenceSearchWords(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } + public PreferenceSearchWords(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } + public PreferenceSearchWords(@NonNull Context context, @Nullable AttributeSet attrs) { super(context, attrs); } + public PreferenceSearchWords(@NonNull Context context) { super(context); } + + + @Override + public void onBindViewHolder(@NonNull PreferenceViewHolder holder) { + super.onBindViewHolder(holder); + EditText editText = holder.itemView.findViewById(R.id.input_text_input_field); + if (editText == null) { + Logger.e(LOG_TAG, "Cannot attach a text change listener. Unable to find the EditText element."); + } else { + editText.addTextChangedListener(TextChangeListener.getInstance(this::onChange)); + } + } + + + @NonNull + public String getLastSearchTerm() { + return lastSearchTerm; + } + + private SettingsStore getSettings() { + if (settings == null) { + settings = new SettingsStore(getContext()); + } + + return settings; + } + + + private void onChange(String word) { + lastSearchTerm = word == null || word.trim().isEmpty() ? "" : word.trim(); + + if (onWords == null) { + Logger.w(LOG_TAG, "No handler set for the word change event."); + } else if (lastSearchTerm.isEmpty()) { + Logger.d(LOG_TAG, "Not searching for an empty word."); + onWords.accept(null); + } else { + Language currentLanguage = LanguageCollection.getLanguage(getContext(), getSettings().getInputLanguage()); + WordStoreAsync.getCustomWords(onWords, currentLanguage, lastSearchTerm); + } + } + + + void setOnWordsHandler(ConsumerCompat> onWords) { + this.onWords = onWords; + } +} diff --git a/app/src/main/java/io/github/sspanak/tt9/preferences/screens/deleteWords/TextChangeListener.java b/app/src/main/java/io/github/sspanak/tt9/preferences/screens/deleteWords/TextChangeListener.java new file mode 100644 index 00000000..6070ecfb --- /dev/null +++ b/app/src/main/java/io/github/sspanak/tt9/preferences/screens/deleteWords/TextChangeListener.java @@ -0,0 +1,39 @@ +package io.github.sspanak.tt9.preferences.screens.deleteWords; + +import android.os.Handler; +import android.os.Looper; +import android.text.Editable; +import android.text.TextWatcher; + +import androidx.annotation.NonNull; + +import io.github.sspanak.tt9.ConsumerCompat; +import io.github.sspanak.tt9.preferences.SettingsStore; + +class TextChangeListener implements TextWatcher { + private static TextChangeListener self; + + @NonNull private ConsumerCompat onChange; + @NonNull private final Handler debouncer = new Handler(Looper.getMainLooper()); + + private TextChangeListener(@NonNull ConsumerCompat onChange) { + this.onChange = onChange; + } + + static TextChangeListener getInstance(@NonNull ConsumerCompat onChange) { + if (self == null) { + self = new TextChangeListener(onChange); + } + + self.onChange = onChange; + return self; + } + + @Override public void afterTextChanged(Editable s) { + debouncer.removeCallbacksAndMessages(null); + debouncer.postDelayed(() -> onChange.accept(s.toString()), SettingsStore.DELETE_WORDS_SEARCH_DELAY); + } + + @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {} + @Override public void onTextChanged(CharSequence s, int start, int before, int count) {} +} diff --git a/app/src/main/java/io/github/sspanak/tt9/preferences/screens/languages/ItemDeleteCustomWords.java b/app/src/main/java/io/github/sspanak/tt9/preferences/screens/languages/ItemDeleteCustomWords.java new file mode 100644 index 00000000..b4439b62 --- /dev/null +++ b/app/src/main/java/io/github/sspanak/tt9/preferences/screens/languages/ItemDeleteCustomWords.java @@ -0,0 +1,11 @@ +package io.github.sspanak.tt9.preferences.screens.languages; + +import androidx.preference.Preference; + +import io.github.sspanak.tt9.preferences.items.ItemClickable; + +class ItemDeleteCustomWords extends ItemClickable { + final static String NAME = "screen_delete_words"; + ItemDeleteCustomWords(Preference item) { super(item); } + @Override protected boolean onClick(Preference p) { return false; } +} diff --git a/app/src/main/java/io/github/sspanak/tt9/preferences/screens/languages/ItemLoadDictionary.java b/app/src/main/java/io/github/sspanak/tt9/preferences/screens/languages/ItemLoadDictionary.java index ef305f1f..1a3d7882 100644 --- a/app/src/main/java/io/github/sspanak/tt9/preferences/screens/languages/ItemLoadDictionary.java +++ b/app/src/main/java/io/github/sspanak/tt9/preferences/screens/languages/ItemLoadDictionary.java @@ -39,8 +39,6 @@ class ItemLoadDictionary extends ItemClickable { this.onStart = onStart; this.onFinish = onFinish; - - loader.setOnStatusChange(this::onLoadingStatusChange); refreshStatus(); } @@ -85,6 +83,7 @@ class ItemLoadDictionary extends ItemClickable { private void setLoadingStatus() { + loader.setOnStatusChange(this::onLoadingStatusChange); onStart.run(); item.setTitle(context.getString(R.string.dictionary_cancel_load)); } diff --git a/app/src/main/java/io/github/sspanak/tt9/preferences/screens/languages/LanguagesScreen.java b/app/src/main/java/io/github/sspanak/tt9/preferences/screens/languages/LanguagesScreen.java index 1377ab81..0e57fdca 100644 --- a/app/src/main/java/io/github/sspanak/tt9/preferences/screens/languages/LanguagesScreen.java +++ b/app/src/main/java/io/github/sspanak/tt9/preferences/screens/languages/LanguagesScreen.java @@ -67,6 +67,8 @@ public class LanguagesScreen extends BaseScreenFragment { this::onActionFinish )); + clickables.add(new ItemDeleteCustomWords(findPreference(ItemDeleteCustomWords.NAME))); + exportCustomWordsItem = new ItemExportCustomWords( findPreference(ItemExportCustomWords.NAME), activity, diff --git a/app/src/main/res/layout/pref_deletable_word.xml b/app/src/main/res/layout/pref_deletable_word.xml new file mode 100644 index 00000000..60ca012f --- /dev/null +++ b/app/src/main/res/layout/pref_deletable_word.xml @@ -0,0 +1,28 @@ + + + + + + + diff --git a/app/src/main/res/layout/pref_input_text.xml b/app/src/main/res/layout/pref_input_text.xml new file mode 100644 index 00000000..8bdc1e40 --- /dev/null +++ b/app/src/main/res/layout/pref_input_text.xml @@ -0,0 +1,33 @@ + + + + + + + + + + diff --git a/app/src/main/res/values-bg/strings.xml b/app/src/main/res/values-bg/strings.xml index 202a5875..7d140200 100644 --- a/app/src/main/res/values-bg/strings.xml +++ b/app/src/main/res/values-bg/strings.xml @@ -35,7 +35,7 @@ Назад Зелена слушалка Експортирай избраните - Експортирай + Експортирай Експортиране на CSV с всички добавени думи в: „%1$s“. Неуспешно експортиране За повече информация, активирайте режима за отстраняване на грешки и прегледайте журнала. diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index f8172622..070e8400 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -32,7 +32,7 @@ Nein Automatisch Ausgewählte exportieren - Exportieren + Exportieren Exportiere ein CSV mit allen hinzugefügten Wörtern nach: „%1$s“. Export fehlgeschlagen Für weitere Informationen, aktivieren Sie den Debug-Modus und sehen Sie sich die Protokolle an. diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index c85c2488..ac096ed9 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -75,7 +75,7 @@ No Automática Exportar seleccionados - Exportar + Exportar Exportar un CSV con todas las palabras añadidas a: \"%1$s\". Fallo en la exportación Para obtener más información, habilita el modo de depuración y consulta los registros. diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index d39258b9..4f280788 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -75,7 +75,7 @@ Automatique Ajouter mot « %1$s » à %2$s? Exporter les sélectionées - Exporter + Exporter Exporter un CSV avec tous les mots ajoutés vers : «%1$s». Échec de l\'exportation Pour plus d\'informations, activez le mode de débogage et consultez les journaux. diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index e3aecd0f..fc5bf95a 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -41,7 +41,7 @@ No Automatica Esporta selezionate - Esportare + Esportare Esporta un CSV con tutte le parole aggiunte su: \"%1$s\". Esportazione fallita Per ulteriori informazioni, abilita la modalità di debug e consulta i log. diff --git a/app/src/main/res/values-iw/strings.xml b/app/src/main/res/values-iw/strings.xml index 7e443f5a..0f08a61a 100644 --- a/app/src/main/res/values-iw/strings.xml +++ b/app/src/main/res/values-iw/strings.xml @@ -68,7 +68,7 @@ לא אוטומטי ייצוא שנבחר - לְיְצוֹא + לְיְצוֹא ייצוא CSV עם כל המילים שנוספו ל: \"%1$s\". נכשל בייצוא "למידע נוסף, הפעל מצב איתור באגים וראה את הלוגים. " diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 0fbf6f0e..7d23a35f 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -32,7 +32,7 @@ Nee Automatisch Geselecteerde exporteren - Exporteren + Exporteren Exporteer een CSV met alle toegevoegde woorden naar: \"%1$s\". Exporteren mislukt Voor meer informatie, schakel de debug-modus in en bekijk de logs. diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index b8da6951..7fef1b76 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -64,7 +64,7 @@ Não Automático Exportar selecionados - Exportar + Exportar Exportar um CSV com todas as palavras adicionadas para: \"%1$s\". Falha na exportação Para mais informações, ative o modo de depuração e veja os registros. diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 2a46cf9c..4dacd613 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -80,7 +80,7 @@ Автоматически Добавить слово «%1$s» в %2$s? Экспортировать выбранные - Экспортировать + Экспортировать Экспорт CSV со всеми добавленными словами в: «%1$s». Ошибка экспорта Для получения дополнительной информации включите режим отладки и просмотрите журналы. diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 95b8d4e3..e7e2b6a8 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -65,7 +65,7 @@ Видаляється… Експортувати вибрані - Експортувати + Експортувати Експорт CSV з усіма доданими словами в: \"%1$s\". Помилка експорту Для отримання додаткової інформації увімкніть режим відлагодження та перегляньте журнали. diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 64f14d41..9680fd0e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -23,6 +23,7 @@ About ABC Mode Added Words + Delete Added Words Compatibility Appearance Debug Options @@ -73,7 +74,7 @@ Deleting… Export Selected - Export + Export Export a CSV with all added words in: \"%1$s\". Exporting Failed For more info, enable debugging mode and see the logs. @@ -82,6 +83,16 @@ Exporting CSV… Exporting CSV (%1$s)… + Delete + Search and delete misspelled or unneeded words. + Search Words + Search Results + No results + Confirm Deletion + Are you sure you want to delete \"%1$s\"? + Delete + \"%1$s\" was deleted. + Dictionary update available for \"%1$s\". Would you like to load it? Load diff --git a/app/src/main/res/xml/prefs_screen_delete_words.xml b/app/src/main/res/xml/prefs_screen_delete_words.xml new file mode 100644 index 00000000..afb026e7 --- /dev/null +++ b/app/src/main/res/xml/prefs_screen_delete_words.xml @@ -0,0 +1,13 @@ + + + + + + + diff --git a/app/src/main/res/xml/prefs_screen_languages.xml b/app/src/main/res/xml/prefs_screen_languages.xml index 19fb56c9..63bbba89 100644 --- a/app/src/main/res/xml/prefs_screen_languages.xml +++ b/app/src/main/res/xml/prefs_screen_languages.xml @@ -35,7 +35,14 @@ + app:title="@string/dictionary_export_custom_words" /> + +