Browse Source

Added search UI and functionality.

pull/11/head
Eric Kok 11 years ago
parent
commit
ba6a3cd70d
  1. 4
      core/AndroidManifest.xml
  2. 40
      core/res/layout-w600dp/activity_search.xml
  3. 17
      core/res/layout/actionbar_searchsite.xml
  4. 29
      core/res/layout/activity_search.xml
  5. 37
      core/res/layout/fragment_searchresults.xml
  6. 58
      core/res/layout/list_item_searchresult.xml
  7. 28
      core/res/layout/list_item_searchsite.xml
  8. 18
      core/res/menu/activity_search.xml
  9. 6
      core/res/menu/fragment_rssitems_cab.xml
  10. 9
      core/res/menu/fragment_searchresults_cab.xml
  11. 5
      core/res/values/changelog.xml
  12. 11
      core/res/values/strings.xml
  13. 2
      core/res/xml/searchable.xml
  14. 6
      core/src/org/transdroid/core/app/search/SearchHelper.java
  15. 44
      core/src/org/transdroid/core/app/search/SearchResult.java
  16. 8
      core/src/org/transdroid/core/app/search/SearchSite.java
  17. 93
      core/src/org/transdroid/core/app/settings/ApplicationSettings.java
  18. 3
      core/src/org/transdroid/core/app/settings/WebsearchSetting.java
  19. 248
      core/src/org/transdroid/core/gui/search/SearchActivity.java
  20. 4
      core/src/org/transdroid/core/gui/search/SearchHistoryProvider.java
  21. 40
      core/src/org/transdroid/core/gui/search/SearchResultView.java
  22. 71
      core/src/org/transdroid/core/gui/search/SearchResultsAdapter.java
  23. 168
      core/src/org/transdroid/core/gui/search/SearchResultsFragment.java
  24. 19
      core/src/org/transdroid/core/gui/search/SearchSetting.java
  25. 28
      core/src/org/transdroid/core/gui/search/SearchSettingSelectionView.java
  26. 43
      core/src/org/transdroid/core/gui/search/SearchSettingsDropDownAdapter.java
  27. 49
      core/src/org/transdroid/core/gui/search/SearchSiteView.java
  28. 72
      core/src/org/transdroid/core/gui/search/SearchSitesAdapter.java
  29. 61
      core/src/org/transdroid/core/gui/search/SendIntentHelper.java
  30. 26
      core/src/org/transdroid/core/gui/search/TorrentSearchHistoryProvider.java
  31. 30
      full/AndroidManifest.xml
  32. 4
      lite/AndroidManifest.xml

4
core/AndroidManifest.xml

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.transdroid.core" package="org.transdroid.core"
android:versionCode="1" android:versionCode="2"
android:versionName="2.0-alpha1" > android:versionName="2.0-alpha2" >
<uses-sdk <uses-sdk
android:minSdkVersion="7" android:minSdkVersion="7"

40
core/res/layout-w600dp/activity_search.xml

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:baselineAligned="false"
tools:context=".SearchActivity" >
<com.actionbarsherlock.view.SherlockListView
android:id="@+id/searchsites_list"
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="1"
android:choiceMode="singleChoice"
android:listSelector="?attr/selectable_background_transdroid" />
<fragment
android:id="@+id/searchresults_list"
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="3"
class="org.transdroid.core.gui.search.SearchResultsFragment_"
tools:layout="@layout/fragment_searchresults" />
<TextView
android:id="@+id/installmodule_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:drawablePadding="8dip"
android:drawableTop="?attr/loading_progress"
android:gravity="center"
android:maxWidth="400dip"
android:padding="@dimen/margin_default"
android:text="@string/search_installsearch"
android:textIsSelectable="false"
android:visibility="gone" />
</LinearLayout>

17
core/res/layout/actionbar_searchsite.xml

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingRight="@dimen/margin_half" >
<TextView
android:id="@+id/searchsite_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?attr/text_actionbar"
android:textIsSelectable="false"
android:textSize="@dimen/abs__action_bar_title_text_size"
android:fontFamily="sans-serif-condensed" />
</FrameLayout>

29
core/res/layout/activity_search.xml

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".SearchActivity" >
<fragment
android:id="@+id/searchresults_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="org.transdroid.core.gui.search.SearchResultsFragment_"
tools:layout="@layout/fragment_searchresults" />
<TextView
android:id="@+id/installmodule_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:drawablePadding="8dip"
android:drawableTop="?attr/loading_progress"
android:gravity="center"
android:maxWidth="400dip"
android:padding="@dimen/margin_default"
android:text="@string/search_installsearch"
android:textIsSelectable="false"
android:visibility="gone" />
</FrameLayout>

37
core/res/layout/fragment_searchresults.xml

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<com.actionbarsherlock.view.SherlockListView
android:id="@+id/searchresults_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:choiceMode="multipleChoiceModal"
android:listSelector="?attr/selectable_background_transdroid"
android:visibility="gone" />
<ProgressBar
android:id="@+id/loading_progress"
android:layout_width="128dp"
android:layout_height="128dp"
android:layout_gravity="center"
android:indeterminate="true"
android:indeterminateDrawable="?attr/loading_progress"
android:indeterminateOnly="true" />
<TextView
android:id="@+id/empty_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:drawablePadding="8dip"
android:drawableTop="?attr/loading_progress"
android:gravity="center"
android:maxWidth="400dip"
android:padding="@dimen/margin_default"
android:text="@string/search_noresults"
android:textIsSelectable="false"
android:visibility="gone" />
</FrameLayout>

58
core/res/layout/list_item_searchresult.xml

@ -0,0 +1,58 @@
<?xml version="1.0" encoding="utf-8"?>
<org.transdroid.core.gui.rss.RssitemStatusLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="?attr/selectable_background_transdroid"
android:paddingBottom="@dimen/margin_half"
android:paddingLeft="@dimen/margin_default"
android:paddingRight="@dimen/margin_default"
android:paddingTop="@dimen/margin_half" >
<TextView
android:id="@+id/name_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fontFamily="sans-serif-condensed"
android:textColor="?attr/text_bright"
android:textIsSelectable="false"
android:textSize="@dimen/text_enlarged" />
<TextView
android:id="@+id/leechers_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/name_text"
android:layout_alignParentRight="true"
android:layout_marginTop="4dip"
android:textIsSelectable="false"
android:textSize="@dimen/text_small" />
<TextView
android:id="@+id/seeders_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="@id/leechers_text"
android:layout_toLeftOf="@id/leechers_text"
android:layout_marginRight="@dimen/margin_default"
android:textIsSelectable="false"
android:textSize="@dimen/text_small" />
<TextView
android:id="@+id/size_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="@id/leechers_text"
android:textIsSelectable="false"
android:textSize="@dimen/text_small" />
<TextView
android:id="@+id/date_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="@id/leechers_text"
android:layout_toRightOf="@id/size_text"
android:layout_marginRight="@dimen/margin_default"
android:textIsSelectable="false"
android:textSize="@dimen/text_small" />
</org.transdroid.core.gui.rss.RssitemStatusLayout>

