implemented searching algorithm

This commit is contained in:
daniel oeh 2012-07-24 13:54:43 +02:00
parent 6674da6e2c
commit dc02bff7c6
9 changed files with 335 additions and 1 deletions

View File

@ -29,6 +29,7 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data android:name="android.app.default_searchable" android:value=".activity.SearchActivity"/>
</activity>
<activity
android:name="de.danoeh.antennapod.activity.AddFeedActivity"
@ -129,6 +130,12 @@
<activity android:label="@string/about_pref" android:name=".activity.AboutActivity" android:theme="@style/Theme.Sherlock.Light.NoActionBar"></activity>
<activity android:label="@string/opml_import_label" android:name=".activity.OpmlImportActivity"></activity>
<activity android:label="@string/opml_import_label" android:name=".activity.OpmlFeedChooserActivity"></activity>
<activity android:name=".activity.SearchActivity" android:theme="@style/Theme.Sherlock.Light.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.SEARCH"/>
</intent-filter>
<meta-data android:name="android.app.searchable" android:resource="@xml/searchable" /></activity>
</application>
</manifest>

View File

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="8dp" >
<ImageView
android:id="@+id/imgvFeedimage"
android:layout_width="55dip"
android:layout_height="55dip"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_marginLeft="1dip"
android:layout_marginRight="4dip"
android:cropToPadding="true" />
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_centerVertical="true"
android:layout_toRightOf="@id/imgvFeedimage"
android:orientation="vertical" >
<TextView
android:id="@+id/txtvTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLines="2"
android:textStyle="bold" />
<TextView
android:id="@+id/txtvSubtitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/gray" />
</LinearLayout>
</RelativeLayout>

View File

@ -136,6 +136,10 @@
<string name="opml_import_error_dir_empty">The import directory is empty.</string>
<string name="select_all_label">Select all</string>
<string name="deselect_all_label">Deselect all</string>
<string name="search_hint">Search for Feeds or Episodes</string>
<string name="found_in_label">Found in:\u0020</string>
<string name="found_in_shownotes_label">Found in shownotes</string>
<string name="found_in_chapters_label">Found in chapters</string>
</resources>

5
res/xml/searchable.xml Normal file
View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<searchable xmlns:android="http://schemas.android.com/apk/res/android" android:hint="@string/search_hint" android:label="@string/app_name" android:icon="@drawable/ic_launcher">
</searchable>

View File

@ -1,5 +1,5 @@
package de.danoeh.antennapod;
public final class AppConfig {
public final static boolean DEBUG = false;
public final static boolean DEBUG = true;
}

View File

@ -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<SearchResult> 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<String, Void, ArrayList<SearchResult>> executor = new AsyncTask<String, Void, ArrayList<SearchResult>>() {
@Override
protected ArrayList<SearchResult> doInBackground(String... params) {
if (AppConfig.DEBUG)
Log.d(TAG, "Starting background work");
return FeedSearcher.performSearch(params[0]);
}
@Override
protected void onPostExecute(ArrayList<SearchResult> 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);
}
}
}

View File

@ -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<SearchResult> {
public SearchlistAdapter(Context context, int textViewResourceId,
List<SearchResult> 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;
}
}

View File

@ -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<SearchResult> performSearch(final String query) {
String lcQuery = query.toLowerCase();
ArrayList<SearchResult> result = new ArrayList<SearchResult>();
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<SearchResult> 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<SearchResult> 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<SearchResult> 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<SearchResult> 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<SearchResult> 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)));
}
}
}
}
}

View File

@ -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;
}
}