package yuku.alkitab.base.ac;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.SystemClock;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.design.widget.Snackbar;
import android.support.v4.content.res.ResourcesCompat;
import android.support.v4.graphics.ColorUtils;
import android.support.v4.widget.CursorAdapter;
import android.support.v7.app.ActionBar;
import android.support.v7.view.ActionMode;
import android.support.v7.widget.SearchView;
import android.support.v7.widget.Toolbar;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.style.ForegroundColorSpan;
import android.text.style.UnderlineSpan;
import android.util.SparseBooleanArray;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.AutoCompleteTextView;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.ListView;
import android.widget.TextView;
import com.afollestad.materialdialogs.MaterialDialog;
import yuku.afw.V;
import yuku.afw.storage.Preferences;
import yuku.afw.widget.EasyAdapter;
import yuku.alkitab.base.App;
import yuku.alkitab.base.S;
import yuku.alkitab.base.U;
import yuku.alkitab.base.ac.base.BaseActivity;
import yuku.alkitab.base.model.MVersionInternal;
import yuku.alkitab.base.storage.Prefkey;
import yuku.alkitab.base.util.Appearances;
import yuku.alkitab.base.util.Jumper;
import yuku.alkitab.base.util.QueryTokenizer;
import yuku.alkitab.base.util.SearchEngine;
import yuku.alkitab.debug.BuildConfig;
import yuku.alkitab.debug.R;
import yuku.alkitab.model.Book;
import yuku.alkitab.model.Version;
import yuku.alkitab.util.Ari;
import yuku.alkitab.util.IntArrayList;
import yuku.alkitabintegration.display.Launcher;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static yuku.alkitab.base.util.Literals.Array;
public class SearchActivity extends BaseActivity {
public static final String TAG = SearchActivity.class.getSimpleName();
private static final String EXTRA_openedBookId = "openedBookId";
private static int REQCODE_bookFilter = 1;
private static final long ID_CLEAR_HISTORY = -1L;
private static final int COLINDEX_ID = 0;
private static final int COLINDEX_QUERY_STRING = 1;
View root;
TextView bVersion;
SearchView searchView;
ListView lsSearchResults;
TextView tSearchTips;
View panelFilter;
CheckBox cFilterOlds;
CheckBox cFilterNews;
CheckBox cFilterSingleBook;
TextView tFilterAdvanced;
View bEditFilter;
int hiliteColor;
SparseBooleanArray selectedBookIds = new SparseBooleanArray();
int openedBookId;
int filterUserAction = 0; // when it's not user action, set to nonzero
SearchAdapter adapter;
Version searchInVersion;
String searchInVersionId;
float textSizeMult;
SearchHistoryAdapter searchHistoryAdapter;
ActionMode actionMode;
final AdapterView.OnItemLongClickListener lsSearchResults_itemLongClick = (parent, view, position, id) -> {
if (actionMode == null) {
actionMode = startSupportActionMode(new ActionMode.Callback() {
@Override
public boolean onCreateActionMode(final ActionMode mode, final Menu menu) {
getMenuInflater().inflate(R.menu.context_search, menu);
return true;
}
@Override
public boolean onPrepareActionMode(final ActionMode mode, final Menu menu) {
final int checked_count = lsSearchResults.getCheckedItemCount();
if (checked_count == 1) {
mode.setTitle(R.string.verse_select_one_verse_selected);
} else {
mode.setTitle(getString(R.string.verse_select_multiple_verse_selected, checked_count));
}
return true;
}
@Override
public boolean onActionItemClicked(final ActionMode mode, final MenuItem item) {
final int itemId = item.getItemId();
if (itemId == R.id.menuSelectAll) {
for (int i = 0, size = adapter.getCount(); i < size; i++) {
lsSearchResults.setItemChecked(i, true);
}
onCheckedVerseChanged();
} else if (itemId == R.id.menuCopy) {
final SpannableStringBuilder sb = new SpannableStringBuilder();
final IntArrayList aris = adapter.getSearchResults();
final SparseBooleanArray checkeds = lsSearchResults.getCheckedItemPositions();
for (int i = 0, size = checkeds.size(); i < size; i++) {
if (!checkeds.valueAt(i)) continue;
final int position = checkeds.keyAt(i);
final int ari = aris.get(position);
final String reference = searchInVersion.reference(ari);
final String verseText = U.removeSpecialCodes(searchInVersion.loadVerseText(ari));
final int sb_len = sb.length();
sb.append(reference).append("\n").append(verseText).append("\n\n");
if (size < 1000) { // too much spans is very slow
sb.setSpan(new UnderlineSpan(), sb_len, sb_len + reference.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
U.copyToClipboard(sb);
Snackbar.make(root, R.string.search_selected_verse_copied, Snackbar.LENGTH_SHORT).show();
mode.finish();
return true;
}
return false;
}
@Override
public void onDestroyActionMode(final ActionMode mode) {
uncheckAllVerses();
actionMode = null;
}
});
}
final boolean old = lsSearchResults.isItemChecked(position);
lsSearchResults.setItemChecked(position, !old);
onCheckedVerseChanged();
return true;
};
private void uncheckAllVerses() {
final SparseBooleanArray checkeds = lsSearchResults.getCheckedItemPositions();
for (int i = checkeds.size() - 1; i >= 0; i--) {
if (checkeds.valueAt(i)) lsSearchResults.setItemChecked(checkeds.keyAt(i), false);
}
}
private void onCheckedVerseChanged() {
adapter.notifyDataSetChanged();
if (actionMode != null) {
if (lsSearchResults.getCheckedItemCount() == 0) {
actionMode.finish();
} else {
actionMode.invalidate();
}
}
}
static class SearchHistory {
public static class Entry {
public String query_string;
}
public List<Entry> entries = new ArrayList<>();
}
class SearchHistoryAdapter extends CursorAdapter {
List<SearchHistory.Entry> entries = new ArrayList<>();
String query_string;
public SearchHistoryAdapter() {
super(App.context, null, 0);
}
@Override
public View newView(final Context context, final Cursor cursor, final ViewGroup parent) {
return getLayoutInflater().inflate(android.R.layout.simple_list_item_1, parent, false);
}
@Override
public void bindView(final View view, final Context context, final Cursor cursor) {
final TextView text1 = V.get(view, android.R.id.text1);
final long _id = cursor.getLong(COLINDEX_ID);
final CharSequence text;
if (_id == -1) {
final SpannableStringBuilder sb = new SpannableStringBuilder(getString(R.string.search_clear_history));
sb.setSpan(new ForegroundColorSpan(ResourcesCompat.getColor(getResources(), R.color.escape, getTheme())), 0, sb.length(), 0);
text = sb;
} else {
text = cursor.getString(COLINDEX_QUERY_STRING);
}
text1.setText(text);
}
@Override
public CharSequence convertToString(final Cursor cursor) {
return cursor.getString(COLINDEX_QUERY_STRING);
}
public void setData(@NonNull final SearchHistory searchHistory) {
entries.clear();
entries.addAll(searchHistory.entries);
filter();
}
public void setQuery(final String query_string) {
this.query_string = query_string;
filter();
}
private void filter() {
final MatrixCursor mc = new MatrixCursor(Array("_id", "query_string") /* Can be any string, but this must correspond to COLINDEX_ID and COLINDEX_QUERY_STRING */);
for (int i = 0; i < entries.size(); i++) {
final SearchHistory.Entry entry = entries.get(i);
if (TextUtils.isEmpty(query_string) || entry.query_string.toLowerCase().startsWith(query_string.toLowerCase())) {
mc.addRow(Array((long) i, entry.query_string));
}
}
// add last item to clear search history only if there is something else
if (mc.getCount() > 0) {
mc.addRow(Array(ID_CLEAR_HISTORY, ""));
}
// sometimes this is called from bg. So we need to make sure this is run on UI thread.
runOnUiThread(() -> swapCursor(mc));
}
}
public static Intent createIntent(int openedBookId) {
Intent res = new Intent(App.context, SearchActivity.class);
res.putExtra(EXTRA_openedBookId, openedBookId);
return res;
}
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search);
root = V.get(this, R.id.root);
lsSearchResults = V.get(this, R.id.lsSearchResults);
tSearchTips = V.get(this, R.id.tSearchTips);
panelFilter = V.get(this, R.id.panelFilter);
cFilterOlds = V.get(this, R.id.cFilterOlds);
cFilterNews = V.get(this, R.id.cFilterNews);
cFilterSingleBook = V.get(this, R.id.cFilterSingleBook);
tFilterAdvanced = V.get(this, R.id.tFilterAdvanced);
bEditFilter = V.get(this, R.id.bEditFilter);
final Toolbar toolbar = V.get(this, R.id.toolbar);
setSupportActionBar(toolbar);
final ActionBar ab = getSupportActionBar();
assert ab != null;
ab.setDisplayHomeAsUpEnabled(true);
bVersion = V.get(this, R.id.bVersion);
searchInVersion = S.activeVersion;
searchInVersionId = S.activeVersionId;
textSizeMult = S.getDb().getPerVersionSettings(searchInVersionId).fontSizeMultiplier;
bVersion.setOnClickListener(bVersion_click);
searchView = V.get(SearchActivity.this, R.id.searchView);
searchView.setSubmitButtonEnabled(true);
final AutoCompleteTextView autoCompleteTextView = findAutoCompleteTextView(searchView);
if (autoCompleteTextView != null) {
autoCompleteTextView.setThreshold(0);
}
searchView.setSuggestionsAdapter(searchHistoryAdapter = new SearchHistoryAdapter());
searchView.setOnSuggestionListener(new SearchView.OnSuggestionListener() {
@Override
public boolean onSuggestionSelect(final int position) {
return false;
}
@Override
public boolean onSuggestionClick(final int position) {
final Cursor c = searchHistoryAdapter.getCursor();
if (c == null) return false;
final boolean ok = c.moveToPosition(position);
if (!ok) return false;
final long _id = c.getLong(COLINDEX_ID);
if (_id == ID_CLEAR_HISTORY) {
saveSearchHistory(null);
searchHistoryAdapter.setData(loadSearchHistory());
} else {
searchView.setQuery(c.getString(COLINDEX_QUERY_STRING), true);
}
return true;
}
});
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query1) {
search(query1);
return true;
}
@Override
public boolean onQueryTextChange(String newText) {
searchHistoryAdapter.setQuery(newText);
return false;
}
});
// stop opening suggestion dropdown
searchView.post(() -> {
final AutoCompleteTextView searchEditText = findAutoCompleteTextViewRecursive(searchView);
if (searchEditText != null) {
searchEditText.dismissDropDown();
}
});
{
SpannableStringBuilder sb = new SpannableStringBuilder(tSearchTips.getText());
while (true) {
final int pos = TextUtils.indexOf(sb, "[q]");
if (pos < 0) break;
sb.replace(pos, pos + 3, "\"");
}
tSearchTips.setText(sb);
}
tSearchTips.setBackgroundColor(S.applied.backgroundColor);
lsSearchResults.setBackgroundColor(S.applied.backgroundColor);
lsSearchResults.setCacheColorHint(S.applied.backgroundColor);
lsSearchResults.setEmptyView(tSearchTips);
Appearances.applyTextAppearance(tSearchTips, textSizeMult);
hiliteColor = U.getSearchKeywordTextColorByBrightness(S.applied.backgroundBrightness);
lsSearchResults.setChoiceMode(AbsListView.CHOICE_MODE_MULTIPLE);
lsSearchResults.setOnItemClickListener((parent, view, position, id) -> {
if (actionMode != null) {
// By default setItemChecked will be called when action mode is on.
// We just need to invalidate the view and the selected verse count.
onCheckedVerseChanged();
} else {
final int ari = adapter.getSearchResults().get(position);
startActivity(Launcher.openAppAtBibleLocationWithVerseSelected(ari));
// Because we are in CHOICE_MODE_MULTIPLE, this verse is automatically marked as checked.
// so we have to manually uncheck this.
uncheckAllVerses();
}
});
lsSearchResults.setOnItemLongClickListener(lsSearchResults_itemLongClick);
bEditFilter.setOnClickListener(v -> bEditFilter_click());
cFilterOlds.setOnCheckedChangeListener(cFilterOlds_checkedChange);
cFilterNews.setOnCheckedChangeListener(cFilterNews_checkedChange);
cFilterSingleBook.setOnCheckedChangeListener(cFilterSingleBook_checkedChange);
{
openedBookId = getIntent().getIntExtra(EXTRA_openedBookId, -1);
final Book book = S.activeVersion.getBook(openedBookId);
if (book == null) { // active version has changed somehow when this activity fainted. so, invalidate openedBookId
openedBookId = -1;
cFilterSingleBook.setEnabled(false);
} else {
cFilterSingleBook.setText(getString(R.string.search_bookname_only, book.shortName));
}
}
for (final Book book : searchInVersion.getConsecutiveBooks()) {
selectedBookIds.put(book.bookId, true);
}
configureFilterDisplayOldNewTest();
if (usingRevIndex()) {
SearchEngine.preloadRevIndex();
}
displaySearchInVersion();
}
static AutoCompleteTextView findAutoCompleteTextViewRecursive(final ViewGroup group) {
for (int i = 0; i < group.getChildCount(); i++) {
final View child = group.getChildAt(i);
if (child instanceof AutoCompleteTextView) {
return (AutoCompleteTextView) child;
}
if (child instanceof ViewGroup) {
final AutoCompleteTextView res = findAutoCompleteTextViewRecursive((ViewGroup) child);
if (res != null) {
return res;
}
}
}
return null;
}
AutoCompleteTextView findAutoCompleteTextView(ViewGroup group) {
for (int i = 0, len = group.getChildCount(); i < len; i++) {
final View child = group.getChildAt(i);
if (child instanceof AutoCompleteTextView) {
return (AutoCompleteTextView) child;
} else if (child instanceof ViewGroup) {
return findAutoCompleteTextView((ViewGroup) child);
}
}
return null;
}
@Override
protected void onStart() {
super.onStart();
searchHistoryAdapter.setData(loadSearchHistory());
}
void displaySearchInVersion() {
final String versionInitials = S.getVersionInitials(searchInVersion);
bVersion.setText(versionInitials);
searchView.setQueryHint(getString(R.string.search_in_version_short_name_placeholder, versionInitials));
if (adapter != null) {
adapter.notifyDataSetChanged();
}
}
void configureFilterDisplayOldNewTest() {
// the following variables will have value:
// if some are off and some are on -> null.
// if all on -> true.
// if all off -> false.
Boolean olds = null;
Boolean news = null;
int oneOfThemOn = -1;
{
int c_on = 0, c_off = 0;
for (int i = 0; i < 39; i++) {
boolean on = selectedBookIds.get(i, false);
if (on) c_on++; else c_off++;
}
if (c_on == 39) olds = true;
if (c_off == 39) olds = false;
}
{
int c_on = 0, c_off = 0;
for (int i = 39; i < 66; i++) {
boolean nyala = selectedBookIds.get(i, false);
if (nyala) c_on++; else c_off++;
}
if (c_on == 27) news = true;
if (c_off == 27) news = false;
}
{
int c = 0;
int k = 0;
for (int i = 0, len = selectedBookIds.size(); i < len; i++) {
if (selectedBookIds.valueAt(i)) {
k = selectedBookIds.keyAt(i);
c++;
if (c > 1) break;
}
}
if (c == 1) {
oneOfThemOn = k;
}
}
filterUserAction++; {
if (olds != null && news != null) { // both are either true or false
cFilterOlds.setVisibility(View.VISIBLE);
cFilterOlds.setChecked(olds);
cFilterNews.setVisibility(View.VISIBLE);
cFilterNews.setChecked(news);
cFilterSingleBook.setVisibility(View.VISIBLE);
cFilterSingleBook.setChecked(false);
tFilterAdvanced.setVisibility(View.GONE);
} else {
if (oneOfThemOn != -1 && oneOfThemOn == openedBookId) {
cFilterOlds.setVisibility(View.VISIBLE);
cFilterOlds.setChecked(false);
cFilterNews.setVisibility(View.VISIBLE);
cFilterNews.setChecked(false);
cFilterSingleBook.setVisibility(View.VISIBLE);
cFilterSingleBook.setChecked(true);
tFilterAdvanced.setVisibility(View.GONE);
} else {
cFilterOlds.setVisibility(View.VISIBLE);
cFilterOlds.setChecked(false);
cFilterNews.setVisibility(View.VISIBLE);
cFilterNews.setChecked(false);
cFilterSingleBook.setVisibility(View.GONE);
tFilterAdvanced.setVisibility(View.VISIBLE);
int cnt = 0;
int bookId = 0;
for (int i = 0, len = selectedBookIds.size(); i < len; i++) {
if (selectedBookIds.valueAt(i)) {
cnt++;
bookId = selectedBookIds.keyAt(i);
}
}
if (cnt != 1) {
tFilterAdvanced.setText(getString(R.string.search_filter_multiple_books_selected, cnt));
} else {
tFilterAdvanced.setText(searchInVersion.reference(bookId, 0, 0));
}
}
} filterUserAction--;
}
final String singleBookReference = searchInVersion.reference(openedBookId, 0, 0);
cFilterSingleBook.setText(getString(R.string.search_bookname_only, singleBookReference));
}
private CompoundButton.OnCheckedChangeListener cFilterOlds_checkedChange = new CompoundButton.OnCheckedChangeListener() {
@Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (filterUserAction != 0) return;
filterUserAction++; {
if (isChecked) {
cFilterSingleBook.setVisibility(View.VISIBLE);
cFilterSingleBook.setChecked(false);
tFilterAdvanced.setVisibility(View.GONE);
}
setSelectedBookIdsBasedOnFilter();
} filterUserAction--;
}
};
private CompoundButton.OnCheckedChangeListener cFilterNews_checkedChange = new CompoundButton.OnCheckedChangeListener() {
@Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (filterUserAction != 0) return;
filterUserAction++; {
if (isChecked) {
cFilterSingleBook.setVisibility(View.VISIBLE);
cFilterSingleBook.setChecked(false);
tFilterAdvanced.setVisibility(View.GONE);
}
setSelectedBookIdsBasedOnFilter();
} filterUserAction--;
}
};
private CompoundButton.OnCheckedChangeListener cFilterSingleBook_checkedChange = new CompoundButton.OnCheckedChangeListener() {
@Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (filterUserAction != 0) return;
filterUserAction++; {
if (isChecked) {
cFilterOlds.setChecked(false);
cFilterNews.setChecked(false);
}
setSelectedBookIdsBasedOnFilter();
} filterUserAction--;
}
};
final View.OnClickListener bVersion_click = v -> S.openVersionsDialog(this, false, searchInVersionId, mv -> {
final Version selectedVersion = mv.getVersion();
if (selectedVersion == null) {
new MaterialDialog.Builder(SearchActivity.this)
.content(getString(R.string.version_error_opening, mv.longName))
.positiveText(R.string.ok)
.show();
return;
}
searchInVersion = selectedVersion;
searchInVersionId = mv.getVersionId();
textSizeMult = S.getDb().getPerVersionSettings(searchInVersionId).fontSizeMultiplier;
Appearances.applyTextAppearance(tSearchTips, textSizeMult);
displaySearchInVersion();
configureFilterDisplayOldNewTest();
bVersion.setText(S.getVersionInitials(searchInVersion));
if (adapter != null) {
adapter.notifyDataSetChanged();
}
});
protected void setSelectedBookIdsBasedOnFilter() {
selectedBookIds.clear();
if (cFilterOlds.isChecked()) for (int i = 0; i < 39; i++) selectedBookIds.put(i, true);
if (cFilterNews.isChecked()) for (int i = 39; i < 66; i++) selectedBookIds.put(i, true);
if (openedBookId != -1) {
if (cFilterSingleBook.isChecked()) selectedBookIds.put(openedBookId, true);
}
}
protected SearchEngine.Query getQuery() {
SearchEngine.Query res = new SearchEngine.Query();
res.query_string = searchView.getQuery().toString();
res.bookIds = selectedBookIds;
return res;
}
public void bEditFilter_click() {
startActivityForResult(SearchBookFilterActivity.createIntent(selectedBookIds, searchInVersion.getConsecutiveBooks()), REQCODE_bookFilter);
}
@Override
protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
if (requestCode == REQCODE_bookFilter && resultCode == RESULT_OK) {
final SearchBookFilterActivity.Result result = SearchBookFilterActivity.obtainResult(data);
if (result != null) {
selectedBookIds = result.selectedBookIds;
configureFilterDisplayOldNewTest();
}
return;
}
super.onActivityResult(requestCode, resultCode, data);
}
protected void search(final String query_string) {
if (query_string.trim().length() == 0) {
return;
}
{ // check if there is anything chosen
int firstSelected = selectedBookIds.indexOfValue(true);
if (firstSelected < 0) {
new MaterialDialog.Builder(this)
.content(R.string.pilih_setidaknya_satu_kitab)
.positiveText(R.string.ok)
.show();
return;
}
}
final String[] tokens = QueryTokenizer.tokenize(query_string);
final MaterialDialog pd = new MaterialDialog.Builder(this)
.content(getString(R.string.search_searching_tokens, Arrays.toString(tokens)))
.cancelable(false)
.progress(true, 0)
.show();
new AsyncTask<Void, Void, IntArrayList>() {
boolean debugstats_revIndexUsed;
long debugstats_totalTimeMs;
long debugstats_cpuTimeMs;
@Override protected IntArrayList doInBackground(Void... params) {
searchHistoryAdapter.setData(addSearchHistoryEntry(query_string));
final long totalMs = System.currentTimeMillis();
final long cpuMs = SystemClock.currentThreadTimeMillis();
final IntArrayList res;
synchronized (SearchActivity.this) {
if (usingRevIndex()) {
debugstats_revIndexUsed = true;
res = SearchEngine.searchByRevIndex(searchInVersion, getQuery());
} else {
debugstats_revIndexUsed = false;
res = SearchEngine.searchByGrep(searchInVersion, getQuery());
}
}
debugstats_totalTimeMs = System.currentTimeMillis() - totalMs;
debugstats_cpuTimeMs = SystemClock.currentThreadTimeMillis() - cpuMs;
return res;
}
@Override protected void onPostExecute(IntArrayList result) {
if (result == null) {
result = new IntArrayList(); // empty result
}
if (actionMode != null) {
actionMode.finish();
}
uncheckAllVerses();
lsSearchResults.setAdapter(adapter = new SearchAdapter(result, tokens));
if (result.size() > 0) {
Snackbar.make(lsSearchResults, getString(R.string.size_hasil, result.size()), Snackbar.LENGTH_LONG).show();
//# close soft keyboard
InputMethodManager inputManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
inputManager.hideSoftInputFromWindow(searchView.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
searchView.clearFocus();
lsSearchResults.requestFocus();
} else {
final Jumper jumper = new Jumper(query_string);
CharSequence noresult = getText(R.string.search_no_result);
noresult = TextUtils.expandTemplate(noresult, query_string);
final int fallbackAri = shouldShowFallback(jumper);
if (fallbackAri != 0) {
final SpannableStringBuilder sb = new SpannableStringBuilder();
sb.append(noresult);
sb.append("\n\n");
CharSequence fallback = getText(R.string.search_no_result_fallback);
fallback = TextUtils.expandTemplate(fallback, searchInVersion.reference(fallbackAri));
sb.append(fallback);
tSearchTips.setText(sb);
tSearchTips.setOnClickListener(v -> {
if (Ari.toVerse(fallbackAri) == 0) {
startActivity(Launcher.openAppAtBibleLocation(fallbackAri));
} else {
startActivity(Launcher.openAppAtBibleLocationWithVerseSelected(fallbackAri));
}
});
} else {
tSearchTips.setText(noresult);
tSearchTips.setClickable(false);
tSearchTips.setOnClickListener(null);
}
}
if (BuildConfig.DEBUG) {
new MaterialDialog.Builder(SearchActivity.this)
.content("This msg is shown only on DEBUG build\n\n" +
"Search results: " + result.size() + "\n" +
"Method: " + (debugstats_revIndexUsed? "revindex": "grep") + "\n" +
"Total time: " + debugstats_totalTimeMs + " ms\n" +
"CPU (thread) time: " + debugstats_cpuTimeMs + " ms")
.positiveText(R.string.ok)
.show();
}
pd.setOnDismissListener(null);
pd.dismiss();
}
/**
* @return ari not 0 if fallback is to be shown
*/
int shouldShowFallback(final Jumper jumper) {
if (!jumper.getParseSucceeded()) {
return 0;
}
final int chapter_1 = jumper.getChapter();
if (chapter_1 == 0) return 0;
final Version version = searchInVersion;
final int bookId = jumper.getBookId(version.getConsecutiveBooks());
if (bookId == -1) return 0;
final Book book = version.getBook(bookId);
if (book == null) return 0;
if (chapter_1 > book.chapter_count) return 0;
final int verse_1 = jumper.getVerse();
if (verse_1 != 0 && verse_1 > book.verse_counts[chapter_1 - 1]) return 0;
return Ari.encode(bookId, chapter_1, verse_1);
}
}.execute();
}
@NonNull SearchHistory loadSearchHistory() {
final String json = Preferences.getString(Prefkey.searchHistory, null);
if (json == null) {
return new SearchHistory();
}
return App.getDefaultGson().fromJson(json, SearchHistory.class);
}
void saveSearchHistory(@Nullable SearchHistory sh) {
if (sh == null) {
Preferences.remove(Prefkey.searchHistory);
} else {
final String json = App.getDefaultGson().toJson(sh);
Preferences.setString(Prefkey.searchHistory, json);
}
}
// returns the modified SearchHistory
SearchHistory addSearchHistoryEntry(final String query_string) {
final SearchHistory sh = loadSearchHistory();
// look for this query_string and remove
for (int i = sh.entries.size() - 1; i >= 0; i--) {
if (U.equals(sh.entries.get(i).query_string, query_string)) {
sh.entries.remove(i);
}
}
final SearchHistory.Entry entry = new SearchHistory.Entry();
entry.query_string = query_string;
sh.entries.add(0, entry);
// if more than MAX, remove last
while (sh.entries.size() > 20) {
sh.entries.remove(sh.entries.size() - 1);
}
saveSearchHistory(sh);
return sh;
}
boolean usingRevIndex() {
return searchInVersionId == null || searchInVersionId.equals(MVersionInternal.getVersionInternalId());
}
class SearchAdapter extends EasyAdapter {
final IntArrayList searchResults;
final SearchEngine.ReadyTokens rt;
public SearchAdapter(IntArrayList searchResults, String[] tokens) {
this.searchResults = searchResults;
this.rt = tokens == null ? null : new SearchEngine.ReadyTokens(tokens);
}
@Override
public int getCount() {
return searchResults.size();
}
@Override public View newView(int position, ViewGroup parent) {
return getLayoutInflater().inflate(R.layout.item_search_result, parent, false);
}
@Override public void bindView(View view, int position, ViewGroup parent) {
final boolean checked = lsSearchResults.isItemChecked(position);
final int checkedBgColor;
final int checkedTextColor;
if (checked) {
final int colorRgb = Preferences.getInt(R.string.pref_selectedVerseBgColor_key, R.integer.pref_selectedVerseBgColor_default);
checkedBgColor = ColorUtils.setAlphaComponent(colorRgb, 0xa0);
checkedTextColor = U.getTextColorForSelectedVerse(checkedBgColor);
} else {
// no need to calculate
checkedBgColor = 0;
checkedTextColor = 0;
}
final TextView lReference = V.get(view, R.id.lReference);
final TextView lSnippet = V.get(view, R.id.lSnippet);
final int ari = searchResults.get(position);
final SpannableStringBuilder sb = new SpannableStringBuilder(searchInVersion.reference(ari));
Appearances.applySearchResultReferenceAppearance(lReference, sb, textSizeMult);
if (checked) {
lReference.setTextColor(checkedTextColor);
}
Appearances.applyTextAppearance(lSnippet, textSizeMult);
if (checked) {
lSnippet.setTextColor(checkedTextColor);
}
final String verseText = U.removeSpecialCodes(searchInVersion.loadVerseText(ari));
if (verseText != null) {
lSnippet.setText(SearchEngine.hilite(verseText, rt, checked? checkedTextColor: hiliteColor));
} else {
lSnippet.setText(R.string.generic_verse_not_available_in_this_version);
}
if (checked) {
view.setBackgroundColor(checkedBgColor);
} else {
view.setBackgroundColor(0x0);
}
}
IntArrayList getSearchResults() {
return searchResults;
}
}
}