28
core/res/layout/list_item_searchsite.xml

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingBottom="@dimen/margin_half"
android:paddingLeft="@dimen/margin_default"
android:paddingRight="@dimen/margin_default"
android:paddingTop="@dimen/margin_half" >
<ImageView
android:id="@+id/favicon_image"
android:layout_width="24dip"
android:layout_height="24dip"
android:layout_marginRight="@dimen/margin_half"
android:scaleType="centerCrop"
tools:ignore="contentDescription" />
<TextView
android:id="@+id/name_text"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginTop="1dip"
android:textIsSelectable="false" />
</LinearLayout>

18
core/res/menu/activity_search.xml

@ -0,0 +1,18 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="@+id/action_refresh"
android:icon="?attr/ic_action_refresh"
android:showAsAction="always"
android:title="@string/action_refresh"/>
<item
android:id="@+id/action_search"
android:icon="?attr/ic_action_search"
android:showAsAction="collapseActionView|ifRoom"
android:title="@string/action_search"/>
<item
android:id="@+id/action_downloadsearch"
android:showAsAction="always"
android:title="@string/search_download"/>
</menu>

6
core/res/menu/fragment_rssitems_cab.xml

@ -1,5 +1,11 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android" > <menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="@+id/action_showdetails"
android:icon="?attr/ic_action_new"
android:showAsAction="always"
android:title="@string/action_showdetails" />
<item <item
android:id="@+id/action_addall" android:id="@+id/action_addall"
android:icon="?attr/ic_action_new" android:icon="?attr/ic_action_new"

9
core/res/menu/fragment_searchresults_cab.xml

@ -0,0 +1,9 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="@+id/action_addall"
android:icon="?attr/ic_action_new"
android:showAsAction="always"
android:title="@string/action_addall" />
</menu>

5
core/res/values/changelog.xml

@ -1,6 +1,11 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="system_changelog"> <string name="system_changelog">
Transdroid 2.0.0-alpha2\n
- Fixed Transmission adapter folder setting\n
- Fixed RSS feed screens\n
- UI tweaks\n
\n
Transdroid 2.0.0-alpha1\n Transdroid 2.0.0-alpha1\n
- Totally reworked Holo-style interface\n - Totally reworked Holo-style interface\n
- Provide tablet interface on smaller tablets\n - Provide tablet interface on smaller tablets\n

11
core/res/values/strings.xml

@ -38,6 +38,7 @@
<string name="action_priority_high">High</string> <string name="action_priority_high">High</string>
<string name="action_remoteplay">Remote play in VLC</string> <string name="action_remoteplay">Remote play in VLC</string>
<string name="action_download">Download using (S)FTP</string> <string name="action_download">Download using (S)FTP</string>
<string name="action_showdetails">Show details</string>
<string name="action_removesettings">Remove settings</string> <string name="action_removesettings">Remove settings</string>
<string name="action_visitwebsite">Visit transdroid.org</string> <string name="action_visitwebsite">Visit transdroid.org</string>
@ -117,8 +118,18 @@
<string name="search_torrentsearch">Torrent search</string> <string name="search_torrentsearch">Torrent search</string>
<string name="search_hint">Search for torrents</string> <string name="search_hint">Search for torrents</string>
<string name="search_noresults">No results for your query</string>
<string name="search_seeders">S: %1$s</string>
<string name="search_leechers">L: %1$s</string>
<string name="search_installsearch">This feature requires a one-time installation of the Torrent Search module. Click download to get the install package (apk) from transdroid.org and restart your search.</string>
<string name="search_download">Download module</string>
<string name="search_openingdetails">Opening details for %1$s</string>
<string name="search_barcodescannernotfound">The Barcode Scanner could not be found. Would you like to install it from the Play Store?</string> <string name="search_barcodescannernotfound">The Barcode Scanner could not be found. Would you like to install it from the Play Store?</string>
<string name="search_filemanagernotfound">No compatible file manager could not be found. Would you like to install IO File Manager from the Play Store?</string> <string name="search_filemanagernotfound">No compatible file manager could not be found. Would you like to install IO File Manager from the Play Store?</string>
<plurals name="search_resutlsselected">
<item quantity="one">%1$d result selected</item>
<item quantity="other">%1$d results selected</item>
</plurals>
<string name="rss_feeds">RSS feeds</string> <string name="rss_feeds">RSS feeds</string>
<string name="rss_nosettings">You have not defined any RSS feeds yet to monitor. Torrent-specific RSS feeds keep you up to date with new releases and you are notified of new items.</string> <string name="rss_nosettings">You have not defined any RSS feeds yet to monitor. Torrent-specific RSS feeds keep you up to date with new releases and you are notified of new items.</string>

2
core/res/xml/searchable.xml

@ -3,6 +3,6 @@
<searchable xmlns:android="http://schemas.android.com/apk/res/android" <searchable xmlns:android="http://schemas.android.com/apk/res/android"
android:label="@string/search_torrentsearch" android:label="@string/search_torrentsearch"
android:hint="@string/search_hint" android:hint="@string/search_hint"
android:searchSuggestAuthority="org.transdroid.core.gui.SearchHistoryProvider" android:searchSuggestAuthority="org.transdroid.core.gui.search.SearchHistoryProvider"
android:searchSuggestSelection=" ? " /> android:searchSuggestSelection=" ? " />

6
core/src/org/transdroid/core/app/search/SearchHelper.java

