diff --git a/FAQ.md b/FAQ.md index 587cff71cd..2ee732e2c7 100644 --- a/FAQ.md +++ b/FAQ.md @@ -109,7 +109,7 @@ Related questions: * ~~Unified starred messages view~~ (there is already a special search for this) * ~~Notification move action~~ * ~~S/MIME support~~ -* Search for settings: low priority +* ~~Search for settings~~ Anything on this list is in random order and *might* be added in the near future. diff --git a/app/src/main/java/eu/faircode/email/FragmentBase.java b/app/src/main/java/eu/faircode/email/FragmentBase.java index 5c84e2a8d2..3621321c28 100644 --- a/app/src/main/java/eu/faircode/email/FragmentBase.java +++ b/app/src/main/java/eu/faircode/email/FragmentBase.java @@ -37,6 +37,7 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.inputmethod.InputMethodManager; +import android.widget.ScrollView; import android.widget.TextView; import android.widget.Toast; @@ -71,6 +72,7 @@ public class FragmentBase extends Fragment { private long message = -1; private long attachment = -1; + private int scrollTo = 0; private static final int REQUEST_ATTACHMENT = 51; private static final int REQUEST_ATTACHMENTS = 52; @@ -97,6 +99,37 @@ public class FragmentBase extends Fragment { updateSubtitle(); } + void scrollTo(int resid) { + scrollTo = resid; + scrollTo(); + } + + private void scrollTo() { + if (scrollTo == 0) + return; + + View view = getView(); + if (view == null) + return; + + final ScrollView scroll = view.findViewById(R.id.scroll); + if (scroll == null) + return; + + final View child = scroll.findViewById(scrollTo); + if (child == null) + return; + + scrollTo = 0; + + scroll.post(new Runnable() { + @Override + public void run() { + scroll.scrollTo(0, child.getTop()); + } + }); + } + @Override public void startActivity(Intent intent) { try { @@ -176,6 +209,7 @@ public class FragmentBase extends Fragment { public void onActivityCreated(Bundle savedInstanceState) { Log.d("Activity " + this + " saved=" + (savedInstanceState != null)); super.onActivityCreated(savedInstanceState); + scrollTo(); } @Override diff --git a/app/src/main/java/eu/faircode/email/FragmentOptions.java b/app/src/main/java/eu/faircode/email/FragmentOptions.java index 148911fa07..3ca8744e89 100644 --- a/app/src/main/java/eu/faircode/email/FragmentOptions.java +++ b/app/src/main/java/eu/faircode/email/FragmentOptions.java @@ -25,18 +25,26 @@ import android.app.Dialog; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; +import android.database.Cursor; +import android.database.MatrixCursor; import android.os.Bundle; import android.view.KeyEvent; import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.CheckBox; import android.widget.CompoundButton; +import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AlertDialog; +import androidx.appcompat.widget.SearchView; import androidx.constraintlayout.widget.Group; +import androidx.cursoradapter.widget.SimpleCursorAdapter; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentStatePagerAdapter; @@ -74,6 +82,7 @@ public class FragmentOptions extends FragmentBase { @Nullable public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_options, container, false); + setHasOptionsMenu(true); pager = view.findViewById(R.id.pager); adapter = new PagerAdapter(getChildFragmentManager()); @@ -144,6 +153,97 @@ public class FragmentOptions extends FragmentBase { onExit(); } + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + inflater.inflate(R.menu.menu_setup, menu); + + final MenuItem menuSearch = menu.findItem(R.id.menu_search); + final SearchView searchView = (SearchView) menuSearch.getActionView(); + + searchView.setQueryHint(getString(R.string.title_search)); + + searchView.setOnSuggestionListener(new SearchView.OnSuggestionListener() { + @Override + public boolean onSuggestionSelect(int position) { + return false; + } + + @Override + public boolean onSuggestionClick(int position) { + Cursor cursor = searchView.getSuggestionsAdapter().getCursor(); + cursor.moveToPosition(position); + int id = cursor.getInt(cursor.getColumnIndex("_id")); + int tab = cursor.getInt(cursor.getColumnIndex("tab")); + + pager.setCurrentItem(tab); + FragmentBase fragment = (FragmentBase) adapter.instantiateItem(pager, tab); + fragment.scrollTo(id); + menuSearch.collapseActionView(); + + return true; + } + }); + + searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { + private int[] tabs = { + R.layout.fragment_setup, + R.layout.fragment_options_synchronize, + R.layout.fragment_options_send, + R.layout.fragment_options_connection, + R.layout.fragment_options_display, + R.layout.fragment_options_behavior, + R.layout.fragment_options_privacy, + R.layout.fragment_options_encryption, + R.layout.fragment_options_notifications, + R.layout.fragment_options_misc + }; + + @Override + public boolean onQueryTextSubmit(String query) { + return false; + } + + @Override + public boolean onQueryTextChange(String newText) { + MatrixCursor cursor = new MatrixCursor(new String[]{"_id", "tab", "title"}); + + if (newText != null && newText.length() > 2) { + LayoutInflater inflater = LayoutInflater.from(searchView.getContext()); + for (int tab = 0; tab < tabs.length; tab++) + getSuggestions(newText.toLowerCase(), tab, inflater.inflate(tabs[tab], null), cursor); + } + + searchView.setSuggestionsAdapter(new SimpleCursorAdapter( + searchView.getContext(), + R.layout.spinner_item1_dropdown, + cursor, + new String[]{"title"}, + new int[]{android.R.id.text1}, + 0 + )); + + return false; + } + }); + + super.onCreateOptionsMenu(menu, inflater); + } + + private void getSuggestions(String query, int tab, View view, MatrixCursor cursor) { + if (view instanceof ViewGroup) { + ViewGroup group = (ViewGroup) view; + for (int i = 0; i <= group.getChildCount(); i++) + getSuggestions(query, tab, group.getChildAt(i), cursor); + } else if (view instanceof TextView) { + String text = ((TextView) view).getText().toString(); + if (text.toLowerCase().contains(query)) + cursor.newRow() + .add("_id", view.getId()) + .add("tab", tab) + .add("title", text); + } + } + @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); diff --git a/app/src/main/java/eu/faircode/email/FragmentSetup.java b/app/src/main/java/eu/faircode/email/FragmentSetup.java index 2e0f0a3251..4cb2898e68 100644 --- a/app/src/main/java/eu/faircode/email/FragmentSetup.java +++ b/app/src/main/java/eu/faircode/email/FragmentSetup.java @@ -356,8 +356,6 @@ public class FragmentSetup extends FragmentBase { public void onChanged(@Nullable List accounts) { done = (accounts != null && accounts.size() > 0); - getActivity().invalidateOptionsMenu(); - tvQuickRemark.setVisibility(done ? View.VISIBLE : View.GONE); tvAccountDone.setText(done ? R.string.title_setup_done : R.string.title_setup_to_do); diff --git a/app/src/main/res/layout/fragment_options_behavior.xml b/app/src/main/res/layout/fragment_options_behavior.xml index d238d74778..4e2c444216 100644 --- a/app/src/main/res/layout/fragment_options_behavior.xml +++ b/app/src/main/res/layout/fragment_options_behavior.xml @@ -2,6 +2,7 @@ - + + +