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 - 14sp 17sp @@ -40,4 +35,10 @@ 14sp 63dp + + 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 @@ 16dp 8dp 16dp + 8dp 12sp @@ -40,4 +41,10 @@ 13sp 53dp + + 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 + Servers Add new server Search 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