Browse Source

Merge branch 'dev'

pull/13/merge
Eric Kok 11 years ago
parent
commit
68d48a8808
  1. 4
      core/AndroidManifest.xml
  2. BIN
      core/res/drawable-hdpi/ic_action_done_dark.png
  3. BIN
      core/res/drawable-hdpi/ic_action_done_light.png
  4. BIN
      core/res/drawable-hdpi/widget_preview.png
  5. BIN
      core/res/drawable-mdpi/ic_action_done_dark.png
  6. BIN
      core/res/drawable-mdpi/ic_action_done_light.png
  7. BIN
      core/res/drawable-xhdpi/ic_action_done_dark.png
  8. BIN
      core/res/drawable-xhdpi/ic_action_done_light.png
  9. 37
      core/res/layout-v11/actionbar_donebutton.xml
  10. 106
      core/res/layout-v11/activity_widgetconfig.xml
  11. 68
      core/res/layout-v11/list_item_widget_dark.xml
  12. 68
      core/res/layout-v11/list_item_widget_light.xml
  13. 116
      core/res/layout-v11/widget_torrents_dark.xml
  14. 115
      core/res/layout-v11/widget_torrents_light.xml
  15. 11
      core/res/values-sw600dp/dimens.xml
  16. 27
      core/res/values-v11/bools.xml
  17. 21
      core/res/values-v14/dimens.xml
  18. 1
      core/res/values/attrs.xml
  19. 2
      core/res/values/bools.xml
  20. 1
      core/res/values/changelog.xml
  21. 14
      core/res/values/colors.xml
  22. 12
      core/res/values/dimens.xml
  23. 9
      core/res/values/strings.xml
  24. 16
      core/res/values/styles.xml
  25. 29
      core/res/xml/appwidget_info.xml
  26. 54
      core/src/org/transdroid/core/app/settings/ApplicationSettings.java
  27. 2
      core/src/org/transdroid/core/gui/FilterEntryDialog.java
  28. 22
      core/src/org/transdroid/core/gui/TorrentsActivity.java
  29. 66
      core/src/org/transdroid/core/gui/lists/SimpleListItemSpinnerAdapter.java
  30. 70
      core/src/org/transdroid/core/gui/lists/SortByListItem.java
  31. 9
      core/src/org/transdroid/core/gui/lists/TorrentFilePriorityLayout.java
  32. 27
      core/src/org/transdroid/core/gui/lists/TorrentStatusLayout.java
  33. 16
      core/src/org/transdroid/core/gui/navigation/StatusType.java
  34. 2
      core/src/org/transdroid/core/gui/search/BarcodeHelper.java
  35. 2
      core/src/org/transdroid/core/gui/search/FilePickerHelper.java
  36. 2
      core/src/org/transdroid/core/gui/search/UrlEntryDialog.java
  37. 63
      core/src/org/transdroid/core/widget/WidgetConfig.java
  38. 262
      core/src/org/transdroid/core/widget/WidgetConfigActivity.java
  39. 143
      core/src/org/transdroid/core/widget/WidgetProvider.java
  40. 198
      core/src/org/transdroid/core/widget/WidgetService.java
  41. 38
      full/AndroidManifest.xml
  42. 38
      lite/AndroidManifest.xml

4
core/AndroidManifest.xml

@ -17,8 +17,8 @@
--> -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.transdroid.core" package="org.transdroid.core"
android:versionCode="5" android:versionCode="6"
android:versionName="2.0-beta1" > android:versionName="2.0" >
<uses-sdk <uses-sdk
android:minSdkVersion="7" android:minSdkVersion="7"

BIN
core/res/drawable-hdpi/ic_action_done_dark.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
core/res/drawable-hdpi/ic_action_done_light.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
core/res/drawable-hdpi/widget_preview.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

BIN
core/res/drawable-mdpi/ic_action_done_dark.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
core/res/drawable-mdpi/ic_action_done_light.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
core/res/drawable-xhdpi/ic_action_done_dark.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
core/res/drawable-xhdpi/ic_action_done_light.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

37
core/res/layout-v14/actionbar_progressitem.xml → core/res/layout-v11/actionbar_donebutton.xml

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- <!--
Copyright 2010-2013 Eric Kok et al. Copyright 2010-2013 Eric Kok et al.
Based on Roman Nurik 2012 Apache License, Version 2.0
Transdroid is free software: you can redistribute it and/or modify Transdroid is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -15,26 +16,22 @@
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with Transdroid. If not, see <http://www.gnu.org/licenses/>. along with Transdroid. If not, see <http://www.gnu.org/licenses/>.
--> -->
<FrameLayout <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/actionbar_done"
android:layout_width="wrap_content" style="?android:actionButtonStyle"
android:layout_height="?attr/actionBarSize"> android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" >
<!-- This is a wrapper to be able to set the size of the progress item (since the first FrameLayout will be merged) --> <TextView
<FrameLayout style="?android:actionBarTabTextStyle"
android:layout_width="56dip" android:layout_width="wrap_content"
android:layout_height="match_parent" android:layout_height="wrap_content"
android:paddingLeft="3dip"> android:layout_gravity="center"
android:drawableLeft="?attr/ic_action_done"
<ProgressBar android:drawablePadding="8dp"
android:id="@+id/progress" android:gravity="center_vertical"
android:layout_width="20dip" android:paddingRight="20dp"
android:layout_height="20dip" android:text="@string/widget_done" />
android:layout_gravity="center"
style="@android:style/Widget.ProgressBar.Small.Inverse"
android:indeterminate="true"
android:indeterminateOnly="true" />
</FrameLayout>
</FrameLayout> </FrameLayout>

106
core/res/layout-v11/activity_widgetconfig.xml

@ -0,0 +1,106 @@
<?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/>.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:dividerPadding="@dimen/margin_default"
android:orientation="@integer/widget_config_orientation" >
<FrameLayout
android:layout_width="@dimen/widget_preview_width"
android:layout_height="@dimen/widget_preview_height"
android:layout_gravity="center_horizontal"
android:background="@null"
android:padding="@dimen/widget_preview_padding" >
<include layout="@layout/widget_torrents_light" />
</FrameLayout>
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/background_light"
android:fillViewport="true"
android:paddingLeft="@dimen/margin_default"
android:paddingRight="@dimen/margin_default" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:id="@+id/filterheader_text"
style="@style/SectionHeader"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/widget_filter"
android:textIsSelectable="false" />
<Spinner
android:id="@+id/server_spinner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_half" />
<Spinner
android:id="@+id/filter_spinner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_half" />
<TextView
android:id="@+id/sortbyheader_text"
style="@style/SectionHeader"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/widget_sortby"
android:textIsSelectable="false" />
<Spinner
android:id="@+id/sort_spinner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_half" />
<CheckBox
android:id="@+id/reverseorder_check_box"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_half"
android:text="@string/widget_reversesortorder" />
<TextView
android:id="@+id/lookfeelheader_text"
style="@style/SectionHeader"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/widget_lookfeel"
android:textIsSelectable="false" />
<CheckBox
android:id="@+id/darktheme_check_box"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/margin_half"
android:layout_marginTop="@dimen/margin_half"
android:text="@string/widget_usedarktheme" />
</LinearLayout>
</ScrollView>
</LinearLayout>

68
core/res/layout-v11/list_item_widget_dark.xml

@ -0,0 +1,68 @@
<?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"
android:id="@+id/widget_line_layout"
android:layout_width="fill_parent"
android:layout_height="@dimen/widget_list_item_height"
android:background="@drawable/selectable_background_transdroid"
android:paddingRight="@dimen/widget_list_item_padding" >
<TextView
android:id="@+id/status_view"
android:layout_width="6dp"
android:layout_height="@dimen/widget_list_item_height" />
<TextView
android:id="@+id/name_text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/widget_list_item_padding_left"
android:ellipsize="end"
android:fontFamily="sans-serif-condensed"
android:maxLines="1"
android:paddingTop="@dimen/widget_list_item_padding"
android:textColor="@color/text_bright_dark"
android:textIsSelectable="false"
android:textSize="@dimen/text_enlarged" />
<TextView
android:id="@+id/ratio_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_below="@id/name_text"
android:layout_marginLeft="@dimen/widget_list_item_padding"
android:layout_marginTop="4dip"
android:maxLines="1"
android:paddingBottom="@dimen/widget_list_item_padding"
android:textIsSelectable="false"
android:textSize="@dimen/text_small" />
<TextView
android:id="@+id/progress_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="@id/ratio_text"
android:layout_alignParentLeft="true"
android:layout_marginLeft="@dimen/widget_list_item_padding_left"
android:layout_toLeftOf="@id/ratio_text"
android:maxLines="1"
android:textIsSelectable="false"
android:textSize="@dimen/text_small" />
</RelativeLayout>