@ -76,14 +76,14 @@ public class SearchHelper {
} }
/** /**
* Queries the Torrent Search module to search for torrents on the web. This method is synchornous and should always * Queries the Torrent Search module to search for torrents on the web. This method is synchronous and should always
* be called in a background thread. * be called in a background thread.
* @param query The search query to pass to the torrent site * @param query The search query to pass to the torrent site
* @param site The site to search, as retrieved from the TorrentSitesProvider, or null if the Torrent Search package * @param site The site to search, as retrieved from the TorrentSitesProvider, or null if the Torrent Search package
* @param sortBy.name() The sort order to request from the torrent site, if supported * @param sortBy.name() The sort order to request from the torrent site, if supported
* @return A list of torrent search results as POJOs, or null if the Torrent Search package is not installed * @return A list of torrent search results as POJOs, or null if the Torrent Search package is not installed
*/ */
public List<SearchResult> search(String query, SearchSite site, SearchSortOrder sortBy) { public ArrayList<SearchResult> search(String query, SearchSite site, SearchSortOrder sortBy) {
// Try to query the TorrentSearchProvider to search for torrents on the web // Try to query the TorrentSearchProvider to search for torrents on the web
Uri uri = Uri.parse("content://org.transdroid.search.torrentsearchprovider/search/" + query); Uri uri = Uri.parse("content://org.transdroid.search.torrentsearchprovider/search/" + query);
@ -96,7 +96,7 @@ public class SearchHelper {
sortBy.name()); sortBy.name());
} }
if (cursor.moveToFirst()) { if (cursor.moveToFirst()) {
List<SearchResult> results = new ArrayList<SearchResult>(); ArrayList<SearchResult> results = new ArrayList<SearchResult>();
do { do {
// Read the cursor fields into the SearchResult object // Read the cursor fields into the SearchResult object
results.add(new SearchResult(cursor.getInt(CURSOR_SEARCH_ID), cursor.getString(CURSOR_SEARCH_NAME), results.add(new SearchResult(cursor.getInt(CURSOR_SEARCH_ID), cursor.getString(CURSOR_SEARCH_NAME),

44
core/src/org/transdroid/core/app/search/SearchResult.java

@ -2,11 +2,14 @@ package org.transdroid.core.app.search;
import java.util.Date; import java.util.Date;
import android.os.Parcel;
import android.os.Parcelable;
/** /**
* Represents a search result as retrieved by querying the Torrent Search package. * Represents a search result as retrieved by querying the Torrent Search package.
* @author Eric Kok * @author Eric Kok
*/ */
public class SearchResult { public class SearchResult implements Parcelable {
private final int id; private final int id;
private final String name; private final String name;
@ -61,4 +64,43 @@ public class SearchResult {
return leechers; return leechers;
} }
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel out, int flags) {
out.writeInt(id);
out.writeString(name);
out.writeString(torrentUrl);
out.writeString(detailsUrl);
out.writeString(size);
out.writeLong(addedOn == null ? -1 : addedOn.getTime());
out.writeString(seeders);
out.writeString(leechers);
}
public static final Parcelable.Creator<SearchResult> CREATOR = new Parcelable.Creator<SearchResult>() {
public SearchResult createFromParcel(Parcel in) {
return new SearchResult(in);
}
public SearchResult[] newArray(int size) {
return new SearchResult[size];
}
};
public SearchResult(Parcel in) {
id = in.readInt();
name = in.readString();
torrentUrl = in.readString();
detailsUrl = in.readString();
size = in.readString();
long addedOnIn = in.readLong();
addedOn = addedOnIn == -1 ? null : new Date(addedOnIn);
seeders = in.readString();
leechers = in.readString();
}
} }

8
core/src/org/transdroid/core/app/search/SearchSite.java

@ -1,12 +1,13 @@
package org.transdroid.core.app.search; package org.transdroid.core.app.search;
import org.transdroid.core.gui.lists.SimpleListItem; import org.transdroid.core.gui.lists.SimpleListItem;
import org.transdroid.core.gui.search.SearchSetting;
/** /**
* Represents an available torrent site that can be searched using the Torrent Search package. * Represents an available torrent site that can be searched using the Torrent Search package.
* @author Eric Kok * @author Eric Kok
*/ */
public class SearchSite implements SimpleListItem { public class SearchSite implements SimpleListItem, SearchSetting {
private final int id; private final int id;
private final String key; private final String key;
@ -37,4 +38,9 @@ public class SearchSite implements SimpleListItem {
return rssFeedUrl; return rssFeedUrl;
} }
@Override
public String getBaseUrl() {
return rssFeedUrl;
}
} }

93
core/src/org/transdroid/core/app/settings/ApplicationSettings.java

@ -1,12 +1,17 @@
package org.transdroid.core.app.settings; package org.transdroid.core.app.settings;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import org.androidannotations.annotations.Bean;
import org.androidannotations.annotations.EBean; import org.androidannotations.annotations.EBean;
import org.androidannotations.annotations.EBean.Scope; import org.androidannotations.annotations.EBean.Scope;
import org.androidannotations.annotations.RootContext; import org.androidannotations.annotations.RootContext;
import org.transdroid.core.app.search.SearchHelper;
import org.transdroid.core.app.search.SearchSite;
import org.transdroid.core.gui.search.SearchSetting;
import org.transdroid.daemon.Daemon; import org.transdroid.daemon.Daemon;
import org.transdroid.daemon.OS; import org.transdroid.daemon.OS;
import org.transdroid.daemon.TorrentsSortBy; import org.transdroid.daemon.TorrentsSortBy;
@ -26,6 +31,8 @@ public class ApplicationSettings {
@RootContext @RootContext
protected Context context; protected Context context;
private SharedPreferences prefs; private SharedPreferences prefs;
@Bean
protected SearchHelper searchHelper;
protected ApplicationSettings(Context context) { protected ApplicationSettings(Context context) {
prefs = PreferenceManager.getDefaultSharedPreferences(context); prefs = PreferenceManager.getDefaultSharedPreferences(context);
@ -40,7 +47,7 @@ public class ApplicationSettings {
for (int i = 0; i <= getMaxServer(); i++) { for (int i = 0; i <= getMaxServer(); i++) {
servers.add(getServerSetting(i)); servers.add(getServerSetting(i));
} }
return servers; return Collections.unmodifiableList(servers);
} }
/** /**
@ -208,7 +215,7 @@ public class ApplicationSettings {
for (int i = 0; i <= getMaxWebsearch(); i++) { for (int i = 0; i <= getMaxWebsearch(); i++) {
websearches.add(getWebsearchSetting(i)); websearches.add(getWebsearchSetting(i));
} }
return websearches; return Collections.unmodifiableList(websearches);
} }
/** /**
@ -271,7 +278,7 @@ public class ApplicationSettings {
for (int i = 0; i <= getMaxRssfeed(); i++) { for (int i = 0; i <= getMaxRssfeed(); i++) {
rssfeeds.add(getRssfeedSetting(i)); rssfeeds.add(getRssfeedSetting(i));
} }
return rssfeeds; return Collections.unmodifiableList(rssfeeds);
} }
/** /**
@ -373,4 +380,84 @@ public class ApplicationSettings {
return prefs.getBoolean("system_lastusedsortdirection", false); return prefs.getBoolean("system_lastusedsortdirection", false);
} }
/**
* Returns the list of all available in-app search sites as well as all web searches that the user configured.
* @return A list of search settings, all of which are either a {@link SearchSite} or {@link WebsearchSetting}
*/
public List<SearchSetting> getSearchSettings() {
List<SearchSetting> all = new ArrayList<SearchSetting>();
all.addAll(searchHelper.getAvailableSites());
all.addAll(getWebsearchSettings());
return Collections.unmodifiableList(all);
}
/**
* Returns the settings of the search site that was last used by the user or was selected by the user as default
* site in the main settings. As opposed to getLastUsedSearchSiteKey(int), this method checks whether a site was
* already registered as being last used (or set as default) and checks whether the site still exists. It returns
* the first in-app search site if that fails.
* @return A site settings object of the last used server (or, if not known, the first server), or null if no
* servers exist
*/
public SearchSetting getLastUsedSearchSite() {
String lastKey = getLastUsedSearchSiteKey();
List<SearchSite> allsites = searchHelper.getAvailableSites();
int lastWebsearch = -1;
try {
lastWebsearch = Integer.parseInt(lastKey);
} catch (Exception e) {
// Not an in-app search site, but probably an in-app search
}
if (lastKey == null) {
// No site yet set specified; return the first in-app one, if available
if (allsites != null) {
return allsites.get(0);
}
return null;
}
if (lastWebsearch >= 0) {
// The last used site should be a user-configured web search site
int max = getMaxWebsearch(); // Zero-based index, so with max == 0 there is 1 server
if (max < 0 || lastWebsearch > max) {
// No web search sites configured
return null;
}
return getWebsearchSetting(lastWebsearch);
}
// Should be an in-app search key
if (allsites != null) {
for (SearchSite searchSite : allsites) {
if (searchSite.getKey().equals(lastKey)) {
return searchSite;
}
}
// Not found at all; probably a no longer existing web search; return the first in-app one
return allsites.get(0);
}
return null;
}
/**
* Returns the unique key of the site that the used last used or selected as default form the main settings; use
* with getLastUsedSearchSite directly. WARNING: the returned string may no longer refer to a known web search site
* or in-app search settings object.
* @return A string indicating the key of the last used search site, or null if no site was yet used or set as
* default
*/
private String getLastUsedSearchSiteKey() {
return prefs.getString("header_setsearchsite", null);
}
/**
* Registers the unique key of some web search or in-app search site as being last used by the user
* @param order The key identifying the specific server
*/
public void setLastUsedSearchSite(String siteKey) {
prefs.edit().putString("header_setsearchsite", siteKey).commit();
}
} }

3
core/src/org/transdroid/core/app/settings/WebsearchSetting.java

@ -1,6 +1,7 @@
package org.transdroid.core.app.settings; package org.transdroid.core.app.settings;
import org.transdroid.core.gui.lists.SimpleListItem; import org.transdroid.core.gui.lists.SimpleListItem;
import org.transdroid.core.gui.search.SearchSetting;
import android.net.Uri; import android.net.Uri;
import android.text.TextUtils; import android.text.TextUtils;
@ -9,7 +10,7 @@ import android.text.TextUtils;
* Represents a user-specified website that can be searched (by starting the browser, rather than in-app) * Represents a user-specified website that can be searched (by starting the browser, rather than in-app)
* @author Eric Kok * @author Eric Kok
*/ */
public class WebsearchSetting implements SimpleListItem { public class WebsearchSetting implements SimpleListItem, SearchSetting {
private static final String DEFAULT_NAME = "Default"; private static final String DEFAULT_NAME = "Default";
private static final String KEY_PREFIX = "websearch_"; private static final String KEY_PREFIX = "websearch_";

248
core/src/org/transdroid/core/gui/search/SearchActivity.java

@ -0,0 +1,248 @@
package org.transdroid.core.gui.search;
import java.util.List;
import org.androidannotations.annotations.AfterViews;
import org.androidannotations.annotations.Bean;
import org.androidannotations.annotations.EActivity;
import org.androidannotations.annotations.FragmentById;
import org.androidannotations.annotations.OptionsItem;
import org.androidannotations.annotations.OptionsMenu;
import org.androidannotations.annotations.SystemService;
import org.androidannotations.annotations.ViewById;
import org.transdroid.core.R;
import org.transdroid.core.app.search.SearchHelper;
import org.transdroid.core.app.search.SearchSite;
import org.transdroid.core.app.settings.ApplicationSettings;
import org.transdroid.core.app.settings.SystemSettings_;
import org.transdroid.core.app.settings.WebsearchSetting;
import org.transdroid.core.gui.TorrentsActivity_;
import org.transdroid.core.gui.navigation.NavigationHelper;
import android.annotation.TargetApi;
import android.app.SearchManager;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.SearchRecentSuggestions;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.TextView;
import com.actionbarsherlock.app.ActionBar;
import com.actionbarsherlock.app.ActionBar.OnNavigationListener;
import com.actionbarsherlock.app.SherlockFragmentActivity;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem;
import com.actionbarsherlock.view.SherlockListView;
import com.actionbarsherlock.widget.SearchView;
/**
* An activity that shows search results to the user (after a query was supplied by the standard Android search manager)
* and either shows the list of search sites on the left (e.g. on tablets) or allows switching between search sites via
* the action bar spinner.
* @author Eric Kok
*/
@EActivity(resName = "activity_search")
@OptionsMenu(resName = "activity_search")
public class SearchActivity extends SherlockFragmentActivity implements OnNavigationListener {
@FragmentById(resName = "searchresults_list")
protected SearchResultsFragment fragmentResults;
@ViewById
protected SherlockListView searchsitesList;
@ViewById
protected TextView installmoduleText;
@Bean
protected ApplicationSettings applicationSettings;
@Bean
protected NavigationHelper navigationHelper;
@Bean
protected SearchHelper searchHelper;
@SystemService
protected SearchManager searchManager;
private SearchRecentSuggestions suggestions = new SearchRecentSuggestions(this,
TorrentSearchHistoryProvider.AUTHORITY, TorrentSearchHistoryProvider.MODE);
private List<SearchSetting> searchSites;
private SearchSetting lastUsedSite;
private String lastUsedQuery;
@Override
public void onCreate(Bundle savedInstanceState) {
// Set the theme according to the user preference
if (SystemSettings_.getInstance_(this).useDarkTheme()) {
setTheme(R.style.TransdroidTheme_Dark);
getSupportActionBar().setIcon(R.drawable.ic_activity_torrents);
}
super.onCreate(savedInstanceState);
}
@AfterViews
protected void init() {
// Get the user query, as coming from the standard SearchManager
handleIntent(getIntent());
if (!searchHelper.isTorrentSearchInstalled()) {
// The module install text will be shown instead (in onPrepareOptionsMenu)
return;
}
// Load sites and find the last used (or set as default) search site
searchSites = applicationSettings.getSearchSettings();
lastUsedSite = applicationSettings.getLastUsedSearchSite();
int lastUsedPosition = -1;
if (lastUsedSite != null) {
for (int i = 0; i < searchSites.size(); i++) {
if (searchSites.get(i).getKey().equals(lastUsedSite.getKey()))
lastUsedPosition = i;
}
}
// Allow site selection via list (on large screens) or action bar spinner
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
if (searchsitesList != null) {
// The current layout has a dedicated list view to select the search site
SearchSitesAdapter searchSitesAdapter = SearchSitesAdapter_.getInstance_(this);
searchSitesAdapter.update(searchSites);
searchsitesList.setAdapter(searchSitesAdapter);
searchsitesList.setOnItemClickListener(onSearchSiteClicked);
// Select the last used site; this also starts the search!
if (lastUsedPosition >= 0)
searchsitesList.setItemChecked(lastUsedPosition, true);
} else {
// Use the action bar spinner to select sites
getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
getSupportActionBar().setDisplayShowTitleEnabled(false);
getSupportActionBar().setListNavigationCallbacks(new SearchSettingsDropDownAdapter(this, searchSites), this);
// Select the last used site; this also starts the search!
if (lastUsedPosition >= 0)
getSupportActionBar().setSelectedNavigationItem(lastUsedPosition);
}
}
@TargetApi(Build.VERSION_CODES.FROYO)
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
if (navigationHelper.enableSearchUi()) {
// For Android 2.1+, add an expandable SearchView to the action bar
MenuItem item = menu.findItem(R.id.action_search);
if (android.os.Build.VERSION.SDK_INT >= 8) {
final SearchView searchView = new SearchView(this);
searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
searchView.setQueryRefinementEnabled(true);
item.setActionView(searchView);
}
}
return true;
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
boolean searchInstalled = searchHelper.isTorrentSearchInstalled();
menu.findItem(R.id.action_search).setVisible(searchInstalled);
menu.findItem(R.id.action_refresh).setVisible(searchInstalled);
menu.findItem(R.id.action_downloadsearch).setVisible(!searchInstalled);
if (searchsitesList != null)
searchsitesList.setVisibility(searchInstalled ? View.VISIBLE : View.GONE);
if (searchInstalled)
getSupportFragmentManager().beginTransaction().show(fragmentResults).commit();
else
getSupportFragmentManager().beginTransaction().hide(fragmentResults).commit();
installmoduleText.setVisibility(searchInstalled ? View.GONE : View.VISIBLE);
return true;
}
@Override
protected void onNewIntent(Intent intent) {
handleIntent(intent);
refreshSearch();
}
private void handleIntent(Intent intent) {
lastUsedQuery = getQuery(intent);
getSupportActionBar().setTitle(NavigationHelper.buildCondensedFontString(lastUsedQuery));
// Is this actually a full HTTP URL? Then redirect this request to add the URL directly
if (lastUsedQuery != null
&& (lastUsedQuery.startsWith("http") || lastUsedQuery.startsWith("https")
|| lastUsedQuery.startsWith("magnet") || lastUsedQuery.startsWith("file"))) {
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(lastUsedQuery)));
finish();
return;
}
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
@OptionsItem(android.R.id.home)
protected void navigateUp() {
TorrentsActivity_.intent(this).flags(Intent.FLAG_ACTIVITY_CLEAR_TOP).start();
}
private OnItemClickListener onSearchSiteClicked = new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
lastUsedSite = searchSites.get(position);
refreshSearch();
}
};
@Override
public boolean onNavigationItemSelected(int itemPosition, long itemId) {
lastUsedSite = searchSites.get(itemPosition);
refreshSearch();
return true;
}
/**
* Extracts the query string from the search {@link Intent}
* @return The query string that was entered by the user
*/
private String getQuery(Intent intent) {
String query = null;
if (intent.getAction().equals(Intent.ACTION_SEARCH)) {
query = intent.getStringExtra(SearchManager.QUERY);
} else if (intent.getAction().equals(Intent.ACTION_SEND)) {
query = SendIntentHelper.cleanUpText(intent);
}
if (query != null && query.length() > 0) {
// Remember this search query to later show as a suggestion
suggestions.saveRecentQuery(query, null);
return query;
}
return null;
}
@OptionsItem(resName = "action_refresh")
protected void refreshSearch() {
if (lastUsedSite instanceof WebsearchSetting) {
// Start a browser page directly to the requested search results
WebsearchSetting websearch = (WebsearchSetting) lastUsedSite;
startActivity(new Intent(Intent.ACTION_VIEW,
Uri.parse(String.format(websearch.getBaseUrl(), lastUsedQuery))));
} else if (lastUsedSite instanceof SearchSite) {
// Ask the resutls fragment to start a search for the specified query
fragmentResults.startSearch(lastUsedQuery, (SearchSite) lastUsedSite);
}
}
@OptionsItem(resName = "action_downloadsearch")
protected void downloadSearchModule() {
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.transdroid.org/latest-search")));
}
}

4
core/src/org/transdroid/core/gui/SearchHistoryProvider.java → core/src/org/transdroid/core/gui/search/SearchHistoryProvider.java

@ -1,4 +1,4 @@
package org.transdroid.core.gui; package org.transdroid.core.gui.search;
import android.content.Context; import android.content.Context;
import android.content.SearchRecentSuggestionsProvider; import android.content.SearchRecentSuggestionsProvider;
@ -10,7 +10,7 @@ import android.provider.SearchRecentSuggestions;
*/ */
public class SearchHistoryProvider extends SearchRecentSuggestionsProvider { public class SearchHistoryProvider extends SearchRecentSuggestionsProvider {
public final static String AUTHORITY = "org.transdroid.core.gui.SearchHistoryProvider"; public final static String AUTHORITY = "org.transdroid.core.gui.search.SearchHistoryProvider";
public final static int MODE = DATABASE_MODE_QUERIES; public final static int MODE = DATABASE_MODE_QUERIES;
public SearchHistoryProvider() { public SearchHistoryProvider() {

40
core/src/org/transdroid/core/gui/search/SearchResultView.java

@ -0,0 +1,40 @@
package org.transdroid.core.gui.search;
import org.androidannotations.annotations.EViewGroup;
import org.androidannotations.annotations.ViewById;
import org.transdroid.core.R;
import org.transdroid.core.app.search.SearchResult;
import android.content.Context;
import android.text.format.DateUtils;
import android.widget.TextView;
import fr.marvinlabs.widget.CheckableRelativeLayout;
/**
* View that represents a {@link SearchResult} object from an in-app search
* @author Eric Kok
*/
@EViewGroup(resName = "list_item_searchresult")
public class SearchResultView extends CheckableRelativeLayout {
// Views
@ViewById
protected TextView nameText, seedersText, leechersText, sizeText, dateText;
public SearchResultView(Context context) {
super(context);
}
public void bind(SearchResult result) {
nameText.setText(result.getName());
sizeText.setText(result.getSize());
dateText.setText(result.getAddedOn() == null ? "" : DateUtils.getRelativeDateTimeString(getContext(), result
.getAddedOn().getTime(), DateUtils.SECOND_IN_MILLIS, DateUtils.WEEK_IN_MILLIS,
DateUtils.FORMAT_ABBREV_MONTH));
seedersText.setText(getContext().getString(R.string.search_seeders, result.getSeeders()));
leechersText.setText(getContext().getString(R.string.search_leechers, result.getLeechers()));
}
}

71
core/src/org/transdroid/core/gui/search/SearchResultsAdapter.java

@ -0,0 +1,71 @@
package org.transdroid.core.gui.search;
import java.util.List;
import org.androidannotations.annotations.EBean;
import org.androidannotations.annotations.RootContext;
import org.transdroid.core.app.search.SearchResult;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
/**
* Adapter that contains a list of {@link SearchResult}s.
* @author Eric Kok
*/
@EBean
public class SearchResultsAdapter extends BaseAdapter {
private List<SearchResult> results = null;
@RootContext
protected Context context;
/**
* Allows updating the search results, replacing the old data
* @param newRssfeeds The new list of search results
*/
public void update(List<SearchResult> results) {
this.results = results;
notifyDataSetChanged();
}
@Override
public boolean hasStableIds() {
return true;
}
@Override
public int getCount() {
if (results == null)
return 0;
return results.size();
}
@Override
public SearchResult getItem(int position) {
if (results == null)
return null;
return results.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
SearchResultView rssitemView;
if (convertView == null) {
rssitemView = SearchResultView_.build(context);
} else {
rssitemView = (SearchResultView) convertView;
}
rssitemView.bind(getItem(position));
return rssitemView;
}
}

168
core/src/org/transdroid/core/gui/search/SearchResultsFragment.java

@ -0,0 +1,168 @@
package org.transdroid.core.gui.search;
import java.util.ArrayList;
import java.util.List;
import org.androidannotations.annotations.AfterViews;
import org.androidannotations.annotations.Background;
import org.androidannotations.annotations.Bean;
import org.androidannotations.annotations.EFragment;
import org.androidannotations.annotations.InstanceState;
import org.androidannotations.annotations.ItemClick;
import org.androidannotations.annotations.UiThread;
import org.androidannotations.annotations.ViewById;
import org.transdroid.core.R;
import org.transdroid.core.app.search.SearchHelper;
import org.transdroid.core.app.search.SearchHelper.SearchSortOrder;
import org.transdroid.core.app.search.SearchResult;
import org.transdroid.core.app.search.SearchSite;
import org.transdroid.core.gui.navigation.SelectionManagerMode;
import android.content.Intent;
import android.net.Uri;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import com.actionbarsherlock.app.SherlockFragment;
import com.actionbarsherlock.view.ActionMode;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem;
import com.actionbarsherlock.view.SherlockListView;
import com.actionbarsherlock.view.SherlockListView.MultiChoiceModeListenerCompat;
/**
* Fragment that lists the items in a specific RSS feed
* @author Eric Kok
*/
@EFragment(resName = "fragment_searchresults")
public class SearchResultsFragment extends SherlockFragment {
@InstanceState
protected ArrayList<SearchResult> results = null;
@Bean
protected SearchHelper searchHelper;
// Views
@ViewById(resName = "searchresults_list")
protected SherlockListView resultsList;
@Bean
protected SearchResultsAdapter resultsAdapter;
@ViewById
protected TextView emptyText;
@ViewById
protected ProgressBar loadingProgress;
@AfterViews
protected void init() {
// Set up the list adapter, which allows multi-select
resultsList.setAdapter(resultsAdapter);
resultsList.setMultiChoiceModeListener(onItemsSelected);
if (results != null)
showResults();
}
public void startSearch(String query, SearchSite site) {
loadingProgress.setVisibility(View.VISIBLE);
resultsList.setVisibility(View.GONE);
emptyText.setVisibility(View.GONE);
performSearch(query, site);
}
@Background
protected void performSearch(String query, SearchSite site) {
results = searchHelper.search(query, site, SearchSortOrder.BySeeders);
showResults();
}
@UiThread
protected void showResults() {
loadingProgress.setVisibility(View.GONE);
if (results == null || results.size() == 0) {
resultsList.setVisibility(View.GONE);
emptyText.setVisibility(View.VISIBLE);
return;
}
resultsAdapter.update(results);
resultsList.setVisibility(View.VISIBLE);
emptyText.setVisibility(View.GONE);
}
@ItemClick(resName = "searchresults_list")
protected void onItemClicked(SearchResult item) {
Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(item.getTorrentUrl()));
i.putExtra("TORRENT_TITLE", item.getName());
startActivity(i);
}
private MultiChoiceModeListenerCompat onItemsSelected = new MultiChoiceModeListenerCompat() {
SelectionManagerMode selectionManagerMode;
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
// Show contextual action bar to add items in batch mode
mode.getMenuInflater().inflate(R.menu.fragment_searchresults_cab, menu);
selectionManagerMode = new SelectionManagerMode(resultsList, R.plurals.search_resutlsselected);
selectionManagerMode.onCreateActionMode(mode, menu);
return true;
}
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return selectionManagerMode.onPrepareActionMode(mode, menu);
}
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
// Get checked torrents
List<SearchResult> checked = new ArrayList<SearchResult>();
for (int i = 0; i < resultsList.getCheckedItemPositions().size(); i++) {
if (resultsList.getCheckedItemPositions().valueAt(i))
checked.add(resultsAdapter.getItem(resultsList.getCheckedItemPositions().keyAt(i)));
}
int itemId = item.getItemId();
if (itemId == R.id.action_addall) {
// Start an Intent that adds multiple items at once, by supplying the urls and titles as string array
// extras and setting the Intent action to ADD_MULTIPLE
Intent intent = new Intent("org.transdroid.ADD_MULTIPLE");
String[] urls = new String[checked.size()];
String[] titles = new String[checked.size()];
for (int i = 0; i < checked.size(); i++) {
urls[i] = checked.get(i).getTorrentUrl();
titles[i] = checked.get(i).getName();
}
intent.putExtra("TORRENT_URLS", urls);
intent.putExtra("TORRENT_TITLES", titles);
startActivity(intent);
mode.finish();
return true;
} else if (itemId == R.id.action_showdetails) {
SearchResult first = checked.get(0);
// Open the torrent's web page in the browser
Toast.makeText(getActivity(), getString(R.string.search_openingdetails, first), Toast.LENGTH_LONG)
.show();
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(first.getDetailsUrl())));
return true;
} else {
return false;
}
}
@Override
public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) {
selectionManagerMode.onItemCheckedStateChanged(mode, position, id, checked);
}
@Override
public void onDestroyActionMode(ActionMode mode) {
selectionManagerMode.onDestroyActionMode(mode);
}
};
}

