Browse Source

Build torrent and details fragment UI and started on logic.

pull/11/head
Eric Kok 11 years ago
parent
commit
fc83f907e1
  1. 6
      lib/src/org/transdroid/daemon/BitComet/BitCometAdapter.java
  2. 3
      lib/src/org/transdroid/daemon/Bitflu/BitfluAdapter.java
  3. 3
      lib/src/org/transdroid/daemon/BuffaloNas/BuffaloNasAdapter.java
  4. 3
      lib/src/org/transdroid/daemon/DLinkRouterBT/DLinkRouterBTAdapter.java
  5. 5
      lib/src/org/transdroid/daemon/Deluge/DelugeAdapter.java
  6. 4
      lib/src/org/transdroid/daemon/Ktorrent/StatsParser.java
  7. 3
      lib/src/org/transdroid/daemon/Qbittorrent/QbittorrentAdapter.java
  8. 10
      lib/src/org/transdroid/daemon/Rtorrent/RtorrentAdapter.java
  9. 4
      lib/src/org/transdroid/daemon/Tfb4rt/StatsParser.java
  10. 7
      lib/src/org/transdroid/daemon/Torrent.java
  11. 3
      lib/src/org/transdroid/daemon/Transmission/TransmissionAdapter.java
  12. 3
      lib/src/org/transdroid/daemon/Utorrent/UtorrentAdapter.java
  13. 16
      lib/src/org/transdroid/daemon/Vuze/VuzeAdapter.java
  14. 84
      lib/src/org/transdroid/daemon/util/FileSizeConverter.java
  15. 2
      lite/.classpath
  16. 64
      lite/AndroidManifest.xml
  17. 2
      lite/res/layout-w600dp/activity_torrents.xml
  18. 4
      lite/res/layout-w720dp/activity_torrents.xml
  19. 16
      lite/res/layout/activity_details.xml
  20. 3
      lite/res/layout/activity_torrents.xml
  21. 1
      lite/res/layout/fragment_details.xml
  22. 26
      lite/res/layout/fragment_details_header.xml
  23. 1
      lite/res/layout/fragment_torrents.xml
  24. 11
      lite/res/layout/list_item_torrent.xml
  25. 58
      lite/res/layout/list_item_torrentfile.xml
  26. 9
      lite/res/menu/activity_details.xml
  27. 59
      lite/res/values/strings.xml
  28. 8
      lite/res/xml/searchable.xml
  29. 2
      lite/src/org/transdroid/core/app/search/SearchHelper.java
  30. 2
      lite/src/org/transdroid/core/app/search/SearchResult.java
  31. 6
      lite/src/org/transdroid/core/app/search/SearchSite.java
  32. 2
      lite/src/org/transdroid/core/app/settings/AboutSettings.java
  33. 52
      lite/src/org/transdroid/core/app/settings/ApplicationSettings.java
  34. 2
      lite/src/org/transdroid/core/app/settings/NotificationSettings.java
  35. 6
      lite/src/org/transdroid/core/app/settings/RssfeedSetting.java
  36. 33
      lite/src/org/transdroid/core/app/settings/ServerSetting.java
  37. 6
      lite/src/org/transdroid/core/app/settings/WebsearchSetting.java
  38. 132
      lite/src/org/transdroid/core/gui/DetailsActivity.java
  39. 113
      lite/src/org/transdroid/core/gui/DetailsFagment.java
  40. 22
      lite/src/org/transdroid/core/gui/SearchHistoryProvider.java
  41. 253
      lite/src/org/transdroid/core/gui/TorrentsActivity.java
  42. 69
      lite/src/org/transdroid/core/gui/TorrentsFragment.java
  43. 141
      lite/src/org/transdroid/core/gui/lists/DetailsAdapter.java
  44. 233
      lite/src/org/transdroid/core/gui/lists/LocalTorrent.java
  45. 4
      lite/src/org/transdroid/core/gui/lists/SimpleListItem.java
  46. 91
      lite/src/org/transdroid/core/gui/lists/SimpleListItemAdapter.java
  47. 10
      lite/src/org/transdroid/core/gui/lists/SimpleListItemView.java
  48. 85
      lite/src/org/transdroid/core/gui/lists/TorrentDetailsView.java
  49. 53
      lite/src/org/transdroid/core/gui/lists/TorrentFileView.java
  50. 2
      lite/src/org/transdroid/core/gui/lists/TorrentProgressBar.java
  51. 47
      lite/src/org/transdroid/core/gui/lists/TorrentView.java
  52. 67
      lite/src/org/transdroid/core/gui/lists/TorrentsAdapter.java
  53. 78
      lite/src/org/transdroid/core/gui/navigation/FilterListAdapter.java
  54. 5
      lite/src/org/transdroid/core/gui/navigation/FilterSeparatorView.java
  55. 6
      lite/src/org/transdroid/core/gui/navigation/Label.java
  56. 2
      lite/src/org/transdroid/core/gui/navigation/NavigationHelper.java
  57. 5
      lite/src/org/transdroid/core/gui/navigation/StatusType.java
  58. 20
      lite/src/org/transdroid/core/gui/settings/MainSettingsActivity.java
  59. 4
      lite/src/org/transdroid/core/gui/settings/OtherSettingsActivity.java
  60. 4
      lite/src/org/transdroid/core/gui/settings/RssfeedPreference.java
  61. 4
      lite/src/org/transdroid/core/gui/settings/RssfeedSettingsActivity.java
  62. 4
      lite/src/org/transdroid/core/gui/settings/ServerPreference.java
  63. 4
      lite/src/org/transdroid/core/gui/settings/ServerSettingsActivity.java
  64. 4
      lite/src/org/transdroid/core/gui/settings/WebsearchPreference.java
  65. 4
      lite/src/org/transdroid/core/gui/settings/WebsearchSettingsActivity.java
  66. 47
      lite/src/org/transdroid/lite/gui/DetailsFagment.java
  67. 94
      lite/src/org/transdroid/lite/gui/TorrentsActivity.java
  68. 11
      lite/src/org/transdroid/lite/gui/TorrentsFragment.java
  69. 125
      lite/src/org/transdroid/lite/gui/navigation/FilterAdapter.java

6
lib/src/org/transdroid/daemon/BitComet/BitCometAdapter.java

@ -480,7 +480,8 @@ public class BitCometAdapter implements IDaemonAdapter { @@ -480,7 +480,8 @@ public class BitCometAdapter implements IDaemonAdapter {
comment,
dateAdded,
null,
null));
null,
settings.getType()));
}
}
}
@ -557,7 +558,8 @@ public class BitCometAdapter implements IDaemonAdapter { @@ -557,7 +558,8 @@ public class BitCometAdapter implements IDaemonAdapter {
label,
dateAdded,
null,
null)); // Not supported in the web interface
null, // Not supported in the web interface
settings.getType()));
id++; // Stop/start/etc. requests are made by ID, which is the order number in the returned XML list :-S

