package com.lcneves.cookme;
import android.app.ListActivity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Color;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.PowerManager;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.style.ForegroundColorSpan;
import android.view.ContextMenu;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.SearchView;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;
import android.widget.Toast;
import java.util.Locale;
public class SearchSimple extends ListActivity {
private ListActivity activity = SearchSimple.this;
ListView lv;
ProgressDialog mProgressDialog;
static String[] selIngredients;
static String recipeName;
Cursor cursor;
int displayRows;
final int DISPLAY_ROWS_INCREASE = 20;
boolean results;
boolean complex;
boolean filter;
boolean noMore;
DatabaseHelper database = new DatabaseHelper(this);
ComplexCursorAdapter adapter;
static String query;
static boolean newQuery;
View footerView;
LinearLayout filterLayout;
TextView filterTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search_simple);
filterLayout = (LinearLayout) findViewById(R.id.filter_layout);
filterTextView = (TextView) findViewById(R.id.filter_text);
filterLayout.setVisibility(View.GONE);
Intent intent = getIntent();
selIngredients = intent.getStringArrayExtra("com.lcneves.cookme.INGREDIENTS");
recipeName = intent.getStringExtra("com.lcneves.cookme.RECIPENAME");
displayRows = 0;
results = false;
complex = false;
filter = false;
noMore = false;
newQuery = false;
searchResults();
}
void searchResults() {
mProgressDialog = new ProgressDialog(SearchSimple.this);
mProgressDialog.setMessage("Searching recipes...");
mProgressDialog.setIndeterminate(true);
mProgressDialog.setIndeterminateDrawable(getResources().getDrawable(R.drawable.progress_dialog_anim));
mProgressDialog.setCancelable(false);
final SearchTask searchTask = new SearchTask(SearchSimple.this);
searchTask.execute();
}
private class SearchTask extends AsyncTask<String, Integer, String> {
private Context context;
private PowerManager.WakeLock mWakeLock;
public SearchTask(Context context) {
this.context = context;
}
@Override
protected String doInBackground(final String... args) {
displayRows = displayRows + DISPLAY_ROWS_INCREASE;
DatabaseHelper database = new DatabaseHelper(getApplicationContext());
SQLiteDatabase db = database.getWritableDatabase();
cursor = db.query(DatabaseHelper.RECIPES_TABLE,
new String[] {DatabaseHelper.REC_ID, DatabaseHelper.REC_NAME, DatabaseHelper.REC_INGREDIENTS, DatabaseHelper.REC_URL},
DatabaseHelper.createWhereClause(recipeName, selIngredients), null, null, null,
"LENGTH("+DatabaseHelper.REC_INGREDIENTS +")", Integer.toString(displayRows));
if(!(results = cursor.moveToFirst()) && selIngredients.length > 0) {
searchComplex();
results = cursor.moveToFirst();
}
return null;
}
@Override
protected void onPreExecute() {
super.onPreExecute();
// take CPU lock to prevent CPU from going off if the user
// presses the power button during download
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
getClass().getName());
mWakeLock.acquire();
mProgressDialog.show();
}
@Override
protected void onPostExecute(String result) {
mWakeLock.release();
if(results) {
if(cursor.getCount() < displayRows) noMore = true;
adapter = new ComplexCursorAdapter(activity,
R.layout.list_item_simple,
cursor,
new String[]{DatabaseHelper.REC_NAME, DatabaseHelper.REC_INGREDIENTS, DatabaseHelper.REC_URL},
new int[]{R.id.name, R.id.ingredients, R.id.url},
0);
setListAdapter(adapter);
lv = getListView();
registerForContextMenu(lv);
footerView = ((LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.simple_footer, null, false);
if(!(noMore && (complex || selIngredients.length == 0))) lv.addFooterView(footerView);
} else {
switch (selIngredients.length) {
case 0:
Toast.makeText(SearchSimple.this, "No recipes found with the name \"" + recipeName + "\"", Toast.LENGTH_LONG).show();
break;
case 1:
case 2:
StringBuilder sb = new StringBuilder("No recipes");
if (!recipeName.isEmpty()) sb.append(" for \"" + recipeName + "\"");
sb.append(" found using \"" + selIngredients[0] + "\"");
if (selIngredients.length == 2) sb.append(" and \"" + selIngredients[1] + "\"");
Toast.makeText(SearchSimple.this, sb.toString(), Toast.LENGTH_LONG).show();
break;
default:
Toast.makeText(SearchSimple.this, "No recipes found!", Toast.LENGTH_LONG).show();
}
startActivity(new Intent(SearchSimple.this, MainActivity.class));
}
mProgressDialog.dismiss();
}
}
private void searchComplex() {
complex = true;
noMore = false;
StringBuilder sb = new StringBuilder("CREATE VIEW ");
sb.append(DatabaseHelper.RESULTS_VIEW);
sb.append(" AS SELECT ");
sb.append(DatabaseHelper.RECIPES_TABLE);
sb.append(".*,Count(r._id) as CountMatches FROM (");
final String QUERY_LIKE_STUB = "SELECT " + DatabaseHelper.REC_ID + " FROM " + DatabaseHelper.RECIPES_TABLE + " WHERE ";
sb.append(QUERY_LIKE_STUB);
sb.append(DatabaseHelper.createWhereClause(recipeName, new String[] { selIngredients[0] } ));
for (int i = 1; i < selIngredients.length; ++i) {
sb.append(" UNION ALL ");
sb.append(QUERY_LIKE_STUB);
sb.append(DatabaseHelper.createWhereClause(recipeName, new String[]{selIngredients[i]}));
}
sb.append(") AS r INNER JOIN ");
sb.append(DatabaseHelper.RECIPES_TABLE);
sb.append(" ON r._id = ");
sb.append(DatabaseHelper.RECIPES_TABLE);
sb.append("._id GROUP BY r._id ORDER BY CountMatches DESC, LENGTH(");
sb.append(DatabaseHelper.REC_INGREDIENTS);
sb.append(")");
SQLiteDatabase db = database.getWritableDatabase();
db.execSQL("DROP VIEW IF EXISTS " + DatabaseHelper.RESULTS_VIEW);
db.execSQL(sb.toString());
db.close();
cursor = database.getResultsViewCursor(displayRows);
}
@Override
protected void onListItemClick(ListView l, View v, int pos, long id) {
super.onListItemClick(l, v, pos, id);
String[] recipe = new String[3];
cursor.moveToPosition(pos);
recipe[0]=cursor.getString(cursor.getColumnIndex(DatabaseHelper.REC_NAME));
recipe[1]=cursor.getString(cursor.getColumnIndex(DatabaseHelper.REC_INGREDIENTS));
recipe[2]=cursor.getString(cursor.getColumnIndex(DatabaseHelper.REC_URL));
Intent intent = new Intent(this, RecipeViewer.class);
intent.putExtra("com.lcneves.cookme.RECIPE", recipe);
startActivity(intent);
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenu.ContextMenuInfo menuInfo) {
String[] menuItems = new String[3];
menuItems[0] = "Open recipe webpage";
menuItems[1] = "Share recipe link";
menuItems[2] = "Share recipe ingredients";
for (int i = 0; i<menuItems.length; i++) {
menu.add(Menu.NONE, i, i, menuItems[i]);
}
}
@Override
public boolean onContextItemSelected(MenuItem item) {
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo)item.getMenuInfo();
int menuItemIndex = item.getItemId();
String[] recipe = new String[3];
cursor.moveToPosition(info.position);
recipe[0]=cursor.getString(cursor.getColumnIndex(DatabaseHelper.REC_NAME));
recipe[1]=cursor.getString(cursor.getColumnIndex(DatabaseHelper.REC_INGREDIENTS));
recipe[2]=cursor.getString(cursor.getColumnIndex(DatabaseHelper.REC_URL));
switch (menuItemIndex) {
case 0:
Intent intent = new Intent(this, RecipeViewer.class);
intent.putExtra("com.lcneves.cookme.RECIPE", recipe);
startActivity(intent);
break;
case 1:
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, recipe[0]+": "+recipe[2]);
sendIntent.setType("text/plain");
startActivity(Intent.createChooser(sendIntent, "Share link with..."));
break;
case 2:
Intent sendIntent2 = new Intent();
sendIntent2.setAction(Intent.ACTION_SEND);
sendIntent2.putExtra(Intent.EXTRA_TEXT, recipe[0]+":\n\n"+recipe[1]+"\n\n"+recipe[2]);
sendIntent2.setType("text/plain");
startActivity(Intent.createChooser(sendIntent2, "Share recipe with..."));
break;
}
return true;
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
if (filter) cancelFilter(null);
else {
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);
}
return true;
}
return super.onKeyDown(keyCode, event);
}
public void clickShowMore(View v) {
mProgressDialog = new ProgressDialog(this);
mProgressDialog.setMessage("Fetching more recipes...");
mProgressDialog.setIndeterminate(true);
mProgressDialog.setIndeterminateDrawable(getResources().getDrawable(R.drawable.progress_dialog_anim));
mProgressDialog.setCancelable(false);
final ShowMore showMore = new ShowMore(this);
showMore.execute();
}
private class ShowMore extends AsyncTask<String, Integer, String> {
private Context context;
public ShowMore(Context context) {
this.context = context;
}
@Override
protected String doInBackground(final String... args) {
displayRows = displayRows + DISPLAY_ROWS_INCREASE;
if(filter && complex) cursor = database.getFilterViewCursor(displayRows, query);
else if(filter && noMore) {
searchComplex();
cursor = database.getFilterViewCursor(displayRows, query);
}
else if(filter) cursor = database.getFilterSimpleCursor(recipeName, selIngredients, displayRows, query);
else if(complex) cursor = database.getResultsViewCursor(displayRows);
else if(noMore) searchComplex();
else cursor = database.getSimpleViewCursor(recipeName, selIngredients, displayRows);
cursor.moveToFirst();
if(cursor.getCount() < displayRows) noMore = true;
return null;
}
@Override
protected void onPreExecute() {
mProgressDialog.show();
}
@Override
protected void onPostExecute(String result) {
adapter.changeCursor(cursor);
adapter.notifyDataSetChanged();
if(noMore && (complex || selIngredients.length == 0) && lv.getFooterViewsCount() > 0) lv.removeFooterView(footerView);
mProgressDialog.dismiss();
}
}
public void filterResultsAction(String query) {
displayRows = newQuery ? DISPLAY_ROWS_INCREASE : displayRows + DISPLAY_ROWS_INCREASE;
mProgressDialog = new ProgressDialog(this);
mProgressDialog.setMessage("Filtering results for \""+query+"\"...");
mProgressDialog.setIndeterminate(true);
mProgressDialog.setIndeterminateDrawable(getResources().getDrawable(R.drawable.progress_dialog_anim));
mProgressDialog.setCancelable(false);
final FilterResults filterResults = new FilterResults(this);
filterResults.execute(query);
}
private class FilterResults extends AsyncTask<String, Integer, String> {
private Context context;
public FilterResults(Context context) {
this.context = context;
}
@Override
protected String doInBackground(final String... args) {
if(complex) cursor = database.getFilterViewCursor(displayRows, query);
else cursor = database.getFilterSimpleCursor(recipeName, selIngredients, displayRows, query);
results = cursor.moveToFirst();
return null;
}
@Override
protected void onPreExecute() {
mProgressDialog.show();
}
@Override
protected void onPostExecute(String result) {
mProgressDialog.dismiss();
if(results) {
filterLayout.setVisibility(View.VISIBLE);
filterTextView.setText("Filtering results for \""+query+"\"");
if(cursor.getCount() < displayRows) noMore = true;
adapter.changeCursor(cursor);
adapter.notifyDataSetChanged();
lv.setSelection(0);
filter = true;
if(lv.getFooterViewsCount() == 0 && !(noMore && (complex || selIngredients.length == 0))) lv.addFooterView(footerView);
if(lv.getFooterViewsCount() > 0 && noMore && (complex || selIngredients.length == 0)) lv.removeFooterView(footerView);
} else Toast.makeText(SearchSimple.this, "No recipes match \""+query+"\"", Toast.LENGTH_LONG).show();
}
}
public void cancelFilter(View v) {
Intent intentReload = new Intent(this, SearchSimple.class);
intentReload.putExtra("com.lcneves.cookme.INGREDIENTS", selIngredients);
intentReload.putExtra("com.lcneves.cookme.RECIPENAME", recipeName);
startActivity(intentReload);
this.finish();
}
private class ComplexCursorAdapter extends SimpleCursorAdapter {
public ComplexCursorAdapter(Context context, int layout, Cursor c,
String[] from, int[] to, int flags) {
super(context, layout, c, from, to, flags);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = super.getView(position, convertView, parent);
TextView ingredients = (TextView) view.findViewById(R.id.ingredients);
Spannable ingredientsSpan = new SpannableString(ingredients.getText());
String ingredientsSpanString = ingredientsSpan.toString().toLowerCase(Locale.ENGLISH);
for(String s : selIngredients) {
for(int j = -1; (j = ingredientsSpanString.indexOf(s.toLowerCase(Locale.ENGLISH), j + 1)) != -1;) {
ingredientsSpan.setSpan(new ForegroundColorSpan(Color.argb(208, 0, 127, 0)), j, j + s.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
ingredients.setText(ingredientsSpan, TextView.BufferType.SPANNABLE);
return view;
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.search_simple, menu);
final MenuItem searchMenuItem = menu.findItem(R.id.action_filter);
final SearchView filterSearchView = (SearchView)searchMenuItem.getActionView();
filterSearchView.setFocusable(false);
filterSearchView.setQueryHint("Filter results");
filterSearchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextChange(String newText) {
return false;
}
@Override
public boolean onQueryTextSubmit(String query) {
SearchSimple.query = query.trim();
newQuery = true;
final InputMethodManager imm = (InputMethodManager) getBaseContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(filterSearchView.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
searchMenuItem.collapseActionView();
filterSearchView.setIconified(true);
filterResultsAction(query.trim());
return true;
}
});
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
return super.onOptionsItemSelected(item);
}
public void clickAboutMenuSimple(MenuItem menu) {
MainActivity.AboutDialogFragment aboutDialog = new MainActivity.AboutDialogFragment();
aboutDialog.show(getFragmentManager(), "tag");
}
}