X-Git-Url: http://gitweb.fperrin.net/?p=Dictionary.git;a=blobdiff_plain;f=src%2Fcom%2Fhughes%2Fandroid%2Fdictionary%2FDictionaryActivity.java;h=e2558a0773605615ff629cb7aab682a9605a2de3;hp=0b09e6da8855fdf4e151e5499b1cb2a0545b5ddd;hb=c76660b2772122109529d3616289980a7084eeeb;hpb=83d9dc7cd871082a82c2dd0dbb7a0ceabd7c83a0 diff --git a/src/com/hughes/android/dictionary/DictionaryActivity.java b/src/com/hughes/android/dictionary/DictionaryActivity.java index 0b09e6d..e2558a0 100644 --- a/src/com/hughes/android/dictionary/DictionaryActivity.java +++ b/src/com/hughes/android/dictionary/DictionaryActivity.java @@ -21,17 +21,20 @@ import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; +import android.database.Cursor; +import android.database.MatrixCursor; import android.graphics.Color; import android.graphics.Typeface; import android.net.Uri; import android.os.Bundle; import android.os.Handler; -import android.preference.PreferenceManager; +import android.support.v7.preference.PreferenceManager; import android.speech.tts.TextToSpeech; import android.speech.tts.TextToSpeech.OnInitListener; import android.support.annotation.NonNull; import android.support.design.widget.FloatingActionButton; import android.support.v4.view.MenuItemCompat; +import android.support.v4.widget.CursorAdapter; import android.support.v7.app.ActionBar; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.SearchView; @@ -65,6 +68,7 @@ import android.view.inputmethod.InputMethodManager; import android.widget.AdapterView; import android.widget.AdapterView.AdapterContextMenuInfo; import android.widget.AdapterView.OnItemClickListener; +import android.widget.AutoCompleteTextView; import android.widget.BaseAdapter; import android.widget.Button; import android.widget.FrameLayout; @@ -101,6 +105,7 @@ import java.io.PrintWriter; import java.io.RandomAccessFile; import java.nio.channels.FileChannel; import java.text.SimpleDateFormat; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Date; @@ -147,6 +152,9 @@ public class DictionaryActivity extends AppCompatActivity { }); private SearchOperation currentSearchOperation = null; + private final int MAX_SEARCH_HISTORY = 10; + private final ArrayList searchHistory = new ArrayList<>(MAX_SEARCH_HISTORY); + private MatrixCursor searchHistoryCursor = new MatrixCursor(new String[] {"_id", "search"}); private TextToSpeech textToSpeech; private volatile boolean ttsReady; @@ -173,6 +181,7 @@ public class DictionaryActivity extends AppCompatActivity { } private SearchView searchView; + private AutoCompleteTextView searchTextView; private ImageButton languageButton; private SearchView.OnQueryTextListener onQueryTextListener; @@ -213,6 +222,7 @@ public class DictionaryActivity extends AppCompatActivity { Log.d(LOG, "onSaveInstanceState: " + searchView.getQuery().toString()); outState.putString(C.INDEX_SHORT_NAME, index.shortName); outState.putString(C.SEARCH_TOKEN, searchView.getQuery().toString()); + outState.putStringArrayList(C.SEARCH_HISTORY, searchHistory); } private int getMatchLen(String search, Index.IndexEntry e) { @@ -238,12 +248,44 @@ public class DictionaryActivity extends AppCompatActivity { } dictRaf = null; } - Toast.makeText(this, getString(R.string.invalidDictionary, "", e.getMessage()), - Toast.LENGTH_LONG).show(); + if (!isFinishing()) + Toast.makeText(this, getString(R.string.invalidDictionary, "", e.getMessage()), + Toast.LENGTH_LONG).show(); startActivity(DictionaryManagerActivity.getLaunchIntent(getApplicationContext())); finish(); } + private void saveSearchHistory() { + final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); + final SharedPreferences.Editor ed = prefs.edit(); + for (int i = 0; i < searchHistory.size(); i++) { + ed.putString("history" + i, searchHistory.get(i)); + } + ed.remove("history" + searchHistory.size()); + ed.apply(); + } + + private void addToSearchHistory() { + addToSearchHistory(searchView.getQuery().toString()); + } + + private void addToSearchHistory(String text) { + if (text == null || text.isEmpty()) return; + int exists = searchHistory.indexOf(text); + if (exists >= 0) searchHistory.remove(exists); + else if (searchHistory.size() >= MAX_SEARCH_HISTORY) searchHistory.remove(searchHistory.size() - 1); + searchHistory.add(0, text); + searchHistoryCursor = new MatrixCursor(new String[] {"_id", "search"}); + for (int i = 0; i < searchHistory.size(); i++) { + final Object[] row = {i, searchHistory.get(i)}; + searchHistoryCursor.addRow(row); + } + if (searchView.getSuggestionsAdapter().getCursor() != null) { + searchView.getSuggestionsAdapter().swapCursor(searchHistoryCursor); + searchView.getSuggestionsAdapter().notifyDataSetChanged(); + } + } + @Override public void onCreate(Bundle savedInstanceState) { DictionaryApplication.INSTANCE.init(getApplicationContext()); @@ -284,7 +326,7 @@ public class DictionaryActivity extends AppCompatActivity { * -> language in which the phrase is written to -> to which * language shall be translated */ - if (intentAction != null && intentAction.equals("com.hughes.action.ACTION_SEARCH_DICT")) { + if ("com.hughes.action.ACTION_SEARCH_DICT".equals(intentAction)) { String query = intent.getStringExtra(SearchManager.QUERY); String from = intent.getStringExtra("from"); if (from != null) @@ -413,7 +455,8 @@ public class DictionaryActivity extends AppCompatActivity { } if (dictFilename == null) { - Toast.makeText(this, getString(R.string.no_dict_file), Toast.LENGTH_LONG).show(); + if (!isFinishing()) + Toast.makeText(this, getString(R.string.no_dict_file), Toast.LENGTH_LONG).show(); startActivity(DictionaryManagerActivity.getLaunchIntent(getApplicationContext())); finish(); return; @@ -522,8 +565,9 @@ public class DictionaryActivity extends AppCompatActivity { typeface = Typeface.createFromAsset(getAssets(), fontName); } catch (Exception e) { Log.w(LOG, "Exception trying to use typeface, using default.", e); - Toast.makeText(this, getString(R.string.fontFailure, e.getLocalizedMessage()), - Toast.LENGTH_LONG).show(); + if (!isFinishing()) + Toast.makeText(this, getString(R.string.fontFailure, e.getLocalizedMessage()), + Toast.LENGTH_LONG).show(); } break; } @@ -568,6 +612,54 @@ public class DictionaryActivity extends AppCompatActivity { if (text == null) { text = ""; } + + searchView.setOnSuggestionListener(new SearchView.OnSuggestionListener() { + @Override + public boolean onSuggestionSelect(int position) { + return false; + } + + @Override + public boolean onSuggestionClick(int position) { + String h = searchHistory.get(position); + addToSearchHistory(h); + setSearchText(h, true); + return true; + } + }); + searchView.setSuggestionsAdapter(new CursorAdapter(this, text.isEmpty() ? searchHistoryCursor : null, 0) { + @Override + public View newView(Context context, Cursor c, ViewGroup p) { + TextView v = new TextView(context); + v.setTextColor(textColorFg); + v.setTypeface(typeface); + v.setTextSize(TypedValue.COMPLEX_UNIT_SP, 4 * fontSizeSp / 3); + return v; + } + @Override + public void bindView(View v, Context context, Cursor c) { + TextView t = (TextView)v; + t.setText(c.getString(1)); + } + }); + + // Set up search history + ArrayList savedHistory = null; + if (savedInstanceState != null) savedHistory = savedInstanceState.getStringArrayList(C.SEARCH_HISTORY); + if (savedHistory != null && !savedHistory.isEmpty()) { + } else { + savedHistory = new ArrayList<>(); + for (int i = 0; i < MAX_SEARCH_HISTORY; i++) { + String h = prefs.getString("history" + i, null); + if (h == null) break; + savedHistory.add(h); + } + } + for (int i = savedHistory.size() - 1; i >= 0; i--) { + addToSearchHistory(savedHistory.get(i)); + } + addToSearchHistory(text); + setSearchText(text, true); Log.d(LOG, "Trying to restore searchText=" + text); @@ -626,6 +718,7 @@ public class DictionaryActivity extends AppCompatActivity { @Override public boolean onQueryTextSubmit(String query) { Log.d(LOG, "OnQueryTextListener: onQueryTextSubmit: " + searchView.getQuery()); + addToSearchHistory(); hideKeyboard(); return true; } @@ -639,6 +732,7 @@ public class DictionaryActivity extends AppCompatActivity { }; searchView.setOnQueryTextListener(onQueryTextListener); searchView.setFocusable(true); + searchTextView = (AutoCompleteTextView)searchView.findViewById(android.support.v7.appcompat.R.id.search_src_text); LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(0, FrameLayout.LayoutParams.WRAP_CONTENT, 1); customSearchView.addView(searchView, lp); @@ -692,6 +786,13 @@ public class DictionaryActivity extends AppCompatActivity { prefs.commit(); } + @Override + protected void onPause() { + super.onPause(); + addToSearchHistory(); + saveSearchHistory(); + } + @Override protected void onDestroy() { super.onDestroy(); @@ -739,14 +840,23 @@ public class DictionaryActivity extends AppCompatActivity { Log.d(LOG, "Trying to show soft keyboard."); final boolean searchTextHadFocus = searchView.hasFocus(); searchView.requestFocusFromTouch(); + searchTextView.requestFocus(); final InputMethodManager manager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); manager.showSoftInput(searchView, InputMethodManager.SHOW_IMPLICIT); + manager.showSoftInput(searchTextView, InputMethodManager.SHOW_IMPLICIT); if (!searchTextHadFocus) { defocusSearchText(); } } }, delay); } + searchView.post(new Runnable() { + @Override + public void run() { + searchTextView.setThreshold(0); + searchTextView.showDropDown(); + } + }); } private void hideKeyboard() { @@ -794,6 +904,7 @@ public class DictionaryActivity extends AppCompatActivity { searchView.requestFocus(); } if (searchView.getQuery().toString().length() > 0) { + addToSearchHistory(); searchView.setQuery("", false); } showKeyboard(); @@ -843,7 +954,7 @@ public class DictionaryActivity extends AppCompatActivity { final LinearLayout result = new LinearLayout(parent.getContext()); - for (int i = 0; dictionaryInfo.indexInfos != null && i < dictionaryInfo.indexInfos.size(); ++i) { + for (int i = 0; i < dictionaryInfo.indexInfos.size(); ++i) { final IndexInfo indexInfo = dictionaryInfo.indexInfos.get(i); final View button = IsoUtils.INSTANCE.createButton(parent.getContext(), indexInfo, application.languageButtonPixels); @@ -1195,6 +1306,7 @@ public class DictionaryActivity extends AppCompatActivity { @Override public void run() { setIndexAndSearchText(actualIndexToUse, selectedText, true); + addToSearchHistory(selectedText); } }, 100); } @@ -1240,13 +1352,14 @@ public class DictionaryActivity extends AppCompatActivity { try { wordList.getParentFile().mkdirs(); final PrintWriter out = new PrintWriter(new FileWriter(wordList, true)); - out.println(rawText.toString()); + out.println(rawText); out.close(); } catch (Exception e) { Log.e(LOG, "Unable to append to " + wordList.getAbsolutePath(), e); - Toast.makeText(this, - getString(R.string.failedAddingToWordList, wordList.getAbsolutePath()), - Toast.LENGTH_LONG).show(); + if (!isFinishing()) + Toast.makeText(this, + getString(R.string.failedAddingToWordList, wordList.getAbsolutePath()), + Toast.LENGTH_LONG).show(); } } @@ -1281,7 +1394,7 @@ public class DictionaryActivity extends AppCompatActivity { Log.d(LOG, "Trying to hide soft keyboard."); final InputMethodManager inputManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); View focus = getCurrentFocus(); - if (focus != null) { + if (inputManager != null && focus != null) { inputManager.hideSoftInputFromWindow(focus.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); } @@ -1347,7 +1460,9 @@ public class DictionaryActivity extends AppCompatActivity { Log.d(LOG, "searchFinished: " + searchOperation + ", searchResult=" + searchResult); currentSearchOperation = null; - uiHandler.postDelayed(new Runnable() { + // Note: it's important to post to the ListView, otherwise + // the jumpToRow will randomly not work. + getListView().post(new Runnable() { @Override public void run() { if (currentSearchOperation == null) { @@ -1366,10 +1481,10 @@ public class DictionaryActivity extends AppCompatActivity { Log.d(LOG, "More coming, waiting for currentSearchOperation."); } } - }, 20); + }); } - private final void jumpToRow(final int row) { + private void jumpToRow(final int row) { Log.d(LOG, "jumpToRow: " + row + ", refocusSearchText=" + false); // getListView().requestFocusFromTouch(); getListView().setSelectionFromTop(row, 0); @@ -1402,7 +1517,7 @@ public class DictionaryActivity extends AppCompatActivity { } public String toString() { - return String.format("SearchOperation(%s,%s)", searchText, interrupted.toString()); + return String.format("SearchOperation(%s,%s)", searchText, interrupted); } @Override @@ -1432,7 +1547,7 @@ public class DictionaryActivity extends AppCompatActivity { Log.d(LOG, "interrupted, skipping searchFinished."); } } catch (Exception e) { - Log.e(LOG, "Failure during search (can happen during Activity close."); + Log.e(LOG, "Failure during search (can happen during Activity close): " + e.getMessage()); } finally { synchronized (this) { done = true; @@ -1448,10 +1563,16 @@ public class DictionaryActivity extends AppCompatActivity { private void showHtml(final List htmlEntries, final String htmlTextToHighlight) { String html = HtmlEntry.htmlBody(htmlEntries, index.shortName); + String style = ""; + if (typeface == Typeface.SERIF) { style = "font-family: serif;"; } + else if (typeface == Typeface.SANS_SERIF) { style = "font-family: sans-serif;"; } + else if (typeface == Typeface.MONOSPACE) { style = "font-family: monospace;"; } + if (application.getSelectedTheme() == DictionaryApplication.Theme.DEFAULT) + style += "background-color: black; color: white;"; // Log.d(LOG, "html=" + html); startActivityForResult( HtmlDisplayActivity.getHtmlIntent(getApplicationContext(), String.format( - "%s", html), + "%s", style, html), htmlTextToHighlight, false), 0); } @@ -1497,7 +1618,7 @@ public class DictionaryActivity extends AppCompatActivity { DisplayMetrics dm = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(dm); scale = dm.density; - } catch (NullPointerException e) + } catch (NullPointerException ignored) {} // Convert the dps to pixels, based on density scale mPaddingDefault = (int) (PADDING_DEFAULT_DP * scale + 0.5f); @@ -1600,19 +1721,6 @@ public class DictionaryActivity extends AppCompatActivity { col1.setTextColor(textColorFg); col2.setTextColor(textColorFg); - // Set the columns in the table. - if (r > 0) { - final TextView bullet = new TextView(tableRow.getContext()); - bullet.setText(" •"); - tableRow.addView(bullet); - } - tableRow.addView(col1, layoutParams); - if (r > 0) { - final TextView bullet = new TextView(tableRow.getContext()); - bullet.setText(" •"); - tableRow.addView(bullet); - } - tableRow.addView(col2, layoutParams); col1.setWidth(1); col2.setWidth(1); @@ -1630,13 +1738,37 @@ public class DictionaryActivity extends AppCompatActivity { col2.setOnLongClickListener(textViewLongClickListenerIndex1); } + // Set the columns in the table. + if (r == 0) { + tableRow.addView(col1, layoutParams); + tableRow.addView(col2, layoutParams); + } else { + for (int i = 0; i < 2; i++) { + final TextView bullet = new TextView(tableRow.getContext()); + bullet.setText(" • "); + LinearLayout wrapped = new LinearLayout(context); + wrapped.setOrientation(LinearLayout.HORIZONTAL); + LinearLayout.LayoutParams p1 = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT, 0); + wrapped.addView(bullet, p1); + LinearLayout.LayoutParams p2 = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT, 1); + wrapped.addView(i == 0 ? col1 : col2, p2); + tableRow.addView(wrapped, layoutParams); + } + } + result.addView(tableRow); } for (int r = 0; r < rowCount; ++r) { final TableRow tableRow = (TableRow)result.getChildAt(r); - final TextView col1 = (TextView)tableRow.getChildAt(r == 0 ? 0 : 1); - final TextView col2 = (TextView)tableRow.getChildAt(r == 0 ? 1 : 3); + View left = tableRow.getChildAt(0); + View right = tableRow.getChildAt(1); + if (r > 0) { + left = ((ViewGroup)left).getChildAt(1); + right = ((ViewGroup)right).getChildAt(1); + } + final TextView col1 = (TextView)left; + final TextView col2 = (TextView)right; // Set what's in the columns. final Pair pair = entry.pairs.get(r); @@ -1831,6 +1963,8 @@ public class DictionaryActivity extends AppCompatActivity { currentSearchOperation = new SearchOperation(text, index); searchExecutor.execute(currentSearchOperation); ((FloatingActionButton)findViewById(R.id.floatSearchButton)).setImageResource(text.length() > 0 ? R.drawable.ic_clear_black_24dp : R.drawable.ic_search_black_24dp); + searchView.getSuggestionsAdapter().swapCursor(text.isEmpty() ? searchHistoryCursor : null); + searchView.getSuggestionsAdapter().notifyDataSetChanged(); } // --------------------------------------------------------------------------