3
lib/src/org/transdroid/daemon/Bitflu/BitfluAdapter.java

@ -214,7 +214,8 @@ public class BitfluAdapter implements IDaemonAdapter { @@ -214,7 +214,8 @@ public class BitfluAdapter implements IDaemonAdapter {
null, // label
null, // Not available
null, // Not available
null)); // Not available
null, // Not available
settings.getType()));
}
}
// Return the list

3
lib/src/org/transdroid/daemon/BuffaloNas/BuffaloNasAdapter.java

@ -281,7 +281,8 @@ public class BuffaloNasAdapter implements IDaemonAdapter { @@ -281,7 +281,8 @@ public class BuffaloNasAdapter implements IDaemonAdapter {
null,
null,
null,
null));
null,
settings.getType()));
}
// Return the list

3
lib/src/org/transdroid/daemon/DLinkRouterBT/DLinkRouterBTAdapter.java

@ -376,7 +376,8 @@ public class DLinkRouterBTAdapter implements IDaemonAdapter { @@ -376,7 +376,8 @@ public class DLinkRouterBTAdapter implements IDaemonAdapter {
null,
null,
null,
null);
null,
settings.getType());
torrents.add(new_t);
}

5
lib/src/org/transdroid/daemon/Deluge/DelugeAdapter.java

@ -593,8 +593,9 @@ public class DelugeAdapter implements IDaemonAdapter { @@ -593,8 +593,9 @@ public class DelugeAdapter implements IDaemonAdapter {
0f, // Not available
tor.has(RPC_LABEL)? tor.getString(RPC_LABEL): null,
tor.has(RPC_TIMEADDED)? new Date(tor.getInt(RPC_TIMEADDED) * 1000L): null,
null,
tor.getString(RPC_MESSAGE))); // Not available
null, // Not available
tor.getString(RPC_MESSAGE),
settings.getType()));
}
}

4
lib/src/org/transdroid/daemon/Ktorrent/StatsParser.java

@ -5,6 +5,7 @@ import java.io.Reader; @@ -5,6 +5,7 @@ import java.io.Reader;
import java.util.ArrayList;
import java.util.List;
import org.transdroid.daemon.Daemon;
import org.transdroid.daemon.DaemonException;
import org.transdroid.daemon.Torrent;
import org.transdroid.daemon.TorrentStatus;
@ -85,7 +86,8 @@ public class StatsParser { @@ -85,7 +86,8 @@ public class StatsParser {
null, // Not supported in the web interface
null, // Not supported in the web interface
null, // Not supported in the web interface
null)); // Not supported in the web interface
null, // Not supported in the web interface
Daemon.KTorrent));
id++; // Stop/start/etc. requests are made by ID, which is the order number in the returned XML list :-S
} else if (next == XmlPullParser.START_TAG && name.equals("torrent")){

3
lib/src/org/transdroid/daemon/Qbittorrent/QbittorrentAdapter.java

@ -394,7 +394,8 @@ public class QbittorrentAdapter implements IDaemonAdapter { @@ -394,7 +394,8 @@ public class QbittorrentAdapter implements IDaemonAdapter {
null,
null, // Only available in /json/propertiesGeneral on a per-torrent basis, unfortunately
null,
null));
null,
settings.getType()));
}
// Return the list

10
lib/src/org/transdroid/daemon/Rtorrent/RtorrentAdapter.java

@ -350,10 +350,11 @@ public class RtorrentAdapter implements IDaemonAdapter { @@ -350,10 +350,11 @@ public class RtorrentAdapter implements IDaemonAdapter {
(Long)info[10], // totalSize
((Long)info[8]).floatValue() / ((Long)info[10]).floatValue(), // partDone
0f, // TODO: Add availability data
label, // See remark on rTorrent/groups above
label,
added,
finished,
error));
error,
settings.getType()));
} else {
@ -379,10 +380,11 @@ public class RtorrentAdapter implements IDaemonAdapter { @@ -379,10 +380,11 @@ public class RtorrentAdapter implements IDaemonAdapter {
(Integer)info[10], // totalSize
((Integer)info[8]).floatValue() / ((Integer)info[10]).floatValue(), // partDone
0f, // TODO: Add availability data
label, // See remark on rTorrent/groups above
label,
added,
finished,
error));
error,
settings.getType()));
}
}

4
lib/src/org/transdroid/daemon/Tfb4rt/StatsParser.java

