package au.com.newint.newinternationalist;
import android.app.ProgressDialog;
import android.app.SearchManager;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.AsyncTask;
import android.support.v7.app.ActionBarActivity;
import android.support.v4.app.Fragment;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.text.Html;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import org.w3c.dom.Text;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class SearchActivity extends ActionBarActivity {
static String searchQuery;
static ArrayList<Issue> issuesArray;
static ArrayList<ArrayList<Article>> filteredIssueArticlesArray;
static ProgressDialog loadingProgressDialog;
static Intent intent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search);
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container, new SearchFragment())
.commit();
}
intent = getIntent();
searchQuery = intent.getStringExtra(SearchManager.QUERY);
// Set the activity title
setTitle("Results for: " + searchQuery);
// Send Google Analytics if the user allows it
Helpers.sendGoogleAnalytics("Search: " + searchQuery);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_search, menu);
// Get the SearchView and set the searchable configuration
SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
android.support.v7.widget.SearchView searchView = (android.support.v7.widget.SearchView) menu.findItem(R.id.action_search).getActionView();
// Assumes current activity is the searchable activity
searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
searchView.setIconifiedByDefault(false); // Do not iconify the widget; expand it by default
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
switch (item.getItemId()) {
case R.id.action_settings:
// Helpers.debugLog("Menu", "Settings pressed.");
// Settings intent
Intent settingsIntent = new Intent(this, SettingsActivity.class);
startActivity(settingsIntent);
return true;
case R.id.about:
// Helpers.debugLog("Menu", "About pressed.");
// About intent
Intent aboutIntent = new Intent(this, AboutActivity.class);
startActivity(aboutIntent);
return true;
case R.id.action_search:
Helpers.debugLog("Search", "Search tapped on Home view.");
// onSearchRequested();
default:
return super.onOptionsItemSelected(item);
}
}
/**
* A placeholder fragment containing a simple view.
*/
public static class SearchFragment extends Fragment {
public SearchFragment() {
}
static View rootView = null;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.fragment_search, container, false);
// Recycler view search results as cards and headers
final RecyclerView recList = (RecyclerView) rootView.findViewById(R.id.search_results_card_list);
recList.setHasFixedSize(true);
LinearLayoutManager llm = new LinearLayoutManager(rootView.getContext());
llm.setOrientation(LinearLayoutManager.VERTICAL);
recList.setLayoutManager(llm);
final SearchAdapter adapter = new SearchAdapter();
recList.setAdapter(adapter);
return rootView;
}
// Adapter for CardView
public class SearchAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
public ArrayList<Object> listElements;
public Issue issue;
private static final int TYPE_HEADER = 0;
private static final int TYPE_ARTICLE = 1;
public SearchAdapter() {
listElements = new ArrayList<>();
// Set a loading indicator going
loadingProgressDialog = new ProgressDialog(getActivity());
loadingProgressDialog.setTitle(getResources().getString(R.string.search_loading_progress_title));
loadingProgressDialog.setMessage(getResources().getString(R.string.search_loading_progress_message));
loadingProgressDialog.show();
// Perform the serach in an AsyncTask
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
// Build up the issuesArray
issuesArray = Publisher.INSTANCE.getIssuesFromFilesystem();
// Get the intent, verify the action and get the query
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
// Perform the search
filterArticlesForSearchQuery(searchQuery);
}
for (ArrayList<Article> articleList : filteredIssueArticlesArray) {
if (articleList.size() <= 0) {
continue;
}
Issue issue = new Issue(articleList.get(0).getIssueID());
listElements.add(issue);
for (Article article : articleList) {
listElements.add(article);
}
}
return null;
}
@Override
protected void onPostExecute(Void unused) {
// After loading finishes dismiss the loading dialog
loadingProgressDialog.dismiss();
notifyDataSetChanged();
// Show empty notice if no results
TextView emptyView = (TextView)rootView.findViewById(R.id.empty_view);
if (listElements.size() > 0) {
emptyView.setVisibility(View.GONE);
} else {
emptyView.setVisibility(View.VISIBLE);
}
}
}.execute();
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = null;
if (viewType == 0) {
// Header
itemView = LayoutInflater.
from(parent.getContext()).
inflate(R.layout.fragment_search_header, parent, false);
return new SearchHeaderViewHolder(itemView);
} else if (viewType == 1) {
// Article
itemView = LayoutInflater.
from(parent.getContext()).
inflate(R.layout.fragment_search_card_view, parent, false);
return new SearchArticleViewHolder(itemView);
} else {
// Uh oh... didn't match view type.
return null;
}
}
@Override
public int getItemCount() {
return listElements.size();
}
@Override
public int getItemViewType(int position) {
if (isPositionHeader(position)) {
return TYPE_HEADER;
}
return TYPE_ARTICLE;
}
private boolean isPositionHeader(int position) {
return listElements.get(position) instanceof Issue;
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (holder instanceof SearchHeaderViewHolder) {
// Header
issue = (Issue) listElements.get(position);
DateFormat dateFormat = new SimpleDateFormat("MMMM, yyyy", Locale.getDefault());
String issueHeaderString = Integer.toString(issue.getNumber()) + " - " + issue.getTitle() + "\n\n" + dateFormat.format(issue.getRelease());
((SearchHeaderViewHolder) holder).searchResultsHeader.setText(issueHeaderString);
// Set cover image
final ImageView coverImageView = ((SearchHeaderViewHolder) holder).issueCoverImageView;
// Set the loading cover for recycled views
// Bitmap defaultCoverBitmap = BitmapFactory.decodeResource(MainActivity.applicationContext.getResources(), R.drawable.home_cover);
// coverImageView.setImageBitmap(defaultCoverBitmap);
issue.getCoverCacheStreamFactoryForSize((int) getResources().getDimension(R.dimen.search_results_cover_width)).preload(new CacheStreamFactory.CachePreloadCallback() {
@Override
public void onLoad(byte[] payload) {
Bitmap coverBitmap = Helpers.bitmapDecode(payload);
coverImageView.setImageBitmap(coverBitmap);
}
@Override
public void onLoadBackground(byte[] payload) {
}
});
} else if (holder instanceof SearchArticleViewHolder) {
// Article
Article article = (Article) listElements.get(position);
SearchArticleViewHolder searchArticleViewHolder = ((SearchArticleViewHolder) holder);
searchArticleViewHolder.articleTitleTextView.setText(article.getTitle());
String articleTeaser = article.getTeaser();
if (articleTeaser != null && !articleTeaser.isEmpty()) {
searchArticleViewHolder.articleTeaserTextView.setVisibility(View.VISIBLE);
searchArticleViewHolder.articleTeaserTextView.setText(Html.fromHtml(articleTeaser));
} else {
// Remove teaser view.
searchArticleViewHolder.articleTeaserTextView.setVisibility(View.GONE);
}
ArrayList<Image> images = article.getImages();
final ImageView articleImageView = searchArticleViewHolder.articleImageView;
if (images.size() > 0) {
images.get(0).getImageCacheStreamFactoryForSize(MainActivity.applicationContext.getResources().getDisplayMetrics().widthPixels).preload(new CacheStreamFactory.CachePreloadCallback() {
@Override
public void onLoad(byte[] payload) {
if (payload != null && payload.length > 0) {
Bitmap coverBitmap = Helpers.bitmapDecode(payload);
articleImageView.setImageBitmap(coverBitmap);
}
}
@Override
public void onLoadBackground(byte[] payload) {
}
});
} else {
articleImageView.setVisibility(View.GONE);
}
}
}
public class SearchArticleViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public TextView articleTitleTextView;
public TextView articleTeaserTextView;
public ImageView articleImageView;
public SearchArticleViewHolder(View itemView) {
super(itemView);
articleTitleTextView = (TextView) itemView.findViewById(R.id.search_article_title);
articleTeaserTextView = (TextView) itemView.findViewById(R.id.search_article_teaser);
articleImageView = (ImageView) itemView.findViewById(R.id.search_article_image);
itemView.setOnClickListener(this);
}
@Override
public void onClick(View v) {
// Toast.makeText(MainActivity.applicationContext, "View clicked at position: " + getPosition(), Toast.LENGTH_SHORT).show();
Intent articleIntent = new Intent(MainActivity.applicationContext, ArticleActivity.class);
// Pass issue through as a Parcel
if (listElements.get(getPosition()) instanceof Article) {
Article articleTapped = (Article) listElements.get(getPosition());
Issue articleTappedIssue = new Issue(articleTapped.getIssueID());
articleIntent.putExtra("article", articleTapped);
articleIntent.putExtra("issue", articleTappedIssue);
}
startActivity(articleIntent);
}
}
public class SearchHeaderViewHolder extends RecyclerView.ViewHolder {
public ImageView issueCoverImageView;
public TextView searchResultsHeader;
public SearchHeaderViewHolder(View itemView) {
super(itemView);
issueCoverImageView = (ImageView) itemView.findViewById(R.id.search_results_cover);
searchResultsHeader = (TextView) itemView.findViewById(R.id.search_results_header);
}
}
}
}
// Search logic
static public void filterArticlesForSearchQuery(String query) {
// Helpers.debugLog("Search", "Search for " + query);
// This is an AND search by default.
// Split the search terms so they can be searched without being in sequence
ArrayList<String> quotedTerms = new ArrayList<String>();
Pattern regex = Pattern.compile("[^\\s\"']+|\"([^\"]*)\"|'([^']*)'");
Matcher regexMatcher = regex.matcher(query);
while (regexMatcher.find()) {
if (regexMatcher.group(1) != null) {
// Add double-quoted string without the quotes
quotedTerms.add(Pattern.quote(regexMatcher.group(1)));
} else if (regexMatcher.group(2) != null) {
// Add single-quoted string without the quotes
quotedTerms.add(Pattern.quote(regexMatcher.group(2)));
} else {
// Add unquoted word
quotedTerms.add(Pattern.quote(regexMatcher.group()));
}
}
filteredIssueArticlesArray = new ArrayList<>();
for (Issue issue : issuesArray) {
filteredIssueArticlesArray.add(issue.getArticles());
}
for (String term : quotedTerms) {
filteredIssueArticlesArray = filterArticleList(term, filteredIssueArticlesArray);
}
}
static ArrayList<ArrayList<Article>> filterArticleList(String searchTerm, ArrayList<ArrayList<Article>> arrayOfArticleArrays) {
ArrayList<ArrayList<Article>> filteredArrayOfArticleArrays = new ArrayList<>();
// Create a pattern to match
Pattern pattern = Pattern.compile(searchTerm, Pattern.CASE_INSENSITIVE);
// Helpers.debugLog("Search", pattern.toString());
for (ArrayList<Article> articlesArray : arrayOfArticleArrays) {
ArrayList <Article> filteredArticles = new ArrayList<Article>();
for (Article article : articlesArray) {
// Search title
Matcher titleMatcher = pattern.matcher(article.getTitle());
if (titleMatcher.find()) {
filteredArticles.add(article);
} else {
// Search teaser
Matcher teaserMatcher = pattern.matcher(article.getTeaser());
if (teaserMatcher.find()) {
filteredArticles.add(article);
} else {
// Search the body if it exists on file
if (article.isBodyOnFilesystem()) {
Matcher bodyMatcher = pattern.matcher(article.getExpandedBody(null));
if (bodyMatcher.find()) {
filteredArticles.add(article);
}
}
}
}
}
if (filteredArticles.size() > 0) {
filteredArrayOfArticleArrays.add(filteredArticles);
}
}
return filteredArrayOfArticleArrays;
}
}