Eric Kok
12 years ago
69 changed files with 1850 additions and 422 deletions
@ -0,0 +1,16 @@
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<!-- This layout is for phones in portrait and shows only the torrents list. --> |
||||
<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=".DetailsActivity" > |
||||
|
||||
<fragment |
||||
android:id="@+id/torrent_details" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="match_parent" |
||||
class="org.transdroid.core.gui.DetailsFragment_" |
||||
tools:layout="@layout/fragment_details" /> |
||||
|
||||
</FrameLayout> |
@ -0,0 +1,58 @@
@@ -0,0 +1,58 @@
|
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<fr.marvinlabs.widget.CheckableRelativeLayout |
||||
xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:layout_width="fill_parent" |
||||
android:layout_height="wrap_content" |
||||
android:orientation="vertical" |
||||
android:layout_marginTop="@dimen/margin_half" |
||||
android:layout_marginBottom="@dimen/margin_half" |
||||
android:layout_marginLeft="@dimen/margin_half" |
||||
android:layout_marginRight="@dimen/margin_default"> |
||||
|
||||
<fr.marvinlabs.widget.InertCheckBox |
||||
android:id="@+id/file_checkbox" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" /> |
||||
|
||||
<TextView |
||||
android:id="@+id/name_text" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:layout_alignParentTop="true" |
||||
android:layout_toRightOf="@+id/file_checkbox" |
||||
android:textColor="#fff" |
||||
android:textIsSelectable="true" |
||||
android:textSize="15sp" /> |
||||
|
||||
<TextView |
||||
android:id="@+id/progress_text" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:layout_below="@id/name_text" |
||||
android:layout_alignParentRight="true" |
||||
android:layout_marginLeft="@dimen/margin_half" |
||||
android:layout_marginTop="4dip" |
||||
android:textSize="12sp" |
||||
android:textIsSelectable="false" /> |
||||
|
||||
<TextView |
||||
android:id="@+id/sizes_text" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:layout_alignBaseline="@+id/progress_text" |
||||
android:layout_alignBottom="@+id/progress_text" |
||||
android:layout_toRightOf="@+id/priority_image" |
||||
android:textIsSelectable="false" |
||||
android:textSize="12sp" /> |
||||
|
||||
<ImageView |
||||
android:id="@+id/priority_image" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:layout_alignLeft="@+id/name_text" |
||||
android:layout_below="@+id/name_text" |
||||
android:layout_marginTop="4dip" |
||||
android:layout_marginRight="@dimen/margin_half" |
||||
android:contentDescription="@string/status_priority_normal" /> |
||||
|
||||
</fr.marvinlabs.widget.CheckableRelativeLayout> |
@ -0,0 +1,9 @@
@@ -0,0 +1,9 @@
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android" > |
||||
|
||||
<item |
||||
android:id="@+id/action_refresh" |
||||
android:icon="@drawable/ic_action_refresh" |
||||
android:showAsAction="always" |
||||
android:title="@string/action_refresh"/> |
||||
|
||||
</menu> |
@ -0,0 +1,8 @@
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
|
||||
<searchable xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:label="@string/search_torrentsearch" |
||||
android:hint="@string/search_hint" |
||||
android:searchSuggestAuthority="org.transdroid.core.gui.SearchHistoryProvider" |
||||
android:searchSuggestSelection=" ? " /> |
||||
|
@ -1,4 +1,4 @@
@@ -1,4 +1,4 @@
|
||||
package org.transdroid.lite.app.search; |
||||
package org.transdroid.core.app.search; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.List; |
@ -1,4 +1,4 @@
@@ -1,4 +1,4 @@
|
||||
package org.transdroid.lite.app.search; |
||||
package org.transdroid.core.app.search; |
||||
|
||||
import java.util.Date; |
||||
|
@ -1,12 +1,12 @@
@@ -1,12 +1,12 @@
|
||||
package org.transdroid.lite.app.search; |
||||
package org.transdroid.core.app.search; |
||||
|
||||
import org.transdroid.lite.gui.navigation.FilterItem; |
||||
import org.transdroid.core.gui.lists.SimpleListItem; |
||||
|
||||
/** |
||||
* Represents an available torrent site that can be searched using the Torrent Search package. |
||||
* @author Eric Kok |
||||
*/ |
||||
public class SearchSite implements FilterItem { |
||||
public class SearchSite implements SimpleListItem { |
||||
|
||||
private final int id; |
||||
private final String key; |
@ -1,4 +1,4 @@
@@ -1,4 +1,4 @@
|
||||
package org.transdroid.lite.app.settings; |
||||
package org.transdroid.core.app.settings; |
||||
|
||||
import org.androidannotations.annotations.EBean; |
||||
import org.androidannotations.annotations.RootContext; |
@ -1,4 +1,4 @@
@@ -1,4 +1,4 @@
|
||||
package org.transdroid.lite.app.settings; |
||||
package org.transdroid.core.app.settings; |
||||
|
||||
import org.androidannotations.annotations.EBean; |
||||
import org.androidannotations.annotations.EBean.Scope; |
@ -0,0 +1,132 @@
@@ -0,0 +1,132 @@
|
||||
package org.transdroid.core.gui; |
||||
|
||||
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.EActivity; |
||||
import org.androidannotations.annotations.Extra; |
||||
import org.androidannotations.annotations.FragmentById; |
||||
import org.androidannotations.annotations.InstanceState; |
||||
import org.androidannotations.annotations.OptionsItem; |
||||
import org.androidannotations.annotations.OptionsMenu; |
||||
import org.androidannotations.annotations.UiThread; |
||||
import org.transdroid.core.R; |
||||
import org.transdroid.core.app.settings.ApplicationSettings; |
||||
import org.transdroid.core.app.settings.ServerSetting; |
||||
import org.transdroid.core.gui.lists.LocalTorrent; |
||||
import org.transdroid.daemon.IDaemonAdapter; |
||||
import org.transdroid.daemon.Torrent; |
||||
import org.transdroid.daemon.TorrentDetails; |
||||
import org.transdroid.daemon.TorrentFile; |
||||
import org.transdroid.daemon.task.DaemonTaskFailureResult; |
||||
import org.transdroid.daemon.task.DaemonTaskResult; |
||||
import org.transdroid.daemon.task.GetFileListTask; |
||||
import org.transdroid.daemon.task.GetFileListTaskSuccessResult; |
||||
import org.transdroid.daemon.task.GetTorrentDetailsTask; |
||||
import org.transdroid.daemon.task.GetTorrentDetailsTaskSuccessResult; |
||||
import org.transdroid.daemon.task.RetrieveTask; |
||||
import org.transdroid.daemon.task.RetrieveTaskSuccessResult; |
||||
|
||||
import android.widget.Toast; |
||||
|
||||
import com.actionbarsherlock.app.SherlockFragmentActivity; |
||||
|
||||
@EActivity(R.layout.activity_details) |
||||
@OptionsMenu(R.menu.activity_details) |
||||
public class DetailsActivity extends SherlockFragmentActivity { |
||||
|
||||
@Extra |
||||
@InstanceState |
||||
protected Torrent torrent; |
||||
|
||||
// Settings
|
||||
@Bean |
||||
protected ApplicationSettings applicationSettings; |
||||
private IDaemonAdapter currentConnection = null; |
||||
|
||||
// Details view components
|
||||
@FragmentById(R.id.torrent_details) |
||||
protected DetailsFagment fragmentDetails; |
||||
|
||||
@AfterViews |
||||
protected void init() { |
||||
|
||||
// Simple action bar with up, torrent name as title and refresh button
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true); |
||||
getSupportActionBar().setTitle(torrent.getName()); |
||||
|
||||
// Connect to the last used server
|
||||
ServerSetting lastUsed = applicationSettings.getLastUsedServer(); |
||||
currentConnection = lastUsed.createServerAdapter(); |
||||
|
||||
// Load fine details and torrent files
|
||||
refreshTorrentDetails(); |
||||
|
||||
} |
||||
|
||||
@OptionsItem(R.id.action_refresh) |
||||
protected void refreshScreen() { |
||||
refreshTorrent(); |
||||
refreshTorrentDetails(); |
||||
refreshTorrentFiles(); |
||||
} |
||||
|
||||
@Background |
||||
protected void refreshTorrent() { |
||||
DaemonTaskResult result = RetrieveTask.create(currentConnection).execute(); |
||||
if (result instanceof RetrieveTaskSuccessResult) { |
||||
onTorrentsRetrieved(((RetrieveTaskSuccessResult) result).getTorrents(), ((RetrieveTaskSuccessResult) result).getLabels()); |
||||
} else { |
||||
onCommunicationError((DaemonTaskFailureResult)result); |
||||
} |
||||
} |
||||
|
||||
@UiThread |
||||
protected void onTorrentsRetrieved(List<Torrent> torrents, List<org.transdroid.daemon.Label> labels) { |
||||
// Update the details fragment
|
||||
fragmentDetails.perhapsUpdateTorrent(torrents); |
||||
} |
||||
|
||||
@Background |
||||
protected void refreshTorrentDetails() { |
||||
DaemonTaskResult result = GetTorrentDetailsTask.create(currentConnection, torrent).execute(); |
||||
if (result instanceof GetTorrentDetailsTaskSuccessResult) { |
||||
onTorrentDetailsRetrieved(((GetTorrentDetailsTaskSuccessResult) result).getTorrentDetails()); |
||||
} else { |
||||
onCommunicationError((DaemonTaskFailureResult)result); |
||||
} |
||||
} |
||||
|
||||
@UiThread |
||||
protected void onTorrentDetailsRetrieved(TorrentDetails torrentDetails) { |
||||
// Update the details fragment with the new fine details for the shown torrent
|
||||
fragmentDetails.updateTorrentDetails(torrentDetails); |
||||
} |
||||
|
||||
@Background |
||||
protected void refreshTorrentFiles() { |
||||
DaemonTaskResult result = GetFileListTask.create(currentConnection, torrent).execute(); |
||||
if (result instanceof GetFileListTaskSuccessResult) { |
||||
onTorrentFilesRetrieved(((GetFileListTaskSuccessResult) result).getFiles()); |
||||
} else { |
||||
onCommunicationError((DaemonTaskFailureResult)result); |
||||
} |
||||
} |
||||
|
||||
@UiThread |
||||
protected void onTorrentFilesRetrieved(List<TorrentFile> torrentFiles) { |
||||
// Update the details fragment with the newly retrieved list of files
|
||||
fragmentDetails.updateTorrentFiles(new ArrayList<TorrentFile>(torrentFiles)); |
||||
} |
||||
|
||||
@UiThread |
||||
protected void onCommunicationError(DaemonTaskFailureResult result) { |
||||
// TODO: Properly report this error
|
||||
Toast.makeText(this, getString(LocalTorrent.getResourceForDaemonException(result.getException())), |
||||
Toast.LENGTH_LONG).show(); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,113 @@
@@ -0,0 +1,113 @@
|
||||
package org.transdroid.core.gui; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
import org.androidannotations.annotations.AfterViews; |
||||
import org.androidannotations.annotations.EFragment; |
||||
import org.androidannotations.annotations.InstanceState; |
||||
import org.androidannotations.annotations.ViewById; |
||||
import org.transdroid.core.R; |
||||
import org.transdroid.core.gui.lists.DetailsAdapter; |
||||
import org.transdroid.core.gui.lists.SimpleListItemAdapter; |
||||
import org.transdroid.daemon.Torrent; |
||||
import org.transdroid.daemon.TorrentDetails; |
||||
import org.transdroid.daemon.TorrentFile; |
||||
|
||||
import android.widget.TextView; |
||||
|
||||
import com.actionbarsherlock.app.SherlockFragment; |
||||
import com.actionbarsherlock.view.SherlockListView; |
||||
|
||||
/** |
||||
* Fragment that shown detailed statistics about some torrent. These come from some already fetched {@link Torrent} |
||||
* object, but it also retrieves further detailed statistics. |
||||
* @author Eric Kok |
||||
*/ |
||||
@EFragment(R.layout.fragment_details) |
||||
public class DetailsFagment extends SherlockFragment { |
||||
|
||||
// Local data
|
||||
@InstanceState |
||||
protected Torrent torrent = null; |
||||
@InstanceState |
||||
protected TorrentDetails torrentDetails = null; |
||||
@InstanceState |
||||
protected ArrayList<TorrentFile> torrentFiles = null; |
||||
|
||||
// Views
|
||||
@ViewById(R.id.details_list) |
||||
protected SherlockListView detailsList; |
||||
@ViewById |
||||
protected TextView emptyText; |
||||
|
||||
@AfterViews |
||||
protected void init() { |
||||
|
||||
detailsList.setAdapter(new DetailsAdapter()); |
||||
detailsList.setEmptyView(emptyText); // Shows a text that no torrent was selected yet
|
||||
if (torrent != null) |
||||
updateTorrent(torrent); |
||||
if (torrentDetails != null) |
||||
updateTorrentDetails(torrentDetails); |
||||
if (torrentFiles != null) |
||||
updateTorrentFiles(torrentFiles); |
||||
|
||||
} |
||||
|
||||
/** |
||||
* Updates the details adapter header to show the new torrent data |
||||
* @param newTorrent The new torrent object |
||||
*/ |
||||
public void updateTorrent(Torrent newTorrent) { |
||||
this.torrent = newTorrent; |
||||
((DetailsAdapter) detailsList.getAdapter()).updateTorrent(newTorrent); |
||||
} |
||||
|
||||
/** |
||||
* Updates the details adapter to show the list of trackers and tracker errors |
||||
* @param newTorrentDetails The new fine details object of some torrent |
||||
*/ |
||||
public void updateTorrentDetails(TorrentDetails newTorrentDetails) { |
||||
this.torrentDetails = newTorrentDetails; |
||||
((DetailsAdapter) detailsList.getAdapter()).updateTrackers(SimpleListItemAdapter.SimpleStringItem |
||||
.wrapStringsList(newTorrentDetails.getTrackers())); |
||||
((DetailsAdapter) detailsList.getAdapter()).updateErrors(SimpleListItemAdapter.SimpleStringItem |
||||
.wrapStringsList(newTorrentDetails.getErrors())); |
||||
} |
||||
|
||||
/** |
||||
* Updates the list adapter to show a new list of torrent files, replacing the old files list |
||||
* @param newTorrents The new, updated list of torrent file objects |
||||
*/ |
||||
public void updateTorrentFiles(ArrayList<TorrentFile> newTorrentFiles) { |
||||
this.torrentFiles = newTorrentFiles; |
||||
((DetailsAdapter) detailsList.getAdapter()).updateTorrentFiles(newTorrentFiles); |
||||
} |
||||
|
||||
/** |
||||
* Can be called if some outside activity returned new torrents, so we can perhaps piggyback on this by update our |
||||
* data as well |
||||
* @param torrents The last of retrieved torrents |
||||
*/ |
||||
public void perhapsUpdateTorrent(List<Torrent> torrents) { |
||||
for (Torrent newTorrent : torrents) { |
||||
if (newTorrent.getUniqueID().equals(this.torrent.getUniqueID())) { |
||||
// Found, so we can update our data as well
|
||||
updateTorrent(newTorrent); |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Clear the screen by fully clearing the internal merge list (with header and other lists) |
||||
*/ |
||||
public void clear() { |
||||
detailsList.setAdapter(new DetailsAdapter()); |
||||
torrent = null; |
||||
torrentDetails = null; |
||||
torrentFiles = null; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,22 @@
@@ -0,0 +1,22 @@
|
||||
package org.transdroid.core.gui; |
||||
|
||||
import android.content.Context; |
||||
import android.content.SearchRecentSuggestionsProvider; |
||||
import android.provider.SearchRecentSuggestions; |
||||
|
||||
public class SearchHistoryProvider extends SearchRecentSuggestionsProvider { |
||||
|
||||
public final static String AUTHORITY = "org.transdroid.core.gui.SearchHistoryProvider"; |
||||
public final static int MODE = DATABASE_MODE_QUERIES; |
||||
|
||||
public SearchHistoryProvider() { |
||||
super(); |
||||
setupSuggestions(AUTHORITY, MODE); |
||||
} |
||||
|
||||
public static void clearHistory(Context context) { |
||||
SearchRecentSuggestions suggestions = new SearchRecentSuggestions(context, |
||||
SearchHistoryProvider.AUTHORITY, SearchHistoryProvider.MODE); |
||||
suggestions.clearHistory(); |
||||
} |
||||
} |
@ -0,0 +1,253 @@
@@ -0,0 +1,253 @@
|
||||
package org.transdroid.core.gui; |
||||
|
||||
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.EActivity; |
||||
import org.androidannotations.annotations.FragmentById; |
||||
import org.androidannotations.annotations.InstanceState; |
||||
import org.androidannotations.annotations.OptionsItem; |
||||
import org.androidannotations.annotations.OptionsMenu; |
||||
import org.androidannotations.annotations.SystemService; |
||||
import org.androidannotations.annotations.UiThread; |
||||
import org.androidannotations.annotations.ViewById; |
||||
import org.transdroid.core.R; |
||||
import org.transdroid.core.app.settings.ApplicationSettings; |
||||
import org.transdroid.core.app.settings.ServerSetting; |
||||
import org.transdroid.core.gui.lists.LocalTorrent; |
||||
import org.transdroid.core.gui.lists.SimpleListItem; |
||||
import org.transdroid.core.gui.navigation.FilterListAdapter; |
||||
import org.transdroid.core.gui.navigation.FilterListAdapter_; |
||||
import org.transdroid.core.gui.navigation.Label; |
||||
import org.transdroid.core.gui.navigation.NavigationHelper; |
||||
import org.transdroid.core.gui.navigation.StatusType; |
||||
import org.transdroid.core.gui.navigation.StatusType.StatusTypeFilter; |
||||
import org.transdroid.daemon.IDaemonAdapter; |
||||
import org.transdroid.daemon.Torrent; |
||||
import org.transdroid.daemon.task.DaemonTaskFailureResult; |
||||
import org.transdroid.daemon.task.DaemonTaskResult; |
||||
import org.transdroid.daemon.task.RetrieveTask; |
||||
import org.transdroid.daemon.task.RetrieveTaskSuccessResult; |
||||
|
||||
import android.annotation.TargetApi; |
||||
import android.app.SearchManager; |
||||
import android.os.Build; |
||||
import android.view.View; |
||||
import android.widget.AdapterView; |
||||
import android.widget.AdapterView.OnItemSelectedListener; |
||||
import android.widget.Toast; |
||||
|
||||
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; |
||||
|
||||
@EActivity(R.layout.activity_torrents) |
||||
@OptionsMenu(R.menu.activity_torrents) |
||||
public class TorrentsActivity extends SherlockFragmentActivity implements OnNavigationListener { |
||||
|
||||
// Navigation components
|
||||
@Bean |
||||
protected NavigationHelper navigationHelper; |
||||
@ViewById |
||||
protected SherlockListView filtersList; |
||||
protected FilterListAdapter navigationListAdapter = null; |
||||
protected FilterListAdapter navigationSpinnerAdapter = null; |
||||
@SystemService |
||||
protected SearchManager searchManager; |
||||
|
||||
// Settings
|
||||
@Bean |
||||
protected ApplicationSettings applicationSettings; |
||||
@InstanceState |
||||
boolean firstStart = true; |
||||
private IDaemonAdapter currentConnection = null; |
||||
|
||||
// Torrents list components
|
||||
@FragmentById(R.id.torrent_list) |
||||
protected TorrentsFragment fragmentTorrents; |
||||
|
||||
// Details view components
|
||||
@FragmentById(R.id.torrent_details) |
||||
protected DetailsFagment fragmentDetails; |
||||
|
||||
@AfterViews |
||||
protected void init() { |
||||
|
||||
// Set up navigation, with an action bar spinner and possibly (if room) with a filter list
|
||||
getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_LIST); |
||||
getSupportActionBar().setHomeButtonEnabled(false); |
||||
navigationSpinnerAdapter = FilterListAdapter_.getInstance_(this); |
||||
// Servers are always added to the action bar spinner
|
||||
navigationSpinnerAdapter.updateServers(applicationSettings.getServerSettings()); |
||||
getSupportActionBar().setListNavigationCallbacks(navigationSpinnerAdapter, this); |
||||
if (filtersList != null) { |
||||
// There was room for a dedicated filter list; add the status types
|
||||
navigationListAdapter = FilterListAdapter_.getInstance_(this); |
||||
filtersList.setAdapter(navigationListAdapter); |
||||
navigationListAdapter.updateStatusTypes(StatusType.getAllStatusTypes(this)); |
||||
filtersList.setOnItemSelectedListener(onFilterListItemSelected); |
||||
} else { |
||||
// Add status types directly to the action bar spinner
|
||||
navigationSpinnerAdapter.updateStatusTypes(StatusType.getAllStatusTypes(this)); |
||||
} |
||||
|
||||
// Connect to the last used server
|
||||
ServerSetting lastUsed = applicationSettings.getLastUsedServer(); |
||||
if (lastUsed == null) { |
||||
// No server settings yet;
|
||||
return; |
||||
} |
||||
// Set this as selection in the action bar spinner; we can use the server setting key since we have stable ids
|
||||
// TODO: Does this call the action bar item selection callback?
|
||||
getSupportActionBar().setSelectedNavigationItem(lastUsed.getOrder()); |
||||
|
||||
// Handle any start up intents or instead just refresh the torrents list
|
||||
if (firstStart) { |
||||
handleStartIntent(); |
||||
} else { |
||||
refreshTorrents(); |
||||
} |
||||
|
||||
} |
||||
|
||||
@Override |
||||
protected void onResume() { |
||||
super.onResume(); |
||||
refreshTorrents(); |
||||
} |
||||
|
||||
@TargetApi(Build.VERSION_CODES.FROYO) |
||||
@Override |
||||
public boolean onCreateOptionsMenu(Menu menu) { |
||||
super.onCreateOptionsMenu(menu); |
||||
// 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; |
||||
} |
||||
|
||||
/** |
||||
* Called when an item in the action bar navigation spinner was selected |
||||
*/ |
||||
@Override |
||||
public boolean onNavigationItemSelected(int itemPosition, long itemId) { |
||||
Object item = navigationSpinnerAdapter.getItem(itemPosition); |
||||
if (item instanceof SimpleListItem) { |
||||
// A filter item was selected form the navigation spinner
|
||||
filterSelected((SimpleListItem) item); |
||||
return true; |
||||
} |
||||
// A header was selected; no action
|
||||
return false; |
||||
} |
||||
|
||||
// Handles clicks (selections) on the dedicated list of filter items (if it exists)
|
||||
// NOTE: Unfortunately we cannot use the @ItemSelect(R.id.filters_list) annotation as it throws NPE exceptions when
|
||||
// the list doesn't exist (read: on small screens)
|
||||
protected OnItemSelectedListener onFilterListItemSelected = new OnItemSelectedListener() { |
||||
@Override |
||||
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { |
||||
filterSelected((SimpleListItem) filtersList.getAdapter().getItem(position)); |
||||
} |
||||
@Override |
||||
public void onNothingSelected(AdapterView<?> parent) { |
||||
// TODO: Check if this happens
|
||||
} |
||||
}; |
||||
|
||||
/** |
||||
* A new filter was selected; update the view over the current data |
||||
* @param selected True if the filter item was selected, false if it was deselected |
||||
* @param item The touched filter item |
||||
*/ |
||||
protected void filterSelected(SimpleListItem item) { |
||||
|
||||
// Server selection
|
||||
if (item instanceof ServerSetting) { |
||||
ServerSetting server = (ServerSetting) item; |
||||
|
||||
if (currentConnection != null && server.equals(currentConnection.getSettings())) { |
||||
// Already connected to this server; just ask for a refresh instead
|
||||
refreshTorrents(); |
||||
return; |
||||
} |
||||
|
||||
// Update connection to the newly selected server and refresh
|
||||
currentConnection = server.createServerAdapter(); |
||||
clearScreens(); |
||||
refreshTorrents(); |
||||
|
||||
} |
||||
|
||||
if (item instanceof StatusTypeFilter) { |
||||
// TODO: Update the torrent list view
|
||||
} |
||||
|
||||
if (item instanceof Label) { |
||||
// TODO: Update the torrent list view
|
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* If required, add torrents, switch to a specific server, etc. |
||||
*/ |
||||
protected void handleStartIntent() { |
||||
// TODO: Handle start intent
|
||||
} |
||||
|
||||
@OptionsItem(R.id.action_refresh) |
||||
protected void refreshScreen() { |
||||
refreshTorrents(); |
||||
// TODO: Refresh TorentDetails and TorrentFiles as well
|
||||
} |
||||
|
||||
private void clearScreens() { |
||||
// Clear the currently shown list of torrent and perhaps the details
|
||||
fragmentTorrents.clear(); |
||||
if (fragmentDetails != null) { |
||||
fragmentDetails.clear(); |
||||
} |
||||
} |
||||
|
||||
@Background |
||||
protected void refreshTorrents() { |
||||
DaemonTaskResult result = RetrieveTask.create(currentConnection).execute(); |
||||
if (result instanceof RetrieveTaskSuccessResult) { |
||||
onTorrentsRetrieved(((RetrieveTaskSuccessResult) result).getTorrents(), ((RetrieveTaskSuccessResult) result).getLabels()); |
||||
} else { |
||||
onCommunicationError((DaemonTaskFailureResult)result); |
||||
} |
||||
} |
||||
|
||||
@UiThread |
||||
protected void onTorrentsRetrieved(List<Torrent> torrents, List<org.transdroid.daemon.Label> labels) { |
||||
// Report the newly retrieved list of torrents to the torrents fragment
|
||||
fragmentTorrents.updateTorrents(new ArrayList<Torrent>(torrents)); |
||||
// Update the details fragment if the currently shown torrent is in the newly retrieved list
|
||||
if (fragmentDetails != null) { |
||||
fragmentDetails.perhapsUpdateTorrent(torrents); |
||||
} |
||||
// TODO: Update local list of labels
|
||||
} |
||||
|
||||
@UiThread |
||||
protected void onCommunicationError(DaemonTaskFailureResult result) { |
||||
// TODO: Properly report this error
|
||||
Toast.makeText(this, getString(LocalTorrent.getResourceForDaemonException(result.getException())), |
||||
Toast.LENGTH_LONG).show(); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,69 @@
@@ -0,0 +1,69 @@
|
||||
package org.transdroid.core.gui; |
||||
|
||||
import java.util.ArrayList; |
||||
|
||||
import org.androidannotations.annotations.AfterViews; |
||||
import org.androidannotations.annotations.EFragment; |
||||
import org.androidannotations.annotations.InstanceState; |
||||
import org.androidannotations.annotations.ItemClick; |
||||
import org.androidannotations.annotations.ViewById; |
||||
import org.transdroid.core.R; |
||||
import org.transdroid.core.gui.lists.TorrentsAdapter; |
||||
import org.transdroid.daemon.Torrent; |
||||
|
||||
import android.view.View; |
||||
import android.widget.TextView; |
||||
|
||||
import com.actionbarsherlock.app.SherlockFragment; |
||||
import com.actionbarsherlock.view.SherlockListView; |
||||
|
||||
@EFragment(R.layout.fragment_torrents) |
||||
public class TorrentsFragment extends SherlockFragment { |
||||
|
||||
// Local data
|
||||
@InstanceState |
||||
protected ArrayList<Torrent> torrents = null; |
||||
|
||||
// Views
|
||||
@ViewById(R.id.torrent_list) |
||||
protected SherlockListView torrentsList; |
||||
@ViewById |
||||
protected TextView emptyText; |
||||
|
||||
@AfterViews |
||||
protected void init() { |
||||
torrentsList.setAdapter(new TorrentsAdapter()); |
||||
torrentsList.setEmptyView(emptyText); |
||||
if (torrents != null) |
||||
updateTorrents(torrents); |
||||
} |
||||
|
||||
/** |
||||
* Updates the list adapter to show a new list of torrent objects, replacing the old torrents completely |
||||
* @param newTorrents The new, updated list of torrents |
||||
*/ |
||||
public void updateTorrents(ArrayList<Torrent> newTorrents) { |
||||
torrents = newTorrents; |
||||
if (newTorrents == null) { |
||||
// Hide list adapter as well as empty text
|
||||
torrentsList.setVisibility(View.GONE); |
||||
emptyText.setVisibility(View.GONE); |
||||
} else { |
||||
((TorrentsAdapter)torrentsList.getAdapter()).update(newTorrents); |
||||
// NOTE: This will also make visible again the list or empty view
|
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Clear currently visible list of torrents |
||||
*/ |
||||
public void clear() { |
||||
updateTorrents(null); |
||||
} |
||||
|
||||
@ItemClick(R.id.torrent_list) |
||||
protected void torrentsListClicked(Torrent torrent) { |
||||
|
||||
} |
||||
|
||||
} |
@ -0,0 +1,141 @@
@@ -0,0 +1,141 @@
|
||||
package org.transdroid.core.gui.lists; |
||||
|
||||
import java.util.List; |
||||
|
||||
import org.androidannotations.annotations.EBean; |
||||
import org.androidannotations.annotations.RootContext; |
||||
import org.transdroid.core.R; |
||||
import org.transdroid.core.gui.navigation.FilterSeparatorView_; |
||||
import org.transdroid.daemon.Torrent; |
||||
import org.transdroid.daemon.TorrentFile; |
||||
|
||||
import android.content.Context; |
||||
import android.view.View; |
||||
import android.view.ViewGroup; |
||||
import android.widget.BaseAdapter; |
||||
|
||||
import com.commonsware.cwac.merge.MergeAdapter; |
||||
|
||||
/** |
||||
* List adapter that holds a header view showing torrent details and show the list list contained by the torrent. |
||||
* @author Eric Kok |
||||
*/ |
||||
@EBean |
||||
public class DetailsAdapter extends MergeAdapter { |
||||
|
||||
@RootContext |
||||
protected Context context; |
||||
private TorrentDetailsView torrentDetailsView = null; |
||||
private TorrentFilesAdapter torrentFilesAdapter = null; |
||||
private SimpleListItemAdapter trackersAdapter = null; |
||||
private SimpleListItemAdapter errorsAdapter = null; |
||||
|
||||
/** |
||||
* Update the torrent data in the details header of this merge adapter |
||||
* @param torrent The torrent for which detailed data is shown |
||||
*/ |
||||
public void updateTorrent(Torrent torrent) { |
||||
if (this.torrentDetailsView == null) { |
||||
torrentDetailsView = TorrentDetailsView_.build(context); |
||||
addView(torrentDetailsView, false); |
||||
} |
||||
torrentDetailsView.update(torrent); |
||||
} |
||||
|
||||
/** |
||||
* Update the list of files contained in this torrent |
||||
* @param torrentFiles The new list of files |
||||
*/ |
||||
public void updateTorrentFiles(List<TorrentFile> torrentFiles) { |
||||
if (this.torrentFilesAdapter == null && torrentFiles != null) { |
||||
addView(FilterSeparatorView_.build(context).setText(context.getString(R.string.status_files)), false); |
||||
this.torrentFilesAdapter = new TorrentFilesAdapter(context, torrentFiles); |
||||
addAdapter(torrentFilesAdapter); |
||||
} else if (this.torrentFilesAdapter != null && torrentFiles != null) { |
||||
this.torrentFilesAdapter.update(torrentFiles); |
||||
} else { |
||||
this.torrentFilesAdapter = null; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Update the list of trackers |
||||
* @param trackers The new list of trackers known for this torrent |
||||
*/ |
||||
public void updateTrackers(List<? extends SimpleListItem> trackers) { |
||||
if (this.trackersAdapter == null && trackers != null) { |
||||
addView(FilterSeparatorView_.build(context).setText(context.getString(R.string.status_trackers)), false); |
||||
this.trackersAdapter = new SimpleListItemAdapter(context, trackers); |
||||
addAdapter(trackersAdapter); |
||||
} else if (this.trackersAdapter != null && trackers != null) { |
||||
this.trackersAdapter.update(trackers); |
||||
} else { |
||||
this.trackersAdapter = null; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Update the list of errors |
||||
* @param errors The new list of errors known for this torrent |
||||
*/ |
||||
public void updateErrors(List<? extends SimpleListItem> errors) { |
||||
if (this.errorsAdapter == null && errors != null) { |
||||
addView(FilterSeparatorView_.build(context).setText(context.getString(R.string.status_errors)), false); |
||||
this.errorsAdapter = new SimpleListItemAdapter(context, errors); |
||||
addAdapter(errorsAdapter); |
||||
} else if (this.errorsAdapter != null && errors != null) { |
||||
this.errorsAdapter.update(errors); |
||||
} else { |
||||
this.errorsAdapter = null; |
||||
} |
||||
} |
||||
|
||||
protected class TorrentFilesAdapter extends BaseAdapter { |
||||
|
||||
private final Context context; |
||||
private List<TorrentFile> items; |
||||
|
||||
public TorrentFilesAdapter(Context context, List<TorrentFile> items) { |
||||
this.context = context; |
||||
this.items = items; |
||||
} |
||||
|
||||
/** |
||||
* Allows updating of the full data list underlying this adapter, replacing all items |
||||
* @param newItems The new list of files to display |
||||
*/ |
||||
public void update(List<TorrentFile> newItems) { |
||||
this.items = newItems; |
||||
notifyDataSetChanged(); |
||||
} |
||||
|
||||
@Override |
||||
public int getCount() { |
||||
return items.size(); |
||||
} |
||||
|
||||
@Override |
||||
public TorrentFile getItem(int position) { |
||||
return items.get(position); |
||||
} |
||||
|
||||
@Override |
||||
public long getItemId(int position) { |
||||
return position; |
||||
} |
||||
|
||||
@Override |
||||
public View getView(int position, View convertView, ViewGroup parent) { |
||||
TorrentFileView torrentFileView; |
||||
if (convertView == null) { |
||||
torrentFileView = TorrentFileView_.build(context); |
||||
} else { |
||||
torrentFileView = (TorrentFileView) convertView; |
||||
} |
||||
torrentFileView.bind(getItem(position)); |
||||
return torrentFileView; |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
@ -0,0 +1,233 @@
@@ -0,0 +1,233 @@
|
||||
package org.transdroid.core.gui.lists; |
||||
|
||||
import java.util.Locale; |
||||
|
||||
import org.transdroid.core.R; |
||||
import org.transdroid.daemon.DaemonException; |
||||
import org.transdroid.daemon.Torrent; |
||||
import org.transdroid.daemon.TorrentStatus; |
||||
import org.transdroid.daemon.util.FileSizeConverter; |
||||
import org.transdroid.daemon.util.TimespanConverter; |
||||
|
||||
import android.content.res.Resources; |
||||
|
||||
/** |
||||
* Wrapper around Torrent to provide some addition getters that give translatable or otherwise formatted Strings of |
||||
* torrent statistics. |
||||
* @author Eric Kok |
||||
*/ |
||||
public class LocalTorrent { |
||||
|
||||
/** |
||||
* Creates the LocalTorrent object so that the translatable/formattable version of a Torrent can be used. |
||||
* @param torrent The Torrent object |
||||
* @return The torrent wrapped as LocalTorrent object |
||||
*/ |
||||
public static LocalTorrent fromTorrent(Torrent torrent) { |
||||
return new LocalTorrent(torrent); |
||||
} |
||||
|
||||
private final Torrent t; |
||||
|
||||
private LocalTorrent(Torrent torrent) { |
||||
this.t = torrent; |
||||
} |
||||
|
||||
private static final String DECIMAL_FORMATTER = "%.1f"; |
||||
|
||||
/** |
||||
* Builds a string showing the upload/download seed ratio. If not downloading, it will base the ratio on the total |
||||
* size; so if you created the torrent yourself you will have downloaded 0 bytes, but the ratio will pretend you |
||||
* have 100%. |
||||
* @return A nicely formatted string containing the upload/download seed ratio |
||||
*/ |
||||
public String getRatioString() { |
||||
long baseSize = t.getTotalSize(); |
||||
if (t.getStatusCode() == TorrentStatus.Downloading) { |
||||
baseSize = t.getDownloadedEver(); |
||||
} |
||||
if (baseSize <= 0) { |
||||
return String.format(Locale.getDefault(), DECIMAL_FORMATTER, 0d); |
||||
} else if (t.getRatio() == Double.POSITIVE_INFINITY) { |
||||
return "\u221E"; |
||||
} else { |
||||
return String.format(Locale.getDefault(), DECIMAL_FORMATTER, t.getRatio()); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Returns a formatted string indicating the current progress in terms of transferred bytes |
||||
* @param r The context resources, to access translations |
||||
* @param withAvailability Whether to show file availability in-line |
||||
* @return A nicely formatted string indicating torrent status and, if applicable, progress in bytes |
||||
*/ |
||||
public String getProgressSizeText(Resources r, boolean withAvailability) { |
||||
|
||||
switch (t.getStatusCode()) { |
||||
case Waiting: |
||||
case Checking: |
||||
case Error: |
||||
// Not downloading yet
|
||||
return r.getString(R.string.status_waitingtodl, FileSizeConverter.getSize(t.getTotalSize())); |
||||
case Downloading: |
||||
// Downloading
|
||||
return r.getString( |
||||
R.string.status_size1, |
||||
FileSizeConverter.getSize(t.getDownloadedEver()), |
||||
FileSizeConverter.getSize(t.getTotalSize()), |
||||
String.format(DECIMAL_FORMATTER, t.getDownloadedPercentage() * 100) |
||||
+ "%" |
||||
+ (!withAvailability ? "" : "/" |
||||
+ String.format(DECIMAL_FORMATTER, t.getAvailability() * 100) + "%")); |
||||
case Seeding: |
||||
case Paused: |
||||
case Queued: |
||||
// Seeding or paused
|
||||
return r.getString(R.string.status_size2, FileSizeConverter.getSize(t.getTotalSize()), |
||||
FileSizeConverter.getSize(t.getUploadedEver())); |
||||
default: |
||||
return ""; |
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* Returns a formatted string indicating either the expected time to download (ETA) or, when seeding, the ratio |
||||
* @param r The context resources, to access translations |
||||
* @return A string like '~ 34 seconds', or 'RATIO 8.2' or an empty string |
||||
*/ |
||||
public String getProgressEtaRatioText(Resources r) { |
||||
switch (t.getStatusCode()) { |
||||
case Downloading: |
||||
// Downloading
|
||||
return getRemainingTimeString(r, true, false); |
||||
case Seeding: |
||||
case Paused: |
||||
case Queued: |
||||
// Seeding or paused
|
||||
return r.getString(R.string.status_ratio, getRatioString()); |
||||
case Waiting: |
||||
case Checking: |
||||
case Error: |
||||
default: |
||||
return ""; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Returns a formatted string indicating the torrent status and connected peers |
||||
* @param r The context resources, to access translations |
||||
* @return A string like 'Queued' or, when seeding or leeching, '2 OF 28 PEERS' |
||||
*/ |
||||
public String getProgressConnectionText(Resources r) { |
||||
|
||||
switch (t.getStatusCode()) { |
||||
case Waiting: |
||||
return r.getString(R.string.status_waiting); |
||||
case Checking: |
||||
return r.getString(R.string.status_checking); |
||||
case Downloading: |
||||
return r.getString(R.string.status_peers, t.getPeersSendingToUs(), t.getPeersConnected()); |
||||
case Seeding: |
||||
return r.getString(R.string.status_peers, t.getPeersGettingFromUs(), t.getPeersConnected()); |
||||
case Paused: |
||||
return r.getString(R.string.status_paused); |
||||
case Queued: |
||||
return r.getString(R.string.status_stopped); |
||||
case Error: |
||||
return r.getString(R.string.status_error); |
||||
default: |
||||
return r.getString(R.string.status_unknown); |
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* Returns a formatted string indicating current transfer speeds for the torrent |
||||
* @param r The context resources, to access translations |
||||
* @return A string like '↓ 28KB/s ↑ 1.8MB/s', or an empty string when not transferrring |
||||
*/ |
||||
public String getProgressSpeedText(Resources r) { |
||||
|
||||
switch (t.getStatusCode()) { |
||||
case Waiting: |
||||
case Checking: |
||||
case Paused: |
||||
case Queued: |
||||
return ""; |
||||
case Downloading: |
||||
return r.getString(R.string.status_speed_down, FileSizeConverter.getSize(t.getRateDownload()) + "/s") + " " |
||||
+ r.getString(R.string.status_speed_up, FileSizeConverter.getSize(t.getRateUpload()) + "/s"); |
||||
case Seeding: |
||||
return r.getString(R.string.status_speed_up, FileSizeConverter.getSize(t.getRateUpload()) + "/s"); |
||||
default: |
||||
return ""; |
||||
} |
||||
|
||||
} |
||||
|
||||
public String getProgressStatusEta(Resources r) { |
||||
switch (t.getStatusCode()) { |
||||
case Waiting: |
||||
return r.getString(R.string.status_waiting).toUpperCase(Locale.getDefault()); |
||||
case Checking: |
||||
return r.getString(R.string.status_checking).toUpperCase(Locale.getDefault()); |
||||
case Error: |
||||
return r.getString(R.string.status_error).toUpperCase(Locale.getDefault()); |
||||
case Downloading: |
||||
// Downloading
|
||||
return r.getString(R.string.status_downloading).toUpperCase(Locale.getDefault()) + " (" |
||||
+ String.format(DECIMAL_FORMATTER, t.getDownloadedPercentage() * 100) + "%), " |
||||
+ getRemainingTimeString(r, false, true); |
||||
case Seeding: |
||||
return r.getString(R.string.status_seeding).toUpperCase(Locale.getDefault()); |
||||
case Paused: |
||||
return r.getString(R.string.status_paused).toUpperCase(Locale.getDefault()); |
||||
case Queued: |
||||
return r.getString(R.string.status_queued).toUpperCase(Locale.getDefault()); |
||||
default: |
||||
return r.getString(R.string.status_unknown).toUpperCase(Locale.getDefault()); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Returns a formatted string indicating the remaining download time |
||||
* @param r The context resources, to access translations |
||||
* @param inDays Whether to show days or use hours for > 24 hours left instead |
||||
* @return A string like '4d 8h 34m 5s' or '2m 3s' |
||||
*/ |
||||
public String getRemainingTimeString(Resources r, boolean abbreviate, boolean inDays) { |
||||
if (t.getEta() == -1 || t.getEta() == -2) { |
||||
return r.getString(R.string.status_unknowneta); |
||||
} |
||||
return r.getString(abbreviate ? R.string.status_eta : R.string.status_etalong, |
||||
TimespanConverter.getTime(t.getEta(), inDays)); |
||||
} |
||||
|
||||
/** |
||||
* Convert a DaemonException to a translatable human-readable error message |
||||
* @param e The exception that was thrown by the server |
||||
* @return A string resource ID to show to the user |
||||
*/ |
||||
public static int getResourceForDaemonException(DaemonException e) { |
||||
switch (e.getType()) { |
||||
case MethodUnsupported: |
||||
return R.string.error_jsonrequesterror; |
||||
case ConnectionError: |
||||
return R.string.error_httperror; |
||||
case UnexpectedResponse: |
||||
return R.string.error_jsonresponseerror; |
||||
case ParsingFailed: |
||||
return R.string.error_jsonrequesterror; |
||||
case NotConnected: |
||||
return R.string.error_daemonnotconnected; |
||||
case AuthenticationFailure: |
||||
return R.string.error_401; |
||||
case FileAccessError: |
||||
return R.string.error_torrentfile; |
||||
default: |
||||
return R.string.error_httperror; |
||||
} |
||||
} |
||||
|
||||
} |
@ -1,11 +1,11 @@
@@ -1,11 +1,11 @@
|
||||
package org.transdroid.lite.gui.navigation; |
||||
package org.transdroid.core.gui.lists; |
||||
|
||||
/** |
||||
* Represents a filter item as shown in the navigation list or spinner. |
||||
* |
||||
* @author Eric Kok |
||||
*/ |
||||
public interface FilterItem { |
||||
public interface SimpleListItem { |
||||
|
||||
public String getName(); |
||||
|
@ -0,0 +1,91 @@
@@ -0,0 +1,91 @@
|
||||
package org.transdroid.core.gui.lists; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
import android.content.Context; |
||||
import android.view.View; |
||||
import android.view.ViewGroup; |
||||
import android.widget.BaseAdapter; |
||||
|
||||
public class SimpleListItemAdapter extends BaseAdapter { |
||||
|
||||
private final Context context; |
||||
private List<? extends SimpleListItem> items; |
||||
|
||||
public SimpleListItemAdapter(Context context, List<? extends SimpleListItem> items) { |
||||
this.context = context; |
||||
this.items = items; |
||||
} |
||||
|
||||
/** |
||||
* Allows updating of the full data list underlying this adapter, replacing all items |
||||
* @param newItems The new list of filter items to display |
||||
*/ |
||||
public void update(List<? extends SimpleListItem> newItems) { |
||||
this.items = newItems; |
||||
notifyDataSetChanged(); |
||||
} |
||||
|
||||
@Override |
||||
public int getCount() { |
||||
return items.size(); |
||||
} |
||||
|
||||
@Override |
||||
public SimpleListItem getItem(int position) { |
||||
return items.get(position); |
||||
} |
||||
|
||||
@Override |
||||
public long getItemId(int position) { |
||||
return position; |
||||
} |
||||
|
||||
@Override |
||||
public View getView(int position, View convertView, ViewGroup parent) { |
||||
SimpleListItemView filterItemView; |
||||
if (convertView == null) { |
||||
filterItemView = SimpleListItemView_.build(context); |
||||
} else { |
||||
filterItemView = (SimpleListItemView) convertView; |
||||
} |
||||
filterItemView.bind(getItem(position)); |
||||
return filterItemView; |
||||
} |
||||
|
||||
/** |
||||
* Represents a very simple list item that only contains a single string to show in the list. Use wrapStringsList to |
||||
* wrap an existing list of strings into a list of {@link SimpleListItem}s. |
||||
* @author Eric Kok |
||||
*/ |
||||
public static class SimpleStringItem implements SimpleListItem { |
||||
|
||||
/** |
||||
* Wraps a simple string of strings into a list of SimpleStringItem to add as data to a |
||||
* {@link SimpleListItemAdapter} |
||||
* @param errorStrings A list of string |
||||
* @return A list of SimpleStringItem objects representing the input strings |
||||
*/ |
||||
public static List<SimpleStringItem> wrapStringsList(List<String> errorStrings) { |
||||
ArrayList<SimpleStringItem> errors = new ArrayList<SimpleStringItem>(); |
||||
for (String errorString : errorStrings) { |
||||
errors.add(new SimpleStringItem(errorString)); |
||||
} |
||||
return errors; |
||||
} |
||||
|
||||
private final String string; |
||||
|
||||
public SimpleStringItem(String string) { |
||||
this.string = string; |
||||
} |
||||
|
||||
@Override |
||||
public String getName() { |
||||
return this.string; |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
@ -0,0 +1,85 @@
@@ -0,0 +1,85 @@
|
||||
package org.transdroid.core.gui.lists; |
||||
|
||||
import org.androidannotations.annotations.EViewGroup; |
||||
import org.androidannotations.annotations.ViewById; |
||||
import org.transdroid.core.R; |
||||
import org.transdroid.daemon.Daemon; |
||||
import org.transdroid.daemon.Torrent; |
||||
import org.transdroid.daemon.util.FileSizeConverter; |
||||
|
||||
import android.content.Context; |
||||
import android.text.TextUtils; |
||||
import android.text.format.DateUtils; |
||||
import android.view.View; |
||||
import android.widget.RelativeLayout; |
||||
import android.widget.TextView; |
||||
|
||||
/** |
||||
* Represents a group of views that show torrent status, sizes, speeds and other details. |
||||
* @author Eric Kok |
||||
*/ |
||||
@EViewGroup(R.layout.fragment_details_header) |
||||
public class TorrentDetailsView extends RelativeLayout { |
||||
|
||||
@ViewById |
||||
protected TextView labelText, dateaddedText, uploadedText, uploadedunitText, ratioText, upspeedText, seedersText, |
||||
downloadedunitText, downloadedText, totalsizeText, downspeedText, leechersText, statusText; |
||||
|
||||
public TorrentDetailsView(Context context) { |
||||
super(context); |
||||
} |
||||
|
||||
/** |
||||
* Update the text fields with new/updated torrent details |
||||
* @param torrent The torrent for which to show details |
||||
*/ |
||||
public void update(Torrent torrent) { |
||||
|
||||
LocalTorrent local = LocalTorrent.fromTorrent(torrent); |
||||
|
||||
// Set label text
|
||||
if (Daemon.supportsLabels(torrent.getDaemon())) { |
||||
if (TextUtils.isEmpty(torrent.getLabelName())) { |
||||
labelText.setText(getResources().getString(R.string.labels_unlabeled)); |
||||
} else { |
||||
labelText.setText(torrent.getLabelName()); |
||||
} |
||||
labelText.setVisibility(View.VISIBLE); |
||||
} else { |
||||
labelText.setVisibility(View.INVISIBLE); |
||||
} |
||||
|
||||
// Set status texts
|
||||
if (torrent.getDateAdded() != null) { |
||||
dateaddedText.setText(getResources().getString( |
||||
R.string.status_sincedate, |
||||
DateUtils.getRelativeDateTimeString(getContext(), torrent.getDateAdded().getTime(), |
||||
DateUtils.SECOND_IN_MILLIS, DateUtils.WEEK_IN_MILLIS, DateUtils.FORMAT_ABBREV_MONTH))); |
||||
dateaddedText.setVisibility(View.VISIBLE); |
||||
} else { |
||||
dateaddedText.setVisibility(View.INVISIBLE); |
||||
} |
||||
statusText.setText(local.getProgressStatusEta(getResources())); |
||||
ratioText.setText(getResources().getString(R.string.status_ratio, local.getRatioString())); |
||||
// TODO: Implement separate numbers of seeders and leechers
|
||||
seedersText.setText(getResources().getString(R.string.status_peers, torrent.getPeersSendingToUs(), |
||||
torrent.getPeersConnected())); |
||||
leechersText.setText(getResources().getString(R.string.status_peers, torrent.getPeersSendingToUs(), |
||||
torrent.getPeersConnected())); |
||||
// TODO: Add field that displays torrent errors (as opposed to tracker errors)
|
||||
// TODO: Add field that displays availability
|
||||
|
||||
// Sizes and speeds texts
|
||||
totalsizeText.setText(FileSizeConverter.getSize(torrent.getTotalSize())); |
||||
downloadedText.setText(FileSizeConverter.getSize(torrent.getDownloadedEver(), false)); |
||||
downloadedunitText.setText(FileSizeConverter.getSizeUnit(torrent.getDownloadedEver()).toString()); |
||||
uploadedText.setText(FileSizeConverter.getSize(torrent.getUploadedEver(), false)); |
||||
uploadedunitText.setText(FileSizeConverter.getSizeUnit(torrent.getUploadedEver()).toString()); |
||||
downspeedText.setText(getResources().getString(R.string.status_speed_down, |
||||
FileSizeConverter.getSize(torrent.getRateDownload()) + "/s")); |
||||
upspeedText.setText(getResources().getString(R.string.status_speed_up, |
||||
FileSizeConverter.getSize(torrent.getRateUpload()) + "/s")); |
||||
|
||||
} |
||||
|
||||
} |
@ -0,0 +1,53 @@
@@ -0,0 +1,53 @@
|
||||
package org.transdroid.core.gui.lists; |
||||
|
||||
import org.androidannotations.annotations.EViewGroup; |
||||
import org.androidannotations.annotations.ViewById; |
||||
import org.transdroid.core.R; |
||||
import org.transdroid.daemon.TorrentFile; |
||||
|
||||
import android.content.Context; |
||||
import android.widget.ImageView; |
||||
import android.widget.TextView; |
||||
import fr.marvinlabs.widget.CheckableRelativeLayout; |
||||
|
||||
/** |
||||
* View that represents some {@link TorrentFile} object and show the file's name, status and priority |
||||
* @author Eric Kok |
||||
*/ |
||||
@EViewGroup(R.layout.list_item_torrentfile) |
||||
public class TorrentFileView extends CheckableRelativeLayout { |
||||
|
||||
@ViewById |
||||
protected TextView nameText, progressText, sizesText; |
||||
@ViewById |
||||
protected ImageView priorityImage; |
||||
|
||||
public TorrentFileView(Context context) { |
||||
super(context, null); |
||||
} |
||||
|
||||
public void bind(TorrentFile torrentFile) { |
||||
nameText.setText(torrentFile.getName()); |
||||
sizesText.setText(torrentFile.getDownloadedAndTotalSizeText()); |
||||
progressText.setText(torrentFile.getProgressText()); |
||||
switch (torrentFile.getPriority()) { |
||||
case Off: |
||||
priorityImage.setImageResource(R.drawable.ic_priority_off); |
||||
priorityImage.setContentDescription(getResources().getString(R.string.status_priority_low)); |
||||
break; |
||||
case Low: |
||||
priorityImage.setImageResource(R.drawable.ic_priority_low); |
||||
priorityImage.setContentDescription(getResources().getString(R.string.status_priority_normal)); |
||||
break; |
||||
case Normal: |
||||
priorityImage.setImageResource(R.drawable.ic_priority_normal); |
||||
priorityImage.setContentDescription(getResources().getString(R.string.status_priority_normal)); |
||||
break; |
||||
case High: |
||||
priorityImage.setImageResource(R.drawable.ic_priority_high); |
||||
priorityImage.setContentDescription(getResources().getString(R.string.status_priority_high)); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
} |
@ -1,4 +1,4 @@
@@ -1,4 +1,4 @@
|
||||
package org.transdroid.lite.gui.lists; |
||||
package org.transdroid.core.gui.lists; |
||||
|
||||
import org.transdroid.core.R; |
||||
|
@ -0,0 +1,47 @@
@@ -0,0 +1,47 @@
|
||||
package org.transdroid.core.gui.lists; |
||||
|
||||
import org.androidannotations.annotations.EViewGroup; |
||||
import org.androidannotations.annotations.ViewById; |
||||
import org.transdroid.core.R; |
||||
import org.transdroid.daemon.Torrent; |
||||
import org.transdroid.daemon.TorrentStatus; |
||||
|
||||
import android.content.Context; |
||||
import android.view.View; |
||||
import android.widget.ImageView; |
||||
import android.widget.TextView; |
||||
import fr.marvinlabs.widget.CheckableRelativeLayout; |
||||
|
||||
/** |
||||
* View that represents some {@link Torrent} object and displays progress, status, speeds, etc. |
||||
* @author Eric Kok |
||||
*/ |
||||
@EViewGroup(R.layout.list_item_torrent) |
||||
public class TorrentView extends CheckableRelativeLayout { |
||||
|
||||
@ViewById |
||||
protected ImageView priorityImage; |
||||
@ViewById |
||||
protected TextView nameText, ratioText, progressText, speedText, peersText; |
||||
@ViewById |
||||
protected TorrentProgressBar torrentProgressbar; |
||||
|
||||
public TorrentView(Context context) { |
||||
super(context, null); |
||||
} |
||||
|
||||
public void bind(Torrent torrent) { |
||||
LocalTorrent local = LocalTorrent.fromTorrent(torrent); |
||||
nameText.setText(torrent.getName()); |
||||
ratioText.setText(local.getProgressEtaRatioText(getResources())); |
||||
progressText.setText(local.getProgressSizeText(getResources(), false)); |
||||
speedText.setText(local.getProgressSpeedText(getResources())); |
||||
peersText.setText(local.getProgressConnectionText(getResources())); |
||||
torrentProgressbar.setProgress((int) (torrent.getDownloadedPercentage() * 100)); |
||||
torrentProgressbar.setActive(torrent.canPause());; |
||||
torrentProgressbar.setError(torrent.getStatusCode() == TorrentStatus.Error); |
||||
// TODO: Implement per-torrent priority and set priorityImage
|
||||
priorityImage.setVisibility(View.INVISIBLE); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,67 @@
@@ -0,0 +1,67 @@
|
||||
package org.transdroid.core.gui.lists; |
||||
|
||||
import java.util.ArrayList; |
||||
|
||||
import org.androidannotations.annotations.EBean; |
||||
import org.androidannotations.annotations.RootContext; |
||||
import org.transdroid.core.gui.lists.TorrentView_; |
||||
import org.transdroid.daemon.Torrent; |
||||
|
||||
import android.content.Context; |
||||
import android.view.View; |
||||
import android.view.ViewGroup; |
||||
import android.widget.BaseAdapter; |
||||
|
||||
/** |
||||
* Adapter that contains a list of torrent objects to show. |
||||
* @author Eric Kok |
||||
*/ |
||||
@EBean |
||||
public class TorrentsAdapter extends BaseAdapter { |
||||
|
||||
private ArrayList<Torrent> torrents = null; |
||||
|
||||
@RootContext |
||||
protected Context context; |
||||
|
||||
/** |
||||
* Allows updating the full internal list of torrents at once, replacing the old list |
||||
* @param newTorrents The new list of torrent objects |
||||
*/ |
||||
public void update(ArrayList<Torrent> newTorrents) { |
||||
this.torrents = newTorrents; |
||||
notifyDataSetChanged(); |
||||
} |
||||
|
||||
@Override |
||||
public int getCount() { |
||||
if (torrents == null) |
||||
return 0; |
||||
return torrents.size(); |
||||
} |
||||
|
||||
@Override |
||||
public Torrent getItem(int position) { |
||||
if (torrents == null) |
||||
return null; |
||||
return torrents.get(position); |
||||
} |
||||
|
||||
@Override |
||||
public long getItemId(int position) { |
||||
return position; |
||||
} |
||||
|
||||
@Override |
||||
public View getView(int position, View convertView, ViewGroup parent) { |
||||
TorrentView torrentView; |
||||
if (convertView == null) { |
||||
torrentView = TorrentView_.build(context); |
||||
} else { |
||||
torrentView = (TorrentView) convertView; |
||||
} |
||||
torrentView.bind(getItem(position)); |
||||
return torrentView; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,78 @@
@@ -0,0 +1,78 @@
|
||||
package org.transdroid.core.gui.navigation; |
||||
|
||||
import java.util.List; |
||||
|
||||
import org.androidannotations.annotations.EBean; |
||||
import org.androidannotations.annotations.RootContext; |
||||
import org.transdroid.core.R; |
||||
import org.transdroid.core.gui.lists.SimpleListItem; |
||||
import org.transdroid.core.gui.lists.SimpleListItemAdapter; |
||||
import org.transdroid.core.gui.navigation.FilterSeparatorView_; |
||||
|
||||
import android.content.Context; |
||||
|
||||
import com.commonsware.cwac.merge.MergeAdapter; |
||||
|
||||
/** |
||||
* List adapter that holds filter items, that is, servers, view types and labels. A header item is inserted where |
||||
* appropriate. |
||||
* @author Eric Kok |
||||
*/ |
||||
@EBean |
||||
public class FilterListAdapter extends MergeAdapter { |
||||
|
||||
@RootContext |
||||
protected Context context; |
||||
private SimpleListItemAdapter serverItems = null; |
||||
private SimpleListItemAdapter statusTypeItems = null; |
||||
private SimpleListItemAdapter labelItems = null; |
||||
|
||||
/** |
||||
* Update the list of available servers |
||||
* @param servers The new list of available servers |
||||
*/ |
||||
public void updateServers(List<? extends SimpleListItem> servers) { |
||||
if (this.serverItems == null && servers != null) { |
||||
addView(FilterSeparatorView_.build(context).setText(context.getString(R.string.navigation_servers)), false); |
||||
this.serverItems = new SimpleListItemAdapter(context, servers); |
||||
addAdapter(serverItems); |
||||
} else if (this.serverItems != null && servers != null) { |
||||
this.serverItems.update(servers); |
||||
} else { |
||||
this.serverItems = null; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Update the list of available status types |
||||
* @param statusTypes The new list of available status types |
||||
*/ |
||||
public void updateStatusTypes(List<? extends SimpleListItem> statusTypes) { |
||||
if (this.statusTypeItems == null && statusTypes != null) { |
||||
addView(FilterSeparatorView_.build(context).setText(context.getString(R.string.navigation_status)), false); |
||||
this.statusTypeItems = new SimpleListItemAdapter(context, statusTypes); |
||||
addAdapter(statusTypeItems); |
||||
} else if (this.statusTypeItems != null && statusTypes != null) { |
||||
this.statusTypeItems.update(statusTypes); |
||||
} else { |
||||
this.statusTypeItems = null; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Update the list of available labels |
||||
* @param labels The new list of available labels |
||||
*/ |
||||
public void updateLabels(List<? extends SimpleListItem> labels) { |
||||
if (this.labelItems == null && labels != null) { |
||||
addView(FilterSeparatorView_.build(context).setText(context.getString(R.string.navigation_labels)), false); |
||||
this.labelItems = new SimpleListItemAdapter(context, labels); |
||||
addAdapter(labelItems); |
||||
} else if (this.serverItems != null && labels != null) { |
||||
this.labelItems.update(labels); |
||||
} else { |
||||
this.labelItems = null; |
||||
} |
||||
} |
||||
|
||||
} |
@ -1,10 +1,12 @@
@@ -1,10 +1,12 @@
|
||||
package org.transdroid.lite.gui.navigation; |
||||
package org.transdroid.core.gui.navigation; |
||||
|
||||
import org.transdroid.core.gui.lists.SimpleListItem; |
||||
|
||||
/** |
||||
* Represents some label that is active or available on the server. |
||||
* @author Eric Kok |
||||
*/ |
||||
public class Label implements FilterItem { |
||||
public class Label implements SimpleListItem { |
||||
|
||||
private final String name; |
||||
|
@ -1,4 +1,4 @@
@@ -1,4 +1,4 @@
|
||||
package org.transdroid.lite.gui.navigation; |
||||
package org.transdroid.core.gui.navigation; |
||||
|
||||
import org.androidannotations.annotations.EBean; |
||||
import org.androidannotations.annotations.RootContext; |
@ -1,9 +1,9 @@
@@ -1,9 +1,9 @@
|
||||
package org.transdroid.lite.gui.settings; |
||||
package org.transdroid.core.gui.settings; |
||||
|
||||
import org.androidannotations.annotations.Bean; |
||||
import org.androidannotations.annotations.EActivity; |
||||
import org.androidannotations.annotations.Extra; |
||||
import org.transdroid.lite.app.settings.ApplicationSettings; |
||||
import org.transdroid.core.app.settings.ApplicationSettings; |
||||
|
||||
import android.os.Bundle; |
||||
|
@ -1,6 +1,6 @@
@@ -1,6 +1,6 @@
|
||||
package org.transdroid.lite.gui.settings; |
||||
package org.transdroid.core.gui.settings; |
||||
|
||||
import org.transdroid.lite.app.settings.RssfeedSetting; |
||||
import org.transdroid.core.app.settings.RssfeedSetting; |
||||
|
||||
import android.content.Context; |
||||
import android.preference.Preference; |
@ -1,10 +1,10 @@
@@ -1,10 +1,10 @@
|
||||
package org.transdroid.lite.gui.settings; |
||||
package org.transdroid.core.gui.settings; |
||||
|
||||
import org.androidannotations.annotations.Bean; |
||||
import org.androidannotations.annotations.EActivity; |
||||
import org.androidannotations.annotations.Extra; |
||||
import org.transdroid.core.R; |
||||
import org.transdroid.lite.app.settings.ApplicationSettings; |
||||
import org.transdroid.core.app.settings.ApplicationSettings; |
||||
|
||||
import android.os.Bundle; |
||||
|
@ -1,6 +1,6 @@
@@ -1,6 +1,6 @@
|
||||
package org.transdroid.lite.gui.settings; |
||||
package org.transdroid.core.gui.settings; |
||||
|
||||
import org.transdroid.lite.app.settings.ServerSetting; |
||||
import org.transdroid.core.app.settings.ServerSetting; |
||||
|
||||
import android.content.Context; |
||||
import android.preference.Preference; |
@ -1,11 +1,11 @@
@@ -1,11 +1,11 @@
|
||||
package org.transdroid.lite.gui.settings; |
||||
package org.transdroid.core.gui.settings; |
||||
|
||||
import org.androidannotations.annotations.Bean; |
||||
import org.androidannotations.annotations.EActivity; |
||||
import org.androidannotations.annotations.Extra; |
||||
import org.transdroid.daemon.Daemon; |
||||
import org.transdroid.core.R; |
||||
import org.transdroid.lite.app.settings.ApplicationSettings; |
||||
import org.transdroid.core.app.settings.ApplicationSettings; |
||||
|
||||
import android.content.SharedPreferences; |
||||
import android.os.Bundle; |
@ -1,6 +1,6 @@
@@ -1,6 +1,6 @@
|
||||
package org.transdroid.lite.gui.settings; |
||||
package org.transdroid.core.gui.settings; |
||||
|
||||
import org.transdroid.lite.app.settings.WebsearchSetting; |
||||
import org.transdroid.core.app.settings.WebsearchSetting; |
||||
|
||||
import android.content.Context; |
||||
import android.preference.Preference; |
@ -1,10 +1,10 @@
@@ -1,10 +1,10 @@
|
||||
package org.transdroid.lite.gui.settings; |
||||
package org.transdroid.core.gui.settings; |
||||
|
||||
import org.androidannotations.annotations.Bean; |
||||
import org.androidannotations.annotations.EActivity; |
||||
import org.androidannotations.annotations.Extra; |
||||
import org.transdroid.core.R; |
||||
import org.transdroid.lite.app.settings.ApplicationSettings; |
||||
import org.transdroid.core.app.settings.ApplicationSettings; |
||||
|
||||
import android.os.Bundle; |
||||
|
@ -1,47 +0,0 @@
@@ -1,47 +0,0 @@
|
||||
package org.transdroid.lite.gui; |
||||
|
||||
import org.androidannotations.annotations.AfterViews; |
||||
import org.androidannotations.annotations.EFragment; |
||||
import org.androidannotations.annotations.FragmentArg; |
||||
import org.androidannotations.annotations.InstanceState; |
||||
import org.androidannotations.annotations.ViewById; |
||||
import org.transdroid.daemon.Torrent; |
||||
import org.transdroid.daemon.TorrentDetails; |
||||
import org.transdroid.core.R; |
||||
|
||||
import android.view.View; |
||||
import android.widget.TextView; |
||||
|
||||
import com.actionbarsherlock.app.SherlockFragment; |
||||
|
||||
/** |
||||
* Fragment that shown detailed statistics about some torrent. These come from some already fetched {@link Torrent} |
||||
* object, but it also retrieves further detailed statistics. |
||||
* |
||||
* @author Eric Kok |
||||
*/ |
||||
@EFragment(R.layout.fragment_details) |
||||
public class DetailsFagment extends SherlockFragment { |
||||
|
||||
@FragmentArg |
||||
@InstanceState |
||||
protected Torrent torrent = null; |
||||
@InstanceState |
||||
protected TorrentDetails torrentDetails; |
||||
|
||||
@ViewById |
||||
protected TextView emptyText; |
||||
|
||||
@AfterViews |
||||
protected void init() { |
||||
|
||||
if (torrent == null) { |
||||
// No torrent specified; show the placeholder layout only
|
||||
emptyText.setVisibility(View.VISIBLE); |
||||
} |
||||
|
||||
// TODO: Show the torrent details and load the advanced statistics
|
||||
|
||||
} |
||||
|
||||
} |
@ -1,94 +0,0 @@
@@ -1,94 +0,0 @@
|
||||
package org.transdroid.lite.gui; |
||||
|
||||
import org.androidannotations.annotations.AfterViews; |
||||
import org.androidannotations.annotations.Bean; |
||||
import org.androidannotations.annotations.EActivity; |
||||
import org.androidannotations.annotations.FragmentById; |
||||
import org.androidannotations.annotations.ItemSelect; |
||||
import org.androidannotations.annotations.OptionsMenu; |
||||
import org.androidannotations.annotations.ViewById; |
||||
import org.transdroid.core.R; |
||||
import org.transdroid.lite.app.settings.ApplicationSettings; |
||||
import org.transdroid.lite.gui.navigation.FilterAdapter; |
||||
import org.transdroid.lite.gui.navigation.FilterItem; |
||||
import org.transdroid.lite.gui.navigation.NavigationHelper; |
||||
import org.transdroid.lite.gui.navigation.StatusType; |
||||
|
||||
import com.actionbarsherlock.app.ActionBar; |
||||
import com.actionbarsherlock.app.ActionBar.OnNavigationListener; |
||||
import com.actionbarsherlock.app.SherlockFragmentActivity; |
||||
import com.actionbarsherlock.view.SherlockListView; |
||||
|
||||
@EActivity(R.layout.activity_torrents) |
||||
@OptionsMenu(R.menu.activity_torrents) |
||||
public class TorrentsActivity extends SherlockFragmentActivity implements OnNavigationListener { |
||||
|
||||
// Navigation components
|
||||
@Bean |
||||
protected NavigationHelper navigationHelper; |
||||
@ViewById |
||||
protected SherlockListView filtersList; |
||||
protected FilterAdapter navigationListAdapter = null; |
||||
protected FilterAdapter navigationSpinnerAdapter = null; |
||||
|
||||
// Settings
|
||||
@Bean |
||||
protected ApplicationSettings applicationSettings; |
||||
|
||||
// Torrents list components
|
||||
@FragmentById(R.id.torrent_list) |
||||
protected TorrentsFragment fragmentTorrents; |
||||
|
||||
// Details view components
|
||||
@FragmentById(R.id.torrent_details) |
||||
protected DetailsFagment fragmentDetails; |
||||
|
||||
@AfterViews |
||||
protected void init() { |
||||
|
||||
// Set up navigation, with an action bar spinner and possibly (if room) with a filter list
|
||||
getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_LIST); |
||||
getSupportActionBar().setHomeButtonEnabled(false); |
||||
navigationSpinnerAdapter = new FilterAdapter(this); |
||||
// Servers are always added to the action bar spinner
|
||||
navigationSpinnerAdapter.updateServers(applicationSettings.getServerSettings()); |
||||
getSupportActionBar().setListNavigationCallbacks(navigationSpinnerAdapter, this); |
||||
if (filtersList != null) { |
||||
// There was room for a dedicated filter list; add the status types
|
||||
navigationListAdapter = new FilterAdapter(this); |
||||
filtersList.setAdapter(navigationListAdapter); |
||||
navigationListAdapter.updateStatusTypes(StatusType.getAllStatusTypes(this)); |
||||
} else { |
||||
// Add status types directly to the action bar spinner
|
||||
navigationSpinnerAdapter.updateStatusTypes(StatusType.getAllStatusTypes(this)); |
||||
} |
||||
|
||||
|
||||
} |
||||
|
||||
/** |
||||
* Called when an item in the action bar navigation spinner was selected |
||||
*/ |
||||
@Override |
||||
public boolean onNavigationItemSelected(int itemPosition, long itemId) { |
||||
Object item = navigationSpinnerAdapter.getItem(itemPosition); |
||||
if (item instanceof FilterItem) { |
||||
// A filter item was selected form the navigation spinner
|
||||
filterSelected(true, (FilterItem) item); |
||||
return true; |
||||
} |
||||
// A header was selected; no action
|
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* A new filter was selected; update the view over the current data |
||||
* @param selected True if the filter item was selected, false if it was deselected |
||||
* @param item The touched filter item |
||||
*/ |
||||
@ItemSelect(R.id.filters_list) |
||||
protected void filterSelected(boolean selected, FilterItem item) { |
||||
// TODO: Update the torrent list view
|
||||
} |
||||
|
||||
} |
@ -1,11 +0,0 @@
@@ -1,11 +0,0 @@
|
||||
package org.transdroid.lite.gui; |
||||
|
||||
import org.androidannotations.annotations.EFragment; |
||||
import org.transdroid.core.R; |
||||
|
||||
import com.actionbarsherlock.app.SherlockFragment; |
||||
|
||||
@EFragment(R.layout.fragment_torrents) |
||||
public class TorrentsFragment extends SherlockFragment { |
||||
|
||||
} |
@ -1,125 +0,0 @@
@@ -1,125 +0,0 @@
|
||||
package org.transdroid.lite.gui.navigation; |
||||
|
||||
import java.util.List; |
||||
|
||||
import org.transdroid.core.R; |
||||
|
||||
import android.content.Context; |
||||
import android.view.View; |
||||
import android.view.ViewGroup; |
||||
import android.widget.BaseAdapter; |
||||
|
||||
import com.commonsware.cwac.merge.MergeAdapter; |
||||
|
||||
/** |
||||
* List adapter that holds filter items, that is, servers, view types and labels. A header item is intersted where |
||||
* appropriate. |
||||
* @author Eric Kok |
||||
*/ |
||||
public class FilterAdapter extends MergeAdapter { |
||||
|
||||
private Context context; |
||||
private FilterItemAdapter serverItems = null; |
||||
private FilterItemAdapter statusTypeItems = null; |
||||
private FilterItemAdapter labelItems = null; |
||||
|
||||
public FilterAdapter(Context context) { |
||||
this.context = context; |
||||
} |
||||
|
||||
/** |
||||
* Update the list of available servers. |
||||
* @param servers The new list of available servers |
||||
*/ |
||||
public void updateServers(List<? extends FilterItem> servers) { |
||||
if (this.serverItems == null && servers != null) { |
||||
addView(FilterSeparatorView_.build(context).setText(context.getString(R.string.navigation_servers)), false); |
||||
this.serverItems = new FilterItemAdapter(context, servers); |
||||
addAdapter(serverItems); |
||||
} else if (this.serverItems != null && servers != null) { |
||||
this.serverItems.update(servers); |
||||
} else { |
||||
this.serverItems = null; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Update the list of available status types. |
||||
* @param statusTypes The new list of available status types |
||||
*/ |
||||
public void updateStatusTypes(List<? extends FilterItem> statusTypes) { |
||||
if (this.statusTypeItems == null && statusTypes != null) { |
||||
addView(FilterSeparatorView_.build(context).setText(context.getString(R.string.navigation_status)), false); |
||||
this.statusTypeItems = new FilterItemAdapter(context, statusTypes); |
||||
addAdapter(statusTypeItems); |
||||
} else if (this.statusTypeItems != null && statusTypes != null) { |
||||
this.statusTypeItems.update(statusTypes); |
||||
} else { |
||||
this.statusTypeItems = null; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Update the list of available labels. |
||||
* @param labels The new list of available labels |
||||
*/ |
||||
public void updateLabels(List<? extends FilterItem> labels) { |
||||
if (this.labelItems == null && labels != null) { |
||||
addView(FilterSeparatorView_.build(context).setText(context.getString(R.string.navigation_labels)), false); |
||||
this.labelItems = new FilterItemAdapter(context, labels); |
||||
addAdapter(labelItems); |
||||
} else if (this.serverItems != null && labels != null) { |
||||
this.labelItems.update(labels); |
||||
} else { |
||||
this.labelItems = null; |
||||
} |
||||
} |
||||
|
||||
protected class FilterItemAdapter extends BaseAdapter { |
||||
|
||||
private final Context context; |
||||
private List<? extends FilterItem> items; |
||||
|
||||
public FilterItemAdapter(Context context, List<? extends FilterItem> items) { |
||||
this.context = context; |
||||
this.items = items; |
||||
} |
||||
|
||||
/** |
||||
* Allows updating of the full data list underlying this adapter, replacing all items |
||||
* @param newItems The new list of filter items to display |
||||
*/ |
||||
public void update(List<? extends FilterItem> newItems) { |
||||
this.items = newItems; |
||||
notifyDataSetChanged(); |
||||
} |
||||
|
||||
@Override |
||||
public int getCount() { |
||||
return items.size(); |
||||
} |
||||
|
||||
@Override |
||||
public FilterItem getItem(int position) { |
||||
return items.get(position); |
||||
} |
||||
|
||||
@Override |
||||
public long getItemId(int position) { |
||||
return position; |
||||
} |
||||
|
||||
@Override |
||||
public View getView(int position, View convertView, ViewGroup parent) { |
||||
FilterItemView filterItemView; |
||||
if (convertView == null) { |
||||
filterItemView = FilterItemView_.build(context); |
||||
} else { |
||||
filterItemView = (FilterItemView) convertView; |
||||
} |
||||
filterItemView.bind(getItem(position)); |
||||
return filterItemView; |
||||
} |
||||
|
||||
} |
||||
} |
Loading…
Reference in new issue