68
core/res/layout-v11/list_item_widget_light.xml

@ -0,0 +1,68 @@
<?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"
android:id="@+id/widget_line_layout"
android:layout_width="fill_parent"
android:layout_height="@dimen/widget_list_item_height"
android:background="@drawable/selectable_background_transdroid2"
android:paddingRight="@dimen/widget_list_item_padding" >
<TextView
android:id="@+id/status_view"
android:layout_width="6dp"
android:layout_height="@dimen/widget_list_item_height" />
<TextView
android:id="@+id/name_text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/widget_list_item_padding_left"
android:ellipsize="end"
android:fontFamily="sans-serif-condensed"
android:maxLines="1"
android:paddingTop="@dimen/widget_list_item_padding"
android:textColor="@color/text_bright_light"
android:textIsSelectable="false"
android:textSize="@dimen/text_enlarged" />
<TextView
android:id="@+id/ratio_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_below="@id/name_text"
android:layout_marginLeft="@dimen/widget_list_item_padding"
android:layout_marginTop="4dip"
android:maxLines="1"
android:paddingBottom="@dimen/widget_list_item_padding"
android:textIsSelectable="false"
android:textSize="@dimen/text_small" />
<TextView
android:id="@+id/progress_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="@id/ratio_text"
android:layout_alignParentLeft="true"
android:layout_marginLeft="@dimen/widget_list_item_padding_left"
android:layout_toLeftOf="@id/ratio_text"
android:maxLines="1"
android:textIsSelectable="false"
android:textSize="@dimen/text_small" />
</RelativeLayout>

116
core/res/layout-v11/widget_torrents_dark.xml

@ -0,0 +1,116 @@
<?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"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/background_dark"
android:padding="@dimen/margin_widget" >
<ImageButton
android:id="@+id/icon_image"
android:layout_width="@dimen/widget_header_height"
android:layout_height="@dimen/widget_header_height"
android:background="@drawable/selectable_background_transdroid"
android:contentDescription="@string/widget_opentransdroid"
android:padding="@dimen/widget_header_padding"
android:scaleType="fitXY"
android:src="@drawable/ic_launcher" />
<ImageButton
android:id="@+id/refresh_button"
android:layout_width="@dimen/widget_header_height"
android:layout_height="@dimen/widget_header_height"
android:layout_alignParentRight="true"
android:background="@drawable/selectable_background_transdroid"
android:contentDescription="@string/action_refresh"
android:padding="@dimen/widget_header_padding"
android:scaleType="fitXY"
android:src="@drawable/ic_action_refresh_dark" />
<LinearLayout
android:id="@+id/navigation_view"
android:layout_width="match_parent"
android:layout_height="@dimen/widget_header_height"
android:layout_toLeftOf="@id/refresh_button"
android:layout_toRightOf="@id/icon_image"
android:background="@drawable/selectable_background_transdroid"
android:clickable="true"
android:orientation="vertical"
android:paddingRight="@dimen/margin_half"
android:paddingTop="3dp" >
<TextView
android:id="@+id/filter_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:fontFamily="sans-serif-condensed"
android:maxLines="1"
android:textColor="@color/text_actionbar_dark"
android:textIsSelectable="false"
android:textSize="@dimen/ui_navigation_filter" />
<TextView
android:id="@+id/server_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="-4dip"
android:ellipsize="marquee"
android:fontFamily="sans-serif-light"
android:maxLines="1"
android:textColor="@color/text_actionbar_dark"
android:textIsSelectable="false"
android:textSize="@dimen/ui_navigation_server" />
</LinearLayout>
<TextView
android:id="@+id/topline_view"
android:layout_width="match_parent"
android:layout_height="2dp"
android:layout_below="@id/icon_image"
android:background="@color/green" />
<TextView
android:id="@+id/bottomline_view"
android:layout_width="match_parent"
android:layout_height="2dp"
android:layout_alignParentBottom="true"
android:background="@color/green" />
<ListView
android:id="@+id/torrents_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@id/bottomline_view"
android:layout_below="@id/topline_view"
android:visibility="gone" />
<TextView
android:id="@+id/error_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@id/bottomline_view"
android:layout_below="@id/topline_view"
android:layout_gravity="center"
android:gravity="center"
android:maxWidth="400dip"
android:padding="@dimen/margin_default"
android:textIsSelectable="false"
android:visibility="gone" />
</RelativeLayout>

115
core/res/layout-v11/widget_torrents_light.xml

@ -0,0 +1,115 @@
<?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"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/background_light"
android:padding="@dimen/margin_widget" >
<ImageButton
android:id="@+id/icon_image"
android:layout_width="@dimen/widget_header_height"
android:layout_height="@dimen/widget_header_height"
android:background="@drawable/selectable_background_transdroid2"
android:contentDescription="@string/widget_opentransdroid"
android:padding="@dimen/widget_header_padding"
android:scaleType="fitXY"
android:src="@drawable/ic_launcher" />
<ImageButton
android:id="@+id/refresh_button"
android:layout_width="@dimen/widget_header_height"
android:layout_height="@dimen/widget_header_height"
android:layout_alignParentRight="true"
android:background="@drawable/selectable_background_transdroid2"
android:contentDescription="@string/action_refresh"
android:padding="@dimen/widget_header_padding"
android:scaleType="fitXY"
android:src="@drawable/ic_action_refresh_light" />
<LinearLayout
android:id="@+id/navigation_view"
android:layout_width="match_parent"
android:layout_height="@dimen/widget_header_height"
android:layout_toLeftOf="@id/refresh_button"
android:layout_toRightOf="@id/icon_image"
android:background="@drawable/selectable_background_transdroid2"
android:clickable="true"
android:orientation="vertical"
android:paddingRight="@dimen/margin_half"
android:paddingTop="3dp" >
<TextView
android:id="@+id/filter_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:fontFamily="sans-serif-condensed"
android:maxLines="1"
android:textColor="@color/text_actionbar_light"
android:textIsSelectable="false"
android:textSize="@dimen/ui_navigation_filter" />
<TextView
android:id="@+id/server_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="-4dip"
android:ellipsize="marquee"
android:fontFamily="sans-serif-light"
android:maxLines="1"
android:textColor="@color/text_actionbar_light"
android:textIsSelectable="false"
android:textSize="@dimen/ui_navigation_server" />
</LinearLayout>
<TextView
android:id="@+id/topline_view"
android:layout_width="match_parent"
android:layout_height="2dp"
android:layout_below="@id/icon_image"
android:background="@color/green" />
<TextView
android:id="@+id/bottomline_view"
android:layout_width="match_parent"
android:layout_height="2dp"
android:layout_alignParentBottom="true"
android:background="@color/green" />
<ListView
android:id="@+id/torrents_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@id/bottomline_view"
android:layout_below="@id/topline_view"
android:visibility="gone" />
<TextView
android:id="@+id/error_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@id/bottomline_view"
android:layout_below="@id/topline_view"
android:layout_gravity="center"
android:gravity="center"
android:padding="@dimen/margin_default"
android:textIsSelectable="false"
android:visibility="gone" />
</RelativeLayout>

11
core/res/values-sw600dp/dimens.xml

