Browse Source

New Material icons, reworking main screen design, corrting action bars... WIP

material
Eric Kok 9 years ago
parent
commit
676a21fb92
  1. 18
      app/build.gradle
  2. 2
      app/src/main/java/org/transdroid/core/app/settings/SystemSettings.java
  3. 91
      app/src/main/java/org/transdroid/core/gui/DetailsActivity.java
  4. 202
      app/src/main/java/org/transdroid/core/gui/DetailsFragment.java
  5. 59
      app/src/main/java/org/transdroid/core/gui/ServerSelectionView.java
  6. 39
      app/src/main/java/org/transdroid/core/gui/ServerStatusView.java
  7. 18
      app/src/main/java/org/transdroid/core/gui/TorrentTasksExecutor.java
  8. 267
      app/src/main/java/org/transdroid/core/gui/TorrentsActivity.java
  9. 103
      app/src/main/java/org/transdroid/core/gui/TorrentsFragment.java
  10. 16
      app/src/main/java/org/transdroid/core/gui/lists/SimpleListItemView.java
  11. 45
      app/src/main/java/org/transdroid/core/gui/lists/TorrentDetailsView.java
  12. 13
      app/src/main/java/org/transdroid/core/gui/lists/TorrentFileView.java
  13. 2
      app/src/main/java/org/transdroid/core/gui/lists/TorrentStatusLayout.java
  14. 17
      app/src/main/java/org/transdroid/core/gui/lists/TorrentView.java
  15. 24
      app/src/main/java/org/transdroid/core/gui/lists/TorrentsAdapter.java
  16. 20
      app/src/main/java/org/transdroid/core/gui/navigation/FilterListAdapter.java
  17. 10
      app/src/main/java/org/transdroid/core/gui/navigation/FilterListItemAdapter.java
  18. 15
      app/src/main/java/org/transdroid/core/gui/navigation/FilterListItemView.java
  19. 18
      app/src/main/java/org/transdroid/core/gui/navigation/FilterSeparatorView.java
  20. 38
      app/src/main/java/org/transdroid/core/gui/navigation/Label.java
  21. 14
      app/src/main/java/org/transdroid/core/gui/navigation/NavigationFilter.java
  22. 43
      app/src/main/java/org/transdroid/core/gui/navigation/NavigationHelper.java
  23. 9
      app/src/main/java/org/transdroid/core/gui/navigation/RefreshableActivity.java
  24. 23
      app/src/main/java/org/transdroid/core/gui/rss/RssfeedLoader.java
  25. 30
      app/src/main/java/org/transdroid/core/gui/rss/RssfeedView.java
  26. 57
      app/src/main/java/org/transdroid/core/gui/rss/RssfeedsActivity.java
  27. 24
      app/src/main/java/org/transdroid/core/gui/rss/RssfeedsAdapter.java
  28. 46
      app/src/main/java/org/transdroid/core/gui/rss/RssfeedsFragment.java
  29. 4
      app/src/main/java/org/transdroid/core/gui/rss/RssitemStatusLayout.java
  30. 17
      app/src/main/java/org/transdroid/core/gui/rss/RssitemView.java
  31. 23
      app/src/main/java/org/transdroid/core/gui/rss/RssitemsActivity.java
  32. 22
      app/src/main/java/org/transdroid/core/gui/rss/RssitemsAdapter.java
  33. 21
      app/src/main/java/org/transdroid/core/gui/rss/RssitemsFragment.java
  34. 3
      app/src/main/java/org/transdroid/core/gui/search/BarcodeHelper.java
  35. 32
      app/src/main/java/org/transdroid/core/gui/search/SearchActivity.java
  36. 18
      app/src/main/java/org/transdroid/core/gui/search/SearchResultsAdapter.java
  37. 158
      app/src/main/java/org/transdroid/core/gui/search/SearchResultsFragment.java
  38. 2
      app/src/main/java/org/transdroid/core/gui/search/SearchSetting.java
  39. 9
      app/src/main/java/org/transdroid/core/gui/search/SearchSettingSelectionView.java
  40. 11
      app/src/main/java/org/transdroid/core/gui/search/SearchSettingsDropDownAdapter.java
  41. 20
      app/src/main/java/org/transdroid/core/gui/search/SearchSiteView.java
  42. 24
      app/src/main/java/org/transdroid/core/gui/search/SearchSitesAdapter.java
  43. 60
      app/src/main/java/org/transdroid/core/gui/search/UrlEntryDialog.java
  44. BIN
      app/src/main/res/drawable-hdpi/ic_action_add.png
  45. BIN
      app/src/main/res/drawable-hdpi/ic_action_discard_dark.png
  46. BIN
      app/src/main/res/drawable-hdpi/ic_action_discard_light.png
  47. BIN
      app/src/main/res/drawable-hdpi/ic_action_done.png
  48. BIN
      app/src/main/res/drawable-hdpi/ic_action_done_dark.png
  49. BIN
      app/src/main/res/drawable-hdpi/ic_action_done_light.png
  50. BIN
      app/src/main/res/drawable-hdpi/ic_action_drawer.png
  51. BIN
      app/src/main/res/drawable-hdpi/ic_action_filter_dark.png
  52. BIN
      app/src/main/res/drawable-hdpi/ic_action_filter_light.png
  53. BIN
      app/src/main/res/drawable-hdpi/ic_action_force_recheck.png
  54. BIN
      app/src/main/res/drawable-hdpi/ic_action_forcerecheck_dark.png
  55. BIN
      app/src/main/res/drawable-hdpi/ic_action_forcerecheck_light.png
  56. BIN
      app/src/main/res/drawable-hdpi/ic_action_info.png
  57. BIN
      app/src/main/res/drawable-hdpi/ic_action_info_dark.png
  58. BIN
      app/src/main/res/drawable-hdpi/ic_action_info_light.png
  59. BIN
      app/src/main/res/drawable-hdpi/ic_action_labels.png
  60. BIN
      app/src/main/res/drawable-hdpi/ic_action_labels_dark.png
  61. BIN
      app/src/main/res/drawable-hdpi/ic_action_labels_light.png
  62. BIN
      app/src/main/res/drawable-hdpi/ic_action_pause.png
  63. BIN
      app/src/main/res/drawable-hdpi/ic_action_pause_dark.png
  64. BIN
      app/src/main/res/drawable-hdpi/ic_action_pause_light.png
  65. BIN
      app/src/main/res/drawable-hdpi/ic_action_priority_high.png
  66. BIN
      app/src/main/res/drawable-hdpi/ic_action_priority_high_dark.png
  67. BIN
      app/src/main/res/drawable-hdpi/ic_action_priority_high_light.png
  68. BIN
      app/src/main/res/drawable-hdpi/ic_action_priority_low.png
  69. BIN
      app/src/main/res/drawable-hdpi/ic_action_priority_low_dark.png
  70. BIN
      app/src/main/res/drawable-hdpi/ic_action_priority_low_light.png
  71. BIN
      app/src/main/res/drawable-hdpi/ic_action_priority_medium.png
  72. BIN
      app/src/main/res/drawable-hdpi/ic_action_priority_normal_dark.png
  73. BIN
      app/src/main/res/drawable-hdpi/ic_action_priority_normal_light.png
  74. BIN
      app/src/main/res/drawable-hdpi/ic_action_priority_off.png
  75. BIN
      app/src/main/res/drawable-hdpi/ic_action_priority_off_dark.png
  76. BIN
      app/src/main/res/drawable-hdpi/ic_action_priority_off_light.png
  77. BIN
      app/src/main/res/drawable-hdpi/ic_action_refresh.png
  78. BIN
      app/src/main/res/drawable-hdpi/ic_action_refresh_dark.png
  79. BIN
      app/src/main/res/drawable-hdpi/ic_action_refresh_light.png
  80. BIN
      app/src/main/res/drawable-hdpi/ic_action_remove.png
  81. BIN
      app/src/main/res/drawable-hdpi/ic_action_remove_dark.png
  82. BIN
      app/src/main/res/drawable-hdpi/ic_action_remove_light.png
  83. BIN
      app/src/main/res/drawable-hdpi/ic_action_resume.png
  84. BIN
      app/src/main/res/drawable-hdpi/ic_action_resume_dark.png
  85. BIN
      app/src/main/res/drawable-hdpi/ic_action_resume_light.png
  86. BIN
      app/src/main/res/drawable-hdpi/ic_action_rss.png.png
  87. BIN
      app/src/main/res/drawable-hdpi/ic_action_rss_dark.png
  88. BIN
      app/src/main/res/drawable-hdpi/ic_action_rss_light.png
  89. BIN
      app/src/main/res/drawable-hdpi/ic_action_save.png
  90. BIN
      app/src/main/res/drawable-hdpi/ic_action_save_dark.png
  91. BIN
      app/src/main/res/drawable-hdpi/ic_action_save_light.png
  92. BIN
      app/src/main/res/drawable-hdpi/ic_action_sort.png
  93. BIN
      app/src/main/res/drawable-hdpi/ic_action_sort_by_size_dark.png
  94. BIN
      app/src/main/res/drawable-hdpi/ic_action_sort_by_size_light.png
  95. BIN
      app/src/main/res/drawable-hdpi/ic_action_start.png
  96. BIN
      app/src/main/res/drawable-hdpi/ic_action_start_dark.png
  97. BIN
      app/src/main/res/drawable-hdpi/ic_action_start_light.png
  98. BIN
      app/src/main/res/drawable-hdpi/ic_action_stop.png
  99. BIN
      app/src/main/res/drawable-hdpi/ic_action_stop_dark.png
  100. BIN
      app/src/main/res/drawable-hdpi/ic_action_stop_light.png
  101. Some files were not shown because too many files have changed in this diff Show More

18
app/build.gradle

