From 98fba9b33861687890c8f9ef3da40eee4d39a343 Mon Sep 17 00:00:00 2001 From: Quentin Gliosca Date: Mon, 13 Apr 2020 20:23:05 +0200 Subject: [PATCH 1/3] Implement a custom search box in the Webview Should fix #106 --- res/drawable-hdpi/ic_find_next_mtrl_alpha.png | Bin 0 -> 409 bytes .../ic_find_previous_mtrl_alpha.png | Bin 0 -> 403 bytes res/drawable-mdpi/ic_find_next_mtrl_alpha.png | Bin 0 -> 318 bytes .../ic_find_previous_mtrl_alpha.png | Bin 0 -> 316 bytes .../ic_find_next_mtrl_alpha.png | Bin 0 -> 578 bytes .../ic_find_previous_mtrl_alpha.png | Bin 0 -> 568 bytes .../ic_find_next_mtrl_alpha.png | Bin 0 -> 683 bytes .../ic_find_previous_mtrl_alpha.png | Bin 0 -> 657 bytes res/drawable/ic_find_next_material.xml | 19 +++ res/drawable/ic_find_previous_material.xml | 19 +++ res/layout/webview_find.xml | 20 +++ res/menu/webview_find.xml | 13 ++ res/values-fr/strings.xml | 3 + res/values/strings.xml | 3 + src/itkach/aard2/ArticleFragment.java | 1 - src/itkach/aard2/ArticleWebView.java | 2 +- src/itkach/aard2/FindActionModeCallback.java | 152 ++++++++++++++++++ src/itkach/aard2/SearchableWebView.java | 63 ++++++++ 18 files changed, 293 insertions(+), 2 deletions(-) create mode 100644 res/drawable-hdpi/ic_find_next_mtrl_alpha.png create mode 100644 res/drawable-hdpi/ic_find_previous_mtrl_alpha.png create mode 100644 res/drawable-mdpi/ic_find_next_mtrl_alpha.png create mode 100644 res/drawable-mdpi/ic_find_previous_mtrl_alpha.png create mode 100644 res/drawable-xhdpi/ic_find_next_mtrl_alpha.png create mode 100644 res/drawable-xhdpi/ic_find_previous_mtrl_alpha.png create mode 100644 res/drawable-xxhdpi/ic_find_next_mtrl_alpha.png create mode 100644 res/drawable-xxhdpi/ic_find_previous_mtrl_alpha.png create mode 100644 res/drawable/ic_find_next_material.xml create mode 100644 res/drawable/ic_find_previous_material.xml create mode 100644 res/layout/webview_find.xml create mode 100644 res/menu/webview_find.xml create mode 100644 src/itkach/aard2/FindActionModeCallback.java create mode 100644 src/itkach/aard2/SearchableWebView.java diff --git a/res/drawable-hdpi/ic_find_next_mtrl_alpha.png b/res/drawable-hdpi/ic_find_next_mtrl_alpha.png new file mode 100644 index 0000000000000000000000000000000000000000..6d5edac40386cbe858f8ff0363599dd6aaaec1c4 GIT binary patch literal 409 zcmV;K0cQS*P)37BqtI+7B}$|yr4(hOW-k`Av9qA8CuJ!cSy?JJmP%PzSjk$%N=Z?&5GhG1 zh5Q`P$(7GSx!gPM=zZ#GX71eco%jBnpHxZ+A%qY@2qFG6&bbNfFH&D+Sit6}3J&0N z;1rg}7`_%)+#5TXj-qHDZ`}uLn28~LJ06&RPOv4a;vINsiXUNTgy9GA#?)WOY}9us zgR7**i&mO?wJs$*z=8c!+2-fEo04Jtq;|>WWxAhqhFkx#yNBDBaZvmG6@S^ zAqe!&yq&}OUXPpR|4YmzZMDwfg$cQZjo63h=J+l)C3VZufZHbQ6+W2Xi&&NPeUpFJ z7u;v=ajeuffFr@6KEvKp-Nkl=Ss#QDLI@#*5F!k(uoW9=j+3I~00000NkvXXu0mjf DB;vg# literal 0 HcmV?d00001 diff --git a/res/drawable-hdpi/ic_find_previous_mtrl_alpha.png b/res/drawable-hdpi/ic_find_previous_mtrl_alpha.png new file mode 100644 index 0000000000000000000000000000000000000000..a5921afe8d6fa8bd0c629ef69950a5b7eb77afd5 GIT binary patch literal 403 zcmV;E0c`$>P)4g43fV}B5-Cb4McF8OvA7#M3(8u`QZ}-(RBSAjvaqm{wTRU%DM}V1B`Kwl zpYfbJQ=g4+XU1H;Pd!a{e!la5bLPz4Tuulfgb+dqArc@A!yarX)$rr^h?m%3O2I2} zCH%}2PL@LWCfql{Z}HjuUd5`ch9AUh6Lt@qaR9H({zGiZTKFk^F(H@TqhyXZ;;uP< z;~LIF@M>H$!Q7&q_+o7=nR8vk(-{0!_;xIqKo{8ejqApIqY>*^lXm!FyfYzoe)7KO z++I90*B@a=8o>jc#aA=8)*_(*&zS`002ovPDHLkV1m!Mv`qj2 literal 0 HcmV?d00001 diff --git a/res/drawable-mdpi/ic_find_next_mtrl_alpha.png b/res/drawable-mdpi/ic_find_next_mtrl_alpha.png new file mode 100644 index 0000000000000000000000000000000000000000..1cfdb3fe6140e8e9ac0eb0104b91f8c35e8e2ac6 GIT binary patch literal 318 zcmV-E0m1%>P)T2OFvXpA%Xe6WA2lrTj+~mr9FTw|x{5K>LiDaLw0Zq9!tnW=o Q-~a#s07*qoM6N<$g0Mt}WB>pF literal 0 HcmV?d00001 diff --git a/res/drawable-mdpi/ic_find_previous_mtrl_alpha.png b/res/drawable-mdpi/ic_find_previous_mtrl_alpha.png new file mode 100644 index 0000000000000000000000000000000000000000..0d3c009d07675ed33bd29f0444766bad92123cca GIT binary patch literal 316 zcmV-C0mJ@@P)W8SBp&HUW+opZl)zVBX}jSxZzA%qY@2qA%^Ii=Za{CGOgsfP!&O*d#z3#y2WPNBd~V_7GhsKphaor#?M4lj1vj;?+`vJ@ z28|w14qSvUVeyEY<2Q29T)3h$=s3(XG3CqPu5vT(;E3TFDKlXpY%6Fo{dSx$6~mo9F8J0W@SqoR6g$)jn993kKlw;@Ii~rCG1S-l>cTC?66HX zGAetpJXziYimM>9Qpgq8!3G*+DvNgb+dqA%qY@2qA}M{P)(J(p11t+BzY)4)eSiykAXpLG6L1vhTt2U#=-fqDLJ8onu%l8}60h z)72ywG9Gm9FRD1!sIuuIGDr=|U={9Hz8G%Vw7B8F%n;VfhO5RVORF50HX5!CXo6=p z6}!QS%*bE_hm4`=O(mev&A?M&zsi9AAluRbT-x|^n~kq`{7B#inQ+;t&ax3>@|wDM z^h(qS?dZ|7%lw8-F&YR*F~U7FRPi;F(d^{TH)^lG^!vJSwj&v=)Ce6^$8f@pW6-Mx zl7NQ>FiFe`%ynzdPxj*f4L(8$A%qY@2qAPx#32;bRa{vGf6951U69E94oEQKA0#HdrK~#9!?bu&vjd2{u@#i?(I2LJ>L#8mw zjWV^?X>!2@DHq6%7A_Xj;*M6EQc7IWO3DSfSyB=gY8RFw7g8G+F63Vh(`piHW6sXo z&Bpoum_Lu-^XxqJdEK3!=lOoWzvn!^-}8NbK_DU`A|fIpA|fIpA|hppHs;5gubCM> z!?gmhXo#u!G$$z1=`Uatp8*)5HHPwQxCKCg4SoVTghV+ZIJbGyeV54HfgUjH&mRhd~g=%C2@5sP2^4LN38hA2q}(IFfk&2 zMY;vl(qqzpVrPhUVbUoTOM%M3K{^|FT_pZpwek>gj5-xAW1I(nHN3ui55Y zbCY?~`JJ$eC#IZdto_Z|6`V5v+BnC&_WhxTFo$bq2&3$o;>-o~M%*rh972kAXGJ+f z)t3&R()X^3cEw0M1eoBonnPx#32;bRa{vGf6951U69E94oEQKA0yarRK~#9!?bl66R8bhl@$s`v3bDu}gUSLo zfd&$T(V`Yf(4wMEM79u%5Zx7l20;+DDuf7H6m2AekX#5Zl%Qx4f#$+R^dVY`U_^tPb4VewfT0GL(z<1N{@5fR?Qw+%UyG1nu}yaE&gG~OvvXHo8xEZZK?o|SQnk} z8C)i1;@u)=!Kg}x%$OcZqY-~SPn_+tW|5Jb={6(3a3uWrW%Qd+@7TM<=xlC~o;P}i zD`bWl|2W@F{7wr0Ip>%&r=5au!e?>aoXs>h$@;IE<-9jP;VpZ@Xp}omi0_9&P%rWA3lc`v*-*>D}So8 zn?9$_IN)#mBD&0iV^puQVm_^=;v^URi=X6^S*(|xp44r0I@pK4v>BY|r&*?zd=F2} zpmS=rd)+ACcP?~;=YP%@zO@1Ch5Z!UgNw+r)c)1%^=CBv)OI+?Jhg(G~HLd zxwwPDJ#HxH^sG3p1Z$q-wA31cudZ<87U5WSF{!wpdzp~@fvBGy)9bLra-%` rs!-n(L_|bHL_|bHL_|bHWC_0j>8V&Ya4U{500000NkvXXu0mjfO|dTD literal 0 HcmV?d00001 diff --git a/res/drawable/ic_find_next_material.xml b/res/drawable/ic_find_next_material.xml new file mode 100644 index 00000000..c6674ebf --- /dev/null +++ b/res/drawable/ic_find_next_material.xml @@ -0,0 +1,19 @@ + + + + diff --git a/res/drawable/ic_find_previous_material.xml b/res/drawable/ic_find_previous_material.xml new file mode 100644 index 00000000..32fcb315 --- /dev/null +++ b/res/drawable/ic_find_previous_material.xml @@ -0,0 +1,19 @@ + + + + diff --git a/res/layout/webview_find.xml b/res/layout/webview_find.xml new file mode 100644 index 00000000..5cdf67af --- /dev/null +++ b/res/layout/webview_find.xml @@ -0,0 +1,20 @@ + + + + \ No newline at end of file diff --git a/res/menu/webview_find.xml b/res/menu/webview_find.xml new file mode 100644 index 00000000..41bb36e6 --- /dev/null +++ b/res/menu/webview_find.xml @@ -0,0 +1,13 @@ + + + + + \ No newline at end of file diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml index 69a46428..cf08c998 100644 --- a/res/values-fr/strings.xml +++ b/res/values-fr/strings.xml @@ -102,5 +102,8 @@ Auto Plein écran Utiliser les boutons du volume +/- pour haut/bas + Rechercher sur la page + Suivant + Précédent diff --git a/res/values/strings.xml b/res/values/strings.xml index d8b041cf..83b24b17 100755 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -109,4 +109,7 @@ Full Screen Use volume buttons for navigation File access was not allowed, quitting... + Find in page + Next + Previous diff --git a/src/itkach/aard2/ArticleFragment.java b/src/itkach/aard2/ArticleFragment.java index 7341aeef..751e053d 100644 --- a/src/itkach/aard2/ArticleFragment.java +++ b/src/itkach/aard2/ArticleFragment.java @@ -73,7 +73,6 @@ private void displayBookmarked(boolean value) { } } - @SuppressWarnings("deprecation") @Override public boolean onOptionsItemSelected(MenuItem item) { int itemId = item.getItemId(); diff --git a/src/itkach/aard2/ArticleWebView.java b/src/itkach/aard2/ArticleWebView.java index 378f801a..c47ad693 100644 --- a/src/itkach/aard2/ArticleWebView.java +++ b/src/itkach/aard2/ArticleWebView.java @@ -33,7 +33,7 @@ import java.util.TimerTask; import java.util.TreeSet; -public class ArticleWebView extends WebView { +public class ArticleWebView extends SearchableWebView { public static final String LOCALHOST = Application.LOCALHOST; private final String styleSwitcherJs; diff --git a/src/itkach/aard2/FindActionModeCallback.java b/src/itkach/aard2/FindActionModeCallback.java new file mode 100644 index 00000000..8d29a201 --- /dev/null +++ b/src/itkach/aard2/FindActionModeCallback.java @@ -0,0 +1,152 @@ +/* +* This file is heavily inspired by the Android Open Source Project +* licensed under the Apache License, Version 2.0 +*/ + +package itkach.aard2; + +import android.content.Context; +import android.os.Build; +import android.text.Editable; +import android.text.Selection; +import android.text.Spannable; +import android.text.TextWatcher; +import android.view.ActionMode; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.inputmethod.InputMethodManager; +import android.widget.EditText; + +class FindActionModeCallback implements ActionMode.Callback, TextWatcher, + View.OnLongClickListener, View.OnClickListener { + + private View searchView; + private EditText editText; + private SearchableWebView webview; + private InputMethodManager imManager; + + FindActionModeCallback(Context context, SearchableWebView webview) { + this.webview = webview; + searchView = LayoutInflater.from(context).inflate(R.layout.webview_find, null); + + editText = searchView.findViewById(R.id.edit); + editText.setOnLongClickListener(this); + editText.setOnClickListener(this); + editText.addTextChangedListener(this); + + imManager = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); + } + + /* Place text in the text field so it can be searched for. */ + void setText(String text) { + editText.setText(text); + Spannable span = (Spannable) editText.getText(); + int length = span.length(); + // Ideally, we would like to set the selection to the whole field, + // but this brings up the Text selection CAB, which dismisses this + // one. + Selection.setSelection(span, length, length); + // Necessary each time we set the text, so that this will watch + // changes to it. + span.setSpan(this, 0, length, Spannable.SPAN_INCLUSIVE_INCLUSIVE); + } + + /* + * Move the highlight to the next match. + * @param next If true, find the next match further down in the document. + * If false, find the previous match, up in the document. + */ + private void findNext(boolean next) { + webview.findNext(next); + } + + /* + * Highlight all the instances of the string from editText in webview. + */ + void findAll() { + String find = editText.getText().toString(); + if (find.length() == 0) + return; + + if (Build.VERSION.SDK_INT < 16) + webview.findAll(find); + else + webview.findAllAsync(find); + } + + void showSoftInput() { + // imManager.showSoftInputMethod doesn't work + imManager.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0); + } + + // OnLongClickListener implementation + @Override + public boolean onLongClick(View v) { + // Override long click so that select ActionMode is not opened, which + // would exit find ActionMode. + return true; + } + + // OnClickListener implementation + @Override + public void onClick(View v) { + findNext(true); + } + + // ActionMode.Callback implementation + @Override + public boolean onCreateActionMode(ActionMode mode, Menu menu) { + mode.setCustomView(searchView); + mode.getMenuInflater().inflate(R.menu.webview_find, menu); + + Editable edit = editText.getText(); + Selection.setSelection(edit, edit.length()); + editText.requestFocus(); + return true; + } + + @Override + public void onDestroyActionMode(ActionMode mode) { + webview.clearMatches(); + imManager.hideSoftInputFromWindow(webview.getWindowToken(), 0); + webview.setLastFind(editText.getText().toString()); + } + @Override + public boolean onPrepareActionMode(ActionMode mode, Menu menu) { + return false; + } + + @Override + public boolean onActionItemClicked(ActionMode mode, MenuItem item) { + imManager.hideSoftInputFromWindow(webview.getWindowToken(), 0); + switch(item.getItemId()) { + case R.id.find_prev: + findNext(false); + break; + case R.id.find_next: + findNext(true); + break; + default: + return false; + } + return true; + } + + // TextWatcher implementation + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + // Does nothing. Needed to implement TextWatcher. + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + findAll(); + } + + @Override + public void afterTextChanged(Editable s) { + // Does nothing. Needed to implement TextWatcher. + } +} \ No newline at end of file diff --git a/src/itkach/aard2/SearchableWebView.java b/src/itkach/aard2/SearchableWebView.java new file mode 100644 index 00000000..f112a271 --- /dev/null +++ b/src/itkach/aard2/SearchableWebView.java @@ -0,0 +1,63 @@ +/* + * This file is heavily inspired by the Android Open Source Project + * licensed under the Apache License, Version 2.0 + */ + +package itkach.aard2; + +import android.content.Context; +import android.util.AttributeSet; +import android.webkit.WebView; + +class SearchableWebView extends WebView { + + private String mLastFind = null; + + public void setLastFind(String find) { + mLastFind = find; + } + + public SearchableWebView(Context context) { + this(context, null); + } + + public SearchableWebView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + /** + * Start an ActionMode for finding text in this WebView. Only works if this + * WebView is attached to the view system. + * + * @param text If non-null, will be the initial text to search for. + * Otherwise, the last String searched for in this WebView will + * be used to start. + * @param showIme If true, show the IME, assuming the user will begin typing. + * If false and text is non-null, perform a find all. + * @return boolean True if the find dialog is shown, false otherwise. + */ + @Override + public boolean showFindDialog(String text, boolean showIme) { + FindActionModeCallback callback = new FindActionModeCallback(getContext(), this); + if (getParent() == null || startActionMode(callback) == null) { + // Could not start the action mode, so end Find on page + return false; + } + + if (showIme) { + callback.showSoftInput(); + } else if (text != null) { + callback.setText(text); + callback.findAll(); + return true; + } + if (text == null) { + text = mLastFind; + } + if (text != null) { + callback.setText(text); + callback.findAll(); + } + return true; + } +} From d841b07f57fc4643ae4589fe5e33a38b0f430f3e Mon Sep 17 00:00:00 2001 From: Quentin Gliosca Date: Tue, 14 Apr 2020 08:54:18 +0200 Subject: [PATCH 2/3] Add some translations for the webview's search box --- res/values-de/strings.xml | 1 + res/values-es/strings.xml | 3 +++ res/values-it/strings.xml | 9 ++++++--- res/values-ru/strings.xml | 1 + 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml index 5ffdd9fc..01ba596d 100644 --- a/res/values-de/strings.xml +++ b/res/values-de/strings.xml @@ -96,4 +96,5 @@ Lade externen Inhalt Vollbild Lautstärketasten für die Navigation verwenden + Suche in Seite diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml index 324f8518..8684130e 100644 --- a/res/values-es/strings.xml +++ b/res/values-es/strings.xml @@ -102,5 +102,8 @@ Pantalla completa Usar botones de volumen para navegación Acceso de archivo denegado, saliendo... + Buscar en la página + Siguiente + Anterior" diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml index 2b268ee8..9ef9a51c 100644 --- a/res/values-it/strings.xml +++ b/res/values-it/strings.xml @@ -94,7 +94,10 @@ is missing a quantity used in that language, otherwise the app will crash Stile interfaccia utente Chiaro Scuro - Carica contenuto remoto - Schermo intero - Usare i tasti del volume per la navigazione +Carica contenuto remoto +Schermo intero +Usare i tasti del volume per la navigazione +Trova nella pagina +Successivo +Precedente diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml index 86a30a11..cb0069d2 100644 --- a/res/values-ru/strings.xml +++ b/res/values-ru/strings.xml @@ -87,4 +87,5 @@ Загрузить удалённый контент Весь экран Использовать кнопки громкости для навигации + Поиск на странице From 65d17e8a483e82feb8a0c5e3da228460b5f4cdb8 Mon Sep 17 00:00:00 2001 From: Quentin Gliosca Date: Sat, 18 Apr 2020 08:37:42 +0200 Subject: [PATCH 3/3] Fix match clearing after the find is deleted character by character --- src/itkach/aard2/FindActionModeCallback.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/itkach/aard2/FindActionModeCallback.java b/src/itkach/aard2/FindActionModeCallback.java index 8d29a201..a962ae7f 100644 --- a/src/itkach/aard2/FindActionModeCallback.java +++ b/src/itkach/aard2/FindActionModeCallback.java @@ -67,8 +67,6 @@ private void findNext(boolean next) { */ void findAll() { String find = editText.getText().toString(); - if (find.length() == 0) - return; if (Build.VERSION.SDK_INT < 16) webview.findAll(find);