implemented word search

This commit is contained in:
daniel oeh 2012-07-24 16:52:29 +02:00
parent 8bad211f68
commit 7d99031706
6 changed files with 111 additions and 26 deletions

View File

@ -145,6 +145,7 @@
<string name="search_results_label">Search results</string> <string name="search_results_label">Search results</string>
<string name="search_term_label">You searched:\u0020</string> <string name="search_term_label">You searched:\u0020</string>
<string name="search_label">Search</string> <string name="search_label">Search</string>
<string name="found_in_title_label">Found in title</string>
</resources> </resources>

View File

@ -69,7 +69,7 @@ public class SearchActivity extends SherlockListActivity {
Log.d(TAG, "Starting search"); Log.d(TAG, "Starting search");
String query = intent.getStringExtra(SearchManager.QUERY); String query = intent.getStringExtra(SearchManager.QUERY);
getSupportActionBar().setSubtitle( getSupportActionBar().setSubtitle(
getString(R.string.search_term_label) + query); getString(R.string.search_term_label) + "\"" + query + "\"");
startSearch(query); startSearch(query);
} }
} }

View File

@ -57,10 +57,13 @@ public class SearchlistAdapter extends ArrayAdapter<SearchResult> {
} else if (component.getClass() == FeedItem.class) { } else if (component.getClass() == FeedItem.class) {
FeedItem item = (FeedItem) component; FeedItem item = (FeedItem) component;
holder.title.setText(item.getTitle()); holder.title.setText(item.getTitle());
holder.subtitle.setVisibility(View.VISIBLE); if (result.getSubtitle() != null) {
holder.subtitle.setText(result.getSubtitle()); holder.subtitle.setVisibility(View.VISIBLE);
holder.subtitle.setText(result.getSubtitle());
}
FeedImageLoader.getInstance().loadBitmap(item.getFeed().getImage(), FeedImageLoader.getInstance().loadBitmap(item.getFeed().getImage(),
holder.cover); } holder.cover);
}
return convertView; return convertView;
} }

View File