19
core/src/org/transdroid/core/gui/search/SearchSetting.java

@ -0,0 +1,19 @@
package org.transdroid.core.gui.search;
import org.transdroid.core.gui.lists.SimpleListItem;
public interface SearchSetting extends SimpleListItem {
/**
* Should return a unique key for this search setting, so that it can be compared (using equals()) to other settings.
* @return A unique string identifying this search setting
*/
public String getKey();
/**
* Should return an URL (which may still be abstract and not the actual search URL) specific to the search site
* @return A clean URL directing to the search site, to, for example, get the favicon of the site
*/
public String getBaseUrl();
}

28
core/src/org/transdroid/core/gui/search/SearchSettingSelectionView.java

@ -0,0 +1,28 @@
package org.transdroid.core.gui.search;
import org.androidannotations.annotations.EViewGroup;
import org.androidannotations.annotations.ViewById;
import android.content.Context;
import android.widget.FrameLayout;
import android.widget.TextView;
/**
* View that shows, as part of the action bar spinner, which {@link SearchSetting} is currently chosen.
* @author Eric Kok
*/
@EViewGroup(resName = "actionbar_searchsite")
public class SearchSettingSelectionView extends FrameLayout {
@ViewById
protected TextView searchsiteText;
public SearchSettingSelectionView(Context context) {
super(context);
}
public void bind(SearchSetting searchSettingItem) {
searchsiteText.setText(searchSettingItem.getName());
}
}

