package de.danoeh.antennapod.fragment;
import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.SearchView;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.ListView;
import java.util.List;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.adapter.SearchlistAdapter;
import de.danoeh.antennapod.core.feed.EventDistributor;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedComponent;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.SearchResult;
import de.danoeh.antennapod.core.storage.FeedSearcher;
import rx.Observable;
import rx.Subscription;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;
/**
* Performs a search operation on all feeds or one specific feed and displays the search result.
*/
public class SearchFragment extends ListFragment {
private static final String TAG = "SearchFragment";
private static final String ARG_QUERY = "query";
private static final String ARG_FEED = "feed";
private SearchlistAdapter searchAdapter;
private List<SearchResult> searchResults;
private boolean viewCreated = false;
private boolean itemsLoaded = false;
private Subscription subscription;
/**
* Create a new SearchFragment that searches all feeds.
*/
public static SearchFragment newInstance(String query) {
if (query == null) query = "";
SearchFragment fragment = new SearchFragment();
Bundle args = new Bundle();
args.putString(ARG_QUERY, query);
args.putLong(ARG_FEED, 0);
fragment.setArguments(args);
return fragment;
}
/**
* Create a new SearchFragment that searches one specific feed.
*/
public static SearchFragment newInstance(String query, long feed) {
SearchFragment fragment = newInstance(query);
fragment.getArguments().putLong(ARG_FEED, feed);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
setHasOptionsMenu(true);
search();
}
@Override
public void onStart() {
super.onStart();
EventDistributor.getInstance().register(contentUpdate);
}
@Override
public void onStop() {
super.onStop();
if(subscription != null) {
subscription.unsubscribe();
}
EventDistributor.getInstance().unregister(contentUpdate);
}
@Override
public void onDetach() {
super.onDetach();
if(subscription != null) {
subscription.unsubscribe();
}
}
@Override
public void onDestroyView() {
super.onDestroyView();
searchAdapter = null;
viewCreated = false;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
// add padding
final ListView lv = getListView();
lv.setClipToPadding(false);
final int vertPadding = getResources().getDimensionPixelSize(R.dimen.list_vertical_padding);
lv.setPadding(0, vertPadding, 0, vertPadding);
((AppCompatActivity) getActivity()).getSupportActionBar().setTitle(R.string.search_label);
viewCreated = true;
if (itemsLoaded) {
onFragmentLoaded();
}
}
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
SearchResult result = (SearchResult) l.getAdapter().getItem(position);
FeedComponent comp = result.getComponent();
if (comp.getClass() == Feed.class) {
((MainActivity) getActivity()).loadFeedFragmentById(comp.getId(), null);
} else {
if (comp.getClass() == FeedItem.class) {
FeedItem item = (FeedItem) comp;
((MainActivity) getActivity()).loadChildFragment(ItemFragment.newInstance(item.getId()));
}
}
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
if (itemsLoaded) {
MenuItem item = menu.add(Menu.NONE, R.id.search_item, Menu.NONE, R.string.search_label);
MenuItemCompat.setShowAsAction(item, MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);
final SearchView sv = new SearchView(getActivity());
sv.setQueryHint(getString(R.string.search_hint));
sv.setQuery(getArguments().getString(ARG_QUERY), false);
sv.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String s) {
getArguments().putString(ARG_QUERY, s);
itemsLoaded = false;
search();
return true;
}
@Override
public boolean onQueryTextChange(String s) {
return false;
}
});
MenuItemCompat.setActionView(item, sv);
}
}
private final EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
@Override
public void update(EventDistributor eventDistributor, Integer arg) {
if ((arg & (EventDistributor.UNREAD_ITEMS_UPDATE
| EventDistributor.DOWNLOAD_HANDLED)) != 0) {
search();
}
}
};
private void onFragmentLoaded() {
if (searchAdapter == null) {
searchAdapter = new SearchlistAdapter(getActivity(), itemAccess);
setListAdapter(searchAdapter);
}
searchAdapter.notifyDataSetChanged();
setListShown(true);
}
private final SearchlistAdapter.ItemAccess itemAccess = new SearchlistAdapter.ItemAccess() {
@Override
public int getCount() {
return (searchResults != null) ? searchResults.size() : 0;
}
@Override
public SearchResult getItem(int position) {
if (searchResults != null && 0 <= position && position < searchResults.size()) {
return searchResults.get(position);
} else {
return null;
}
}
};
private void search() {
if(subscription != null) {
subscription.unsubscribe();
}
if (viewCreated && !itemsLoaded) {
setListShown(false);
}
subscription = Observable.fromCallable(this::performSearch)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
if (result != null) {
itemsLoaded = true;
searchResults = result;
if (viewCreated) {
onFragmentLoaded();
}
}
}, error -> {
Log.e(TAG, Log.getStackTraceString(error));
});
}
private List<SearchResult> performSearch() {
Bundle args = getArguments();
String query = args.getString(ARG_QUERY);
long feed = args.getLong(ARG_FEED);
Context context = getActivity();
return FeedSearcher.performSearch(context, query, feed);
}
}