Browse Source

Merge pull request #313 from twig/remote_rss

Add ability to manage RSS on server
pull/406/head
Eric Kok 8 years ago committed by GitHub
parent
commit
1eef19e148
  1. 2
      app/build.gradle
  2. 6
      app/src/main/AndroidManifest.xml
  3. 21
      app/src/main/java/org/transdroid/core/gui/TorrentsActivity.java
  4. 206
      app/src/main/java/org/transdroid/core/gui/remoterss/RemoteRssActivity.java
  5. 175
      app/src/main/java/org/transdroid/core/gui/remoterss/RemoteRssFragment.java
  6. 53
      app/src/main/java/org/transdroid/core/gui/remoterss/RemoteRssItemView.java
  7. 57
      app/src/main/java/org/transdroid/core/gui/remoterss/RemoteRssItemsAdapter.java
  8. 45
      app/src/main/java/org/transdroid/core/gui/remoterss/data/RemoteRssChannel.java
  9. 51
      app/src/main/java/org/transdroid/core/gui/remoterss/data/RemoteRssItem.java
  10. 12
      app/src/main/java/org/transdroid/core/gui/remoterss/data/RemoteRssSupplier.java
  11. 3
      app/src/main/java/org/transdroid/daemon/Daemon.java
  12. 42
      app/src/main/java/org/transdroid/daemon/Utorrent/UtorrentAdapter.java
  13. 75
      app/src/main/java/org/transdroid/daemon/Utorrent/data/UTorrentRemoteRssChannel.java
  14. 67
      app/src/main/java/org/transdroid/daemon/Utorrent/data/UTorrentRemoteRssItem.java
  15. 9
      app/src/main/res/drawable/ic_cloud_download.xml
  16. 79
      app/src/main/res/layout/activity_remoterss.xml
  17. 39
      app/src/main/res/layout/fragment_remoterss.xml
  18. 59
      app/src/main/res/layout/list_item_remoterssitem.xml
  19. 5
      app/src/main/res/menu/activity_torrents_main.xml
  20. 7
      app/src/main/res/values/strings.xml

2
app/build.gradle

@ -2,7 +2,7 @@ apply plugin: 'com.android.application'
apply plugin: 'android-apt' apply plugin: 'android-apt'
android { android {
compileSdkVersion 25 compileSdkVersion 23
buildToolsVersion '25.0.2' buildToolsVersion '25.0.2'
useLibrary 'org.apache.http.legacy' useLibrary 'org.apache.http.legacy'

6
app/src/main/AndroidManifest.xml

@ -239,6 +239,10 @@
android:name="org.transdroid.core.gui.rss.RssitemsActivity_" android:name="org.transdroid.core.gui.rss.RssitemsActivity_"
android:label="@string/rss_feeds" android:label="@string/rss_feeds"
android:theme="@style/TransdroidTheme" /> android:theme="@style/TransdroidTheme" />
<activity
android:name=".core.gui.remoterss.RemoteRssActivity_"
android:label="Remote RSS feeds"
android:theme="@style/TransdroidTheme" />
<!-- Background services --> <!-- Background services -->
<service android:name="org.transdroid.core.service.ServerCheckerService_" /> <service android:name="org.transdroid.core.service.ServerCheckerService_" />
@ -293,4 +297,4 @@
</receiver> </receiver>
</application> </application>
</manifest> </manifest>

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

@ -83,6 +83,9 @@ import org.transdroid.core.gui.navigation.NavigationFilter;
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.RefreshableActivity;
import org.transdroid.core.gui.navigation.StatusType; import org.transdroid.core.gui.navigation.StatusType;
import org.transdroid.core.gui.remoterss.RemoteRssActivity_;
import org.transdroid.core.gui.remoterss.data.RemoteRssChannel;
import org.transdroid.core.gui.remoterss.data.RemoteRssSupplier;
import org.transdroid.core.gui.rss.RssfeedsActivity_; import org.transdroid.core.gui.rss.RssfeedsActivity_;
import org.transdroid.core.gui.search.BarcodeHelper; import org.transdroid.core.gui.search.BarcodeHelper;
import org.transdroid.core.gui.search.FilePickerHelper; import org.transdroid.core.gui.search.FilePickerHelper;
@ -468,6 +471,7 @@ public class TorrentsActivity extends AppCompatActivity implements TorrentTasksE
filterSearch.setVisibility(View.GONE); filterSearch.setVisibility(View.GONE);
torrentsToolbar.getMenu().findItem(R.id.action_search).setVisible(false); torrentsToolbar.getMenu().findItem(R.id.action_search).setVisible(false);
torrentsToolbar.getMenu().findItem(R.id.action_rss).setVisible(false); torrentsToolbar.getMenu().findItem(R.id.action_rss).setVisible(false);
torrentsToolbar.getMenu().findItem(R.id.action_remoterss).setVisible(false);
torrentsToolbar.getMenu().findItem(R.id.action_settings).setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); torrentsToolbar.getMenu().findItem(R.id.action_settings).setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
torrentsToolbar.getMenu().findItem(R.id.action_help).setVisible(true); torrentsToolbar.getMenu().findItem(R.id.action_help).setVisible(true);
actionsToolbar.getMenu().findItem(R.id.action_enableturtle).setVisible(false); actionsToolbar.getMenu().findItem(R.id.action_enableturtle).setVisible(false);
@ -491,10 +495,12 @@ public class TorrentsActivity extends AppCompatActivity implements TorrentTasksE
filtersList.setVisibility(View.VISIBLE); filtersList.setVisibility(View.VISIBLE);
filterSearch.setVisibility(View.VISIBLE); filterSearch.setVisibility(View.VISIBLE);
boolean addByFile = Daemon.supportsAddByFile(currentConnection.getType()); boolean addByFile = Daemon.supportsAddByFile(currentConnection.getType());
boolean hasRemoteRss = Daemon.supportsRemoteRssManagement(currentConnection.getType());
addmenuFileButton.setVisibility(addByFile ? View.VISIBLE : View.GONE); addmenuFileButton.setVisibility(addByFile ? View.VISIBLE : View.GONE);
// Primary toolbar menu // Primary toolbar menu
torrentsToolbar.getMenu().findItem(R.id.action_search).setVisible(navigationHelper.enableSearchUi()); 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_rss).setVisible(navigationHelper.enableRssUi());
torrentsToolbar.getMenu().findItem(R.id.action_remoterss).setVisible(hasRemoteRss);
torrentsToolbar.getMenu().findItem(R.id.action_settings).setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); torrentsToolbar.getMenu().findItem(R.id.action_settings).setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
torrentsToolbar.getMenu().findItem(R.id.action_help).setVisible(false); torrentsToolbar.getMenu().findItem(R.id.action_help).setVisible(false);
// Secondary toolbar menu // Secondary toolbar menu
@ -847,6 +853,21 @@ public class TorrentsActivity extends AppCompatActivity implements TorrentTasksE
MainSettingsActivity_.intent(this).start(); MainSettingsActivity_.intent(this).start();
} }
@OptionsItem(R.id.action_remoterss)
protected void openRemoteRss() {
ArrayList<RemoteRssChannel> rssFeedItems = ((RemoteRssSupplier) (currentConnection)).getRemoteRssChannels();
if (rssFeedItems.size() == 0) {
return;
}
// Passing the items over as a feed can overload the Intent size limit and crash without a stack trace!
RemoteRssActivity_.intent(this)
// .feeds(rssFeedItems)
.start()
;
}
@OptionsItem(R.id.action_help) @OptionsItem(R.id.action_help)
protected void openHelp() { protected void openHelp() {
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.transdroid.org/download/"))); startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.transdroid.org/download/")));

206
app/src/main/java/org/transdroid/core/gui/remoterss/RemoteRssActivity.java

@ -0,0 +1,206 @@
/*
* 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.remoterss;
import android.annotation.TargetApi;
import android.os.Build;
import android.os.Bundle;
import android.os.Parcel;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.widget.LinearLayout;
import android.widget.ListView;
import org.androidannotations.annotations.AfterViews;
import org.androidannotations.annotations.Bean;
import org.androidannotations.annotations.EActivity;
import org.androidannotations.annotations.FragmentById;
import org.androidannotations.annotations.InstanceState;
import org.androidannotations.annotations.ItemClick;
import org.androidannotations.annotations.OptionsItem;
import org.androidannotations.annotations.ViewById;
import org.transdroid.R;
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.SimpleListItemAdapter;
import org.transdroid.core.gui.remoterss.data.RemoteRssChannel;
import org.transdroid.core.gui.remoterss.data.RemoteRssItem;
import org.transdroid.core.gui.remoterss.data.RemoteRssSupplier;
import org.transdroid.core.service.ConnectivityHelper;
import org.transdroid.daemon.IDaemonAdapter;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
/**
* An activity that displays a list of {@link RemoteRssItem}s via an instance of {@link RemoteRssFragment}.
* The activity manages the drawer to filter items by the feed they came through.
*
* By default it displays the latest items within the last month.
*
* @author Twig Nguyen
*/
@EActivity(R.layout.activity_remoterss)
public class RemoteRssActivity extends AppCompatActivity {
// @Extra
@InstanceState
protected ArrayList<RemoteRssChannel> feeds;
@InstanceState
protected ArrayList<RemoteRssItem> recentItems;
// Server connection
@Bean
protected ApplicationSettings applicationSettings;
@Bean
protected ConnectivityHelper connectivityHelper;
private IDaemonAdapter currentConnection;
// Details view components
@ViewById
protected DrawerLayout drawerLayout;
@ViewById
protected LinearLayout drawerContainer;
@ViewById
protected Toolbar torrentsToolbar;
@ViewById
protected ListView drawerList;
@FragmentById(R.id.remoterss_fragment)
protected RemoteRssFragment fragmentRemoteRss;
@Override
public void onCreate(Bundle savedInstanceState) {
// Set the theme according to the user preference
if (SystemSettings_.getInstance_(this).useDarkTheme()) {
setTheme(R.style.TransdroidTheme_Dark);
}
super.onCreate(savedInstanceState);
}
@AfterViews
protected void init() {
// Simple action bar with up, torrent name as title and refresh button
torrentsToolbar.setNavigationIcon(R.drawable.ic_action_drawer);
setSupportActionBar(torrentsToolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
// Connect to the last used server
ServerSetting lastUsed = applicationSettings.getLastUsedServer();
currentConnection = lastUsed.createServerAdapter(connectivityHelper.getConnectedNetworkName(), this);
feeds = ((RemoteRssSupplier) (currentConnection)).getRemoteRssChannels();
// Fill in the filter list
showChannelFilters();
// Show all items
showRecentItems();
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
@OptionsItem(android.R.id.home)
protected void navigateUp() {
if (drawerLayout.isDrawerOpen(drawerContainer)) {
drawerLayout.closeDrawers();
} else {
drawerLayout.openDrawer(drawerContainer);
}
}
@Override
public void onBackPressed() {
if (drawerLayout.isDrawerOpen(drawerContainer)) {
drawerLayout.closeDrawers();
} else {
finish();
}
}
protected void showRecentItems() {
if (recentItems == null) {
recentItems = new ArrayList<>();
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.MONTH, -1);
Date oneMonthAgo = calendar.getTime();
for (RemoteRssChannel feed : feeds) {
for (RemoteRssItem item : feed.getItems()) {
if (item.getTimestamp().after(oneMonthAgo)) {
recentItems.add(item);
}
}
}
// Sort by -newest
Collections.sort(recentItems, new Comparator<RemoteRssItem>() {
@Override
public int compare(RemoteRssItem lhs, RemoteRssItem rhs) {
return rhs.getTimestamp().compareTo(lhs.getTimestamp());
}
});
}
fragmentRemoteRss.updateRemoteItems(recentItems);
RemoteRssChannel channel = (RemoteRssChannel) drawerList.getAdapter().getItem(0);
getSupportActionBar().setSubtitle(channel.getName());
}
protected void showChannelFilters() {
List<RemoteRssChannel> feedLabels = new ArrayList<>(feeds.size() +1);
feedLabels.add(new RemoteRssChannel() {
@Override
public String getName() {
return getString(R.string.remoterss_filter_allrecent);
}
@Override
public void writeToParcel(Parcel dest, int flags) {
}
});
feedLabels.addAll(feeds);
drawerList.setAdapter(new SimpleListItemAdapter(this, feedLabels));
}
@ItemClick(R.id.drawer_list)
protected void onFeedSelected(int position) {
if (position == 0) {
showRecentItems();
}
else {
fragmentRemoteRss.updateRemoteItems(feeds.get(position -1).getItems());
}
RemoteRssChannel channel = (RemoteRssChannel) drawerList.getAdapter().getItem(position);
getSupportActionBar().setSubtitle(channel.getName());
drawerLayout.closeDrawers();
}
public IDaemonAdapter getCurrentConnection() {
return currentConnection;
}
}

175
app/src/main/java/org/transdroid/core/gui/remoterss/RemoteRssFragment.java

@ -0,0 +1,175 @@
/*
* 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.remoterss;
import android.app.Fragment;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.ActionMenuView;
import android.view.View;
import android.widget.ListView;
import android.widget.TextView;
import com.nispok.snackbar.Snackbar;
import com.nispok.snackbar.SnackbarManager;
import com.nispok.snackbar.enums.SnackbarType;
import org.androidannotations.annotations.AfterViews;
import org.androidannotations.annotations.Background;
import org.androidannotations.annotations.Bean;
import org.androidannotations.annotations.EFragment;
import org.androidannotations.annotations.InstanceState;
import org.androidannotations.annotations.ItemClick;
import org.androidannotations.annotations.UiThread;
import org.androidannotations.annotations.ViewById;
import org.transdroid.R;
import org.transdroid.core.gui.lists.LocalTorrent;
import org.transdroid.core.gui.log.Log;
import org.transdroid.core.gui.remoterss.data.RemoteRssItem;
import org.transdroid.daemon.Daemon;
import org.transdroid.daemon.IDaemonAdapter;
import org.transdroid.daemon.task.AddByMagnetUrlTask;
import org.transdroid.daemon.task.AddByUrlTask;
import org.transdroid.daemon.task.DaemonTaskFailureResult;
import org.transdroid.daemon.task.DaemonTaskResult;
import org.transdroid.daemon.task.DaemonTaskSuccessResult;
import java.util.ArrayList;
import java.util.List;
/**
* Fragment that shows a list of RSS items from the server and allows the user
* to download remotely, without having to set up RSS feeds on the Android device.
* @author Twig
*/
@EFragment(R.layout.fragment_remoterss)
public class RemoteRssFragment extends Fragment {
@Bean
protected Log log;
// Local data
@InstanceState
protected ArrayList<RemoteRssItem> remoteRssItems;
// Views
@ViewById
protected View detailsContainer;
@ViewById(R.id.contextual_menu)
protected ActionMenuView contextualMenu;
@ViewById
protected SwipeRefreshLayout swipeRefreshLayout;
@ViewById
protected ListView torrentsList;
@ViewById
protected TextView remoterssNoFilesMessage;
protected RemoteRssItemsAdapter adapter;
@AfterViews
protected void init() {
// Inject menu options in the actions toolbar
setHasOptionsMenu(true);
// // On large screens where this fragment is shown next to the torrents list, we show a continues grey vertical
// // line to separate the lists visually
// if (!NavigationHelper_.getInstance_(getActivity()).isSmallScreen()) {
// if (SystemSettings_.getInstance_(getActivity()).useDarkTheme()) {
// detailsContainer.setBackgroundResource(R.drawable.details_list_background_dark);
// } else {
// detailsContainer.setBackgroundResource(R.drawable.details_list_background_light);
// }
// }
// Set up details adapter
adapter = new RemoteRssItemsAdapter(getActivity());
torrentsList.setAdapter(adapter);
torrentsList.setFastScrollEnabled(true);
// Restore the fragment state (on orientation changes et al.)
if (remoteRssItems != null) {
updateRemoteItems(remoteRssItems);
}
}
/**
* Updates the UI with a new list of RSS items.
*/
public void updateRemoteItems(List<RemoteRssItem> remoteItems) {
remoteRssItems = new ArrayList<>(remoteItems);
adapter.updateItems(remoteRssItems);
torrentsList.smoothScrollToPosition(0);
// Show/hide a nice message if there are no items to show
remoterssNoFilesMessage.setVisibility(remoteRssItems.size() > 0 ? View.GONE : View.VISIBLE);
}
/**
* When the user clicks on an item, prepare to download it.
*/
@ItemClick(resName = "torrents_list")
protected void detailsListClicked(int position) {
RemoteRssItem item = (RemoteRssItem) adapter.getItem(position);
downloadRemoteRssItem(item);
}
/**
* Download the item in a background thread and display success/fail accordingly.
*/
@Background
protected void downloadRemoteRssItem(RemoteRssItem item) {
RemoteRssActivity activity = (RemoteRssActivity) getActivity();
IDaemonAdapter currentConnection = activity.getCurrentConnection();
DaemonTaskResult result;
if (item.isMagnetLink()) {
// Check if it's supported
if (!Daemon.supportsAddByMagnetUrl(currentConnection.getType())) {
onTaskFailed(getString(R.string.error_magnet_links_unsupported));
return;
}
AddByMagnetUrlTask addByMagnetUrlTask = AddByMagnetUrlTask.create(currentConnection, item.getLink());
result = addByMagnetUrlTask.execute(log);
}
else {
result = AddByUrlTask.create(currentConnection, item.getLink(), item.getTitle()).execute(log);
}
if (result instanceof DaemonTaskSuccessResult) {
onTaskSucceeded((DaemonTaskSuccessResult) result, getString(R.string.result_added, item.getTitle()));
} else if (result instanceof DaemonTaskFailureResult){
DaemonTaskFailureResult failure = ((DaemonTaskFailureResult) result);
String message = getString(LocalTorrent.getResourceForDaemonException(failure.getException()));
onTaskFailed(message);
}
}
@UiThread
protected void onTaskSucceeded(DaemonTaskSuccessResult result, String successMessage) {
SnackbarManager.show(Snackbar.with(getActivity()).text(successMessage));
}
@UiThread
protected void onTaskFailed(String message) {
SnackbarManager.show(Snackbar.with(getActivity())
.text(message)
.colorResource(R.color.red)
.type(SnackbarType.MULTI_LINE)
);
}
}

53
app/src/main/java/org/transdroid/core/gui/remoterss/RemoteRssItemView.java

@ -0,0 +1,53 @@
/*
* 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.remoterss;
import android.content.Context;
import android.text.format.DateFormat;
import android.widget.LinearLayout;
import android.widget.TextView;
import org.androidannotations.annotations.EViewGroup;
import org.androidannotations.annotations.ViewById;
import org.transdroid.R;
import org.transdroid.core.gui.remoterss.data.RemoteRssItem;
/**
* View that represents some {@link RemoteRssItem} object.
* @author Twig
*/
@EViewGroup(R.layout.list_item_remoterssitem)
public class RemoteRssItemView extends LinearLayout {
// Views
@ViewById
protected TextView nameText, dateText, labelText;
public RemoteRssItemView(Context context) {
super(context);
}
public void bind(RemoteRssItem item) {
labelText.setText(item.getSourceName());
nameText.setText(item.getName());
dateText.setText(
DateFormat.getDateFormat(getContext()).format(item.getTimestamp()) +
" " +
DateFormat.getTimeFormat(getContext()).format(item.getTimestamp())
);
}
}

57
app/src/main/java/org/transdroid/core/gui/remoterss/RemoteRssItemsAdapter.java

@ -0,0 +1,57 @@
package org.transdroid.core.gui.remoterss;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import org.transdroid.core.gui.remoterss.data.RemoteRssItem;
import java.util.ArrayList;
import java.util.List;
public class RemoteRssItemsAdapter extends BaseAdapter {
protected Context context;
protected List<RemoteRssItem> items;
public RemoteRssItemsAdapter(Context context) {
this.context = context;
items = new ArrayList<>();
}
@Override
public int getCount() {
return items.size();
}
@Override
public Object getItem(int position) {
return items.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
RemoteRssItemView itemView;
if (convertView == null) {
itemView = RemoteRssItemView_.build(context);
}
else {
itemView = (RemoteRssItemView) convertView;
}
itemView.bind((RemoteRssItem) getItem(position));
return itemView;
}
public void updateItems(List<RemoteRssItem> remoteItems) {
items = remoteItems;
notifyDataSetChanged();
}
}

45
app/src/main/java/org/transdroid/core/gui/remoterss/data/RemoteRssChannel.java

@ -0,0 +1,45 @@
package org.transdroid.core.gui.remoterss.data;
import android.os.Parcelable;
import org.transdroid.core.gui.lists.SimpleListItem;
import java.util.Date;
import java.util.List;
/**
* @author Twig
*/
public abstract class RemoteRssChannel implements Parcelable, SimpleListItem {
protected int id;
protected String name;
protected String link;
protected long lastUpdated;
protected List<RemoteRssItem> items;
@Override
public int describeContents() {
return 0;
}
public int getId() {
return id;
}
public String getLink() {
return link;
}
public Date getLastUpdated() {
return new Date(lastUpdated);
}
public List<RemoteRssItem> getItems() {
return items;
}
@Override
public String getName() {
return name;
}
}

51
app/src/main/java/org/transdroid/core/gui/remoterss/data/RemoteRssItem.java

@ -0,0 +1,51 @@
package org.transdroid.core.gui.remoterss.data;
import android.os.Parcelable;
import org.transdroid.core.gui.lists.SimpleListItem;
import java.util.Date;
/**
* @author Twig
*/
public abstract class RemoteRssItem implements Parcelable, SimpleListItem {
protected String title;
protected String link; // May be magnet or http(s)
protected String sourceName; // Name of RSS feed channel
protected Date timestamp;
@Override
public String getName() {
return title;
}
public String getTitle() {
return title;
}
public String getLink() {
return link;
}
public String getSourceName() {
return sourceName;
}
public void setSourceName(String sourceName) {
this.sourceName = sourceName;
}
public Date getTimestamp() {
return timestamp;
}
public boolean isMagnetLink() {
return link.startsWith("magnet:?");
}
@Override
public int describeContents() {
return 0;
}
}

12
app/src/main/java/org/transdroid/core/gui/remoterss/data/RemoteRssSupplier.java

@ -0,0 +1,12 @@
package org.transdroid.core.gui.remoterss.data;
import java.util.ArrayList;
/**
* Interface for daemon adapters if they support remote RSS management.
*
* @author Twig
*/
public interface RemoteRssSupplier {
ArrayList<RemoteRssChannel> getRemoteRssChannels();
}

3
app/src/main/java/org/transdroid/daemon/Daemon.java

@ -375,4 +375,7 @@ public enum Daemon {
return type == Deluge || type == Aria2; return type == Deluge || type == Aria2;
} }
public static boolean supportsRemoteRssManagement(Daemon type) {
return type == uTorrent;
}
} }

42
app/src/main/java/org/transdroid/daemon/Utorrent/UtorrentAdapter.java

@ -29,6 +29,8 @@ import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import org.transdroid.core.gui.log.Log; import org.transdroid.core.gui.log.Log;
import org.transdroid.core.gui.remoterss.data.RemoteRssChannel;
import org.transdroid.core.gui.remoterss.data.RemoteRssSupplier;
import org.transdroid.daemon.Daemon; import org.transdroid.daemon.Daemon;
import org.transdroid.daemon.DaemonException; import org.transdroid.daemon.DaemonException;
import org.transdroid.daemon.DaemonException.ExceptionType; import org.transdroid.daemon.DaemonException.ExceptionType;
@ -40,6 +42,7 @@ import org.transdroid.daemon.Torrent;
import org.transdroid.daemon.TorrentDetails; import org.transdroid.daemon.TorrentDetails;
import org.transdroid.daemon.TorrentFile; import org.transdroid.daemon.TorrentFile;
import org.transdroid.daemon.TorrentStatus; import org.transdroid.daemon.TorrentStatus;
import org.transdroid.daemon.Utorrent.data.UTorrentRemoteRssChannel;
import org.transdroid.daemon.task.AddByFileTask; import org.transdroid.daemon.task.AddByFileTask;
import org.transdroid.daemon.task.AddByMagnetUrlTask; import org.transdroid.daemon.task.AddByMagnetUrlTask;
import org.transdroid.daemon.task.AddByUrlTask; import org.transdroid.daemon.task.AddByUrlTask;
@ -69,6 +72,8 @@ import java.io.UnsupportedEncodingException;
import java.net.URI; import java.net.URI;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
@ -77,7 +82,7 @@ import java.util.List;
* HTTP GET requests and responses. * HTTP GET requests and responses.
* @author erickok * @author erickok
*/ */
public class UtorrentAdapter implements IDaemonAdapter { public class UtorrentAdapter implements IDaemonAdapter, RemoteRssSupplier {
private static final String LOG_NAME = "uTorrent daemon"; private static final String LOG_NAME = "uTorrent daemon";
private static final String RPC_URL_HASH = "&hash="; private static final String RPC_URL_HASH = "&hash=";
@ -113,6 +118,10 @@ public class UtorrentAdapter implements IDaemonAdapter {
private DaemonSettings settings; private DaemonSettings settings;
private DefaultHttpClient httpclient; private DefaultHttpClient httpclient;
private static ArrayList<RemoteRssChannel> remoteRssChannels = new ArrayList<>();
/** /**
* Initialises an adapter that provides operations to the uTorrent web daemon * Initialises an adapter that provides operations to the uTorrent web daemon
*/ */
@ -129,6 +138,11 @@ public class UtorrentAdapter implements IDaemonAdapter {
// Request all torrents from server // Request all torrents from server
JSONObject result = makeUtorrentRequest(log, "&list=1"); JSONObject result = makeUtorrentRequest(log, "&list=1");
if (result.has("rssfeeds")) {
parseJsonRemoteRssLists(result.getJSONArray("rssfeeds"));
}
return new RetrieveTaskSuccessResult((RetrieveTask) task, return new RetrieveTaskSuccessResult((RetrieveTask) task,
parseJsonRetrieveTorrents(result.getJSONArray("torrents")), parseJsonRetrieveTorrents(result.getJSONArray("torrents")),
parseJsonRetrieveGetLabels(result.getJSONArray("label"))); parseJsonRetrieveGetLabels(result.getJSONArray("label")));
@ -310,6 +324,29 @@ public class UtorrentAdapter implements IDaemonAdapter {
} }
} }
private void parseJsonRemoteRssLists(JSONArray results) {
remoteRssChannels = new ArrayList<>();
RemoteRssChannel item;
for (int i = 0; i < results.length(); i++) {
try {
item = new UTorrentRemoteRssChannel(results.getJSONArray(i));
remoteRssChannels.add(item);
} catch (JSONException e) {
// Ignore unparseable items so app doesn't crash.
// Haven't run into a case where this fails, yet.
e.printStackTrace();
}
}
Collections.sort(remoteRssChannels, new Comparator<RemoteRssChannel>() {
@Override
public int compare(RemoteRssChannel lhs, RemoteRssChannel rhs) {
return lhs.getName().compareToIgnoreCase(rhs.getName());
}
});
}
private ArrayList<Label> parseJsonRetrieveGetLabels(JSONArray lresults) throws JSONException { private ArrayList<Label> parseJsonRetrieveGetLabels(JSONArray lresults) throws JSONException {
// Parse response // Parse response
@ -620,4 +657,7 @@ public class UtorrentAdapter implements IDaemonAdapter {
return this.settings; return this.settings;
} }
public ArrayList<RemoteRssChannel> getRemoteRssChannels() {
return remoteRssChannels;
}
} }

75
app/src/main/java/org/transdroid/daemon/Utorrent/data/UTorrentRemoteRssChannel.java

@ -0,0 +1,75 @@
package org.transdroid.daemon.Utorrent.data;
import android.os.Parcel;
import android.os.Parcelable;
import org.json.JSONArray;
import org.json.JSONException;
import org.transdroid.core.gui.remoterss.data.RemoteRssChannel;
import org.transdroid.core.gui.remoterss.data.RemoteRssItem;
import java.util.ArrayList;
/**
* uTorrent implementation of RemoteRssChannel.
*
* @author Twig
*/
public class UTorrentRemoteRssChannel extends RemoteRssChannel {
public UTorrentRemoteRssChannel(JSONArray json) throws JSONException {
// boolean enabled = json.getBoolean(1);
boolean isCustomAlias = !json.getBoolean(2);
id = json.getInt(0);
link = json.getString(6);
lastUpdated = json.getLong(7);
if (isCustomAlias) {
name = link.split("\\|")[0];
link = link.split("\\|")[1];
}
else {
name = link;
}
items = new ArrayList<>();
JSONArray filesJson = json.getJSONArray(8);
RemoteRssItem file;
for (int i = 0; i < filesJson.length(); i++) {
file = new UTorrentRemoteRssItem(filesJson.getJSONArray(i));
file.setSourceName(name);
items.add(file);
}
}
public UTorrentRemoteRssChannel(Parcel in) {
id = in.readInt();
name = in.readString();
link = in.readString();
lastUpdated = in.readLong();
items = new ArrayList<>();
in.readList(items, UTorrentRemoteRssItem.class.getClassLoader());
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(id);
dest.writeString(name);
dest.writeString(link);
dest.writeLong(lastUpdated);
dest.writeList(items);
}
public static final Parcelable.Creator<UTorrentRemoteRssChannel> CREATOR = new Parcelable.Creator<UTorrentRemoteRssChannel>() {
public UTorrentRemoteRssChannel createFromParcel(Parcel in) {
return new UTorrentRemoteRssChannel(in);
}
public UTorrentRemoteRssChannel[] newArray(int size) {
return new UTorrentRemoteRssChannel[size];
}
};
}

67
app/src/main/java/org/transdroid/daemon/Utorrent/data/UTorrentRemoteRssItem.java

@ -0,0 +1,67 @@
package org.transdroid.daemon.Utorrent.data;
import android.os.Parcel;
import android.os.Parcelable;
import org.json.JSONArray;
import org.json.JSONException;
import org.transdroid.core.gui.remoterss.data.RemoteRssItem;
import java.util.Calendar;
import java.util.Date;
/**
* uTorrent implementation of RemoteRssItem.
*
* @author Twig
*/
public class UTorrentRemoteRssItem extends RemoteRssItem {
// public String name;
// public int season;
// public int episode;
public UTorrentRemoteRssItem(JSONArray json) throws JSONException {
// name = json.getString(0); // clean name
title = json.getString(1); // filename
link = json.getString(2);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(json.getLong(5) * 1000);
timestamp = calendar.getTime();
// season = json.getInt(6);
// episode = json.getInt(7);
}
public static final Parcelable.Creator<UTorrentRemoteRssItem> CREATOR = new Parcelable.Creator<UTorrentRemoteRssItem>() {
public UTorrentRemoteRssItem createFromParcel(Parcel in) {
return new UTorrentRemoteRssItem(in);
}
public UTorrentRemoteRssItem[] newArray(int size) {
return new UTorrentRemoteRssItem[size];
}
};
public UTorrentRemoteRssItem(Parcel in) {
// name = in.readString();
title = in.readString();
link = in.readString();
sourceName = in.readString();
timestamp = (Date) in.readSerializable();
// season = in.readInt();
// episode = in.readInt();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
// dest.writeString(name);
dest.writeString(title);
dest.writeString(link);
dest.writeString(sourceName);
dest.writeSerializable(timestamp);
// dest.writeInt(season);
// dest.writeInt(episode);
}
}

9
app/src/main/res/drawable/ic_cloud_download.xml

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M19.35,10.04C18.67,6.59 15.64,4 12,4 9.11,4 6.6,5.64 5.35,8.04 2.34,8.36 0,10.91 0,14c0,3.31 2.69,6 6,6h13c2.76,0 5,-2.24 5,-5 0,-2.64 -2.05,-4.78 -4.65,-4.96zM17,13l-5,5 -5,-5h3V9h4v4h3z"/>
</vector>

79
app/src/main/res/layout/activity_remoterss.xml

@ -0,0 +1,79 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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/>.
-->
<!-- This layout is for phones in portrait and shows the remote RSS items list with the filters as navigation drawer. -->
<android.support.v4.widget.DrawerLayout
android:id="@+id/drawer_layout"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".core.gui.remoterss.RemoteRssActivity_">
<!-- The main content view -->
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.Toolbar
android:id="@+id/torrents_toolbar"
style="@style/DefaultToolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize" />
<fragment
android:id="@+id/remoterss_fragment"
class="org.transdroid.core.gui.remoterss.RemoteRssFragment_"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/torrents_toolbar"
tools:layout="@layout/fragment_torrents" />
<View
style="@style/DefaultToolbarShadow"
android:layout_below="@id/torrents_toolbar" />
<View
style="@style/SplitToolbarShadow"
/>
</RelativeLayout>
<!-- The navigation drawer -->
<LinearLayout
android:id="@+id/drawer_container"
android:layout_width="@dimen/ui_filters_list"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="?attr/drawer_background"
android:orientation="vertical">
<ListView
android:id="@+id/drawer_list"
android:layout_width="@dimen/ui_filters_list"
android:layout_height="0dp"
android:layout_weight="1"
android:choiceMode="singleChoice"
android:divider="@null"
tools:listitem="@layout/list_item_filter" />
</LinearLayout>
</android.support.v4.widget.DrawerLayout>

