From d8b791dd40146fadba7d9973a53b68da1f3b3535 Mon Sep 17 00:00:00 2001 From: sspanak Date: Thu, 8 Aug 2024 17:12:46 +0300 Subject: [PATCH] Delete word screen improvements * added the word count * all words are displayed when there is no search term * fixed incorrect padding and font size when the word list is long --- .../io/github/sspanak/tt9/db/WordStore.java | 9 +++-- .../github/sspanak/tt9/db/WordStoreAsync.java | 11 ++++-- .../github/sspanak/tt9/db/sqlite/ReadOps.java | 18 +++++----- .../custom/PreferencePlainText.java | 4 +-- .../deleteWords/DeletableWordsList.java | 35 +++++++++++++++++-- .../deleteWords/DeleteWordsScreen.java | 5 ++- .../deleteWords/PreferenceDeletableWord.java | 26 ++++++++++---- .../deleteWords/PreferenceSearchWords.java | 26 +++++++++----- .../preferences/settings/SettingsStore.java | 1 + 9 files changed, 101 insertions(+), 34 deletions(-) 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 081cb947..cb118292 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 @@ -112,8 +112,13 @@ public class WordStore { } - @NonNull public ArrayList getSimilarCustom(Language language, String wordFilter) { - return language != null && !(language instanceof NullLanguage) && checkOrNotify() ? readOps.getCustomWords(sqlite.getDb(), language, wordFilter) : new ArrayList<>(); + @NonNull public ArrayList getSimilarCustom(String wordFilter, int maxWords) { + return checkOrNotify() ? readOps.getCustomWords(sqlite.getDb(), wordFilter, maxWords) : new ArrayList<>(); + } + + + public long countCustom() { + return checkOrNotify() ? readOps.countCustomWords(sqlite.getDb()) : 0; } 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 010eb30c..2336b3b1 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 @@ -74,9 +74,16 @@ public class WordStoreAsync { } - public static void getCustomWords(ConsumerCompat> dataHandler, Language language, String wordFilter) { + public static void getCustomWords(ConsumerCompat> dataHandler, String wordFilter, int maxWords) { new Thread(() -> asyncHandler.post(() -> dataHandler.accept( - getStore().getSimilarCustom(language, wordFilter))) + getStore().getSimilarCustom(wordFilter, maxWords))) + ).start(); + } + + + public static void countCustomWords(ConsumerCompat dataHandler) { + new Thread(() -> asyncHandler.post(() -> dataHandler.accept( + getStore().countCustom())) ).start(); } 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 74244ce2..82ea1b5c 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 @@ -9,13 +9,13 @@ import androidx.annotation.NonNull; import java.util.ArrayList; -import io.github.sspanak.tt9.db.entities.NormalizationList; -import io.github.sspanak.tt9.util.Logger; import io.github.sspanak.tt9.db.SlowQueryStats; +import io.github.sspanak.tt9.db.entities.NormalizationList; 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; +import io.github.sspanak.tt9.util.Logger; public class ReadOps { private final String LOG_TAG = "ReadOperations"; @@ -71,18 +71,16 @@ public class ReadOps { } - public ArrayList getCustomWords(@NonNull SQLiteDatabase db, @NonNull Language language, @NonNull String wordFilter) { + public ArrayList getCustomWords(@NonNull SQLiteDatabase db, @NonNull String wordFilter, int maxWords) { 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()) - }; + String where = "word LIKE ?"; + String[] whereArgs = new String[]{wordFilter + "%"}; + String limit = maxWords > 0 ? String.valueOf(maxWords) : null; + String orderBy = maxWords > 0 ? null : "word"; - try (Cursor cursor = db.query(Tables.CUSTOM_WORDS, select, where, whereArgs, null, null, "word")) { + try (Cursor cursor = db.query(Tables.CUSTOM_WORDS, select, where, whereArgs, null, null, orderBy, limit)) { while (cursor.moveToNext()) { words.add(cursor.getString(0)); } diff --git a/app/src/main/java/io/github/sspanak/tt9/preferences/custom/PreferencePlainText.java b/app/src/main/java/io/github/sspanak/tt9/preferences/custom/PreferencePlainText.java index b4c15ebb..650e8190 100644 --- a/app/src/main/java/io/github/sspanak/tt9/preferences/custom/PreferencePlainText.java +++ b/app/src/main/java/io/github/sspanak/tt9/preferences/custom/PreferencePlainText.java @@ -15,12 +15,12 @@ final public class PreferencePlainText extends ScreenPreference { public PreferencePlainText(@NonNull Context context) { super(context); } @Override - protected int getDefaultLayout() { + public int getDefaultLayout() { return R.layout.pref_plain_text; } @Override - protected int getLargeLayout() { + public int getLargeLayout() { return R.layout.pref_plain_text_large; } } 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 index 6f4077ff..467f2525 100644 --- 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 @@ -8,14 +8,19 @@ import java.util.ArrayList; import io.github.sspanak.tt9.R; import io.github.sspanak.tt9.preferences.custom.PreferencePlainText; +import io.github.sspanak.tt9.preferences.settings.SettingsStore; class DeletableWordsList { static final String NAME = "delete_words_list"; private final PreferenceCategory item; + private final boolean largeFont; + private int currentWords = 0; + private long totalWords = 0; - DeletableWordsList(Preference preference) { + DeletableWordsList(SettingsStore settings, Preference preference) { item = preference instanceof PreferenceCategory ? (PreferenceCategory) preference : null; + largeFont = settings.getSettingsFontSize() == SettingsStore.FONT_SIZE_LARGE; } private void clear() { @@ -24,10 +29,19 @@ class DeletableWordsList { } } + void delete(PreferenceDeletableWord wordItem) { + if (item != null) { + item.removePreference(wordItem); + setTotalWords(totalWords - 1); + } + } + private void addWord(String word) { if (item != null) { PreferenceDeletableWord pref = new PreferenceDeletableWord(item.getContext()); + pref.setParent(this); pref.setWord(word); + pref.setLayoutResource(largeFont ? pref.getLargeLayout() : pref.getDefaultLayout()); item.addPreference(pref); } } @@ -40,18 +54,35 @@ class DeletableWordsList { void addNoResult(boolean noSearchTerm) { if (item != null) { - Preference pref = new PreferencePlainText(item.getContext()); + PreferencePlainText pref = new PreferencePlainText(item.getContext()); pref.setSummary(noSearchTerm ? "--" : item.getContext().getString(R.string.search_results_void)); + pref.setLayoutResource(largeFont ? pref.getLargeLayout() : pref.getDefaultLayout()); item.addPreference(pref); } } void setResult(@NonNull String searchTerm, ArrayList words) { clear(); + if (words == null || words.isEmpty()) { addNoResult(searchTerm.isEmpty()); } else { addWords(words); } + + currentWords = words == null ? 0 : words.size(); + setResultCount(); + } + + void setTotalWords(long total) { + totalWords = total > 0 ? total : 0; + setResultCount(); + } + + private void setResultCount() { + if (item != null) { + String results = " (" + currentWords + "/" + totalWords + ")"; + item.setTitle(item.getContext().getString(R.string.search_results) + results); + } } } 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 index e715b031..686f153e 100644 --- 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 @@ -19,12 +19,15 @@ public class DeleteWordsScreen extends BaseScreenFragment { } private void createPage() { - DeletableWordsList searchResultsList = new DeletableWordsList(findPreference(DeletableWordsList.NAME)); + DeletableWordsList searchResultsList = new DeletableWordsList(activity.getSettings(), findPreference(DeletableWordsList.NAME)); + searchResultsList.setTotalWords(0); searchResultsList.setResult("", null); PreferenceSearchWords searchWords = findPreference(PreferenceSearchWords.NAME); if (searchWords != null) { searchWords.setOnWordsHandler((words) -> searchResultsList.setResult(searchWords.getLastSearchTerm(), words)); + searchWords.setOnTotalWordsHandler(searchResultsList::setTotalWords); + searchWords.search(""); } resetFontSize(false); 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 index 9931be66..fea6bfab 100644 --- 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 @@ -16,6 +16,7 @@ import io.github.sspanak.tt9.preferences.settings.SettingsStore; import io.github.sspanak.tt9.ui.UI; public class PreferenceDeletableWord extends ScreenPreference { + private DeletableWordsList parent; private String word; @@ -29,7 +30,14 @@ public class PreferenceDeletableWord extends ScreenPreference { @Override protected int getLargeLayout() { return R.layout.pref_deletable_word_large; } - public void setWord(String word) { + void setParent(DeletableWordsList parent) { + if (parent != null) { + this.parent = parent; + } + } + + + void setWord(String word) { this.word = word; setTitle(word); } @@ -62,14 +70,18 @@ public class PreferenceDeletableWord extends ScreenPreference { } - private void onWordDeleted() { - if (getParent() instanceof PreferenceCategory) { + private void deleteSelf() { + if (parent != null) { + parent.delete(this); + } else 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)) - ); + UI.toastFromAsync(getContext(), getContext().getString(R.string.delete_words_deleted_x, word)); + } + + + private void onWordDeleted() { + ((Activity) getContext()).runOnUiThread(this::deleteSelf); } } 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 index d701e261..d323530a 100644 --- 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 @@ -9,8 +9,6 @@ import androidx.annotation.Nullable; import java.util.ArrayList; 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.items.ItemTextInput; import io.github.sspanak.tt9.preferences.settings.SettingsStore; import io.github.sspanak.tt9.util.ConsumerCompat; @@ -21,8 +19,11 @@ public class PreferenceSearchWords extends ItemTextInput { private static final String LOG_TAG = PreferenceSearchWords.class.getSimpleName(); private ConsumerCompat> onWords; + private ConsumerCompat onTotalWords; private SettingsStore settings; + @NonNull private String lastSearchTerm = ""; + private long totalWords = 0; public PreferenceSearchWords(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } @@ -39,24 +40,29 @@ public class PreferenceSearchWords extends ItemTextInput { } + @Override + protected void onChange(String word) { + search(word); + } + + @NonNull public String getLastSearchTerm() { return lastSearchTerm; } - @Override - protected void onChange(String word) { + void search(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); + WordStoreAsync.countCustomWords(onTotalWords); + WordStoreAsync.getCustomWords(onWords, lastSearchTerm, SettingsStore.CUSTOM_WORDS_SEARCH_RESULTS_MAX); } else { - Language currentLanguage = LanguageCollection.getLanguage(getContext(), getSettings().getInputLanguage()); - WordStoreAsync.getCustomWords(onWords, currentLanguage, lastSearchTerm); + WordStoreAsync.countCustomWords(onTotalWords); + WordStoreAsync.getCustomWords(onWords, lastSearchTerm, -1); } } @@ -64,4 +70,8 @@ public class PreferenceSearchWords extends ItemTextInput { void setOnWordsHandler(ConsumerCompat> onWords) { this.onWords = onWords; } + + void setOnTotalWordsHandler(ConsumerCompat onTotalWords) { + this.onTotalWords = onTotalWords; + } } diff --git a/app/src/main/java/io/github/sspanak/tt9/preferences/settings/SettingsStore.java b/app/src/main/java/io/github/sspanak/tt9/preferences/settings/SettingsStore.java index e3609f84..33a7d35b 100644 --- a/app/src/main/java/io/github/sspanak/tt9/preferences/settings/SettingsStore.java +++ b/app/src/main/java/io/github/sspanak/tt9/preferences/settings/SettingsStore.java @@ -10,6 +10,7 @@ public class SettingsStore extends SettingsUI { public final static int CLIPBOARD_PREVIEW_LENGTH = 20; public final static int CUSTOM_WORDS_IMPORT_MAX_LINES = 250; public final static int CUSTOM_WORDS_MAX = 1000; + public final static int CUSTOM_WORDS_SEARCH_RESULTS_MAX = 50; public final static int DICTIONARY_AUTO_LOAD_COOLDOWN_TIME = 1200000; // 20 minutes in ms public final static int DICTIONARY_DOWNLOAD_CONNECTION_TIMEOUT = 10000; // ms public final static int DICTIONARY_DOWNLOAD_READ_TIMEOUT = 10000; // ms