@ -16,11 +16,6 @@
--> -->
<resources> <resources>
<!-- Margins -->
<dimen name="margin_default">16dp</dimen>
<dimen name="margin_half">8dp</dimen>
<dimen name="margin_torrentlistleft">16dp</dimen>
<!-- Text sizes --> <!-- Text sizes -->
<dimen name="text_small">14sp</dimen> <dimen name="text_small">14sp</dimen>
<dimen name="text_default">17sp</dimen> <dimen name="text_default">17sp</dimen>
@ -40,4 +35,10 @@
<dimen name="ui_serverstatus_smallnumber">14sp</dimen> <dimen name="ui_serverstatus_smallnumber">14sp</dimen>
<dimen name="ui_serverstatus_width">63dp</dimen> <dimen name="ui_serverstatus_width">63dp</dimen>
<!-- Widget configuration -->
<integer name="widget_config_orientation">0</integer>
<dimen name="widget_preview_padding">30dp</dimen>
<dimen name="widget_preview_height">-1dp</dimen>
<dimen name="widget_preview_width">300dp</dimen>
</resources> </resources>

27
core/res/layout/actionbar_progressitem.xml → core/res/values-v11/bools.xml

@ -15,26 +15,7 @@
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with Transdroid. If not, see <http://www.gnu.org/licenses/>. along with Transdroid. If not, see <http://www.gnu.org/licenses/>.
--> -->
<FrameLayout <resources>
xmlns:android="http://schemas.android.com/apk/res/android" <!-- Used to enable the scrolling widget on Honeycomb (API 11) and higher only -->
android:layout_width="wrap_content" <bool name="widget_available">true</bool>
android:layout_height="?attr/actionBarSize"> </resources>
<!-- This is a wrapper to be able to set the size of the progress item (since the first FrameLayout will be merged) -->
<FrameLayout
android:layout_width="26dip"
android:layout_height="match_parent"
android:paddingLeft="3dip">
<ProgressBar
android:id="@+id/progress"
android:layout_width="20dip"
android:layout_height="20dip"
android:layout_gravity="center_vertical"
style="@android:style/Widget.ProgressBar.Small.Inverse"
android:indeterminate="true"
android:indeterminateOnly="true" />
</FrameLayout>
</FrameLayout>

21
core/res/values-v14/dimens.xml

@ -0,0 +1,21 @@
<!--
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/>.
-->
<resources>
<dimen name="margin_widget">0dp</dimen>
</resources>

1
core/res/values/attrs.xml

@ -42,6 +42,7 @@
<attr name="ic_action_stop" format="reference"/> <attr name="ic_action_stop" format="reference"/>
<attr name="ic_action_trackers" format="reference"/> <attr name="ic_action_trackers" format="reference"/>
<attr name="ic_action_website" format="reference"/> <attr name="ic_action_website" format="reference"/>
<attr name="ic_action_done" format="reference"/>
<attr name="loading_progress" format="reference"/> <attr name="loading_progress" format="reference"/>
<attr name="selectable_background_transdroid" format="reference"/> <attr name="selectable_background_transdroid" format="reference"/>
<attr name="text_bright" format="reference" /> <attr name="text_bright" format="reference" />

2
core/res/values/bools.xml

@ -18,4 +18,6 @@
<resources> <resources>
<!-- Used to determine if a device is 'small', i.e. a phone; for reference: a Nexus 7's smallest width is 533dip --> <!-- Used to determine if a device is 'small', i.e. a phone; for reference: a Nexus 7's smallest width is 533dip -->
<bool name="show_dialog_fullscreen">true</bool> <bool name="show_dialog_fullscreen">true</bool>
<!-- Used to enable the scrolling widget on Honeycomb (API 11) and higher only -->
<bool name="widget_available">false</bool>
</resources> </resources>

1
core/res/values/changelog.xml

@ -18,6 +18,7 @@
<resources> <resources>
<string name="system_changelog"> <string name="system_changelog">
Transdroid 2.0.0\n Transdroid 2.0.0\n
- Scrollable home screen widget (Android 3+)\n
- Allow changing of storage location (Deluge and Transmission)\n - Allow changing of storage location (Deluge and Transmission)\n
- Allow file downloads via AndFTP\n - Allow file downloads via AndFTP\n
- UI improvements for Lite version\n - UI improvements for Lite version\n

14
core/res/values/colors.xml

@ -16,8 +16,22 @@
along with Transdroid. If not, see <http://www.gnu.org/licenses/>. along with Transdroid. If not, see <http://www.gnu.org/licenses/>.
--> -->
<resources> <resources>
<!-- General layout colours -->
<color name="green">#8acc12</color> <color name="green">#8acc12</color>
<color name="ledgreen">#7dbb21</color> <color name="ledgreen">#7dbb21</color>
<color name="crouton_error">#c81113</color> <color name="crouton_error">#c81113</color>
<color name="crouton_info">#aada62</color> <color name="crouton_info">#aada62</color>
<!-- Torrent and file status colours -->
<color name="torrent_downloading">#42a8fa</color> <!-- Blue -->
<color name="torrent_paused">#a759d4</color> <!-- Purple -->
<color name="torrent_seeding">#8acc12</color> <!-- Green -->
<color name="torrent_error">#de3939</color> <!-- Red -->
<color name="torrent_other">#9e9e9e</color> <!-- Grey -->
<color name="file_low">#c8e88e</color> <!-- Light green -->
<color name="file_normal">#8acc12</color> <!-- Normal green -->
<color name="file_high">#4b6617</color> <!-- Dark green -->
<color name="file_off">#9e9e9e</color> <!-- Grey -->
</resources> </resources>

12
core/res/values/dimens.xml

@ -20,6 +20,7 @@
<dimen name="margin_default">16dp</dimen> <dimen name="margin_default">16dp</dimen>
<dimen name="margin_half">8dp</dimen> <dimen name="margin_half">8dp</dimen>
<dimen name="margin_torrentlistleft">16dp</dimen> <dimen name="margin_torrentlistleft">16dp</dimen>
<dimen name="margin_widget">8dp</dimen>
<!-- Text sizes --> <!-- Text sizes -->
<dimen name="text_small">12sp</dimen> <dimen name="text_small">12sp</dimen>
@ -40,4 +41,15 @@
<dimen name="ui_serverstatus_smallnumber">13sp</dimen> <dimen name="ui_serverstatus_smallnumber">13sp</dimen>
<dimen name="ui_serverstatus_width">53dp</dimen> <dimen name="ui_serverstatus_width">53dp</dimen>
<!-- Widget configuration -->
<integer name="widget_config_orientation">1</integer>
<dimen name="widget_preview_padding">20dp</dimen>
<dimen name="widget_preview_height">200dp</dimen>
<dimen name="widget_preview_width">-1dp</dimen>
<dimen name="widget_header_height">46dp</dimen>
<dimen name="widget_header_padding">6dp</dimen>
<dimen name="widget_list_item_height">54dp</dimen>
<dimen name="widget_list_item_padding">6dp</dimen>
<dimen name="widget_list_item_padding_left">12dp</dimen>
</resources> </resources>

9
core/res/values/strings.xml

@ -190,6 +190,15 @@
</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="widget_loading">Loading&#8230;</string>
<string name="widget_opentransdroid">Open Transdroid</string>
<string name="widget_filter">SERVER VIEW</string>
<string name="widget_lookfeel">LOOK &amp; FEEL</string>
<string name="widget_sortby">SORT ORDER</string>
<string name="widget_reversesortorder">Reversed sort order</string>
<string name="widget_usedarktheme">Use dark theme (no preview)</string>
<string name="widget_done">DONE</string>
<string name="pref_servers">Servers</string> <string name="pref_servers">Servers</string>
<string name="pref_addserver">Add new server</string> <string name="pref_addserver">Add new server</string>
<string name="pref_searchsites">Search sites</string> <string name="pref_searchsites">Search sites</string>

16
core/res/values/styles.xml