@ -5,6 +5,7 @@ import java.io.Reader; @@ -5,6 +5,7 @@ import java.io.Reader;
import java.util.ArrayList;
import java.util.List;
import org.transdroid.daemon.Daemon;
import org.transdroid.daemon.DaemonException;
import org.transdroid.daemon.Torrent;
import org.transdroid.daemon.TorrentStatus;
@ -80,7 +81,8 @@ public class StatsParser { @@ -80,7 +81,8 @@ public class StatsParser {
null, // Not supported in the XML stats
null,
null,
null));
null,
Daemon.Tfb4rt));
} else if (next == XmlPullParser.START_TAG && name.equals("transfer")){

7
lib/src/org/transdroid/daemon/Torrent.java

@ -55,6 +55,7 @@ public final class Torrent implements Parcelable, Comparable<Torrent> { @@ -55,6 +55,7 @@ public final class Torrent implements Parcelable, Comparable<Torrent> {
final private Date dateAdded;
final private Date dateDone;
final private String error;
final private Daemon daemon;
//public long getID() { return id; }
//public String getHash() { return hash; }
@ -80,6 +81,7 @@ public final class Torrent implements Parcelable, Comparable<Torrent> { @@ -80,6 +81,7 @@ public final class Torrent implements Parcelable, Comparable<Torrent> {
public Date getDateAdded() { return dateAdded; }
public Date getDateDone() { return dateDone; }
public String getError() { return error; }
public Daemon getDaemon() { return daemon; }
private Torrent(Parcel in) {
this.id = in.readLong();
@ -108,12 +110,13 @@ public final class Torrent implements Parcelable, Comparable<Torrent> { @@ -108,12 +110,13 @@ public final class Torrent implements Parcelable, Comparable<Torrent> {
long lDateDone = in.readLong();
this.dateDone = (lDateDone == -1)? null: new Date(lDateDone);
this.error = in.readString();
this.daemon = Daemon.valueOf(in.readString());
}
public Torrent(long id, String hash, String name, TorrentStatus statusCode, String locationDir, int rateDownload, int rateUpload,
int peersGettingFromUs, int peersSendingToUs, int peersConnected, int peersKnown, int eta,
long downloadedEver, long uploadedEver, long totalSize, float partDone, float available, String label,
Date dateAdded, Date realDateDone, String error) {
Date dateAdded, Date realDateDone, String error, Daemon daemon) {
this.id = id;
this.hash = hash;
this.name = name;
@ -149,6 +152,7 @@ public final class Torrent implements Parcelable, Comparable<Torrent> { @@ -149,6 +152,7 @@ public final class Torrent implements Parcelable, Comparable<Torrent> {
this.dateDone = cal.getTime();
}
this.error = error;
this.daemon = daemon;
}
/**
@ -296,6 +300,7 @@ public final class Torrent implements Parcelable, Comparable<Torrent> { @@ -296,6 +300,7 @@ public final class Torrent implements Parcelable, Comparable<Torrent> {
dest.writeLong((dateAdded == null)? -1: dateAdded.getTime());
dest.writeLong((dateDone == null)? -1: dateDone.getTime());
dest.writeString(error);
dest.writeString(daemon.name());
}
}

3
lib/src/org/transdroid/daemon/Transmission/TransmissionAdapter.java

@ -500,7 +500,8 @@ public class TransmissionAdapter implements IDaemonAdapter { @@ -500,7 +500,8 @@ public class TransmissionAdapter implements IDaemonAdapter {
null, // No label/category/group support in the RPC API for now
new Date(tor.getLong(RPC_DATEADDED) * 1000L),
new Date(tor.getLong(RPC_DATEDONE) * 1000L),
errorString));
errorString,
settings.getType()));
}
// Return the list

3
lib/src/org/transdroid/daemon/Utorrent/UtorrentAdapter.java

@ -515,7 +515,8 @@ public class UtorrentAdapter implements IDaemonAdapter { @@ -515,7 +515,8 @@ public class UtorrentAdapter implements IDaemonAdapter {
addedOnDate,
completedOnDate,
// uTorrent doesn't give the error message, so just remind that there is some error
status == TorrentStatus.Error? "See GUI for error message": null));
status == TorrentStatus.Error? "See GUI for error message": null,
settings.getType()));
}
return torrents;

16
lib/src/org/transdroid/daemon/Vuze/VuzeAdapter.java

@ -31,6 +31,7 @@ import java.util.Map; @@ -31,6 +31,7 @@ import java.util.Map;
import org.apache.openjpa.lib.util.Base16Encoder;
import org.transdroid.daemon.Daemon;
import org.transdroid.daemon.DaemonException;
import org.transdroid.daemon.DaemonException.ExceptionType;
import org.transdroid.daemon.DaemonMethod;
import org.transdroid.daemon.DaemonSettings;
import org.transdroid.daemon.IDaemonAdapter;
@ -38,7 +39,6 @@ import org.transdroid.daemon.Priority; @@ -38,7 +39,6 @@ import org.transdroid.daemon.Priority;
import org.transdroid.daemon.Torrent;
import org.transdroid.daemon.TorrentFile;
import org.transdroid.daemon.TorrentStatus;
import org.transdroid.daemon.DaemonException.ExceptionType;
import org.transdroid.daemon.task.AddByFileTask;
import org.transdroid.daemon.task.AddByUrlTask;
import org.transdroid.daemon.task.DaemonTask;
@ -99,18 +99,27 @@ public class VuzeAdapter implements IDaemonAdapter { @@ -99,18 +99,27 @@ public class VuzeAdapter implements IDaemonAdapter {
case AddByFile:
byte[] bytes;
FileInputStream in = null;
try {
// Request to add a torrent by local .torrent file
String file = ((AddByFileTask)task).getFile();
FileInputStream in = new FileInputStream(new File(URI.create(file)));
in = new FileInputStream(new File(URI.create(file)));
bytes = new byte[in.available()];
in.read(bytes, 0, in.available());
in.close();
} catch (FileNotFoundException e) {
return new DaemonTaskFailureResult(task, new DaemonException(ExceptionType.FileAccessError, e.toString()));
} catch (IllegalArgumentException e) {
return new DaemonTaskFailureResult(task, new DaemonException(ExceptionType.FileAccessError, "Invalid local URI"));
} catch (Exception e) {
return new DaemonTaskFailureResult(task, new DaemonException(ExceptionType.FileAccessError, e.toString()));
} finally {
try {
if (in != null)
in.close();
} catch (IOException e) {
// Ignore; it was already closed or never opened
}
}
makeVuzeCall(DaemonMethod.AddByFile, "createFromBEncodedData[byte[]]", new String[] { Base16Encoder.encode(bytes) });
return new DaemonTaskSuccessResult(task);
@ -406,7 +415,8 @@ public class VuzeAdapter implements IDaemonAdapter { @@ -406,7 +415,8 @@ public class VuzeAdapter implements IDaemonAdapter {
null, // TODO: Implement Vuze label support
new Date((Long) statsinfo.get("time_started")), // dateAdded
null, // Unsupported?
error));
error,
settings.getType()));
}

84
lib/src/org/transdroid/daemon/util/FileSizeConverter.java

@ -15,71 +15,99 @@ @@ -15,71 +15,99 @@
* along with Transdroid. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.transdroid.daemon.util;
package org.transdroid.daemon.util;
/**
* Quick and dirty file size formatter.
*
* @author erickok
*
*/
public class FileSizeConverter {
private static final String DECIMAL_FORMATTER = "%.1f";
/**
* A quantity in which to express a file size.
*
* @author erickok
*
*/
public enum SizeUnit {
B,
KB,
MB,
GB
B, KB, MB, GB
}
private static int INC_SIZE = 1024;
// Returns a file size given in bytes to a different unit, as a formatted string
public static String getSize(long from, SizeUnit to)
{
/**
* Returns a file size (in bytes) in a different unit, as a formatted string
* @param from The file size in bytes
* @param to The unit to convert to
* @return A formatted string with number (rounded to one decimal) and unit, e.g. 1177.4MB
*/
public static String getSize(long from, SizeUnit to) {
String out;
switch (to) {
case B:
out = String.valueOf(from);
break;
case KB:
out = String.format(DECIMAL_FORMATTER, ((double)from) / 1024);
out = String.format(DECIMAL_FORMATTER, ((double) from) / INC_SIZE);
break;
case MB:
out = String.format(DECIMAL_FORMATTER, ((double)from) / 1024 / 1024);
out = String.format(DECIMAL_FORMATTER, ((double) from) / INC_SIZE / INC_SIZE);
break;
default:
out = String.format(DECIMAL_FORMATTER, ((double)from) / 1024 / 1024 / 1024);
out = String.format(DECIMAL_FORMATTER, ((double) from) / INC_SIZE / INC_SIZE / INC_SIZE);
break;
}
return (out + " " + to.toString());
return (out + " " + to.toString());
}
// Returns a file size in bytes in a nice readable formatted string
/**
* Returns a file size as nice readable string, with unit, e.g. 1234567890 (bytes) returns 1,15GB
* @param from The file size in bytes
* @return A formatted string with number (rounded to one decimal), with unit text
*/
public static String getSize(long from) {
return getSize(from, true);
}
// Returns a file size in bytes in a nice readable formatted string
/**
* Returns a file size as nice readable string, e.g. 1234567890 (bytes) returns 1,15 or 1,15GB
* @param from The file size in bytes
* @param withUnit Whether to also append the appropriate unit (B, KB, MB, GB) as text
* @return A formatted string with number (rounded to one decimal) and optionally unit
*/
public static String getSize(long from, boolean withUnit) {
if (from < INC_SIZE) {
return String.valueOf(from) + (withUnit? SizeUnit.B.toString(): "");
} else if (from < (INC_SIZE * INC_SIZE)) {
return String.format(DECIMAL_FORMATTER, ((double)from) / INC_SIZE) + (withUnit? SizeUnit.KB.toString(): "");
return String.valueOf(from) + (withUnit ? SizeUnit.B.toString() : "");
} else if (from < (INC_SIZE * INC_SIZE)) {
return String.format(DECIMAL_FORMATTER, ((double) from) / INC_SIZE)
+ (withUnit ? SizeUnit.KB.toString() : "");
} else if (from < (INC_SIZE * INC_SIZE * INC_SIZE)) {
return String.format(DECIMAL_FORMATTER, ((double)from) / INC_SIZE / INC_SIZE) + (withUnit? SizeUnit.MB.toString(): "");
} else {
return String.format(DECIMAL_FORMATTER, ((double)from) / INC_SIZE / INC_SIZE / INC_SIZE) + (withUnit? SizeUnit.GB.toString(): "");
return String.format(DECIMAL_FORMATTER, ((double) from) / INC_SIZE / INC_SIZE)
+ (withUnit ? SizeUnit.MB.toString() : "");
} else {
return String.format(DECIMAL_FORMATTER, ((double) from) / INC_SIZE / INC_SIZE / INC_SIZE)
+ (withUnit ? SizeUnit.GB.toString() : "");
}
}
/**
* Returns the unit to display some file size (as returned by getSize(long)) in, e.g. 1234567890 (bytes) returns GB
* as it is 1.2GB big
* @param from The file size in bytes
* @return The unit, i.e. B, KB, MB or GB
*/
public static SizeUnit getSizeUnit(long from) {
if (from < INC_SIZE) {
return SizeUnit.B;
} else if (from < (INC_SIZE * INC_SIZE)) {
return SizeUnit.KB;
} else if (from < (INC_SIZE * INC_SIZE * INC_SIZE)) {
return SizeUnit.MB;
} else {
return SizeUnit.GB;
}
}
}

2
lite/.classpath

@ -9,6 +9,6 @@ @@ -9,6 +9,6 @@
<attribute name="optional" value="true"/>
</attributes>
</classpathentry>
<classpathentry combineaccessrules="false" kind="src" path="/Transdroid Torrent Connect"/>
<classpathentry combineaccessrules="false" exported="true" kind="src" path="/Transdroid Torrent Connect"/>
<classpathentry kind="output" path="bin/classes"/>
</classpath>

64
lite/AndroidManifest.xml

@ -17,12 +17,13 @@ @@ -17,12 +17,13 @@
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:icon="@drawable/ic_activity_torrents"
android:label="@string/app_name"
android:theme="@style/TransdroidTheme" >
<!-- Main activities -->
<activity
android:name="org.transdroid.lite.gui.TorrentsActivity_"
android:icon="@drawable/ic_activity_torrents"
android:name="org.transdroid.core.gui.TorrentsActivity_"
android:label="@string/app_name"
android:uiOptions="splitActionBarWhenNarrow" >
<intent-filter>
@ -30,12 +31,59 @@ @@ -30,12 +31,59 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
</intent-filter>
<meta-data
android:name="android.app.default_searchable"
android:value="org.transdroid.gui.search.Search" />
</activity>
<activity android:name="org.transdroid.lite.gui.settings.MainSettingsActivity_" />
<activity android:name="org.transdroid.lite.gui.settings.ServerSettingsActivity_" />
<activity android:name="org.transdroid.lite.gui.settings.WebsearchSettingsActivity_" />
<activity android:name="org.transdroid.lite.gui.settings.RssfeedSettingsActivity_" />
<activity android:name="org.transdroid.lite.gui.settings.OtherSettingsActivity_" />
<activity
android:name="org.transdroid.core.gui.DetailsActivity_"
android:uiOptions="splitActionBarWhenNarrow" >
</activity>
<!-- Settings screens -->
<activity android:name="org.transdroid.core.gui.settings.MainSettingsActivity_" />
<activity android:name="org.transdroid.core.gui.settings.ServerSettingsActivity_" />
<activity android:name="org.transdroid.core.gui.settings.WebsearchSettingsActivity_" />
<activity android:name="org.transdroid.core.gui.settings.RssfeedSettingsActivity_" />
<activity android:name="org.transdroid.core.gui.settings.OtherSettingsActivity_" />
<!-- Search -->
<activity
android:name="org.transdroid.core.gui.SearchActivity"
android:label="@string/search_torrentsearch" >
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
<meta-data
android:name="android.app.default_searchable"
android:value="org.transdroid.gui.search.Search" />
<meta-data
android:name="android.app.searchable"
android:resource="@xml/searchable" />
</activity>
<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>
</manifest>

2
lite/res/layout-w600dp/activity_torrents.xml

@ -21,7 +21,7 @@ @@ -21,7 +21,7 @@
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="3"
class="org.transdroid.gui.TorrentsFragment"
class="org.transdroid.core.gui.TorrentsFragment_"
tools:layout="@layout/fragment_torrents" />
</LinearLayout>

4
lite/res/layout-w720dp/activity_torrents.xml

@ -21,7 +21,7 @@ @@ -21,7 +21,7 @@
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="2"
class="org.transdroid.gui.TorrentsFragment"
class="org.transdroid.core.gui.TorrentsFragment_"
tools:layout="@layout/fragment_torrents" />
<fragment
@ -29,7 +29,7 @@ @@ -29,7 +29,7 @@
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="2"
class="org.transdroid.gui.DetailsFragment"
class="org.transdroid.core.gui.DetailsFragment_"
tools:layout="@layout/fragment_details" />
</LinearLayout>

16
lite/res/layout/activity_details.xml

@ -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>

3
lite/res/layout/activity_torrents.xml

@ -10,6 +10,7 @@ @@ -10,6 +10,7 @@
android:id="@+id/torrent_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="org.transdroid.gui.TorrentsFragment" tools:layout="@layout/fragment_torrents"/>
class="org.transdroid.core.gui.TorrentsFragment_"
tools:layout="@layout/fragment_torrents" />
</FrameLayout>

1
lite/res/layout/fragment_details.xml

@ -19,6 +19,7 @@ @@ -19,6 +19,7 @@
android:drawableTop="@drawable/ic_empty_details"
android:drawablePadding="8dip"
android:text="@string/navigation_emptydetails"
android:gravity="center"
android:textIsSelectable="false"
android:visibility="gone" />

26
lite/res/layout/fragment_details_header.xml

@ -9,9 +9,9 @@ @@ -9,9 +9,9 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:text="UNLABELED"
android:textIsSelectable="true"
style="@style/LabelTextView" />
style="@style/LabelTextView"
android:visibility="invisible" />
<TextView
android:id="@+id/dateadded_text"
@ -19,7 +19,6 @@ @@ -19,7 +19,6 @@
android:layout_height="wrap_content"
android:layout_toLeftOf="@id/label_text"
android:layout_marginRight="@dimen/margin_half"
android:text="SINCE 07:50, 28 FEBRUARY"
android:textIsSelectable="false" />
<View
@ -40,20 +39,18 @@ @@ -40,20 +39,18 @@
android:layout_toRightOf="@id/separator"
android:layout_marginTop="@dimen/margin_half"
android:layout_marginLeft="@dimen/margin_half"
android:text="16.6"
android:textColor="#fff"
android:textSize="33sp"
android:fontFamily="sans-serif-light"
android:textIsSelectable="false" />
<TextView
android:id="@+id/uploaded_unit"
android:id="@+id/uploadedunit_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="@id/uploaded_text"
android:layout_toRightOf="@id/uploaded_text"
android:layout_marginLeft="4dip"
android:text="GB"
android:textColor="#fff"
android:fontFamily="sans-serif-light"
android:textIsSelectable="false" />
@ -65,7 +62,6 @@ @@ -65,7 +62,6 @@
android:layout_below="@id/uploaded_text"
android:layout_toRightOf="@id/separator"
android:layout_marginLeft="@dimen/margin_half"
android:text="RATIO 18.7"
android:textSize="12sp"
android:textIsSelectable="false" />
@ -77,7 +73,6 @@ @@ -77,7 +73,6 @@
android:layout_toRightOf="@id/separator"
android:layout_marginLeft="@dimen/margin_half"
android:layout_marginBottom="4dip"
android:text="↑1.4MB/s"
android:textSize="22sp"
android:textColor="#fff"
android:fontFamily="sans-serif-light"
@ -90,18 +85,16 @@ @@ -90,18 +85,16 @@
android:layout_below="@id/upspeed_text"
android:layout_toRightOf="@id/separator"
android:layout_marginLeft="@dimen/margin_half"
android:text="56 (1208) SEEDERS"
android:textSize="12sp"
android:textIsSelectable="false" />
<TextView
android:id="@+id/downloaded_unit"
android:id="@+id/downloadedunit_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="@id/uploaded_unit"
android:layout_alignBaseline="@id/uploadedunit_text"
android:layout_toLeftOf="@id/separator"
android:layout_marginRight="@dimen/margin_half"
android:text="MB"
android:textColor="#fff"
android:fontFamily="sans-serif-light"
android:textIsSelectable="false" />
@ -110,10 +103,9 @@ @@ -110,10 +103,9 @@
android:id="@+id/downloaded_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="@id/uploaded_unit"
android:layout_toLeftOf="@id/downloaded_unit"
android:layout_alignBaseline="@id/uploadedunit_text"
android:layout_toLeftOf="@id/downloadedunit_text"
android:layout_marginRight="4dip"
android:text="325.6"
android:textColor="#fff"
android:textSize="33sp"
android:fontFamily="sans-serif-light"
@ -126,7 +118,6 @@ @@ -126,7 +118,6 @@
android:layout_alignBaseline="@id/ratio_text"
android:layout_toLeftOf="@id/separator"
android:layout_marginRight="@dimen/margin_half"
android:text="/ 388.8MB"
android:textSize="12sp"
android:textIsSelectable="false" />
@ -137,7 +128,6 @@ @@ -137,7 +128,6 @@
android:layout_alignBaseline="@id/upspeed_text"
android:layout_toLeftOf="@id/separator"
android:layout_marginRight="@dimen/margin_half"
android:text="400.8KB/s↓"
android:textSize="22sp"
android:textColor="#fff"
android:fontFamily="sans-serif-light"
@ -150,7 +140,6 @@ @@ -150,7 +140,6 @@
android:layout_alignBaseline="@id/seeders_text"
android:layout_toLeftOf="@id/separator"
android:layout_marginRight="@dimen/margin_half"
android:text="128 (128) LEECHERS"
android:textSize="12sp"
android:textIsSelectable="false" />
@ -160,7 +149,6 @@ @@ -160,7 +149,6 @@
android:layout_height="wrap_content"
android:layout_below="@id/separator"
android:layout_marginBottom="@dimen/margin_half"
android:text="DOWNLADING (80%): ETA 38 SECONDS"
android:textIsSelectable="false" />
</RelativeLayout>

1
lite/res/layout/fragment_torrents.xml

@ -19,6 +19,7 @@ @@ -19,6 +19,7 @@
android:drawableTop="@drawable/ic_empty_details"
android:drawablePadding="8dip"
android:text="@string/navigation_emptytorrents"
android:gravity="center"
android:textIsSelectable="false"
android:visibility="gone" />

11
lite/res/layout/list_item_torrent.xml

@ -15,7 +15,8 @@ @@ -15,7 +15,8 @@
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/margin_half"
android:layout_marginTop="@dimen/margin_half"
android:src="@drawable/ic_priority_normal" />
android:src="@drawable/ic_priority_normal"
android:contentDescription="@string/status_priority_normal" />
<fr.marvinlabs.widget.InertCheckBox
android:id="@+id/torrent_checkbox"
@ -30,7 +31,6 @@ @@ -30,7 +31,6 @@
android:layout_toRightOf="@id/torrent_checkbox"
android:textColor="#fff"
android:textSize="15sp"
android:text="CSI.Miami.Title-That_is_long.S13E16.HDTV.x264-LOL.mp4"
android:textIsSelectable="true" />
<TextView
@ -41,7 +41,6 @@ @@ -41,7 +41,6 @@
android:layout_alignParentRight="true"
android:layout_marginLeft="@dimen/margin_half"
android:layout_marginTop="4dip"
android:text="UNKNOWN ETA"
android:textSize="12sp"
android:textIsSelectable="false" />
@ -52,14 +51,14 @@ @@ -52,14 +51,14 @@
android:layout_alignBaseline="@id/ratio_text"
android:layout_toLeftOf="@id/ratio_text"
android:layout_toRightOf="@id/torrent_checkbox"
android:text="325.6MB OF 388.8MB (0%)"
android:textSize="12sp"
android:textIsSelectable="false" />
<org.transdroid.lite.gui.TorrentProgressBar
<org.transdroid.core.gui.lists.TorrentProgressBar
android:id="@+id/torrent_progressbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/torrent_checkbox"
android:layout_below="@id/ratio_text"
android:layout_marginTop="@dimen/margin_half"
android:layout_marginBottom="@dimen/margin_half" />
@ -71,7 +70,6 @@ @@ -71,7 +70,6 @@
android:layout_below="@id/torrent_progressbar"
android:layout_alignParentRight="true"
android:layout_marginLeft="@dimen/margin_half"
android:text="↓400.8KB/s ↑1.4MB/s"
android:textSize="12sp"
android:textIsSelectable="false" />
@ -82,7 +80,6 @@ @@ -82,7 +80,6 @@
android:layout_alignBaseline="@id/speed_text"
android:layout_toLeftOf="@id/speed_text"
android:layout_toRightOf="@id/torrent_checkbox"
android:text="246 (288) LEECHERS"
android:textSize="12sp"
android:textIsSelectable="false" />

58
lite/res/layout/list_item_torrentfile.xml

@ -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>

9
lite/res/menu/activity_details.xml

@ -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>

59
lite/res/values/strings.xml

@ -45,9 +45,46 @@ @@ -45,9 +45,46 @@
<string name="navigation_status_onlyup">Uploading</string>
<string name="navigation_status_onlyactive">Active</string>
<string name="navigation_status_onlyinactive">Inactive</string>
<string name="navigation_emptytorrents">Connected, but no torrent are active on the server</string>
<string name="navigation_emptytorrents">Connected, but no torrent are active within the current filter</string>
<string name="navigation_emptydetails">Select a torrent to view its details</string>
<string name="status_waiting">Waiting to check&#8230;</string>
<string name="status_checking">Verifying local data&#8230;</string>
<string name="status_waitingtodl">Waiting to download %s</string>
<string name="status_error">Error&#8230;</string>
<string name="status_size1">%1$s OF %2$s (%3$s)</string>
<string name="status_size2">%1$s, UPLOADED %2$s</string>
<string name="status_sincedate">SINCE $s</string>
<string name="status_eta">~ %1$s</string>
<string name="status_etalong">ETA %1$s</string>
<string name="status_unknowneta">UNKNOWN ETA</string>
<string name="status_ratio">RATIO %1$s</string>
<string name="status_peers">%1$s OF %2$s PEERS</string>
<string name="status_speed_up">↑ %1$s</string>
<string name="status_speed_down">↓ %1$s</string>
<string name="status_downloading">Downloading</string>
<string name="status_seeding">Seeding</string>
<string name="status_paused">Paused</string>
<string name="status_queued">Queued</string>
<string name="status_stopped">Stopped</string>
<string name="status_unknown">Unknown status</string>
<string name="status_priority_off">Not downloaded</string>
<string name="status_priority_low">Low priority</string>
<string name="status_priority_normal">Normal priority</string>
<string name="status_priority_high">High priority</string>
<string name="status_trackers">TRACKERS</string>
<string name="status_errors">ERRORS</string>
<string name="status_files">FILES</string>
<string name="labels_showall">All labels</string>
<string name="labels_unlabeled">Unlabeled</string>
<string name="labels_newlabel">New label</string>
<string name="labels_no_support">Setting a label is not supported by your client</string>
<string name="search_torrentsearch">Torrent search</string>
<string name="search_hint">Search for torrents</string>
<string name="search_"></string>
<string name="pref_servers">Servers</string>
<string name="pref_addserver">Add new server</string>
<string name="pref_searchsites">Search sites</string>
@ -120,6 +157,26 @@ @@ -120,6 +157,26 @@
<string name="pref_sendlog_info">Get support or report a bug</string>
<string name="pref_about">About</string>
<string name="error_httperror">Error during communication; check your connection</string>
<string name="error_jsonrequesterror">Internal error building request</string>
<string name="error_jsonresponseerror">Error parsing server response (please check your settings)</string>
<string name="error_daemonnotconnected">Web interface not connected to a running daemon</string>
<string name="error_401">Access denied (please check your settings)</string>
<string name="error_torrentfile">Can\'t read .torrent file</string>
<string name="error_parsingrss">Error while parsing the RSS feed</string>
<string name="error_invalid_url_form">This URL is not well-formed</string>
<string name="error_invalid_search_url">Your web search URL is invalid:</string>
<string name="error_invalid_ip_or_hostname">Input is not a valid IP address or host name</string>
<string name="error_invalid_port_number">Port number is always numeric</string>
<string name="error_invalid_directory">Directory paths end with a / or \</string>
<string name="error_invalid_timeout">Timeout can not be empty and is a positive number</string>
<string name="error_no_url_enclosure">The RSS feed item didn\'t provide an URL enclosure or link tag pointing to the .torrent file</string>
<string name="error_no_link">The RSS feed item does not provide a link to browse to</string>
<string name="error_norssfeed">URL is not a (valid) RSS feed</string>
<string name="error_media_not_available">SD card not available to read/write</string>
<string name="error_no_valid_settings_file">File does not seem to contain Transdroid settings</string>
<string name="error_file_not_found">There is no settings file found</string>
<string-array name="pref_daemon_types" translatable="false">
<item>BitComet</item>
<item>Bitflu 1.2+</item>

8
lite/res/xml/searchable.xml

@ -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=" ? " />

2
lite/src/org/transdroid/lite/app/search/SearchHelper.java → lite/src/org/transdroid/core/app/search/SearchHelper.java

@ -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;

2
lite/src/org/transdroid/lite/app/search/SearchResult.java → lite/src/org/transdroid/core/app/search/SearchResult.java

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
package org.transdroid.lite.app.search;
package org.transdroid.core.app.search;
import java.util.Date;

6
lite/src/org/transdroid/lite/app/search/SearchSite.java → lite/src/org/transdroid/core/app/search/SearchSite.java

@ -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;

2
lite/src/org/transdroid/lite/app/settings/AboutSettings.java → lite/src/org/transdroid/core/app/settings/AboutSettings.java

@ -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;

52
lite/src/org/transdroid/lite/app/settings/ApplicationSettings.java → lite/src/org/transdroid/core/app/settings/ApplicationSettings.java

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
package org.transdroid.lite.app.settings;
package org.transdroid.core.app.settings;
import java.util.ArrayList;
import java.util.List;
@ -52,7 +52,8 @@ public class ApplicationSettings { @@ -52,7 +52,8 @@ public class ApplicationSettings {
}
/**
* Returns the user-specified server settings for a specific server
* Returns the user-specified server settings for a specific server. WARNING: This method does not check if the
* settings actually exist and may rely on empty defaults if called not a non-existing server.
* @param order The order number/identifying key of the settings to retrieve
* @return The server settings object, loaded from shared preferences
*/
@ -71,6 +72,53 @@ public class ApplicationSettings { @@ -71,6 +72,53 @@ public class ApplicationSettings {
prefs.getBoolean("server_alarmnew_" + order, false), false);
}
/**
* Returns the settings of the server that was last used by the user. As opposed to getLastUsedServerKey(int), this
* method checks whether a server was already registered as being last used and check whether the server still
* exists. It returns the first server if that fails. If no servers are configured, null is returned.
* @return A server settings object of the last used server (or, if not known, the first server), or null if no
* servers exist
*/
public ServerSetting getLastUsedServer() {
int max = getMaxServer(); // Zero-based index, so with max == 0 there is 1 server
if (max < 0) {
// No servers configured
return null;
}
int last = getLastUsedServerKey();
if (last < 0 || last > max) {
// Last server was never set or no longer exists
return getServerSetting(0);
}
return getServerSetting(last);
}
/**
* Returns the order number/unique key of the server that the used last used; use with getServerSettings(int) or
* call getLastUsedServer directly. WARNING: the returned integer may no longer refer to a known server settings
* object: check the bounds.
* @return An integer indicating the order number/key or the last used server, or -1 if it was not set
*/
public int getLastUsedServerKey() {
return prefs.getInt("system_lastusedserver", -1);
}
/**
* Registers some server as being the last used by the user
* @param server The settings of the server that the user last used
*/
public void setLastUsedServer(ServerSetting server) {
setLastUsedServerKey(server.getOrder());
}
/**
* Registers the order number/unique key of some server as being last used by the user
* @param order The key identifying the specific server
*/
public void setLastUsedServerKey(int order) {
prefs.edit().putInt("system_lastusedserver", order).commit();
}
/**
* Returns all available user-configured web-based (as opped to in-app) search sites
* @return A list of all stored web search site settings objects

2
lite/src/org/transdroid/lite/app/settings/NotificationSettings.java → lite/src/org/transdroid/core/app/settings/NotificationSettings.java

@ -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;

6
lite/src/org/transdroid/lite/app/settings/RssfeedSetting.java → lite/src/org/transdroid/core/app/settings/RssfeedSetting.java

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
package org.transdroid.lite.app.settings;
package org.transdroid.core.app.settings;
import org.transdroid.lite.gui.navigation.FilterItem;
import org.transdroid.core.gui.lists.SimpleListItem;
import android.net.Uri;
import android.text.TextUtils;
@ -9,7 +9,7 @@ import android.text.TextUtils; @@ -9,7 +9,7 @@ import android.text.TextUtils;
* Represents a user-specified RSS feed.
* @author Eric Kok
*/
public class RssfeedSetting implements FilterItem {
public class RssfeedSetting implements SimpleListItem {
private static final String DEFAULT_NAME = "Default";

33
lite/src/org/transdroid/lite/app/settings/ServerSetting.java → lite/src/org/transdroid/core/app/settings/ServerSetting.java

@ -1,8 +1,10 @@ @@ -1,8 +1,10 @@
package org.transdroid.lite.app.settings;
package org.transdroid.core.app.settings;
import org.transdroid.core.gui.lists.SimpleListItem;
import org.transdroid.daemon.Daemon;
import org.transdroid.daemon.DaemonSettings;
import org.transdroid.daemon.IDaemonAdapter;
import org.transdroid.daemon.OS;
import org.transdroid.lite.gui.navigation.FilterItem;
import android.text.TextUtils;
@ -10,7 +12,7 @@ import android.text.TextUtils; @@ -10,7 +12,7 @@ import android.text.TextUtils;
* Represents a user-configured remote server.
* @author Eric Kok
*/
public class ServerSetting implements FilterItem {
public class ServerSetting implements SimpleListItem {
private static final String DEFAULT_NAME = "Default";
@ -192,4 +194,29 @@ public class ServerSetting implements FilterItem { @@ -192,4 +194,29 @@ public class ServerSetting implements FilterItem {
+ (Daemon.supportsCustomFolder(getType()) && getFolder() != null ? getFolder() : "");
}
@Override
public boolean equals(Object o) {
if (o instanceof ServerSetting) {
// Directly compare order numbers/unique keys
return ((ServerSetting) o).getOrder() == this.key;
} else if (o instanceof DaemonSettings) {
// Old-style DaemonSettings objects can be equal if they were constructed from a ServerSettings object:
// idString should reflect the local key/order
return ((DaemonSettings) o).getIdString().equals(Integer.toString(this.key));
}
// Other objects are never equal to this
return false;
}
public IDaemonAdapter createServerAdapter() {
// Convert local server settings into an old-style DaemonSetting object
// The local integer key is converted to the idString string
// TODO: Add localaddress and localnetwork to DaemonSettings, or solve properly rework the Connect library
// handling of settings
DaemonSettings daemonSettings = new DaemonSettings(name, type, address, port, ssl, sslTrustAll, sslTrustKey,
folder, useAuthentication, username, password, extraPass, os, downloadDir, ftpUrl, ftpPassword,
timeout, alarmOnFinishedDownload, alarmOnNewTorrent, Integer.toString(key), isAutoGenerated);
return type.createAdapter(daemonSettings);
}
}

6
lite/src/org/transdroid/lite/app/settings/WebsearchSetting.java → lite/src/org/transdroid/core/app/settings/WebsearchSetting.java

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

132
lite/src/org/transdroid/core/gui/DetailsActivity.java

@ -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();
}
}

113
lite/src/org/transdroid/core/gui/DetailsFagment.java

@ -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;
}
}

22
lite/src/org/transdroid/core/gui/SearchHistoryProvider.java

@ -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();
}
}

253
lite/src/org/transdroid/core/gui/TorrentsActivity.java

@ -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();
}
}

69
lite/src/org/transdroid/core/gui/TorrentsFragment.java

@ -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) {
}
}

141
lite/src/org/transdroid/core/gui/lists/DetailsAdapter.java

@ -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;
}
}
}

233
lite/src/org/transdroid/core/gui/lists/LocalTorrent.java

@ -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;
}
}
}

