diff --git a/res/values/strings.xml b/res/values/strings.xml index 839ab0c9e..6d883d499 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -145,6 +145,7 @@ Search results You searched:\u0020 Search + Found in title \ No newline at end of file diff --git a/src/de/danoeh/antennapod/activity/SearchActivity.java b/src/de/danoeh/antennapod/activity/SearchActivity.java index df97c1870..2b2d5358b 100644 --- a/src/de/danoeh/antennapod/activity/SearchActivity.java +++ b/src/de/danoeh/antennapod/activity/SearchActivity.java @@ -69,7 +69,7 @@ public class SearchActivity extends SherlockListActivity { Log.d(TAG, "Starting search"); String query = intent.getStringExtra(SearchManager.QUERY); getSupportActionBar().setSubtitle( - getString(R.string.search_term_label) + query); + getString(R.string.search_term_label) + "\"" + query + "\""); startSearch(query); } } diff --git a/src/de/danoeh/antennapod/adapter/SearchlistAdapter.java b/src/de/danoeh/antennapod/adapter/SearchlistAdapter.java index e9cb3e290..4a08eaa2f 100644 --- a/src/de/danoeh/antennapod/adapter/SearchlistAdapter.java +++ b/src/de/danoeh/antennapod/adapter/SearchlistAdapter.java @@ -57,10 +57,13 @@ public class SearchlistAdapter extends ArrayAdapter { } 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()); + if (result.getSubtitle() != null) { + holder.subtitle.setVisibility(View.VISIBLE); + holder.subtitle.setText(result.getSubtitle()); + } FeedImageLoader.getInstance().loadBitmap(item.getFeed().getImage(), - holder.cover); } + holder.cover); + } return convertView; } diff --git a/src/de/danoeh/antennapod/feed/FeedSearcher.java b/src/de/danoeh/antennapod/feed/FeedSearcher.java index a8e92234c..ff8457934 100644 --- a/src/de/danoeh/antennapod/feed/FeedSearcher.java +++ b/src/de/danoeh/antennapod/feed/FeedSearcher.java @@ -1,24 +1,36 @@ package de.danoeh.antennapod.feed; import java.util.ArrayList; +import java.util.Collections; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import android.util.Log; import de.danoeh.antennapod.AppConfig; import de.danoeh.antennapod.PodcastApp; import de.danoeh.antennapod.R; +import de.danoeh.antennapod.util.SearchResultValueComparator; /** Performs search on Feeds and FeedItems */ public class 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. */ public static ArrayList performSearch(final String query, Feed selectedFeed) { String lcQuery = query.toLowerCase(); ArrayList result = new ArrayList(); if (selectedFeed == null) { - if (AppConfig.DEBUG) Log.d(TAG, "Performing global search"); + if (AppConfig.DEBUG) + Log.d(TAG, "Performing global search"); if (AppConfig.DEBUG) Log.d(TAG, "Searching Feed titles"); searchFeedtitles(lcQuery, result); @@ -42,6 +54,10 @@ public class FeedSearcher { Log.d(TAG, "Searching item content encoded data"); searchFeedItemContentEncoded(lcQuery, result, selectedFeed); + if (AppConfig.DEBUG) + Log.d(TAG, "Sorting results"); + Collections.sort(result, new SearchResultValueComparator()); + return result; } @@ -49,8 +65,10 @@ public class FeedSearcher { ArrayList destination) { FeedManager manager = FeedManager.getInstance(); for (Feed feed : manager.getFeeds()) { - if (feed.getTitle().toLowerCase().contains(query)) { - destination.add(new SearchResult(feed, null)); + SearchResult result = createSearchResult(feed, query, feed + .getTitle().toLowerCase(), VALUE_FEED_TITLE); + if (result != null) { + destination.add(result); } } } @@ -70,11 +88,14 @@ public class FeedSearcher { private static void searchFeedItemTitlesSingleFeed(String query, ArrayList destination, Feed feed) { 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())); + SearchResult result = createSearchResult(item, query, item + .getTitle().toLowerCase(), VALUE_ITEM_TITLE); + if (result != null) { + 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()) { 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))); + SearchResult result = createSearchResult(item, query, sc + .getTitle().toLowerCase(), VALUE_ITEM_CHAPTER); + if (result != null) { + 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, ArrayList destination, Feed feed) { 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))); + if (item.getDescription() != null) { + SearchResult result = createSearchResult(item, query, item + .getDescription().toLowerCase(), VALUE_ITEM_DESCRIPTION); + 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); } } else { - searchFeedItemContentEncodedSingleFeed(query, destination, selectedFeed); + searchFeedItemContentEncodedSingleFeed(query, destination, + selectedFeed); } } private static void searchFeedItemContentEncodedSingleFeed(String query, ArrayList destination, Feed feed) { 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))); + if (!destination.contains(item) && item.getContentEncoded() != null) { + SearchResult result = createSearchResult(item, query, item + .getContentEncoded().toLowerCase(), + 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; + } + } + } diff --git a/src/de/danoeh/antennapod/feed/SearchResult.java b/src/de/danoeh/antennapod/feed/SearchResult.java index 3378918f7..b4016f2e8 100644 --- a/src/de/danoeh/antennapod/feed/SearchResult.java +++ b/src/de/danoeh/antennapod/feed/SearchResult.java @@ -4,11 +4,13 @@ public class SearchResult { private FeedComponent component; /** Additional information (e.g. where it was found) */ private String subtitle; + /** Higher value means more importance */ + private int value; - public SearchResult(FeedComponent component, String subtitle) { + public SearchResult(FeedComponent component, int value) { super(); this.component = component; - this.subtitle = subtitle; + this.value = value; } public FeedComponent getComponent() { @@ -19,4 +21,13 @@ public class SearchResult { return subtitle; } + public void setSubtitle(String subtitle) { + this.subtitle = subtitle; + } + + public int getValue() { + return value; + } + + } diff --git a/src/de/danoeh/antennapod/util/SearchResultValueComparator.java b/src/de/danoeh/antennapod/util/SearchResultValueComparator.java new file mode 100644 index 000000000..4bbfac666 --- /dev/null +++ b/src/de/danoeh/antennapod/util/SearchResultValueComparator.java @@ -0,0 +1,14 @@ +package de.danoeh.antennapod.util; + +import java.util.Comparator; + +import de.danoeh.antennapod.feed.SearchResult; + +public class SearchResultValueComparator implements Comparator { + + @Override + public int compare(SearchResult lhs, SearchResult rhs) { + return rhs.getValue() - lhs.getValue(); + } + +}