diff --git a/AndroidManifest.xml b/AndroidManifest.xml index f86a2fb81..ad500c2e8 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -265,7 +265,8 @@ + android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"> + diff --git a/res/drawable-xhdpi/ic_search_down.png b/res/drawable-xhdpi/ic_search_down.png new file mode 100644 index 000000000..23e4d7c4f Binary files /dev/null and b/res/drawable-xhdpi/ic_search_down.png differ diff --git a/res/drawable-xhdpi/ic_search_up.png b/res/drawable-xhdpi/ic_search_up.png new file mode 100644 index 000000000..b2286ea5a Binary files /dev/null and b/res/drawable-xhdpi/ic_search_up.png differ diff --git a/res/menu/local_help.xml b/res/menu/local_help.xml index 0b1800bb8..b3fd9ecad 100644 --- a/res/menu/local_help.xml +++ b/res/menu/local_help.xml @@ -2,6 +2,23 @@ + + + + + + diff --git a/src/org/thoughtcrime/securesms/BaseActionBarActivity.java b/src/org/thoughtcrime/securesms/BaseActionBarActivity.java index f82915532..f7595809b 100644 --- a/src/org/thoughtcrime/securesms/BaseActionBarActivity.java +++ b/src/org/thoughtcrime/securesms/BaseActionBarActivity.java @@ -9,6 +9,8 @@ import androidx.core.app.ActivityOptionsCompat; import androidx.appcompat.app.AppCompatActivity; import android.util.Log; import android.view.KeyEvent; +import android.view.Menu; +import android.view.MenuItem; import android.view.View; import android.view.ViewConfiguration; import android.view.WindowManager; @@ -156,4 +158,16 @@ public abstract class BaseActionBarActivity extends AppCompatActivity { isWaitingForResult = true; } } + + public void makeSearchMenuVisible(final Menu menu, final MenuItem exception, boolean visible) { + for (int i = 0; i < menu.size(); ++i) { + MenuItem item = menu.getItem(i); + int id = item.getItemId(); + if (id==R.id.menu_search_up || id==R.id.menu_search_down) { + item.setVisible(!visible); + } else if (item != exception) { + item.setVisible(visible); + } + } + } } diff --git a/src/org/thoughtcrime/securesms/LocalHelpActivity.java b/src/org/thoughtcrime/securesms/LocalHelpActivity.java index f7318b12a..cbf6b399a 100644 --- a/src/org/thoughtcrime/securesms/LocalHelpActivity.java +++ b/src/org/thoughtcrime/securesms/LocalHelpActivity.java @@ -5,25 +5,29 @@ import android.content.Intent; import android.content.res.AssetManager; import android.net.Uri; import android.os.Bundle; +import android.util.Log; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.webkit.WebView; import android.webkit.WebViewClient; +import android.widget.ImageView; import android.widget.Toast; -import org.thoughtcrime.securesms.connect.ApplicationDcContext; -import org.thoughtcrime.securesms.connect.DcHelper; +import androidx.appcompat.widget.SearchView; + import org.thoughtcrime.securesms.util.DynamicLanguage; import org.thoughtcrime.securesms.util.DynamicTheme; -import java.io.File; import java.io.InputStream; -import java.util.Arrays; import java.util.Locale; public class LocalHelpActivity extends PassphraseRequiredActionBarActivity + implements SearchView.OnQueryTextListener, + WebView.FindListener { + private static final String TAG = LocalHelpActivity.class.getSimpleName(); + private WebView webView; private final DynamicTheme dynamicTheme = new DynamicTheme(); private final DynamicLanguage dynamicLanguage = new DynamicLanguage(); @@ -84,6 +88,7 @@ public class LocalHelpActivity extends PassphraseRequiredActionBarActivity } }); webView.loadUrl("file:///android_asset/" + helpPath.replace("LANG", helpLang)); + webView.setFindListener(this); } @Override @@ -104,10 +109,75 @@ public class LocalHelpActivity extends PassphraseRequiredActionBarActivity menu.clear(); inflater.inflate(R.menu.local_help, menu); + + try { + MenuItem searchItem = menu.findItem(R.id.menu_search_localhelp); + searchItem.setOnActionExpandListener(new MenuItem.OnActionExpandListener() { + @Override + public boolean onMenuItemActionExpand(final MenuItem item) { + LocalHelpActivity.this.lastQuery = ""; + LocalHelpActivity.this.makeSearchMenuVisible(menu, searchItem, false); + return true; + } + + @Override + public boolean onMenuItemActionCollapse(final MenuItem item) { + LocalHelpActivity.this.makeSearchMenuVisible(menu, searchItem, true); + return true; + } + }); + SearchView searchView = (SearchView) searchItem.getActionView(); + searchView.setOnQueryTextListener(this); + searchView.setQueryHint(getString(R.string.search)); + searchView.setIconifiedByDefault(true); + + // hide the [X] beside the search field - this is too much noise, search can be aborted eg. by "back" + ImageView closeBtn = searchView.findViewById(R.id.search_close_btn); + if (closeBtn!=null) { + closeBtn.setEnabled(false); + closeBtn.setImageDrawable(null); + } + } catch (Exception e) { + Log.e(TAG, "cannot set up help-search: ", e); + } + super.onPrepareOptionsMenu(menu); return true; } + private String lastQuery = ""; + private Toast lastToast = null; + + @Override + public boolean onQueryTextSubmit(String query) { + return true; // action handled by listener + } + + @Override + public boolean onQueryTextChange(String query) { + String normQuery = query.trim(); + lastQuery = normQuery; + if (lastToast!=null) { + lastToast.cancel(); + lastToast = null; + } + webView.findAllAsync(normQuery); + return true; // action handled by listener + } + + @Override + public void onFindResultReceived (int activeMatchOrdinal, int numberOfMatches, boolean isDoneCounting) + { + if (isDoneCounting && numberOfMatches==0 && !lastQuery.isEmpty()) { + String msg = getString(R.string.search_no_result_for_x, lastQuery); + if (lastToast!=null) { + lastToast.cancel(); + } + lastToast = Toast.makeText(this, msg, Toast.LENGTH_SHORT); + lastToast.show(); + } + } + @Override public boolean onOptionsItemSelected(MenuItem item) { super.onOptionsItemSelected(item); @@ -115,6 +185,20 @@ public class LocalHelpActivity extends PassphraseRequiredActionBarActivity case android.R.id.home: finish(); return true; + case R.id.menu_search_up: + if (lastQuery.isEmpty()) { + webView.scrollTo(0, 0); + } else { + webView.findNext(false); + } + return true; + case R.id.menu_search_down: + if (lastQuery.isEmpty()) { + webView.scrollTo(0, 1000000000); + } else { + webView.findNext(true); + } + return true; case R.id.log_scroll_up: webView.scrollTo(0, 0); return true;