43
core/src/org/transdroid/core/gui/search/SearchSettingsDropDownAdapter.java

@ -0,0 +1,43 @@
package org.transdroid.core.gui.search;
import java.util.List;
import org.transdroid.core.gui.lists.SimpleListItem;
import org.transdroid.core.gui.navigation.FilterListItemAdapter;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
/**
* List adapter that holds search settings, that is, web searches and in-app search sites, displayed as content to a
* Spinner instead of a ListView.
* @author Eric Kok
*/
public class SearchSettingsDropDownAdapter extends FilterListItemAdapter {
private final Context context;
protected SearchSettingSelectionView searchSettingView = null;
public SearchSettingsDropDownAdapter(Context context, List<? extends SimpleListItem> items) {
super(context, items);
this.context = context;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// This returns the item to show in the action bar spinner
if (searchSettingView == null) {
searchSettingView = SearchSettingSelectionView_.build(context);
}
searchSettingView.bind((SearchSetting) getItem(position));
return searchSettingView;
}
@Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
// This returns the item to show in the drop down list
return super.getView(position, convertView, parent);
}
}

49
core/src/org/transdroid/core/gui/search/SearchSiteView.java

@ -0,0 +1,49 @@
package org.transdroid.core.gui.search;
import org.androidannotations.annotations.Bean;
import org.androidannotations.annotations.EViewGroup;
import org.androidannotations.annotations.ViewById;
import org.transdroid.core.app.settings.RssfeedSetting;
import org.transdroid.core.gui.navigation.NavigationHelper;
import android.content.Context;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
/**
* View that represents some {@link RssfeedSetting} object and displays name as well as loads a favicon for the feed's
* site and can load how many new items are available.
* @author Eric Kok
*/
@EViewGroup(resName = "list_item_searchsite")
public class SearchSiteView extends LinearLayout {
private static final String GETFVO_URL = "http://g.etfv.co/%1$s";
@Bean
protected NavigationHelper navigationHelper;
// Views
@ViewById
protected ImageView faviconImage;
@ViewById
protected TextView nameText;
public SearchSiteView(Context context) {
super(context);
}
public void bind(SearchSetting rssfeedLoader) {
// Show the RSS feed name and either a loading indicator or the number of new items
nameText.setText(rssfeedLoader.getName());
// Clear and then asynchronously load the site's favicon
// Uses the g.etfv.co service to resolve the favicon of any URL
faviconImage.setImageDrawable(null);
navigationHelper.getImageCache().displayImage(String.format(GETFVO_URL, rssfeedLoader.getBaseUrl()),
faviconImage);
}
}