4
lite/src/org/transdroid/lite/gui/navigation/FilterItem.java → lite/src/org/transdroid/core/gui/lists/SimpleListItem.java

@ -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();

91
lite/src/org/transdroid/core/gui/lists/SimpleListItemAdapter.java

@ -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;
}
}
}

10
lite/src/org/transdroid/lite/gui/navigation/FilterItemView.java → lite/src/org/transdroid/core/gui/lists/SimpleListItemView.java

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
package org.transdroid.lite.gui.navigation;
package org.transdroid.core.gui.lists;
import org.androidannotations.annotations.EViewGroup;
import org.androidannotations.annotations.ViewById;
@ -9,20 +9,20 @@ import android.widget.LinearLayout; @@ -9,20 +9,20 @@ import android.widget.LinearLayout;
import android.widget.TextView;
/**
* View that represents some {@link FilterItem} object and simple prints out the text (in proper style)
* View that represents some {@link SimpleListItem} object and simple prints out the text (in proper style)
* @author Eric Kok
*/
@EViewGroup(R.layout.list_item_filter)
public class FilterItemView extends LinearLayout {
public class SimpleListItemView extends LinearLayout {
@ViewById
protected TextView itemText;
public FilterItemView(Context context) {
public SimpleListItemView(Context context) {
super(context);
}
public void bind(FilterItem filterItem) {
public void bind(SimpleListItem filterItem) {
itemText.setText(filterItem.getName());
}

85
lite/src/org/transdroid/core/gui/lists/TorrentDetailsView.java

@ -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"));
}
}

53
lite/src/org/transdroid/core/gui/lists/TorrentFileView.java

@ -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;
}
}
}