@ -1,24 +1,36 @@
package de.danoeh.antennapod.feed; package de.danoeh.antennapod.feed;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import android.util.Log; import android.util.Log;
import de.danoeh.antennapod.AppConfig; import de.danoeh.antennapod.AppConfig;
import de.danoeh.antennapod.PodcastApp; import de.danoeh.antennapod.PodcastApp;
import de.danoeh.antennapod.R; import de.danoeh.antennapod.R;
import de.danoeh.antennapod.util.SearchResultValueComparator;
/** Performs search on Feeds and FeedItems */ /** Performs search on Feeds and FeedItems */
public class FeedSearcher { public class FeedSearcher {
private static final String TAG = "FeedSearcher"; private static final String TAG = "FeedSearcher";
// Search result values
private static final int VALUE_FEED_TITLE = 3;
private static final int VALUE_ITEM_TITLE = 2;
private static final int VALUE_ITEM_CHAPTER = 1;
private static final int VALUE_ITEM_DESCRIPTION = 0;
private static final int VALUE_WORD_MATCH = 4;
/** Performs a search in all feeds or one specific feed. */ /** Performs a search in all feeds or one specific feed. */
public static ArrayList<SearchResult> performSearch(final String query, public static ArrayList<SearchResult> performSearch(final String query,
Feed selectedFeed) { Feed selectedFeed) {
String lcQuery = query.toLowerCase(); String lcQuery = query.toLowerCase();
ArrayList<SearchResult> result = new ArrayList<SearchResult>(); ArrayList<SearchResult> result = new ArrayList<SearchResult>();
if (selectedFeed == null) { if (selectedFeed == null) {
if (AppConfig.DEBUG) Log.d(TAG, "Performing global search"); if (AppConfig.DEBUG)
Log.d(TAG, "Performing global search");
if (AppConfig.DEBUG) if (AppConfig.DEBUG)
Log.d(TAG, "Searching Feed titles"); Log.d(TAG, "Searching Feed titles");
searchFeedtitles(lcQuery, result); searchFeedtitles(lcQuery, result);
@ -42,6 +54,10 @@ public class FeedSearcher {
Log.d(TAG, "Searching item content encoded data"); Log.d(TAG, "Searching item content encoded data");
searchFeedItemContentEncoded(lcQuery, result, selectedFeed); searchFeedItemContentEncoded(lcQuery, result, selectedFeed);
if (AppConfig.DEBUG)
Log.d(TAG, "Sorting results");
Collections.sort(result, new SearchResultValueComparator());
return result; return result;
} }
@ -49,8 +65,10 @@ public class FeedSearcher {
ArrayList<SearchResult> destination) { ArrayList<SearchResult> destination) {
FeedManager manager = FeedManager.getInstance(); FeedManager manager = FeedManager.getInstance();
for (Feed feed : manager.getFeeds()) { for (Feed feed : manager.getFeeds()) {
if (feed.getTitle().toLowerCase().contains(query)) { SearchResult result = createSearchResult(feed, query, feed
destination.add(new SearchResult(feed, null)); .getTitle().toLowerCase(), VALUE_FEED_TITLE);
if (result != null) {
destination.add(result);
} }
} }
} }
@ -70,11 +88,14 @@ public class FeedSearcher {
private static void searchFeedItemTitlesSingleFeed(String query, private static void searchFeedItemTitlesSingleFeed(String query,
ArrayList<SearchResult> destination, Feed feed) { ArrayList<SearchResult> destination, Feed feed) {
for (FeedItem item : feed.getItems()) { for (FeedItem item : feed.getItems()) {
if (item.getTitle().toLowerCase().contains(query)) { SearchResult result = createSearchResult(item, query, item
destination.add(new SearchResult(item, PodcastApp.getInstance() .getTitle().toLowerCase(), VALUE_ITEM_TITLE);
.getString(R.string.found_in_label) if (result != null) {
+ item.getFeed().getTitle())); result.setSubtitle(PodcastApp.getInstance().getString(
R.string.found_in_title_label));
destination.add(result);
} }
} }
} }
@ -95,10 +116,12 @@ public class FeedSearcher {
for (FeedItem item : feed.getItems()) { for (FeedItem item : feed.getItems()) {
if (item.getSimpleChapters() != null) { if (item.getSimpleChapters() != null) {
for (SimpleChapter sc : item.getSimpleChapters()) { for (SimpleChapter sc : item.getSimpleChapters()) {
if (sc.getTitle().toLowerCase().contains(query)) { SearchResult result = createSearchResult(item, query, sc
destination.add(new SearchResult(item, PodcastApp .getTitle().toLowerCase(), VALUE_ITEM_CHAPTER);
.getInstance().getString( if (result != null) {
R.string.found_in_chapters_label))); result.setSubtitle(PodcastApp.getInstance().getString(
R.string.found_in_chapters_label));
destination.add(result);
} }
} }
} }
@ -121,10 +144,15 @@ public class FeedSearcher {
private static void searchFeedItemDescriptionSingleFeed(String query, private static void searchFeedItemDescriptionSingleFeed(String query,
ArrayList<SearchResult> destination, Feed feed) { ArrayList<SearchResult> destination, Feed feed) {
for (FeedItem item : feed.getItems()) { for (FeedItem item : feed.getItems()) {
if (item.getDescription() != null if (item.getDescription() != null) {
&& item.getDescription().toLowerCase().contains(query)) { SearchResult result = createSearchResult(item, query, item
destination.add(new SearchResult(item, PodcastApp.getInstance() .getDescription().toLowerCase(), VALUE_ITEM_DESCRIPTION);
.getString(R.string.found_in_shownotes_label))); if (result != null) {
result.setSubtitle(PodcastApp.getInstance().getString(
R.string.found_in_shownotes_label));
destination.add(result);
}
} }
} }
} }
@ -137,19 +165,47 @@ public class FeedSearcher {
searchFeedItemContentEncodedSingleFeed(query, destination, feed); searchFeedItemContentEncodedSingleFeed(query, destination, feed);
} }
} else { } else {
searchFeedItemContentEncodedSingleFeed(query, destination, selectedFeed); searchFeedItemContentEncodedSingleFeed(query, destination,
selectedFeed);
} }
} }
private static void searchFeedItemContentEncodedSingleFeed(String query, private static void searchFeedItemContentEncodedSingleFeed(String query,
ArrayList<SearchResult> destination, Feed feed) { ArrayList<SearchResult> destination, Feed feed) {
for (FeedItem item : feed.getItems()) { for (FeedItem item : feed.getItems()) {
if (!destination.contains(item) && item.getContentEncoded() != null if (!destination.contains(item) && item.getContentEncoded() != null) {
&& item.getContentEncoded().toLowerCase().contains(query)) { SearchResult result = createSearchResult(item, query, item
destination.add(new SearchResult(item, PodcastApp.getInstance() .getContentEncoded().toLowerCase(),
.getString(R.string.found_in_shownotes_label))); VALUE_ITEM_DESCRIPTION);
if (result != null) {
result.setSubtitle(PodcastApp.getInstance().getString(
R.string.found_in_shownotes_label));
destination.add(result);
}
} }
} }
} }
private static SearchResult createSearchResult(FeedComponent component,
String query, String text, int baseValue) {
int bonus = 0;
boolean found = false;
// try word search
Pattern word = Pattern.compile("\b" + query + "\b");
Matcher matcher = word.matcher(text);
found = matcher.find();
if (found) {
bonus = VALUE_WORD_MATCH;
} else {
// search for other occurence
found = text.contains(query);
}
if (found) {
return new SearchResult(component, baseValue + bonus);
} else {
return null;
}
}
} }

View File

@ -4,11 +4,13 @@ public class SearchResult {
private FeedComponent component; private FeedComponent component;
/** Additional information (e.g. where it was found) */ /** Additional information (e.g. where it was found) */
private String subtitle; private String subtitle;
/** Higher value means more importance */
private int value;
public SearchResult(FeedComponent component, String subtitle) { public SearchResult(FeedComponent component, int value) {
super(); super();
this.component = component; this.component = component;
this.subtitle = subtitle; this.value = value;
} }
public FeedComponent getComponent() { public FeedComponent getComponent() {
@ -19,4 +21,13 @@ public class SearchResult {
return subtitle; return subtitle;
} }
public void setSubtitle(String subtitle) {
this.subtitle = subtitle;
}
public int getValue() {
return value;
}
} }

View File

@ -0,0 +1,14 @@
package de.danoeh.antennapod.util;
import java.util.Comparator;
import de.danoeh.antennapod.feed.SearchResult;
public class SearchResultValueComparator implements Comparator<SearchResult> {
@Override
public int compare(SearchResult lhs, SearchResult rhs) {
return rhs.getValue() - lhs.getValue();
}
}