Manage your torrents from your Android device
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

296 lines
11 KiB

/*
* Copyright 2010-2018 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.widget;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.appwidget.AppWidgetManager;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.ListView;
import android.widget.Spinner;
import android.widget.TextView;
import org.androidannotations.annotations.AfterViews;
import org.androidannotations.annotations.Background;
import org.androidannotations.annotations.Bean;
import org.androidannotations.annotations.EActivity;
import org.androidannotations.annotations.ItemSelect;
import org.androidannotations.annotations.UiThread;
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.SimpleListItemSpinnerAdapter;
import org.transdroid.core.gui.lists.SortByListItem;
import org.transdroid.core.gui.log.Log;
import org.transdroid.core.gui.navigation.StatusType;
import org.transdroid.core.gui.navigation.StatusType.StatusTypeFilter;
import org.transdroid.core.service.ConnectivityHelper;
import org.transdroid.daemon.Daemon;
import org.transdroid.daemon.IDaemonAdapter;
import org.transdroid.daemon.Label;
import org.transdroid.daemon.Torrent;
import org.transdroid.daemon.TorrentsComparator;
import org.transdroid.daemon.TorrentsSortBy;
import org.transdroid.daemon.task.DaemonTaskResult;
import org.transdroid.daemon.task.RetrieveTask;
import org.transdroid.daemon.task.RetrieveTaskSuccessResult;
import org.transdroid.daemon.util.FileSizeConverter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
@EActivity(resName = "activity_widgetconfig")
public class ListWidgetConfigActivity extends AppCompatActivity {
// Views and adapters
@ViewById
protected Spinner serverSpinner, filterSpinner, sortSpinner;
@ViewById
protected CheckBox reverseorderCheckBox, showstatusCheckBox;
@ViewById
protected TextView filterText, serverText, errorText;
@ViewById
protected TextView downcountText, upcountText, downcountSign, upcountSign, downspeedText, upspeedText;
@ViewById
protected ListView torrentsList;
@ViewById
protected View navigationView, serverstatusView;
// Settings and helpers
@Bean
protected Log log;
@Bean
protected ConnectivityHelper connectivityHelper;
@Bean
protected ApplicationSettings applicationSettings;
@Bean
protected SystemSettings systemSettings;
protected OnCheckedChangeListener reverseorderCheckedChanged = new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
filterTorrents();
}
};
protected OnCheckedChangeListener showstatusCheckChanged = new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
navigationView.setVisibility(showstatusCheckBox.isChecked() ? View.GONE : View.VISIBLE);
serverstatusView.setVisibility(showstatusCheckBox.isChecked() ? View.VISIBLE : View.GONE);
}
};
private List<Torrent> previewTorrents = null;
private int appWidgetId;
private OnClickListener doneClicked = new OnClickListener() {
@Override
public void onClick(View v) {
// All spinner have to be initialised already
if (serverSpinner.getSelectedItem() == null) {
return;
}
if (filterSpinner.getSelectedItem() == null) {
return;
}
if (sortSpinner.getSelectedItem() == null) {
return;
}
// Store these user preferences
int server = ((ServerSetting) serverSpinner.getSelectedItem()).getOrder();
StatusType statusType = ((StatusTypeFilter) filterSpinner.getSelectedItem()).getStatusType();
TorrentsSortBy sortBy = ((SortByListItem) sortSpinner.getSelectedItem()).getSortBy();
boolean reverseSort = reverseorderCheckBox.isChecked();
boolean showstatus = showstatusCheckBox.isChecked();
ListWidgetConfig config = new ListWidgetConfig(server, statusType, sortBy, reverseSort, showstatus);
applicationSettings.setWidgetConfig(appWidgetId, config);
// Return the widget configuration result
AppWidgetManager manager = AppWidgetManager.getInstance(ListWidgetConfigActivity.this);
manager.updateAppWidget(appWidgetId, ListWidgetProvider.buildRemoteViews(getApplicationContext(), appWidgetId, config));
manager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.torrents_list);
setResult(RESULT_OK, new Intent().putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId));
finish();
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getIntent() == null || getIntent().getExtras() == null ||
!getIntent().hasExtra(AppWidgetManager.EXTRA_APPWIDGET_ID)) {
// Invalid configuration; return canceled result
setResult(RESULT_CANCELED, new Intent().putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID));
finish();
}
// Get the appwidget ID we are configuring
appWidgetId = getIntent().getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
// Set preliminary canceled result and continue with the initialisation
setResult(RESULT_CANCELED, new Intent().putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId));
}
@AfterViews
protected void init() {
// Populate the selection spinners with custom array adapters
List<SortByListItem> sortOrders = new ArrayList<>();
for (TorrentsSortBy order : TorrentsSortBy.values()) {
sortOrders.add(new SortByListItem(this, order));
}
serverSpinner.setAdapter(new SimpleListItemSpinnerAdapter<>(this, 0, applicationSettings.getAllServerSettings()));
filterSpinner.setAdapter(new SimpleListItemSpinnerAdapter<>(this, 0, StatusType.getAllStatusTypes(this)));
sortSpinner.setAdapter(new SimpleListItemSpinnerAdapter<>(this, 0, sortOrders));
reverseorderCheckBox.setOnCheckedChangeListener(reverseorderCheckedChanged);
showstatusCheckBox.setOnCheckedChangeListener(showstatusCheckChanged);
torrentsList.setEmptyView(errorText);
// Set up action bar with a done button
// Inspired by NoNonsenseNotes's ListWidgetConfig.java (Apache License, Version 2.0)
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM,
ActionBar.DISPLAY_SHOW_CUSTOM | ActionBar.DISPLAY_SHOW_HOME | ActionBar.DISPLAY_SHOW_TITLE);
@SuppressLint("InflateParams") // Uses local activity theme correctly, so missing the inflation parent is okay
View doneButtonFrame = getLayoutInflater().inflate(R.layout.actionbar_donebutton, null);
doneButtonFrame.findViewById(R.id.actionbar_done).setOnClickListener(doneClicked);
getSupportActionBar().setCustomView(doneButtonFrame);
}
}
@ItemSelect
protected void serverSpinnerItemSelected(boolean selected, ServerSetting server) {
serverText.setText(server.getName());
loadTorrents();
}
@ItemSelect
protected void filterSpinnerItemSelected(boolean selected, StatusTypeFilter statusTypeFilter) {
filterText.setText(statusTypeFilter.getName());
filterTorrents();
}
@ItemSelect
protected void sortSpinnerItemSelected(boolean selected, SortByListItem sortByListItem) {
filterTorrents();
}
@Background
protected void loadTorrents() {
if (serverSpinner.getSelectedItem() == null) {
return;
}
// Create a connection object and retrieve the live torrents
IDaemonAdapter connection =
((ServerSetting) serverSpinner.getSelectedItem()).createServerAdapter(connectivityHelper.getConnectedNetworkName(), this);
DaemonTaskResult result = RetrieveTask.create(connection).execute(log);
if (result instanceof RetrieveTaskSuccessResult) {
// Success; show the active torrents in the widget preview
onTorrentsRetrieved(((RetrieveTaskSuccessResult) result).getTorrents(), ((RetrieveTaskSuccessResult) result).getLabels());
} else {
// Can't connect right now; provide a nice error message
showError(false);
}
}
@UiThread
protected void onTorrentsRetrieved(List<Torrent> torrents, List<Label> labels) {
previewTorrents = torrents;
filterTorrents();
}
protected void filterTorrents() {
// All spinners have to be initialised already
if (serverSpinner.getSelectedItem() == null) {
return;
}
if (filterSpinner.getSelectedItem() == null) {
return;
}
if (sortSpinner.getSelectedItem() == null) {
return;
}
if (previewTorrents == null) {
return;
}
// Get the already loaded torrents and filter and sort them
ArrayList<Torrent> filteredTorrents = new ArrayList<>(previewTorrents.size());
StatusTypeFilter statusTypeFilter = (StatusTypeFilter) filterSpinner.getSelectedItem();
boolean dormantAsInactive = systemSettings.treatDormantAsInactive();
for (Torrent torrent : previewTorrents) {
if (statusTypeFilter.matches(torrent, dormantAsInactive)) {
filteredTorrents.add(torrent);
}
}
if (filteredTorrents.size() == 0) {
showError(true);
return;
}
TorrentsSortBy sortBy = ((SortByListItem) sortSpinner.getSelectedItem()).getSortBy();
Daemon serverType = filteredTorrents.get(0).getDaemon();
Collections.sort(filteredTorrents, new TorrentsComparator(serverType, sortBy, reverseorderCheckBox.isChecked()));
// Update the server status count and speeds
int downcount = 0, upcount = 0, downspeed = 0, upspeed = 0;
for (Torrent torrent : previewTorrents) {
if (torrent.isDownloading(dormantAsInactive)) {
downcount++;
upcount++;
} else if (torrent.isSeeding(dormantAsInactive)) {
upcount++;
}
downspeed += torrent.getRateDownload();
upspeed += torrent.getRateUpload();
}
downcountText.setText(Integer.toString(downcount));
upcountText.setText(Integer.toString(upcount));
downspeedText.setText(FileSizeConverter.getSize(downspeed) + "/s");
upspeedText.setText(FileSizeConverter.getSize(upspeed) + "/s");
// Finally update the widget preview with the live, filtered and sorted torrents list
torrentsList.setAdapter(new ListWidgetPreviewAdapter(this, 0, filteredTorrents));
torrentsList.setVisibility(View.VISIBLE);
errorText.setVisibility(View.GONE);
}
@UiThread
protected void showError(boolean emptyResults) {
torrentsList.setVisibility(View.GONE);
errorText.setVisibility(View.VISIBLE);
errorText.setText(emptyResults ? R.string.navigation_emptytorrents : R.string.error_httperror);
}
}