@ -17,11 +17,12 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"> <resources xmlns:android="http://schemas.android.com/apk/res/android">
<style name="TransdroidTheme" parent="Theme.Transdroid.Light"> <style name="TransdroidTheme" parent="Theme.Transdroid.Light">
<!-- All customizations that are NOT specific to a particular API-level can go here. --> <!-- All customizations that are NOT specific to a particular API-level can go here. -->
<item name="android:textViewStyle">@style/DefaultTextView</item> <item name="android:textViewStyle">@style/DefaultTextView</item>
<item name="android:windowBackground">@color/background_light</item> <item name="android:windowBackground">@color/background_light</item>
<item name="ic_action_discard">@drawable/ic_action_discard_light</item> <item name="ic_action_discard">@drawable/ic_action_discard_light</item>
<item name="ic_action_done">@drawable/ic_action_done_light</item>
<item name="ic_action_filter">@drawable/ic_action_filter_light</item> <item name="ic_action_filter">@drawable/ic_action_filter_light</item>
<item name="ic_action_labels">@drawable/ic_action_labels_light</item> <item name="ic_action_labels">@drawable/ic_action_labels_light</item>
<item name="ic_action_new">@drawable/ic_action_new_light</item> <item name="ic_action_new">@drawable/ic_action_new_light</item>
@ -48,11 +49,12 @@
</style> </style>
<style name="TransdroidTheme.Dark" parent="Theme.Transdroid.Dark"> <style name="TransdroidTheme.Dark" parent="Theme.Transdroid.Dark">
<!-- All customizations that are NOT specific to a particular API-level can go here. --> <!-- All customizations that are NOT specific to a particular API-level can go here. -->
<item name="android:textViewStyle">@style/DefaultTextView</item> <item name="android:textViewStyle">@style/DefaultTextView</item>
<item name="android:windowBackground">@color/background_dark</item> <item name="android:windowBackground">@color/background_dark</item>
<item name="ic_action_discard">@drawable/ic_action_discard_dark</item> <item name="ic_action_discard">@drawable/ic_action_discard_dark</item>
<item name="ic_action_done">@drawable/ic_action_done_dark</item>
<item name="ic_action_filter">@drawable/ic_action_filter_dark</item> <item name="ic_action_filter">@drawable/ic_action_filter_dark</item>
<item name="ic_action_labels">@drawable/ic_action_labels_dark</item> <item name="ic_action_labels">@drawable/ic_action_labels_dark</item>
<item name="ic_action_new">@drawable/ic_action_new_dark</item> <item name="ic_action_new">@drawable/ic_action_new_dark</item>
@ -78,6 +80,16 @@
<item name="text_actionbar">@color/text_actionbar_dark</item> <item name="text_actionbar">@color/text_actionbar_dark</item>
</style> </style>
<!-- No theme background to let users wall paper shine through -->
<!-- Inspired by NoNonsenseNotes's ThemeWidgetConfig -->
<style name="TransdroidTheme.WidgetConfig" parent="@style/TransdroidTheme">
<item name="android:background">@null</item>
<item name="android:colorBackgroundCacheHint">@null</item>
<item name="android:windowContentOverlay">@null</item>
<item name="android:windowShowWallpaper">true</item>
<item name="android:windowBackground">@android:color/transparent</item>
</style>
<!-- Taken from http://stackoverflow.com/questions/10020466/android-4-0-sub-title-section-label-styling --> <!-- Taken from http://stackoverflow.com/questions/10020466/android-4-0-sub-title-section-label-styling -->
<style name="SectionHeader" parent="android:Widget.Holo.Light.TextView"> <style name="SectionHeader" parent="android:Widget.Holo.Light.TextView">
<item name="android:drawableBottom">@drawable/section_header</item> <item name="android:drawableBottom">@drawable/section_header</item>

29
core/res/xml/appwidget_info.xml

@ -0,0 +1,29 @@
<?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/>.
-->
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:configure="org.transdroid.core.widget.WidgetConfigActivity_"
android:initialKeyguardLayout="@layout/widget_torrents_light"
android:initialLayout="@layout/widget_torrents_light"
android:minHeight="110dip"
android:minResizeHeight="110dip"
android:minResizeWidth="110dp"
android:minWidth="180dp"
android:previewImage="@drawable/widget_preview"
android:resizeMode="horizontal|vertical"
android:updatePeriodMillis="3600000"
android:widgetCategory="home_screen|keyguard" />

54
core/src/org/transdroid/core/app/settings/ApplicationSettings.java

@ -16,6 +16,7 @@
*/ */
package org.transdroid.core.app.settings; package org.transdroid.core.app.settings;
import java.security.InvalidParameterException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Date; import java.util.Date;
@ -29,7 +30,9 @@ import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
import org.transdroid.core.app.search.SearchHelper; import org.transdroid.core.app.search.SearchHelper;
import org.transdroid.core.app.search.SearchSite; 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.gui.search.SearchSetting;
import org.transdroid.core.widget.WidgetConfig;
import org.transdroid.daemon.Daemon; import org.transdroid.daemon.Daemon;
import org.transdroid.daemon.OS; import org.transdroid.daemon.OS;
import org.transdroid.daemon.TorrentsSortBy; import org.transdroid.daemon.TorrentsSortBy;
@ -508,4 +511,55 @@ public class ApplicationSettings {
prefs.edit().putString(server.getUniqueIdentifier(), lastStats.toString()).commit(); 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 WidgetConfig getWidgetConfig(int appWidgetId) {
if (!prefs.contains("widget_server_" + appWidgetId))
return null;
// @formatter:off
return new WidgetConfig(
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
}
/**
* Stores the user settings for some specific app widget. Existing settings for the supplied app widget ID will be
* overridden.
* @param appWidgetId The unique ID of the app widget to store settings for, as supplied by the AppWidgetManager
* @param settings A widget configuration object, which may not be null
*/
public void setWidgetConfig(int appWidgetId, WidgetConfig settings) {
if (settings == null)
throw new InvalidParameterException(
"The widget setting may not be null. Use removeWidgetConfig instead to remove existing settings for some app widget.");
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();
}
/**
* Remove the setting for some specific app widget.
* @param appWidgetId The unique ID of the app widget to store settings for, as supplied by the AppWidgetManager
*/
public void removeWidgetConfig(int appWidgetId) {
Editor edit = prefs.edit();
edit.remove("widget_server_" + appWidgetId);
edit.remove("widget_status_" + appWidgetId);
edit.remove("widget_sortby_" + appWidgetId);
edit.remove("widget_reverse_" + appWidgetId);
edit.remove("widget_darktheme_" + appWidgetId);
edit.commit();
}
} }

2
core/src/org/transdroid/core/gui/FilterEntryDialog.java

