implemented searching algorithm
This commit is contained in:
parent
6674da6e2c
commit
dc02bff7c6
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -1,5 +1,5 @@
|
|||
package de.danoeh.antennapod;
|
||||
|
||||
public final class AppConfig {
|
||||
public final static boolean DEBUG = false;
|
||||
public final static boolean DEBUG = true;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue