diff --git a/core/res/drawable-hdpi/ic_action_done_dark.png b/core/res/drawable-hdpi/ic_action_done_dark.png
new file mode 100644
index 00000000..53cf6877
Binary files /dev/null and b/core/res/drawable-hdpi/ic_action_done_dark.png differ
diff --git a/core/res/drawable-hdpi/ic_action_done_light.png b/core/res/drawable-hdpi/ic_action_done_light.png
new file mode 100644
index 00000000..58bf9721
Binary files /dev/null and b/core/res/drawable-hdpi/ic_action_done_light.png differ
diff --git a/core/res/drawable-mdpi/ic_action_done_dark.png b/core/res/drawable-mdpi/ic_action_done_dark.png
new file mode 100644
index 00000000..35cda8e1
Binary files /dev/null and b/core/res/drawable-mdpi/ic_action_done_dark.png differ
diff --git a/core/res/drawable-mdpi/ic_action_done_light.png b/core/res/drawable-mdpi/ic_action_done_light.png
new file mode 100644
index 00000000..cf5fab3a
Binary files /dev/null and b/core/res/drawable-mdpi/ic_action_done_light.png differ
diff --git a/core/res/drawable-xhdpi/ic_action_done_dark.png b/core/res/drawable-xhdpi/ic_action_done_dark.png
new file mode 100644
index 00000000..b52dc370
Binary files /dev/null and b/core/res/drawable-xhdpi/ic_action_done_dark.png differ
diff --git a/core/res/drawable-xhdpi/ic_action_done_light.png b/core/res/drawable-xhdpi/ic_action_done_light.png
new file mode 100644
index 00000000..b8915716
Binary files /dev/null and b/core/res/drawable-xhdpi/ic_action_done_light.png differ
diff --git a/core/res/layout/actionbar_donebutton.xml b/core/res/layout/actionbar_donebutton.xml
new file mode 100644
index 00000000..faf12416
--- /dev/null
+++ b/core/res/layout/actionbar_donebutton.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/core/res/layout/activity_widgetconfig.xml b/core/res/layout/activity_widgetconfig.xml
new file mode 100644
index 00000000..1153afe2
--- /dev/null
+++ b/core/res/layout/activity_widgetconfig.xml
@@ -0,0 +1,91 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/core/res/layout/widget_torrents_dark.xml b/core/res/layout/widget_torrents_dark.xml
new file mode 100644
index 00000000..8b606768
--- /dev/null
+++ b/core/res/layout/widget_torrents_dark.xml
@@ -0,0 +1,69 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/core/res/layout/widget_torrents_light.xml b/core/res/layout/widget_torrents_light.xml
new file mode 100644
index 00000000..8b606768
--- /dev/null
+++ b/core/res/layout/widget_torrents_light.xml
@@ -0,0 +1,69 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/core/res/values-sw600dp/dimens.xml b/core/res/values-sw600dp/dimens.xml
index 268734c6..2a8dc8ce 100644
--- a/core/res/values-sw600dp/dimens.xml
+++ b/core/res/values-sw600dp/dimens.xml
@@ -16,11 +16,6 @@
-->
-
- 16dp
- 8dp
- 16dp
-
14sp17sp
@@ -40,4 +35,10 @@
14sp63dp
+
+ 0
+ 15dp
+ -1dp
+ 300dp
+
diff --git a/core/res/values-v14/dimens.xml b/core/res/values-v14/dimens.xml
new file mode 100644
index 00000000..54dfd51f
--- /dev/null
+++ b/core/res/values-v14/dimens.xml
@@ -0,0 +1,21 @@
+
+
+
+ 0dp
+
+
diff --git a/core/res/values/attrs.xml b/core/res/values/attrs.xml
index 5bd9fc95..64c2f81e 100644
--- a/core/res/values/attrs.xml
+++ b/core/res/values/attrs.xml
@@ -42,6 +42,7 @@
+
diff --git a/core/res/values/dimens.xml b/core/res/values/dimens.xml
index 21633559..3dec83c5 100644
--- a/core/res/values/dimens.xml
+++ b/core/res/values/dimens.xml
@@ -20,6 +20,7 @@
16dp8dp16dp
+ 8dp12sp
@@ -40,4 +41,10 @@
13sp53dp
+
+ 1
+ 10dp
+ 150dp
+ -1dp
+
diff --git a/core/res/values/strings.xml b/core/res/values/strings.xml
index 92e97c81..b5856e1e 100644
--- a/core/res/values/strings.xml
+++ b/core/res/values/strings.xml
@@ -190,6 +190,13 @@
New torrents for %1$s
+ Open Transdroid
+ SERVER VIEW
+ LOOK & FEEL
+ Reverse sort order
+ Use dark theme
+ DONE
+
ServersAdd new serverSearch sites
diff --git a/core/res/values/styles.xml b/core/res/values/styles.xml
index bf67e11f..85579153 100644
--- a/core/res/values/styles.xml
+++ b/core/res/values/styles.xml
@@ -22,6 +22,7 @@
@color/background_light@drawable/ic_action_discard_light
+ @drawable/ic_action_done_light@drawable/ic_action_filter_light@drawable/ic_action_labels_light@drawable/ic_action_new_light
@@ -53,6 +54,7 @@
@color/background_dark@drawable/ic_action_discard_dark
+ @drawable/ic_action_done_dark@drawable/ic_action_filter_dark@drawable/ic_action_labels_dark@drawable/ic_action_new_dark
diff --git a/core/res/xml/appwidget_info.xml b/core/res/xml/appwidget_info.xml
new file mode 100644
index 00000000..57d66929
--- /dev/null
+++ b/core/res/xml/appwidget_info.xml
@@ -0,0 +1,29 @@
+
+
+
diff --git a/core/src/org/transdroid/core/app/settings/ApplicationSettings.java b/core/src/org/transdroid/core/app/settings/ApplicationSettings.java
index 5946714e..ec13a23e 100644
--- a/core/src/org/transdroid/core/app/settings/ApplicationSettings.java
+++ b/core/src/org/transdroid/core/app/settings/ApplicationSettings.java
@@ -29,7 +29,9 @@ import org.json.JSONArray;
import org.json.JSONException;
import org.transdroid.core.app.search.SearchHelper;
import org.transdroid.core.app.search.SearchSite;
+import org.transdroid.core.gui.navigation.StatusType;
import org.transdroid.core.gui.search.SearchSetting;
+import org.transdroid.core.widget.WidgetSettings;
import org.transdroid.daemon.Daemon;
import org.transdroid.daemon.OS;
import org.transdroid.daemon.TorrentsSortBy;
@@ -408,7 +410,7 @@ public class ApplicationSettings {
all.addAll(getWebsearchSettings());
return Collections.unmodifiableList(all);
}
-
+
/**
* Returns the settings of the search site that was last used by the user or was selected by the user as default
* site in the main settings. As opposed to getLastUsedSearchSiteKey(int), this method checks whether a site was
@@ -434,7 +436,7 @@ public class ApplicationSettings {
}
return null;
}
-
+
if (lastWebsearch >= 0) {
// The last used site should be a user-configured web search site
int max = getMaxWebsearch(); // Zero-based index, so with max == 0 there is 1 server
@@ -444,7 +446,7 @@ public class ApplicationSettings {
}
return getWebsearchSetting(lastWebsearch);
}
-
+
// Should be an in-app search key
if (allsites != null) {
for (SearchSite searchSite : allsites) {
@@ -455,7 +457,7 @@ public class ApplicationSettings {
// Not found at all; probably a no longer existing web search; return the first in-app one
return allsites.get(0);
}
-
+
return null;
}
@@ -503,5 +505,33 @@ public class ApplicationSettings {
public void setServerLastStats(ServerSetting server, JSONArray lastStats) {
prefs.edit().putString(server.getUniqueIdentifier(), lastStats.toString()).commit();
}
-
+
+ /**
+ * Returns the user configuration for some specific app widget, if the widget is known at all.
+ * @param appWidgetId The unique ID of the app widget to retrieve settings for, as supplied by the AppWidgetManager
+ * @return A widget configuration object, or null if no settings were stored for the widget ID
+ */
+ public WidgetSettings getWidgetConfig(int appWidgetId) {
+ if (!prefs.contains("widget_server_" + appWidgetId))
+ return null;
+ // @formatter:off
+ return new WidgetSettings(
+ prefs.getInt("widget_server_" + appWidgetId, -1),
+ StatusType.valueOf(prefs.getString("widget_status_" + appWidgetId, StatusType.ShowAll.name())),
+ TorrentsSortBy.valueOf(prefs.getString("widget_sortby_" + appWidgetId, TorrentsSortBy.Alphanumeric.name())),
+ prefs.getBoolean("widget_reverse_" + appWidgetId, false),
+ prefs.getBoolean("widget_darktheme_" + appWidgetId, false));
+ // @formatter:on
+ }
+
+ public void setWidgetConfig(int appWidgetId, WidgetSettings settings) {
+ Editor edit = prefs.edit();
+ edit.putInt("widget_server_" + appWidgetId, settings.getServerId());
+ edit.putString("widget_status_" + appWidgetId, settings.getStatusType().name());
+ edit.putString("widget_sortby_" + appWidgetId, settings.getSortBy().name());
+ edit.putBoolean("widget_reverse_" + appWidgetId, settings.shouldReserveSort());
+ edit.putBoolean("widget_darktheme_" + appWidgetId, settings.shouldUseDarkTheme());
+ edit.commit();
+ }
+
}
diff --git a/core/src/org/transdroid/core/gui/lists/SortByListItem.java b/core/src/org/transdroid/core/gui/lists/SortByListItem.java
new file mode 100644
index 00000000..d05c6aef
--- /dev/null
+++ b/core/src/org/transdroid/core/gui/lists/SortByListItem.java
@@ -0,0 +1,46 @@
+/*
+ * 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 .
+ */
+package org.transdroid.core.gui.lists;
+
+import org.transdroid.daemon.TorrentsSortBy;
+
+/**
+ * Represents a way in which a torrents list can be sorted.
+ * @author Eric Kok
+ */
+public class SortByListItem implements SimpleListItem {
+
+ private TorrentsSortBy sortBy;
+
+ public SortByListItem(TorrentsSortBy sortBy) {
+ this.sortBy = sortBy;
+ }
+
+ /**
+ * Returns the contained represented sort order.
+ * @return The sort by order as its enumeration value
+ */
+ public TorrentsSortBy getSortBy() {
+ return sortBy;
+ }
+
+ @Override
+ public String getName() {
+ return sortBy.name();
+ }
+
+}
diff --git a/core/src/org/transdroid/core/gui/navigation/StatusType.java b/core/src/org/transdroid/core/gui/navigation/StatusType.java
index 74b26190..08c74e58 100644
--- a/core/src/org/transdroid/core/gui/navigation/StatusType.java
+++ b/core/src/org/transdroid/core/gui/navigation/StatusType.java
@@ -97,6 +97,10 @@ public enum StatusType {
this.name = name;
}
+ public StatusType getStatusType() {
+ return statusType;
+ }
+
@Override
public String getName() {
return name;
diff --git a/core/src/org/transdroid/core/widget/WidgetConfigActivity.java b/core/src/org/transdroid/core/widget/WidgetConfigActivity.java
new file mode 100644
index 00000000..abaa2f2e
--- /dev/null
+++ b/core/src/org/transdroid/core/widget/WidgetConfigActivity.java
@@ -0,0 +1,265 @@
+/*
+ * 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 .
+ */
+package org.transdroid.core.widget;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.androidannotations.annotations.AfterViews;
+import org.androidannotations.annotations.Background;
+import org.androidannotations.annotations.Bean;
+import org.androidannotations.annotations.EActivity;
+import org.androidannotations.annotations.ItemSelect;
+import org.androidannotations.annotations.SystemService;
+import org.androidannotations.annotations.UiThread;
+import org.androidannotations.annotations.ViewById;
+import org.transdroid.core.R;
+import org.transdroid.core.app.settings.ApplicationSettings;
+import org.transdroid.core.app.settings.ServerSetting;
+import org.transdroid.core.app.settings.SystemSettings_;
+import org.transdroid.core.gui.lists.SimpleListItem;
+import org.transdroid.core.gui.lists.SortByListItem;
+import org.transdroid.core.gui.lists.TorrentsAdapter;
+import org.transdroid.core.gui.navigation.FilterListItemAdapter;
+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 android.appwidget.AppWidgetManager;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+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.Spinner;
+import android.widget.TextView;
+
+import com.actionbarsherlock.app.ActionBar;
+import com.actionbarsherlock.app.SherlockActivity;
+import com.actionbarsherlock.view.SherlockListView;
+
+@EActivity(resName = "activity_widgetconfig")
+public class WidgetConfigActivity extends SherlockActivity {
+
+ // Views and adapters
+ @ViewById
+ protected Spinner serverSpinner, filterSpinner, sortSpinner;
+ @ViewById
+ protected CheckBox reverseorderCheckBox, darkthemeCheckBox;
+ @ViewById
+ protected TextView filterText, serverText, errorText;
+ @ViewById
+ protected SherlockListView torrentsList;
+ @Bean
+ protected TorrentsAdapter previewTorrentsAdapter;
+ private List previewTorrents = null;
+
+ // Settings and helpers
+ @SystemService
+ protected AppWidgetManager appWidgetManager;
+ @SystemService
+ protected LayoutInflater layoutInflater;
+ @Bean
+ protected ConnectivityHelper connectivityHelper;
+ @Bean
+ protected ApplicationSettings applicationSettings;
+ private int appWidgetId;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+
+ // 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);
+
+ if (getIntent() != null && getIntent().getExtras() != null) {
+ // 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));
+ }
+
+ // Invalid configuration; return canceled result
+ setResult(RESULT_CANCELED,
+ new Intent().putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID));
+ finish();
+
+ }
+
+ @AfterViews
+ protected void init() {
+
+ // Populate the selection spinners
+ List sortOrders = new ArrayList();
+ for (TorrentsSortBy order : TorrentsSortBy.values()) {
+ sortOrders.add(new SortByListItem(order));
+ }
+ serverSpinner.setAdapter(new FilterListItemAdapter(this, applicationSettings.getServerSettings()));
+ filterSpinner.setAdapter(new FilterListItemAdapter(this, StatusType.getAllStatusTypes(this)));
+ sortSpinner.setAdapter(new FilterListItemAdapter(this, sortOrders));
+ // TODO: Update to AndroidAnnotations 3.0 and use @CheckedChanged
+ reverseorderCheckBox.setOnCheckedChangeListener(reverseorderCheckedChanged);
+ torrentsList.setAdapter(previewTorrentsAdapter);
+
+ // Set up action bar with a done button
+ // Inspired by NoNonsenseNotes's ListWidgetConfig.java (Apache License, Version 2.0)
+ getSupportActionBar().setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM,
+ ActionBar.DISPLAY_SHOW_CUSTOM | ActionBar.DISPLAY_SHOW_HOME | ActionBar.DISPLAY_SHOW_TITLE);
+ View doneButtonFrame = layoutInflater.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();
+ }
+
+ protected OnCheckedChangeListener reverseorderCheckedChanged = new OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ 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());
+ DaemonTaskResult result = RetrieveTask.create(connection).execute();
+ 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 torrents, List