39
app/src/main/res/layout/fragment_remoterss.xml

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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/>.
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="@string/remoterss_no_files"
android:gravity="center"
android:id="@+id/remoterss_no_files_message"/>
<ListView
android:id="@+id/torrents_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:choiceMode="multipleChoiceModal"
android:clipToPadding="false"
tools:listitem="@layout/list_item_remoterssitem"
tools:visibility="visible"/>
</FrameLayout>

59
app/src/main/res/layout/list_item_remoterssitem.xml

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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/>.
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="?attr/activatable_background"
android:paddingBottom="@dimen/margin_default"
android:paddingLeft="@dimen/margin_default"
android:paddingRight="@dimen/margin_default"
android:paddingTop="@dimen/margin_default">
<TextView
android:id="@+id/label_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dip"
android:textIsSelectable="false"
android:textSize="@dimen/text_small"
tools:text="Source channel name"/>
<TextView
android:id="@+id/name_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fontFamily="sans-serif-condensed"
android:textColor="?attr/text_bright"
android:textIsSelectable="false"
android:textSize="@dimen/text_enlarged"
tools:text="Title for torrent"
android:layout_below="@+id/label_text"/>
<TextView
android:id="@+id/date_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/name_text"
android:layout_marginTop="4dip"
android:textIsSelectable="false"
android:textSize="@dimen/text_small"
tools:text="25-12-2015"
/>
</RelativeLayout>

5
app/src/main/res/menu/activity_torrents_main.xml

@ -28,6 +28,11 @@
android:icon="@drawable/ic_action_rss" android:icon="@drawable/ic_action_rss"
android:title="@string/action_rss" android:title="@string/action_rss"
app:showAsAction="ifRoom" /> app:showAsAction="ifRoom" />
<item
android:id="@+id/action_remoterss"
android:icon="@drawable/ic_cloud_download"
android:title="@string/action_remoterss"
app:showAsAction="ifRoom" />
<item <item
android:id="@+id/action_help" android:id="@+id/action_help"
android:title="@string/action_help" android:title="@string/action_help"

7
app/src/main/res/values/strings.xml

@ -25,6 +25,7 @@
<string name="action_search">Search</string> <string name="action_search">Search</string>
<string name="action_refresh">Refresh</string> <string name="action_refresh">Refresh</string>
<string name="action_rss">RSS</string> <string name="action_rss">RSS</string>
<string name="action_remoterss">Remote RSS</string>
<string name="action_enableturtle">Enable turtle mode</string> <string name="action_enableturtle">Enable turtle mode</string>
<string name="action_disableturtle">Disable turtle mode</string> <string name="action_disableturtle">Disable turtle mode</string>
<string name="action_sort">Sort list</string> <string name="action_sort">Sort list</string>
@ -209,7 +210,10 @@
<item quantity="other">%1$s new RSS feed torrents</item> <item quantity="other">%1$s new RSS feed torrents</item>
</plurals> </plurals>
<string name="rss_service_newfor">New torrents for %1$s</string> <string name="rss_service_newfor">New torrents for %1$s</string>
<string name="remoterss_filter_allrecent">(All recent)</string>
<string name="remoterss_no_files">No torrent files found.\n\nAre your RSS feeds configured correctly?</string>
<string name="widget_loading">Loading&#8230;</string> <string name="widget_loading">Loading&#8230;</string>
<string name="widget_opentransdroid">Open Transdroid</string> <string name="widget_opentransdroid">Open Transdroid</string>
<string name="widget_filter">SERVER VIEW</string> <string name="widget_filter">SERVER VIEW</string>
@ -442,6 +446,7 @@
<string name="error_httperror">Error during communication; check your connection</string> <string name="error_httperror">Error during communication; check your connection</string>
<string name="error_unsupported">Your torrent client does not support this operation</string> <string name="error_unsupported">Your torrent client does not support this operation</string>
<string name="error_magnet_links_unsupported">Your torrent client does not support magnet links</string>
<string name="error_jsonrequesterror">Internal error building request</string> <string name="error_jsonrequesterror">Internal error building request</string>
<string name="error_jsonresponseerror">Error parsing server response (please check your settings)</string> <string name="error_jsonresponseerror">Error parsing server response (please check your settings)</string>
<string name="error_daemonnotconnected">Web interface not connected to a running daemon</string> <string name="error_daemonnotconnected">Web interface not connected to a running daemon</string>

Loading…
Cancel
Save