@ -2,12 +2,12 @@ apply plugin: 'com.android.application' @@ -2,12 +2,12 @@ apply plugin: 'com.android.application'
apply plugin: 'android-apt'
android {
compileSdkVersion 21
buildToolsVersion '21.1.1'
compileSdkVersion 22
buildToolsVersion '21.1.2'
defaultConfig {
minSdkVersion 15
targetSdkVersion 21
targetSdkVersion 22
versionCode 217
versionName '2.5.0-SNAPSHOT'
}
@ -33,16 +33,16 @@ android { @@ -33,16 +33,16 @@ android {
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'org.androidannotations:androidannotations-api:3.1'
compile 'org.androidannotations:androidannotations-api:3.2'
compile 'com.j256.ormlite:ormlite-core:4.48'
compile 'com.j256.ormlite:ormlite-android:4.48'
compile 'de.keyboardsurfer.android.widget:crouton:1.8.5@aar'
compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.+'
compile 'com.android.support:appcompat-v7:21.0.0'
compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.3'
compile 'com.android.support:appcompat-v7:22.0.0'
compile 'com.android.support:support-annotations:20.0.0'
compile 'com.getbase:floatingactionbutton:1.2.1'
compile 'com.afollestad:material-dialogs:0.3.6'
apt 'org.androidannotations:androidannotations:3.1'
compile 'com.getbase:floatingactionbutton:1.8.0'
compile 'com.afollestad:material-dialogs:0.6.3.3'
apt 'org.androidannotations:androidannotations:3.2'
}
apt {

2
app/src/main/java/org/transdroid/core/app/settings/SystemSettings.java

@ -76,7 +76,7 @@ public class SystemSettings { @@ -76,7 +76,7 @@ public class SystemSettings {
* @param lastChecked The date/time at which the {@link AppUpdateService} last checked the server for updates
*/
public void setLastCheckedForAppUpdates(Date lastChecked) {
prefs.edit().putLong("system_lastappupdatecheck", lastChecked == null ? -1L : lastChecked.getTime()).commit();
prefs.edit().putLong("system_lastappupdatecheck", lastChecked == null ? -1L : lastChecked.getTime()).apply();
}
}

91
app/src/main/java/org/transdroid/core/gui/DetailsActivity.java

@ -16,8 +16,14 @@ @@ -16,8 +16,14 @@
*/
package org.transdroid.core.gui;
import java.util.ArrayList;
import java.util.List;
import android.annotation.TargetApi;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.widget.Toolbar;
import android.widget.Toast;
import org.androidannotations.annotations.AfterViews;
import org.androidannotations.annotations.Background;
@ -29,8 +35,11 @@ import org.androidannotations.annotations.InstanceState; @@ -29,8 +35,11 @@ import org.androidannotations.annotations.InstanceState;
import org.androidannotations.annotations.OptionsItem;
import org.androidannotations.annotations.OptionsMenu;
import org.androidannotations.annotations.UiThread;
import org.androidannotations.annotations.ViewById;
import org.transdroid.R;
import org.transdroid.core.app.settings.*;
import org.transdroid.core.app.settings.ApplicationSettings;
import org.transdroid.core.app.settings.ServerSetting;
import org.transdroid.core.app.settings.SystemSettings_;
import org.transdroid.core.gui.lists.LocalTorrent;
import org.transdroid.core.gui.log.Log;
import org.transdroid.core.gui.navigation.Label;
@ -63,23 +72,19 @@ import org.transdroid.daemon.task.SetTrackersTask; @@ -63,23 +72,19 @@ import org.transdroid.daemon.task.SetTrackersTask;
import org.transdroid.daemon.task.StartTask;
import org.transdroid.daemon.task.StopTask;
import android.annotation.TargetApi;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.View;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
import de.keyboardsurfer.android.widget.crouton.Crouton;
/**
* An activity that holds a single torrents details fragment. It is used on devices (i.e. phones) where there is no room
* to show details in the {@link TorrentsActivity} directly. Task execution, such as loading of more details and
* updating file priorities, is performed in this activity via background methods.
* An activity that holds a single torrents details fragment. It is used on devices (i.e. phones) where there is no room to show details in the {@link
* TorrentsActivity} directly. Task execution, such as loading of more details and updating file priorities, is performed in this activity via
* background methods.
* @author Eric Kok
*/
@EActivity(resName = "activity_details")
@OptionsMenu(resName = "activity_details")
@EActivity(R.layout.activity_details)
@OptionsMenu(R.menu.activity_details)
public class DetailsActivity extends ActionBarActivity implements TorrentTasksExecutor, RefreshableActivity {
@Extra
@ -101,7 +106,9 @@ public class DetailsActivity extends ActionBarActivity implements TorrentTasksEx @@ -101,7 +106,9 @@ public class DetailsActivity extends ActionBarActivity implements TorrentTasksEx
private IDaemonAdapter currentConnection = null;
// Details view components
@FragmentById(resName = "torrentdetails_fragment")
@ViewById
protected Toolbar torrentsToolbar;
@FragmentById(R.id.torrentdetails_fragment)
protected DetailsFragment fragmentDetails;
@Override
@ -123,6 +130,7 @@ public class DetailsActivity extends ActionBarActivity implements TorrentTasksEx @@ -123,6 +130,7 @@ public class DetailsActivity extends ActionBarActivity implements TorrentTasksEx
}
// Simple action bar with up, torrent name as title and refresh button
setSupportActionBar(torrentsToolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setTitle(NavigationHelper.buildCondensedFontString(torrent.getName()));
@ -151,14 +159,19 @@ public class DetailsActivity extends ActionBarActivity implements TorrentTasksEx @@ -151,14 +159,19 @@ public class DetailsActivity extends ActionBarActivity implements TorrentTasksEx
/**
* Attaches some view (perhaps contained in a fragment) to this activity's pull to refresh support
* @param view The view to attach
* @param container The refresh container to handle user refresh requests and show the progress
*/
@Override
public void addRefreshableView(View view) {
// TODO Add new style pull to refresh library
public void addSwipeRefreshLayout(SwipeRefreshLayout container) {
container.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
refreshScreen();
}
});
}
@OptionsItem(resName = "action_refresh")
@OptionsItem(R.id.action_refresh)
public void refreshScreen() {
fragmentDetails.updateIsLoading(true, null);
refreshTorrent();
@ -170,8 +183,7 @@ public class DetailsActivity extends ActionBarActivity implements TorrentTasksEx @@ -170,8 +183,7 @@ public class DetailsActivity extends ActionBarActivity implements TorrentTasksEx
protected void refreshTorrent() {
DaemonTaskResult result = RetrieveTask.create(currentConnection).execute(log);
if (result instanceof RetrieveTaskSuccessResult) {
onTorrentsRetrieved(((RetrieveTaskSuccessResult) result).getTorrents(),
((RetrieveTaskSuccessResult) result).getLabels());
onTorrentsRetrieved(((RetrieveTaskSuccessResult) result).getTorrents(), ((RetrieveTaskSuccessResult) result).getLabels());
} else {
onCommunicationError((DaemonTaskFailureResult) result, true);
}
@ -179,8 +191,9 @@ public class DetailsActivity extends ActionBarActivity implements TorrentTasksEx @@ -179,8 +191,9 @@ public class DetailsActivity extends ActionBarActivity implements TorrentTasksEx
@Background
public void refreshTorrentDetails(Torrent torrent) {
if (!Daemon.supportsFineDetails(torrent.getDaemon()))
if (!Daemon.supportsFineDetails(torrent.getDaemon())) {
return;
}
DaemonTaskResult result = GetTorrentDetailsTask.create(currentConnection, torrent).execute(log);
if (result instanceof GetTorrentDetailsTaskSuccessResult) {
onTorrentDetailsRetrieved(torrent, ((GetTorrentDetailsTaskSuccessResult) result).getTorrentDetails());
@ -191,8 +204,9 @@ public class DetailsActivity extends ActionBarActivity implements TorrentTasksEx @@ -191,8 +204,9 @@ public class DetailsActivity extends ActionBarActivity implements TorrentTasksEx
@Background
public void refreshTorrentFiles(Torrent torrent) {
if (!Daemon.supportsFileListing(torrent.getDaemon()))
if (!Daemon.supportsFileListing(torrent.getDaemon())) {
return;
}
DaemonTaskResult result = GetFileListTask.create(currentConnection, torrent).execute(log);
if (result instanceof GetFileListTaskSuccessResult) {
onTorrentFilesRetrieved(torrent, ((GetFileListTaskSuccessResult) result).getFiles());
@ -255,8 +269,7 @@ public class DetailsActivity extends ActionBarActivity implements TorrentTasksEx @@ -255,8 +269,7 @@ public class DetailsActivity extends ActionBarActivity implements TorrentTasksEx
DaemonTaskResult result = RemoveTask.create(currentConnection, torrent, withData).execute(log);
if (result instanceof DaemonTaskSuccessResult) {
// Close the details activity (as the torrent is now removed)
closeActivity(getString(withData ? R.string.result_removed_with_data : R.string.result_removed,
torrent.getName()));
closeActivity(getString(withData ? R.string.result_removed_with_data : R.string.result_removed, torrent.getName()));
} else {
onCommunicationError((DaemonTaskFailureResult) result, false);
}
@ -264,19 +277,18 @@ public class DetailsActivity extends ActionBarActivity implements TorrentTasksEx @@ -264,19 +277,18 @@ public class DetailsActivity extends ActionBarActivity implements TorrentTasksEx
@UiThread
protected void closeActivity(String closeText) {
setResult(RESULT_OK,
new Intent().putExtra("torrent_removed", true).putExtra("affected_torrent", torrent));
setResult(RESULT_OK, new Intent().putExtra("torrent_removed", true).putExtra("affected_torrent", torrent));
finish();
if (closeText != null)
if (closeText != null) {
Toast.makeText(this, closeText, Toast.LENGTH_LONG).show();
}
}
@Background
@Override
public void updateLabel(Torrent torrent, String newLabel) {
torrent.mimicNewLabel(newLabel);
DaemonTaskResult result = SetLabelTask.create(currentConnection, torrent, newLabel == null ? "" : newLabel)
.execute(log);
DaemonTaskResult result = SetLabelTask.create(currentConnection, torrent, newLabel == null ? "" : newLabel).execute(log);
if (result instanceof DaemonTaskSuccessResult) {
onTaskSucceeded((DaemonTaskSuccessResult) result, getString(R.string.result_labelset, newLabel));
} else {
@ -290,8 +302,7 @@ public class DetailsActivity extends ActionBarActivity implements TorrentTasksEx @@ -290,8 +302,7 @@ public class DetailsActivity extends ActionBarActivity implements TorrentTasksEx
torrent.mimicCheckingStatus();
DaemonTaskResult result = ForceRecheckTask.create(currentConnection, torrent).execute(log);
if (result instanceof DaemonTaskSuccessResult) {
onTaskSucceeded((DaemonTaskSuccessResult) result,
getString(R.string.result_recheckedstarted, torrent.getName()));
onTaskSucceeded((DaemonTaskSuccessResult) result, getString(R.string.result_recheckedstarted, torrent.getName()));
} else {
onCommunicationError((DaemonTaskFailureResult) result, false);
}
@ -322,8 +333,7 @@ public class DetailsActivity extends ActionBarActivity implements TorrentTasksEx @@ -322,8 +333,7 @@ public class DetailsActivity extends ActionBarActivity implements TorrentTasksEx
@Background
@Override
public void updatePriority(Torrent torrent, List<TorrentFile> files, Priority priority) {
DaemonTaskResult result = SetFilePriorityTask.create(currentConnection, torrent, priority,
new ArrayList<TorrentFile>(files)).execute(log);
DaemonTaskResult result = SetFilePriorityTask.create(currentConnection, torrent, priority, new ArrayList<>(files)).execute(log);
if (result instanceof DaemonTaskSuccessResult) {
onTaskSucceeded((DaemonTaskSuccessResult) result, getString(R.string.result_priotitiesset));
} else {
@ -334,8 +344,7 @@ public class DetailsActivity extends ActionBarActivity implements TorrentTasksEx @@ -334,8 +344,7 @@ public class DetailsActivity extends ActionBarActivity implements TorrentTasksEx
@UiThread
protected void onTaskSucceeded(DaemonTaskSuccessResult result, String successMessage) {
// Set the activity result so the calling activity knows it needs to update its view
setResult(RESULT_OK,
new Intent().putExtra("torrent_updated", true).putExtra("affected_torrent", torrent));
setResult(RESULT_OK, new Intent().putExtra("torrent_updated", true).putExtra("affected_torrent", torrent));
// Refresh the screen as well
refreshTorrent();
refreshTorrentDetails(torrent);
@ -351,7 +360,7 @@ public class DetailsActivity extends ActionBarActivity implements TorrentTasksEx @@ -351,7 +360,7 @@ public class DetailsActivity extends ActionBarActivity implements TorrentTasksEx
@UiThread
protected void onTorrentFilesRetrieved(Torrent torrent, List<TorrentFile> torrentFiles) {
// Update the details fragment with the newly retrieved list of files
fragmentDetails.updateTorrentFiles(torrent, new ArrayList<TorrentFile>(torrentFiles));
fragmentDetails.updateTorrentFiles(torrent, new ArrayList<>(torrentFiles));
}
@UiThread
@ -359,8 +368,7 @@ public class DetailsActivity extends ActionBarActivity implements TorrentTasksEx @@ -359,8 +368,7 @@ public class DetailsActivity extends ActionBarActivity implements TorrentTasksEx
log.i(this, result.getException().toString());
String error = getString(LocalTorrent.getResourceForDaemonException(result.getException()));
fragmentDetails.updateIsLoading(false, isCritical ? error : null);
Crouton.showText(this, getString(LocalTorrent.getResourceForDaemonException(result.getException())),
NavigationHelper.CROUTON_ERROR_STYLE);
Crouton.showText(this, getString(LocalTorrent.getResourceForDaemonException(result.getException())), NavigationHelper.CROUTON_ERROR_STYLE);
}
@UiThread
@ -368,8 +376,7 @@ public class DetailsActivity extends ActionBarActivity implements TorrentTasksEx @@ -368,8 +376,7 @@ public class DetailsActivity extends ActionBarActivity implements TorrentTasksEx
// Update the details fragment accordingly
fragmentDetails.updateIsLoading(false, null);
fragmentDetails.perhapsUpdateTorrent(torrents);
fragmentDetails.updateLabels(Label.convertToNavigationLabels(labels,
getResources().getString(R.string.labels_unlabeled)));
fragmentDetails.updateLabels(Label.convertToNavigationLabels(labels, getResources().getString(R.string.labels_unlabeled)));
}
}

202
app/src/main/java/org/transdroid/core/gui/DetailsFragment.java

@ -16,9 +16,22 @@ @@ -16,9 +16,22 @@
*/
package org.transdroid.core.gui;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import android.annotation.SuppressLint;
import android.app.Fragment;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.support.v4.widget.SwipeRefreshLayout;
import android.view.ActionMode;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AbsListView.MultiChoiceModeListener;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import org.androidannotations.annotations.AfterViews;
import org.androidannotations.annotations.Click;
@ -29,10 +42,16 @@ import org.androidannotations.annotations.OptionsItem; @@ -29,10 +42,16 @@ import org.androidannotations.annotations.OptionsItem;
import org.androidannotations.annotations.OptionsMenu;
import org.androidannotations.annotations.ViewById;
import org.transdroid.R;
import org.transdroid.core.app.settings.*;
import org.transdroid.core.app.settings.ServerSetting;
import org.transdroid.core.app.settings.SystemSettings_;
import org.transdroid.core.gui.lists.DetailsAdapter;
import org.transdroid.core.gui.lists.SimpleListItemAdapter;
import org.transdroid.core.gui.navigation.*;
import org.transdroid.core.gui.navigation.Label;
import org.transdroid.core.gui.navigation.NavigationHelper;
import org.transdroid.core.gui.navigation.NavigationHelper_;
import org.transdroid.core.gui.navigation.RefreshableActivity;
import org.transdroid.core.gui.navigation.SelectionManagerMode;
import org.transdroid.core.gui.navigation.SetLabelDialog;
import org.transdroid.core.gui.navigation.SetLabelDialog.OnLabelPickedListener;
import org.transdroid.core.gui.navigation.SetStorageLocationDialog;
import org.transdroid.core.gui.navigation.SetStorageLocationDialog.OnStorageLocationUpdatedListener;
@ -44,33 +63,21 @@ import org.transdroid.daemon.Torrent; @@ -44,33 +63,21 @@ import org.transdroid.daemon.Torrent;
import org.transdroid.daemon.TorrentDetails;
import org.transdroid.daemon.TorrentFile;
import android.annotation.SuppressLint;
import android.app.Fragment;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.view.ActionMode;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AbsListView.MultiChoiceModeListener;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import de.keyboardsurfer.android.widget.crouton.Crouton;
/**
* Fragment that shows detailed statistics about some torrent. These come from some already fetched {@link Torrent}
* object, but it also retrieves further detailed statistics. The actual execution of tasks is performed by the activity
* that contains this fragment, as per the {@link TorrentTasksExecutor} interface.
* Fragment that shows detailed statistics about some torrent. These come from some already fetched {@link Torrent} object, but it also retrieves
* further detailed statistics. The actual execution of tasks is performed by the activity that contains this fragment, as per the {@link
* TorrentTasksExecutor} interface.
* @author Eric Kok
*/
@EFragment(resName = "fragment_details")
@OptionsMenu(resName = "fragment_details")
public class DetailsFragment extends Fragment implements OnTrackersUpdatedListener, OnLabelPickedListener,
OnStorageLocationUpdatedListener {
@EFragment(R.layout.fragment_details)
@OptionsMenu(R.menu.fragment_details)
public class DetailsFragment extends Fragment implements OnTrackersUpdatedListener, OnLabelPickedListener, OnStorageLocationUpdatedListener {
// Local data
@InstanceState
@ -90,9 +97,11 @@ public class DetailsFragment extends Fragment implements OnTrackersUpdatedListen @@ -90,9 +97,11 @@ public class DetailsFragment extends Fragment implements OnTrackersUpdatedListen
private ServerSetting currentServerSettings = null;
// Views
@ViewById(resName = "details_container")
@ViewById
protected View detailsContainer;
@ViewById(resName = "details_list")
@ViewById
protected SwipeRefreshLayout swipeRefreshLayout;
@ViewById
protected ListView detailsList;
@ViewById
protected TextView emptyText, errorText;
@ -118,16 +127,19 @@ public class DetailsFragment extends Fragment implements OnTrackersUpdatedListen @@ -118,16 +127,19 @@ public class DetailsFragment extends Fragment implements OnTrackersUpdatedListen
detailsList.setMultiChoiceModeListener(onDetailsSelected);
detailsList.setFastScrollEnabled(true);
if (getActivity() != null && getActivity() instanceof RefreshableActivity) {
((RefreshableActivity) getActivity()).addRefreshableView(detailsList);
((RefreshableActivity) getActivity()).addSwipeRefreshLayout(swipeRefreshLayout);
}
// Restore the fragment state (on orientation changes et al.)
if (torrent != null)
if (torrent != null) {
updateTorrent(torrent);
if (torrentDetails != null)
}
if (torrentDetails != null) {
updateTorrentDetails(torrent, torrentDetails);
if (torrentFiles != null)
}
if (torrentFiles != null) {
updateTorrentFiles(torrent, torrentFiles);
}
}
@ -165,13 +177,14 @@ public class DetailsFragment extends Fragment implements OnTrackersUpdatedListen @@ -165,13 +177,14 @@ public class DetailsFragment extends Fragment implements OnTrackersUpdatedListen
*/
public void updateTorrentDetails(Torrent checkTorrent, TorrentDetails newTorrentDetails) {
// Check if these are actually the details of the torrent we are now showing
if (torrentId == null || !torrentId.equals(checkTorrent.getUniqueID()))
if (torrentId == null || !torrentId.equals(checkTorrent.getUniqueID())) {
return;
}
this.torrentDetails = newTorrentDetails;
((DetailsAdapter) detailsList.getAdapter()).updateTrackers(
SimpleListItemAdapter.SimpleStringItem.wrapStringsList(newTorrentDetails.getTrackers()));
((DetailsAdapter) detailsList.getAdapter()).updateErrors(
SimpleListItemAdapter.SimpleStringItem.wrapStringsList(newTorrentDetails.getErrors()));
((DetailsAdapter) detailsList.getAdapter())
.updateTrackers(SimpleListItemAdapter.SimpleStringItem.wrapStringsList(newTorrentDetails.getTrackers()));
((DetailsAdapter) detailsList.getAdapter())
.updateErrors(SimpleListItemAdapter.SimpleStringItem.wrapStringsList(newTorrentDetails.getErrors()));
}
/**
@ -181,22 +194,23 @@ public class DetailsFragment extends Fragment implements OnTrackersUpdatedListen @@ -181,22 +194,23 @@ public class DetailsFragment extends Fragment implements OnTrackersUpdatedListen
*/
public void updateTorrentFiles(Torrent checkTorrent, ArrayList<TorrentFile> newTorrentFiles) {
// Check if these are actually the details of the torrent we are now showing
if (torrentId == null || !torrentId.equals(checkTorrent.getUniqueID()))
if (torrentId == null || !torrentId.equals(checkTorrent.getUniqueID())) {
return;
}
Collections.sort(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.
* 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) {
// Only try to update if we actually were showing a torrent
if (this.torrentId == null || torrents == null)
if (this.torrentId == null || torrents == null) {
return;
}
for (Torrent newTorrent : torrents) {
if (newTorrent.getUniqueID().equals(torrentId)) {
// Found, so we can update our data as well
@ -207,12 +221,12 @@ public class DetailsFragment extends Fragment implements OnTrackersUpdatedListen @@ -207,12 +221,12 @@ public class DetailsFragment extends Fragment implements OnTrackersUpdatedListen
}
/**
* Updates the locally maintained list of labels that are active on the server. Used in the label picking dialog and
* should be updated every time after the list of torrents was retrieved to keep it updated.
* Updates the locally maintained list of labels that are active on the server. Used in the label picking dialog and should be updated every time
* after the list of torrents was retrieved to keep it updated.
* @param currentLabels The list of known server labels
*/
public void updateLabels(ArrayList<Label> currentLabels) {
this.currentLabels = currentLabels == null ? null : new ArrayList<Label>(currentLabels);
this.currentLabels = currentLabels == null ? null : new ArrayList<>(currentLabels);
}
/**
@ -238,8 +252,10 @@ public class DetailsFragment extends Fragment implements OnTrackersUpdatedListen @@ -238,8 +252,10 @@ public class DetailsFragment extends Fragment implements OnTrackersUpdatedListen
this.isLoadingTorrent = isLoading;
this.hasCriticalError = connectionErrorMessage != null;
errorText.setText(connectionErrorMessage);
if (isLoading || hasCriticalError)
swipeRefreshLayout.setRefreshing(isLoading);
if (isLoading || hasCriticalError) {
clear();
}
}
@ItemClick(resName = "details_list")
@ -287,59 +303,59 @@ public class DetailsFragment extends Fragment implements OnTrackersUpdatedListen @@ -287,59 +303,59 @@ public class DetailsFragment extends Fragment implements OnTrackersUpdatedListen
}
@OptionsItem(resName = "action_resume")
@OptionsItem(R.id.action_resume)
protected void resumeTorrent() {
getTasksExecutor().resumeTorrent(torrent);
}
@OptionsItem(resName = "action_pause")
@OptionsItem(R.id.action_pause)
protected void pauseTorrent() {
getTasksExecutor().pauseTorrent(torrent);
}
@OptionsItem(resName = "action_start_direct")
@OptionsItem(R.id.action_start_direct)
protected void startTorrentDirect() {
getTasksExecutor().startTorrent(torrent, false);
}
@OptionsItem(resName = "action_start_default")
@OptionsItem(R.id.action_start_default)
protected void startTorrentDefault() {
getTasksExecutor().startTorrent(torrent, false);
}
@OptionsItem(resName = "action_start_forced")
@OptionsItem(R.id.action_start_forced)
protected void startTorrentForced() {
getTasksExecutor().startTorrent(torrent, true);
}
@OptionsItem(resName = "action_stop")
@OptionsItem(R.id.action_stop)
protected void stopTorrent() {
getTasksExecutor().stopTorrent(torrent);
}
@OptionsItem(resName = "action_remove_default")
@OptionsItem(R.id.action_remove_default)
protected void removeTorrentDefault() {
getTasksExecutor().removeTorrent(torrent, false);
}
@OptionsItem(resName = "action_remove_withdata")
@OptionsItem(R.id.action_remove_withdata)
protected void removeTorrentWithData() {
getTasksExecutor().removeTorrent(torrent, true);
}
@OptionsItem(resName = "action_setlabel")
@OptionsItem(R.id.action_setlabel)
protected void setLabel() {
if (currentLabels != null)
new SetLabelDialog().setOnLabelPickedListener(this).setCurrentLabels(currentLabels)
.show(getFragmentManager(), "SetLabelDialog");
if (currentLabels != null) {
new SetLabelDialog().setOnLabelPickedListener(this).setCurrentLabels(currentLabels).show(getFragmentManager(), "SetLabelDialog");
}
}
@OptionsItem(resName = "action_forcerecheck")
@OptionsItem(R.id.action_forcerecheck)
protected void setForceRecheck() {
getTasksExecutor().forceRecheckTorrent(torrent);
}
@OptionsItem(resName = "action_updatetrackers")
@OptionsItem(R.id.action_updatetrackers)
protected void updateTrackers() {
if (torrentDetails == null) {
Crouton.showText(getActivity(), R.string.error_stillloadingdetails, NavigationHelper.CROUTON_INFO_STYLE);
@ -349,7 +365,7 @@ public class DetailsFragment extends Fragment implements OnTrackersUpdatedListen @@ -349,7 +365,7 @@ public class DetailsFragment extends Fragment implements OnTrackersUpdatedListen
.show(getFragmentManager(), "SetTrackersDialog");
}
@OptionsItem(resName = "action_changelocation")
@OptionsItem(R.id.action_changelocation)
protected void changeStorageLocation() {
new SetStorageLocationDialog().setOnStorageLocationUpdated(this).setCurrentLocation(torrent.getLocationDir())
.show(getFragmentManager(), "SetStorageLocationDialog");
@ -357,22 +373,25 @@ public class DetailsFragment extends Fragment implements OnTrackersUpdatedListen @@ -357,22 +373,25 @@ public class DetailsFragment extends Fragment implements OnTrackersUpdatedListen
@Override
public void onLabelPicked(String newLabel) {
if (torrent == null)
if (torrent == null) {
return;
}
getTasksExecutor().updateLabel(torrent, newLabel);
}
@Override
public void onTrackersUpdated(List<String> updatedTrackers) {
if (torrent == null)
if (torrent == null) {
return;
}
getTasksExecutor().updateTrackers(torrent, updatedTrackers);
}
@Override
public void onStorageLocationUpdated(String newLocation) {
if (torrent == null)
if (torrent == null) {
return;
}
getTasksExecutor().updateLocation(torrent, newLocation);
}
@ -413,11 +432,9 @@ public class DetailsFragment extends Fragment implements OnTrackersUpdatedListen @@ -413,11 +432,9 @@ public class DetailsFragment extends Fragment implements OnTrackersUpdatedListen
((TorrentsActivity) getActivity()).stopRefresh = true;
((TorrentsActivity) getActivity()).stopAutoRefresh();
}
boolean filePaths =
currentServerSettings != null && Daemon.supportsFilePaths(currentServerSettings.getType());
boolean filePaths = currentServerSettings != null && Daemon.supportsFilePaths(currentServerSettings.getType());
menu.findItem(R.id.action_download).setVisible(filePaths);
boolean filePriorities = currentServerSettings != null &&
Daemon.supportsFilePrioritySetting(currentServerSettings.getType());
boolean filePriorities = currentServerSettings != null && Daemon.supportsFilePrioritySetting(currentServerSettings.getType());
menu.findItem(R.id.action_priority_off).setVisible(filePriorities);
menu.findItem(R.id.action_priority_low).setVisible(filePriorities);
menu.findItem(R.id.action_priority_normal).setVisible(filePriorities);
@ -430,35 +447,36 @@ public class DetailsFragment extends Fragment implements OnTrackersUpdatedListen @@ -430,35 +447,36 @@ public class DetailsFragment extends Fragment implements OnTrackersUpdatedListen
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
// Get checked torrents
List<TorrentFile> checked = new ArrayList<TorrentFile>();
List<TorrentFile> checked = new ArrayList<>();
for (int i = 0; i < detailsList.getCheckedItemPositions().size(); i++) {
if (detailsList.getCheckedItemPositions().valueAt(i)
&& i < detailsList.getAdapter().getCount()
&& detailsList.getAdapter().getItem(detailsList.getCheckedItemPositions().keyAt(i)) instanceof TorrentFile)
checked.add((TorrentFile) detailsList.getAdapter().getItem(
detailsList.getCheckedItemPositions().keyAt(i)));
if (detailsList.getCheckedItemPositions().valueAt(i) && i < detailsList.getAdapter().getCount() &&
detailsList.getAdapter().getItem(detailsList.getCheckedItemPositions().keyAt(i)) instanceof TorrentFile) {
checked.add((TorrentFile) detailsList.getAdapter().getItem(detailsList.getCheckedItemPositions().keyAt(i)));
}
}
int itemId = item.getItemId();
if (itemId == R.id.action_download) {
if (checked.size() < 1 || currentServerSettings == null)
if (checked.size() < 1 || currentServerSettings == null) {
return true;
}
String urlBase = currentServerSettings.getFtpUrl();
if (urlBase == null || urlBase.equals(""))
if (urlBase == null || urlBase.equals("")) {
urlBase = "ftp://" + currentServerSettings.getAddress();
}
// Try using AndFTP intents
Intent andftpStart = new Intent(Intent.ACTION_PICK);
andftpStart.setDataAndType(Uri.parse(urlBase), "vnd.android.cursor.dir/lysesoft.andftp.uri");
andftpStart.putExtra("command_type", "download");
andftpStart.putExtra("ftp_pasv", "true");
if (Uri.parse(urlBase).getUserInfo() != null)
if (Uri.parse(urlBase).getUserInfo() != null) {
andftpStart.putExtra("ftp_username", Uri.parse(urlBase).getUserInfo());
else
} else {
andftpStart.putExtra("ftp_username", currentServerSettings.getUsername());
if (currentServerSettings.getFtpPassword() != null
&& !currentServerSettings.getFtpPassword().equals("")) {
}
if (currentServerSettings.getFtpPassword() != null && !currentServerSettings.getFtpPassword().equals("")) {
andftpStart.putExtra("ftp_password", currentServerSettings.getFtpPassword());
} else {
andftpStart.putExtra("ftp_password", currentServerSettings.getPassword());
@ -472,8 +490,9 @@ public class DetailsFragment extends Fragment implements OnTrackersUpdatedListen @@ -472,8 +490,9 @@ public class DetailsFragment extends Fragment implements OnTrackersUpdatedListen
// If the file is directly in the root, AndFTP fails if we supply the proper path (like
// /file.pdf)
// Work around this bug by removing the leading / if no further directories are used in the path
if (file.startsWith("/") && file.indexOf("/", 1) < 0)
if (file.startsWith("/") && file.indexOf("/", 1) < 0) {
file = file.substring(1);
}
andftpStart.putExtra("remote_file" + (f + 1), file);
}
}
@ -485,8 +504,7 @@ public class DetailsFragment extends Fragment implements OnTrackersUpdatedListen @@ -485,8 +504,7 @@ public class DetailsFragment extends Fragment implements OnTrackersUpdatedListen
// Try using a VIEW intent given an ftp:// scheme URI
String url = urlBase + checked.get(0).getFullPath();
Intent simpleStart = new Intent(Intent.ACTION_VIEW, Uri.parse(url))
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Intent simpleStart = new Intent(Intent.ACTION_VIEW, Uri.parse(url)).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (simpleStart.resolveActivity(getActivity().getPackageManager()) != null) {
startActivity(simpleStart);
mode.finish();
@ -494,8 +512,7 @@ public class DetailsFragment extends Fragment implements OnTrackersUpdatedListen @@ -494,8 +512,7 @@ public class DetailsFragment extends Fragment implements OnTrackersUpdatedListen
}
// No app is available that can handle FTP downloads
Crouton.showText(getActivity(), getString(R.string.error_noftpapp, url),
NavigationHelper.CROUTON_ERROR_STYLE);
Crouton.showText(getActivity(), getString(R.string.error_noftpapp, url), NavigationHelper.CROUTON_ERROR_STYLE);
mode.finish();
return true;
@ -503,24 +520,27 @@ public class DetailsFragment extends Fragment implements OnTrackersUpdatedListen @@ -503,24 +520,27 @@ public class DetailsFragment extends Fragment implements OnTrackersUpdatedListen
StringBuilder names = new StringBuilder();
for (int f = 0; f < checked.size(); f++) {
if (f != 0)
if (f != 0) {
names.append("\n");
}
names.append(checked.get(f).getName());
}
ClipboardManager clipboardManager = (ClipboardManager) getActivity().getSystemService(
Context.CLIPBOARD_SERVICE);
ClipboardManager clipboardManager = (ClipboardManager) getActivity().getSystemService(Context.CLIPBOARD_SERVICE);
clipboardManager.setPrimaryClip(ClipData.newPlainText("Transdroid", names.toString()));
mode.finish();
return true;
} else {
Priority priority = Priority.Off;
if (itemId == R.id.action_priority_low)
if (itemId == R.id.action_priority_low) {
priority = Priority.Low;
if (itemId == R.id.action_priority_normal)
}
if (itemId == R.id.action_priority_normal) {
priority = Priority.Normal;
if (itemId == R.id.action_priority_high)
}
if (itemId == R.id.action_priority_high) {
priority = Priority.High;
}
getTasksExecutor().updatePriority(torrent, checked, priority);
mode.finish();
return true;

59
app/src/main/java/org/transdroid/core/gui/ServerSelectionView.java

@ -0,0 +1,59 @@ @@ -0,0 +1,59 @@
/*
* Copyright 2010-2013 Eric Kok et al.
*
* Transdroid is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Transdroid is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Transdroid. If not, see <http://www.gnu.org/licenses/>.
*/
package org.transdroid.core.gui;
import android.content.Context;
import android.widget.RelativeLayout;
import android.widget.TextView;
import org.androidannotations.annotations.EViewGroup;
import org.androidannotations.annotations.ViewById;
import org.transdroid.R;
import org.transdroid.core.gui.navigation.NavigationFilter;
import org.transdroid.daemon.IDaemonAdapter;
@EViewGroup(R.layout.actionbar_serverselection)
public class ServerSelectionView extends RelativeLayout {
@ViewById
protected TextView filterText, serverText;
public ServerSelectionView(Context context) {
super(context);
}
public ServerSelectionView(TorrentsActivity activity) {
super(activity.torrentsToolbar.getContext());
}
/**
* Updates the name of the current connected server.
* @param currentServer The server currently connected to
*/
public void updateCurrentServer(IDaemonAdapter currentServer) {
serverText.setText(currentServer.getSettings().getName());
}
/**
* Updates the name of the selected filter.
* @param currentFilter The filter that is currently selected
*/
public void updateCurrentFilter(NavigationFilter currentFilter) {
filterText.setText(currentFilter.getName());
}
}

39
app/src/main/java/org/transdroid/core/gui/ServerStatusView.java

@ -16,30 +16,29 @@ @@ -16,30 +16,29 @@
*/
package org.transdroid.core.gui;
import java.util.List;
import android.content.Context;
import android.view.View;
import android.widget.RelativeLayout;
import android.widget.TextView;
import org.androidannotations.annotations.EViewGroup;
import org.androidannotations.annotations.ViewById;
import org.transdroid.R;
import org.transdroid.core.gui.navigation.NavigationFilter;
import org.transdroid.core.gui.navigation.NavigationHelper;
import org.transdroid.core.gui.navigation.SetTransferRatesDialog;
import org.transdroid.core.gui.navigation.SetTransferRatesDialog.OnRatesPickedListener;
import org.transdroid.daemon.IDaemonAdapter;
import org.transdroid.daemon.Torrent;
import org.transdroid.daemon.util.FileSizeConverter;
import android.content.Context;
import android.view.View;
import android.widget.RelativeLayout;
import android.widget.TextView;
import java.util.List;
import de.keyboardsurfer.android.widget.crouton.Crouton;
@EViewGroup(resName = "actionbar_serverstatus")
@EViewGroup(R.layout.actionbar_serverstatus)
public class ServerStatusView extends RelativeLayout implements OnRatesPickedListener {
@ViewById
protected TextView filterText, serverText, downcountText, upcountText, downcountSign, upcountSign, downspeedText, upspeedText;
protected TextView downcountText, upcountText, downcountSign, upcountSign, downspeedText, upspeedText;
@ViewById
protected View speedswrapperLayout;
private TorrentsActivity activity;
@ -49,26 +48,10 @@ public class ServerStatusView extends RelativeLayout implements OnRatesPickedLis @@ -49,26 +48,10 @@ public class ServerStatusView extends RelativeLayout implements OnRatesPickedLis
}
public ServerStatusView(TorrentsActivity activity) {
super(activity.getSupportActionBar().getThemedContext());
super(activity);
this.activity = activity;
}
/**
* Updates the name of the current connected server.
* @param currentServer The server currently connected to
*/
public void updateCurrentServer(IDaemonAdapter currentServer) {
serverText.setText(currentServer.getSettings().getName());
}
/**
* Updates the name of the selected filter.
* @param currentFilter The filter that is currently selected
*/
public void updateCurrentFilter(NavigationFilter currentFilter) {
filterText.setText(currentFilter.getName());
}
/**
* Updates the statistics as shown in the action bar through this server status view.
* @param torrents The most recently received list of torrents
@ -115,8 +98,8 @@ public class ServerStatusView extends RelativeLayout implements OnRatesPickedLis @@ -115,8 +98,8 @@ public class ServerStatusView extends RelativeLayout implements OnRatesPickedLis
private OnClickListener onStartDownPickerClicked = new OnClickListener() {
public void onClick(View v) {
new SetTransferRatesDialog().setOnRatesPickedListener(ServerStatusView.this).show(
activity.getFragmentManager(), "SetTransferRatesDialog");
new SetTransferRatesDialog().setOnRatesPickedListener(ServerStatusView.this)
.show(activity.getFragmentManager(), "SetTransferRatesDialog");
}
};

18
app/src/main/java/org/transdroid/core/gui/TorrentTasksExecutor.java

@ -16,28 +16,38 @@ @@ -16,28 +16,38 @@
*/
package org.transdroid.core.gui;
import java.util.List;
import org.transdroid.daemon.Priority;
import org.transdroid.daemon.Torrent;
import org.transdroid.daemon.TorrentFile;
import java.util.List;
/**
* Interface to be implemented by any activity that wants containing fragments to be able to load data and execute
* commands against a torrent server.
* Interface to be implemented by any activity that wants containing fragments to be able to load data and execute commands against a torrent server.
* @author Eric Kok
*/
public interface TorrentTasksExecutor {
void resumeTorrent(Torrent torrent);
void pauseTorrent(Torrent torrent);
void startTorrent(Torrent torrent, boolean forced);
void stopTorrent(Torrent torrent);
void removeTorrent(Torrent torrent, boolean withData);
void forceRecheckTorrent(Torrent torrent);
void updateLabel(Torrent torrent, String newLabel);
void updateTrackers(Torrent torrent, List<String> newTrackers);
void updateLocation(Torrent torrent, String newLocation);
void refreshTorrentDetails(Torrent torrent);
void refreshTorrentFiles(Torrent torrent);
void updatePriority(Torrent torrent, List<TorrentFile> files, Priority priority);
}

267
app/src/main/java/org/transdroid/core/gui/TorrentsActivity.java

@ -26,8 +26,10 @@ import android.os.Build; @@ -26,8 +26,10 @@ import android.os.Build;
import android.os.Bundle;
import android.support.v4.view.MenuItemCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.widget.SearchView;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.view.Menu;
@ -37,17 +39,19 @@ import android.view.View.OnClickListener; @@ -37,17 +39,19 @@ import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.SearchView;
import com.getbase.floatingactionbutton.FloatingActionButton;
import com.getbase.floatingactionbutton.FloatingActionsMenu;
import org.androidannotations.annotations.AfterViews;
import org.androidannotations.annotations.Background;
import org.androidannotations.annotations.Bean;
import org.androidannotations.annotations.Click;
import org.androidannotations.annotations.EActivity;
import org.androidannotations.annotations.FragmentById;
import org.androidannotations.annotations.InstanceState;
import org.androidannotations.annotations.OnActivityResult;
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;
@ -133,14 +137,12 @@ import java.util.Map.Entry; @@ -133,14 +137,12 @@ import java.util.Map.Entry;
import de.keyboardsurfer.android.widget.crouton.Crouton;
/**
* Main activity that holds the fragment that shows the torrents list, presents a way to filter the list (via an action
* bar spinner or list side list) and potentially shows a torrent details fragment too, if there is room. Task execution
* such as loading of and adding torrents is performs in this activity, using background methods. Finally, the activity
* offers navigation elements such as access to settings and showing connection issues.
* Main activity that holds the fragment that shows the torrents list, presents a way to filter the list (via an action bar spinner or list side list)
* and potentially shows a torrent details fragment too, if there is room. Task execution such as loading of and adding torrents is performs in this
* activity, using background methods. Finally, the activity offers navigation elements such as access to settings and showing connection issues.
* @author Eric Kok
*/
@EActivity(resName = "activity_torrents")
@OptionsMenu(resName = "activity_torrents")
@EActivity(R.layout.activity_torrents)
public class TorrentsActivity extends ActionBarActivity implements TorrentTasksExecutor, RefreshableActivity {
private static final int RESULT_DETAILS = 0;
@ -158,17 +160,28 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE @@ -158,17 +160,28 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE
@Bean
protected ConnectivityHelper connectivityHelper;
@ViewById
protected Toolbar selectionToolbar;
@ViewById
protected Toolbar torrentsToolbar;
@ViewById
protected Toolbar actionsToolbar;
@ViewById
protected FloatingActionsMenu addmenuButton;
@ViewById
protected FloatingActionButton addmenuFileButton;
@ViewById
protected DrawerLayout drawerLayout;
@ViewById
protected ListView drawerList;
@ViewById
protected ListView filtersList;
protected ListView navigationList;
protected FilterListAdapter navigationListAdapter;
protected ServerStatusView serverStatusView;
protected ActionBarDrawerToggle drawerToggle;
@ViewById
protected SearchView filterSearch;
private ListView navigationList;
private FilterListAdapter navigationListAdapter;
private ServerSelectionView serverSelectionView;
private ServerStatusView serverStatusView;
private ActionBarDrawerToggle drawerToggle;
// Settings
@Bean
@ -184,9 +197,9 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE @@ -184,9 +197,9 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE
@InstanceState
protected ArrayList<Label> lastNavigationLabels;
// Contained torrent and details fragments
@FragmentById(resName = "torrents_fragment")
@FragmentById(R.id.torrents_fragment)
protected TorrentsFragment fragmentTorrents;
@FragmentById(resName = "torrentdetails_fragment")
@FragmentById(R.id.torrentdetails_fragment)
protected DetailsFragment fragmentDetails;
@InstanceState
boolean firstStart = true;
@ -195,20 +208,6 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE @@ -195,20 +208,6 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE
// Auto refresh task
private AsyncTask<Void, Void, Void> autoRefreshTask;
/**
* Handles item selections on the dedicated list of filter items
*/
private OnItemClickListener onFilterListItemClicked = new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
navigationList.setItemChecked(position, true);
Object item = navigationList.getAdapter().getItem(position);
if (item instanceof SimpleListItem) {
filterSelected((SimpleListItem) item, false);
}
drawerLayout.closeDrawer(drawerList);
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
@ -217,18 +216,24 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE @@ -217,18 +216,24 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE
setTheme(R.style.TransdroidTheme_Dark);
}
// Catch any uncaught exception to log it
Thread.setDefaultUncaughtExceptionHandler(
new LogUncaughtExceptionHandler(this, Thread.getDefaultUncaughtExceptionHandler()));
Thread.setDefaultUncaughtExceptionHandler(new LogUncaughtExceptionHandler(this, Thread.getDefaultUncaughtExceptionHandler()));
super.onCreate(savedInstanceState);
}
@AfterViews
protected void init() {
// Use a custom view as action bar content, showing filter selection and current torrent counts/speeds
setSupportActionBar(torrentsToolbar);
// Use custom views as action bar content, showing filter selection and current torrent counts/speeds
serverSelectionView = ServerSelectionView_.build(this);
serverStatusView = ServerStatusView_.build(this);
torrentsToolbar.addView(serverStatusView);
if (selectionToolbar != null) {
selectionToolbar.addView(serverSelectionView);
} else {
torrentsToolbar.addView(serverSelectionView);
}
actionsToolbar.addView(serverStatusView);
setSupportActionBar(torrentsToolbar); // For direct menu item inflation by the contained fragments
getSupportActionBar().setDisplayShowTitleEnabled(false);
// Construct the filters list, i.e. the list of servers, status types and labels
navigationListAdapter = FilterListAdapter_.getInstance_(this);
@ -242,18 +247,19 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE @@ -242,18 +247,19 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE
navigationList = filtersList;
} else {
navigationList = drawerList;
drawerToggle = new ActionBarDrawerToggle(this, drawerLayout, R.string.navigation_opendrawer,
R.string.navigation_closedrawer);
drawerToggle =
new ActionBarDrawerToggle(this, drawerLayout, torrentsToolbar, R.string.navigation_opendrawer, R.string.navigation_closedrawer);
drawerToggle.setDrawerIndicatorEnabled(true);
drawerLayout.setDrawerListener(drawerToggle);
}
navigationList.setAdapter(navigationListAdapter);
navigationList.setOnItemClickListener(onFilterListItemClicked);
// Now that all items (or at least their adapters) have been added, ensure a filter is selected
// NOTE When this is a fresh start, it might override the filter later (based on the last user selection)
// NOTE When this is a fresh start, we might override the filter later (based on the last user selection)
if (currentFilter == null) {
currentFilter = StatusType.getShowAllType(this);
}
filterSearch.setOnQueryTextListener(filterQueryTextChanged);
// Load the default server or a server that was explicitly supplied in the starting intent
ServerSetting defaultServer = applicationSettings.getDefaultServer();
@ -293,8 +299,8 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE @@ -293,8 +299,8 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE
// Resume after instead of fully loading the torrents list; create connection and set action bar title
ServerSetting lastUsed = applicationSettings.getLastUsedServer();
currentConnection = lastUsed.createServerAdapter(connectivityHelper.getConnectedNetworkName(), this);
serverStatusView.updateCurrentServer(currentConnection);
serverStatusView.updateCurrentFilter(currentFilter);
serverSelectionView.updateCurrentServer(currentConnection);
serverSelectionView.updateCurrentFilter(currentFilter);
}
firstStart = false;
@ -378,7 +384,6 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE @@ -378,7 +384,6 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE
}
};
// Executes serially by default on Honeycomb, was parallel before
autoRefreshTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
@ -398,6 +403,9 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE @@ -398,6 +403,9 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
// Manually insert the actions into the main torrent and secondary actions toolbars
torrentsToolbar.inflateMenu(R.menu.activity_torrents_main);
actionsToolbar.inflateMenu(R.menu.activity_torrents_secondary);
if (navigationHelper.enableSearchUi()) {
// Add an expandable SearchView to the action bar
MenuItem item = menu.findItem(R.id.action_search);
@ -437,16 +445,16 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE @@ -437,16 +445,16 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE
// No connection yet; hide all menu options except settings
if (currentConnection == null) {
menu.findItem(R.id.action_add).setVisible(false);
menu.findItem(R.id.action_search).setVisible(false);
menu.findItem(R.id.action_rss).setVisible(false);
menu.findItem(R.id.action_enableturtle).setVisible(false);
menu.findItem(R.id.action_disableturtle).setVisible(false);
menu.findItem(R.id.action_refresh).setVisible(false);
menu.findItem(R.id.action_sort).setVisible(false);
menu.findItem(R.id.action_filter).setVisible(false);
menu.findItem(R.id.action_settings).setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
menu.findItem(R.id.action_help).setVisible(true);
torrentsToolbar.setNavigationIcon(null);
addmenuButton.setVisibility(View.GONE);
torrentsToolbar.getMenu().findItem(R.id.action_search).setVisible(false);
torrentsToolbar.getMenu().findItem(R.id.action_rss).setVisible(false);
torrentsToolbar.getMenu().findItem(R.id.action_settings).setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
torrentsToolbar.getMenu().findItem(R.id.action_help).setVisible(true);
actionsToolbar.getMenu().findItem(R.id.action_enableturtle).setVisible(false);
actionsToolbar.getMenu().findItem(R.id.action_disableturtle).setVisible(false);
actionsToolbar.getMenu().findItem(R.id.action_refresh).setVisible(false);
actionsToolbar.getMenu().findItem(R.id.action_sort).setVisible(false);
if (fragmentTorrents != null) {
fragmentTorrents.updateConnectionStatus(false, null);
}
@ -454,20 +462,22 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE @@ -454,20 +462,22 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE
}
// There is a connection (read: settings to some server known)
menu.findItem(R.id.action_add).setVisible(true);
torrentsToolbar.setNavigationIcon(R.drawable.ic_action_drawer);
addmenuButton.setVisibility(View.VISIBLE);
boolean addByFile = Daemon.supportsAddByFile(currentConnection.getType());
menu.findItem(R.id.action_add_fromfile).setVisible(addByFile);
menu.findItem(R.id.action_search).setVisible(navigationHelper.enableSearchUi());
menu.findItem(R.id.action_rss).setVisible(navigationHelper.enableRssUi());
addmenuFileButton.setVisibility(addByFile ? View.VISIBLE : View.GONE);
// Primary toolbar menu
torrentsToolbar.getMenu().findItem(R.id.action_search).setVisible(navigationHelper.enableSearchUi());
torrentsToolbar.getMenu().findItem(R.id.action_rss).setVisible(navigationHelper.enableRssUi());
torrentsToolbar.getMenu().findItem(R.id.action_settings).setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
torrentsToolbar.getMenu().findItem(R.id.action_help).setVisible(false);
// Secondary toolbar menu
boolean hasAltMode = Daemon.supportsSetAlternativeMode(currentConnection.getType());
menu.findItem(R.id.action_enableturtle).setVisible(hasAltMode && !turleModeEnabled);
menu.findItem(R.id.action_disableturtle).setVisible(hasAltMode && turleModeEnabled);
menu.findItem(R.id.action_refresh).setVisible(true);
menu.findItem(R.id.action_sort).setVisible(true);
menu.findItem(R.id.action_sort_added).setVisible(Daemon.supportsDateAdded(currentConnection.getType()));
menu.findItem(R.id.action_filter).setVisible(true);
menu.findItem(R.id.action_settings).setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
menu.findItem(R.id.action_help).setVisible(false);
actionsToolbar.getMenu().findItem(R.id.action_enableturtle).setVisible(hasAltMode && !turleModeEnabled);
actionsToolbar.getMenu().findItem(R.id.action_disableturtle).setVisible(hasAltMode && turleModeEnabled);
actionsToolbar.getMenu().findItem(R.id.action_refresh).setVisible(true);
actionsToolbar.getMenu().findItem(R.id.action_sort).setVisible(true);
actionsToolbar.getMenu().findItem(R.id.action_sort_added).setVisible(Daemon.supportsDateAdded(currentConnection.getType()));
if (fragmentTorrents != null) {
fragmentTorrents.updateConnectionStatus(true, currentConnection.getType());
}
@ -481,6 +491,21 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE @@ -481,6 +491,21 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE
return drawerToggle != null && drawerToggle.onOptionsItemSelected(item);
}
/**
* Handles item selections on the dedicated list of filter items
*/
private OnItemClickListener onFilterListItemClicked = new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
navigationList.setItemChecked(position, true);
Object item = navigationList.getAdapter().getItem(position);
if (item instanceof SimpleListItem) {
filterSelected((SimpleListItem) item, false);
}
drawerLayout.closeDrawer(drawerList);
}
};
/**
* A new filter was selected; update the view over the current data
* @param item The touched filter item
@ -505,9 +530,9 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE @@ -505,9 +530,9 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE
// Update connection to the newly selected server and refresh
currentConnection = server.createServerAdapter(connectivityHelper.getConnectedNetworkName(), this);
applicationSettings.setLastUsedServer(server);
serverStatusView.updateCurrentServer(currentConnection);
serverSelectionView.updateCurrentServer(currentConnection);
if (forceNewConnection) {
serverStatusView.updateCurrentFilter(currentFilter);
serverSelectionView.updateCurrentFilter(currentFilter);
}
// Clear the currently shown list of torrents and perhaps the details
@ -528,7 +553,7 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE @@ -528,7 +553,7 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE
// Set new filter
currentFilter = (NavigationFilter) item;
fragmentTorrents.applyNavigationFilter(currentFilter);
serverStatusView.updateCurrentFilter(currentFilter);
serverSelectionView.updateCurrentFilter(currentFilter);
// Remember that the user last selected this
applicationSettings.setLastUsedNavigationFilter(currentFilter);
// Clear the details view
@ -564,8 +589,7 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE @@ -564,8 +589,7 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE
protected void handleStartIntent() {
// For intents that come from out of the application, perhaps we can not directly add them
if (applicationSettings.getDefaultServerKey() == ApplicationSettings.DEFAULTSERVER_ASKONADD &&
getIntent().getData() != null) {
if (applicationSettings.getDefaultServerKey() == ApplicationSettings.DEFAULTSERVER_ASKONADD && getIntent().getData() != null) {
// First ask which server to use before adding any intent from the extras
ServerPickerDialog.startServerPicker(this, applicationSettings.getAllServerSettings());
return;
@ -597,8 +621,7 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE @@ -597,8 +621,7 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE
String[] titles = intent.getStringArrayExtra("TORRENT_TITLES");
if (urls != null) {
for (int i = 0; i < urls.length; i++) {
String title = (titles != null && titles.length >= i ? titles[i] :
NavigationHelper.extractNameFromUri(Uri.parse(urls[i])));
String title = (titles != null && titles.length >= i ? titles[i] : NavigationHelper.extractNameFromUri(Uri.parse(urls[i])));
if (intent.hasExtra("PRIVATE_SOURCE")) {
// This is marked by the Search Module as being a private source site; get the url locally first
addTorrentFromPrivateSource(urls[i], title, intent.getStringExtra("PRIVATE_SOURCE"));
@ -694,12 +717,12 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE @@ -694,12 +717,12 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE
return true;
}
@OptionsItem(resName = "action_add_fromurl")
@Click(R.id.addmenu_link_button)
protected void startUrlEntryDialog() {
UrlEntryDialog.startUrlEntry(this);
}
@OptionsItem(resName = "action_add_fromfile")
@Click(R.id.addmenu_file_button)
protected void startFilePicker() {
FilePickerHelper.startFilePicker(this);
}
@ -714,7 +737,7 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE @@ -714,7 +737,7 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE
}
}
@OptionsItem(resName = "action_add_frombarcode")
@Click(R.id.addmenu_barcode_button)
protected void startBarcodeScanner() {
BarcodeHelper.startBarcodeScanner(this, BarcodeHelper.ACTIVITY_BARCODE_ADDTORRENT);
}
@ -741,14 +764,19 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE @@ -741,14 +764,19 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE
/**
* Attaches some view (perhaps contained in a fragment) to this activity's pull to refresh support
* @param view The view to attach
* @param container The refresh container to handle user refresh requests and show the progress
*/
@Override
public void addRefreshableView(View view) {
// TODO Add new style pull to refresh library (using SwipeRefreshLayout?)
public void addSwipeRefreshLayout(SwipeRefreshLayout container) {
container.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
refreshScreen();
}
});
}
@OptionsItem(resName = "action_refresh")
@OptionsItem(R.id.action_refresh)
public void refreshScreen() {
fragmentTorrents.updateIsLoading(true);
refreshTorrents();
@ -757,80 +785,89 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE @@ -757,80 +785,89 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE
}
}
@OptionsItem(resName = "action_enableturtle")
@OptionsItem(R.id.action_enableturtle)
protected void enableTurtleMode() {
updateTurtleMode(true);
}
@OptionsItem(resName = "action_disableturtle")
@OptionsItem(R.id.action_disableturtle)
protected void disableTurtleMode() {
updateTurtleMode(false);
}
@OptionsItem(resName = "action_rss")
@OptionsItem(R.id.action_rss)
protected void openRss() {
RssfeedsActivity_.intent(this).start();
}
@OptionsItem(resName = "action_settings")
@OptionsItem(R.id.action_settings)
protected void openSettings() {
MainSettingsActivity_.intent(this).start();
}
@OptionsItem(resName = "action_help")
@OptionsItem(R.id.action_help)
protected void openHelp() {
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.transdroid.org/download/")));
}
@OptionsItem(resName = "action_sort_byname")
@OptionsItem(R.id.action_sort_byname)
protected void sortByName() {
fragmentTorrents.sortBy(TorrentsSortBy.Alphanumeric);
}
@OptionsItem(resName = "action_sort_status")
@OptionsItem(R.id.action_sort_status)
protected void sortByStatus() {
fragmentTorrents.sortBy(TorrentsSortBy.Status);
}
@OptionsItem(resName = "action_sort_done")
@OptionsItem(R.id.action_sort_done)
protected void sortByDateDone() {
fragmentTorrents.sortBy(TorrentsSortBy.DateDone);
}
@OptionsItem(resName = "action_sort_added")
@OptionsItem(R.id.action_sort_added)
protected void sortByDateAdded() {
fragmentTorrents.sortBy(TorrentsSortBy.DateAdded);
}
@OptionsItem(resName = "action_sort_percent")
@OptionsItem(R.id.action_sort_percent)
protected void sortByPercent() {
fragmentTorrents.sortBy(TorrentsSortBy.Percent);
}
@OptionsItem(resName = "action_sort_downspeed")
@OptionsItem(R.id.action_sort_downspeed)
protected void sortByDownspeed() {
fragmentTorrents.sortBy(TorrentsSortBy.DownloadSpeed);
}
@OptionsItem(resName = "action_sort_upspeed")
@OptionsItem(R.id.action_sort_upspeed)
protected void sortByUpspeed() {
fragmentTorrents.sortBy(TorrentsSortBy.UploadSpeed);
}
@OptionsItem(resName = "action_sort_ratio")
@OptionsItem(R.id.action_sort_ratio)
protected void sortByRatio() {
fragmentTorrents.sortBy(TorrentsSortBy.Ratio);
}
@OptionsItem(resName = "action_sort_size")
@OptionsItem(R.id.action_sort_size)
protected void sortBySize() {
fragmentTorrents.sortBy(TorrentsSortBy.Size);
}
@OptionsItem(resName = "action_filter")
protected void startFilterEntryDialog() {
FilterEntryDialog.startFilterEntry(this);
}
private SearchView.OnQueryTextListener filterQueryTextChanged = new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
// Redirect to filter method which will directly apply it
filterTorrents(newText);
return true;
}
};
/**
* Redirect the newly entered list filter to the torrents fragment.
@ -841,16 +878,15 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE @@ -841,16 +878,15 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE
}
/**
* Shows the a details fragment for the given torrent, either in the dedicated details fragment pane, in the same
* pane as the torrent list was displayed or by starting a details activity.
* Shows the a details fragment for the given torrent, either in the dedicated details fragment pane, in the same pane as the torrent list was
* displayed or by starting a details activity.
* @param torrent The torrent to show detailed statistics for
*/
public void openDetails(Torrent torrent) {
if (fragmentDetails != null && fragmentDetails.isAdded()) {
fragmentDetails.updateTorrent(torrent);
} else {
DetailsActivity_.intent(this).torrent(torrent).currentLabels(lastNavigationLabels)
.startForResult(RESULT_DETAILS);
DetailsActivity_.intent(this).torrent(torrent).currentLabels(lastNavigationLabels).startForResult(RESULT_DETAILS);
}
}
@ -863,8 +899,7 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE @@ -863,8 +899,7 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE
return;
}
if (result instanceof RetrieveTaskSuccessResult) {
onTorrentsRetrieved(((RetrieveTaskSuccessResult) result).getTorrents(),
((RetrieveTaskSuccessResult) result).getLabels());
onTorrentsRetrieved(((RetrieveTaskSuccessResult) result).getTorrents(), ((RetrieveTaskSuccessResult) result).getLabels());
} else {
onCommunicationError((DaemonTaskFailureResult) result, true);
}
@ -961,9 +996,8 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE @@ -961,9 +996,8 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE
AddByMagnetUrlTask addByMagnetUrlTask = AddByMagnetUrlTask.create(currentConnection, url);
if (!Daemon.supportsAddByMagnetUrl(currentConnection.getType())) {
// No support for magnet links: forcefully let the task fail to report the error
onCommunicationError(new DaemonTaskFailureResult(addByMagnetUrlTask,
new DaemonException(DaemonException.ExceptionType.MethodUnsupported,
currentConnection.getType().name() + " does not support magnet links")), false);
onCommunicationError(new DaemonTaskFailureResult(addByMagnetUrlTask, new DaemonException(DaemonException.ExceptionType.MethodUnsupported,
currentConnection.getType().name() + " does not support magnet links")), false);
return;
}
@ -1021,8 +1055,7 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE @@ -1021,8 +1055,7 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE
try {
// Cookies are taken from the websearchSetting that we already matched against this target URL
DefaultHttpClient httpclient =
HttpHelper.createStandardHttpClient(false, null, null, true, null, 10000, null, -1);
DefaultHttpClient httpclient = HttpHelper.createStandardHttpClient(false, null, null, true, null, 10000, null, -1);
Map<String, String> cookies = HttpHelper.parseCookiePairs(websearchSetting.getCookies());
String domain = Uri.parse(url).getHost();
for (Entry<String, String> pair : cookies.entrySet()) {
@ -1140,8 +1173,7 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE @@ -1140,8 +1173,7 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE
DaemonTaskResult result = RemoveTask.create(currentConnection, torrent, withData).execute(log);
if (result instanceof DaemonTaskSuccessResult) {
onTaskSucceeded((DaemonTaskSuccessResult) result,
getString(withData ? R.string.result_removed_with_data : R.string.result_removed,
torrent.getName()));
getString(withData ? R.string.result_removed_with_data : R.string.result_removed, torrent.getName()));
} else {
onCommunicationError((DaemonTaskFailureResult) result, false);
}
@ -1151,12 +1183,10 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE @@ -1151,12 +1183,10 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE
@Override
public void updateLabel(Torrent torrent, String newLabel) {
torrent.mimicNewLabel(newLabel);
DaemonTaskResult result =
SetLabelTask.create(currentConnection, torrent, newLabel == null ? "" : newLabel).execute(log);
DaemonTaskResult result = SetLabelTask.create(currentConnection, torrent, newLabel == null ? "" : newLabel).execute(log);
if (result instanceof DaemonTaskSuccessResult) {
onTaskSucceeded((DaemonTaskSuccessResult) result,
newLabel == null ? getString(R.string.result_labelremoved) :
getString(R.string.result_labelset, newLabel));
newLabel == null ? getString(R.string.result_labelremoved) : getString(R.string.result_labelset, newLabel));
} else {
onCommunicationError((DaemonTaskFailureResult) result, false);
}
@ -1168,8 +1198,7 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE @@ -1168,8 +1198,7 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE
torrent.mimicCheckingStatus();
DaemonTaskResult result = ForceRecheckTask.create(currentConnection, torrent).execute(log);
if (result instanceof DaemonTaskSuccessResult) {
onTaskSucceeded((DaemonTaskSuccessResult) result,
getString(R.string.result_recheckedstarted, torrent.getName()));
onTaskSucceeded((DaemonTaskSuccessResult) result, getString(R.string.result_recheckedstarted, torrent.getName()));
} else {
onCommunicationError((DaemonTaskFailureResult) result, false);
}
@ -1200,9 +1229,7 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE @@ -1200,9 +1229,7 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE
@Background
@Override
public void updatePriority(Torrent torrent, List<TorrentFile> files, Priority priority) {
DaemonTaskResult result =
SetFilePriorityTask.create(currentConnection, torrent, priority, new ArrayList<TorrentFile>(files))
.execute(log);
DaemonTaskResult result = SetFilePriorityTask.create(currentConnection, torrent, priority, new ArrayList<TorrentFile>(files)).execute(log);
if (result instanceof DaemonTaskSuccessResult) {
onTaskSucceeded((DaemonTaskSuccessResult) result, getString(R.string.result_priotitiesset));
} else {
@ -1212,8 +1239,7 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE @@ -1212,8 +1239,7 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE
@Background
public void updateMaxSpeeds(Integer maxDownloadSpeed, Integer maxUploadSpeed) {
DaemonTaskResult result =
SetTransferRatesTask.create(currentConnection, maxUploadSpeed, maxDownloadSpeed).execute(log);
DaemonTaskResult result = SetTransferRatesTask.create(currentConnection, maxUploadSpeed, maxDownloadSpeed).execute(log);
if (result instanceof DaemonTaskSuccessResult) {
onTaskSucceeded((DaemonTaskSuccessResult) result, getString(R.string.result_maxspeedsset));
} else {
@ -1246,8 +1272,7 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE @@ -1246,8 +1272,7 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE
@UiThread
protected void onTorrentsRetrieved(List<Torrent> torrents, List<org.transdroid.daemon.Label> labels) {
lastNavigationLabels =
Label.convertToNavigationLabels(labels, getResources().getString(R.string.labels_unlabeled));
lastNavigationLabels = Label.convertToNavigationLabels(labels, getResources().getString(R.string.labels_unlabeled));
// Report the newly retrieved list of torrents to the torrents fragment
fragmentTorrents.updateIsLoading(false);
@ -1281,8 +1306,8 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE @@ -1281,8 +1306,8 @@ public class TorrentsActivity extends ActionBarActivity implements TorrentTasksE
}
// Update the server status (counts and speeds) in the action bar
serverStatusView.updateStatus(torrents, systemSettings.treatDormantAsInactive(),
Daemon.supportsSetTransferRates(currentConnection.getType()));
serverStatusView
.updateStatus(torrents, systemSettings.treatDormantAsInactive(), Daemon.supportsSetTransferRates(currentConnection.getType()));
}

103
app/src/main/java/org/transdroid/core/gui/TorrentsFragment.java

@ -16,10 +16,16 @@ @@ -16,10 +16,16 @@
*/
package org.transdroid.core.gui;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.Locale;
import android.app.Fragment;
import android.support.v4.widget.SwipeRefreshLayout;
import android.view.ActionMode;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AbsListView.MultiChoiceModeListener;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import org.androidannotations.annotations.AfterViews;
import org.androidannotations.annotations.Bean;
@ -31,7 +37,8 @@ import org.androidannotations.annotations.ViewById; @@ -31,7 +37,8 @@ import org.androidannotations.annotations.ViewById;
import org.transdroid.R;
import org.transdroid.core.app.settings.ApplicationSettings;
import org.transdroid.core.app.settings.SystemSettings;
import org.transdroid.core.gui.lists.*;
import org.transdroid.core.gui.lists.TorrentsAdapter;
import org.transdroid.core.gui.lists.TorrentsAdapter_;
import org.transdroid.core.gui.navigation.Label;
import org.transdroid.core.gui.navigation.NavigationFilter;
import org.transdroid.core.gui.navigation.RefreshableActivity;
@ -43,23 +50,17 @@ import org.transdroid.daemon.Torrent; @@ -43,23 +50,17 @@ import org.transdroid.daemon.Torrent;
import org.transdroid.daemon.TorrentsComparator;
import org.transdroid.daemon.TorrentsSortBy;
import android.app.Fragment;
import android.view.ActionMode;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AbsListView.MultiChoiceModeListener;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.Locale;
/**
* Fragment that shows a list of torrents that are active on the server. It supports sorting and filtering and can show
* connection progress and issues. However, actual task starting and execution and overall navigation elements are part
* of the containing activity, not this fragment.
* Fragment that shows a list of torrents that are active on the server. It supports sorting and filtering and can show connection progress and
* issues. However, actual task starting and execution and overall navigation elements are part of the containing activity, not this fragment.
* @author Eric Kok
*/
@EFragment(resName = "fragment_torrents")
@EFragment(R.layout.fragment_torrents)
public class TorrentsFragment extends Fragment implements OnLabelPickedListener {
// Local data
@ -91,7 +92,9 @@ public class TorrentsFragment extends Fragment implements OnLabelPickedListener @@ -91,7 +92,9 @@ public class TorrentsFragment extends Fragment implements OnLabelPickedListener
protected Daemon daemonType;
// Views
@ViewById(resName = "torrents_list")
@ViewById
protected SwipeRefreshLayout swipeRefreshLayout;
@ViewById
protected ListView torrentsList;
@ViewById
protected TextView emptyText;
@ -113,11 +116,12 @@ public class TorrentsFragment extends Fragment implements OnLabelPickedListener @@ -113,11 +116,12 @@ public class TorrentsFragment extends Fragment implements OnLabelPickedListener
torrentsList.setAdapter(TorrentsAdapter_.getInstance_(getActivity()));
torrentsList.setMultiChoiceModeListener(onTorrentsSelected);
torrentsList.setFastScrollEnabled(true);
if (torrents != null)
if (torrents != null) {
updateTorrents(torrents, currentLabels);
}
// Allow pulls on the list view to refresh the torrents
if (getActivity() != null && getActivity() instanceof RefreshableActivity) {
((RefreshableActivity) getActivity()).addRefreshableView(torrentsList);
((RefreshableActivity) getActivity()).addSwipeRefreshLayout(swipeRefreshLayout);
}
nosettingsText.setText(getString(R.string.navigation_nosettings, getString(R.string.app_name)));
@ -149,8 +153,9 @@ public class TorrentsFragment extends Fragment implements OnLabelPickedListener @@ -149,8 +153,9 @@ public class TorrentsFragment extends Fragment implements OnLabelPickedListener
}
}
// In case it was an update, add the updated torrent object
if (!wasRemoved)
if (!wasRemoved) {
this.torrents.add(affected);
}
// Now refresh the screen
applyAllFilters();
}
@ -162,8 +167,9 @@ public class TorrentsFragment extends Fragment implements OnLabelPickedListener @@ -162,8 +167,9 @@ public class TorrentsFragment extends Fragment implements OnLabelPickedListener
*/
public void clear(boolean clearError, boolean clearFilter) {
this.torrents = null;
if (clearError)
if (clearError) {
this.connectionErrorMessage = null;
}
if (clearFilter) {
this.currentTextFilter = null;
this.currentNavigationFilter = null;
@ -172,8 +178,8 @@ public class TorrentsFragment extends Fragment implements OnLabelPickedListener @@ -172,8 +178,8 @@ public class TorrentsFragment extends Fragment implements OnLabelPickedListener
}
/**
* Stores the new sort order (for future refreshes) and sorts the current visible list. If the given new sort
* property equals the existing property, the list sort order is reversed instead.
* Stores the new sort order (for future refreshes) and sorts the current visible list. If the given new sort property equals the existing
* property, the list sort order is reversed instead.
* @param newSortOrder The sort order that the user selected.
*/
public void sortBy(TorrentsSortBy newSortOrder) {
@ -212,26 +218,26 @@ public class TorrentsFragment extends Fragment implements OnLabelPickedListener @@ -212,26 +218,26 @@ public class TorrentsFragment extends Fragment implements OnLabelPickedListener
}
// Filter the list of torrents to show according to navigation and text filters
ArrayList<Torrent> filteredTorrents = new ArrayList<Torrent>(torrents);
ArrayList<Torrent> filteredTorrents = new ArrayList<>(torrents);
if (currentNavigationFilter != null) {
// Remove torrents that do not match the selected navigation filter
for (Iterator<Torrent> torrentIter = filteredTorrents.iterator(); torrentIter.hasNext();) {
if (!currentNavigationFilter.matches(torrentIter.next(), systemSettings.treatDormantAsInactive()))
for (Iterator<Torrent> torrentIter = filteredTorrents.iterator(); torrentIter.hasNext(); ) {
if (!currentNavigationFilter.matches(torrentIter.next(), systemSettings.treatDormantAsInactive())) {
torrentIter.remove();
}
}
}
if (currentTextFilter != null) {
// Remove torrent that do not contain the text filter string
for (Iterator<Torrent> torrentIter = filteredTorrents.iterator(); torrentIter.hasNext();) {
if (!torrentIter.next().getName().toLowerCase(Locale.getDefault())
.contains(currentTextFilter.toLowerCase(Locale.getDefault())))
// Remove torrents that do not contain the text filter string
for (Iterator<Torrent> torrentIter = filteredTorrents.iterator(); torrentIter.hasNext(); ) {
if (!torrentIter.next().getName().toLowerCase(Locale.getDefault()).contains(currentTextFilter.toLowerCase(Locale.getDefault()))) {
torrentIter.remove();
}
}
}
// Sort the list of filtered torrents
Collections.sort(filteredTorrents, new TorrentsComparator(daemonType, this.currentSortOrder,
this.currentSortDescending));
Collections.sort(filteredTorrents, new TorrentsComparator(daemonType, this.currentSortOrder, this.currentSortDescending));
((TorrentsAdapter) torrentsList.getAdapter()).update(filteredTorrents);
updateViewVisibility();
@ -270,11 +276,11 @@ public class TorrentsFragment extends Fragment implements OnLabelPickedListener @@ -270,11 +276,11 @@ public class TorrentsFragment extends Fragment implements OnLabelPickedListener
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
// Get checked torrents
ArrayList<Torrent> checked = new ArrayList<Torrent>();
ArrayList<Torrent> checked = new ArrayList<>();
for (int i = 0; i < torrentsList.getCheckedItemPositions().size(); i++) {
if (torrentsList.getCheckedItemPositions().valueAt(i) && i < torrentsList.getAdapter().getCount())
checked.add((Torrent) torrentsList.getAdapter().getItem(
torrentsList.getCheckedItemPositions().keyAt(i)));
if (torrentsList.getCheckedItemPositions().valueAt(i) && i < torrentsList.getAdapter().getCount()) {
checked.add((Torrent) torrentsList.getAdapter().getItem(torrentsList.getCheckedItemPositions().keyAt(i)));
}
}
int itemId = item.getItemId();
@ -316,9 +322,10 @@ public class TorrentsFragment extends Fragment implements OnLabelPickedListener @@ -316,9 +322,10 @@ public class TorrentsFragment extends Fragment implements OnLabelPickedListener
return true;
} else if (itemId == R.id.action_setlabel) {
lastMultiSelectedTorrents = checked;
if (currentLabels != null)
if (currentLabels != null) {
new SetLabelDialog().setOnLabelPickedListener(TorrentsFragment.this).setCurrentLabels(currentLabels)
.show(getFragmentManager(), "SetLabelDialog");
.show(getFragmentManager(), "SetLabelDialog");
}
mode.finish();
return true;
} else {
@ -359,7 +366,7 @@ public class TorrentsFragment extends Fragment implements OnLabelPickedListener @@ -359,7 +366,7 @@ public class TorrentsFragment extends Fragment implements OnLabelPickedListener
}
}
@ItemClick(resName = "torrents_list")
@ItemClick(R.id.torrents_list)
protected void torrentsListClicked(Torrent torrent) {
// Show the torrent details fragment
((TorrentsActivity) getActivity()).openDetails(torrent);
@ -373,8 +380,8 @@ public class TorrentsFragment extends Fragment implements OnLabelPickedListener @@ -373,8 +380,8 @@ public class TorrentsFragment extends Fragment implements OnLabelPickedListener
}
/**
* Updates the shown screen depending on whether we have a connection (so torrents can be shown) or not (in case we
* need to show a message suggesting help). This should only ever be called on the UI thread.
* Updates the shown screen depending on whether we have a connection (so torrents can be shown) or not (in case we need to show a message
* suggesting help). This should only ever be called on the UI thread.
* @param hasAConnection True if the user has servers configured and therefore has a connection that can be used
*/
public void updateConnectionStatus(boolean hasAConnection, Daemon daemonType) {
@ -393,12 +400,12 @@ public class TorrentsFragment extends Fragment implements OnLabelPickedListener @@ -393,12 +400,12 @@ public class TorrentsFragment extends Fragment implements OnLabelPickedListener
}
/**
* Updates the shown screen depending on whether the torrents are loading. This should only ever be called on the UI
* thread.
* Updates the shown screen depending on whether the torrents are loading. This should only ever be called on the UI thread.
* @param isLoading True if the list of torrents is (re)loading, false otherwise
*/
public void updateIsLoading(boolean isLoading) {
this.isLoading = isLoading;
swipeRefreshLayout.setRefreshing(isLoading);
if (isLoading) {
clear(true, false); // Indirectly also calls updateViewVisibility()
} else {
@ -407,10 +414,8 @@ public class TorrentsFragment extends Fragment implements OnLabelPickedListener @@ -407,10 +414,8 @@ public class TorrentsFragment extends Fragment implements OnLabelPickedListener
}
/**
* Updates the shown screen depending on whether a connection error occurred. This should only ever be called on the
* UI thread.
* @param connectionErrorMessage The error message from the last failed connection attempt, or null to clear the
* visible error text
* Updates the shown screen depending on whether a connection error occurred. This should only ever be called on the UI thread.
* @param connectionErrorMessage The error message from the last failed connection attempt, or null to clear the visible error text
*/
public void updateError(String connectionErrorMessage) {
this.connectionErrorMessage = connectionErrorMessage;

16
app/src/main/java/org/transdroid/core/gui/lists/SimpleListItemView.java

@ -16,31 +16,33 @@ @@ -16,31 +16,33 @@
*/
package org.transdroid.core.gui.lists;
import org.androidannotations.annotations.EViewGroup;
import org.androidannotations.annotations.ViewById;
import android.content.Context;
import android.widget.FrameLayout;
import android.widget.TextView;
import org.androidannotations.annotations.EViewGroup;
import org.androidannotations.annotations.ViewById;
import org.transdroid.R;
/**
* View that represents some {@link SimpleListItem} object and simple prints out the text (in proper style)
* @author Eric Kok
*/
@EViewGroup(resName="list_item_simple")
@EViewGroup(R.layout.list_item_simple)
public class SimpleListItemView extends FrameLayout {
@ViewById
protected TextView itemText;
public SimpleListItemView(Context context) {
super(context);
}
public void bind(SimpleListItem filterItem, int autoLinkMask) {
itemText.setText(filterItem.getName());
if (autoLinkMask > 0)
if (autoLinkMask > 0) {
itemText.setAutoLinkMask(autoLinkMask);
}
}
}

45
app/src/main/java/org/transdroid/core/gui/lists/TorrentDetailsView.java

@ -16,13 +16,6 @@ @@ -16,13 +16,6 @@
*/
package org.transdroid.core.gui.lists;
import org.androidannotations.annotations.EViewGroup;
import org.androidannotations.annotations.ViewById;
import org.transdroid.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;
@ -30,16 +23,23 @@ import android.view.View; @@ -30,16 +23,23 @@ import android.view.View;
import android.widget.RelativeLayout;
import android.widget.TextView;
import org.androidannotations.annotations.EViewGroup;
import org.androidannotations.annotations.ViewById;
import org.transdroid.R;
import org.transdroid.daemon.Daemon;
import org.transdroid.daemon.Torrent;
import org.transdroid.daemon.util.FileSizeConverter;
/**
* Represents a group of views that show torrent status, sizes, speeds and other details.
* @author Eric Kok
*/
@EViewGroup(resName="fragment_details_header")
@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;
protected TextView labelText, dateaddedText, uploadedText, uploadedunitText, ratioText, upspeedText, seedersText, downloadedunitText,
downloadedText, totalsizeText, downspeedText, leechersText, statusText;
@ViewById
protected TorrentStatusLayout statusLayout;
@ -73,36 +73,31 @@ public class TorrentDetailsView extends RelativeLayout { @@ -73,36 +73,31 @@ public class TorrentDetailsView extends RelativeLayout {
// 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.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);
}
statusLayout.setStatus(torrent.getStatusCode());
statusText.setText(getResources().getString(R.string.status_status, local.getProgressStatusEta(getResources())));
ratioText.setText(getResources().getString(R.string.status_ratio, local.getRatioString()));
seedersText.setText(getResources().getString(R.string.status_seeders, torrent.getSeedersConnected(),
torrent.getSeedersKnown()));
leechersText.setText(getResources().getString(R.string.status_leechers, torrent.getLeechersConnected(),
torrent.getLeechersKnown()));
seedersText.setText(getResources().getString(R.string.status_seeders, torrent.getSeedersConnected(), torrent.getSeedersKnown()));
leechersText.setText(getResources().getString(R.string.status_leechers, torrent.getLeechersConnected(), torrent.getLeechersKnown()));
// TODO: Add field that displays torrent errors (as opposed to tracker errors)
// TODO: Add field that displays availability
// Sizes and speeds texts
totalsizeText.setText(getResources().getString(R.string.status_ofsize,
FileSizeConverter.getSize(torrent.getTotalSize())));
totalsizeText.setText(getResources().getString(R.string.status_ofsize, 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_details,
FileSizeConverter.getSize(torrent.getRateDownload()) + "/s"));
upspeedText.setText(getResources().getString(R.string.status_speed_up,
FileSizeConverter.getSize(torrent.getRateUpload()) + "/s"));
downspeedText
.setText(getResources().getString(R.string.status_speed_down_details, FileSizeConverter.getSize(torrent.getRateDownload()) + "/s"));
upspeedText.setText(getResources().getString(R.string.status_speed_up, FileSizeConverter.getSize(torrent.getRateUpload()) + "/s"));
}

13
app/src/main/java/org/transdroid/core/gui/lists/TorrentFileView.java

@ -16,23 +16,24 @@ @@ -16,23 +16,24 @@
*/
package org.transdroid.core.gui.lists;
import android.content.Context;
import android.widget.TextView;
import org.androidannotations.annotations.EViewGroup;
import org.androidannotations.annotations.ViewById;
import org.transdroid.R;
import org.transdroid.daemon.TorrentFile;
import android.content.Context;
import android.widget.TextView;
/**
* View that represents some {@link TorrentFile} object and show the file's name, status and priority
* @author Eric Kok
*/
@EViewGroup(resName="list_item_torrentfile")
@EViewGroup(R.layout.list_item_torrentfile)
public class TorrentFileView extends TorrentFilePriorityLayout {
@ViewById
protected TextView nameText, progressText, sizesText;
public TorrentFileView(Context context) {
super(context, null);
}
@ -43,5 +44,5 @@ public class TorrentFileView extends TorrentFilePriorityLayout { @@ -43,5 +44,5 @@ public class TorrentFileView extends TorrentFilePriorityLayout {
progressText.setText(torrentFile.getProgressText());
setPriority(torrentFile.getPriority());
}
}

2
app/src/main/java/org/transdroid/core/gui/lists/TorrentStatusLayout.java

@ -68,7 +68,7 @@ public class TorrentStatusLayout extends RelativeLayout { @@ -68,7 +68,7 @@ public class TorrentStatusLayout extends RelativeLayout {
/**
* Registers the status of the represented torrent and invalidates the view so the status colour will be updated
* accordingly.
* @param status
* @param status The updated torrent status to show
*/
public void setStatus(TorrentStatus status) {
this.status = status;

17
app/src/main/java/org/transdroid/core/gui/lists/TorrentView.java

@ -16,21 +16,22 @@ @@ -16,21 +16,22 @@
*/
package org.transdroid.core.gui.lists;
import org.androidannotations.annotations.EViewGroup;
import org.androidannotations.annotations.ViewById;
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 org.androidannotations.annotations.EViewGroup;
import org.androidannotations.annotations.ViewById;
import org.transdroid.R;
import org.transdroid.daemon.Torrent;
import org.transdroid.daemon.TorrentStatus;
/**
* View that represents some {@link Torrent} object and displays progress, status, speeds, etc.
* @author Eric Kok
*/
@EViewGroup(resName = "list_item_torrent")
@EViewGroup(R.layout.list_item_torrent)
public class TorrentView extends TorrentStatusLayout {
@ViewById
@ -54,8 +55,8 @@ public class TorrentView extends TorrentStatusLayout { @@ -54,8 +55,8 @@ public class TorrentView extends TorrentStatusLayout {
priorityImage.setVisibility(View.INVISIBLE);
// Only show status bar, peers and speed fields if relevant, i.e. when downloading or actively seeding
if (torrent.getStatusCode() == TorrentStatus.Downloading
|| (torrent.getStatusCode() == TorrentStatus.Seeding && torrent.getRateUpload() > 0)) {
if (torrent.getStatusCode() == TorrentStatus.Downloading ||
(torrent.getStatusCode() == TorrentStatus.Seeding && torrent.getRateUpload() > 0)) {
torrentProgressbar.setVisibility(View.VISIBLE);
torrentProgressbar.setProgress((int) (torrent.getDownloadedPercentage() * 100));
torrentProgressbar.setActive(torrent.canPause());

24
app/src/main/java/org/transdroid/core/gui/lists/TorrentsAdapter.java

@ -16,16 +16,16 @@ @@ -16,16 +16,16 @@
*/
package org.transdroid.core.gui.lists;
import java.util.ArrayList;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import org.androidannotations.annotations.EBean;
import org.androidannotations.annotations.RootContext;
import org.transdroid.daemon.Torrent;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import java.util.ArrayList;
/**
* Adapter that contains a list of torrent objects to show.
@ -33,9 +33,9 @@ import android.widget.BaseAdapter; @@ -33,9 +33,9 @@ import android.widget.BaseAdapter;
*/
@EBean
public class TorrentsAdapter extends BaseAdapter {
private ArrayList<Torrent> torrents = null;
@RootContext
protected Context context;
@ -47,23 +47,25 @@ public class TorrentsAdapter extends BaseAdapter { @@ -47,23 +47,25 @@ public class TorrentsAdapter extends BaseAdapter {
this.torrents = newTorrents;
notifyDataSetChanged();
}
@Override
public boolean hasStableIds() {
return true;
}
@Override
public int getCount() {
if (torrents == null)
if (torrents == null) {
return 0;
}
return torrents.size();
}
@Override
public Torrent getItem(int position) {
if (torrents == null)
if (torrents == null) {
return null;
}
return torrents.get(position);
}

20
app/src/main/java/org/transdroid/core/gui/navigation/FilterListAdapter.java

@ -16,8 +16,8 @@ @@ -16,8 +16,8 @@
*/
package org.transdroid.core.gui.navigation;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.view.View;
import org.androidannotations.annotations.EBean;
import org.androidannotations.annotations.RootContext;
@ -28,12 +28,11 @@ import org.transdroid.core.gui.lists.SimpleListItem; @@ -28,12 +28,11 @@ import org.transdroid.core.gui.lists.SimpleListItem;
import org.transdroid.core.gui.lists.ViewHolderAdapter;
import org.transdroid.core.gui.navigation.StatusType.StatusTypeFilter;
import android.content.Context;
import android.view.View;
import java.util.ArrayList;
import java.util.List;
/**
* List adapter that holds filter items, that is, servers, view types and labels. A header item is inserted where
* appropriate.
* List adapter that holds filter items, that is, servers, view types and labels. A header item is inserted where appropriate.
* @author Eric Kok
*/
@EBean
@ -54,8 +53,7 @@ public class FilterListAdapter extends MergeAdapter { @@ -54,8 +53,7 @@ public class FilterListAdapter extends MergeAdapter {
*/
public void updateServers(List<ServerSetting> servers) {
if (this.serverItems == null && servers != null) {
serverSeparator = new ViewHolderAdapter(FilterSeparatorView_.build(context).setText(
context.getString(R.string.navigation_servers)));
serverSeparator = new ViewHolderAdapter(FilterSeparatorView_.build(context).setText(context.getString(R.string.navigation_servers)));
serverSeparator.setViewVisibility(servers.isEmpty() ? View.GONE : View.VISIBLE);
addAdapter(serverSeparator);
this.serverItems = new FilterListItemAdapter(context, servers);
@ -76,8 +74,7 @@ public class FilterListAdapter extends MergeAdapter { @@ -76,8 +74,7 @@ public class FilterListAdapter extends MergeAdapter {
*/
public void updateStatusTypes(List<StatusTypeFilter> statusTypes) {
if (this.statusTypeItems == null && statusTypes != null) {
statusTypeSeparator = new ViewHolderAdapter(FilterSeparatorView_.build(context).setText(
context.getString(R.string.navigation_status)));
statusTypeSeparator = new ViewHolderAdapter(FilterSeparatorView_.build(context).setText(context.getString(R.string.navigation_status)));
statusTypeSeparator.setViewVisibility(statusTypes.isEmpty() ? View.GONE : View.VISIBLE);
addAdapter(statusTypeSeparator);
this.statusTypeItems = new FilterListItemAdapter(context, statusTypes);
@ -98,8 +95,7 @@ public class FilterListAdapter extends MergeAdapter { @@ -98,8 +95,7 @@ public class FilterListAdapter extends MergeAdapter {
*/
public void updateLabels(List<Label> labels) {
if (this.labelItems == null && labels != null) {
labelSeperator = new ViewHolderAdapter(FilterSeparatorView_.build(context).setText(
context.getString(R.string.navigation_labels)));
labelSeperator = new ViewHolderAdapter(FilterSeparatorView_.build(context).setText(context.getString(R.string.navigation_labels)));
labelSeperator.setViewVisibility(labels.isEmpty() ? View.GONE : View.VISIBLE);
addAdapter(labelSeperator);
this.labelItems = new FilterListItemAdapter(context, labels);

10
app/src/main/java/org/transdroid/core/gui/navigation/FilterListItemAdapter.java

@ -16,16 +16,16 @@ @@ -16,16 +16,16 @@
*/
package org.transdroid.core.gui.navigation;
import java.util.List;
import org.transdroid.core.gui.lists.SimpleListItem;
import org.transdroid.core.gui.lists.SimpleListItemView;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import org.transdroid.core.gui.lists.SimpleListItem;
import org.transdroid.core.gui.lists.SimpleListItemView;
import java.util.List;
public class FilterListItemAdapter extends BaseAdapter {
private final Context context;

15
app/src/main/java/org/transdroid/core/gui/navigation/FilterListItemView.java

@ -16,24 +16,25 @@ @@ -16,24 +16,25 @@
*/
package org.transdroid.core.gui.navigation;
import org.androidannotations.annotations.EViewGroup;
import org.androidannotations.annotations.ViewById;
import org.transdroid.core.gui.lists.SimpleListItem;
import android.content.Context;
import android.widget.FrameLayout;
import android.widget.TextView;
import org.androidannotations.annotations.EViewGroup;
import org.androidannotations.annotations.ViewById;
import org.transdroid.R;
import org.transdroid.core.gui.lists.SimpleListItem;
/**
* View that represents some {@link SimpleListItem} object specifically used to represent a navigation filter item.
* @author Eric Kok
*/
@EViewGroup(resName="list_item_filter")
@EViewGroup(R.layout.list_item_filter)
public class FilterListItemView extends FrameLayout {
@ViewById
protected TextView itemText;
public FilterListItemView(Context context) {
super(context);
}
@ -41,5 +42,5 @@ public class FilterListItemView extends FrameLayout { @@ -41,5 +42,5 @@ public class FilterListItemView extends FrameLayout {
public void bind(SimpleListItem filterItem) {
itemText.setText(filterItem.getName());
}
}

18
app/src/main/java/org/transdroid/core/gui/navigation/FilterSeparatorView.java

@ -16,26 +16,27 @@ @@ -16,26 +16,27 @@
*/
package org.transdroid.core.gui.navigation;
import org.androidannotations.annotations.EViewGroup;
import org.androidannotations.annotations.ViewById;
import android.content.Context;
import android.widget.AbsListView;
import android.widget.FrameLayout;
import android.widget.TextView;
import org.androidannotations.annotations.EViewGroup;
import org.androidannotations.annotations.ViewById;
import org.transdroid.R;
/**
* A list item that shows a sub header or separator (in underlined Holo style).
* @author Eric Kok
*/
@EViewGroup(resName="list_item_separator")
@EViewGroup(R.layout.list_item_separator)
public class FilterSeparatorView extends FrameLayout {
protected String text;
@ViewById
protected TextView separatorText;
public FilterSeparatorView(Context context) {
super(context);
}
@ -47,9 +48,8 @@ public class FilterSeparatorView extends FrameLayout { @@ -47,9 +48,8 @@ public class FilterSeparatorView extends FrameLayout {
*/
public FilterSeparatorView setText(String text) {
separatorText.setText(text);
setLayoutParams(new AbsListView.LayoutParams(AbsListView.LayoutParams.WRAP_CONTENT,
AbsListView.LayoutParams.WRAP_CONTENT));
setLayoutParams(new AbsListView.LayoutParams(AbsListView.LayoutParams.WRAP_CONTENT, AbsListView.LayoutParams.WRAP_CONTENT));
return this;
}
}

38
app/src/main/java/org/transdroid/core/gui/navigation/Label.java

@ -16,16 +16,16 @@ @@ -16,16 +16,16 @@
*/
package org.transdroid.core.gui.navigation;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import org.transdroid.core.gui.lists.SimpleListItem;
import org.transdroid.daemon.Torrent;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Represents some label that is active or available on the server.
@ -44,18 +44,19 @@ public class Label implements SimpleListItem, NavigationFilter, Comparable<Label @@ -44,18 +44,19 @@ public class Label implements SimpleListItem, NavigationFilter, Comparable<Label
this.count = count;
this.isEmptyLabel = isEmptyLabel;
}
public Label(org.transdroid.daemon.Label daemonLabel) {
this(daemonLabel.getName(), daemonLabel.getCount(), false);
}
@Override
public String getName() {
if (TextUtils.isEmpty(this.name))
if (TextUtils.isEmpty(this.name)) {
return unnamedLabelText;
}
return this.name;
}
@Override
public String getCode() {
// Use the class name and label name to provide a unique navigation filter code
@ -77,8 +78,9 @@ public class Label implements SimpleListItem, NavigationFilter, Comparable<Label @@ -77,8 +78,9 @@ public class Label implements SimpleListItem, NavigationFilter, Comparable<Label
*/
@Override
public boolean matches(Torrent torrent, boolean dormantAsInactive) {
if (isEmptyLabel)
if (isEmptyLabel) {
return TextUtils.isEmpty(torrent.getLabelName());
}
return torrent.getLabelName() != null && torrent.getLabelName().equals(name);
}
@ -88,22 +90,22 @@ public class Label implements SimpleListItem, NavigationFilter, Comparable<Label @@ -88,22 +90,22 @@ public class Label implements SimpleListItem, NavigationFilter, Comparable<Label
}
/**
* Converts a list of labels as retrieved from a server daemon into a list of labels that can be used in the UI as
* navigation filters.
* Converts a list of labels as retrieved from a server daemon into a list of labels that can be used in the UI as navigation filters.
* @param daemonLabels The raw list of labels as received from the server daemon adapter
* @param unnamedLabel The text to show for the empty label (i.e. the unnamed label)
* @return A label items that can be used in a filter list such as the action bar spinner
*/
public static ArrayList<Label> convertToNavigationLabels(List<org.transdroid.daemon.Label> daemonLabels,
String unnamedLabel) {
if (daemonLabels == null)
public static ArrayList<Label> convertToNavigationLabels(List<org.transdroid.daemon.Label> daemonLabels, String unnamedLabel) {
if (daemonLabels == null) {
return null;
ArrayList<Label> localLabels = new ArrayList<Label>();
}
ArrayList<Label> localLabels = new ArrayList<>();
unnamedLabelText = unnamedLabel;
localLabels.add(new Label(unnamedLabel, -1, true));
for (org.transdroid.daemon.Label label : daemonLabels) {
if (!TextUtils.isEmpty(label.getName()))
if (!TextUtils.isEmpty(label.getName())) {
localLabels.add(new Label(label));
}
}
Collections.sort(localLabels);
return localLabels;
@ -134,7 +136,7 @@ public class Label implements SimpleListItem, NavigationFilter, Comparable<Label @@ -134,7 +136,7 @@ public class Label implements SimpleListItem, NavigationFilter, Comparable<Label
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeInt(count);
dest.writeInt(isEmptyLabel? 1: 0);
dest.writeInt(isEmptyLabel ? 1 : 0);
}
}

14
app/src/main/java/org/transdroid/core/gui/navigation/NavigationFilter.java

@ -16,10 +16,10 @@ @@ -16,10 +16,10 @@
*/
package org.transdroid.core.gui.navigation;
import org.transdroid.daemon.Torrent;
import android.os.Parcelable;
import org.transdroid.daemon.Torrent;
/**
* Represents a filter, used in the app navigation, that can check if some torrent matches the user-set filter
* @author Eric Kok
@ -27,11 +27,10 @@ import android.os.Parcelable; @@ -27,11 +27,10 @@ import android.os.Parcelable;
public interface NavigationFilter extends Parcelable {
/**
* Implementations should check if the supplied torrent matches the filter; for example a label filter should return
* true if the torrent's label equals this items label name.
* Implementations should check if the supplied torrent matches the filter; for example a label filter should return true if the torrent's label
* equals this items label name.
* @param torrent The torrent to check for matches
* @param dormantAsInactive If true, dormant (0KB/s, so no data transfer) torrents are never actively downloading or
* seeding
* @param dormantAsInactive If true, dormant (0KB/s, so no data transfer) torrents are never actively downloading or seeding
* @return True if the torrent matches the filter and should be shown in the current screen, false otherwise
*/
boolean matches(Torrent torrent, boolean dormantAsInactive);
@ -43,8 +42,7 @@ public interface NavigationFilter extends Parcelable { @@ -43,8 +42,7 @@ public interface NavigationFilter extends Parcelable {
String getName();
/**
* Implementations should return a code that (within reasonable expectations) uniquely identifies it in the list of
* navigation filters
* Implementations should return a code that (within reasonable expectations) uniquely identifies it in the list of navigation filters
* @return The code to uniquely identify this specific navigation filter, such as the name with a class name prefix
*/
String getCode();

43
app/src/main/java/org/transdroid/core/gui/navigation/NavigationHelper.java

@ -42,8 +42,8 @@ import de.keyboardsurfer.android.widget.crouton.Crouton; @@ -42,8 +42,8 @@ import de.keyboardsurfer.android.widget.crouton.Crouton;
import de.keyboardsurfer.android.widget.crouton.Style;
/**
* Helper for activities to make navigation-related decisions, such as when a device can display a larger, tablet style
* layout or how to display errors.
* Helper for activities to make navigation-related decisions, such as when a device can display a larger, tablet style layout or how to display
* errors.
* @author Eric Kok
*/
@SuppressLint("ResourceAsColor")
@ -53,13 +53,11 @@ public class NavigationHelper { @@ -53,13 +53,11 @@ public class NavigationHelper {
/**
* Use with {@link Crouton#showText(android.app.Activity, int, Style)} (and variants) to display error messages.
*/
public static Style CROUTON_ERROR_STYLE =
new Style.Builder().setBackgroundColor(R.color.crouton_error).setTextSize(13).build();
public static Style CROUTON_ERROR_STYLE = new Style.Builder().setBackgroundColor(R.color.crouton_error).setTextSize(13).build();
/**
* Use with {@link Crouton#showText(android.app.Activity, int, Style)} (and variants) to display info messages.
*/
public static Style CROUTON_INFO_STYLE =
new Style.Builder().setBackgroundColor(R.color.crouton_info).setTextSize(13).build();
public static Style CROUTON_INFO_STYLE = new Style.Builder().setBackgroundColor(R.color.crouton_info).setTextSize(13).build();
private static ImageLoader imageCache;
@RootContext
protected Context context;
@ -67,8 +65,8 @@ public class NavigationHelper { @@ -67,8 +65,8 @@ public class NavigationHelper {
/**
* Converts a string into a {@link Spannable} that displays the string in the Roboto Condensed font
* @param string A plain text {@link String}
* @return A {@link Spannable} that can be applied to supporting views (such as the action bar title) so that the
* input string will be displayed using the Roboto Condensed font (if the OS has this)
* @return A {@link Spannable} that can be applied to supporting views (such as the action bar title) so that the input string will be displayed
* using the Roboto Condensed font (if the OS has this)
*/
public static SpannableString buildCondensedFontString(String string) {
if (string == null) {
@ -136,8 +134,7 @@ public class NavigationHelper { @@ -136,8 +134,7 @@ public class NavigationHelper {
if (imageCache == null) {
imageCache = ImageLoader.getInstance();
try {
LruDiscCache diskCache =
new LruDiscCache(context.getCacheDir(), null, new Md5FileNameGenerator(), 640000, 25);
LruDiscCache diskCache = new LruDiscCache(context.getCacheDir(), null, new Md5FileNameGenerator(), 640000, 25);
// @formatter:off
Builder imageCacheBuilder = new Builder(context)
.defaultDisplayImageOptions(
@ -158,19 +155,16 @@ public class NavigationHelper { @@ -158,19 +155,16 @@ public class NavigationHelper {
}
/**
* Returns the application name (like Transdroid) and version name (like 1.5.0), appended by the version code (like
* 180).
* Returns the application name (like Transdroid) and version name (like 1.5.0), appended by the version code (like 180).
* @return The app name and version, such as 'Transdroid 1.5.0 (180)'
*/
public String getAppNameAndVersion() {
return context.getString(R.string.app_name) + " " + BuildConfig.VERSION_NAME + " (" +
Integer.toString(BuildConfig.VERSION_CODE) + ")";
return context.getString(R.string.app_name) + " " + BuildConfig.VERSION_NAME + " (" + Integer.toString(BuildConfig.VERSION_CODE) + ")";
}
/**
* Returns whether the device is considered small (i.e. a phone) rather than large (i.e. a tablet). Can, for
* example, be used to determine if a dialog should be shown full screen. Currently is true if the device's smallest
* dimension is 500 dip.
* Returns whether the device is considered small (i.e. a phone) rather than large (i.e. a tablet). Can, for example, be used to determine if a
* dialog should be shown full screen. Currently is true if the device's smallest dimension is 500 dip.
* @return True if the app runs on a small device, false otherwise
*/
public boolean isSmallScreen() {
@ -178,8 +172,8 @@ public class NavigationHelper { @@ -178,8 +172,8 @@ public class NavigationHelper {
}
/**
* Whether any search-related UI components should be shown in the interface. At the moment returns false only if we
* run as Transdroid Lite version.
* Whether any search-related UI components should be shown in the interface. At the moment returns false only if we run as Transdroid Lite
* version.
* @return True if search is enabled, false otherwise
*/
public boolean enableSearchUi() {
@ -187,8 +181,7 @@ public class NavigationHelper { @@ -187,8 +181,7 @@ public class NavigationHelper {
}
/**
* Whether any RSS-related UI components should be shown in the interface. At the moment returns false only if we
* run as Transdroid Lite version.
* Whether any RSS-related UI components should be shown in the interface. At the moment returns false only if we run as Transdroid Lite version.
* @return True if search is enabled, false otherwise
*/
public boolean enableRssUi() {
@ -196,8 +189,8 @@ public class NavigationHelper { @@ -196,8 +189,8 @@ public class NavigationHelper {
}
/**
* Returns whether any seedbox-related components should be shown in the interface; specifically the option to add
* server settings via easy seedbox-specific screens.
* Returns whether any seedbox-related components should be shown in the interface; specifically the option to add server settings via easy
* seedbox-specific screens.
* @return True if seedbox settings should be shown, false otherwise
*/
public boolean enableSeedboxes() {
@ -206,8 +199,8 @@ public class NavigationHelper { @@ -206,8 +199,8 @@ public class NavigationHelper {
/**
* Whether the custom app update checker should be used to check for new app and search module versions.
* @return True if it should be checked against transdroid.org if there are app updates (as opposed to using the
* Play Store for updates, for example), false otherwise
* @return True if it should be checked against transdroid.org if there are app updates (as opposed to using the Play Store for updates, for
* example), false otherwise
*/
public boolean enableUpdateChecker() {
return context.getResources().getBoolean(R.bool.updatecheck_available);

9
app/src/main/java/org/transdroid/core/gui/navigation/RefreshableActivity.java

@ -16,17 +16,16 @@ @@ -16,17 +16,16 @@
*/
package org.transdroid.core.gui.navigation;
import android.view.View;
import android.support.v4.widget.SwipeRefreshLayout;
/**
* Interface to be implemented by any activity that allows its content to be refreshed; fragments can ask for
* user-initiated refreshes.
* Interface to be implemented by any activity that allows its content to be refreshed; fragments can ask for user-initiated refreshes.
* @author Eric Kok
*/
public interface RefreshableActivity {
public void refreshScreen();
void refreshScreen();
public void addRefreshableView(View view);
void addSwipeRefreshLayout(SwipeRefreshLayout container);
}

23
app/src/main/java/org/transdroid/core/gui/rss/RssfeedLoader.java

@ -16,18 +16,18 @@ @@ -16,18 +16,18 @@
*/
package org.transdroid.core.gui.rss;
import org.transdroid.core.app.settings.RssfeedSetting;
import org.transdroid.core.rssparser.Channel;
import org.transdroid.core.rssparser.Item;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import org.transdroid.core.app.settings.RssfeedSetting;
import org.transdroid.core.rssparser.Channel;
import org.transdroid.core.rssparser.Item;
/**
* A container class that holds RSS feed settings and, after they have been retrieved, the contents as {@link Channel},
* the number of new items and an indication of a connection error.
* A container class that holds RSS feed settings and, after they have been retrieved, the contents as {@link Channel}, the number of new items and an
* indication of a connection error.
* @author Eric Kok
*/
public class RssfeedLoader {
@ -45,7 +45,7 @@ public class RssfeedLoader { @@ -45,7 +45,7 @@ public class RssfeedLoader {
this.channel = channel;
this.hasError = hasError;
if (channel == null || channel.getItems() == null || hasError) {
hasError = true;
this.hasError = true;
newCount = -1;
return;
}
@ -67,8 +67,7 @@ public class RssfeedLoader { @@ -67,8 +67,7 @@ public class RssfeedLoader {
}
});
for (Item item : items) {
if (item.getPubdate() == null || setting.getLastViewed() == null
|| item.getPubdate().after(setting.getLastViewed())) {
if (item.getPubdate() == null || setting.getLastViewed() == null || item.getPubdate().after(setting.getLastViewed())) {
newCount++;
item.setIsNew(true);
} else {
@ -79,12 +78,12 @@ public class RssfeedLoader { @@ -79,12 +78,12 @@ public class RssfeedLoader {
// Use the url of the last RSS item the last time the feed was viewed by the user to count new items
boolean isNew = true;
for (Item item : channel.getItems()) {
if (item.getTheLink() != null && setting.getLastViewedItemUrl() != null
&& item.getTheLink().equals(setting.getLastViewedItemUrl())) {
if (item.getTheLink() != null && setting.getLastViewedItemUrl() != null && item.getTheLink().equals(setting.getLastViewedItemUrl())) {
isNew = false;
}
if (isNew)
if (isNew) {
newCount++;
}
item.setIsNew(isNew);
}
}

30
app/src/main/java/org/transdroid/core/gui/rss/RssfeedView.java

@ -16,12 +16,6 @@ @@ -16,12 +16,6 @@
*/
package org.transdroid.core.gui.rss;
import org.androidannotations.annotations.Bean;
import org.androidannotations.annotations.EViewGroup;
import org.androidannotations.annotations.ViewById;
import org.transdroid.core.app.settings.RssfeedSetting;
import org.transdroid.core.gui.navigation.NavigationHelper;
import android.content.Context;
import android.view.View;
import android.widget.ImageView;
@ -29,19 +23,26 @@ import android.widget.LinearLayout; @@ -29,19 +23,26 @@ import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import org.androidannotations.annotations.Bean;
import org.androidannotations.annotations.EViewGroup;
import org.androidannotations.annotations.ViewById;
import org.transdroid.R;
import org.transdroid.core.app.settings.RssfeedSetting;
import org.transdroid.core.gui.navigation.NavigationHelper;
/**
* View that represents some {@link RssfeedSetting} object and displays name as well as loads a favicon for the feed's
* site and can load how many new items are available.
* View that represents some {@link RssfeedSetting} object and displays name as well as loads a favicon for the feed's site and can load how many new
* items are available.
* @author Eric Kok
*/
@EViewGroup(resName = "list_item_rssfeed")
@EViewGroup(R.layout.list_item_rssfeed)
public class RssfeedView extends LinearLayout {
private static final String GETFVO_URL = "http://g.etfv.co/%1$s";
@Bean
protected NavigationHelper navigationHelper;
// Views
@ViewById
protected ImageView faviconImage;
@ -61,18 +62,17 @@ public class RssfeedView extends LinearLayout { @@ -61,18 +62,17 @@ public class RssfeedView extends LinearLayout {
if (rssfeedLoader.hasError() || rssfeedLoader.getChannel() != null) {
loadingProgress.setVisibility(View.GONE);
newcountText.setVisibility(View.VISIBLE);
newcountText.setText(rssfeedLoader.hasError()? "?": Integer.toString(rssfeedLoader.getNewCount()));
newcountText.setText(rssfeedLoader.hasError() ? "?" : Integer.toString(rssfeedLoader.getNewCount()));
} else {
loadingProgress.setVisibility(View.VISIBLE);
newcountText.setVisibility(View.GONE);
}
// Clear and then asynchronously load the RSS feed site' favicon
// Uses the g.etfv.co service to resolve the favicon of any feed URL
faviconImage.setImageDrawable(null);
navigationHelper.getImageCache().displayImage(String.format(GETFVO_URL, rssfeedLoader.getSetting().getUrl()),
faviconImage);
navigationHelper.getImageCache().displayImage(String.format(GETFVO_URL, rssfeedLoader.getSetting().getUrl()), faviconImage);
}
}

57
app/src/main/java/org/transdroid/core/gui/rss/RssfeedsActivity.java

@ -16,9 +16,14 @@ @@ -16,9 +16,14 @@
*/
package org.transdroid.core.gui.rss;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import android.annotation.TargetApi;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import org.androidannotations.annotations.AfterViews;
import org.androidannotations.annotations.Background;
@ -29,24 +34,22 @@ import org.androidannotations.annotations.OptionsItem; @@ -29,24 +34,22 @@ import org.androidannotations.annotations.OptionsItem;
import org.androidannotations.annotations.UiThread;
import org.androidannotations.annotations.ViewById;
import org.transdroid.R;
import org.transdroid.core.app.settings.*;
import org.transdroid.core.gui.*;
import org.transdroid.core.app.settings.ApplicationSettings;
import org.transdroid.core.app.settings.RssfeedSetting;
import org.transdroid.core.app.settings.SystemSettings_;
import org.transdroid.core.gui.TorrentsActivity_;
import org.transdroid.core.gui.log.Log;
import org.transdroid.core.gui.navigation.NavigationHelper;
import org.transdroid.core.rssparser.Channel;
import org.transdroid.core.rssparser.RssParser;
import android.annotation.TargetApi;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import de.keyboardsurfer.android.widget.crouton.Crouton;
@EActivity(resName = "activity_rssfeeds")
@EActivity(R.layout.activity_rssfeeds)
public class RssfeedsActivity extends ActionBarActivity {
// Settings and local data
@ -57,9 +60,9 @@ public class RssfeedsActivity extends ActionBarActivity { @@ -57,9 +60,9 @@ public class RssfeedsActivity extends ActionBarActivity {
protected List<RssfeedLoader> loaders;
// Contained feeds and items fragments
@FragmentById(resName = "rssfeeds_fragment")
@FragmentById(R.id.rssfeeds_fragment)
protected RssfeedsFragment fragmentFeeds;
@FragmentById(resName = "rssitems_fragment")
@FragmentById(R.id.rssitems_fragment)
protected RssitemsFragment fragmentItems;
@ViewById
protected Toolbar rssfeedsToolbar;
@ -96,7 +99,7 @@ public class RssfeedsActivity extends ActionBarActivity { @@ -96,7 +99,7 @@ public class RssfeedsActivity extends ActionBarActivity {
* Reload the RSS feed settings and start loading all the feeds. To be called from contained fragments.
*/
public void refreshFeeds() {
loaders = new ArrayList<RssfeedLoader>();
loaders = new ArrayList<>();
// For each RSS feed setting the user created, start a loader that retrieved the RSS feed (via a background
// thread) and, on success, determines the new items in the feed
for (RssfeedSetting setting : applicationSettings.getRssfeedSettings()) {
@ -127,8 +130,7 @@ public class RssfeedsActivity extends ActionBarActivity { @@ -127,8 +130,7 @@ public class RssfeedsActivity extends ActionBarActivity {
}
/**
* Stores the retrieved RSS feed content channel into the loader and updates the RSS feed in the feeds list
* fragment.
* Stores the retrieved RSS feed content channel into the loader and updates the RSS feed in the feeds list fragment.
* @param loader The RSS feed loader that was executed
* @param channel The data that was retrieved, or null if it could not be parsed
* @param hasError True if a connection error occurred in the loading of the feed; false otherwise
@ -140,12 +142,10 @@ public class RssfeedsActivity extends ActionBarActivity { @@ -140,12 +142,10 @@ public class RssfeedsActivity extends ActionBarActivity {
}
/**
* Opens an RSS feed in the dedicated fragment (if there was space in the UI) or a new {@link RssitemsActivity}.
* Optionally this also registers in the user preferences that the feed was now viewed, so that in the future the
* new items can be properly marked.
* Opens an RSS feed in the dedicated fragment (if there was space in the UI) or a new {@link RssitemsActivity}. Optionally this also registers in
* the user preferences that the feed was now viewed, so that in the future the new items can be properly marked.
* @param loader The RSS feed loader (with settings and the loaded content channel) to show
* @param markAsViewedNow True if the user settings should be updated to reflect this feed's last viewed date; false
* otherwise
* @param markAsViewedNow True if the user settings should be updated to reflect this feed's last viewed date; false otherwise
*/
public void openRssfeed(RssfeedLoader loader, boolean markAsViewedNow) {
@ -156,8 +156,9 @@ public class RssfeedsActivity extends ActionBarActivity { @@ -156,8 +156,9 @@ public class RssfeedsActivity extends ActionBarActivity {
// be loaded until the RSS feeds screen in opened again.
if (!loader.hasError() && loader.getChannel() != null && markAsViewedNow) {
String lastViewedItemUrl = null;
if (loader.getChannel().getItems() != null && loader.getChannel().getItems().size() > 0)
if (loader.getChannel().getItems() != null && loader.getChannel().getItems().size() > 0) {
lastViewedItemUrl = loader.getChannel().getItems().get(0).getTheLink();
}
applicationSettings.setRssfeedLastViewer(loader.getSetting().getOrder(), new Date(), lastViewedItemUrl);
}
fragmentItems.update(loader.getChannel(), loader.hasError());
@ -178,14 +179,16 @@ public class RssfeedsActivity extends ActionBarActivity { @@ -178,14 +179,16 @@ public class RssfeedsActivity extends ActionBarActivity {
// be loaded until the RSS feeds screen in opened again
if (markAsViewedNow) {
String lastViewedItemUrl = null;
if (loader.getChannel().getItems() != null && loader.getChannel().getItems().size() > 0)
if (loader.getChannel().getItems() != null && loader.getChannel().getItems().size() > 0) {
lastViewedItemUrl = loader.getChannel().getItems().get(0).getTheLink();
}
applicationSettings.setRssfeedLastViewer(loader.getSetting().getOrder(), new Date(), lastViewedItemUrl);
}
String name = loader.getChannel().getTitle();
if (TextUtils.isEmpty(name))
if (TextUtils.isEmpty(name)) {
name = loader.getSetting().getName();
}
if (TextUtils.isEmpty(name) && !TextUtils.isEmpty(loader.getSetting().getUrl())) {
name = Uri.parse(loader.getSetting().getUrl()).getHost();
}

24
app/src/main/java/org/transdroid/core/gui/rss/RssfeedsAdapter.java

@ -16,16 +16,16 @@ @@ -16,16 +16,16 @@
*/
package org.transdroid.core.gui.rss;
import java.util.List;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import org.androidannotations.annotations.EBean;
import org.androidannotations.annotations.RootContext;
import org.transdroid.core.app.settings.RssfeedSetting;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import java.util.List;
/**
* Adapter that contains a list of {@link RssfeedSetting}s, each with associated loaded RSS feed {@link org.transdroid.core.rssparser.Channel}.
@ -33,9 +33,9 @@ import android.widget.BaseAdapter; @@ -33,9 +33,9 @@ import android.widget.BaseAdapter;
*/
@EBean
public class RssfeedsAdapter extends BaseAdapter {
private List<RssfeedLoader> loaders = null;
@RootContext
protected Context context;
@ -47,23 +47,25 @@ public class RssfeedsAdapter extends BaseAdapter { @@ -47,23 +47,25 @@ public class RssfeedsAdapter extends BaseAdapter {
this.loaders = loaders;
notifyDataSetChanged();
}
@Override
public boolean hasStableIds() {
return true;
}
@Override
public int getCount() {
if (loaders == null)
if (loaders == null) {
return 0;
}
return loaders.size();
}
@Override
public RssfeedLoader getItem(int position) {
if (loaders == null)
if (loaders == null) {
return null;
}
return loaders.get(position);
}

46
app/src/main/java/org/transdroid/core/gui/rss/RssfeedsFragment.java

@ -16,7 +16,12 @@ @@ -16,7 +16,12 @@
*/
package org.transdroid.core.gui.rss;
import java.util.List;
import android.app.Fragment;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ListView;
import android.widget.TextView;
import org.androidannotations.annotations.AfterViews;
import org.androidannotations.annotations.Bean;
@ -26,25 +31,20 @@ import org.androidannotations.annotations.OptionsItem; @@ -26,25 +31,20 @@ import org.androidannotations.annotations.OptionsItem;
import org.androidannotations.annotations.OptionsMenu;
import org.androidannotations.annotations.ViewById;
import org.transdroid.R;
import org.transdroid.core.gui.settings.*;
import org.transdroid.core.gui.settings.MainSettingsActivity_;
import android.app.Fragment;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ListView;
import android.widget.TextView;
import java.util.List;
/**
* Fragment lists the RSS feeds the user wants to monitor and, if room, the list of items in a feed in a right pane.
* @author Eric Kok
*/
@EFragment(resName = "fragment_rssfeeds")
@OptionsMenu(resName = "fragment_rssfeeds")
@EFragment(R.layout.fragment_rssfeeds)
@OptionsMenu(R.menu.fragment_rssfeeds)
public class RssfeedsFragment extends Fragment {
// Views
@ViewById(resName = "rssfeeds_list")
@ViewById(R.id.rssfeeds_list)
protected ListView feedsList;
@Bean
protected RssfeedsAdapter rssfeedsAdapter;
@ -59,39 +59,39 @@ public class RssfeedsFragment extends Fragment { @@ -59,39 +59,39 @@ public class RssfeedsFragment extends Fragment {
public void update(List<RssfeedLoader> loaders) {
rssfeedsAdapter.update(loaders);
boolean hasSettings = !(loaders == null || loaders.size() == 0);
feedsList.setVisibility(hasSettings ? View.VISIBLE: View.GONE);
nosettingsText.setVisibility(hasSettings ? View.GONE: View.VISIBLE);
feedsList.setVisibility(hasSettings ? View.VISIBLE : View.GONE);
nosettingsText.setVisibility(hasSettings ? View.GONE : View.VISIBLE);
getActivity().invalidateOptionsMenu();
}
@Override
public void onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
menu.findItem(R.id.action_settings).setShowAsAction(
rssfeedsAdapter == null || rssfeedsAdapter.getCount() == 0 ? MenuItem.SHOW_AS_ACTION_ALWAYS
: MenuItem.SHOW_AS_ACTION_NEVER);
boolean hasFeeds = rssfeedsAdapter != null && rssfeedsAdapter.getCount() > 0;
menu.findItem(R.id.action_refresh).setShowAsAction(hasFeeds ? MenuItem.SHOW_AS_ACTION_ALWAYS : MenuItem.SHOW_AS_ACTION_NEVER);
menu.findItem(R.id.action_settings).setShowAsAction(!hasFeeds ? MenuItem.SHOW_AS_ACTION_ALWAYS : MenuItem.SHOW_AS_ACTION_NEVER);
}
@OptionsItem(resName = "action_settings")
@OptionsItem(R.id.action_settings)
protected void openSettings() {
MainSettingsActivity_.intent(getActivity()).start();
}
@OptionsItem(resName = "action_refresh")
@OptionsItem(R.id.action_refresh)
protected void refreshScreen() {
((RssfeedsActivity)getActivity()).refreshFeeds();
((RssfeedsActivity) getActivity()).refreshFeeds();
}
@ItemClick(resName = "rssfeeds_list")
@ItemClick(R.id.rssfeeds_list)
protected void onFeedClicked(RssfeedLoader loader) {
((RssfeedsActivity)getActivity()).openRssfeed(loader, true);
((RssfeedsActivity) getActivity()).openRssfeed(loader, true);
}
/**
* Notifies the contained list of RSS feeds that the underlying data has been changed.
*/
public void notifyDataSetChanged() {
rssfeedsAdapter.notifyDataSetChanged();
}
}

4
app/src/main/java/org/transdroid/core/gui/rss/RssitemStatusLayout.java

@ -26,8 +26,8 @@ import android.widget.RelativeLayout; @@ -26,8 +26,8 @@ import android.widget.RelativeLayout;
import org.transdroid.R;
/**
* A relative layout that that is checkable (to be used in a contextual action bar) and shows a coloured bar in the far
* left indicating the view status, that is, if the item is new to the user or was viewed earlier.
* A relative layout that that is checkable (to be used in a contextual action bar) and shows a coloured bar in the far left indicating the view
* status, that is, if the item is new to the user or was viewed earlier.
* @author Eric Kok
*/
public class RssitemStatusLayout extends RelativeLayout {

17
app/src/main/java/org/transdroid/core/gui/rss/RssitemView.java

@ -16,19 +16,20 @@ @@ -16,19 +16,20 @@
*/
package org.transdroid.core.gui.rss;
import org.androidannotations.annotations.EViewGroup;
import org.androidannotations.annotations.ViewById;
import org.transdroid.core.rssparser.Item;
import android.content.Context;
import android.text.format.DateUtils;
import android.widget.TextView;
import org.androidannotations.annotations.EViewGroup;
import org.androidannotations.annotations.ViewById;
import org.transdroid.R;
import org.transdroid.core.rssparser.Item;
/**
* View that represents some {@link Item} object, which is a single item in some RSS feed.
* @author Eric Kok
*/
@EViewGroup(resName = "list_item_rssitem")
@EViewGroup(R.layout.list_item_rssitem)
public class RssitemView extends RssitemStatusLayout {
// Views
@ -42,9 +43,9 @@ public class RssitemView extends RssitemStatusLayout { @@ -42,9 +43,9 @@ public class RssitemView extends RssitemStatusLayout {
public void bind(Item rssitem) {
nameText.setText(rssitem.getTitle());
dateText.setText(rssitem.getPubdate() == null ? "" : DateUtils.getRelativeDateTimeString(getContext(), rssitem
.getPubdate().getTime(), DateUtils.SECOND_IN_MILLIS, DateUtils.WEEK_IN_MILLIS,
DateUtils.FORMAT_ABBREV_MONTH));
dateText.setText(rssitem.getPubdate() == null ? "" : DateUtils
.getRelativeDateTimeString(getContext(), rssitem.getPubdate().getTime(), DateUtils.SECOND_IN_MILLIS, DateUtils.WEEK_IN_MILLIS,
DateUtils.FORMAT_ABBREV_MONTH));
setIsNew(rssitem.isNew());
}

23
app/src/main/java/org/transdroid/core/gui/rss/RssitemsActivity.java

@ -16,6 +16,13 @@ @@ -16,6 +16,13 @@
*/
package org.transdroid.core.gui.rss;
import android.annotation.TargetApi;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.widget.Toolbar;
import org.androidannotations.annotations.AfterViews;
import org.androidannotations.annotations.EActivity;
import org.androidannotations.annotations.Extra;
@ -23,20 +30,12 @@ import org.androidannotations.annotations.FragmentById; @@ -23,20 +30,12 @@ import org.androidannotations.annotations.FragmentById;
import org.androidannotations.annotations.OptionsItem;
import org.androidannotations.annotations.ViewById;
import org.transdroid.R;
import org.transdroid.core.app.settings.*;
import org.transdroid.core.gui.*;
import org.transdroid.core.app.settings.SystemSettings_;
import org.transdroid.core.gui.TorrentsActivity_;
import org.transdroid.core.gui.navigation.NavigationHelper;
import org.transdroid.core.rssparser.Channel;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.widget.Toolbar;
@EActivity(resName = "activity_rssitems")
@EActivity(R.layout.activity_rssitems)
public class RssitemsActivity extends ActionBarActivity {
@Extra
@ -44,7 +43,7 @@ public class RssitemsActivity extends ActionBarActivity { @@ -44,7 +43,7 @@ public class RssitemsActivity extends ActionBarActivity {
@Extra
protected String rssfeedName;
@FragmentById(resName = "rssitems_fragment")
@FragmentById(R.id.rssitems_fragment)
protected RssitemsFragment fragmentItems;
@ViewById
protected Toolbar rssfeedsToolbar;

22
app/src/main/java/org/transdroid/core/gui/rss/RssitemsAdapter.java

@ -16,16 +16,16 @@ @@ -16,16 +16,16 @@
*/
package org.transdroid.core.gui.rss;
import org.androidannotations.annotations.EBean;
import org.androidannotations.annotations.RootContext;
import org.transdroid.core.rssparser.Channel;
import org.transdroid.core.rssparser.Item;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import org.androidannotations.annotations.EBean;
import org.androidannotations.annotations.RootContext;
import org.transdroid.core.rssparser.Channel;
import org.transdroid.core.rssparser.Item;
/**
* Adapter that contains a list of {@link Item}s in an RSS feed.
* @author Eric Kok
@ -34,7 +34,7 @@ import android.widget.BaseAdapter; @@ -34,7 +34,7 @@ import android.widget.BaseAdapter;
public class RssitemsAdapter extends BaseAdapter {
private Channel rssfeed = null;
@RootContext
protected Context context;
@ -46,23 +46,25 @@ public class RssitemsAdapter extends BaseAdapter { @@ -46,23 +46,25 @@ public class RssitemsAdapter extends BaseAdapter {
this.rssfeed = rssfeed;
notifyDataSetChanged();
}
@Override
public boolean hasStableIds() {
return true;
}
@Override
public int getCount() {
if (rssfeed == null)
if (rssfeed == null) {
return 0;
}
return rssfeed.getItems().size();
}
@Override
public Item getItem(int position) {
if (rssfeed == null)
if (rssfeed == null) {
return null;
}
return rssfeed.getItems().get(position);
}

21
app/src/main/java/org/transdroid/core/gui/rss/RssitemsFragment.java

@ -44,10 +44,10 @@ import org.androidannotations.annotations.InstanceState; @@ -44,10 +44,10 @@ import org.androidannotations.annotations.InstanceState;
import org.androidannotations.annotations.ItemClick;
import org.androidannotations.annotations.ViewById;
import org.transdroid.R;
import org.transdroid.core.gui.*;
import org.transdroid.core.gui.TorrentsActivity_;
import org.transdroid.core.gui.navigation.NavigationHelper;
import org.transdroid.core.gui.navigation.SelectionManagerMode;
import org.transdroid.core.gui.search.*;
import org.transdroid.core.gui.search.SearchActivity_;
import org.transdroid.core.rssparser.Channel;
import org.transdroid.core.rssparser.Item;
@ -60,7 +60,7 @@ import de.keyboardsurfer.android.widget.crouton.Crouton; @@ -60,7 +60,7 @@ import de.keyboardsurfer.android.widget.crouton.Crouton;
* Fragment that lists the items in a specific RSS feed
* @author Eric Kok
*/
@EFragment(resName = "fragment_rssitems")
@EFragment(R.layout.fragment_rssitems)
public class RssitemsFragment extends Fragment {
@InstanceState
@ -69,7 +69,7 @@ public class RssitemsFragment extends Fragment { @@ -69,7 +69,7 @@ public class RssitemsFragment extends Fragment {
protected boolean hasError = false;
// Views
@ViewById(resName = "rssitems_list")
@ViewById(R.id.rssitems_list)
protected ListView rssitemsList;
private MultiChoiceModeListener onItemsSelected = new MultiChoiceModeListener() {
@ -92,7 +92,7 @@ public class RssitemsFragment extends Fragment { @@ -92,7 +92,7 @@ public class RssitemsFragment extends Fragment {
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
// Get checked torrents
List<Item> checked = new ArrayList<Item>();
List<Item> checked = new ArrayList<>();
for (int i = 0; i < rssitemsList.getCheckedItemPositions().size(); i++) {
if (rssitemsList.getCheckedItemPositions().valueAt(i)) {
checked.add(rssitemsAdapter.getItem(rssitemsList.getCheckedItemPositions().keyAt(i)));
@ -126,8 +126,7 @@ public class RssitemsFragment extends Fragment { @@ -126,8 +126,7 @@ public class RssitemsFragment extends Fragment {
}
names.append(checked.get(f).getTitle());
}
ClipboardManager clipboardManager =
(ClipboardManager) getActivity().getSystemService(Context.CLIPBOARD_SERVICE);
ClipboardManager clipboardManager = (ClipboardManager) getActivity().getSystemService(Context.CLIPBOARD_SERVICE);
clipboardManager.setPrimaryClip(ClipData.newPlainText("Transdroid", names.toString()));
mode.finish();
return true;
@ -146,13 +145,10 @@ public class RssitemsFragment extends Fragment { @@ -146,13 +145,10 @@ public class RssitemsFragment extends Fragment {
return new AlertDialog.Builder(getActivity()).setMessage(first.getDescription())
.setPositiveButton(R.string.action_close, null).create();
}
;
}.show(getFragmentManager(), "RssItemDescription");
} else if (itemId == R.id.action_openwebsite) {
// Open the browser to show the website contained in the item's link tag
Toast.makeText(getActivity(), getString(R.string.search_openingdetails, first.getTitle()),
Toast.LENGTH_LONG).show();
Toast.makeText(getActivity(), getString(R.string.search_openingdetails, first.getTitle()), Toast.LENGTH_LONG).show();
if (!TextUtils.isEmpty(first.getLink())) {
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(first.getLink())));
} else {
@ -201,8 +197,7 @@ public class RssitemsFragment extends Fragment { @@ -201,8 +197,7 @@ public class RssitemsFragment extends Fragment {
/**
* Update the shown RSS items in the list.
* @param channel The loaded RSS content channel object
* @param hasError True if there were errors in loading the channel, in which case an error text is shown; false
* otherwise
* @param hasError True if there were errors in loading the channel, in which case an error text is shown; false otherwise
*/
public void update(Channel channel, boolean hasError) {
rssitemsAdapter.update(channel);

3
app/src/main/java/org/transdroid/core/gui/search/BarcodeHelper.java

@ -106,6 +106,9 @@ public class BarcodeHelper { @@ -106,6 +106,9 @@ public class BarcodeHelper {
* can be constructed for it
*/
public static String handleScanResult(int resultCode, Intent data, boolean supportsSearch) {
if (data == null || !data.hasExtra("SCAN_RESULT")) {
return null;
}
String contents = data.getStringExtra("SCAN_RESULT");
String formatName = data.getStringExtra("SCAN_RESULT_FORMAT");
if (formatName != null && formatName.equals("QR_CODE")) {

32
app/src/main/java/org/transdroid/core/gui/search/SearchActivity.java

@ -45,23 +45,24 @@ import org.androidannotations.annotations.ViewById; @@ -45,23 +45,24 @@ import org.androidannotations.annotations.ViewById;
import org.transdroid.R;
import org.transdroid.core.app.search.SearchHelper;
import org.transdroid.core.app.search.SearchSite;
import org.transdroid.core.app.settings.*;
import org.transdroid.core.gui.*;
import org.transdroid.core.app.settings.ApplicationSettings;
import org.transdroid.core.app.settings.SystemSettings_;
import org.transdroid.core.app.settings.WebsearchSetting;
import org.transdroid.core.gui.TorrentsActivity_;
import org.transdroid.core.gui.navigation.NavigationHelper;
import java.util.List;
/**
* An activity that shows search results to the user (after a query was supplied by the standard Android search manager)
* and either shows the list of search sites on the left (e.g. on tablets) or allows switching between search sites via
* the action bar spinner.
* An activity that shows search results to the user (after a query was supplied by the standard Android search manager) and either shows the list of
* search sites on the left (e.g. on tablets) or allows switching between search sites via the action bar spinner.
* @author Eric Kok
*/
@EActivity(resName = "activity_search")
@OptionsMenu(resName = "activity_search")
@EActivity(R.layout.activity_search)
@OptionsMenu(R.menu.activity_search)
public class SearchActivity extends ActionBarActivity implements ActionBar.OnNavigationListener {
@FragmentById(resName = "searchresults_fragment")
@FragmentById(R.id.searchresults_fragment)
protected SearchResultsFragment fragmentResults;
@ViewById
protected ListView searchsitesList;
@ -76,8 +77,7 @@ public class SearchActivity extends ActionBarActivity implements ActionBar.OnNav @@ -76,8 +77,7 @@ public class SearchActivity extends ActionBarActivity implements ActionBar.OnNav
@SystemService
protected SearchManager searchManager;
private MenuItem searchMenu = null;
private SearchRecentSuggestions suggestions =
new SearchRecentSuggestions(this, SearchHistoryProvider.AUTHORITY, SearchHistoryProvider.MODE);
private SearchRecentSuggestions suggestions = new SearchRecentSuggestions(this, SearchHistoryProvider.AUTHORITY, SearchHistoryProvider.MODE);
private List<SearchSetting> searchSites;
private SearchSetting lastUsedSite;
@ -96,7 +96,6 @@ public class SearchActivity extends ActionBarActivity implements ActionBar.OnNav @@ -96,7 +96,6 @@ public class SearchActivity extends ActionBarActivity implements ActionBar.OnNav
// Set the theme according to the user preference
if (SystemSettings_.getInstance_(this).useDarkTheme()) {
setTheme(R.style.TransdroidTheme_Dark);
getSupportActionBar().setIcon(R.drawable.ic_activity_torrents);
}
super.onCreate(savedInstanceState);
}
@ -252,7 +251,7 @@ public class SearchActivity extends ActionBarActivity implements ActionBar.OnNav @@ -252,7 +251,7 @@ public class SearchActivity extends ActionBarActivity implements ActionBar.OnNav
}
@OptionsItem(resName = "action_refresh")
@OptionsItem(R.id.action_refresh)
protected void refreshSearch() {
if (searchMenu != null) {
@ -264,8 +263,7 @@ public class SearchActivity extends ActionBarActivity implements ActionBar.OnNav @@ -264,8 +263,7 @@ public class SearchActivity extends ActionBarActivity implements ActionBar.OnNav
// Start a browser page directly to the requested search results
WebsearchSetting websearch = (WebsearchSetting) lastUsedSite;
startActivity(
new Intent(Intent.ACTION_VIEW, Uri.parse(websearch.getBaseUrl().replace("%s", lastUsedQuery))));
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(websearch.getBaseUrl().replace("%s", lastUsedQuery))));
finish();
} else if (lastUsedSite instanceof SearchSite) {
@ -273,15 +271,15 @@ public class SearchActivity extends ActionBarActivity implements ActionBar.OnNav @@ -273,15 +271,15 @@ public class SearchActivity extends ActionBarActivity implements ActionBar.OnNav
// Save the search site currently used to search for future usage
applicationSettings.setLastUsedSearchSite(lastUsedSite);
// Update the activity title (only shown on large devices)
getSupportActionBar().setTitle(NavigationHelper.buildCondensedFontString(
getString(R.string.search_queryonsite, lastUsedQuery, lastUsedSite.getName())));
getSupportActionBar().setTitle(
NavigationHelper.buildCondensedFontString(getString(R.string.search_queryonsite, lastUsedQuery, lastUsedSite.getName())));
// Ask the results fragment to start a search for the specified query
fragmentResults.startSearch(lastUsedQuery, (SearchSite) lastUsedSite);
}
}
@OptionsItem(resName = "action_downloadsearch")
@OptionsItem(R.id.action_downloadsearch)
protected void downloadSearchModule() {
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.transdroid.org/latest-search")));
}

18
app/src/main/java/org/transdroid/core/gui/search/SearchResultsAdapter.java

@ -16,16 +16,16 @@ @@ -16,16 +16,16 @@
*/
package org.transdroid.core.gui.search;
import java.util.List;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import org.androidannotations.annotations.EBean;
import org.androidannotations.annotations.RootContext;
import org.transdroid.core.app.search.SearchResult;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import java.util.List;
/**
* Adapter that contains a list of {@link SearchResult}s.
@ -41,7 +41,7 @@ public class SearchResultsAdapter extends BaseAdapter { @@ -41,7 +41,7 @@ public class SearchResultsAdapter extends BaseAdapter {
/**
* Allows updating the search results, replacing the old data
* @param newRssfeeds The new list of search results
* @param results The new list of search results
*/
public void update(List<SearchResult> results) {
this.results = results;
@ -55,15 +55,17 @@ public class SearchResultsAdapter extends BaseAdapter { @@ -55,15 +55,17 @@ public class SearchResultsAdapter extends BaseAdapter {
@Override
public int getCount() {
if (results == null)
if (results == null) {
return 0;
}
return results.size();
}
@Override
public SearchResult getItem(int position) {
if (results == null)
if (results == null) {
return null;
}
return results.get(position);
}

158
app/src/main/java/org/transdroid/core/gui/search/SearchResultsFragment.java

@ -42,9 +42,11 @@ import org.transdroid.core.app.search.SearchHelper; @@ -42,9 +42,11 @@ import org.transdroid.core.app.search.SearchHelper;
import org.transdroid.core.app.search.SearchHelper.SearchSortOrder;
import org.transdroid.core.app.search.SearchResult;
import org.transdroid.core.app.search.SearchSite;
import org.transdroid.core.app.settings.*;
import org.transdroid.core.gui.*;
import org.transdroid.core.gui.navigation.*;
import org.transdroid.core.app.settings.SystemSettings_;
import org.transdroid.core.gui.TorrentsActivity_;
import org.transdroid.core.gui.navigation.NavigationHelper;
import org.transdroid.core.gui.navigation.NavigationHelper_;
import org.transdroid.core.gui.navigation.SelectionManagerMode;
import java.util.ArrayList;
import java.util.List;
@ -55,7 +57,7 @@ import de.keyboardsurfer.android.widget.crouton.Crouton; @@ -55,7 +57,7 @@ import de.keyboardsurfer.android.widget.crouton.Crouton;
* Fragment that lists the items in a specific RSS feed
* @author Eric Kok
*/
@EFragment(resName = "fragment_searchresults")
@EFragment(R.layout.fragment_searchresults)
public class SearchResultsFragment extends Fragment {
@InstanceState
@ -66,80 +68,8 @@ public class SearchResultsFragment extends Fragment { @@ -66,80 +68,8 @@ public class SearchResultsFragment extends Fragment {
protected SearchHelper searchHelper;
// Views
@ViewById(resName = "searchresults_list")
@ViewById(R.id.searchresults_list)
protected ListView resultsList;
private MultiChoiceModeListener onItemsSelected = new MultiChoiceModeListener() {
SelectionManagerMode selectionManagerMode;
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
// Show contextual action bar to add items in batch mode
mode.getMenuInflater().inflate(R.menu.fragment_searchresults_cab, menu);
selectionManagerMode = new SelectionManagerMode(resultsList, R.plurals.search_resutlsselected);
selectionManagerMode.onCreateActionMode(mode, menu);
return true;
}
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return selectionManagerMode.onPrepareActionMode(mode, menu);
}
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
// Get checked torrents
List<SearchResult> checked = new ArrayList<SearchResult>();
for (int i = 0; i < resultsList.getCheckedItemPositions().size(); i++) {
if (resultsList.getCheckedItemPositions().valueAt(i)) {
checked.add(resultsAdapter.getItem(resultsList.getCheckedItemPositions().keyAt(i)));
}
}
int itemId = item.getItemId();
if (itemId == R.id.action_addall) {
// Start an Intent that adds multiple items at once, by supplying the urls and titles as string array
// extras and setting the Intent action to ADD_MULTIPLE
Intent intent = new Intent("org.transdroid.ADD_MULTIPLE");
String[] urls = new String[checked.size()];
String[] titles = new String[checked.size()];
for (int i = 0; i < checked.size(); i++) {
urls[i] = checked.get(i).getTorrentUrl();
titles[i] = checked.get(i).getName();
}
intent.putExtra("TORRENT_URLS", urls);
intent.putExtra("TORRENT_TITLES", titles);
if (resultsSource != null) {
intent.putExtra("PRIVATE_SOURCE", resultsSource);
}
startActivity(intent);
mode.finish();
return true;
} else if (itemId == R.id.action_showdetails) {
SearchResult first = checked.get(0);
// Open the torrent's web page in the browser
if (checked.size() > 1) {
Toast.makeText(getActivity(), getString(R.string.search_openingdetails, first.getName()),
Toast.LENGTH_LONG).show();
}
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(first.getDetailsUrl())));
return true;
} else {
return false;
}
}
@Override
public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) {
selectionManagerMode.onItemCheckedStateChanged(mode, position, id, checked);
}
@Override
public void onDestroyActionMode(ActionMode mode) {
selectionManagerMode.onDestroyActionMode(mode);
}
};
@Bean
protected SearchResultsAdapter resultsAdapter;
@ViewById
@ -196,7 +126,7 @@ public class SearchResultsFragment extends Fragment { @@ -196,7 +126,7 @@ public class SearchResultsFragment extends Fragment {
emptyText.setVisibility(View.GONE);
}
@ItemClick(resName = "searchresults_list")
@ItemClick(R.id.searchresults_list)
protected void onItemClicked(SearchResult item) {
if (item.getTorrentUrl() == null) {
Crouton.showText(getActivity(), R.string.error_notorrentfile, NavigationHelper.CROUTON_ERROR_STYLE);
@ -212,4 +142,76 @@ public class SearchResultsFragment extends Fragment { @@ -212,4 +142,76 @@ public class SearchResultsFragment extends Fragment {
startActivity(i);
}
private MultiChoiceModeListener onItemsSelected = new MultiChoiceModeListener() {
SelectionManagerMode selectionManagerMode;
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
// Show contextual action bar to add items in batch mode
mode.getMenuInflater().inflate(R.menu.fragment_searchresults_cab, menu);
selectionManagerMode = new SelectionManagerMode(resultsList, R.plurals.search_resutlsselected);
selectionManagerMode.onCreateActionMode(mode, menu);
return true;
}
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return selectionManagerMode.onPrepareActionMode(mode, menu);
}
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
// Get checked torrents
List<SearchResult> checked = new ArrayList<SearchResult>();
for (int i = 0; i < resultsList.getCheckedItemPositions().size(); i++) {
if (resultsList.getCheckedItemPositions().valueAt(i)) {
checked.add(resultsAdapter.getItem(resultsList.getCheckedItemPositions().keyAt(i)));
}
}
int itemId = item.getItemId();
if (itemId == R.id.action_addall) {
// Start an Intent that adds multiple items at once, by supplying the urls and titles as string array
// extras and setting the Intent action to ADD_MULTIPLE
Intent intent = new Intent("org.transdroid.ADD_MULTIPLE");
String[] urls = new String[checked.size()];
String[] titles = new String[checked.size()];
for (int i = 0; i < checked.size(); i++) {
urls[i] = checked.get(i).getTorrentUrl();
titles[i] = checked.get(i).getName();
}
intent.putExtra("TORRENT_URLS", urls);
intent.putExtra("TORRENT_TITLES", titles);
if (resultsSource != null) {
intent.putExtra("PRIVATE_SOURCE", resultsSource);
}
startActivity(intent);
mode.finish();
return true;
} else if (itemId == R.id.action_showdetails) {
SearchResult first = checked.get(0);
// Open the torrent's web page in the browser
if (checked.size() > 1) {
Toast.makeText(getActivity(), getString(R.string.search_openingdetails, first.getName()), Toast.LENGTH_LONG).show();
}
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(first.getDetailsUrl())));
return true;
} else {
return false;
}
}
@Override
public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) {
selectionManagerMode.onItemCheckedStateChanged(mode, position, id, checked);
}
@Override
public void onDestroyActionMode(ActionMode mode) {
selectionManagerMode.onDestroyActionMode(mode);
}
};
}

2
app/src/main/java/org/transdroid/core/gui/search/SearchSetting.java

@ -25,7 +25,7 @@ public interface SearchSetting extends SimpleListItem { @@ -25,7 +25,7 @@ public interface SearchSetting extends SimpleListItem {
* @return A unique string identifying this search setting
*/
public String getKey();
/**
* Should return an URL (which may still be abstract and not the actual search URL) specific to the search site
* @return A clean URL directing to the search site, to, for example, get the favicon of the site

9
app/src/main/java/org/transdroid/core/gui/search/SearchSettingSelectionView.java

@ -16,18 +16,19 @@ @@ -16,18 +16,19 @@
*/
package org.transdroid.core.gui.search;
import org.androidannotations.annotations.EViewGroup;
import org.androidannotations.annotations.ViewById;
import android.content.Context;
import android.widget.FrameLayout;
import android.widget.TextView;
import org.androidannotations.annotations.EViewGroup;
import org.androidannotations.annotations.ViewById;
import org.transdroid.R;
/**
* View that shows, as part of the action bar spinner, which {@link SearchSetting} is currently chosen.
* @author Eric Kok
*/
@EViewGroup(resName = "actionbar_searchsite")
@EViewGroup(R.layout.actionbar_searchsite)
public class SearchSettingSelectionView extends FrameLayout {
@ViewById

11
app/src/main/java/org/transdroid/core/gui/search/SearchSettingsDropDownAdapter.java

@ -16,18 +16,17 @@ @@ -16,18 +16,17 @@
*/
package org.transdroid.core.gui.search;
import java.util.List;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import org.transdroid.core.gui.lists.SimpleListItem;
import org.transdroid.core.gui.navigation.FilterListItemAdapter;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import java.util.List;
/**
* List adapter that holds search settings, that is, web searches and in-app search sites, displayed as content to a
* Spinner instead of a ListView.
* List adapter that holds search settings, that is, web searches and in-app search sites, displayed as content to a Spinner instead of a ListView.
* @author Eric Kok
*/
public class SearchSettingsDropDownAdapter extends FilterListItemAdapter {

20
app/src/main/java/org/transdroid/core/gui/search/SearchSiteView.java

@ -16,23 +16,24 @@ @@ -16,23 +16,24 @@
*/
package org.transdroid.core.gui.search;
import android.content.Context;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import org.androidannotations.annotations.Bean;
import org.androidannotations.annotations.EViewGroup;
import org.androidannotations.annotations.ViewById;
import org.transdroid.R;
import org.transdroid.core.app.settings.RssfeedSetting;
import org.transdroid.core.gui.navigation.NavigationHelper;
import android.content.Context;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
/**
* View that represents some {@link RssfeedSetting} object and displays name as well as loads a favicon for the feed's
* site and can load how many new items are available.
* View that represents some {@link RssfeedSetting} object and displays name as well as loads a favicon for the feed's site and can load how many new
* items are available.
* @author Eric Kok
*/
@EViewGroup(resName = "list_item_searchsite")
@EViewGroup(R.layout.list_item_searchsite)
public class SearchSiteView extends LinearLayout {
private static final String GETFVO_URL = "http://g.etfv.co/%1$s";
@ -57,8 +58,7 @@ public class SearchSiteView extends LinearLayout { @@ -57,8 +58,7 @@ public class SearchSiteView extends LinearLayout {
// Clear and then asynchronously load the site's favicon
// Uses the g.etfv.co service to resolve the favicon of any URL
faviconImage.setImageDrawable(null);
navigationHelper.getImageCache().displayImage(String.format(GETFVO_URL, rssfeedLoader.getBaseUrl()),
faviconImage);
navigationHelper.getImageCache().displayImage(String.format(GETFVO_URL, rssfeedLoader.getBaseUrl()), faviconImage);
}

24
app/src/main/java/org/transdroid/core/gui/search/SearchSitesAdapter.java

@ -16,17 +16,17 @@ @@ -16,17 +16,17 @@
*/
package org.transdroid.core.gui.search;
import java.util.List;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import org.androidannotations.annotations.EBean;
import org.androidannotations.annotations.RootContext;
import org.transdroid.core.app.search.SearchSite;
import org.transdroid.core.app.settings.WebsearchSetting;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import java.util.List;
/**
* Adapter that contains a list of {@link SearchSetting}s, either {@link SearchSite} or {@link WebsearchSetting}.
@ -34,9 +34,9 @@ import android.widget.BaseAdapter; @@ -34,9 +34,9 @@ import android.widget.BaseAdapter;
*/
@EBean
public class SearchSitesAdapter extends BaseAdapter {
private List<SearchSetting> sites = null;
@RootContext
protected Context context;
@ -48,23 +48,25 @@ public class SearchSitesAdapter extends BaseAdapter { @@ -48,23 +48,25 @@ public class SearchSitesAdapter extends BaseAdapter {
this.sites = sites;
notifyDataSetChanged();
}
@Override
public boolean hasStableIds() {
return true;
}
@Override
public int getCount() {
if (sites == null)
if (sites == null) {
return 0;
}
return sites.size();
}
@Override
public SearchSetting getItem(int position) {
if (sites == null)
if (sites == null) {
return null;
}
return sites.get(position);
}

60
app/src/main/java/org/transdroid/core/gui/search/UrlEntryDialog.java

@ -16,9 +16,6 @@ @@ -16,9 +16,6 @@
*/
package org.transdroid.core.gui.search;
import org.transdroid.core.gui.TorrentsActivity;
import org.transdroid.core.gui.navigation.NavigationHelper;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.AlertDialog;
@ -34,11 +31,14 @@ import android.text.TextUtils; @@ -34,11 +31,14 @@ import android.text.TextUtils;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import org.transdroid.core.gui.TorrentsActivity;
import org.transdroid.core.gui.navigation.NavigationHelper;
public class UrlEntryDialog {
/**
* Opens a dialog that allows entry of a single URL string, which (on confirmation) will be supplied to the calling
* activity's {@link TorrentsActivity#addTorrentByUrl(String, String) method}.
* Opens a dialog that allows entry of a single URL string, which (on confirmation) will be supplied to the calling activity's {@link
* TorrentsActivity#addTorrentByUrl(String, String) method}.
* @param activity The activity that opens (and owns) this dialog
*/
@SuppressLint("ValidFragment")
@ -48,34 +48,32 @@ public class UrlEntryDialog { @@ -48,34 +48,32 @@ public class UrlEntryDialog {
public android.app.Dialog onCreateDialog(android.os.Bundle savedInstanceState) {
final EditText urlInput = new EditText(activity);
urlInput.setInputType(InputType.TYPE_TEXT_VARIATION_URI);
if (android.os.Build.VERSION.SDK_INT >= 11) {
ClipboardManager clipboard = (ClipboardManager) activity
.getSystemService(Context.CLIPBOARD_SERVICE);
if (clipboard.hasPrimaryClip() && clipboard.getPrimaryClip().getItemCount() > 0) {
CharSequence content = clipboard.getPrimaryClip().getItemAt(0).coerceToText(activity);
urlInput.setText(content);
}
ClipboardManager clipboard = (ClipboardManager) activity.getSystemService(Context.CLIPBOARD_SERVICE);
if (clipboard.hasPrimaryClip() && clipboard.getPrimaryClip().getItemCount() > 0) {
CharSequence content = clipboard.getPrimaryClip().getItemAt(0).coerceToText(activity);
urlInput.setText(content);
}
((InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE)).toggleSoftInput(
InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY);
return new AlertDialog.Builder(activity).setView(urlInput)
.setPositiveButton(android.R.string.ok, new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// Assume text entry box input as URL and treat the filename (after the last /) as title
String url = urlInput.getText().toString();
Uri uri = Uri.parse(url);
if (activity != null && !TextUtils.isEmpty(url)) {
String title = NavigationHelper.extractNameFromUri(uri);
if (uri.getScheme() != null && uri.getScheme().equals("magnet")) {
activity.addTorrentByMagnetUrl(url, title);
} else {
activity.addTorrentByUrl(url, title);
}
}
((InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE))
.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY);
return new AlertDialog.Builder(activity).setView(urlInput).setPositiveButton(android.R.string.ok, new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// Assume text entry box input as URL and treat the filename (after the last /) as title
String url = urlInput.getText().toString();
Uri uri = Uri.parse(url);
if (!TextUtils.isEmpty(url)) {
String title = NavigationHelper.extractNameFromUri(uri);
if (uri.getScheme() != null && uri.getScheme().equals("magnet")) {
activity.addTorrentByMagnetUrl(url, title);
} else {
activity.addTorrentByUrl(url, title);
}
}).setNegativeButton(android.R.string.cancel, null).create();
};
}
}
}).setNegativeButton(android.R.string.cancel, null).create();
}
;
}.show(activity.getFragmentManager(), "urlentry");
}

BIN
app/src/main/res/drawable-hdpi/ic_action_add.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 223 B

BIN
app/src/main/res/drawable-hdpi/ic_action_discard_dark.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

BIN
app/src/main/res/drawable-hdpi/ic_action_discard_light.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

BIN
app/src/main/res/drawable-hdpi/ic_action_done.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 309 B

BIN
app/src/main/res/drawable-hdpi/ic_action_done_dark.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

BIN
app/src/main/res/drawable-hdpi/ic_action_done_light.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

BIN
app/src/main/res/drawable-hdpi/ic_action_drawer.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 B

BIN
app/src/main/res/drawable-hdpi/ic_action_filter_dark.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 580 B

BIN
app/src/main/res/drawable-hdpi/ic_action_filter_light.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 678 B

BIN
app/src/main/res/drawable-hdpi/ic_action_force_recheck.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 221 B

BIN
app/src/main/res/drawable-hdpi/ic_action_forcerecheck_dark.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 556 B

BIN
app/src/main/res/drawable-hdpi/ic_action_forcerecheck_light.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 652 B

BIN
app/src/main/res/drawable-hdpi/ic_action_info.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 608 B

BIN
app/src/main/res/drawable-hdpi/ic_action_info_dark.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 911 B

BIN
app/src/main/res/drawable-hdpi/ic_action_info_light.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 994 B

BIN
app/src/main/res/drawable-hdpi/ic_action_labels.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 377 B

BIN
app/src/main/res/drawable-hdpi/ic_action_labels_dark.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

BIN
app/src/main/res/drawable-hdpi/ic_action_labels_light.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

BIN
app/src/main/res/drawable-hdpi/ic_action_pause.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 B

BIN
app/src/main/res/drawable-hdpi/ic_action_pause_dark.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

BIN
app/src/main/res/drawable-hdpi/ic_action_pause_light.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

BIN
app/src/main/res/drawable-hdpi/ic_action_priority_high.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 653 B

BIN
app/src/main/res/drawable-hdpi/ic_action_priority_high_dark.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 750 B

BIN
app/src/main/res/drawable-hdpi/ic_action_priority_high_light.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 867 B

BIN
app/src/main/res/drawable-hdpi/ic_action_priority_low.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 772 B

BIN
app/src/main/res/drawable-hdpi/ic_action_priority_low_dark.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 892 B

BIN
app/src/main/res/drawable-hdpi/ic_action_priority_low_light.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

BIN
app/src/main/res/drawable-hdpi/ic_action_priority_medium.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 713 B

BIN
app/src/main/res/drawable-hdpi/ic_action_priority_normal_dark.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 842 B

BIN
app/src/main/res/drawable-hdpi/ic_action_priority_normal_light.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 961 B

BIN
app/src/main/res/drawable-hdpi/ic_action_priority_off.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 800 B

BIN
app/src/main/res/drawable-hdpi/ic_action_priority_off_dark.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 912 B

BIN
app/src/main/res/drawable-hdpi/ic_action_priority_off_light.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

BIN
app/src/main/res/drawable-hdpi/ic_action_refresh.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 531 B

BIN
app/src/main/res/drawable-hdpi/ic_action_refresh_dark.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

BIN
app/src/main/res/drawable-hdpi/ic_action_refresh_light.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

BIN
app/src/main/res/drawable-hdpi/ic_action_remove.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 246 B

BIN
app/src/main/res/drawable-hdpi/ic_action_remove_dark.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

BIN
app/src/main/res/drawable-hdpi/ic_action_remove_light.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

BIN
app/src/main/res/drawable-hdpi/ic_action_resume.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 360 B

BIN
app/src/main/res/drawable-hdpi/ic_action_resume_dark.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

BIN
app/src/main/res/drawable-hdpi/ic_action_resume_light.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

BIN
app/src/main/res/drawable-hdpi/ic_action_rss.png.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 759 B

BIN
app/src/main/res/drawable-hdpi/ic_action_rss_dark.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 956 B

BIN
app/src/main/res/drawable-hdpi/ic_action_rss_light.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

BIN
app/src/main/res/drawable-hdpi/ic_action_save.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 341 B

BIN
app/src/main/res/drawable-hdpi/ic_action_save_dark.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 394 B

BIN
app/src/main/res/drawable-hdpi/ic_action_save_light.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 398 B

BIN
app/src/main/res/drawable-hdpi/ic_action_sort.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 B

BIN
app/src/main/res/drawable-hdpi/ic_action_sort_by_size_dark.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

BIN
app/src/main/res/drawable-hdpi/ic_action_sort_by_size_light.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

BIN
app/src/main/res/drawable-hdpi/ic_action_start.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 282 B

BIN
app/src/main/res/drawable-hdpi/ic_action_start_dark.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

BIN
app/src/main/res/drawable-hdpi/ic_action_start_light.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

BIN
app/src/main/res/drawable-hdpi/ic_action_stop.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 B

BIN
app/src/main/res/drawable-hdpi/ic_action_stop_dark.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

BIN
app/src/main/res/drawable-hdpi/ic_action_stop_light.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save