From b6b1b2a58268005ea6bb96b3873eac1553a653b8 Mon Sep 17 00:00:00 2001 From: M66B Date: Thu, 1 Jul 2021 16:35:20 +0200 Subject: [PATCH] Improved text search --- .../eu/faircode/email/AdapterMessage.java | 122 +-------------- .../eu/faircode/email/FragmentMessages.java | 146 ++++++++++++++++++ app/src/main/res/layout/fragment_messages.xml | 18 ++- .../main/res/layout/popup_search_in_text.xml | 32 ---- app/src/main/res/values/dimen.xml | 1 + 5 files changed, 172 insertions(+), 147 deletions(-) delete mode 100644 app/src/main/res/layout/popup_search_in_text.xml diff --git a/app/src/main/java/eu/faircode/email/AdapterMessage.java b/app/src/main/java/eu/faircode/email/AdapterMessage.java index cb83e8b792..20ded4c31f 100644 --- a/app/src/main/java/eu/faircode/email/AdapterMessage.java +++ b/app/src/main/java/eu/faircode/email/AdapterMessage.java @@ -55,18 +55,14 @@ import android.os.Parcelable; import android.provider.CalendarContract; import android.provider.ContactsContract; import android.provider.Settings; -import android.text.Editable; import android.text.Html; import android.text.Spannable; -import android.text.SpannableString; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.TextUtils; -import android.text.TextWatcher; import android.text.format.DateUtils; import android.text.method.ArrowKeyMovementMethod; import android.text.method.LinkMovementMethod; -import android.text.style.BackgroundColorSpan; import android.text.style.DynamicDrawableSpan; import android.text.style.ForegroundColorSpan; import android.text.style.ImageSpan; @@ -75,7 +71,6 @@ import android.text.style.StyleSpan; import android.text.style.URLSpan; import android.util.Pair; import android.util.TypedValue; -import android.view.Gravity; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.Menu; @@ -93,7 +88,6 @@ import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityNodeInfo; import android.view.animation.AccelerateDecelerateInterpolator; -import android.view.inputmethod.InputMethodManager; import android.view.textclassifier.ConversationAction; import android.view.textclassifier.ConversationActions; import android.webkit.WebSettings; @@ -106,7 +100,6 @@ import android.widget.CompoundButton; import android.widget.EditText; import android.widget.ImageButton; import android.widget.ImageView; -import android.widget.PopupWindow; import android.widget.Spinner; import android.widget.TextView; import android.widget.Toast; @@ -196,7 +189,7 @@ import biweekly.property.RawProperty; import biweekly.util.ICalDate; import static android.app.Activity.RESULT_OK; -import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; +import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static androidx.webkit.WebSettingsCompat.FORCE_DARK_OFF; import static androidx.webkit.WebSettingsCompat.FORCE_DARK_ON; @@ -289,7 +282,6 @@ public class AdapterMessage extends RecyclerView.Adapter differ; private Map keyPosition = new HashMap<>(); private Map positionKey = new HashMap<>(); @@ -2043,6 +2035,7 @@ public class AdapterMessage extends RecyclerView.Adapter 0); - } - - @Override - public void afterTextChanged(Editable s) { - // Do nothing - } - }); - - ibNext.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - searchResult = find(etSearch.getText().toString(), ++searchResult); - } - }); - - PopupWindow pw = new PopupWindow(dview, WRAP_CONTENT, WRAP_CONTENT); - pw.setFocusable(true); - pw.setOnDismissListener(new PopupWindow.OnDismissListener() { - @Override - public void onDismiss() { - SpannableString ss = new SpannableString(tvBody.getText()); - for (BackgroundColorSpan span : ss.getSpans(0, ss.length(), BackgroundColorSpan.class)) - ss.removeSpan(span); - tvBody.setText(ss); - } - }); - pw.showAtLocation(parentFragment.getView(), Gravity.TOP | Gravity.END, 0, 0); - - final InputMethodManager imm = - (InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); - if (imm != null) - imm.toggleSoftInput(InputMethodManager.SHOW_IMPLICIT, 0); - } - - private int find(String query, int result) { - query = query.toLowerCase(); - - SpannableString ss = new SpannableString(tvBody.getText()); - for (BackgroundColorSpan span : ss.getSpans(0, ss.length(), BackgroundColorSpan.class)) - ss.removeSpan(span); - - int p = -1; - String text = tvBody.getText().toString().toLowerCase(); - for (int i = 0; i < result; i++) - p = (p < 0 ? text.indexOf(query) : text.indexOf(query, p + 1)); - - if (p < 0 && result > 1) { - result = 1; - p = text.indexOf(query); - } - if (p < 0) - result = 0; - - final int pos = p; - if (pos > 0) { - int color = Helper.resolveColor(context, R.attr.colorHighlight); - ss.setSpan(new BackgroundColorSpan(color), pos, pos + query.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - tvBody.setText(ss); - - final int apos = getAdapterPosition(); - - tvBody.post(new Runnable() { - @Override - public void run() { - try { - int line = tvBody.getLayout().getLineForOffset(pos); - int y = tvBody.getLayout().getLineTop(line); - - int dy = Helper.dp2pixels(context, 48); - - Rect rect = new Rect(); - tvBody.getDrawingRect(rect); - ((ViewGroup) itemView).offsetDescendantRectToMyCoords(tvBody, rect); - - properties.scrollTo(apos, rect.top + y - dy); - } catch (Throwable ex) { - Log.e(ex); - } - } - }); - } else - tvBody.setText(ss, TextView.BufferType.SPANNABLE); - - return result; + properties.startSearch(tvBody); } private void onMenuCreateRule(TupleMessageEx message) { @@ -6496,6 +6388,10 @@ public class AdapterMessage extends RecyclerView.Adapter 1) { + searchIndex = 1; + pos = text.indexOf(query); + } + + // Scroll to found text + if (pos >= 0) { + int color = Helper.resolveColor(searchView.getContext(), R.attr.colorHighlight); + SpannableString ss = new SpannableString(searchView.getText()); + ss.setSpan(new BackgroundColorSpan(color), + pos, pos + query.length(), + Spannable.SPAN_EXCLUSIVE_EXCLUSIVE | Spannable.SPAN_COMPOSING); + searchView.setText(ss); + + int line = searchView.getLayout().getLineForOffset(pos); + int y = searchView.getLayout().getLineTop(line); + int dy = searchView.getContext().getResources() + .getDimensionPixelSize(R.dimen.search_in_text_margin); + + View itemView = rvMessage.findContainingItemView(searchView); + if (itemView != null) { + Rect rect = new Rect(); + searchView.getDrawingRect(rect); + + RecyclerView.ViewHolder holder = rvMessage.getChildViewHolder(itemView); + ((ViewGroup) itemView).offsetDescendantRectToMyCoords(searchView, rect); + + iProperties.scrollTo(holder.getAdapterPosition(), rect.top + y - dy); + } + } + + boolean hasNext = (pos >= 0 && + (text.indexOf(query) != pos || + text.indexOf(query, pos + 1) >= 0)); + etSearch.setActionEnabled(hasNext); + } + + private void clearSearch() { + if (searchView == null) + return; + + SpannableString ss = new SpannableString(searchView.getText()); + for (BackgroundColorSpan span : ss.getSpans(0, ss.length(), BackgroundColorSpan.class)) + if ((ss.getSpanFlags(span) & Spannable.SPAN_COMPOSING) != 0) + ss.removeSpan(span); + searchView.setText(ss); + } + private ActivityBase.IKeyPressedListener onBackPressedListener = new ActivityBase.IKeyPressedListener() { @Override public boolean onKeyPressed(KeyEvent event) { diff --git a/app/src/main/res/layout/fragment_messages.xml b/app/src/main/res/layout/fragment_messages.xml index 762fea0427..5869c7460c 100644 --- a/app/src/main/res/layout/fragment_messages.xml +++ b/app/src/main/res/layout/fragment_messages.xml @@ -135,6 +135,22 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/tvHintSelect" /> + + + app:layout_constraintTop_toBottomOf="@id/etSearch" /> - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/values/dimen.xml b/app/src/main/res/values/dimen.xml index dc8b16c5e7..b027df5b48 100644 --- a/app/src/main/res/values/dimen.xml +++ b/app/src/main/res/values/dimen.xml @@ -11,4 +11,5 @@ 6dp 3dp 3dp + 48dp \ No newline at end of file