72
core/src/org/transdroid/core/gui/search/SearchSitesAdapter.java

@ -0,0 +1,72 @@
package org.transdroid.core.gui.search;
import java.util.List;
import org.androidannotations.annotations.EBean;
import org.androidannotations.annotations.RootContext;
import org.transdroid.core.app.search.SearchSite;
import org.transdroid.core.app.settings.WebsearchSetting;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
/**
* Adapter that contains a list of {@link SearchSetting}s, either {@link SearchSite} or {@link WebsearchSetting}.
* @author Eric Kok
*/
@EBean
public class SearchSitesAdapter extends BaseAdapter {
private List<SearchSetting> sites = null;
@RootContext
protected Context context;
/**
* Allows updating the full internal list of sites at once, replacing the old list
* @param sites The new list of search sites, either in-app or web search settings
*/
public void update(List<SearchSetting> sites) {
this.sites = sites;
notifyDataSetChanged();
}
@Override
public boolean hasStableIds() {
return true;
}
@Override
public int getCount() {
if (sites == null)
return 0;
return sites.size();
}
@Override
public SearchSetting getItem(int position) {
if (sites == null)
return null;
return sites.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
SearchSiteView rssfeedView;
if (convertView == null) {
rssfeedView = SearchSiteView_.build(context);
} else {
rssfeedView = (SearchSiteView) convertView;
}
rssfeedView.bind(getItem(position));
return rssfeedView;
}
}