2
lite/src/org/transdroid/lite/gui/lists/TorrentProgressBar.java → lite/src/org/transdroid/core/gui/lists/TorrentProgressBar.java

@ -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;

47
lite/src/org/transdroid/core/gui/lists/TorrentView.java

@ -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);
}
}

67
lite/src/org/transdroid/core/gui/lists/TorrentsAdapter.java

@ -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;
}
}

78
lite/src/org/transdroid/core/gui/navigation/FilterListAdapter.java

@ -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;
}
}
}

5
lite/src/org/transdroid/lite/gui/navigation/FilterSeparatorView.java → lite/src/org/transdroid/core/gui/navigation/FilterSeparatorView.java

@ -1,8 +1,9 @@ @@ -1,8 +1,9 @@
package org.transdroid.lite.gui.navigation;
package org.transdroid.core.gui.navigation;
import org.androidannotations.annotations.EViewGroup;
import org.androidannotations.annotations.ViewById;
import org.transdroid.core.R;
import org.transdroid.core.gui.lists.SimpleListItem;
import android.content.Context;
import android.widget.LinearLayout;
@ -25,7 +26,7 @@ public class FilterSeparatorView extends LinearLayout { @@ -25,7 +26,7 @@ public class FilterSeparatorView extends LinearLayout {
super(context);
}
public void bind(FilterItem filterItem) {
public void bind(SimpleListItem filterItem) {
separatorText.setText(text);
}

6
lite/src/org/transdroid/lite/gui/navigation/Label.java → lite/src/org/transdroid/core/gui/navigation/Label.java

@ -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;

2
lite/src/org/transdroid/lite/gui/navigation/NavigationHelper.java → lite/src/org/transdroid/core/gui/navigation/NavigationHelper.java

@ -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;

5
lite/src/org/transdroid/lite/gui/navigation/StatusType.java → lite/src/org/transdroid/core/gui/navigation/StatusType.java

@ -1,9 +1,10 @@ @@ -1,9 +1,10 @@
package org.transdroid.lite.gui.navigation;
package org.transdroid.core.gui.navigation;
import java.util.Arrays;
import java.util.List;
import org.transdroid.core.R;
import org.transdroid.core.gui.lists.SimpleListItem;
import android.content.Context;
@ -57,7 +58,7 @@ public enum StatusType { @@ -57,7 +58,7 @@ public enum StatusType {
*/
abstract StatusTypeFilter getFilterItem(Context context);
public static class StatusTypeFilter implements FilterItem {
public static class StatusTypeFilter implements SimpleListItem {
private final String name;

20
lite/src/org/transdroid/lite/gui/settings/MainSettingsActivity.java → lite/src/org/transdroid/core/gui/settings/MainSettingsActivity.java

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
package org.transdroid.lite.gui.settings;
package org.transdroid.core.gui.settings;
import java.util.ArrayList;
import java.util.List;
@ -6,15 +6,15 @@ import java.util.List; @@ -6,15 +6,15 @@ import java.util.List;
import org.androidannotations.annotations.Bean;
import org.androidannotations.annotations.EActivity;
import org.transdroid.core.R;
import org.transdroid.lite.app.search.SearchHelper;
import org.transdroid.lite.app.search.SearchSite;
import org.transdroid.lite.app.settings.ApplicationSettings;
import org.transdroid.lite.app.settings.RssfeedSetting;
import org.transdroid.lite.app.settings.ServerSetting;
import org.transdroid.lite.app.settings.WebsearchSetting;
import org.transdroid.lite.gui.settings.RssfeedPreference.OnRssfeedClickedListener;
import org.transdroid.lite.gui.settings.ServerPreference.OnServerClickedListener;
import org.transdroid.lite.gui.settings.WebsearchPreference.OnWebsearchClickedListener;
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.RssfeedSetting;
import org.transdroid.core.app.settings.ServerSetting;
import org.transdroid.core.app.settings.WebsearchSetting;
import org.transdroid.core.gui.settings.RssfeedPreference.OnRssfeedClickedListener;
import org.transdroid.core.gui.settings.ServerPreference.OnServerClickedListener;
import org.transdroid.core.gui.settings.WebsearchPreference.OnWebsearchClickedListener;
import android.os.Bundle;
import android.preference.ListPreference;

4
lite/src/org/transdroid/lite/gui/settings/OtherSettingsActivity.java → lite/src/org/transdroid/core/gui/settings/OtherSettingsActivity.java

@ -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;

4
lite/src/org/transdroid/lite/gui/settings/RssfeedPreference.java → lite/src/org/transdroid/core/gui/settings/RssfeedPreference.java

@ -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;

4
lite/src/org/transdroid/lite/gui/settings/RssfeedSettingsActivity.java → lite/src/org/transdroid/core/gui/settings/RssfeedSettingsActivity.java

@ -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;

4
lite/src/org/transdroid/lite/gui/settings/ServerPreference.java → lite/src/org/transdroid/core/gui/settings/ServerPreference.java

@ -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;

4
lite/src/org/transdroid/lite/gui/settings/ServerSettingsActivity.java → lite/src/org/transdroid/core/gui/settings/ServerSettingsActivity.java

@ -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;

4
lite/src/org/transdroid/lite/gui/settings/WebsearchPreference.java → lite/src/org/transdroid/core/gui/settings/WebsearchPreference.java

@ -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;

4
lite/src/org/transdroid/lite/gui/settings/WebsearchSettingsActivity.java → lite/src/org/transdroid/core/gui/settings/WebsearchSettingsActivity.java

@ -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;

47
lite/src/org/transdroid/lite/gui/DetailsFagment.java

@ -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
}
}

94
lite/src/org/transdroid/lite/gui/TorrentsActivity.java

@ -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
}
}

11
lite/src/org/transdroid/lite/gui/TorrentsFragment.java

@ -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 {
}

125
lite/src/org/transdroid/lite/gui/navigation/FilterAdapter.java

@ -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…
Cancel
Save