@ -16,6 +16,7 @@
*/ */
package org.transdroid.core.gui; package org.transdroid.core.gui;
import android.annotation.SuppressLint;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
@ -32,6 +33,7 @@ public class FilterEntryDialog {
* torrents. * torrents.
* @param activity The activity that opens (and owns) this dialog * @param activity The activity that opens (and owns) this dialog
*/ */
@SuppressLint("ValidFragment")
public static void startFilterEntry(final TorrentsActivity activity) { public static void startFilterEntry(final TorrentsActivity activity) {
new DialogFragment() { new DialogFragment() {
public android.app.Dialog onCreateDialog(android.os.Bundle savedInstanceState) { public android.app.Dialog onCreateDialog(android.os.Bundle savedInstanceState) {

22
core/src/org/transdroid/core/gui/TorrentsActivity.java

@ -56,6 +56,7 @@ import org.transdroid.core.gui.search.UrlEntryDialog;
import org.transdroid.core.gui.settings.*; import org.transdroid.core.gui.settings.*;
import org.transdroid.core.service.BootReceiver; import org.transdroid.core.service.BootReceiver;
import org.transdroid.core.service.ConnectivityHelper; import org.transdroid.core.service.ConnectivityHelper;
import org.transdroid.core.widget.WidgetProvider;
import org.transdroid.daemon.Daemon; import org.transdroid.daemon.Daemon;
import org.transdroid.daemon.IDaemonAdapter; import org.transdroid.daemon.IDaemonAdapter;
import org.transdroid.daemon.Priority; import org.transdroid.daemon.Priority;
@ -212,9 +213,19 @@ public class TorrentsActivity extends SherlockFragmentActivity implements OnNavi
// No server settings yet; // No server settings yet;
return; return;
} }
if (getIntent().getExtras() == null && getIntent().hasExtra("org.transdroid.START_SERVER")) { Torrent startTorrent = null;
lastUsed = applicationSettings.getServerSetting(getIntent().getExtras().getInt( if (getIntent().getAction() != null && getIntent().getAction().equals(WidgetProvider.INTENT_STARTSERVER)
"org.transdroid.START_SERVER")); && getIntent().getExtras() == null && getIntent().hasExtra(WidgetProvider.EXTRA_SERVER)) {
// A server settings order ID was provided in this org.transdroid.START_SERVER action intent
int serverId = getIntent().getExtras().getInt(WidgetProvider.EXTRA_SERVER);
if (serverId < 0 || serverId > applicationSettings.getMaxServer()) {
Log.e(this, "Tried to start with " + WidgetProvider.EXTRA_SERVER + " intent but " + serverId
+ " is not an existing server order id");
} else {
lastUsed = applicationSettings.getServerSetting(serverId);
if (getIntent().hasExtra(WidgetProvider.EXTRA_TORRENT))
startTorrent = getIntent().getParcelableExtra(WidgetProvider.EXTRA_TORRENT);
}
} }
// Set this as selection in the action bar spinner; we can use the server setting key since we have stable ids // Set this as selection in the action bar spinner; we can use the server setting key since we have stable ids
@ -222,7 +233,10 @@ public class TorrentsActivity extends SherlockFragmentActivity implements OnNavi
skipNextOnNavigationItemSelectedCall = true; skipNextOnNavigationItemSelectedCall = true;
// Handle any start up intents // Handle any start up intents
if (firstStart && getIntent() != null) { if (startTorrent != null) {
openDetails(startTorrent);
startTorrent = null;
} else if (firstStart && getIntent() != null) {
currentConnection = lastUsed.createServerAdapter(connectivityHelper.getConnectedNetworkName()); currentConnection = lastUsed.createServerAdapter(connectivityHelper.getConnectedNetworkName());
handleStartIntent(); handleStartIntent();
} }

66
core/src/org/transdroid/core/gui/lists/SimpleListItemSpinnerAdapter.java

@ -0,0 +1,66 @@
/*
* 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.lists;
import java.util.List;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
/**
* A wrapper around {@link ArrayAdapter} that contains {@link SimpleListItem}s which simply show their name in the
* Spinner. The standard Android spinner resources are used for the layout.
* @author Eric Kok
*/
public class SimpleListItemSpinnerAdapter<T extends SimpleListItem> extends ArrayAdapter<T> {
/**
* Constructs the adapter, supplying the {@link SimpleListItem}s to show in the spinner. The given resource will be
* ignored as the standard Android Spinner layout is used instead.
* @param context The UI context to inflate the layout in
* @param resource This is ignored; android.R.layout.simple_spinner_item is always used instead
* @param objects The items to show in the spinner, which can simply display some name
*/
public SimpleListItemSpinnerAdapter(Context context, int resource, List<T> objects) {
super(context, android.R.layout.simple_spinner_item, objects);
setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// This relies on the ArrayAdapter implementation and the used standard xml layouts that simply return a
// TextView; this can then be filled with the SimpleListItem's name instead of the standard toString()
// implementation
TextView text = (TextView) super.getView(position, convertView, parent);
text.setText(getItem(position).getName());
return text;
}
@Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
// This relies on the ArrayAdapter implementation and the used standard xml layouts that simply return a
// TextView; this can then be filled with the SimpleListItem's name instead of the standard toString()
// implementation
TextView text = (TextView) super.getDropDownView(position, convertView, parent);
text.setText(getItem(position).getName());
return text;
}
}

70
core/src/org/transdroid/core/gui/lists/SortByListItem.java

@ -0,0 +1,70 @@
/*
* 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.lists;
import org.transdroid.core.R;
import org.transdroid.daemon.TorrentsSortBy;
import android.content.Context;
/**
* Represents a way in which a torrents list can be sorted.
* @author Eric Kok
*/
public class SortByListItem implements SimpleListItem {
private final TorrentsSortBy sortBy;
private final String name;
public SortByListItem(Context context, TorrentsSortBy sortBy) {
this.sortBy = sortBy;
switch (sortBy) {
case DateAdded:
this.name = context.getString(R.string.action_sort_added);
break;
case DateDone:
this.name = context.getString(R.string.action_sort_done);
break;
case Ratio:
this.name = context.getString(R.string.action_sort_ratio);
break;
case Status:
this.name = context.getString(R.string.action_sort_status);
break;
case UploadSpeed:
this.name = context.getString(R.string.action_sort_upspeed);
break;
default:
this.name = context.getString(R.string.action_sort_alpha);
break;
}
}
/**
* 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 name;
}
}

9
core/src/org/transdroid/core/gui/lists/TorrentFilePriorityLayout.java

@ -16,6 +16,7 @@
*/ */
package org.transdroid.core.gui.lists; package org.transdroid.core.gui.lists;
import org.transdroid.core.R;
import org.transdroid.daemon.Priority; import org.transdroid.daemon.Priority;
import android.content.Context; import android.content.Context;
@ -56,10 +57,10 @@ public class TorrentFilePriorityLayout extends CheckableRelativeLayout {
} }
private void initPaints() { private void initPaints() {
offPaint.setColor(0xFF9E9E9E); // Grey offPaint.setColor(getResources().getColor(R.color.file_off));
lowPaint.setColor(0xFFC8E88E); // Light green lowPaint.setColor(getResources().getColor(R.color.file_low));
normalPaint.setColor(0xFF8ACC12); // Normal green normalPaint.setColor(getResources().getColor(R.color.file_normal));
highPaint.setColor(0xFF4B6617); // Dark green highPaint.setColor(getResources().getColor(R.color.file_high));
} }
public void setPriority(Priority priority) { public void setPriority(Priority priority) {

27
core/src/org/transdroid/core/gui/lists/TorrentStatusLayout.java

@ -16,6 +16,7 @@
*/ */
package org.transdroid.core.gui.lists; package org.transdroid.core.gui.lists;
import org.transdroid.core.R;
import org.transdroid.daemon.TorrentStatus; import org.transdroid.daemon.TorrentStatus;
import android.content.Context; import android.content.Context;
@ -37,10 +38,10 @@ public class TorrentStatusLayout extends CheckableRelativeLayout {
private final int WIDTH = (int) (6 * scale + 0.5f); private final int WIDTH = (int) (6 * scale + 0.5f);
private TorrentStatus status = null; private TorrentStatus status = null;
private final Paint inactiveDonePaint = new Paint(); private final Paint pausedPaint = new Paint();
private final Paint inactivePaint = new Paint(); private final Paint otherPaint = new Paint();
private final Paint progressPaint = new Paint(); private final Paint downloadingPaint = new Paint();
private final Paint donePaint = new Paint(); private final Paint seedingPaint = new Paint();
private final Paint errorPaint = new Paint(); private final Paint errorPaint = new Paint();
private final RectF fullRect = new RectF(); private final RectF fullRect = new RectF();
@ -57,11 +58,11 @@ public class TorrentStatusLayout extends CheckableRelativeLayout {
} }
private void initPaints() { private void initPaints() {
inactiveDonePaint.setColor(0xFFA759D4); // Purple pausedPaint.setColor(getResources().getColor(R.color.torrent_paused));
inactivePaint.setColor(0xFF9E9E9E); // Grey otherPaint.setColor(getResources().getColor(R.color.torrent_other));
progressPaint.setColor(0xFF42A8FA); // Blue downloadingPaint.setColor(getResources().getColor(R.color.torrent_downloading));
donePaint.setColor(0xFF8ACC12); // Green seedingPaint.setColor(getResources().getColor(R.color.torrent_seeding));
errorPaint.setColor(0xFFDE3939); // Red errorPaint.setColor(getResources().getColor(R.color.torrent_error));
} }
/** /**
@ -88,19 +89,19 @@ public class TorrentStatusLayout extends CheckableRelativeLayout {
switch (status) { switch (status) {
case Downloading: case Downloading:
canvas.drawRect(fullRect, progressPaint); canvas.drawRect(fullRect, downloadingPaint);
break; break;
case Paused: case Paused:
canvas.drawRect(fullRect, inactiveDonePaint); canvas.drawRect(fullRect, pausedPaint);
break; break;
case Seeding: case Seeding:
canvas.drawRect(fullRect, donePaint); canvas.drawRect(fullRect, seedingPaint);
break; break;
case Error: case Error:
canvas.drawRect(fullRect, errorPaint); canvas.drawRect(fullRect, errorPaint);
break; break;
default: // Checking, Waiting, Queued, Unknown default: // Checking, Waiting, Queued, Unknown
canvas.drawRect(fullRect, inactivePaint); canvas.drawRect(fullRect, otherPaint);
break; break;
} }

16
core/src/org/transdroid/core/gui/navigation/StatusType.java

@ -35,27 +35,27 @@ import android.os.Parcelable;
public enum StatusType { public enum StatusType {
ShowAll { ShowAll {
StatusTypeFilter getFilterItem(Context context) { public StatusTypeFilter getFilterItem(Context context) {
return new StatusTypeFilter(StatusType.ShowAll, context.getString(R.string.navigation_status_showall)); return new StatusTypeFilter(StatusType.ShowAll, context.getString(R.string.navigation_status_showall));
} }
}, },
OnlyDownloading { OnlyDownloading {
StatusTypeFilter getFilterItem(Context context) { public StatusTypeFilter getFilterItem(Context context) {
return new StatusTypeFilter(StatusType.OnlyDownloading, context.getString(R.string.navigation_status_onlydown)); return new StatusTypeFilter(StatusType.OnlyDownloading, context.getString(R.string.navigation_status_onlydown));
} }
}, },
OnlyUploading { OnlyUploading {
StatusTypeFilter getFilterItem(Context context) { public StatusTypeFilter getFilterItem(Context context) {
return new StatusTypeFilter(StatusType.OnlyUploading, context.getString(R.string.navigation_status_onlyup)); return new StatusTypeFilter(StatusType.OnlyUploading, context.getString(R.string.navigation_status_onlyup));
} }
}, },
OnlyActive { OnlyActive {
StatusTypeFilter getFilterItem(Context context) { public StatusTypeFilter getFilterItem(Context context) {
return new StatusTypeFilter(StatusType.OnlyActive, context.getString(R.string.navigation_status_onlyactive)); return new StatusTypeFilter(StatusType.OnlyActive, context.getString(R.string.navigation_status_onlyactive));
} }
}, },
OnlyInactive { OnlyInactive {
StatusTypeFilter getFilterItem(Context context) { public StatusTypeFilter getFilterItem(Context context) {
return new StatusTypeFilter(StatusType.OnlyInactive, context.getString(R.string.navigation_status_onlyinactive)); return new StatusTypeFilter(StatusType.OnlyInactive, context.getString(R.string.navigation_status_onlyinactive));
} }
}; };
@ -85,7 +85,7 @@ public enum StatusType {
* @param context The Android UI context, to access translations * @param context The Android UI context, to access translations
* @return A filter item object to show in the GUI * @return A filter item object to show in the GUI
*/ */
abstract StatusTypeFilter getFilterItem(Context context); public abstract StatusTypeFilter getFilterItem(Context context);
public static class StatusTypeFilter implements SimpleListItem, NavigationFilter { public static class StatusTypeFilter implements SimpleListItem, NavigationFilter {
@ -97,6 +97,10 @@ public enum StatusType {
this.name = name; this.name = name;
} }
public StatusType getStatusType() {
return statusType;
}
@Override @Override
public String getName() { public String getName() {
return name; return name;

2
core/src/org/transdroid/core/gui/search/BarcodeHelper.java

@ -19,6 +19,7 @@ package org.transdroid.core.gui.search;
import org.transdroid.core.R; import org.transdroid.core.R;
import org.transdroid.core.app.search.GoogleWebSearchBarcodeResolver; import org.transdroid.core.app.search.GoogleWebSearchBarcodeResolver;
import android.annotation.SuppressLint;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener; import android.content.DialogInterface.OnClickListener;
@ -41,6 +42,7 @@ public class BarcodeHelper {
* @param activity The calling activity, to which the result is returned or a dialog is bound that asks to install * @param activity The calling activity, to which the result is returned or a dialog is bound that asks to install
* the bar code scanner * the bar code scanner
*/ */
@SuppressLint("ValidFragment")
public static void startBarcodeScanner(final SherlockFragmentActivity activity) { public static void startBarcodeScanner(final SherlockFragmentActivity activity) {
try { try {
// Start a bar code scanner that can handle the SCAN intent (specifically ZXing) // Start a bar code scanner that can handle the SCAN intent (specifically ZXing)

2
core/src/org/transdroid/core/gui/search/FilePickerHelper.java

@ -18,6 +18,7 @@ package org.transdroid.core.gui.search;
import org.transdroid.core.R; import org.transdroid.core.R;
import android.annotation.SuppressLint;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener; import android.content.DialogInterface.OnClickListener;
@ -38,6 +39,7 @@ public class FilePickerHelper {
* @param activity The calling activity, to which the result is returned or a dialog is bound that asks to install * @param activity The calling activity, to which the result is returned or a dialog is bound that asks to install
* the file picker * the file picker
*/ */
@SuppressLint("ValidFragment")
public static void startFilePicker(final SherlockFragmentActivity activity) { public static void startFilePicker(final SherlockFragmentActivity activity) {
try { try {
// Start a file manager that can handle the PICK_FILE intent (specifically IO File Manager) // Start a file manager that can handle the PICK_FILE intent (specifically IO File Manager)

2
core/src/org/transdroid/core/gui/search/UrlEntryDialog.java

@ -19,6 +19,7 @@ package org.transdroid.core.gui.search;
import org.transdroid.core.gui.TorrentsActivity; import org.transdroid.core.gui.TorrentsActivity;
import org.transdroid.core.gui.navigation.NavigationHelper; import org.transdroid.core.gui.navigation.NavigationHelper;
import android.annotation.SuppressLint;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
@ -37,6 +38,7 @@ public class UrlEntryDialog {
* activity's {@link TorrentsActivity#addTorrentByUrl(String, String) method}. * activity's {@link TorrentsActivity#addTorrentByUrl(String, String) method}.
* @param activity The activity that opens (and owns) this dialog * @param activity The activity that opens (and owns) this dialog
*/ */
@SuppressLint("ValidFragment")
public static void startUrlEntry(final TorrentsActivity activity) { public static void startUrlEntry(final TorrentsActivity activity) {
new DialogFragment() { new DialogFragment() {
public android.app.Dialog onCreateDialog(android.os.Bundle savedInstanceState) { public android.app.Dialog onCreateDialog(android.os.Bundle savedInstanceState) {

63
core/src/org/transdroid/core/widget/WidgetConfig.java

@ -0,0 +1,63 @@
/*
* 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.widget;
import org.transdroid.core.gui.navigation.StatusType;
import org.transdroid.daemon.TorrentsSortBy;
/**
* Represents a set of settings that define how the user configured a specific app widget.
* @author Eric Kok
*/
public class WidgetConfig {
private final int serverId;
private final StatusType statusType;
private final TorrentsSortBy sortBy;
private final boolean reserveSort;
private final boolean useDarkTheme;
public WidgetConfig(int serverId, StatusType statusType, TorrentsSortBy sortBy, boolean reverseSort,
boolean useDarkTheme) {
this.serverId = serverId;
this.statusType = statusType;
this.sortBy = sortBy;
this.reserveSort = reverseSort;
this.useDarkTheme = useDarkTheme;
}
public int getServerId() {
return serverId;
}
public StatusType getStatusType() {
return statusType;
}
public TorrentsSortBy getSortBy() {
return sortBy;
}
public boolean shouldReserveSort() {
return reserveSort;
}
public boolean shouldUseDarkTheme() {
return useDarkTheme;
}
}

262
core/src/org/transdroid/core/widget/WidgetConfigActivity.java

@ -0,0 +1,262 @@
/*
* 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.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.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.gui.lists.SimpleListItemSpinnerAdapter;
import org.transdroid.core.gui.lists.SortByListItem;
import org.transdroid.core.gui.lists.TorrentsAdapter;
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.annotation.TargetApi;
import android.appwidget.AppWidgetManager;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
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 com.actionbarsherlock.app.ActionBar;
import com.actionbarsherlock.app.SherlockActivity;
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
@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 ListView torrentsList;
@Bean
protected TorrentsAdapter previewTorrentsAdapter;
private List<Torrent> previewTorrents = null;
// Settings and helpers
@Bean
protected ConnectivityHelper connectivityHelper;
@Bean
protected ApplicationSettings applicationSettings;
private int appWidgetId;
@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<SortByListItem>();
for (TorrentsSortBy order : TorrentsSortBy.values()) {
sortOrders.add(new SortByListItem(this, order));
}
serverSpinner.setAdapter(new SimpleListItemSpinnerAdapter<ServerSetting>(this, 0, applicationSettings
.getServerSettings()));
filterSpinner.setAdapter(new SimpleListItemSpinnerAdapter<StatusTypeFilter>(this, 0, StatusType
.getAllStatusTypes(this)));
sortSpinner.setAdapter(new SimpleListItemSpinnerAdapter<SortByListItem>(this, 0, sortOrders));
// TODO: Update to AndroidAnnotations 3.0 and use @CheckedChanged
reverseorderCheckBox.setOnCheckedChangeListener(reverseorderCheckedChanged);
torrentsList.setAdapter(previewTorrentsAdapter);
torrentsList.setEmptyView(errorText);
// 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 = 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();
}
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<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<Torrent>(previewTorrents.size());
StatusTypeFilter statusTypeFilter = (StatusTypeFilter) filterSpinner.getSelectedItem();
for (Torrent torrent : previewTorrents) {
if (statusTypeFilter.matches(torrent))
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()));
// Finally update the widget preview with the live, filtered and sorted torrents list
previewTorrentsAdapter.update(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);
}
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 useDarkTheme = darkthemeCheckBox.isChecked();
WidgetConfig config = new WidgetConfig(server, statusType, sortBy, reverseSort, useDarkTheme);
applicationSettings.setWidgetConfig(appWidgetId, config);
// Return the widget configuration result
AppWidgetManager manager = AppWidgetManager.getInstance(WidgetConfigActivity.this);
manager.updateAppWidget(appWidgetId,
WidgetProvider.buildRemoteViews(getApplicationContext(), appWidgetId, config));
manager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.torrents_list);
setResult(RESULT_OK, new Intent().putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId));
finish();
}
};
}

143
core/src/org/transdroid/core/widget/WidgetProvider.java

@ -0,0 +1,143 @@
/*
* 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.widget;
import org.androidannotations.annotations.Bean;
import org.androidannotations.annotations.EReceiver;
import org.transdroid.core.R;
import org.transdroid.core.app.settings.*;
import org.transdroid.core.gui.*;
import org.transdroid.core.gui.log.Log;
import android.annotation.TargetApi;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.widget.RemoteViews;
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
@EReceiver
public class WidgetProvider extends AppWidgetProvider {
public static final String INTENT_STARTSERVER = "org.transdroid.START_SERVER";
public static final String EXTRA_TORRENT = "extra_torrent";
public static final String EXTRA_SERVER = "extra_server";
public static final String EXTRA_REFRESH = "extra_refresh";
@Bean
protected ApplicationSettings applicationSettings;
@Override
public void onReceive(Context context, Intent intent) {
if (intent != null && intent.hasExtra(EXTRA_REFRESH)) {
// Manually requested a refresh for the app widget of which the ID was supplied
int appWidgetId = intent.getIntExtra(EXTRA_REFRESH, -1);
AppWidgetManager.getInstance(context).updateAppWidget(appWidgetId,
buildRemoteViews(context, appWidgetId, applicationSettings.getWidgetConfig(appWidgetId)));
AppWidgetManager.getInstance(context).notifyAppWidgetViewDataChanged(appWidgetId, R.id.torrents_list);
return;
}
super.onReceive(context, intent);
}
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
for (int appWidgetId : appWidgetIds) {
appWidgetManager.updateAppWidget(appWidgetId,
buildRemoteViews(context, appWidgetId, applicationSettings.getWidgetConfig(appWidgetId)));
appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.torrents_list);
}
}
@Override
public void onDeleted(Context context, int[] appWidgetIds) {
for (int appWidgetId : appWidgetIds) {
applicationSettings.removeWidgetConfig(appWidgetId);
}
}
/**
* Loads and sets up the layout for some specific app widget given the user's widget settings. Note that the views
* for the list view rows are loaded separately in the {@link WidgetViewsFactory}.
* @param context The app widget context, with access to resources
* @param appWidgetId The specific ID of the app widget to load
* @param config The user widget configuration, with filter and theme preferences
* @return A fully initialised set of remote views to update the widget with the AppWidgetManager
*/
@SuppressWarnings("deprecation")
public static RemoteViews buildRemoteViews(Context context, int appWidgetId, WidgetConfig config) {
// Does the server to show and its widget settings actually still exist?
if (context == null || config == null)
return null;
ApplicationSettings appSettings = ApplicationSettings_.getInstance_(context);
if (config.getServerId() < 0 || config.getServerId() > appSettings.getMaxServer()) {
Log.e(context, "Tried to set up widget " + appWidgetId + " but the bound server ID " + config.getServerId()
+ " no longer exists.");
return null;
}
// Load the dark or light widget layout xml
RemoteViews rv = new RemoteViews(context.getPackageName(),
config.shouldUseDarkTheme() ? R.layout.widget_torrents_dark : R.layout.widget_torrents_light);
// Set up the widget's list view loading service which refers to the WidgetViewsFactory
Intent data = new Intent(context, WidgetService_.class);
data.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
data.setData(Uri.parse(data.toUri(Intent.URI_INTENT_SCHEME)));
rv.setRemoteAdapter(appWidgetId, R.id.torrents_list, data);
Intent open = new Intent(context, TorrentsActivity_.class);
open.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
rv.setPendingIntentTemplate(R.id.torrents_list,
PendingIntent.getActivity(context, appWidgetId, open, PendingIntent.FLAG_UPDATE_CURRENT));
rv.setEmptyView(R.id.torrents_list, R.id.error_text);
rv.setTextViewText(R.id.error_text, context.getString(R.string.widget_loading));
// Show the server and status type filter from the widget configuration in the 'action bar'
ServerSetting server = appSettings.getServerSetting(config.getServerId());
rv.setTextViewText(R.id.server_text, server.getName());
rv.setTextViewText(R.id.filter_text, config.getStatusType().getFilterItem(context).getName());
// Set up the START_SERVER intent for 'action bar' clicks to start Transdroid normally
Intent start = new Intent(context, TorrentsActivity_.class);
//start.setData(Uri.parse("intent://widget/" + appWidgetId + "/start/" + config.getServerId()));
start.setAction(INTENT_STARTSERVER);
start.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
start.putExtra(EXTRA_SERVER, config.getServerId());
rv.setOnClickPendingIntent(R.id.icon_image,
PendingIntent.getActivity(context, appWidgetId, start, PendingIntent.FLAG_UPDATE_CURRENT));
rv.setOnClickPendingIntent(R.id.navigation_view,
PendingIntent.getActivity(context, appWidgetId, start, PendingIntent.FLAG_UPDATE_CURRENT));
// Set up the widgets refresh button pending intent (calling this WidgetProvider itself)
// Make sure that the intent is unique using a custom data path (rather than just the extras)
Intent refresh = new Intent(context, WidgetProvider_.class);
refresh.setData(Uri.parse("intent://widget/" + appWidgetId + "/refresh"));
refresh.putExtra(EXTRA_REFRESH, appWidgetId);
refresh.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
rv.setOnClickPendingIntent(R.id.refresh_button,
PendingIntent.getBroadcast(context, appWidgetId, refresh, PendingIntent.FLAG_UPDATE_CURRENT));
return rv;
}
}

198
core/src/org/transdroid/core/widget/WidgetService.java

@ -0,0 +1,198 @@
/*
* 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.widget;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.androidannotations.annotations.EService;
import org.transdroid.core.R;
import org.transdroid.core.app.settings.*;
import org.transdroid.core.app.settings.ServerSetting;
import org.transdroid.core.gui.lists.LocalTorrent;
import org.transdroid.core.gui.log.Log;
import org.transdroid.core.service.*;
import org.transdroid.daemon.Daemon;
import org.transdroid.daemon.IDaemonAdapter;
import org.transdroid.daemon.Torrent;
import org.transdroid.daemon.TorrentsComparator;
import org.transdroid.daemon.task.DaemonTaskResult;
import org.transdroid.daemon.task.RetrieveTask;
import org.transdroid.daemon.task.RetrieveTaskSuccessResult;
import android.annotation.TargetApi;
import android.appwidget.AppWidgetManager;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.widget.RemoteViews;
import android.widget.RemoteViewsService;
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
@EService
public class WidgetService extends RemoteViewsService {
@Override
public RemoteViewsFactory onGetViewFactory(Intent intent) {
return new WidgetViewsFactory(this.getApplicationContext(), intent);
}
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
class WidgetViewsFactory implements RemoteViewsService.RemoteViewsFactory {
private final Context context;
private final int appWidgetId;
private List<Torrent> torrents = null;
private WidgetConfig config = null;
public WidgetViewsFactory(Context applicationContext, Intent intent) {
this.context = applicationContext;
this.appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);
}
@Override
public void onCreate() {
// Nothing to do here (wait for onDataSetChanged)
}
@Override
public void onDataSetChanged() {
// Load the widget settings
ApplicationSettings settings = ApplicationSettings_.getInstance_(context);
config = settings.getWidgetConfig(appWidgetId);
if (config == null || config.getServerId() < 0) {
Log.e(context, "Looking for widget data while the widget wasn't yet configured");
return;
}
ServerSetting server = settings.getServerSetting(config.getServerId());
if (server == null) {
// TODO: Show error text some how in the remote view, perhaps via the EmptyView's text?
Log.e(context, "The server for which this widget was created no longer exists");
if (torrents != null)
torrents.clear();
return;
}
// Load the torrents; synchronously
IDaemonAdapter connection = server.createServerAdapter(ConnectivityHelper_.getInstance_(context)
.getConnectedNetworkName());
DaemonTaskResult result = RetrieveTask.create(connection).execute();
if (!(result instanceof RetrieveTaskSuccessResult)) {
// TODO: Show error text somehow in the remote view, perhaps via the EmptyView's text?
Log.e(context, "The torrents could not be retrieved at this time; probably a connection issue");
if (torrents != null)
torrents.clear();
return;
}
// We have data; filter, sort and store it to use later when getViewAt gets called
ArrayList<Torrent> filteredTorrents = new ArrayList<Torrent>();
for (Torrent torrent : ((RetrieveTaskSuccessResult) result).getTorrents()) {
if (config.getStatusType().getFilterItem(context).matches(torrent))
filteredTorrents.add(torrent);
}
if (filteredTorrents.size() > 0) {
// Only sort when there are actually torrents left after filtering
Daemon serverType = filteredTorrents.get(0).getDaemon();
Collections.sort(filteredTorrents,
new TorrentsComparator(serverType, config.getSortBy(), config.shouldReserveSort()));
}
torrents = filteredTorrents;
}
@Override
public RemoteViews getViewAt(int position) {
// Load the dark or light widget list item layout xml
RemoteViews rv = new RemoteViews(context.getPackageName(),
config.shouldUseDarkTheme() ? R.layout.list_item_widget_dark : R.layout.list_item_widget_light);
// Bind the torrent details texts and status colour
Torrent torrent = torrents.get(position);
LocalTorrent local = LocalTorrent.fromTorrent(torrent);
rv.setTextViewText(R.id.name_text, torrent.getName());
rv.setTextViewText(R.id.progress_text, local.getProgressSizeText(context.getResources(), false));
rv.setTextViewText(R.id.ratio_text, local.getProgressEtaRatioText(context.getResources()));
int statusColour;
switch (torrent.getStatusCode()) {
case Downloading:
statusColour = R.color.torrent_downloading;
break;
case Paused:
statusColour = R.color.torrent_paused;
break;
case Seeding:
statusColour = R.color.torrent_seeding;
break;
case Error:
statusColour = R.color.torrent_error;
break;
default: // Checking, Waiting, Queued, Unknown
statusColour = R.color.torrent_other;
break;
}
rv.setInt(R.id.status_view, "setBackgroundColor", context.getResources().getColor(statusColour));
Intent startIntent = new Intent();
startIntent.putExtra(WidgetProvider.EXTRA_SERVER, config.getServerId());
startIntent.putExtra(WidgetProvider.EXTRA_TORRENT, torrent);
rv.setOnClickFillInIntent(R.id.widget_line_layout, startIntent);
return rv;
}
@Override
public RemoteViews getLoadingView() {
return null;
}
@Override
public void onDestroy() {
if (torrents != null)
torrents.clear();
torrents = null;
}
@Override
public int getViewTypeCount() {
return 1;
}
@Override
public boolean hasStableIds() {
return true;
}
@Override
public int getCount() {
if (torrents == null)
return 0;
return torrents.size();
}
@Override
public long getItemId(int position) {
return position;
}
}

38
full/AndroidManifest.xml

@ -17,8 +17,8 @@
--> -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.transdroid.full" package="org.transdroid.full"
android:versionCode="5" android:versionCode="6"
android:versionName="2.0-beta1" > android:versionName="2.0" >
<uses-sdk <uses-sdk
android:minSdkVersion="7" android:minSdkVersion="7"
@ -52,6 +52,7 @@
<!-- Main activities --> <!-- Main activities -->
<activity <activity
android:name="org.transdroid.core.gui.TorrentsActivity_" android:name="org.transdroid.core.gui.TorrentsActivity_"
android:allowTaskReparenting="true"
android:label="@string/app_name" android:label="@string/app_name"
android:theme="@style/TransdroidTheme" android:theme="@style/TransdroidTheme"
android:uiOptions="splitActionBarWhenNarrow" > android:uiOptions="splitActionBarWhenNarrow" >
@ -68,6 +69,11 @@
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
</intent-filter> </intent-filter>
<intent-filter>
<action android:name="org.transdroid.START_SERVER" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<intent-filter> <intent-filter>
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
@ -240,6 +246,34 @@
android:value="android.intent.action.BOOT_COMPLETED" /> android:value="android.intent.action.BOOT_COMPLETED" />
</intent-filter> </intent-filter>
</receiver> </receiver>
<!-- Home screen widget -->
<activity
android:name="org.transdroid.core.widget.WidgetConfigActivity_"
android:theme="@style/TransdroidTheme.WidgetConfig"
android:enabled="@bool/widget_available" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
</intent-filter>
</activity>
<service
android:name="org.transdroid.core.widget.WidgetService_"
android:enabled="@bool/widget_available"
android:exported="false"
android:permission="android.permission.BIND_REMOTEVIEWS" />
<receiver
android:name="org.transdroid.core.widget.WidgetProvider_"
android:enabled="@bool/widget_available" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/appwidget_info" />
</receiver>
</application> </application>
</manifest> </manifest>

38
lite/AndroidManifest.xml

@ -17,8 +17,8 @@
--> -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.transdroid.lite" package="org.transdroid.lite"
android:versionCode="5" android:versionCode="6"
android:versionName="2.0-beta1" > android:versionName="2.0" >
<uses-sdk <uses-sdk
android:minSdkVersion="7" android:minSdkVersion="7"
@ -52,6 +52,7 @@
<!-- Main activities --> <!-- Main activities -->
<activity <activity
android:name="org.transdroid.core.gui.TorrentsActivity_" android:name="org.transdroid.core.gui.TorrentsActivity_"
android:allowTaskReparenting="true"
android:label="@string/app_name" android:label="@string/app_name"
android:theme="@style/TransdroidTheme" android:theme="@style/TransdroidTheme"
android:uiOptions="splitActionBarWhenNarrow" > android:uiOptions="splitActionBarWhenNarrow" >
@ -68,6 +69,11 @@
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
</intent-filter> </intent-filter>
<intent-filter>
<action android:name="org.transdroid.START_SERVER" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<intent-filter> <intent-filter>
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
@ -193,6 +199,34 @@
android:value="android.intent.action.BOOT_COMPLETED" /> android:value="android.intent.action.BOOT_COMPLETED" />
</intent-filter> </intent-filter>
</receiver> </receiver>
<!-- Home screen widget -->
<activity
android:name="org.transdroid.core.widget.WidgetConfigActivity_"
android:enabled="@bool/widget_available" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
</intent-filter>
</activity>
<service
android:name="org.transdroid.core.widget.WidgetService_"
android:enabled="@bool/widget_available"
android:exported="false"
android:permission="android.permission.BIND_REMOTEVIEWS" />
<receiver
android:name="org.transdroid.core.widget.WidgetProvider_"
android:theme="@style/TransdroidTheme.WidgetConfig"
android:enabled="@bool/widget_available" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/appwidget_info" />
</receiver>
</application> </application>
</manifest> </manifest>
Loading…
Cancel
Save