61
core/src/org/transdroid/core/gui/search/SendIntentHelper.java

@ -0,0 +1,61 @@
package org.transdroid.core.gui.search;
import android.content.Intent;
/**
* Used to clean up text as received from a generic ACTION_SEND intent. This class is highly custom-based for known
* applications, i.e. the EXTRA_TEXT send by some known applications.
* @author Eric Kok
*/
public class SendIntentHelper {
private static final String SOUNDHOUND1 = "Just used #SoundHound to find ";
private static final String SOUNDHOUND1_END = " http://";
private static final String SHAZAM = "I just used Shazam to discover ";
private static final String SHAZAM_END = ". http://";
private static final String YOUTUBE_ID = "Watch \"";
private static final String YOUTUBE_START = "\"";
private static final String YOUTUBE_END = "\"";
/**
* Cleans a SEND intent text string by removing irrelevant parts, so that the remaining text can be used as search
* string. Typically deals with specific known applications such as Shazam and YouTube's SEND intents.
* @param intent The original SEND intent that was received
* @return A cleaned string to be used as search query
*/
public static String cleanUpText(Intent intent) {
if (intent == null || !intent.hasExtra(Intent.EXTRA_TEXT)) {
return null;
}
String text = intent.getStringExtra(Intent.EXTRA_TEXT);
try {
// Soundhound song/artist share
if (text.startsWith(SOUNDHOUND1)) {
return cutOut(text, SOUNDHOUND1, SOUNDHOUND1_END).replace(" by ", " ");
}
// Shazam song share
if (text.startsWith(SHAZAM)) {
return cutOut(text, SHAZAM, SHAZAM_END).replace(" by ", " ");
}
// YouTube app share (stores title in EXTRA_SUBJECT)
if (intent.hasExtra(Intent.EXTRA_SUBJECT)) {
String subject = intent.getStringExtra(Intent.EXTRA_SUBJECT);
if (subject.startsWith(YOUTUBE_ID)) {
return cutOut(subject, YOUTUBE_START, YOUTUBE_END);
}
}
} catch (Exception e) {
// Ignore any errors in parsing; just return the raw text
}
return text;
}
private static String cutOut(String text, String start, String end) {
int startAt = text.indexOf(start) + start.length();
return text.substring(startAt, text.indexOf(end, startAt));
}
}

