diff --git a/AndroidManifest.xml b/AndroidManifest.xml index ad03fc1e7..ecacd413c 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -29,6 +29,7 @@ + + + + + + + \ No newline at end of file diff --git a/res/layout/searchlist_item.xml b/res/layout/searchlist_item.xml new file mode 100644 index 000000000..13ad5d883 --- /dev/null +++ b/res/layout/searchlist_item.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/res/values/strings.xml b/res/values/strings.xml index 1c32ce086..2a00375d0 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -136,6 +136,10 @@ The import directory is empty. Select all Deselect all + Search for Feeds or Episodes + Found in:\u0020 + Found in shownotes + Found in chapters \ No newline at end of file diff --git a/res/xml/searchable.xml b/res/xml/searchable.xml new file mode 100644 index 000000000..522bd9be5 --- /dev/null +++ b/res/xml/searchable.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/de/danoeh/antennapod/AppConfig.java b/src/de/danoeh/antennapod/AppConfig.java index ab3626388..7aab19fd3 100644 --- a/src/de/danoeh/antennapod/AppConfig.java +++ b/src/de/danoeh/antennapod/AppConfig.java @@ -1,5 +1,5 @@ package de.danoeh.antennapod; public final class AppConfig { - public final static boolean DEBUG = false; + public final static boolean DEBUG = true; } diff --git a/src/de/danoeh/antennapod/activity/SearchActivity.java b/src/de/danoeh/antennapod/activity/SearchActivity.java new file mode 100644 index 000000000..9cc3b1717 --- /dev/null +++ b/src/de/danoeh/antennapod/activity/SearchActivity.java @@ -0,0 +1,70 @@ +package de.danoeh.antennapod.activity; + +import java.util.ArrayList; + +import android.annotation.SuppressLint; +import android.app.SearchManager; +import android.content.Intent; +import android.os.AsyncTask; +import android.os.Bundle; +import android.util.Log; + +import com.actionbarsherlock.app.SherlockListActivity; + +import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.adapter.SearchlistAdapter; +import de.danoeh.antennapod.feed.FeedComponent; +import de.danoeh.antennapod.feed.FeedSearcher; +import de.danoeh.antennapod.feed.SearchResult; + +public class SearchActivity extends SherlockListActivity { + private static final String TAG = "SearchActivity"; + + private SearchlistAdapter searchAdapter; + private ArrayList content; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (Intent.ACTION_SEARCH.equals(getIntent().getAction())) { + if (AppConfig.DEBUG) + Log.d(TAG, "Starting search"); + String query = getIntent().getStringExtra(SearchManager.QUERY); + startSearch(query); + } + } + + @SuppressLint({ "NewApi", "NewApi" }) + private void startSearch(String query) { + AsyncTask> executor = new AsyncTask>() { + + @Override + protected ArrayList doInBackground(String... params) { + if (AppConfig.DEBUG) + Log.d(TAG, "Starting background work"); + return FeedSearcher.performSearch(params[0]); + } + + @Override + protected void onPostExecute(ArrayList result) { + if (AppConfig.DEBUG) + Log.d(TAG, "Background work finished"); + if (AppConfig.DEBUG) + Log.d(TAG, "Found " + result.size() + " results"); + content = result; + + searchAdapter = new SearchlistAdapter(SearchActivity.this, 0, + content); + getListView().setAdapter(searchAdapter); + searchAdapter.notifyDataSetChanged(); + + } + + }; + if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) { + executor.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, query); + } else { + executor.execute(query); + } + } +} diff --git a/src/de/danoeh/antennapod/adapter/SearchlistAdapter.java b/src/de/danoeh/antennapod/adapter/SearchlistAdapter.java new file mode 100644 index 000000000..e9cb3e290 --- /dev/null +++ b/src/de/danoeh/antennapod/adapter/SearchlistAdapter.java @@ -0,0 +1,74 @@ +package de.danoeh.antennapod.adapter; + +import java.util.List; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.ImageView; +import android.widget.TextView; +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.asynctask.FeedImageLoader; +import de.danoeh.antennapod.feed.Feed; +import de.danoeh.antennapod.feed.FeedComponent; +import de.danoeh.antennapod.feed.FeedItem; +import de.danoeh.antennapod.feed.SearchResult; + +/** List adapter for search activity. */ +public class SearchlistAdapter extends ArrayAdapter { + + public SearchlistAdapter(Context context, int textViewResourceId, + List objects) { + super(context, textViewResourceId, objects); + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + Holder holder; + SearchResult result = getItem(position); + FeedComponent component = result.getComponent(); + + // Inflate Layout + if (convertView == null) { + holder = new Holder(); + LayoutInflater inflater = (LayoutInflater) getContext() + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + + convertView = inflater.inflate(R.layout.searchlist_item, null); + holder.title = (TextView) convertView.findViewById(R.id.txtvTitle); + holder.cover = (ImageView) convertView + .findViewById(R.id.imgvFeedimage); + holder.subtitle = (TextView) convertView + .findViewById(R.id.txtvSubtitle); + + convertView.setTag(holder); + } else { + holder = (Holder) convertView.getTag(); + } + if (component.getClass() == Feed.class) { + Feed feed = (Feed) component; + holder.title.setText(feed.getTitle()); + holder.subtitle.setVisibility(View.GONE); + FeedImageLoader.getInstance().loadBitmap(feed.getImage(), + holder.cover); + + } else if (component.getClass() == FeedItem.class) { + FeedItem item = (FeedItem) component; + holder.title.setText(item.getTitle()); + holder.subtitle.setVisibility(View.VISIBLE); + holder.subtitle.setText(result.getSubtitle()); + FeedImageLoader.getInstance().loadBitmap(item.getFeed().getImage(), + holder.cover); } + + return convertView; + } + + static class Holder { + ImageView cover; + TextView title; + TextView subtitle; + } + +} diff --git a/src/de/danoeh/antennapod/feed/FeedSearcher.java b/src/de/danoeh/antennapod/feed/FeedSearcher.java new file mode 100644 index 000000000..ff9f5a4c8 --- /dev/null +++ b/src/de/danoeh/antennapod/feed/FeedSearcher.java @@ -0,0 +1,113 @@ +package de.danoeh.antennapod.feed; + +import java.util.ArrayList; + +import android.util.Log; + +import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.PodcastApp; +import de.danoeh.antennapod.R; + +/** Performs search on Feeds and FeedItems */ +public class FeedSearcher { + private static final String TAG = "FeedSearcher"; + + public static ArrayList performSearch(final String query) { + String lcQuery = query.toLowerCase(); + ArrayList result = new ArrayList(); + if (AppConfig.DEBUG) + Log.d(TAG, "Searching Feed titles"); + searchFeedtitles(lcQuery, result); + if (AppConfig.DEBUG) + Log.d(TAG, "Searching Feeditem titles"); + searchFeedItemTitles(lcQuery, result); + if (AppConfig.DEBUG) + Log.d(TAG, "Searching item-chaptertitles"); + + searchFeedItemChapters(lcQuery, result); + if (AppConfig.DEBUG) + Log.d(TAG, "Searching item descriptions"); + + searchFeedItemDescription(lcQuery, result); + if (AppConfig.DEBUG) + Log.d(TAG, "Searching item content encoded data"); + + searchFeedItemContentEncoded(lcQuery, result); + return result; + } + + private static void searchFeedtitles(String query, + ArrayList destination) { + FeedManager manager = FeedManager.getInstance(); + for (Feed feed : manager.getFeeds()) { + if (feed.getTitle().toLowerCase().contains(query)) { + destination.add(new SearchResult(feed, null)); + } + } + } + + private static void searchFeedItemTitles(String query, + ArrayList destination) { + FeedManager manager = FeedManager.getInstance(); + for (Feed feed : manager.getFeeds()) { + for (FeedItem item : feed.getItems()) { + if (item.getTitle().toLowerCase().contains(query)) { + destination.add(new SearchResult(item, PodcastApp + .getInstance().getString(R.string.found_in_label) + + item.getFeed().getTitle())); + } + } + } + } + + private static void searchFeedItemChapters(String query, + ArrayList destination) { + FeedManager manager = FeedManager.getInstance(); + for (Feed feed : manager.getFeeds()) { + for (FeedItem item : feed.getItems()) { + if (item.getSimpleChapters() != null) { + for (SimpleChapter sc : item.getSimpleChapters()) { + if (sc.getTitle().toLowerCase().contains(query)) { + destination.add(new SearchResult(item, PodcastApp + .getInstance().getString( + R.string.found_in_chapters_label))); + } + } + } + } + } + } + + private static void searchFeedItemDescription(String query, + ArrayList destination) { + FeedManager manager = FeedManager.getInstance(); + for (Feed feed : manager.getFeeds()) { + for (FeedItem item : feed.getItems()) { + if (item.getDescription() != null + && item.getDescription().toLowerCase().contains(query)) { + destination.add(new SearchResult(item, PodcastApp + .getInstance().getString( + R.string.found_in_shownotes_label))); + } + } + } + } + + private static void searchFeedItemContentEncoded(String query, + ArrayList destination) { + FeedManager manager = FeedManager.getInstance(); + for (Feed feed : manager.getFeeds()) { + for (FeedItem item : feed.getItems()) { + if (!destination.contains(item) + && item.getContentEncoded() != null + && item.getContentEncoded().toLowerCase() + .contains(query)) { + destination.add(new SearchResult(item, PodcastApp + .getInstance().getString( + R.string.found_in_shownotes_label))); + } + } + } + } + +} diff --git a/src/de/danoeh/antennapod/feed/SearchResult.java b/src/de/danoeh/antennapod/feed/SearchResult.java new file mode 100644 index 000000000..3378918f7 --- /dev/null +++ b/src/de/danoeh/antennapod/feed/SearchResult.java @@ -0,0 +1,22 @@ +package de.danoeh.antennapod.feed; + +public class SearchResult { + private FeedComponent component; + /** Additional information (e.g. where it was found) */ + private String subtitle; + + public SearchResult(FeedComponent component, String subtitle) { + super(); + this.component = component; + this.subtitle = subtitle; + } + + public FeedComponent getComponent() { + return component; + } + + public String getSubtitle() { + return subtitle; + } + +}