26
core/src/org/transdroid/core/gui/search/TorrentSearchHistoryProvider.java

@ -0,0 +1,26 @@
package org.transdroid.core.gui.search;
import android.content.Context;
import android.content.SearchRecentSuggestionsProvider;
import android.provider.SearchRecentSuggestions;
/**
* Provides a wrapper for the {@link SearchRecentSuggestionsProvider} to show the last torrent searches to the user.
* @author Eric Kok
*/
public class TorrentSearchHistoryProvider extends SearchRecentSuggestionsProvider {
public static final String AUTHORITY = "org.transdroid.core.gui.search.TorrentSearchHistoryProvider";
public static final int MODE = DATABASE_MODE_QUERIES;
public TorrentSearchHistoryProvider() {
super();
setupSuggestions(AUTHORITY, MODE);
}
public static void clearHistory(Context context) {
SearchRecentSuggestions suggestions = new SearchRecentSuggestions(context,
TorrentSearchHistoryProvider.AUTHORITY, TorrentSearchHistoryProvider.MODE);
suggestions.clearHistory();
}
}

30
full/AndroidManifest.xml

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.transdroid.full" package="org.transdroid.full"
android:versionCode="1" android:versionCode="2"
android:versionName="2.0-alpha1" > android:versionName="2.0-alpha2" >
<uses-sdk <uses-sdk
android:minSdkVersion="7" android:minSdkVersion="7"
@ -146,10 +146,9 @@
<data android:scheme="magnet" /> <data android:scheme="magnet" />
</intent-filter> </intent-filter>
<meta-data <meta-data
android:name="android.app.default_searchable" android:name="android.app.default_searchable"
android:value="org.transdroid.core.gui.SearchActivity_" /> android:value="org.transdroid.core.gui.search.SearchActivity_" />
</activity> </activity>
<activity <activity
android:name="org.transdroid.core.gui.DetailsActivity_" android:name="org.transdroid.core.gui.DetailsActivity_"
@ -168,10 +167,11 @@
<!-- Search --> <!-- Search -->
<activity <activity
android:name="org.transdroid.core.gui.SearchActivity_" android:name="org.transdroid.core.gui.search.SearchActivity_"
android:icon="@drawable/ic_launcher" android:icon="@drawable/ic_launcher"
android:label="@string/search_torrentsearch" android:label="@string/search_torrentsearch"
android:theme="@style/TransdroidTheme" > android:theme="@style/TransdroidTheme"
android:launchMode="singleTask" >
<intent-filter> <intent-filter>
<action android:name="android.intent.action.SEARCH" /> <action android:name="android.intent.action.SEARCH" />
@ -185,13 +185,17 @@
<data android:mimeType="text/plain" /> <data android:mimeType="text/plain" />
</intent-filter> </intent-filter>
<meta-data
android:name="android.app.default_searchable"
android:value="org.transdroid.gui.search.Search" />
<meta-data <meta-data
android:name="android.app.searchable" android:name="android.app.searchable"
android:resource="@xml/searchable" /> android:resource="@xml/searchable" />
<meta-data
android:name="android.app.default_searchable"
android:value="org.transdroid.core.gui.search.SearchActivity_" />
</activity> </activity>
<provider
android:name="org.transdroid.core.gui.search.TorrentSearchHistoryProvider"
android:authorities="org.transdroid.core.gui.search.TorrentSearchHistoryProvider"
android:exported="false" />
<!-- RSS --> <!-- RSS -->
<activity <activity
@ -203,14 +207,6 @@
android:label="@string/rss_feeds" android:label="@string/rss_feeds"
android:theme="@style/TransdroidTheme" /> android:theme="@style/TransdroidTheme" />
<provider
android:name="org.transdroid.core.gui.SearchHistoryProvider"
android:authorities="org.transdroid.core.gui.SearchHistoryProvider"
android:exported="false" />
<meta-data
android:name="android.app.default_searchable"
android:value="org.transdroid.core.gui.SearchActivity_" />
</application> </application>
</manifest> </manifest>

4
lite/AndroidManifest.xml

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.transdroid.lite" package="org.transdroid.lite"
android:versionCode="1" android:versionCode="2"
android:versionName="2.0-alpha1" > android:versionName="2.0-alpha2" >
<uses-sdk <uses-sdk
android:minSdkVersion="7" android:minSdkVersion="7"

Loading…
Cancel
Save