summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AndroidManifest.xml49
-rw-r--r--assets/Roboto-Light.ttfbin0 -> 115200 bytes
-rw-r--r--assets/Roboto.ttfbin0 -> 114976 bytes
-rw-r--r--res/drawable-hdpi/ic_action_overflow.pngbin0 -> 225 bytes
-rw-r--r--res/drawable-hdpi/ic_action_overflow_dark.pngbin0 -> 217 bytes
-rwxr-xr-xres/drawable-hdpi/ic_drag_handle.pngbin0 -> 220 bytes
-rwxr-xr-xres/drawable-hdpi/ic_drag_handle_dark.pngbin0 -> 204 bytes
-rw-r--r--res/drawable-hdpi/ic_drawer.pngbin0 -> 2829 bytes
-rw-r--r--res/drawable-hdpi/ic_drawer_dark.pngbin0 -> 2826 bytes
-rw-r--r--res/drawable-mdpi/ic_action_overflow.pngbin0 -> 197 bytes
-rw-r--r--res/drawable-mdpi/ic_action_overflow_dark.pngbin0 -> 201 bytes
-rwxr-xr-xres/drawable-mdpi/ic_drag_handle.pngbin0 -> 175 bytes
-rwxr-xr-xres/drawable-mdpi/ic_drag_handle_dark.pngbin0 -> 159 bytes
-rw-r--r--res/drawable-mdpi/ic_drawer.pngbin0 -> 2820 bytes
-rw-r--r--res/drawable-mdpi/ic_drawer_dark.pngbin0 -> 2816 bytes
-rw-r--r--res/drawable-xhdpi/ic_action_overflow.pngbin0 -> 267 bytes
-rw-r--r--res/drawable-xhdpi/ic_action_overflow_dark.pngbin0 -> 262 bytes
-rwxr-xr-xres/drawable-xhdpi/ic_drag_handle.pngbin0 -> 234 bytes
-rwxr-xr-xres/drawable-xhdpi/ic_drag_handle_dark.pngbin0 -> 216 bytes
-rw-r--r--res/drawable-xhdpi/ic_drawer.pngbin0 -> 2836 bytes
-rw-r--r--res/drawable-xhdpi/ic_drawer_dark.pngbin0 -> 1038 bytes
-rw-r--r--res/drawable-xxhdpi/ic_action_overflow.pngbin0 -> 264 bytes
-rw-r--r--res/drawable-xxhdpi/ic_action_overflow_dark.pngbin0 -> 264 bytes
-rwxr-xr-xres/drawable-xxhdpi/ic_drag_handle.pngbin0 -> 290 bytes
-rwxr-xr-xres/drawable-xxhdpi/ic_drag_handle_dark.pngbin0 -> 265 bytes
-rw-r--r--res/drawable-xxhdpi/ic_drawer.pngbin0 -> 202 bytes
-rw-r--r--res/drawable-xxhdpi/ic_drawer_dark.pngbin0 -> 202 bytes
-rw-r--r--res/layout-land/audioplayer_activity.xml353
-rw-r--r--res/layout/addfeed.xml30
-rw-r--r--res/layout/audioplayer_activity.xml343
-rw-r--r--res/layout/downloaded_episodeslist_item.xml111
-rw-r--r--res/layout/downloadlist_item.xml99
-rw-r--r--res/layout/external_player_fragment.xml57
-rw-r--r--res/layout/feedinfo.xml10
-rw-r--r--res/layout/feeditem_dialog.xml55
-rw-r--r--res/layout/feeditemlist_header.xml97
-rw-r--r--res/layout/feeditemlist_item.xml258
-rw-r--r--res/layout/gpodnetauth_credentials.xml4
-rw-r--r--res/layout/gpodnetauth_device.xml4
-rw-r--r--res/layout/gpodnetauth_finish.xml4
-rw-r--r--res/layout/main.xml51
-rw-r--r--res/layout/nav_feedlistitem.xml38
-rw-r--r--res/layout/nav_listitem.xml20
-rw-r--r--res/layout/nav_section_item.xml26
-rw-r--r--res/layout/new_episodes_fragment.xml45
-rw-r--r--res/layout/new_episodes_listdivider.xml16
-rw-r--r--res/layout/new_episodes_listitem.xml130
-rw-r--r--res/layout/onlinefeedview_header.xml3
-rw-r--r--res/layout/pager_fragment.xml12
-rw-r--r--res/layout/queue_fragment.xml58
-rw-r--r--res/layout/queue_listitem.xml130
-rw-r--r--res/layout/searchlist_item.xml28
-rw-r--r--res/menu/feeditem_dialog.xml48
-rw-r--r--res/menu/feedlist.xml24
-rw-r--r--res/menu/main.xml35
-rw-r--r--res/menu/new_episodes.xml20
-rw-r--r--res/values-v16/styles.xml9
-rw-r--r--res/values-v19/colors.xml5
-rw-r--r--res/values/attrs.xml69
-rw-r--r--res/values/dimens.xml6
-rw-r--r--res/values/strings.xml23
-rw-r--r--res/values/styles.xml77
-rw-r--r--src/de/danoeh/antennapod/activity/AddFeedActivity.java1
-rw-r--r--src/de/danoeh/antennapod/activity/AudioplayerActivity.java142
-rw-r--r--src/de/danoeh/antennapod/activity/DownloadActivity.java4
-rw-r--r--src/de/danoeh/antennapod/activity/FeedItemlistActivity.java2
-rw-r--r--src/de/danoeh/antennapod/activity/MainActivity.java445
-rw-r--r--src/de/danoeh/antennapod/activity/SearchActivity.java8
-rw-r--r--src/de/danoeh/antennapod/adapter/ActionButtonUtils.java63
-rw-r--r--src/de/danoeh/antennapod/adapter/DefaultActionButtonCallback.java49
-rw-r--r--src/de/danoeh/antennapod/adapter/DownloadedEpisodesListAdapter.java124
-rw-r--r--src/de/danoeh/antennapod/adapter/DownloadlistAdapter.java207
-rw-r--r--src/de/danoeh/antennapod/adapter/ExternalEpisodesListAdapter.java4
-rw-r--r--src/de/danoeh/antennapod/adapter/InternalFeedItemlistAdapter.java74
-rw-r--r--src/de/danoeh/antennapod/adapter/NavListAdapter.java186
-rw-r--r--src/de/danoeh/antennapod/adapter/NewEpisodesListAdapter.java217
-rw-r--r--src/de/danoeh/antennapod/adapter/QueueListAdapter.java155
-rw-r--r--src/de/danoeh/antennapod/adapter/SearchlistAdapter.java38
-rw-r--r--src/de/danoeh/antennapod/asynctask/DownloadObserver.java40
-rw-r--r--src/de/danoeh/antennapod/dialog/FeedItemDialog.java335
-rw-r--r--src/de/danoeh/antennapod/fragment/AddFeedFragment.java76
-rw-r--r--src/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java164
-rw-r--r--src/de/danoeh/antennapod/fragment/DownloadLogFragment.java121
-rw-r--r--src/de/danoeh/antennapod/fragment/DownloadsFragment.java145
-rw-r--r--src/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java14
-rw-r--r--src/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java2
-rw-r--r--src/de/danoeh/antennapod/fragment/ItemlistFragment.java601
-rw-r--r--src/de/danoeh/antennapod/fragment/NewEpisodesFragment.java381
-rw-r--r--src/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java323
-rw-r--r--src/de/danoeh/antennapod/fragment/QueueFragment.java349
-rw-r--r--src/de/danoeh/antennapod/fragment/RunningDownloadsFragment.java69
-rw-r--r--src/de/danoeh/antennapod/fragment/SearchFragment.java247
-rw-r--r--src/de/danoeh/antennapod/fragment/gpodnet/GpodnetMainFragment.java131
-rw-r--r--src/de/danoeh/antennapod/fragment/gpodnet/PodcastListFragment.java37
-rw-r--r--src/de/danoeh/antennapod/fragment/gpodnet/SearchListFragment.java31
-rw-r--r--src/de/danoeh/antennapod/fragment/gpodnet/TagFragment.java47
-rw-r--r--src/de/danoeh/antennapod/fragment/gpodnet/TagListFragment.java42
-rw-r--r--src/de/danoeh/antennapod/service/download/DownloadService.java25
-rw-r--r--src/de/danoeh/antennapod/storage/DBReader.java26
-rw-r--r--src/de/danoeh/antennapod/storage/PodDBAdapter.java5
-rw-r--r--src/de/danoeh/antennapod/util/gui/FeedItemUndoToken.java55
-rw-r--r--src/de/danoeh/antennapod/util/menuhandler/MenuItemUtils.java20
102 files changed, 5853 insertions, 1499 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index c14d4bfe7..cce892747 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -45,28 +45,12 @@
<activity
android:name=".activity.MainActivity"
android:configChanges="keyboardHidden|orientation"
+ android:launchMode="singleTask"
android:label="@string/app_name">
- <meta-data
- android:name="android.app.default_searchable"
- android:value="de.danoeh.antennapod.activity.SearchActivity"/>
- <meta-data
- android:name="android.app.searchable"
- android:resource="@xml/searchable"/>
-
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
- </activity>
- <activity
- android:name="de.danoeh.antennapod.activity.AddFeedActivity"
- android:configChanges="keyboardHidden|orientation"
- android:label="@string/add_new_feed_label"
- android:windowSoftInputMode="adjustResize">
- <meta-data
- android:name="android.support.PARENT_ACTIVITY"
- android:value="de.danoeh.antennapod.activity.MainActivity"/>
-
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
@@ -114,6 +98,18 @@
<data android:mimeType="text/plain"/>
</intent-filter>
+
+ </activity>
+ <activity
+ android:name="de.danoeh.antennapod.activity.AddFeedActivity"
+ android:configChanges="keyboardHidden|orientation"
+ android:label="@string/add_new_feed_label"
+ android:windowSoftInputMode="adjustResize">
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value="de.danoeh.antennapod.activity.MainActivity"/>
+
+
</activity>
<activity
android:name="de.danoeh.antennapod.activity.FeedItemlistActivity"
@@ -121,12 +117,6 @@
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="de.danoeh.antennapod.activity.MainActivity"/>
- <meta-data
- android:name="android.app.default_searchable"
- android:value="de.danoeh.antennapod.activity.SearchActivity"/>
- <meta-data
- android:name="android.app.searchable"
- android:resource="@xml/searchable"/>
</activity>
<activity
android:name="de.danoeh.antennapod.activity.ItemviewActivity"
@@ -296,19 +286,6 @@
android:label="@string/opml_import_label">
</activity>
<activity
- android:name=".activity.SearchActivity"
- android:configChanges="keyboardHidden|orientation"
- android:label="@string/search_results_label"
- android:launchMode="singleTop">
- <intent-filter>
- <action android:name="android.intent.action.SEARCH"/>
- </intent-filter>
-
- <meta-data
- android:name="android.app.searchable"
- android:resource="@xml/searchable"/>
- </activity>
- <activity
android:name=".activity.MiroGuideMainActivity"
android:label="@string/miro_guide_label">
<meta-data
diff --git a/assets/Roboto-Light.ttf b/assets/Roboto-Light.ttf
new file mode 100644
index 000000000..13bf13af0
--- /dev/null
+++ b/assets/Roboto-Light.ttf
Binary files differ
diff --git a/assets/Roboto.ttf b/assets/Roboto.ttf
new file mode 100644
index 000000000..0ba95c98c
--- /dev/null
+++ b/assets/Roboto.ttf
Binary files differ
diff --git a/res/drawable-hdpi/ic_action_overflow.png b/res/drawable-hdpi/ic_action_overflow.png
new file mode 100644
index 000000000..002fc4bfb
--- /dev/null
+++ b/res/drawable-hdpi/ic_action_overflow.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_action_overflow_dark.png b/res/drawable-hdpi/ic_action_overflow_dark.png
new file mode 100644
index 000000000..c8792cbe2
--- /dev/null
+++ b/res/drawable-hdpi/ic_action_overflow_dark.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_drag_handle.png b/res/drawable-hdpi/ic_drag_handle.png
new file mode 100755
index 000000000..38ec201de
--- /dev/null
+++ b/res/drawable-hdpi/ic_drag_handle.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_drag_handle_dark.png b/res/drawable-hdpi/ic_drag_handle_dark.png
new file mode 100755
index 000000000..e96d23252
--- /dev/null
+++ b/res/drawable-hdpi/ic_drag_handle_dark.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_drawer.png b/res/drawable-hdpi/ic_drawer.png
new file mode 100644
index 000000000..c59f601ca
--- /dev/null
+++ b/res/drawable-hdpi/ic_drawer.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_drawer_dark.png b/res/drawable-hdpi/ic_drawer_dark.png
new file mode 100644
index 000000000..6614ea4f4
--- /dev/null
+++ b/res/drawable-hdpi/ic_drawer_dark.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_action_overflow.png b/res/drawable-mdpi/ic_action_overflow.png
new file mode 100644
index 000000000..6f0fb23f4
--- /dev/null
+++ b/res/drawable-mdpi/ic_action_overflow.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_action_overflow_dark.png b/res/drawable-mdpi/ic_action_overflow_dark.png
new file mode 100644
index 000000000..b4a4a221f
--- /dev/null
+++ b/res/drawable-mdpi/ic_action_overflow_dark.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_drag_handle.png b/res/drawable-mdpi/ic_drag_handle.png
new file mode 100755
index 000000000..4afbdc67d
--- /dev/null
+++ b/res/drawable-mdpi/ic_drag_handle.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_drag_handle_dark.png b/res/drawable-mdpi/ic_drag_handle_dark.png
new file mode 100755
index 000000000..2b25c4101
--- /dev/null
+++ b/res/drawable-mdpi/ic_drag_handle_dark.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_drawer.png b/res/drawable-mdpi/ic_drawer.png
new file mode 100644
index 000000000..1ed2c56ee
--- /dev/null
+++ b/res/drawable-mdpi/ic_drawer.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_drawer_dark.png b/res/drawable-mdpi/ic_drawer_dark.png
new file mode 100644
index 000000000..b05c026c1
--- /dev/null
+++ b/res/drawable-mdpi/ic_drawer_dark.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_action_overflow.png b/res/drawable-xhdpi/ic_action_overflow.png
new file mode 100644
index 000000000..7ba4e10ea
--- /dev/null
+++ b/res/drawable-xhdpi/ic_action_overflow.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_action_overflow_dark.png b/res/drawable-xhdpi/ic_action_overflow_dark.png
new file mode 100644
index 000000000..5d8af5d63
--- /dev/null
+++ b/res/drawable-xhdpi/ic_action_overflow_dark.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_drag_handle.png b/res/drawable-xhdpi/ic_drag_handle.png
new file mode 100755
index 000000000..5bdcac342
--- /dev/null
+++ b/res/drawable-xhdpi/ic_drag_handle.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_drag_handle_dark.png b/res/drawable-xhdpi/ic_drag_handle_dark.png
new file mode 100755
index 000000000..d341c7c82
--- /dev/null
+++ b/res/drawable-xhdpi/ic_drag_handle_dark.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_drawer.png b/res/drawable-xhdpi/ic_drawer.png
new file mode 100644
index 000000000..a5fa74def
--- /dev/null
+++ b/res/drawable-xhdpi/ic_drawer.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_drawer_dark.png b/res/drawable-xhdpi/ic_drawer_dark.png
new file mode 100644
index 000000000..bcf49dd73
--- /dev/null
+++ b/res/drawable-xhdpi/ic_drawer_dark.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_action_overflow.png b/res/drawable-xxhdpi/ic_action_overflow.png
new file mode 100644
index 000000000..5a603b6bc
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_action_overflow.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_action_overflow_dark.png b/res/drawable-xxhdpi/ic_action_overflow_dark.png
new file mode 100644
index 000000000..e22049b1e
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_action_overflow_dark.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_drag_handle.png b/res/drawable-xxhdpi/ic_drag_handle.png
new file mode 100755
index 000000000..f834699c6
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_drag_handle.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_drag_handle_dark.png b/res/drawable-xxhdpi/ic_drag_handle_dark.png
new file mode 100755
index 000000000..a9408bc9d
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_drag_handle_dark.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_drawer.png b/res/drawable-xxhdpi/ic_drawer.png
new file mode 100644
index 000000000..9c4685d6e
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_drawer.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_drawer_dark.png b/res/drawable-xxhdpi/ic_drawer_dark.png
new file mode 100644
index 000000000..f7e3b3079
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_drawer_dark.png
Binary files differ
diff --git a/res/layout-land/audioplayer_activity.xml b/res/layout-land/audioplayer_activity.xml
index 7900e1ced..8f8fdbee3 100644
--- a/res/layout-land/audioplayer_activity.xml
+++ b/res/layout-land/audioplayer_activity.xml
@@ -1,178 +1,197 @@
<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<android.support.v4.widget.DrawerLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/drawer_layout"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="horizontal" >
+ android:layout_height="match_parent">
- <FrameLayout
- android:id="@+id/contentView"
- android:layout_width="0dp"
+ <LinearLayout
+ android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_weight="0.5" >
- </FrameLayout>
+ android:orientation="horizontal">
- <RelativeLayout
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="0.5"
- android:background="?attr/non_transparent_background"
- android:orientation="vertical" >
+ <FrameLayout
+ android:id="@+id/contentView"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="0.5">
+ </FrameLayout>
<RelativeLayout
- android:id="@+id/navBar"
- android:layout_width="fill_parent"
- android:layout_height="60dp"
- android:layout_alignParentTop="true" >
-
- <ImageButton
- android:id="@+id/butNavLeft"
- android:contentDescription="@string/show_shownotes_label"
- android:layout_width="60dp"
- android:layout_height="match_parent"
- android:layout_alignParentLeft="true"
- android:background="?attr/borderless_button"
- android:padding="4dp" />
-
- <ImageButton
- android:id="@+id/butNavRight"
- android:contentDescription="@string/show_chapters_label"
- android:layout_width="60dp"
- android:layout_height="match_parent"
- android:layout_alignParentRight="true"
- android:background="?attr/borderless_button"
- android:padding="4dp" />
-
- <TextView
- android:id="@+id/txtvTitle"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentTop="true"
- android:layout_marginLeft="8dp"
- android:layout_marginRight="8dp"
- android:layout_marginTop="8dp"
- android:layout_toLeftOf="@id/butNavRight"
- android:layout_toRightOf="@id/butNavLeft"
- android:ellipsize="marquee"
- android:marqueeRepeatLimit="marquee_forever"
- android:maxLines="1"
- android:textColor="?android:attr/textColorPrimary"
- android:textSize="@dimen/text_size_medium"
- android:textStyle="bold" />
-
- <TextView
- android:id="@+id/txtvFeed"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_below="@id/txtvTitle"
- android:layout_marginLeft="8dp"
- android:layout_marginRight="8dp"
- android:layout_toLeftOf="@id/butNavRight"
- android:layout_toRightOf="@id/butNavLeft"
- android:ellipsize="marquee"
- android:marqueeRepeatLimit="marquee_forever"
- android:maxLines="1"
- android:textColor="?android:attr/textColorSecondary"
- android:textSize="@dimen/text_size_small" />
- </RelativeLayout>
-
- <View
- android:id="@+id/navBarDivider"
- android:layout_width="match_parent"
- android:layout_height="1dp"
- android:layout_below="@id/navBar"
- android:background="@color/bright_blue" />
-
- <RelativeLayout
- android:id="@+id/player_control"
- android:layout_width="match_parent"
- android:layout_height="80dp"
- android:layout_alignParentBottom="true"
- android:background="?attr/overlay_background" >
-
- <ImageButton
- android:id="@+id/butPlay"
- android:contentDescription="@string/pause_label"
- android:layout_width="80dp"
- android:layout_height="match_parent"
- android:layout_centerHorizontal="true"
- android:background="?attr/borderless_button"
- android:src="?attr/av_pause" />
-
- <ImageButton
- android:id="@+id/butRev"
- android:contentDescription="@string/rewind_label"
- android:layout_width="60dp"
- android:layout_height="match_parent"
- android:layout_toLeftOf="@id/butPlay"
- android:background="?attr/borderless_button"
- android:src="?attr/av_rewind" />
-
- <ImageButton
- android:id="@+id/butFF"
- android:contentDescription="@string/fast_forward_label"
- android:layout_width="60dp"
- android:layout_height="match_parent"
- android:layout_toRightOf="@id/butPlay"
- android:background="?attr/borderless_button"
- android:src="?attr/av_fast_forward" />
-
- <Button
- android:id="@+id/butPlaybackSpeed"
- android:layout_width="60dp"
- android:layout_height="match_parent"
- android:layout_toRightOf="@id/butFF"
- android:background="?attr/borderless_button"
- android:src="?attr/av_fast_forward"
- android:textColor="@color/gray"
- android:textSize="@dimen/text_size_medium"
- android:visibility="gone" />
- </RelativeLayout>
-
- <RelativeLayout
- android:id="@+id/playtime_layout"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_above="@id/player_control"
- android:layout_alignParentLeft="true"
- android:background="?attr/overlay_drawable" >
-
- <TextView
- android:id="@+id/txtvPosition"
- android:layout_width="wrap_content"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="0.5"
+ android:background="?attr/non_transparent_background"
+ android:orientation="vertical">
+
+ <RelativeLayout
+ android:id="@+id/navBar"
+ android:layout_width="fill_parent"
+ android:layout_height="60dp"
+ android:layout_alignParentTop="true">
+
+ <ImageButton
+ android:id="@+id/butNavLeft"
+ android:contentDescription="@string/show_shownotes_label"
+ android:layout_width="60dp"
+ android:layout_height="match_parent"
+ android:layout_alignParentLeft="true"
+ android:background="?attr/borderless_button"
+ android:padding="4dp"/>
+
+ <ImageButton
+ android:id="@+id/butNavRight"
+ android:contentDescription="@string/show_chapters_label"
+ android:layout_width="60dp"
+ android:layout_height="match_parent"
+ android:layout_alignParentRight="true"
+ android:background="?attr/borderless_button"
+ android:padding="4dp"/>
+
+ <TextView
+ android:id="@+id/txtvTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentTop="true"
+ android:layout_marginLeft="8dp"
+ android:layout_marginRight="8dp"
+ android:layout_marginTop="8dp"
+ android:layout_toLeftOf="@id/butNavRight"
+ android:layout_toRightOf="@id/butNavLeft"
+ android:ellipsize="marquee"
+ android:marqueeRepeatLimit="marquee_forever"
+ android:maxLines="1"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textSize="@dimen/text_size_medium"
+ android:textStyle="bold"/>
+
+ <TextView
+ android:id="@+id/txtvFeed"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/txtvTitle"
+ android:layout_marginLeft="8dp"
+ android:layout_marginRight="8dp"
+ android:layout_toLeftOf="@id/butNavRight"
+ android:layout_toRightOf="@id/butNavLeft"
+ android:ellipsize="marquee"
+ android:marqueeRepeatLimit="marquee_forever"
+ android:maxLines="1"
+ android:textColor="?android:attr/textColorSecondary"
+ android:textSize="@dimen/text_size_small"/>
+ </RelativeLayout>
+
+ <View
+ android:id="@+id/navBarDivider"
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:layout_below="@id/navBar"
+ android:background="@color/bright_blue"/>
+
+ <RelativeLayout
+ android:id="@+id/player_control"
+ android:layout_width="match_parent"
+ android:layout_height="80dp"
+ android:layout_alignParentBottom="true"
+ android:background="?attr/overlay_background">
+
+ <ImageButton
+ android:id="@+id/butPlay"
+ android:contentDescription="@string/pause_label"
+ android:layout_width="80dp"
+ android:layout_height="match_parent"
+ android:layout_centerHorizontal="true"
+ android:background="?attr/borderless_button"
+ android:src="?attr/av_pause"/>
+
+ <ImageButton
+ android:id="@+id/butRev"
+ android:contentDescription="@string/rewind_label"
+ android:layout_width="60dp"
+ android:layout_height="match_parent"
+ android:layout_toLeftOf="@id/butPlay"
+ android:background="?attr/borderless_button"
+ android:src="?attr/av_rewind"/>
+
+ <ImageButton
+ android:id="@+id/butFF"
+ android:contentDescription="@string/fast_forward_label"
+ android:layout_width="60dp"
+ android:layout_height="match_parent"
+ android:layout_toRightOf="@id/butPlay"
+ android:background="?attr/borderless_button"
+ android:src="?attr/av_fast_forward"/>
+
+ <Button
+ android:id="@+id/butPlaybackSpeed"
+ android:layout_width="60dp"
+ android:layout_height="match_parent"
+ android:layout_toRightOf="@id/butFF"
+ android:background="?attr/borderless_button"
+ android:src="?attr/av_fast_forward"
+ android:textColor="@color/gray"
+ android:textSize="@dimen/text_size_medium"
+ android:visibility="gone"/>
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:id="@+id/playtime_layout"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_above="@id/player_control"
android:layout_alignParentLeft="true"
- android:layout_centerVertical="true"
- android:layout_marginLeft="8dp"
- android:layout_marginTop="16dp"
- android:text="@string/position_default_label"
- android:textColor="?android:attr/textColorSecondary"
- android:textSize="@dimen/text_size_micro" />
-
- <TextView
- android:id="@+id/txtvLength"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_alignParentTop="true"
- android:layout_centerVertical="true"
- android:layout_marginRight="8dp"
- android:layout_marginTop="16dp"
- android:text="@string/position_default_label"
- android:textColor="?android:attr/textColorSecondary"
- android:textSize="@dimen/text_size_micro" />
-
- <SeekBar
- android:id="@+id/sbPosition"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- android:layout_marginLeft="8dp"
- android:layout_marginRight="8dp"
- android:layout_marginTop="16dp"
- android:layout_toLeftOf="@id/txtvLength"
- android:layout_toRightOf="@id/txtvPosition"
- android:max="500" />
+ android:background="?attr/overlay_drawable">
+
+ <TextView
+ android:id="@+id/txtvPosition"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_centerVertical="true"
+ android:layout_marginLeft="8dp"
+ android:layout_marginTop="16dp"
+ android:text="@string/position_default_label"
+ android:textColor="?android:attr/textColorSecondary"
+ android:textSize="@dimen/text_size_micro"/>
+
+ <TextView
+ android:id="@+id/txtvLength"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_alignParentTop="true"
+ android:layout_centerVertical="true"
+ android:layout_marginRight="8dp"
+ android:layout_marginTop="16dp"
+ android:text="@string/position_default_label"
+ android:textColor="?android:attr/textColorSecondary"
+ android:textSize="@dimen/text_size_micro"/>
+
+ <SeekBar
+ android:id="@+id/sbPosition"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_marginLeft="8dp"
+ android:layout_marginRight="8dp"
+ android:layout_marginTop="16dp"
+ android:layout_toLeftOf="@id/txtvLength"
+ android:layout_toRightOf="@id/txtvPosition"
+ android:max="500"/>
+ </RelativeLayout>
</RelativeLayout>
- </RelativeLayout>
-</LinearLayout> \ No newline at end of file
+ </LinearLayout>
+
+ <ListView
+ android:id="@+id/nav_list"
+ android:layout_width="@dimen/drawer_width"
+ android:layout_height="match_parent"
+ android:layout_gravity="start"
+ android:choiceMode="singleChoice"
+ android:background="?attr/nav_drawer_background"
+ android:scrollbarStyle="outsideOverlay"
+ android:paddingLeft="8dp"
+ android:paddingRight="8dp"/>
+
+</android.support.v4.widget.DrawerLayout> \ No newline at end of file
diff --git a/res/layout/addfeed.xml b/res/layout/addfeed.xml
index bb0842c0f..48c89f802 100644
--- a/res/layout/addfeed.xml
+++ b/res/layout/addfeed.xml
@@ -20,9 +20,7 @@
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_margin="16dp"
- android:textSize="@dimen/text_size_large"
- android:textColor="@color/bright_blue"
- android:textStyle="italic"
+ style="@style/AntennaPod.TextView.Heading"
android:text="@string/txtvfeedurl_label"/>
<EditText
@@ -48,37 +46,34 @@
android:layout_height="wrap_content"
android:layout_below="@id/butConfirm"
android:layout_margin="8dp"
- android:textSize="@dimen/text_size_large"
- android:textColor="@color/bright_blue"
- android:textStyle="italic"
+ style="@style/AntennaPod.TextView.Heading"
android:text="@string/podcastdirectories_label"/>
- <Button
- android:id="@+id/butBrowseGpoddernet"
+ <TextView
+ android:id="@+id/txtvPodcastDirectoriesDescr"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:text="@string/podcastdirectories_descr"
+ android:textSize="@dimen/text_size_medium"
android:layout_below="@id/txtvPodcastDirectories"
- android:layout_margin="8dp"
- android:text="@string/gpodnet_main_label"/>
+ android:layout_margin="8dp"/>
<Button
- android:id="@+id/butBrowseMiroguide"
+ android:id="@+id/butBrowseGpoddernet"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_below="@id/butBrowseGpoddernet"
+ android:layout_below="@id/txtvPodcastDirectoriesDescr"
android:layout_margin="8dp"
- android:text="@string/miro_guide_label"/>
+ android:text="@string/browse_gpoddernet_label"/>
<TextView
android:id="@+id/txtvOpmlImport"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_below="@id/butBrowseMiroguide"
+ android:layout_below="@id/butBrowseGpoddernet"
android:layout_margin="8dp"
- android:textSize="@dimen/text_size_large"
- android:textColor="@color/bright_blue"
- android:textStyle="italic"
+ style="@style/AntennaPod.TextView.Heading"
android:text="@string/opml_import_label"/>
<TextView
@@ -87,6 +82,7 @@
android:layout_height="wrap_content"
android:layout_below="@id/txtvOpmlImport"
android:layout_margin="8dp"
+ android:textSize="@dimen/text_size_medium"
android:text="@string/opml_import_txtv_button_lable"/>
<Button
diff --git a/res/layout/audioplayer_activity.xml b/res/layout/audioplayer_activity.xml
index 9b501fbdb..a879aad55 100644
--- a/res/layout/audioplayer_activity.xml
+++ b/res/layout/audioplayer_activity.xml
@@ -1,173 +1,182 @@
<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<android.support.v4.widget.DrawerLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/drawer_layout"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="?attr/non_transparent_background"
- android:orientation="vertical" >
-
- <RelativeLayout
- android:id="@+id/navBar"
- android:layout_width="fill_parent"
- android:layout_height="60dp"
- android:layout_alignParentTop="true" >
-
- <ImageButton
- android:id="@+id/butNavLeft"
- android:contentDescription="@string/show_shownotes_label"
- android:layout_width="60dp"
- android:layout_height="match_parent"
- android:layout_alignParentLeft="true"
- android:background="?attr/borderless_button"
- android:padding="4dp" />
-
- <ImageButton
- android:id="@+id/butNavRight"
- android:contentDescription="@string/show_chapters_label"
- android:layout_width="60dp"
- android:layout_height="match_parent"
- android:layout_alignParentRight="true"
- android:background="?attr/borderless_button"
- android:padding="4dp" />
-
- <TextView
- android:id="@+id/txtvTitle"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentTop="true"
- android:layout_marginLeft="8dp"
- android:layout_marginRight="8dp"
- android:layout_marginTop="8dp"
- android:layout_toLeftOf="@id/butNavRight"
- android:layout_toRightOf="@id/butNavLeft"
- android:ellipsize="marquee"
- android:marqueeRepeatLimit="marquee_forever"
- android:maxLines="1"
- android:textColor="?android:attr/textColorPrimary"
- android:textSize="@dimen/text_size_small"
- android:textStyle="bold" />
-
- <TextView
- android:id="@+id/txtvFeed"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_below="@id/txtvTitle"
- android:layout_marginLeft="8dp"
- android:layout_marginRight="8dp"
- android:layout_toLeftOf="@id/butNavRight"
- android:layout_toRightOf="@id/butNavLeft"
- android:ellipsize="marquee"
- android:marqueeRepeatLimit="marquee_forever"
- android:maxLines="1"
- android:textColor="?android:attr/textColorSecondary"
- android:textSize="@dimen/text_size_small" />
- </RelativeLayout>
-
- <View
- android:id="@+id/navBarDivider"
- android:layout_width="match_parent"
- android:layout_height="1dp"
- android:layout_below="@id/navBar"
- android:background="@color/bright_blue" />
-
- <RelativeLayout
- android:id="@+id/player_control"
- android:layout_width="match_parent"
- android:layout_height="80dp"
- android:layout_alignParentBottom="true"
- android:background="?attr/overlay_background" >
-
- <ImageButton
- android:id="@+id/butPlay"
- android:contentDescription="@string/pause_label"
- android:layout_width="80dp"
- android:layout_height="match_parent"
- android:layout_centerHorizontal="true"
- android:background="?attr/borderless_button"
- android:src="?attr/av_pause" />
-
- <ImageButton
- android:id="@+id/butRev"
- android:contentDescription="@string/rewind_label"
- android:layout_width="80dp"
- android:layout_height="match_parent"
- android:layout_toLeftOf="@id/butPlay"
- android:background="?attr/borderless_button"
- android:src="?attr/av_rewind" />
-
- <ImageButton
- android:id="@+id/butFF"
- android:contentDescription="@string/fast_forward_label"
- android:layout_width="80dp"
- android:layout_height="match_parent"
- android:layout_toRightOf="@id/butPlay"
- android:background="?attr/borderless_button"
- android:src="?attr/av_fast_forward" />
-
- <Button
- android:id="@+id/butPlaybackSpeed"
- android:contentDescription="@string/set_playback_speed_label"
- android:layout_width="80dp"
- android:layout_height="match_parent"
- android:layout_toRightOf="@id/butFF"
- android:background="?attr/borderless_button"
- android:src="?attr/av_fast_forward"
- android:textColor="@color/gray"
- android:textSize="@dimen/text_size_medium"
- android:visibility="gone" />
- </RelativeLayout>
-
- <RelativeLayout
- android:id="@+id/playtime_layout"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_above="@id/player_control"
- android:layout_alignParentLeft="true"
- android:background="?attr/overlay_drawable" >
-
- <TextView
- android:id="@+id/txtvPosition"
- android:layout_width="wrap_content"
+ android:layout_height="match_parent">
+
+ <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/content"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="?attr/non_transparent_background"
+ android:orientation="vertical">
+
+ <RelativeLayout
+ android:id="@+id/navBar"
+ android:layout_width="fill_parent"
+ android:layout_height="60dp"
+ android:layout_alignParentTop="true">
+
+ <ImageButton
+ android:id="@+id/butNavLeft"
+ android:contentDescription="@string/show_shownotes_label"
+ android:layout_width="60dp"
+ android:layout_height="match_parent"
+ android:layout_alignParentLeft="true"
+ android:background="?attr/borderless_button"
+ android:padding="4dp"/>
+
+ <ImageButton
+ android:id="@+id/butNavRight"
+ android:contentDescription="@string/show_chapters_label"
+ android:layout_width="60dp"
+ android:layout_height="match_parent"
+ android:layout_alignParentRight="true"
+ android:background="?attr/borderless_button"
+ android:padding="4dp"/>
+
+ <TextView
+ android:id="@+id/txtvTitle"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_centerInParent="true"
+ android:layout_alignParentTop="true"
+ android:layout_marginLeft="8dp"
+ android:layout_marginRight="8dp"
+ android:layout_marginTop="8dp"
+ android:layout_toLeftOf="@id/butNavRight"
+ android:layout_toRightOf="@id/butNavLeft"
+ android:ellipsize="marquee"
+ android:marqueeRepeatLimit="marquee_forever"
+ android:maxLines="2"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textSize="16sp"
+ android:fontFamily="sans-serif-light"
+ />
+ </RelativeLayout>
+
+ <View
+ android:id="@+id/navBarDivider"
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:layout_below="@id/navBar"
+ android:background="@color/bright_blue"/>
+
+ <RelativeLayout
+ android:id="@+id/player_control"
+ android:layout_width="match_parent"
+ android:layout_height="80dp"
+ android:layout_alignParentBottom="true"
+ android:background="?attr/overlay_background">
+
+ <ImageButton
+ android:id="@+id/butPlay"
+ android:contentDescription="@string/pause_label"
+ android:layout_width="80dp"
+ android:layout_height="match_parent"
+ android:layout_centerHorizontal="true"
+ android:background="?attr/borderless_button"
+ android:src="?attr/av_pause"/>
+
+ <ImageButton
+ android:id="@+id/butRev"
+ android:contentDescription="@string/rewind_label"
+ android:layout_width="80dp"
+ android:layout_height="match_parent"
+ android:layout_toLeftOf="@id/butPlay"
+ android:background="?attr/borderless_button"
+ android:src="?attr/av_rewind"/>
+
+ <ImageButton
+ android:id="@+id/butFF"
+ android:contentDescription="@string/fast_forward_label"
+ android:layout_width="80dp"
+ android:layout_height="match_parent"
+ android:layout_toRightOf="@id/butPlay"
+ android:background="?attr/borderless_button"
+ android:src="?attr/av_fast_forward"/>
+
+ <Button
+ android:id="@+id/butPlaybackSpeed"
+ android:contentDescription="@string/set_playback_speed_label"
+ android:layout_width="80dp"
+ android:layout_height="match_parent"
+ android:layout_toRightOf="@id/butFF"
+ android:background="?attr/borderless_button"
+ android:src="?attr/av_fast_forward"
+ android:textColor="@color/gray"
+ android:textSize="@dimen/text_size_medium"
+ android:visibility="gone"/>
+ </RelativeLayout>
+
+ <RelativeLayout
+ android:id="@+id/playtime_layout"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_above="@id/player_control"
android:layout_alignParentLeft="true"
- android:layout_centerVertical="true"
- android:layout_marginLeft="8dp"
- android:layout_marginTop="16dp"
- android:text="@string/position_default_label"
- android:textColor="?android:attr/textColorSecondary"
- android:textSize="@dimen/text_size_micro" />
-
- <TextView
- android:id="@+id/txtvLength"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_alignParentTop="true"
- android:layout_centerVertical="true"
- android:layout_marginRight="8dp"
- android:layout_marginTop="16dp"
- android:text="@string/position_default_label"
- android:textColor="?android:attr/textColorSecondary"
- android:textSize="@dimen/text_size_micro" />
-
- <SeekBar
- android:id="@+id/sbPosition"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- android:layout_marginLeft="8dp"
- android:layout_marginRight="8dp"
- android:layout_marginTop="16dp"
- android:layout_toLeftOf="@id/txtvLength"
- android:layout_toRightOf="@id/txtvPosition"
- android:max="500" />
- </RelativeLayout>
+ android:background="?attr/overlay_drawable">
+
+ <TextView
+ android:id="@+id/txtvPosition"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_centerVertical="true"
+ android:layout_marginLeft="8dp"
+ android:layout_marginTop="16dp"
+ android:text="@string/position_default_label"
+ android:textColor="?android:attr/textColorSecondary"
+ android:fontFamily="sans-serif-light"
+ android:textSize="@dimen/text_size_micro"/>
+
+ <TextView
+ android:id="@+id/txtvLength"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_alignParentTop="true"
+ android:layout_centerVertical="true"
+ android:layout_marginRight="8dp"
+ android:layout_marginTop="16dp"
+ android:text="@string/position_default_label"
+ android:textColor="?android:attr/textColorSecondary"
+ android:fontFamily="sans-serif-light"
+ android:textSize="@dimen/text_size_micro"/>
+
+ <SeekBar
+ android:id="@+id/sbPosition"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_marginLeft="8dp"
+ android:layout_marginRight="8dp"
+ android:layout_marginTop="16dp"
+ android:layout_toLeftOf="@id/txtvLength"
+ android:layout_toRightOf="@id/txtvPosition"
+ android:max="500"/>
+ </RelativeLayout>
+
+ <FrameLayout
+ android:id="@+id/contentView"
+ android:layout_width="match_parent"
+ android:layout_height="0px"
+ android:layout_above="@id/playtime_layout"
+ android:layout_below="@id/navBarDivider">
+ </FrameLayout>
- <FrameLayout
- android:id="@+id/contentView"
- android:layout_width="match_parent"
- android:layout_height="0px"
- android:layout_above="@id/playtime_layout"
- android:layout_below="@id/navBarDivider" >
- </FrameLayout>
+ </RelativeLayout>
-</RelativeLayout> \ No newline at end of file
+ <ListView
+ android:id="@+id/nav_list"
+ android:layout_width="@dimen/drawer_width"
+ android:layout_height="match_parent"
+ android:layout_gravity="start"
+ android:choiceMode="singleChoice"
+ android:background="?attr/nav_drawer_background"
+ android:scrollbarStyle="outsideOverlay"
+ android:paddingLeft="8dp"
+ android:paddingRight="8dp"/>
+
+</android.support.v4.widget.DrawerLayout> \ No newline at end of file
diff --git a/res/layout/downloaded_episodeslist_item.xml b/res/layout/downloaded_episodeslist_item.xml
new file mode 100644
index 000000000..35b3dbf9a
--- /dev/null
+++ b/res/layout/downloaded_episodeslist_item.xml
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:orientation="horizontal"
+ android:layout_height="match_parent">
+
+ <RelativeLayout
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:layout_marginRight="16dp">
+
+ <ImageView
+ android:id="@+id/imgvImage"
+ android:contentDescription="@string/cover_label"
+ android:layout_width="@dimen/thumbnail_length_itemlist"
+ android:layout_height="@dimen/thumbnail_length_itemlist"
+ android:layout_alignParentLeft="true"
+ android:scaleType="centerCrop"/>
+
+ <ImageView
+ android:id="@+id/statusPlaying"
+ android:contentDescription="@string/status_playing_label"
+ android:layout_width="@dimen/status_indicator_width"
+ android:layout_height="18dp"
+ android:layout_alignParentRight="true"
+ android:layout_alignParentTop="true"
+ android:layout_marginBottom="8dp"
+ android:layout_marginTop="8dp"
+ android:layout_marginLeft="8dp"
+ android:background="@color/status_playing"
+ android:gravity="center"
+ android:padding="2dp"
+ android:src="@drawable/av_play_dark"/>
+
+ <TextView
+ android:id="@+id/txtvPublished"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="8dp"
+ android:layout_marginRight="8dp"
+ android:layout_alignParentTop="true"
+ android:layout_toRightOf="@id/imgvImage"
+ android:layout_toLeftOf="@id/statusPlaying"
+ android:ellipsize="end"
+ android:maxLines="1"
+ android:textColor="?android:attr/textColorTertiary"
+ android:textSize="@dimen/text_size_micro"/>
+
+ <TextView
+ android:id="@+id/txtvTitle"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/txtvPublished"
+ android:layout_marginLeft="8dp"
+ android:layout_marginRight="4dp"
+ android:layout_marginTop="2dp"
+ android:layout_toRightOf="@id/imgvImage"
+ android:layout_toLeftOf="@id/statusPlaying"
+ android:ellipsize="end"
+ android:lines="2"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textSize="@dimen/text_size_small"/>
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentRight="true"
+ android:layout_toRightOf="@id/imgvImage"
+ android:orientation="vertical">
+
+ <RelativeLayout
+ android:id="@+id/bottom_bar"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <TextView
+ android:id="@+id/txtvSize"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="8dp"
+ android:layout_marginRight="8dp"
+ android:layout_alignParentLeft="true"
+ android:textColor="?android:attr/textColorTertiary"
+ android:textSize="@dimen/text_size_micro"/>
+ </RelativeLayout>
+ </LinearLayout>
+ </RelativeLayout>
+
+ <View
+ android:layout_width="1dp"
+ android:layout_height="match_parent"
+ android:background="@drawable/vertical_divider"
+ android:layout_marginTop="8dp"
+ android:layout_marginBottom="8dp"/>
+
+ <ImageButton
+ android:id="@+id/butSecondaryAction"
+ android:contentDescription="@string/remove_episode_lable"
+ android:focusable="false"
+ android:clickable="false"
+ android:focusableInTouchMode="false"
+ android:layout_width="@dimen/listview_secondary_button_width"
+ android:layout_height="match_parent"
+ android:background="?attr/borderless_button"
+ android:src="?attr/content_discard"
+ />
+
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/downloadlist_item.xml b/res/layout/downloadlist_item.xml
index 688a64876..a0a589175 100644
--- a/res/layout/downloadlist_item.xml
+++ b/res/layout/downloadlist_item.xml
@@ -1,46 +1,73 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical" >
-
- <TextView
- android:id="@+id/txtvTitle"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginLeft="8dp"
- android:layout_marginTop="8dp"
- android:textStyle="bold" />
-
- <TextView
- android:id="@+id/txtvMessage"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_margin="8dp" />
-
- <ProgressBar
- android:id="@+id/progProgress"
- style="?android:attr/progressBarStyleHorizontal"
- android:layout_width="match_parent"
- android:layout_height="16dp"
- android:layout_margin="8dp" />
-
- <RelativeLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_margin="8dp" >
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="horizontal">
+
+ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
<TextView
- android:id="@+id/txtvDownloaded"
- android:layout_width="wrap_content"
+ android:id="@+id/txtvTitle"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_alignParentLeft="true" />
+ android:layout_marginLeft="8dp"
+ android:layout_marginTop="8dp"
+ android:textStyle="bold"/>
<TextView
- android:id="@+id/txtvPercent"
- android:layout_width="wrap_content"
+ android:id="@+id/txtvMessage"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="8dp"/>
+
+ <ProgressBar
+ android:id="@+id/progProgress"
+ style="?android:attr/progressBarStyleHorizontal"
+ android:layout_width="match_parent"
+ android:layout_height="16dp"
+ android:layout_margin="8dp"/>
+
+ <RelativeLayout
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_alignParentRight="true" />
- </RelativeLayout>
+ android:layout_margin="8dp">
+
+ <TextView
+ android:id="@+id/txtvDownloaded"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"/>
+
+ <TextView
+ android:id="@+id/txtvPercent"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"/>
+ </RelativeLayout>
+
+ </LinearLayout>
+
+
+ <View
+ android:layout_width="1dp"
+ android:layout_height="match_parent"
+ android:background="@drawable/vertical_divider"
+ android:layout_marginTop="8dp"
+ android:layout_marginBottom="8dp"/>
+ <ImageButton
+ android:id="@+id/butSecondaryAction"
+ android:contentDescription="@string/cancel_download_label"
+ android:focusable="false"
+ android:clickable="false"
+ android:focusableInTouchMode="false"
+ android:layout_width="@dimen/listview_secondary_button_width"
+ android:layout_height="match_parent"
+ android:background="?attr/borderless_button"
+ android:src="?attr/navigation_cancel"
+ />
</LinearLayout> \ No newline at end of file
diff --git a/res/layout/external_player_fragment.xml b/res/layout/external_player_fragment.xml
index d619d7a77..f084ccac1 100644
--- a/res/layout/external_player_fragment.xml
+++ b/res/layout/external_player_fragment.xml
@@ -1,26 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/fragmentLayout"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:visibility="gone" >
+ android:id="@+id/fragmentLayout"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:visibility="gone">
<View
android:layout_width="match_parent"
- android:layout_height="1.5dp"
- android:background="#AAAAAA" />
+ android:layout_height="2dp"
+ android:background="@color/bright_blue"/>
<LinearLayout
android:layout_width="match_parent"
- android:layout_height="wrap_content" >
+ android:layout_height="wrap_content">
<RelativeLayout
android:id="@+id/layoutInfo"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
- android:background="?attr/borderless_button" >
+ android:background="?attr/borderless_button">
<ImageView
android:id="@+id/imgvCover"
@@ -28,9 +28,10 @@
android:layout_width="@dimen/external_player_height"
android:layout_height="@dimen/external_player_height"
android:layout_alignParentLeft="true"
+ android:padding="4dp"
android:adjustViewBounds="true"
android:cropToPadding="true"
- android:scaleType="fitXY" />
+ android:scaleType="fitXY"/>
<TextView
android:id="@+id/txtvTitle"
@@ -42,37 +43,9 @@
android:layout_marginTop="8dp"
android:layout_toRightOf="@id/imgvCover"
android:ellipsize="end"
- android:maxLines="1"
- android:textStyle="bold" />
-
- <TextView
- android:id="@+id/txtvPosition"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_below="@id/txtvTitle"
- android:layout_marginBottom="8dp"
- android:layout_marginLeft="8dp"
- android:layout_marginRight="8dp"
- android:layout_marginTop="4dp"
- android:layout_toRightOf="@id/imgvCover"
- android:maxLines="1"
- android:textSize="@dimen/text_size_micro" />
-
- <TextView
- android:id="@+id/txtvStatus"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_below="@id/txtvTitle"
- android:layout_marginBottom="8dp"
- android:layout_marginLeft="8dp"
- android:layout_marginRight="8dp"
- android:layout_marginTop="4dp"
- android:layout_toRightOf="@id/txtvPosition"
- android:ellipsize="end"
- android:maxLines="1"
- android:textColor="?android:attr/textColorSecondary"
- android:textSize="@dimen/text_size_micro" />
+ android:maxLines="2"
+ android:textSize="18sp"
+ android:fontFamily="sans-serif-light"/>
</RelativeLayout>
<ImageButton
@@ -80,7 +53,7 @@
android:contentDescription="@string/pause_label"
android:layout_width="@dimen/external_player_height"
android:layout_height="@dimen/external_player_height"
- android:background="?attr/borderless_button" />
+ android:background="?attr/borderless_button"/>
</LinearLayout>
</LinearLayout> \ No newline at end of file
diff --git a/res/layout/feedinfo.xml b/res/layout/feedinfo.xml
index d975ef549..8c907c132 100644
--- a/res/layout/feedinfo.xml
+++ b/res/layout/feedinfo.xml
@@ -26,9 +26,7 @@
android:layout_centerVertical="true"
android:layout_margin="4dp"
android:layout_toRightOf="@id/imgvCover"
- android:textSize="@dimen/text_size_large"
- android:textStyle="bold"
- android:textColor="?android:attr/textColorPrimary"/>
+ style="@style/AntennaPod.TextView.Heading"/>
<View
android:id="@+id/divider"
@@ -99,12 +97,11 @@
<TextView
android:id="@+id/txtvSettings"
+ style="@style/AntennaPod.TextView.Heading"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:text="@string/podcast_settings_label"
- android:textSize="@dimen/text_size_medium"
- android:textColor="?android:attr/textColorPrimary"
android:layout_marginLeft="8dp"
android:layout_marginBottom="8dp"
android:layout_marginTop="24dp"/>
@@ -119,13 +116,12 @@
android:textColor="?android:attr/textColorPrimary"/>
<TextView
+ style="@style/AntennaPod.TextView.Heading"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginBottom="8dp"
android:layout_marginTop="24dp"
- android:textSize="@dimen/text_size_medium"
- android:textColor="?android:attr/textColorPrimary"
android:text="@string/description_label"/>
<TextView
diff --git a/res/layout/feeditem_dialog.xml b/res/layout/feeditem_dialog.xml
new file mode 100644
index 000000000..4241ef9c8
--- /dev/null
+++ b/res/layout/feeditem_dialog.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <LinearLayout
+ android:id="@+id/header"
+ android:orientation="horizontal"
+ android:layout_alignParentTop="true"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <ImageButton
+ android:layout_width="0dp"
+ android:layout_height="48dp"
+ android:layout_weight="1"
+ android:id="@+id/butAction1"
+ android:background="?attr/borderless_button"
+ tools:ignore="ContentDescription"/>
+
+ <ImageButton
+ android:layout_width="0dp"
+ android:layout_height="48dp"
+ android:layout_weight="1"
+ android:id="@+id/butAction2"
+ android:background="?attr/borderless_button"
+ tools:ignore="ContentDescription"/>
+
+ <ImageButton
+ android:layout_width="0dp"
+ android:layout_height="48dp"
+ android:layout_weight="1"
+ android:id="@+id/butMoreActions"
+ android:background="?attr/borderless_button"
+ android:src="?attr/ic_action_overflow"
+ android:contentDescription="@string/butAction_label"/>
+ </LinearLayout>
+
+ <View
+ android:id="@+id/divider"
+ android:layout_width="match_parent"
+ android:layout_height="3dp"
+ android:layout_below="@id/header"
+ android:background="@color/bright_blue"/>
+
+ <WebView
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_below="@id/divider"
+ android:layout_alignParentBottom="true"
+ android:id="@+id/webview"/>
+
+</RelativeLayout> \ No newline at end of file
diff --git a/res/layout/feeditemlist_header.xml b/res/layout/feeditemlist_header.xml
index 560013abd..d2ce7556f 100644
--- a/res/layout/feeditemlist_header.xml
+++ b/res/layout/feeditemlist_header.xml
@@ -1,56 +1,53 @@
<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="?attr/borderless_button"
- android:orientation="vertical" >
- <RelativeLayout
- android:layout_width="wrap_content"
- android:layout_height="match_parent" >
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ tools:context="de.danoeh.antennapod.activity.MainActivity">
+
+ <ImageView
+ android:id="@+id/imgvCover"
+ android:contentDescription="@string/cover_label"
+ android:layout_width="@dimen/thumbnail_length_onlinefeedview"
+ android:layout_height="@dimen/thumbnail_length_onlinefeedview"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentTop="true"
+ android:layout_margin="4dp"/>
- <TextView
- android:id="@+id/txtvHeaderTitle"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentLeft="true"
- android:layout_centerVertical="true"
- android:layout_marginBottom="32dp"
- android:layout_marginLeft="28dp"
- android:layout_marginRight="16dp"
- android:layout_marginTop="32dp"
- android:paddingLeft="8dp"
- android:textAllCaps="true"
- android:textColor="@color/dark_blue"
- android:textSize="@dimen/text_size_large"
- android:typeface="sans" />
+ <TextView
+ android:id="@+id/txtvTitle"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:ellipsize="end"
+ android:gravity="center_vertical"
+ android:layout_alignTop="@id/imgvCover"
+ android:layout_toRightOf="@id/imgvCover"
+ android:layout_alignParentRight="true"
+ android:lines="1"
+ style="@style/AntennaPod.TextView.Heading"
+ android:layout_margin="4dp"/>
- <ImageButton
- android:id="@+id/butAction"
- android:contentDescription="@string/butAction_label"
- android:layout_width="48dp"
- android:layout_height="match_parent"
- android:layout_alignParentBottom="true"
- android:layout_alignParentRight="true"
- android:background="?attr/borderless_button"
- android:clickable="false"
- android:focusable="false"
- android:focusableInTouchMode="false"
- android:paddingLeft="24dp"
- android:paddingRight="8dp"
- android:paddingTop="16dp"
- android:scaleType="fitEnd"
- android:src="?attr/spinner_button" />
+ <TextView
+ android:id="@+id/txtvAuthor"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_margin="4dp"
+ android:layout_below="@id/txtvTitle"
+ android:layout_toRightOf="@id/imgvCover"
+ android:lines="1"
+ android:ellipsize="end"
+ android:textColor="?android:attr/textColorSecondary"
+ android:textSize="@dimen/text_size_small"/>
- <TextView
- android:id="@+id/txtvNumItems"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_centerVertical="true"
- android:layout_toLeftOf="@id/butAction"
- android:textColor="@color/dark_blue"
- android:textSize="@dimen/text_size_large"
- android:textStyle="normal" />
- </RelativeLayout>
+ <TextView
+ android:id="@+id/txtvLink"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:lines="1"
+ android:ellipsize="end"
+ android:layout_below="@id/txtvAuthor"
+ android:layout_toRightOf="@id/imgvCover"
+ android:textSize="@dimen/text_size_small"/>
-</LinearLayout> \ No newline at end of file
+</RelativeLayout> \ No newline at end of file
diff --git a/res/layout/feeditemlist_item.xml b/res/layout/feeditemlist_item.xml
index e2898b601..c887d3a4f 100644
--- a/res/layout/feeditemlist_item.xml
+++ b/res/layout/feeditemlist_item.xml
@@ -1,155 +1,133 @@
<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="0dip"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:paddingLeft="4dp" >
- <TextView
- android:id="@+id/txtvItemname"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_marginBottom="4dp"
- android:layout_marginRight="4dp"
- android:layout_marginTop="4dp"
- android:layout_toLeftOf="@+id/butAction"
- android:ellipsize="end"
- android:lines="2"
- android:textColor="?android:attr/textColorPrimary"
- android:textSize="@dimen/text_size_medium" />
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:orientation="horizontal"
+ android:layout_height="match_parent">
- <TextView
- android:id="@+id/txtvFeedname"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_below="@id/txtvItemname"
- android:layout_marginBottom="4dp"
- android:layout_toLeftOf="@id/butAction"
- android:textColor="?android:attr/textColorSecondary"
- android:textSize="@dimen/text_size_micro"
- android:visibility="gone" />
+ <RelativeLayout
+ android:layout_margin="8dp"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:paddingLeft="4dp">
- <TextView
- android:id="@+id/txtvPublished"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_below="@id/txtvFeedname"
- android:layout_marginBottom="4dp"
- android:layout_toLeftOf="@id/butAction"
- android:textColor="?android:attr/textColorTertiary"
- android:textSize="@dimen/text_size_micro" />
+ <TextView
+ android:id="@+id/txtvPublished"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentTop="true"
+ android:layout_marginBottom="4dp"
+ android:textColor="?android:attr/textColorTertiary"
+ android:textSize="@dimen/text_size_micro"/>
- <ImageView
- android:id="@+id/imgvType"
- android:layout_width="@dimen/enc_icons_size"
- android:layout_height="@dimen/enc_icons_size"
- android:layout_below="@id/txtvPublished"
- android:layout_toLeftOf="@+id/imgvInPlaylist"
- android:padding="2dp"
- tools:ignore="ContentDescription"/>
+ <TextView
+ android:id="@+id/txtvItemname"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/txtvPublished"
+ android:layout_marginBottom="4dp"
+ android:layout_marginRight="4dp"
+ android:layout_marginTop="4dp"
+ android:ellipsize="end"
+ android:lines="2"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textSize="@dimen/text_size_medium"/>
- <ImageView
- android:id="@id/imgvInPlaylist"
- android:contentDescription="@string/in_queue_label"
- android:layout_width="@dimen/enc_icons_size"
- android:layout_height="@dimen/enc_icons_size"
- android:layout_below="@id/txtvPublished"
- android:layout_toLeftOf="@+id/imgvDownloaded"
- android:padding="2dp"
- android:src="?attr/stat_playlist"
- android:visibility="visible" />
- <ImageView
- android:id="@id/imgvDownloaded"
- android:contentDescription="@string/status_downloaded_label"
- android:layout_width="@dimen/enc_icons_size"
- android:layout_height="@dimen/enc_icons_size"
- android:layout_below="@id/txtvPublished"
- android:layout_toLeftOf="@+id/imgvDownloading"
- android:padding="2dp"
- android:src="?attr/av_download"
- android:visibility="visible" />
+ <ImageView
+ android:id="@+id/imgvInPlaylist"
+ android:contentDescription="@string/in_queue_label"
+ android:layout_width="@dimen/enc_icons_size"
+ android:layout_height="@dimen/enc_icons_size"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentRight="true"
+ android:padding="2dp"
+ android:src="?attr/stat_playlist"
+ android:visibility="visible"/>
- <ImageView
- android:id="@id/imgvDownloading"
- android:contentDescription="@string/downloading_label"
- android:layout_width="@dimen/enc_icons_size"
- android:layout_height="@dimen/enc_icons_size"
- android:layout_below="@id/txtvPublished"
- android:layout_toLeftOf="@id/butAction"
- android:padding="2dp"
- android:src="?attr/navigation_refresh"
- android:visibility="visible" />
+ <ImageView
+ android:id="@+id/imgvType"
+ android:layout_width="@dimen/enc_icons_size"
+ android:layout_height="@dimen/enc_icons_size"
+ android:layout_alignParentBottom="true"
+ android:layout_toLeftOf="@+id/imgvInPlaylist"
+ android:padding="2dp"
+ tools:ignore="ContentDescription"/>
- <TextView
- android:id="@+id/txtvLenSize"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentLeft="true"
- android:layout_below="@id/txtvPublished"
- android:maxLines="2"
- android:textColor="?android:attr/textColorTertiary"
- android:textSize="@dimen/text_size_micro" />
+ <TextView
+ android:id="@+id/txtvLenSize"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_below="@id/txtvItemname"
+ android:maxLines="2"
+ android:layout_marginBottom="2dp"
+ android:textColor="?android:attr/textColorTertiary"
+ android:textSize="@dimen/text_size_micro"/>
- <ProgressBar
- android:id="@+id/pbar_episode_progress"
- style="?android:attr/progressBarStyleHorizontal"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_below="@id/txtvPublished"
- android:layout_marginBottom="4dp"
- android:layout_marginLeft="4dp"
- android:layout_marginRight="4dp"
- android:layout_marginTop="2dp"
- android:layout_toLeftOf="@id/imgvType"
- android:layout_toRightOf="@id/txtvLenSize" />
+ <ProgressBar
+ android:id="@+id/pbar_episode_progress"
+ style="?android:attr/progressBarStyleHorizontal"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/txtvItemname"
+ android:layout_marginLeft="4dp"
+ android:layout_marginRight="4dp"
+ android:layout_marginTop="2dp"
+ android:layout_toLeftOf="@id/imgvType"
+ android:layout_toRightOf="@id/txtvLenSize"/>
- <ImageButton
- android:id="@id/butAction"
- android:contentDescription="@string/butAction_label"
- android:layout_width="48dp"
+ <TextView
+ android:id="@+id/statusUnread"
+ android:contentDescription="@string/status_unread_label"
+ android:layout_width="wrap_content"
+ android:layout_height="18dp"
+ android:layout_alignParentRight="true"
+ android:layout_alignParentTop="true"
+ android:layout_marginLeft="8dp"
+ android:layout_marginBottom="8dp"
+ android:background="@color/status_unread"
+ android:gravity="center"
+ android:minWidth="@dimen/status_indicator_width"
+ android:text="@string/new_label"
+ android:textAlignment="center"
+ android:textColor="@color/white"
+ android:textSize="@dimen/text_size_micro"
+ android:textStyle="bold"/>
+
+ <ImageView
+ android:id="@+id/statusPlaying"
+ android:contentDescription="@string/status_playing_label"
+ android:layout_width="@dimen/status_indicator_width"
+ android:layout_height="18dp"
+ android:layout_alignParentRight="true"
+ android:layout_alignParentTop="true"
+ android:layout_marginLeft="8dp"
+ android:layout_marginBottom="8dp"
+ android:background="@color/status_playing"
+ android:gravity="center"
+ android:padding="2dp"
+ android:src="@drawable/av_play_dark"/>
+
+ </RelativeLayout>
+
+ <View
+ android:layout_width="1dp"
android:layout_height="match_parent"
- android:layout_alignParentBottom="true"
- android:layout_alignParentRight="true"
- android:background="?attr/borderless_button"
- android:clickable="false"
+ android:background="@drawable/vertical_divider"
+ android:layout_marginTop="8dp"
+ android:layout_marginBottom="8dp"/>
+
+ <ImageButton
+ android:id="@+id/butSecondaryAction"
android:focusable="false"
+ android:clickable="false"
android:focusableInTouchMode="false"
- android:paddingLeft="24dp"
- android:paddingRight="8dp"
- android:paddingTop="16dp"
- android:scaleType="fitEnd"
- android:src="?attr/spinner_button" />
-
- <TextView
- android:id="@+id/statusUnread"
- android:contentDescription="@string/status_unread_label"
- android:layout_width="wrap_content"
- android:layout_height="18dp"
- android:layout_alignParentRight="true"
- android:layout_alignParentTop="true"
- android:layout_margin="8dp"
- android:background="@color/status_unread"
- android:gravity="center"
- android:minWidth="@dimen/status_indicator_width"
- android:text="@string/new_label"
- android:textAlignment="center"
- android:textColor="@color/white"
- android:textSize="@dimen/text_size_micro"
- android:textStyle="bold" />
-
- <ImageView
- android:id="@+id/statusPlaying"
- android:contentDescription="@string/status_playing_label"
- android:layout_width="@dimen/status_indicator_width"
- android:layout_height="18dp"
- android:layout_alignParentRight="true"
- android:layout_alignParentTop="true"
- android:layout_margin="8dp"
- android:background="@color/status_playing"
- android:gravity="center"
- android:padding="2dp"
- android:src="@drawable/av_play_dark" />
+ android:layout_width="@dimen/listview_secondary_button_width"
+ android:layout_height="match_parent"
+ android:background="?attr/borderless_button"
+ tools:ignore="ContentDescription"/>
-</RelativeLayout> \ No newline at end of file
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/gpodnetauth_credentials.xml b/res/layout/gpodnetauth_credentials.xml
index b66fc9414..3e3c4e54f 100644
--- a/res/layout/gpodnetauth_credentials.xml
+++ b/res/layout/gpodnetauth_credentials.xml
@@ -10,10 +10,8 @@
android:layout_height="wrap_content"
android:text="@string/gpodnetauth_login_title"
android:layout_alignParentTop="true"
- android:textSize="@dimen/text_size_large"
android:layout_margin="16dp"
- android:textColor="@color/bright_blue"
- android:textStyle="italic"/>
+ style="@style/AntennaPod.TextView.Heading"/>
<TextView
android:id="@id/txtvDescription"
diff --git a/res/layout/gpodnetauth_device.xml b/res/layout/gpodnetauth_device.xml
index e7bfdc425..33d3d2718 100644
--- a/res/layout/gpodnetauth_device.xml
+++ b/res/layout/gpodnetauth_device.xml
@@ -10,10 +10,8 @@
android:layout_height="wrap_content"
android:text="@string/gpodnetauth_device_title"
android:layout_alignParentTop="true"
- android:textSize="@dimen/text_size_large"
android:layout_margin="16dp"
- android:textColor="@color/bright_blue"
- android:textStyle="italic"/>
+ style="@style/AntennaPod.TextView.Heading"/>
<TextView
android:id="@+id/txtvDescription"
diff --git a/res/layout/gpodnetauth_finish.xml b/res/layout/gpodnetauth_finish.xml
index 3b0b10d04..71873201a 100644
--- a/res/layout/gpodnetauth_finish.xml
+++ b/res/layout/gpodnetauth_finish.xml
@@ -10,10 +10,8 @@
android:layout_height="wrap_content"
android:text="@string/gpodnetauth_finish_title"
android:layout_alignParentTop="true"
- android:textSize="@dimen/text_size_large"
android:layout_margin="16dp"
- android:textColor="@color/bright_blue"
- android:textStyle="italic"/>
+ style="@style/AntennaPod.TextView.Heading"/>
<TextView
android:id="@+id/txtvDescription"
diff --git a/res/layout/main.xml b/res/layout/main.xml
index 2917db164..cfd59b87c 100644
--- a/res/layout/main.xml
+++ b/res/layout/main.xml
@@ -1,21 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/main_view"
+<android.support.v4.widget.DrawerLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/drawer_layout"
android:layout_width="match_parent"
- android:layout_height="match_parent" >
+ android:layout_height="match_parent">
- <FrameLayout
- android:id="@+id/playerFragment"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentBottom="true" />
+ <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/content"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
- <android.support.v4.view.ViewPager
- android:id="@+id/viewpager"
- android:layout_width="match_parent"
- android:layout_height="0px"
- android:layout_above="@id/playerFragment"
- android:layout_alignParentTop="true" >
- </android.support.v4.view.ViewPager>
-</RelativeLayout> \ No newline at end of file
+ <FrameLayout
+ android:id="@+id/playerFragment"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"/>
+
+ <FrameLayout
+ android:id="@+id/main_view"
+ android:layout_width="match_parent"
+ android:layout_height="0px"
+ android:layout_alignParentTop="true"
+ android:layout_above="@id/playerFragment"/>
+
+ </RelativeLayout>
+
+ <ListView
+ android:id="@+id/nav_list"
+ android:layout_width="@dimen/drawer_width"
+ android:layout_height="match_parent"
+ android:layout_gravity="start"
+ android:choiceMode="singleChoice"
+ android:background="?attr/nav_drawer_background"
+ android:scrollbarStyle="outsideOverlay"
+ android:paddingLeft="8dp"
+ android:paddingRight="8dp"/>
+
+</android.support.v4.widget.DrawerLayout> \ No newline at end of file
diff --git a/res/layout/nav_feedlistitem.xml b/res/layout/nav_feedlistitem.xml
new file mode 100644
index 000000000..e01087077
--- /dev/null
+++ b/res/layout/nav_feedlistitem.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+
+ <ImageView
+ android:id="@+id/imgvCover"
+ android:contentDescription="@string/cover_label"
+ android:layout_width="@dimen/thumbnail_length_navlist"
+ android:layout_height="@dimen/thumbnail_length_navlist"
+ android:layout_alignParentLeft="true"
+ android:layout_centerVertical="true"
+ android:adjustViewBounds="true"
+ android:cropToPadding="true"
+ android:scaleType="fitXY"
+ android:layout_marginTop="6dp"
+ android:layout_marginBottom="6dp"/>
+
+
+ <TextView
+ android:id="@+id/txtvTitle"
+ android:lines="1"
+ android:ellipsize="end"
+ android:layout_centerVertical="true"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textSize="@dimen/text_size_navdrawer"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="12dp"
+ android:layout_marginTop="14dp"
+ android:layout_marginBottom="14dp"
+ android:layout_marginRight="48dp"
+ android:layout_toRightOf="@id/imgvCover"
+ />
+</RelativeLayout> \ No newline at end of file
diff --git a/res/layout/nav_listitem.xml b/res/layout/nav_listitem.xml
new file mode 100644
index 000000000..f1b585189
--- /dev/null
+++ b/res/layout/nav_listitem.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <TextView
+ android:id="@+id/txtvTitle"
+ android:lines="1"
+ android:ellipsize="end"
+ android:layout_centerVertical="true"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textSize="@dimen/text_size_navdrawer"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_alignParentLeft="true"
+ android:layout_marginTop="28dp"
+ android:layout_marginBottom="28dp"/>
+</RelativeLayout> \ No newline at end of file
diff --git a/res/layout/nav_section_item.xml b/res/layout/nav_section_item.xml
new file mode 100644
index 000000000..1f2fc7e3e
--- /dev/null
+++ b/res/layout/nav_section_item.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@android:color/transparent">
+
+ <TextView
+ android:id="@+id/txtvTitle"
+ android:textColor="?android:attr/textColorTertiary"
+ android:textSize="@dimen/text_size_small"
+ android:typeface="sans"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentBottom="true"
+ android:layout_marginTop="16dp"
+ android:paddingBottom="4dp"/>
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="2dp"
+ android:layout_alignParentBottom="true"
+ android:background="@color/gray"/>
+</RelativeLayout> \ No newline at end of file
diff --git a/res/layout/new_episodes_fragment.xml b/res/layout/new_episodes_fragment.xml
new file mode 100644
index 000000000..460fe73d0
--- /dev/null
+++ b/res/layout/new_episodes_fragment.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:dslv="http://schemas.android.com/apk/res-auto"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <com.mobeta.android.dslv.DragSortListView
+ android:id="@android:id/list"
+ android:paddingLeft="8dp"
+ android:paddingRight="8dp"
+ android:scrollbarStyle="outsideOverlay"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ dslv:collapsed_height="2dp"
+ dslv:drag_enabled="false"
+ dslv:drag_scroll_start="0.33"
+ dslv:float_alpha="0.6"
+ dslv:max_drag_scroll_speed="0.5"
+ dslv:remove_enabled="true"
+ dslv:remove_mode="flingRemove"
+ dslv:slide_shuffle_speed="0.3"
+ dslv:sort_enabled="false"
+ dslv:track_drag_sort="false"
+ dslv:float_background_color="?attr/dragview_float_background"
+ dslv:use_default_controller="true"/>
+
+ <TextView
+ android:id="@id/android:empty"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:text="@string/no_items_label"/>
+
+ <ProgressBar
+ android:id="@+id/progLoading"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:indeterminateOnly="true"
+ android:visibility="gone"/>
+
+</FrameLayout> \ No newline at end of file
diff --git a/res/layout/new_episodes_listdivider.xml b/res/layout/new_episodes_listdivider.xml
new file mode 100644
index 000000000..6b4f55d61
--- /dev/null
+++ b/res/layout/new_episodes_listdivider.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <TextView
+ android:padding="12dp"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textAllCaps="true"
+ style="@style/AntennaPod.TextView.Heading"
+ android:text="@string/recently_published_episodes_label"/>
+
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/new_episodes_listitem.xml b/res/layout/new_episodes_listitem.xml
new file mode 100644
index 000000000..721b88071
--- /dev/null
+++ b/res/layout/new_episodes_listitem.xml
@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:orientation="horizontal"
+ android:layout_height="match_parent">
+
+ <RelativeLayout
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:layout_marginRight="16dp">
+
+ <ImageView
+ android:id="@+id/imgvImage"
+ android:contentDescription="@string/cover_label"
+ android:layout_width="@dimen/thumbnail_length_itemlist"
+ android:layout_height="@dimen/thumbnail_length_itemlist"
+ android:layout_alignParentLeft="true"
+ android:scaleType="centerCrop"/>
+
+ <ImageView
+ android:id="@+id/statusPlaying"
+ android:contentDescription="@string/status_playing_label"
+ android:layout_width="@dimen/status_indicator_width"
+ android:layout_height="18dp"
+ android:layout_alignParentRight="true"
+ android:layout_alignParentTop="true"
+ android:layout_marginBottom="8dp"
+ android:layout_marginTop="8dp"
+ android:layout_marginLeft="8dp"
+ android:background="@color/status_playing"
+ android:gravity="center"
+ android:padding="2dp"
+ android:src="@drawable/av_play_dark"/>
+
+ <TextView
+ android:id="@+id/txtvPublished"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="8dp"
+ android:layout_marginRight="8dp"
+ android:layout_alignParentTop="true"
+ android:layout_toRightOf="@id/imgvImage"
+ android:layout_toLeftOf="@id/statusPlaying"
+ android:ellipsize="end"
+ android:maxLines="1"
+ android:textColor="?android:attr/textColorTertiary"
+ android:textSize="@dimen/text_size_micro"/>
+
+ <TextView
+ android:id="@+id/txtvTitle"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/txtvPublished"
+ android:layout_marginLeft="8dp"
+ android:layout_marginRight="4dp"
+ android:layout_marginTop="2dp"
+ android:layout_toRightOf="@id/imgvImage"
+ android:layout_toLeftOf="@id/statusPlaying"
+ android:ellipsize="end"
+ android:lines="2"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textSize="@dimen/text_size_small"/>
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentRight="true"
+ android:layout_toRightOf="@id/imgvImage"
+ android:orientation="vertical">
+
+ <RelativeLayout
+ android:id="@+id/bottom_bar"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <ImageView
+ android:id="@id/imgvInPlaylist"
+ android:contentDescription="@string/in_queue_label"
+ android:layout_width="@dimen/enc_icons_size"
+ android:layout_height="@dimen/enc_icons_size"
+ android:layout_alignParentRight="true"
+ android:src="?attr/stat_playlist"/>
+
+ <ProgressBar
+ android:id="@+id/pbar_download_progress"
+ style="?android:attr/progressBarStyleHorizontal"
+ android:max="100"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_toLeftOf="@id/imgvInPlaylist"
+ android:layout_marginLeft="8dp"
+ android:layout_marginRight="8dp"
+ android:layout_alignParentLeft="true"/>
+
+ <TextView
+ android:id="@+id/txtvDuration"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_toLeftOf="@id/imgvInPlaylist"
+ android:layout_marginLeft="8dp"
+ android:layout_marginRight="8dp"
+ android:layout_alignParentLeft="true"
+ android:textColor="?android:attr/textColorTertiary"
+ android:textSize="@dimen/text_size_micro"/>
+ </RelativeLayout>
+ </LinearLayout>
+ </RelativeLayout>
+
+ <View
+ android:layout_width="1dp"
+ android:layout_height="match_parent"
+ android:background="@drawable/vertical_divider"
+ android:layout_marginTop="8dp"
+ android:layout_marginBottom="8dp"/>
+
+ <ImageButton
+ android:id="@+id/butSecondaryAction"
+ android:focusable="false"
+ android:clickable="false"
+ android:focusableInTouchMode="false"
+ android:layout_width="@dimen/listview_secondary_button_width"
+ android:layout_height="match_parent"
+ android:background="?attr/borderless_button"
+ tools:ignore="ContentDescription"/>
+
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/onlinefeedview_header.xml b/res/layout/onlinefeedview_header.xml
index 441df6174..6cec28e92 100644
--- a/res/layout/onlinefeedview_header.xml
+++ b/res/layout/onlinefeedview_header.xml
@@ -23,8 +23,7 @@
android:layout_toRightOf="@id/imgvCover"
android:layout_alignParentRight="true"
android:lines="1"
- android:textColor="?android:attr/textColorPrimary"
- android:textSize="@dimen/text_size_medium"
+ style="@style/AntennaPod.TextView.Heading"
android:layout_margin="4dp"/>
<TextView
diff --git a/res/layout/pager_fragment.xml b/res/layout/pager_fragment.xml
new file mode 100644
index 000000000..cb7ae0151
--- /dev/null
+++ b/res/layout/pager_fragment.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <android.support.v4.view.ViewPager
+ android:id="@+id/pager"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/queue_fragment.xml b/res/layout/queue_fragment.xml
new file mode 100644
index 000000000..1c48768a2
--- /dev/null
+++ b/res/layout/queue_fragment.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:dslv="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <com.mobeta.android.dslv.DragSortListView
+ android:id="@android:id/list"
+ android:paddingLeft="8dp"
+ android:paddingRight="8dp"
+ android:scrollbarStyle="outsideOverlay"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ dslv:collapsed_height="2dp"
+ dslv:drag_enabled="true"
+ dslv:drag_handle_id="@id/drag_handle"
+ dslv:drag_scroll_start="0.33"
+ dslv:float_alpha="0.6"
+ dslv:max_drag_scroll_speed="0.5"
+ dslv:remove_enabled="true"
+ dslv:remove_mode="flingRemove"
+ dslv:slide_shuffle_speed="0.3"
+ dslv:sort_enabled="true"
+ dslv:track_drag_sort="true"
+ dslv:float_background_color="?attr/dragview_float_background"
+ dslv:use_default_controller="true"/>
+
+ <TextView
+ android:id="@id/android:empty"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:text="@string/no_items_label"/>
+
+ <ProgressBar
+ android:id="@+id/progLoading"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:indeterminateOnly="true"
+ android:visibility="gone"/>
+
+ <LinearLayout
+ android:id="@+id/undobar"
+ style="@style/UndoBar">
+
+ <TextView
+ android:id="@+id/undobar_message"
+ style="@style/UndoBarMessage"/>
+
+ <Button
+ android:id="@+id/undobar_button"
+ style="@style/UndoBarButton"/>
+ </LinearLayout>
+
+</FrameLayout> \ No newline at end of file
diff --git a/res/layout/queue_listitem.xml b/res/layout/queue_listitem.xml
new file mode 100644
index 000000000..5bac726f3
--- /dev/null
+++ b/res/layout/queue_listitem.xml
@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:orientation="horizontal"
+ android:layout_height="match_parent">
+
+ <ImageView
+ android:layout_width="24dp"
+ android:layout_height="match_parent"
+ android:id="@+id/drag_handle"
+ android:src="?attr/dragview_background"
+ android:scaleType="center"
+ android:layout_margin="8dp"
+ android:contentDescription="@string/drag_handle_content_description"/>
+
+ <RelativeLayout
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:layout_marginRight="16dp">
+
+ <ImageView
+ android:id="@+id/imgvImage"
+ android:contentDescription="@string/cover_label"
+ android:layout_width="@dimen/thumbnail_length_itemlist"
+ android:layout_height="@dimen/thumbnail_length_itemlist"
+ android:layout_alignParentLeft="true"
+ android:scaleType="centerCrop"/>
+
+ <ImageView
+ android:id="@+id/statusPlaying"
+ android:contentDescription="@string/status_playing_label"
+ android:layout_width="@dimen/status_indicator_width"
+ android:layout_height="18dp"
+ android:layout_alignParentRight="true"
+ android:layout_alignParentTop="true"
+ android:layout_marginBottom="8dp"
+ android:layout_marginTop="8dp"
+ android:background="@color/status_playing"
+ android:gravity="center"
+ android:padding="2dp"
+ android:src="@drawable/av_play_dark"/>
+
+ <TextView
+ android:id="@+id/txtvPublished"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="8dp"
+ android:layout_marginRight="8dp"
+ android:layout_alignParentTop="true"
+ android:layout_toRightOf="@id/imgvImage"
+ android:layout_toLeftOf="@id/statusPlaying"
+ android:ellipsize="end"
+ android:maxLines="1"
+ android:textColor="?android:attr/textColorTertiary"
+ android:textSize="@dimen/text_size_micro"/>
+
+ <TextView
+ android:id="@+id/txtvTitle"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/txtvPublished"
+ android:layout_marginLeft="8dp"
+ android:layout_marginRight="4dp"
+ android:layout_marginTop="2dp"
+ android:layout_toRightOf="@id/imgvImage"
+ android:layout_toLeftOf="@id/statusPlaying"
+ android:ellipsize="end"
+ android:lines="2"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textSize="@dimen/text_size_small"/>
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentRight="true"
+ android:layout_toRightOf="@id/imgvImage"
+ android:orientation="vertical">
+
+ <RelativeLayout
+ android:id="@+id/bottom_bar"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <ProgressBar
+ android:id="@+id/pbar_download_progress"
+ style="?android:attr/progressBarStyleHorizontal"
+ android:max="100"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_marginLeft="8dp"
+ android:layout_marginRight="8dp"
+ android:layout_alignParentLeft="true"/>
+
+ <TextView
+ android:id="@+id/txtvDuration"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="8dp"
+ android:layout_marginRight="8dp"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentRight="true"
+ android:textColor="?android:attr/textColorTertiary"
+ android:textSize="@dimen/text_size_micro"/>
+ </RelativeLayout>
+ </LinearLayout>
+ </RelativeLayout>
+
+ <View
+ android:layout_width="1dp"
+ android:layout_height="match_parent"
+ android:background="@drawable/vertical_divider"
+ android:layout_marginTop="8dp"
+ android:layout_marginBottom="8dp"/>
+
+ <ImageButton
+ android:id="@+id/butSecondaryAction"
+ android:focusable="false"
+ android:clickable="false"
+ android:focusableInTouchMode="false"
+ android:layout_width="@dimen/listview_secondary_button_width"
+ android:layout_height="match_parent"
+ android:background="?attr/borderless_button"
+ tools:ignore="ContentDescription"/>
+
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/searchlist_item.xml b/res/layout/searchlist_item.xml
index 889f40eef..c83f34482 100644
--- a/res/layout/searchlist_item.xml
+++ b/res/layout/searchlist_item.xml
@@ -1,19 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:padding="8dp" >
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
<ImageView
android:id="@+id/imgvFeedimage"
android:contentDescription="@string/cover_label"
- android:layout_width="55dip"
- android:layout_height="55dip"
+ android:layout_width="@dimen/thumbnail_length_itemlist"
+ android:layout_height="@dimen/thumbnail_length_itemlist"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
- android:layout_marginLeft="1dip"
- android:layout_marginRight="4dip"
- android:cropToPadding="true" />
+ android:scaleType="centerCrop"/>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
@@ -21,20 +18,27 @@
android:layout_height="match_parent"
android:layout_centerVertical="true"
android:layout_toRightOf="@id/imgvFeedimage"
- android:orientation="vertical" >
+ android:orientation="vertical">
<TextView
android:id="@+id/txtvTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:maxLines="2"
- android:textStyle="bold" />
+ android:layout_margin="4dp"
+ android:lines="2"
+ android:ellipsize="end"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textSize="@dimen/text_size_small"/>
<TextView
android:id="@+id/txtvSubtitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:textColor="?android:attr/textColorSecondary" />
+ android:layout_margin="4dp"
+ android:lines="1"
+ android:ellipsize="end"
+ android:textColor="?android:attr/textColorTertiary"
+ android:textSize="@dimen/text_size_small"/>
</LinearLayout>
</RelativeLayout> \ No newline at end of file
diff --git a/res/menu/feeditem_dialog.xml b/res/menu/feeditem_dialog.xml
new file mode 100644
index 000000000..f33b7502a
--- /dev/null
+++ b/res/menu/feeditem_dialog.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:custom="http://schemas.android.com/apk/res-auto">
+
+ <item
+ android:id="@id/skip_episode_item"
+ android:title="@string/skip_episode_label"
+ custom:showAsAction="collapseActionView">
+ </item>
+
+ <item
+ android:id="@+id/mark_read_item"
+ custom:showAsAction="collapseActionView"
+ android:title="@string/mark_read_label">
+ </item>
+ <item
+ android:id="@+id/mark_unread_item"
+ custom:showAsAction="collapseActionView"
+ android:title="@string/mark_unread_label">
+ </item>
+ <item
+ android:id="@+id/add_to_queue_item"
+ custom:showAsAction="collapseActionView"
+ android:title="@string/add_to_queue_label">
+ </item>
+ <item
+ android:id="@+id/remove_from_queue_item"
+ custom:showAsAction="collapseActionView"
+ android:title="@string/remove_from_queue_label">
+ </item>
+ <item
+ android:id="@+id/share_link_item"
+ custom:showAsAction="collapseActionView"
+ android:title="@string/share_link_label">
+ </item>
+ <item
+ android:id="@+id/visit_website_item"
+ android:icon="?attr/location_web_site"
+ custom:showAsAction="ifRoom|collapseActionView"
+ android:title="@string/visit_website_label">
+ </item>
+ <item
+ android:id="@+id/support_item"
+ custom:showAsAction="collapseActionView"
+ android:title="@string/support_label">
+ </item>
+
+</menu> \ No newline at end of file
diff --git a/res/menu/feedlist.xml b/res/menu/feedlist.xml
index 74f4fc923..28df69f2d 100644
--- a/res/menu/feedlist.xml
+++ b/res/menu/feedlist.xml
@@ -5,39 +5,37 @@
<item
android:id="@+id/refresh_item"
android:icon="?attr/navigation_refresh"
+ android:menuCategory="container"
custom:showAsAction="ifRoom|collapseActionView"
android:title="@string/refresh_label">
</item>
<item
android:id="@+id/mark_all_read_item"
+ android:menuCategory="container"
custom:showAsAction="collapseActionView"
android:title="@string/mark_all_read_label">
</item>
<item
android:id="@+id/show_info_item"
+ android:menuCategory="container"
android:icon="?attr/action_about"
custom:showAsAction="collapseActionView"
android:title="@string/show_info_label">
</item>
<item
- android:id="@+id/remove_item"
- android:icon="?attr/content_discard"
+ android:id="@+id/support_item"
+ android:menuCategory="container"
custom:showAsAction="collapseActionView"
- android:title="@string/remove_feed_label"
- android:visible="true">
+ android:title="@string/support_label"
+ android:visible="false">
</item>
<item
- android:id="@+id/visit_website_item"
- android:icon="?attr/location_web_site"
+ android:id="@+id/remove_item"
+ android:menuCategory="container"
+ android:icon="?attr/content_discard"
custom:showAsAction="collapseActionView"
- android:title="@string/visit_website_label"
+ android:title="@string/remove_feed_label"
android:visible="true">
</item>
- <item
- android:id="@+id/support_item"
- custom:showAsAction="collapseActionView"
- android:title="@string/support_label"
- android:visible="false">
- </item>
</menu> \ No newline at end of file
diff --git a/res/menu/main.xml b/res/menu/main.xml
index 45047fc46..c5b069b40 100644
--- a/res/menu/main.xml
+++ b/res/menu/main.xml
@@ -1,42 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res-auto">
- <item
- android:id="@+id/all_feed_refresh"
- android:title="@string/refresh_label"
- android:icon="?attr/navigation_refresh"
- custom:showAsAction="ifRoom|collapseActionView">
- </item>
- <item
- android:id="@+id/add_feed"
- android:title="@string/add_feed_label"
- android:icon="?attr/content_new"
- custom:showAsAction="ifRoom|collapseActionView">
- </item>
- <item
- android:id="@id/search_item"
- android:icon="?attr/action_search"
- android:title="@string/search_label"
- custom:showAsAction="ifRoom|collapseActionView"
- android:actionViewClass="android.support.v7.widget.SearchView"/>
- <item
- android:id="@+id/show_player"
- android:title="@string/show_player_label"
- android:icon="@drawable/av_play"
- custom:showAsAction="collapseActionView"/>
- <item
- android:id="@+id/show_playback_history"
- android:title="@string/playback_history_label"
- custom:showAsAction="collapseActionView"/>
- <item
- android:id="@+id/show_downloads"
- android:title="@string/downloads_label"
- android:icon="@drawable/av_download"
- custom:showAsAction="collapseActionView">
- </item>
+
<item
android:id="@+id/show_preferences"
android:title="@string/settings_label"
+ android:menuCategory="system"
android:icon="?attr/action_settings"
custom:showAsAction="collapseActionView"/>
diff --git a/res/menu/new_episodes.xml b/res/menu/new_episodes.xml
new file mode 100644
index 000000000..00ff3bc5a
--- /dev/null
+++ b/res/menu/new_episodes.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:custom="http://schemas.android.com/apk/res-auto">
+
+ <item
+ android:id="@+id/refresh_item"
+ android:title="@string/refresh_label"
+ android:menuCategory="container"
+ custom:showAsAction="ifRoom|collapseActionView"
+ android:icon="?attr/navigation_refresh"/>
+
+ <item
+ android:id="@+id/mark_all_read_item"
+ android:title="@string/mark_all_read_label"
+ android:menuCategory="container"
+ custom:showAsAction="ifRoom|collapseActionView"
+ android:icon="?attr/navigation_accept"/>
+
+</menu> \ No newline at end of file
diff --git a/res/values-v16/styles.xml b/res/values-v16/styles.xml
new file mode 100644
index 000000000..947e43f38
--- /dev/null
+++ b/res/values-v16/styles.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <style name="AntennaPod.TextView.Heading" parent="@android:style/TextAppearance.Medium">
+ <item name="android:textSize">@dimen/text_size_large</item>
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
+ <item name="android:fontFamily">sans-serif-light</item>
+ </style>
+</resources> \ No newline at end of file
diff --git a/res/values-v19/colors.xml b/res/values-v19/colors.xml
new file mode 100644
index 000000000..16c065d75
--- /dev/null
+++ b/res/values-v19/colors.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <color name="selection_background_color_dark">#484B4D</color>
+ <color name="selection_background_color_light">#E3E3E3</color>
+</resources> \ No newline at end of file
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index e8334cd60..751134a50 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -1,39 +1,42 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
- <attr name="action_about" format="reference" />
- <attr name="action_search" format="reference" />
- <attr name="action_settings" format="reference" />
- <attr name="action_stream" format="reference" />
- <attr name="av_download" format="reference" />
- <attr name="av_fast_forward" format="reference" />
- <attr name="av_pause" format="reference" />
- <attr name="av_play" format="reference" />
- <attr name="av_rewind" format="reference" />
- <attr name="content_discard" format="reference" />
- <attr name="content_new" format="reference" />
- <attr name="default_cover" format="reference" />
- <attr name="device_access_time" format="reference" />
- <attr name="location_web_site" format="reference" />
- <attr name="navigation_accept" format="reference" />
- <attr name="navigation_cancel" format="reference" />
- <attr name="navigation_expand" format="reference" />
- <attr name="navigation_collapse" format="reference" />
- <attr name="navigation_refresh" format="reference" />
- <attr name="navigation_up" format="reference" />
- <attr name="navigation_shownotes" format="reference" />
- <attr name="navigation_chapters" format="reference" />
- <attr name="social_share" format="reference" />
- <attr name="stat_playlist" format="reference" />
- <attr name="type_audio" format="reference" />
- <attr name="type_video" format="reference" />
- <attr name="borderless_button" format="reference" />
- <attr name="spinner_button" format="reference" />
- <attr name="overlay_drawable" format="reference" />
- <attr name="dragview_background" format="reference" />
- <attr name="dragview_float_background" format="reference" />
+ <attr name="action_about" format="reference"/>
+ <attr name="action_search" format="reference"/>
+ <attr name="action_settings" format="reference"/>
+ <attr name="action_stream" format="reference"/>
+ <attr name="av_download" format="reference"/>
+ <attr name="av_fast_forward" format="reference"/>
+ <attr name="av_pause" format="reference"/>
+ <attr name="av_play" format="reference"/>
+ <attr name="av_rewind" format="reference"/>
+ <attr name="content_discard" format="reference"/>
+ <attr name="content_new" format="reference"/>
+ <attr name="default_cover" format="reference"/>
+ <attr name="device_access_time" format="reference"/>
+ <attr name="location_web_site" format="reference"/>
+ <attr name="navigation_accept" format="reference"/>
+ <attr name="navigation_cancel" format="reference"/>
+ <attr name="navigation_expand" format="reference"/>
+ <attr name="navigation_collapse" format="reference"/>
+ <attr name="navigation_refresh" format="reference"/>
+ <attr name="navigation_up" format="reference"/>
+ <attr name="navigation_shownotes" format="reference"/>
+ <attr name="navigation_chapters" format="reference"/>
+ <attr name="social_share" format="reference"/>
+ <attr name="stat_playlist" format="reference"/>
+ <attr name="type_audio" format="reference"/>
+ <attr name="type_video" format="reference"/>
+ <attr name="borderless_button" format="reference"/>
+ <attr name="spinner_button" format="reference"/>
+ <attr name="overlay_drawable" format="reference"/>
+ <attr name="dragview_background" format="reference"/>
+ <attr name="dragview_float_background" format="reference"/>
+ <attr name="ic_action_overflow" format="reference"/>
<!-- Used in itemdescription -->
- <attr name="non_transparent_background" format="reference" />
- <attr name="overlay_background" format="color" />
+ <attr name="non_transparent_background" format="reference"/>
+ <attr name="overlay_background" format="color"/>
+ <attr name="nav_drawer_background" format="color"/>
+ <attr name="nav_drawer_toggle" format="reference"/>
</resources> \ No newline at end of file
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 8dea65a5b..f90b25a3a 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -4,13 +4,17 @@
<dimen name="widget_margin">8dp</dimen>
<dimen name="thumbnail_length">70dp</dimen>
<dimen name="dragview_length">54dp</dimen>
- <dimen name="external_player_height">55dp</dimen>
+ <dimen name="external_player_height">70dp</dimen>
<dimen name="enc_icons_size">20dp</dimen>
<dimen name="text_size_micro">12sp</dimen>
<dimen name="text_size_small">14sp</dimen>
+ <dimen name="text_size_navdrawer">16sp</dimen>
<dimen name="text_size_medium">18sp</dimen>
<dimen name="text_size_large">22sp</dimen>
<dimen name="status_indicator_width">36dp</dimen>
<dimen name="thumbnail_length_itemlist">80dp</dimen>
<dimen name="thumbnail_length_onlinefeedview">110dp</dimen>
+ <dimen name="thumbnail_length_navlist">42dp</dimen>
+ <dimen name="listview_secondary_button_width">48dp</dimen>
+ <dimen name="drawer_width">280dp</dimen>
</resources> \ No newline at end of file
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 6d36a5c07..cf3b02148 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -4,22 +4,33 @@
tools:ignore="MissingTranslation"
>
- <!-- Activitiy titles -->
+ <!-- Activitiy and fragment titles -->
<string name="app_name">AntennaPod</string>
<string name="feeds_label">Feeds</string>
<string name="podcasts_label">PODCASTS</string>
<string name="episodes_label">EPISODES</string>
+ <string name="new_episodes_label">New episodes</string>
<string name="new_label">New</string>
<string name="waiting_list_label">Waiting list</string>
<string name="settings_label">Settings</string>
<string name="add_new_feed_label">Add podcast</string>
<string name="downloads_label">Downloads</string>
+ <string name="downloads_running_label">Running</string>
+ <string name="downloads_completed_label">Completed</string>
+ <string name="downloads_log_label">Log</string>
<string name="cancel_download_label">Cancel Download</string>
<string name="download_log_label">Download log</string>
<string name="playback_history_label">Playback history</string>
<string name="gpodnet_main_label">gpodder.net</string>
<string name="gpodnet_auth_label">gpodder.net login</string>
+ <!-- New episodes fragment -->
+ <string name="recently_published_episodes_label">Recently published</string>
+
+ <!-- Main activity -->
+ <string name="drawer_open">Open menu</string>
+ <string name="drawer_close">Close menu</string>
+
<!-- Webview actions -->
<string name="open_in_browser_label">Open in browser</string>
<string name="copy_url_label">Copy URL</string>
@@ -59,12 +70,15 @@
<!-- 'Add Feed' Activity labels -->
<string name="feedurl_label">Feed URL</string>
<string name="txtvfeedurl_label">Add Podcast by URL</string>
- <string name="podcastdirectories_label">Podcast directories</string>
+ <string name="podcastdirectories_label">Find podcast in directory</string>
+ <string name="podcastdirectories_descr">You can search for new podcasts by name, category or popularity in the gpodder.net directory.</string>
+ <string name="browse_gpoddernet_label">Browse gpodder.net</string>
<!-- Actions on feeds -->
<string name="mark_all_read_label">Mark all as read</string>
+ <string name="mark_all_read_msg">Marked all episodes as read</string>
<string name="show_info_label">Show information</string>
- <string name="remove_feed_label">Remove Feed</string>
+ <string name="remove_feed_label">Remove podcast</string>
<string name="share_link_label">Share website link</string>
<string name="share_source_label">Share feed link</string>
<string name="feed_delete_confirmation_msg">Please confirm that you want to delete this feed and ALL episodes of this feed that you have downloaded.</string>
@@ -76,6 +90,7 @@
<string name="pause_label">Pause</string>
<string name="stream_label">Stream</string>
<string name="remove_label">Remove</string>
+ <string name="remove_episode_lable">Remove episode</string>
<string name="mark_read_label">Mark as read</string>
<string name="mark_unread_label">Mark as unread</string>
<string name="add_to_queue_label">Add to Queue</string>
@@ -349,10 +364,12 @@
<string name="status_playing_label">Episode is being played</string>
<string name="status_downloading_label">Episode is being downloaded</string>
<string name="status_downloaded_label">Episode is downloaded</string>
+ <string name="status_not_downloaded_label">Episode has not been downloaded yet</string>
<string name="status_unread_label">Item is new</string>
<string name="in_queue_label">Episode is in the queue</string>
<string name="new_episodes_count_label">Number of new episodes</string>
<string name="in_progress_episodes_count_label">Number of episodes you have started listening to</string>
+ <string name="drag_handle_content_description">Drag to change the position of this item</string>
<!-- OPML backup -->
<string name="backup_restored">"Restored feed subscriptions from backup"</string>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index d08b8060f..d6dccb426 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -33,8 +33,11 @@
<item name="attr/overlay_background">@color/overlay_light</item>
<item name="attr/spinner_button">@drawable/spinner_button</item>
<item name="attr/overlay_drawable">@drawable/overlay_drawable</item>
- <item name="attr/dragview_background">@drawable/dragview_background</item>
+ <item name="attr/dragview_background">@drawable/ic_drag_handle</item>
<item name="attr/dragview_float_background">@color/white</item>
+ <item name="attr/nav_drawer_background">@color/white</item>
+ <item name="attr/nav_drawer_toggle">@drawable/ic_drawer</item>
+ <item name="attr/ic_action_overflow">@drawable/ic_action_overflow</item>
</style>
<style name="Theme.AntennaPod.Dark" parent="@style/Theme.AppCompat">
@@ -69,43 +72,55 @@
<item name="attr/overlay_background">@color/overlay_dark</item>
<item name="attr/spinner_button">@drawable/spinner_button_dark</item>
<item name="attr/overlay_drawable">@drawable/overlay_drawable_dark</item>
- <item name="attr/dragview_background">@drawable/dragview_background_dark</item>
+ <item name="attr/dragview_background">@drawable/ic_drag_handle_dark</item>
<item name="attr/dragview_float_background">@color/black</item>
+ <item name="attr/nav_drawer_background">#3B3B3B</item>
+ <item name="attr/nav_drawer_toggle">@drawable/ic_drawer_dark</item>
+ <item name="attr/ic_action_overflow">@drawable/ic_action_overflow_dark</item>
+
</style>
<style name="UndoBar">
- <item name="android:layout_width">match_parent</item>
- <item name="android:layout_height">48dp</item>
- <item name="android:layout_gravity">bottom</item>
- <item name="android:layout_marginLeft">8dp</item>
- <item name="android:layout_marginRight">8dp</item>
- <item name="android:layout_marginBottom">16dp</item>
- <item name="android:orientation">horizontal</item>
- <item name="android:background">@drawable/undobar</item>
- <item name="android:clickable">true</item>
- <item name="android:divider">@drawable/undobar_divider</item>
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">48dp</item>
+ <item name="android:layout_gravity">bottom</item>
+ <item name="android:layout_marginLeft">8dp</item>
+ <item name="android:layout_marginRight">8dp</item>
+ <item name="android:layout_marginBottom">16dp</item>
+ <item name="android:orientation">horizontal</item>
+ <item name="android:background">@drawable/undobar</item>
+ <item name="android:clickable">true</item>
+ <item name="android:divider">@drawable/undobar_divider</item>
</style>
+
<style name="UndoBarMessage">
- <item name="android:layout_width">0dp</item>
- <item name="android:layout_weight">1</item>
- <item name="android:layout_height">wrap_content</item>
- <item name="android:layout_marginLeft">16dp</item>
- <item name="android:layout_gravity">center_vertical</item>
- <item name="android:layout_marginRight">16dp</item>
- <item name="android:textAppearance">?android:textAppearanceMedium</item>
- <item name="android:textColor">#fff</item>
+ <item name="android:layout_width">0dp</item>
+ <item name="android:layout_weight">1</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_marginLeft">16dp</item>
+ <item name="android:layout_gravity">center_vertical</item>
+ <item name="android:layout_marginRight">16dp</item>
+ <item name="android:textAppearance">?android:textAppearanceMedium</item>
+ <item name="android:textColor">#fff</item>
</style>
+
<style name="UndoBarButton">
- <item name="android:layout_width">wrap_content</item>
- <item name="android:layout_height">match_parent</item>
- <item name="android:paddingLeft">16dp</item>
- <item name="android:paddingRight">16dp</item>
- <item name="android:background">@drawable/undobar_button</item>
- <item name="android:drawableLeft">@drawable/ic_undobar_undo</item>
- <item name="android:drawablePadding">12dp</item>
- <item name="android:textAppearance">?android:textAppearanceSmall</item>
- <item name="android:textStyle">bold</item>
- <item name="android:textColor">#fff</item>
- <item name="android:text">@string/undo</item>
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">match_parent</item>
+ <item name="android:paddingLeft">16dp</item>
+ <item name="android:paddingRight">16dp</item>
+ <item name="android:background">@drawable/undobar_button</item>
+ <item name="android:drawableLeft">@drawable/ic_undobar_undo</item>
+ <item name="android:drawablePadding">12dp</item>
+ <item name="android:textAppearance">?android:textAppearanceSmall</item>
+ <item name="android:textStyle">bold</item>
+ <item name="android:textColor">#fff</item>
+ <item name="android:text">@string/undo</item>
+ </style>
+
+ <style name="AntennaPod.TextView.Heading" parent="@android:style/TextAppearance.Medium">
+ <item name="android:textSize">@dimen/text_size_large</item>
+ <item name="android:textStyle">italic</item>
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
</style>
</resources>
diff --git a/src/de/danoeh/antennapod/activity/AddFeedActivity.java b/src/de/danoeh/antennapod/activity/AddFeedActivity.java
index a77689ddb..54eff51c5 100644
--- a/src/de/danoeh/antennapod/activity/AddFeedActivity.java
+++ b/src/de/danoeh/antennapod/activity/AddFeedActivity.java
@@ -50,7 +50,6 @@ public class AddFeedActivity extends ActionBarActivity {
etxtFeedurl.setText(getIntent().getDataString());
}
- butBrowseMiroGuide = (Button) findViewById(R.id.butBrowseMiroguide);
butBrowserGpoddernet = (Button) findViewById(R.id.butBrowseGpoddernet);
butOpmlImport = (Button) findViewById(R.id.butOpmlImport);
butConfirm = (Button) findViewById(R.id.butConfirm);
diff --git a/src/de/danoeh/antennapod/activity/AudioplayerActivity.java b/src/de/danoeh/antennapod/activity/AudioplayerActivity.java
index de989fa46..7a4429705 100644
--- a/src/de/danoeh/antennapod/activity/AudioplayerActivity.java
+++ b/src/de/danoeh/antennapod/activity/AudioplayerActivity.java
@@ -4,11 +4,16 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.content.res.TypedArray;
+import android.os.AsyncTask;
import android.os.Bundle;
+import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.app.ListFragment;
+import android.support.v4.widget.DrawerLayout;
import android.util.Log;
+import android.view.Menu;
+import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
@@ -18,18 +23,20 @@ import android.widget.ImageView.ScaleType;
import de.danoeh.antennapod.BuildConfig;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.adapter.ChapterListAdapter;
+import de.danoeh.antennapod.adapter.NavListAdapter;
import de.danoeh.antennapod.asynctask.ImageLoader;
import de.danoeh.antennapod.dialog.VariableSpeedDialog;
-import de.danoeh.antennapod.feed.Chapter;
-import de.danoeh.antennapod.feed.MediaType;
-import de.danoeh.antennapod.feed.SimpleChapter;
+import de.danoeh.antennapod.feed.*;
import de.danoeh.antennapod.fragment.CoverFragment;
import de.danoeh.antennapod.fragment.ItemDescriptionFragment;
import de.danoeh.antennapod.preferences.UserPreferences;
import de.danoeh.antennapod.service.playback.PlaybackService;
+import de.danoeh.antennapod.storage.DBReader;
import de.danoeh.antennapod.util.playback.ExternalMedia;
import de.danoeh.antennapod.util.playback.Playable;
+import java.util.List;
+
/**
* Activity for playing audio files.
*/
@@ -44,6 +51,11 @@ public class AudioplayerActivity extends MediaplayerActivity {
private static final String PREF_KEY_SELECTED_FRAGMENT_POSITION = "selectedFragmentPosition";
private static final String PREF_PLAYABLE_ID = "playableId";
+ private DrawerLayout drawerLayout;
+ private NavListAdapter navAdapter;
+ private ListView navList;
+ private ActionBarDrawerToggle drawerToggle;
+
private Fragment[] detachedFragments;
private CoverFragment coverFragment;
@@ -58,7 +70,6 @@ public class AudioplayerActivity extends MediaplayerActivity {
private int savedPosition = -1;
private TextView txtvTitle;
- private TextView txtvFeed;
private Button butPlaybackSpeed;
private ImageButton butNavLeft;
private ImageButton butNavRight;
@@ -108,6 +119,8 @@ public class AudioplayerActivity extends MediaplayerActivity {
super.onStop();
if (BuildConfig.DEBUG)
Log.d(TAG, "onStop");
+ cancelLoadTask();
+ EventDistributor.getInstance().unregister(contentUpdate);
}
@@ -142,6 +155,7 @@ public class AudioplayerActivity extends MediaplayerActivity {
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
+ drawerToggle.onConfigurationChanged(newConfig);
}
@Override
@@ -149,6 +163,7 @@ public class AudioplayerActivity extends MediaplayerActivity {
// super.onSaveInstanceState(outState); would cause crash
if (BuildConfig.DEBUG)
Log.d(TAG, "onSaveInstanceState");
+
}
@Override
@@ -223,6 +238,8 @@ public class AudioplayerActivity extends MediaplayerActivity {
switchToFragment(savedPosition);
}
+ EventDistributor.getInstance().register(contentUpdate);
+ loadData();
}
@Override
@@ -382,12 +399,52 @@ public class AudioplayerActivity extends MediaplayerActivity {
protected void setupGUI() {
super.setupGUI();
resetFragmentView();
+ drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
+ navList = (ListView) findViewById(R.id.nav_list);
txtvTitle = (TextView) findViewById(R.id.txtvTitle);
- txtvFeed = (TextView) findViewById(R.id.txtvFeed);
butNavLeft = (ImageButton) findViewById(R.id.butNavLeft);
butNavRight = (ImageButton) findViewById(R.id.butNavRight);
butPlaybackSpeed = (Button) findViewById(R.id.butPlaybackSpeed);
+ TypedArray typedArray = obtainStyledAttributes(new int[]{R.attr.nav_drawer_toggle});
+ drawerToggle = new ActionBarDrawerToggle(this, drawerLayout, typedArray.getResourceId(0,0), R.string.drawer_open, R.string.drawer_close) {
+ String currentTitle = getSupportActionBar().getTitle().toString();
+ @Override
+ public void onDrawerOpened(View drawerView) {
+ super.onDrawerOpened(drawerView);
+ currentTitle = getSupportActionBar().getTitle().toString();
+ getSupportActionBar().setTitle(R.string.app_name);
+ supportInvalidateOptionsMenu();
+ }
+
+ @Override
+ public void onDrawerClosed(View drawerView) {
+ super.onDrawerClosed(drawerView);
+ getSupportActionBar().setTitle(currentTitle);
+ supportInvalidateOptionsMenu();
+ }
+ };
+ typedArray.recycle();
+ drawerToggle.setDrawerIndicatorEnabled(false);
+
+ navAdapter = new NavListAdapter(itemAccess, this);
+ navList.setAdapter(navAdapter);
+ navList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ int viewType = parent.getAdapter().getItemViewType(position);
+ if (viewType != NavListAdapter.VIEW_TYPE_SECTION_DIVIDER) {
+ int relPos = (viewType == NavListAdapter.VIEW_TYPE_NAV) ? position : position - NavListAdapter.SUBSCRIPTION_OFFSET;
+ Intent intent = new Intent(AudioplayerActivity.this, MainActivity.class);
+ intent.putExtra(MainActivity.EXTRA_NAV_TYPE, viewType);
+ intent.putExtra(MainActivity.EXTRA_NAV_INDEX, relPos);
+ startActivity(intent);
+ }
+ drawerLayout.closeDrawer(navList);
+ }
+ });
+ drawerToggle.syncState();
+
butNavLeft.setOnClickListener(new OnClickListener() {
@Override
@@ -491,7 +548,6 @@ public class AudioplayerActivity extends MediaplayerActivity {
return false;
}
txtvTitle.setText(media.getEpisodeTitle());
- txtvFeed.setText(media.getFeedTitle());
if (media.getChapters() != null) {
butNavRight.setVisibility(View.VISIBLE);
} else {
@@ -551,4 +607,78 @@ public class AudioplayerActivity extends MediaplayerActivity {
return R.layout.audioplayer_activity;
}
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (drawerToggle.onOptionsItemSelected(item)) {
+ return true;
+ } else {
+ return super.onOptionsItemSelected(item);
+ }
+ }
+
+ private List<Feed> feeds;
+ private AsyncTask<Void, Void, List<Feed>> loadTask;
+
+ private void loadData() {
+ loadTask = new AsyncTask<Void, Void, List<Feed>>() {
+ @Override
+ protected List<Feed> doInBackground(Void... params) {
+ return DBReader.getFeedList(AudioplayerActivity.this);
+ }
+
+ @Override
+ protected void onPostExecute(List<Feed> result) {
+ super.onPostExecute(result);
+ feeds = result;
+ if (navAdapter != null) {
+ navAdapter.notifyDataSetChanged();
+ }
+ }
+ };
+ loadTask.execute();
+ }
+
+ private void cancelLoadTask() {
+ if (loadTask != null) {
+ loadTask.cancel(true);
+ }
+ }
+
+ private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
+
+ @Override
+ public void update(EventDistributor eventDistributor, Integer arg) {
+ if ((EventDistributor.FEED_LIST_UPDATE & arg) != 0) {
+ if (BuildConfig.DEBUG)
+ Log.d(TAG, "Received contentUpdate Intent.");
+ loadData();
+ }
+ }
+ };
+
+ private final NavListAdapter.ItemAccess itemAccess = new NavListAdapter.ItemAccess() {
+ @Override
+ public int getCount() {
+ if (feeds != null) {
+ return feeds.size();
+ } else {
+ return 0;
+ }
+ }
+
+ @Override
+ public Feed getItem(int position) {
+ if (feeds != null && position < feeds.size()) {
+ return feeds.get(position);
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public int getSelectedItemIndex() {
+ return -1;
+ }
+ };
}
diff --git a/src/de/danoeh/antennapod/activity/DownloadActivity.java b/src/de/danoeh/antennapod/activity/DownloadActivity.java
index 996929cdb..416de73a4 100644
--- a/src/de/danoeh/antennapod/activity/DownloadActivity.java
+++ b/src/de/danoeh/antennapod/activity/DownloadActivity.java
@@ -180,8 +180,8 @@ public class DownloadActivity extends ActionBarActivity implements
@Override
public void onDownloadDataAvailable(List<Downloader> downloaderList) {
- dla = new DownloadlistAdapter(DownloadActivity.this, 0,
- downloaderList);
+ //dla = new DownloadlistAdapter(DownloadActivity.this, 0,
+ // downloaderList);
listview.setAdapter(dla);
dla.notifyDataSetChanged();
}
diff --git a/src/de/danoeh/antennapod/activity/FeedItemlistActivity.java b/src/de/danoeh/antennapod/activity/FeedItemlistActivity.java
index d0305eada..95ccb859f 100644
--- a/src/de/danoeh/antennapod/activity/FeedItemlistActivity.java
+++ b/src/de/danoeh/antennapod/activity/FeedItemlistActivity.java
@@ -166,7 +166,7 @@ public class FeedItemlistActivity extends ActionBarActivity {
public boolean onOptionsItemSelected(MenuItem item) {
try {
if (FeedMenuHandler.onOptionsItemClicked(this, item, feed)) {
- filf.getListAdapter().notifyDataSetChanged();
+ // filf.getListAdapter().notifyDataSetChanged();
} else {
switch (item.getItemId()) {
case R.id.remove_item:
diff --git a/src/de/danoeh/antennapod/activity/MainActivity.java b/src/de/danoeh/antennapod/activity/MainActivity.java
index 1a49e63d0..5fcd45289 100644
--- a/src/de/danoeh/antennapod/activity/MainActivity.java
+++ b/src/de/danoeh/antennapod/activity/MainActivity.java
@@ -1,164 +1,295 @@
package de.danoeh.antennapod.activity;
-import android.app.SearchManager;
-import android.app.SearchableInfo;
-import android.content.Context;
import android.content.Intent;
+import android.content.res.Configuration;
+import android.content.res.TypedArray;
import android.media.AudioManager;
+import android.os.AsyncTask;
import android.os.Bundle;
+import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentPagerAdapter;
+import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
-import android.support.v4.view.MenuItemCompat;
-import android.support.v4.view.ViewPager;
+import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarActivity;
-import android.support.v7.widget.SearchView;
import android.util.Log;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.Window;
+import android.view.*;
+import android.widget.AdapterView;
+import android.widget.ListView;
import de.danoeh.antennapod.BuildConfig;
import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.adapter.NavListAdapter;
import de.danoeh.antennapod.feed.EventDistributor;
-import de.danoeh.antennapod.fragment.EpisodesFragment;
-import de.danoeh.antennapod.fragment.ExternalPlayerFragment;
-import de.danoeh.antennapod.fragment.FeedlistFragment;
+import de.danoeh.antennapod.feed.Feed;
+import de.danoeh.antennapod.fragment.*;
import de.danoeh.antennapod.preferences.UserPreferences;
-import de.danoeh.antennapod.service.download.DownloadService;
-import de.danoeh.antennapod.service.playback.PlaybackService;
import de.danoeh.antennapod.storage.DBReader;
-import de.danoeh.antennapod.storage.DBTasks;
-import de.danoeh.antennapod.storage.DownloadRequester;
import de.danoeh.antennapod.util.StorageUtils;
+import org.apache.commons.lang3.StringUtils;
-import java.util.ArrayList;
+import java.util.List;
/**
* The activity that is shown when the user launches the app.
*/
public class MainActivity extends ActionBarActivity {
private static final String TAG = "MainActivity";
-
private static final int EVENTS = EventDistributor.DOWNLOAD_HANDLED
- | EventDistributor.DOWNLOAD_QUEUED;
+ | EventDistributor.DOWNLOAD_QUEUED
+ | EventDistributor.FEED_LIST_UPDATE
+ | EventDistributor.UNREAD_ITEMS_UPDATE;
+
+ public static final String EXTRA_NAV_INDEX = "nav_index";
+ public static final String EXTRA_NAV_TYPE = "nav_type";
+ public static final String EXTRA_FRAGMENT_ARGS = "fragment_args";
+
+ public static final int POS_NEW = 0,
+ POS_QUEUE = 1,
+ POS_DOWNLOADS = 2,
+ POS_HISTORY = 3,
+ POS_ADD = 4;
- private ViewPager viewpager;
- private TabsAdapter pagerAdapter;
private ExternalPlayerFragment externalPlayerFragment;
+ private DrawerLayout drawerLayout;
+
+ private ListView navList;
+ private NavListAdapter navAdapter;
+
+ private ActionBarDrawerToggle drawerToogle;
+
+ private CharSequence drawerTitle;
+ private CharSequence currentTitle;
- private static boolean appLaunched = false;
@Override
public void onCreate(Bundle savedInstanceState) {
setTheme(UserPreferences.getTheme());
super.onCreate(savedInstanceState);
- StorageUtils.checkStorageAvailability(this);
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
+ StorageUtils.checkStorageAvailability(this);
setContentView(R.layout.main);
setVolumeControlStream(AudioManager.STREAM_MUSIC);
- getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
+ drawerTitle = currentTitle = getTitle();
- viewpager = (ViewPager) findViewById(R.id.viewpager);
- pagerAdapter = new TabsAdapter(this, viewpager);
+ drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
+ navList = (ListView) findViewById(R.id.nav_list);
- viewpager.setAdapter(pagerAdapter);
+ TypedArray typedArray = obtainStyledAttributes(new int[]{R.attr.nav_drawer_toggle});
+ drawerToogle = new ActionBarDrawerToggle(this, drawerLayout, typedArray.getResourceId(0, 0), R.string.drawer_open, R.string.drawer_close) {
+ @Override
+ public void onDrawerOpened(View drawerView) {
+ super.onDrawerOpened(drawerView);
+ currentTitle = getSupportActionBar().getTitle();
+ getSupportActionBar().setTitle(drawerTitle);
+ supportInvalidateOptionsMenu();
+ }
+
+ @Override
+ public void onDrawerClosed(View drawerView) {
+ super.onDrawerClosed(drawerView);
+ getSupportActionBar().setTitle(currentTitle);
+ supportInvalidateOptionsMenu();
+
+ }
+ };
+ typedArray.recycle();
- ActionBar.Tab feedsTab = getSupportActionBar().newTab();
- feedsTab.setText(R.string.podcasts_label);
- ActionBar.Tab episodesTab = getSupportActionBar().newTab();
- episodesTab.setText(R.string.episodes_label);
+ drawerLayout.setDrawerListener(drawerToogle);
+ FragmentManager fm = getSupportFragmentManager();
- pagerAdapter.addTab(feedsTab, FeedlistFragment.class, null);
- pagerAdapter.addTab(episodesTab, EpisodesFragment.class, null);
+ FragmentTransaction transaction = fm.beginTransaction();
+
+ Fragment mainFragment = fm.findFragmentByTag("main");
+ if (mainFragment != null) {
+ transaction.replace(R.id.main_view, mainFragment);
+ } else {
+ loadFragment(NavListAdapter.VIEW_TYPE_NAV, POS_NEW, null);
+ }
- FragmentTransaction transaction = getSupportFragmentManager()
- .beginTransaction();
externalPlayerFragment = new ExternalPlayerFragment();
transaction.replace(R.id.playerFragment, externalPlayerFragment);
transaction.commit();
- // executed on application start
- if (!appLaunched && getIntent().getAction() != null
- && getIntent().getAction().equals(Intent.ACTION_MAIN)) {
- appLaunched = true;
- if (DBReader.getNumberOfUnreadItems(this) > 0) {
- // select 'episodes' tab
- getSupportActionBar().setSelectedNavigationItem(1);
+ getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+ getSupportActionBar().setHomeButtonEnabled(true);
+
+ navAdapter = new NavListAdapter(itemAccess, this);
+ navList.setAdapter(navAdapter);
+ navList.setOnItemClickListener(navListClickListener);
+
+ }
+
+ public ActionBar getMainActivtyActionBar() {
+ return getSupportActionBar();
+ }
+
+ public List<Feed> getFeeds() {
+ return feeds;
+ }
+
+ private void loadFragment(int viewType, int relPos, Bundle args) {
+ FragmentManager fragmentManager = getSupportFragmentManager();
+ // clear back stack
+ for (int i = 0; i < fragmentManager.getBackStackEntryCount(); i++) {
+ fragmentManager.popBackStack();
+ }
+
+ FragmentTransaction fT = fragmentManager.beginTransaction();
+ Fragment fragment = null;
+ if (viewType == NavListAdapter.VIEW_TYPE_NAV) {
+ switch (relPos) {
+ case POS_NEW:
+ fragment = new NewEpisodesFragment();
+ break;
+ case POS_QUEUE:
+ fragment = new QueueFragment();
+ break;
+ case POS_DOWNLOADS:
+ fragment = new DownloadsFragment();
+ break;
+ case POS_HISTORY:
+ fragment = new PlaybackHistoryFragment();
+ break;
+ case POS_ADD:
+ fragment = new AddFeedFragment();
+ break;
+
+ }
+ currentTitle = getString(NavListAdapter.NAV_TITLES[relPos]);
+ selectedNavListIndex = relPos;
+
+ } else if (viewType == NavListAdapter.VIEW_TYPE_SUBSCRIPTION) {
+ Feed feed = itemAccess.getItem(relPos);
+ currentTitle = "";
+ fragment = ItemlistFragment.newInstance(feed.getId());
+ selectedNavListIndex = NavListAdapter.SUBSCRIPTION_OFFSET + relPos;
+
+ }
+ if (fragment != null) {
+ if (args != null) {
+ fragment.setArguments(args);
}
+ fT.replace(R.id.main_view, fragment, "main");
+ fragmentManager.popBackStack();
}
+ fT.commit();
+ getSupportActionBar().setTitle(currentTitle);
+ if (navAdapter != null) {
+ navAdapter.notifyDataSetChanged();
+ }
+ }
+
+ public void loadNavFragment(int position, Bundle args) {
+ loadFragment(NavListAdapter.VIEW_TYPE_NAV, position, args);
+ }
+
+ public void loadFeedFragment(long feedID) {
+ if (feeds != null) {
+ for (int i = 0; i < feeds.size(); i++) {
+ if (feeds.get(i).getId() == feedID) {
+ loadFragment(NavListAdapter.VIEW_TYPE_SUBSCRIPTION, i, null);
+ break;
+ }
+ }
+ }
+ }
+
+ public void loadChildFragment(Fragment fragment) {
+ if (fragment == null) throw new IllegalArgumentException("fragment = null");
+ FragmentManager fm = getSupportFragmentManager();
+ fm.beginTransaction()
+ .replace(R.id.main_view, fragment, "main")
+ .addToBackStack(null)
+ .commit();
+ }
+
+ private AdapterView.OnItemClickListener navListClickListener = new AdapterView.OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ int viewType = parent.getAdapter().getItemViewType(position);
+ if (viewType != NavListAdapter.VIEW_TYPE_SECTION_DIVIDER && position != selectedNavListIndex) {
+ int relPos = (viewType == NavListAdapter.VIEW_TYPE_NAV) ? position : position - NavListAdapter.SUBSCRIPTION_OFFSET;
+ loadFragment(viewType, relPos, null);
+ selectedNavListIndex = position;
+ navAdapter.notifyDataSetChanged();
+ }
+ drawerLayout.closeDrawer(navList);
+ }
+ };
+
+ @Override
+ protected void onPostCreate(Bundle savedInstanceState) {
+ super.onPostCreate(savedInstanceState);
+ drawerToogle.syncState();
if (savedInstanceState != null) {
- getSupportActionBar().setSelectedNavigationItem(
- savedInstanceState.getInt("tab", 0));
+ currentTitle = savedInstanceState.getString("title");
+ if (!drawerLayout.isDrawerOpen(navList)) {
+ getSupportActionBar().setTitle(currentTitle);
+ }
+ selectedNavListIndex = savedInstanceState.getInt("selectedNavIndex");
}
}
@Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ drawerToogle.onConfigurationChanged(newConfig);
+ }
+
+ @Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
- outState.putInt("tab", getSupportActionBar()
- .getSelectedNavigationIndex());
+ outState.putString("title", getSupportActionBar().getTitle().toString());
+ outState.putInt("selectedNavIndex", selectedNavListIndex);
+
}
@Override
protected void onPause() {
super.onPause();
- EventDistributor.getInstance().unregister(contentUpdate);
}
@Override
protected void onResume() {
super.onResume();
StorageUtils.checkStorageAvailability(this);
- updateProgressBarVisibility();
EventDistributor.getInstance().register(contentUpdate);
- }
- private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
-
- @Override
- public void update(EventDistributor eventDistributor, Integer arg) {
- if ((EVENTS & arg) != 0) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Received contentUpdate Intent.");
- updateProgressBarVisibility();
+ Intent intent = getIntent();
+ if (StringUtils.equals(intent.getAction(), Intent.ACTION_SEND)) {
+ String extra = intent.getStringExtra(Intent.EXTRA_TEXT);
+ if (extra != null) {
+ Bundle args = new Bundle();
+ args.putString(AddFeedFragment.ARG_FEED_URL, extra);
+ loadFragment(NavListAdapter.VIEW_TYPE_NAV, POS_ADD, args);
+ selectedNavListIndex = POS_ADD;
+ navAdapter.notifyDataSetChanged();
}
+ } else if (feeds != null && intent.hasExtra(EXTRA_NAV_INDEX) && intent.hasExtra(EXTRA_NAV_TYPE)) {
+ handleNavIntent();
}
- };
- private void updateProgressBarVisibility() {
- if (DownloadService.isRunning
- && DownloadRequester.getInstance().isDownloadingFeeds()) {
- setSupportProgressBarIndeterminateVisibility(true);
- } else {
- setSupportProgressBarIndeterminateVisibility(false);
- }
- supportInvalidateOptionsMenu();
+ loadData();
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ cancelLoadTask();
+ EventDistributor.getInstance().unregister(contentUpdate);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
+ if (drawerToogle.onOptionsItemSelected(item)) {
+ return true;
+ }
switch (item.getItemId()) {
- case R.id.add_feed:
- startActivity(new Intent(this, AddFeedActivity.class));
- return true;
- case R.id.all_feed_refresh:
- DBTasks.refreshAllFeeds(this, null);
- return true;
- case R.id.show_downloads:
- startActivity(new Intent(this, DownloadActivity.class));
- return true;
case R.id.show_preferences:
startActivity(new Intent(this, PreferenceActivity.class));
return true;
- case R.id.show_player:
- startActivity(PlaybackService.getPlayerActivityIntent(this));
- return true;
- case R.id.show_playback_history:
- startActivity(new Intent(this, PlaybackHistoryActivity.class));
- return true;
default:
return super.onOptionsItemSelected(item);
}
@@ -167,13 +298,7 @@ public class MainActivity extends ActionBarActivity {
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
- MenuItem refreshAll = menu.findItem(R.id.all_feed_refresh);
- if (DownloadService.isRunning
- && DownloadRequester.getInstance().isDownloadingFeeds()) {
- refreshAll.setVisible(false);
- } else {
- refreshAll.setVisible(true);
- }
+
return true;
}
@@ -182,104 +307,96 @@ public class MainActivity extends ActionBarActivity {
super.onCreateOptionsMenu(menu);
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main, menu);
-
- SearchManager searchManager =
- (SearchManager) getSystemService(Context.SEARCH_SERVICE);
- MenuItem searchItem = menu.findItem(R.id.search_item);
- SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchItem);
- if (searchView == null) {
- MenuItemCompat.setActionView(searchItem, new SearchView(this));
- searchView = (SearchView) MenuItemCompat.getActionView(searchItem);
- }
- searchView.setIconifiedByDefault(true);
-
- SearchableInfo info = searchManager.getSearchableInfo(getComponentName());
- searchView.setSearchableInfo(
- searchManager.getSearchableInfo(getComponentName()));
-
-
return true;
}
- public static class TabsAdapter extends FragmentPagerAdapter implements
- ActionBar.TabListener, ViewPager.OnPageChangeListener {
- private final Context mContext;
- private final ActionBar mActionBar;
- private final ViewPager mViewPager;
- private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
-
- static final class TabInfo {
- private final Class<?> clss;
- private final Bundle args;
-
- TabInfo(Class<?> _class, Bundle _args) {
- clss = _class;
- args = _args;
- }
- }
-
- public TabsAdapter(MainActivity activity, ViewPager pager) {
- super(activity.getSupportFragmentManager());
- mContext = activity;
- mActionBar = activity.getSupportActionBar();
- mViewPager = pager;
- mViewPager.setAdapter(this);
- mViewPager.setOnPageChangeListener(this);
- }
-
- public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args) {
- TabInfo info = new TabInfo(clss, args);
- tab.setTag(info);
- tab.setTabListener(this);
- mTabs.add(info);
- mActionBar.addTab(tab);
- notifyDataSetChanged();
- }
+ private List<Feed> feeds;
+ private AsyncTask<Void, Void, List<Feed>> loadTask;
+ private int selectedNavListIndex = 0;
+ private NavListAdapter.ItemAccess itemAccess = new NavListAdapter.ItemAccess() {
@Override
public int getCount() {
- return mTabs.size();
+ if (feeds != null) {
+ return feeds.size();
+ } else {
+ return 0;
+ }
}
@Override
- public Fragment getItem(int position) {
- TabInfo info = mTabs.get(position);
- return Fragment.instantiate(mContext, info.clss.getName(),
- info.args);
+ public Feed getItem(int position) {
+ if (feeds != null && position < feeds.size()) {
+ return feeds.get(position);
+ } else {
+ return null;
+ }
}
@Override
- public void onPageScrolled(int position, float positionOffset,
- int positionOffsetPixels) {
+ public int getSelectedItemIndex() {
+ return selectedNavListIndex;
}
- @Override
- public void onPageSelected(int position) {
- mActionBar.setSelectedNavigationItem(position);
- }
- @Override
- public void onPageScrollStateChanged(int state) {
- }
+ };
- @Override
- public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {
- Object tag = tab.getTag();
- for (int i = 0; i < mTabs.size(); i++) {
- if (mTabs.get(i) == tag) {
- mViewPager.setCurrentItem(i);
+ private void loadData() {
+ cancelLoadTask();
+ loadTask = new AsyncTask<Void, Void, List<Feed>>() {
+ @Override
+ protected List<Feed> doInBackground(Void... params) {
+ return DBReader.getFeedList(MainActivity.this);
+ }
+
+ @Override
+ protected void onPostExecute(List<Feed> result) {
+ super.onPostExecute(result);
+ boolean handleIntent = (feeds == null);
+
+ feeds = result;
+ navAdapter.notifyDataSetChanged();
+
+ if (handleIntent) {
+ handleNavIntent();
}
}
+ };
+ loadTask.execute();
+ }
+
+ private void cancelLoadTask() {
+ if (loadTask != null) {
+ loadTask.cancel(true);
}
+ }
- @Override
- public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) {
+ private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
+ @Override
+ public void update(EventDistributor eventDistributor, Integer arg) {
+ if ((EVENTS & arg) != 0) {
+ if (BuildConfig.DEBUG)
+ Log.d(TAG, "Received contentUpdate Intent.");
+ loadData();
+ }
}
+ };
- @Override
- public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) {
+ private void handleNavIntent() {
+ Intent intent = getIntent();
+ if (intent.hasExtra(EXTRA_NAV_INDEX) && intent.hasExtra(EXTRA_NAV_TYPE)) {
+ int index = intent.getIntExtra(EXTRA_NAV_INDEX, 0);
+ int type = intent.getIntExtra(EXTRA_NAV_TYPE, NavListAdapter.VIEW_TYPE_NAV);
+ Bundle args = intent.getBundleExtra(EXTRA_FRAGMENT_ARGS);
+ loadFragment(type, index, args);
}
+ setIntent(new Intent(MainActivity.this, MainActivity.class)); // to avoid handling the intent twice when the configuration changes
}
+ @Override
+ protected void onNewIntent(Intent intent) {
+ super.onNewIntent(intent);
+ setIntent(intent);
+ }
}
diff --git a/src/de/danoeh/antennapod/activity/SearchActivity.java b/src/de/danoeh/antennapod/activity/SearchActivity.java
index f330aeb7d..02c0838b3 100644
--- a/src/de/danoeh/antennapod/activity/SearchActivity.java
+++ b/src/de/danoeh/antennapod/activity/SearchActivity.java
@@ -58,7 +58,7 @@ public class SearchActivity extends ActionBarActivity implements AdapterView.OnI
txtvStatus = (TextView) findViewById(android.R.id.empty);
listView.setOnItemClickListener(this);
- searchAdapter = new SearchlistAdapter(this, 0, new ArrayList<SearchResult>());
+ //searchAdapter = new SearchlistAdapter(this, 0, new ArrayList<SearchResult>());
listView.setAdapter(searchAdapter);
listView.setEmptyView(txtvStatus);
}
@@ -131,7 +131,7 @@ public class SearchActivity extends ActionBarActivity implements AdapterView.OnI
@SuppressLint({"NewApi", "NewApi"})
private void handleSearchRequest(final String query) {
if (searchAdapter != null) {
- searchAdapter.clear();
+ // searchAdapter.clear();
searchAdapter.notifyDataSetChanged();
}
txtvStatus.setText(R.string.search_status_searching);
@@ -154,9 +154,9 @@ public class SearchActivity extends ActionBarActivity implements AdapterView.OnI
Log.d(TAG, "Found " + result.size()
+ " results");
- searchAdapter.clear();
+ // searchAdapter.clear();
for (SearchResult s : result) {
- searchAdapter.add(s);
+ // searchAdapter.add(s);
}
searchAdapter.notifyDataSetChanged();
txtvStatus
diff --git a/src/de/danoeh/antennapod/adapter/ActionButtonUtils.java b/src/de/danoeh/antennapod/adapter/ActionButtonUtils.java
new file mode 100644
index 000000000..78d62a8de
--- /dev/null
+++ b/src/de/danoeh/antennapod/adapter/ActionButtonUtils.java
@@ -0,0 +1,63 @@
+package de.danoeh.antennapod.adapter;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.view.View;
+import android.widget.ImageButton;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.feed.FeedItem;
+import de.danoeh.antennapod.feed.FeedMedia;
+import de.danoeh.antennapod.storage.DownloadRequester;
+
+/**
+ * Utility methods for the action button that is displayed on the right hand side
+ * of a listitem.
+ */
+public class ActionButtonUtils {
+
+ private final int[] labels;
+ private final TypedArray drawables;
+ private final Context context;
+
+ public ActionButtonUtils(Context context) {
+ if (context == null) throw new IllegalArgumentException("context = null");
+ this.context = context;
+ drawables = context.obtainStyledAttributes(new int[]{
+ R.attr.av_play, R.attr.navigation_cancel, R.attr.av_download});
+ labels = new int[]{R.string.play_label, R.string.cancel_download_label, R.string.download_label};
+ }
+
+ /**
+ * Sets the displayed bitmap and content description of the given
+ * action button so that it matches the state of the FeedItem.
+ */
+ public void configureActionButton(ImageButton butSecondary, FeedItem item) {
+ if (butSecondary == null || item == null) throw new IllegalArgumentException("butSecondary or item was null");
+ final FeedMedia media = item.getMedia();
+ if (media != null) {
+ final boolean isDownloadingMedia = DownloadRequester.getInstance().isDownloadingFile(media);
+ if (!media.isDownloaded()) {
+ if (isDownloadingMedia) {
+ // item is being downloaded
+ butSecondary.setVisibility(View.VISIBLE);
+ butSecondary.setImageDrawable(drawables
+ .getDrawable(1));
+ butSecondary.setContentDescription(context.getString(labels[1]));
+ } else {
+ // item is not downloaded and not being downloaded
+ butSecondary.setVisibility(View.VISIBLE);
+ butSecondary.setImageDrawable(drawables.getDrawable(2));
+ butSecondary.setContentDescription(context.getString(labels[2]));
+ }
+ } else {
+ // item is not being downloaded
+ butSecondary.setVisibility(View.VISIBLE);
+ butSecondary
+ .setImageDrawable(drawables.getDrawable(0));
+ butSecondary.setContentDescription(context.getString(labels[0]));
+ }
+ } else {
+ butSecondary.setVisibility(View.INVISIBLE);
+ }
+ }
+}
diff --git a/src/de/danoeh/antennapod/adapter/DefaultActionButtonCallback.java b/src/de/danoeh/antennapod/adapter/DefaultActionButtonCallback.java
new file mode 100644
index 000000000..3acd587af
--- /dev/null
+++ b/src/de/danoeh/antennapod/adapter/DefaultActionButtonCallback.java
@@ -0,0 +1,49 @@
+package de.danoeh.antennapod.adapter;
+
+import android.content.Context;
+import android.widget.Toast;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.dialog.DownloadRequestErrorDialogCreator;
+import de.danoeh.antennapod.feed.FeedItem;
+import de.danoeh.antennapod.feed.FeedMedia;
+import de.danoeh.antennapod.storage.DBTasks;
+import de.danoeh.antennapod.storage.DownloadRequestException;
+import de.danoeh.antennapod.storage.DownloadRequester;
+
+/**
+ * Default implementation of an ActionButtonCallback
+ */
+public class DefaultActionButtonCallback implements ActionButtonCallback {
+ private static final String TAG = "DefaultActionButtonCallback";
+
+ private final Context context;
+
+ public DefaultActionButtonCallback(Context context) {
+ if (context == null) throw new IllegalArgumentException("context = null");
+ this.context = context;
+ }
+
+ @Override
+ public void onActionButtonPressed(final FeedItem item) {
+ final FeedMedia media = item.getMedia();
+ if (media == null) {
+ return;
+ }
+
+ boolean isDownloading = DownloadRequester.getInstance().isDownloadingFile(media);
+ if (!isDownloading && !media.isDownloaded()) {
+ try {
+ DBTasks.downloadFeedItems(context, item);
+ Toast.makeText(context, R.string.status_downloading_label, Toast.LENGTH_SHORT).show();
+ } catch (DownloadRequestException e) {
+ e.printStackTrace();
+ DownloadRequestErrorDialogCreator.newRequestErrorDialog(context, e.getMessage());
+ }
+ } else if (isDownloading) {
+ DownloadRequester.getInstance().cancelDownload(context, media);
+ Toast.makeText(context, R.string.download_cancelled_msg, Toast.LENGTH_SHORT).show();
+ } else { // media is downloaded
+ DBTasks.playMedia(context, media, true, true, false);
+ }
+ }
+}
diff --git a/src/de/danoeh/antennapod/adapter/DownloadedEpisodesListAdapter.java b/src/de/danoeh/antennapod/adapter/DownloadedEpisodesListAdapter.java
new file mode 100644
index 000000000..e873a9e5a
--- /dev/null
+++ b/src/de/danoeh/antennapod/adapter/DownloadedEpisodesListAdapter.java
@@ -0,0 +1,124 @@
+package de.danoeh.antennapod.adapter;
+
+import android.content.Context;
+import android.text.format.DateUtils;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.TextView;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.asynctask.ImageLoader;
+import de.danoeh.antennapod.feed.FeedItem;
+import de.danoeh.antennapod.util.Converter;
+
+/**
+ * Shows a list of downloaded episodes
+ */
+public class DownloadedEpisodesListAdapter extends BaseAdapter {
+
+ private final Context context;
+ private final ItemAccess itemAccess;
+
+ public DownloadedEpisodesListAdapter(Context context, ItemAccess itemAccess) {
+ super();
+ this.context = context;
+ this.itemAccess = itemAccess;
+ }
+
+ @Override
+ public int getCount() {
+ return itemAccess.getCount();
+ }
+
+ @Override
+ public Object getItem(int position) {
+ return itemAccess.getItem(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ Holder holder;
+ final FeedItem item = (FeedItem) getItem(position);
+ if (item == null) return null;
+
+ if (convertView == null) {
+ holder = new Holder();
+ LayoutInflater inflater = (LayoutInflater) context
+ .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ convertView = inflater.inflate(R.layout.downloaded_episodeslist_item,
+ null);
+ holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
+ holder.pubDate = (TextView) convertView
+ .findViewById(R.id.txtvPublished);
+ holder.butSecondary = (ImageButton) convertView
+ .findViewById(R.id.butSecondaryAction);
+ holder.statusPlaying = (ImageView) convertView
+ .findViewById(R.id.statusPlaying);
+ holder.imageView = (ImageView) convertView.findViewById(R.id.imgvImage);
+ holder.txtvSize = (TextView) convertView.findViewById(R.id.txtvSize);
+ convertView.setTag(holder);
+ } else {
+ holder = (Holder) convertView.getTag();
+ }
+
+ holder.title.setText(item.getTitle());
+ holder.pubDate.setText(DateUtils.formatDateTime(context, item.getPubDate().getTime(), DateUtils.FORMAT_SHOW_DATE));
+ holder.txtvSize.setText(Converter.byteToString(item.getMedia().getSize()));
+ FeedItem.State state = item.getState();
+
+ if (state == FeedItem.State.PLAYING) {
+ holder.statusPlaying.setVisibility(View.VISIBLE);
+ holder.butSecondary.setEnabled(false);
+ } else {
+ holder.butSecondary.setEnabled(true);
+ holder.statusPlaying.setVisibility(View.INVISIBLE);
+ }
+
+ holder.butSecondary.setFocusable(false);
+ holder.butSecondary.setTag(item);
+ holder.butSecondary.setOnClickListener(secondaryActionListener);
+
+
+ ImageLoader.getInstance().loadThumbnailBitmap(
+ item,
+ holder.imageView,
+ (int) convertView.getResources().getDimension(
+ R.dimen.thumbnail_length)
+ );
+ return convertView;
+ }
+
+ private View.OnClickListener secondaryActionListener = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ FeedItem item = (FeedItem) v.getTag();
+ itemAccess.onFeedItemSecondaryAction(item);
+ }
+ };
+
+
+ static class Holder {
+ TextView title;
+ TextView pubDate;
+ ImageView imageView;
+ ImageView statusPlaying;
+ TextView txtvSize;
+ ImageButton butSecondary;
+ }
+
+ public interface ItemAccess {
+ int getCount();
+
+ FeedItem getItem(int position);
+
+ void onFeedItemSecondaryAction(FeedItem item);
+ }
+}
diff --git a/src/de/danoeh/antennapod/adapter/DownloadlistAdapter.java b/src/de/danoeh/antennapod/adapter/DownloadlistAdapter.java
index 2739d2f27..fa2e5a0a7 100644
--- a/src/de/danoeh/antennapod/adapter/DownloadlistAdapter.java
+++ b/src/de/danoeh/antennapod/adapter/DownloadlistAdapter.java
@@ -4,7 +4,8 @@ import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
+import android.widget.BaseAdapter;
+import android.widget.ImageButton;
import android.widget.ProgressBar;
import android.widget.TextView;
import de.danoeh.antennapod.R;
@@ -14,86 +15,128 @@ import de.danoeh.antennapod.service.download.Downloader;
import de.danoeh.antennapod.util.Converter;
import de.danoeh.antennapod.util.ThemeUtils;
-import java.util.List;
-
-public class DownloadlistAdapter extends ArrayAdapter<Downloader> {
- private int selectedItemIndex;
-
- public static final int SELECTION_NONE = -1;
-
- public DownloadlistAdapter(Context context, int textViewResourceId,
- List<Downloader> objects) {
- super(context, textViewResourceId, objects);
- this.selectedItemIndex = SELECTION_NONE;
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- Holder holder;
- DownloadRequest request = getItem(position).getDownloadRequest();
- // Inflate layout
- if (convertView == null) {
- holder = new Holder();
- LayoutInflater inflater = (LayoutInflater) getContext()
- .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- convertView = inflater.inflate(R.layout.downloadlist_item, null);
- holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
- holder.message = (TextView) convertView
- .findViewById(R.id.txtvMessage);
- holder.downloaded = (TextView) convertView
- .findViewById(R.id.txtvDownloaded);
- holder.percent = (TextView) convertView
- .findViewById(R.id.txtvPercent);
- holder.progbar = (ProgressBar) convertView
- .findViewById(R.id.progProgress);
-
- convertView.setTag(holder);
- } else {
- holder = (Holder) convertView.getTag();
- }
-
- if (position == selectedItemIndex) {
- convertView.setBackgroundColor(convertView.getResources().getColor(
- ThemeUtils.getSelectionBackgroundColor()));
- } else {
- convertView.setBackgroundResource(0);
- }
-
- holder.title.setText(request.getTitle());
- if (request.getStatusMsg() != 0) {
- holder.message.setText(request.getStatusMsg());
- }
- String strDownloaded = Converter.byteToString(request.getSoFar());
- if (request.getSize() != DownloadStatus.SIZE_UNKNOWN) {
- strDownloaded += " / " + Converter.byteToString(request.getSize());
- holder.percent.setText(request.getProgressPercent() + "%");
- holder.progbar.setProgress(request.getProgressPercent());
- holder.percent.setVisibility(View.VISIBLE);
- } else {
- holder.progbar.setProgress(0);
- holder.percent.setVisibility(View.INVISIBLE);
- }
-
- holder.downloaded.setText(strDownloaded);
-
- return convertView;
- }
-
- static class Holder {
- TextView title;
- TextView message;
- TextView downloaded;
- TextView percent;
- ProgressBar progbar;
- }
-
- public int getSelectedItemIndex() {
- return selectedItemIndex;
- }
-
- public void setSelectedItemIndex(int selectedItemIndex) {
- this.selectedItemIndex = selectedItemIndex;
- notifyDataSetChanged();
- }
+public class DownloadlistAdapter extends BaseAdapter {
+
+ public static final int SELECTION_NONE = -1;
+
+ private int selectedItemIndex;
+ private ItemAccess itemAccess;
+ private Context context;
+
+ public DownloadlistAdapter(Context context,
+ ItemAccess itemAccess) {
+ super();
+ this.selectedItemIndex = SELECTION_NONE;
+ this.context = context;
+ this.itemAccess = itemAccess;
+ }
+
+ @Override
+ public int getCount() {
+ return itemAccess.getCount();
+ }
+
+ @Override
+ public Downloader getItem(int position) {
+ return itemAccess.getItem(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ Holder holder;
+ Downloader downloader = getItem(position);
+ DownloadRequest request = downloader.getDownloadRequest();
+ // Inflate layout
+ if (convertView == null) {
+ holder = new Holder();
+ LayoutInflater inflater = (LayoutInflater) context
+ .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ convertView = inflater.inflate(R.layout.downloadlist_item, null);
+ holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
+ holder.message = (TextView) convertView
+ .findViewById(R.id.txtvMessage);
+ holder.downloaded = (TextView) convertView
+ .findViewById(R.id.txtvDownloaded);
+ holder.percent = (TextView) convertView
+ .findViewById(R.id.txtvPercent);
+ holder.progbar = (ProgressBar) convertView
+ .findViewById(R.id.progProgress);
+ holder.butSecondary = (ImageButton) convertView
+ .findViewById(R.id.butSecondaryAction);
+
+ convertView.setTag(holder);
+ } else {
+ holder = (Holder) convertView.getTag();
+ }
+
+ if (position == selectedItemIndex) {
+ convertView.setBackgroundColor(convertView.getResources().getColor(
+ ThemeUtils.getSelectionBackgroundColor()));
+ } else {
+ convertView.setBackgroundResource(0);
+ }
+
+ holder.title.setText(request.getTitle());
+ if (request.getStatusMsg() != 0) {
+ holder.message.setText(request.getStatusMsg());
+ }
+ String strDownloaded = Converter.byteToString(request.getSoFar());
+ if (request.getSize() != DownloadStatus.SIZE_UNKNOWN) {
+ strDownloaded += " / " + Converter.byteToString(request.getSize());
+ holder.percent.setText(request.getProgressPercent() + "%");
+ holder.progbar.setProgress(request.getProgressPercent());
+ holder.percent.setVisibility(View.VISIBLE);
+ } else {
+ holder.progbar.setProgress(0);
+ holder.percent.setVisibility(View.INVISIBLE);
+ }
+
+ holder.downloaded.setText(strDownloaded);
+
+ holder.butSecondary.setFocusable(false);
+ holder.butSecondary.setTag(downloader);
+ holder.butSecondary.setOnClickListener(butSecondaryListener);
+
+ return convertView;
+ }
+
+ private View.OnClickListener butSecondaryListener = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Downloader downloader = (Downloader) v.getTag();
+ itemAccess.onSecondaryActionClick(downloader);
+ }
+ };
+
+ static class Holder {
+ TextView title;
+ TextView message;
+ TextView downloaded;
+ TextView percent;
+ ProgressBar progbar;
+ ImageButton butSecondary;
+ }
+
+ public int getSelectedItemIndex() {
+ return selectedItemIndex;
+ }
+
+ public void setSelectedItemIndex(int selectedItemIndex) {
+ this.selectedItemIndex = selectedItemIndex;
+ notifyDataSetChanged();
+ }
+
+ public interface ItemAccess {
+ public int getCount();
+
+ public Downloader getItem(int position);
+
+ public void onSecondaryActionClick(Downloader downloader);
+ }
}
diff --git a/src/de/danoeh/antennapod/adapter/ExternalEpisodesListAdapter.java b/src/de/danoeh/antennapod/adapter/ExternalEpisodesListAdapter.java
index aa724f991..9a7b607aa 100644
--- a/src/de/danoeh/antennapod/adapter/ExternalEpisodesListAdapter.java
+++ b/src/de/danoeh/antennapod/adapter/ExternalEpisodesListAdapter.java
@@ -227,10 +227,10 @@ public class ExternalEpisodesListAdapter extends BaseExpandableListAdapter {
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.feeditemlist_header, null);
TextView headerTitle = (TextView) convertView
- .findViewById(R.id.txtvHeaderTitle);
+ .findViewById(0);
ImageButton actionButton = (ImageButton) convertView
.findViewById(R.id.butAction);
- TextView numItems = (TextView) convertView.findViewById(R.id.txtvNumItems);
+ TextView numItems = (TextView) convertView.findViewById(0);
String headerString = null;
int childrenCount = 0;
diff --git a/src/de/danoeh/antennapod/adapter/InternalFeedItemlistAdapter.java b/src/de/danoeh/antennapod/adapter/InternalFeedItemlistAdapter.java
index 4681284f5..356d75d99 100644
--- a/src/de/danoeh/antennapod/adapter/InternalFeedItemlistAdapter.java
+++ b/src/de/danoeh/antennapod/adapter/InternalFeedItemlistAdapter.java
@@ -12,6 +12,7 @@ import de.danoeh.antennapod.R;
import de.danoeh.antennapod.feed.FeedItem;
import de.danoeh.antennapod.feed.FeedMedia;
import de.danoeh.antennapod.feed.MediaType;
+import de.danoeh.antennapod.service.playback.PlayerStatus;
import de.danoeh.antennapod.storage.DownloadRequester;
import de.danoeh.antennapod.util.Converter;
import de.danoeh.antennapod.util.ThemeUtils;
@@ -22,6 +23,7 @@ public class InternalFeedItemlistAdapter extends DefaultFeedItemlistAdapter {
private ActionButtonCallback callback;
private boolean showFeedtitle;
private int selectedItemIndex;
+ private final ActionButtonUtils actionButtonUtils;
public static final int SELECTION_NONE = -1;
@@ -32,6 +34,7 @@ public class InternalFeedItemlistAdapter extends DefaultFeedItemlistAdapter {
this.callback = callback;
this.showFeedtitle = showFeedtitle;
this.selectedItemIndex = SELECTION_NONE;
+ this.actionButtonUtils = new ActionButtonUtils(context);
}
@Override
@@ -49,20 +52,12 @@ public class InternalFeedItemlistAdapter extends DefaultFeedItemlistAdapter {
holder.lenSize = (TextView) convertView
.findViewById(R.id.txtvLenSize);
holder.butAction = (ImageButton) convertView
- .findViewById(R.id.butAction);
+ .findViewById(R.id.butSecondaryAction);
holder.published = (TextView) convertView
.findViewById(R.id.txtvPublished);
holder.inPlaylist = (ImageView) convertView
.findViewById(R.id.imgvInPlaylist);
- holder.downloaded = (ImageView) convertView
- .findViewById(R.id.imgvDownloaded);
holder.type = (ImageView) convertView.findViewById(R.id.imgvType);
- holder.downloading = (ImageView) convertView
- .findViewById(R.id.imgvDownloading);
- if (showFeedtitle) {
- holder.feedtitle = (TextView) convertView
- .findViewById(R.id.txtvFeedname);
- }
holder.statusPlaying = (View) convertView
.findViewById(R.id.statusPlaying);
holder.statusUnread = (View) convertView
@@ -83,11 +78,13 @@ public class InternalFeedItemlistAdapter extends DefaultFeedItemlistAdapter {
convertView.setBackgroundResource(0);
}
- holder.title.setText(item.getTitle());
- if (showFeedtitle) {
- holder.feedtitle.setVisibility(View.VISIBLE);
- holder.feedtitle.setText(item.getFeed().getTitle());
- }
+ StringBuilder buffer = new StringBuilder(item.getTitle());
+ if (showFeedtitle) {
+ buffer.append("(");
+ buffer.append(item.getFeed().getTitle());
+ buffer.append(")");
+ }
+ holder.title.setText(buffer.toString());
FeedItem.State state = item.getState();
switch (state) {
@@ -104,12 +101,10 @@ public class InternalFeedItemlistAdapter extends DefaultFeedItemlistAdapter {
case NEW:
holder.statusPlaying.setVisibility(View.GONE);
holder.statusUnread.setVisibility(View.VISIBLE);
- holder.episodeProgress.setVisibility(View.GONE);
break;
default:
holder.statusPlaying.setVisibility(View.GONE);
holder.statusUnread.setVisibility(View.GONE);
- holder.episodeProgress.setVisibility(View.GONE);
break;
}
@@ -121,11 +116,10 @@ public class InternalFeedItemlistAdapter extends DefaultFeedItemlistAdapter {
FeedMedia media = item.getMedia();
if (media == null) {
- holder.downloaded.setVisibility(View.GONE);
- holder.downloading.setVisibility(View.GONE);
- holder.inPlaylist.setVisibility(View.GONE);
- holder.type.setVisibility(View.GONE);
- holder.lenSize.setVisibility(View.GONE);
+ holder.episodeProgress.setVisibility(View.GONE);
+ holder.inPlaylist.setVisibility(View.INVISIBLE);
+ holder.type.setVisibility(View.INVISIBLE);
+ holder.lenSize.setVisibility(View.INVISIBLE);
} else {
if (state == FeedItem.State.PLAYING
@@ -153,19 +147,16 @@ public class InternalFeedItemlistAdapter extends DefaultFeedItemlistAdapter {
if (((ItemAccess) itemAccess).isInQueue(item)) {
holder.inPlaylist.setVisibility(View.VISIBLE);
} else {
- holder.inPlaylist.setVisibility(View.GONE);
- }
- if (item.getMedia().isDownloaded()) {
- holder.downloaded.setVisibility(View.VISIBLE);
- } else {
- holder.downloaded.setVisibility(View.GONE);
+ holder.inPlaylist.setVisibility(View.INVISIBLE);
}
if (DownloadRequester.getInstance().isDownloadingFile(
item.getMedia())) {
- holder.downloading.setVisibility(View.VISIBLE);
- } else {
- holder.downloading.setVisibility(View.GONE);
+ holder.episodeProgress.setVisibility(View.VISIBLE);
+ holder.episodeProgress.setProgress(((ItemAccess) itemAccess).getItemDownloadProgressPercent(item));
+ } else if (!(state == FeedItem.State.IN_PROGRESS
+ || state == FeedItem.State.PLAYING)) {
+ holder.episodeProgress.setVisibility(View.GONE);
}
TypedArray typeDrawables = getContext().obtainStyledAttributes(
@@ -187,14 +178,10 @@ public class InternalFeedItemlistAdapter extends DefaultFeedItemlistAdapter {
}
}
+ actionButtonUtils.configureActionButton(holder.butAction, item);
holder.butAction.setFocusable(false);
- holder.butAction.setOnClickListener(new OnClickListener() {
-
- @Override
- public void onClick(View v) {
- callback.onActionButtonPressed(item);
- }
- });
+ holder.butAction.setTag(item);
+ holder.butAction.setOnClickListener(butActionListener);
} else {
convertView.setVisibility(View.GONE);
@@ -203,11 +190,16 @@ public class InternalFeedItemlistAdapter extends DefaultFeedItemlistAdapter {
}
+ private final OnClickListener butActionListener = new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ FeedItem item = (FeedItem) v.getTag();
+ callback.onActionButtonPressed(item);
+ }
+ };
+
static class Holder extends DefaultFeedItemlistAdapter.Holder {
- TextView feedtitle;
ImageView inPlaylist;
- ImageView downloaded;
- ImageView downloading;
ImageButton butAction;
View statusUnread;
View statusPlaying;
@@ -225,6 +217,8 @@ public class InternalFeedItemlistAdapter extends DefaultFeedItemlistAdapter {
public static interface ItemAccess extends DefaultFeedItemlistAdapter.ItemAccess {
public boolean isInQueue(FeedItem item);
+
+ int getItemDownloadProgressPercent(FeedItem item);
}
}
diff --git a/src/de/danoeh/antennapod/adapter/NavListAdapter.java b/src/de/danoeh/antennapod/adapter/NavListAdapter.java
new file mode 100644
index 000000000..084f3609f
--- /dev/null
+++ b/src/de/danoeh/antennapod/adapter/NavListAdapter.java
@@ -0,0 +1,186 @@
+package de.danoeh.antennapod.adapter;
+
+import android.content.Context;
+import android.graphics.Typeface;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.ImageView;
+import android.widget.TextView;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.asynctask.ImageLoader;
+import de.danoeh.antennapod.feed.Feed;
+
+/**
+ * BaseAdapter for the navigation drawer
+ */
+public class NavListAdapter extends BaseAdapter {
+ public static final int VIEW_TYPE_COUNT = 3;
+ public static final int VIEW_TYPE_NAV = 0;
+ public static final int VIEW_TYPE_SECTION_DIVIDER = 1;
+ public static final int VIEW_TYPE_SUBSCRIPTION = 2;
+
+ public static final int[] NAV_TITLES = {R.string.new_episodes_label, R.string.queue_label, R.string.downloads_label, R.string.playback_history_label, R.string.add_feed_label};
+
+
+ public static final int SUBSCRIPTION_OFFSET = 1 + NAV_TITLES.length;
+
+ private ItemAccess itemAccess;
+ private Context context;
+
+ public NavListAdapter(ItemAccess itemAccess, Context context) {
+ this.itemAccess = itemAccess;
+ this.context = context;
+ }
+
+ @Override
+ public int getCount() {
+ return NAV_TITLES.length + 1 + itemAccess.getCount();
+ }
+
+ @Override
+ public Object getItem(int position) {
+ int viewType = getItemViewType(position);
+ if (viewType == VIEW_TYPE_NAV) {
+ return context.getString(NAV_TITLES[position]);
+ } else if (viewType == VIEW_TYPE_SECTION_DIVIDER) {
+ return context.getString(R.string.podcasts_label);
+ } else {
+ return itemAccess.getItem(position);
+ }
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ if (0 <= position && position < NAV_TITLES.length) {
+ return VIEW_TYPE_NAV;
+ } else if (position < NAV_TITLES.length + 1) {
+ return VIEW_TYPE_SECTION_DIVIDER;
+ } else {
+ return VIEW_TYPE_SUBSCRIPTION;
+ }
+ }
+
+ @Override
+ public int getViewTypeCount() {
+ return VIEW_TYPE_COUNT;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ int viewType = getItemViewType(position);
+ View v = null;
+ if (viewType == VIEW_TYPE_NAV) {
+ v = getNavView((String) getItem(position), position, convertView, parent);
+ } else if (viewType == VIEW_TYPE_SECTION_DIVIDER) {
+ v = getSectionDividerView((String) getItem(position), position, convertView, parent);
+ } else {
+ v = getFeedView(position - SUBSCRIPTION_OFFSET, convertView, parent);
+ }
+ if (v != null) {
+ TextView txtvTitle = (TextView) v.findViewById(R.id.txtvTitle);
+ if (position == itemAccess.getSelectedItemIndex()) {
+ txtvTitle.setTypeface(null, Typeface.BOLD);
+ } else {
+ txtvTitle.setTypeface(null, Typeface.NORMAL);
+ }
+ }
+ return v;
+ }
+
+ private View getNavView(String title, int position, View convertView, ViewGroup parent) {
+ NavHolder holder;
+ if (convertView == null) {
+ holder = new NavHolder();
+ LayoutInflater inflater = (LayoutInflater) context
+ .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+ convertView = inflater.inflate(R.layout.nav_listitem, null);
+
+ holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
+ convertView.setTag(holder);
+ } else {
+ holder = (NavHolder) convertView.getTag();
+ }
+
+ holder.title.setText(title);
+
+ return convertView;
+ }
+
+ private View getSectionDividerView(String title, int position, View convertView, ViewGroup parent) {
+ SectionHolder holder;
+ if (convertView == null) {
+ holder = new SectionHolder();
+ LayoutInflater inflater = (LayoutInflater) context
+ .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+ convertView = inflater.inflate(R.layout.nav_section_item, null);
+
+ holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
+ convertView.setTag(holder);
+ } else {
+ holder = (SectionHolder) convertView.getTag();
+ }
+
+ holder.title.setText(title);
+
+ convertView.setEnabled(false);
+ convertView.setOnClickListener(null);
+
+ return convertView;
+ }
+
+ private View getFeedView(int feedPos, View convertView, ViewGroup parent) {
+ FeedHolder holder;
+ Feed feed = itemAccess.getItem(feedPos);
+
+ if (convertView == null) {
+ holder = new FeedHolder();
+ LayoutInflater inflater = (LayoutInflater) context
+ .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+ convertView = inflater.inflate(R.layout.nav_feedlistitem, null);
+
+ holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
+ holder.image = (ImageView) convertView.findViewById(R.id.imgvCover);
+ convertView.setTag(holder);
+ } else {
+ holder = (FeedHolder) convertView.getTag();
+ }
+
+ holder.title.setText(feed.getTitle());
+ ImageLoader.getInstance().loadThumbnailBitmap(feed.getImage(), holder.image, (int) context.getResources().getDimension(R.dimen.thumbnail_length_navlist));
+
+ return convertView;
+ }
+
+ static class NavHolder {
+ TextView title;
+ }
+
+ static class SectionHolder {
+ TextView title;
+ }
+
+ static class FeedHolder {
+ TextView title;
+ ImageView image;
+ }
+
+
+ public interface ItemAccess {
+ public int getCount();
+
+ public Feed getItem(int position);
+
+ public int getSelectedItemIndex();
+ }
+
+}
diff --git a/src/de/danoeh/antennapod/adapter/NewEpisodesListAdapter.java b/src/de/danoeh/antennapod/adapter/NewEpisodesListAdapter.java
new file mode 100644
index 000000000..d13314b0b
--- /dev/null
+++ b/src/de/danoeh/antennapod/adapter/NewEpisodesListAdapter.java
@@ -0,0 +1,217 @@
+package de.danoeh.antennapod.adapter;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.text.format.DateUtils;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.*;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.asynctask.ImageLoader;
+import de.danoeh.antennapod.feed.FeedItem;
+import de.danoeh.antennapod.feed.FeedMedia;
+import de.danoeh.antennapod.storage.DownloadRequester;
+import de.danoeh.antennapod.util.Converter;
+
+/**
+ * List adapter for the list of new episodes
+ */
+public class NewEpisodesListAdapter extends BaseAdapter {
+
+ private static final int VIEW_TYPE_FEEDITEM = 0;
+ private static final int VIEW_TYPE_DIVIDER = 1;
+
+ private final Context context;
+ private final ItemAccess itemAccess;
+ private final ActionButtonCallback actionButtonCallback;
+ private final ActionButtonUtils actionButtonUtils;
+
+ public NewEpisodesListAdapter(Context context, ItemAccess itemAccess, ActionButtonCallback actionButtonCallback) {
+ super();
+ this.context = context;
+ this.itemAccess = itemAccess;
+ this.actionButtonUtils = new ActionButtonUtils(context);
+ this.actionButtonCallback = actionButtonCallback;
+ }
+
+ @Override
+ public int getCount() {
+ int unreadItems = itemAccess.getUnreadItemsCount();
+ int recentItems = itemAccess.getRecentItemsCount();
+ return unreadItems + recentItems + 1;
+ }
+
+ @Override
+ public Object getItem(int position) {
+ int unreadItems = itemAccess.getUnreadItemsCount();
+
+ if (position == unreadItems) {
+ return null;
+ }
+ if (position < unreadItems && unreadItems > 0) {
+ return itemAccess.getUnreadItem(position);
+ }
+ return itemAccess.getRecentItem(position - unreadItems - 1);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ int unreadItems = itemAccess.getUnreadItemsCount();
+ if (position == unreadItems) {
+ return VIEW_TYPE_DIVIDER;
+ } else {
+ return VIEW_TYPE_FEEDITEM;
+ }
+ }
+
+ @Override
+ public int getViewTypeCount() {
+ return 2;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ int viewType = getItemViewType(position);
+ if (viewType == VIEW_TYPE_FEEDITEM) {
+ return getFeedItemView(position, convertView, parent);
+ } else {
+ return getDividerView(position, convertView, parent);
+ }
+ }
+
+ public View getDividerView(int position, View convertView, ViewGroup parent) {
+ LayoutInflater inflater = (LayoutInflater) context
+ .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ convertView = inflater.inflate(R.layout.new_episodes_listdivider,
+ null);
+ convertView.setOnClickListener(null);
+ convertView.setEnabled(false);
+ return convertView;
+ }
+
+ public View getFeedItemView(int position, View convertView, ViewGroup parent) {
+ Holder holder;
+ final FeedItem item = (FeedItem) getItem(position);
+ if (item == null) return null;
+
+ if (convertView == null) {
+ holder = new Holder();
+ LayoutInflater inflater = (LayoutInflater) context
+ .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ convertView = inflater.inflate(R.layout.new_episodes_listitem,
+ null);
+ holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
+ holder.pubDate = (TextView) convertView
+ .findViewById(R.id.txtvPublished);
+ holder.butSecondary = (ImageButton) convertView
+ .findViewById(R.id.butSecondaryAction);
+ holder.queueStatus = (ImageView) convertView
+ .findViewById(R.id.imgvInPlaylist);
+ holder.statusPlaying = (ImageView) convertView
+ .findViewById(R.id.statusPlaying);
+ holder.downloadProgress = (ProgressBar) convertView
+ .findViewById(R.id.pbar_download_progress);
+ holder.imageView = (ImageView) convertView.findViewById(R.id.imgvImage);
+ holder.txtvDuration = (TextView) convertView.findViewById(R.id.txtvDuration);
+ convertView.setTag(holder);
+ } else {
+ holder = (Holder) convertView.getTag();
+ }
+
+ holder.title.setText(item.getTitle());
+ holder.pubDate.setText(DateUtils.formatDateTime(context, item.getPubDate().getTime(), DateUtils.FORMAT_SHOW_DATE));
+ FeedItem.State state = item.getState();
+
+ if (state == FeedItem.State.PLAYING) {
+ holder.statusPlaying.setVisibility(View.VISIBLE);
+ } else {
+ holder.statusPlaying.setVisibility(View.INVISIBLE);
+ }
+
+ FeedMedia media = item.getMedia();
+ if (media != null) {
+ final boolean isDownloadingMedia = DownloadRequester.getInstance().isDownloadingFile(media);
+
+ if (media.getDuration() > 0) {
+ holder.txtvDuration.setText(Converter.getDurationStringLong(media.getDuration()));
+ } else {
+ holder.txtvDuration.setText("");
+ }
+
+ if (isDownloadingMedia) {
+ holder.downloadProgress.setVisibility(View.VISIBLE);
+ holder.txtvDuration.setVisibility(View.GONE);
+ } else {
+ holder.txtvDuration.setVisibility(View.VISIBLE);
+ holder.downloadProgress.setVisibility(View.GONE);
+ }
+
+ if (!media.isDownloaded()) {
+ if (isDownloadingMedia) {
+ // item is being downloaded
+ holder.downloadProgress.setProgress(itemAccess.getItemDownloadProgressPercent(item));
+ }
+ }
+ }
+ if (itemAccess.isInQueue(item)) {
+ holder.queueStatus.setVisibility(View.VISIBLE);
+ } else {
+ holder.queueStatus.setVisibility(View.INVISIBLE);
+ }
+
+ actionButtonUtils.configureActionButton(holder.butSecondary, item);
+ holder.butSecondary.setFocusable(false);
+ holder.butSecondary.setTag(item);
+ holder.butSecondary.setOnClickListener(secondaryActionListener);
+
+
+
+ ImageLoader.getInstance().loadThumbnailBitmap(
+ item,
+ holder.imageView,
+ (int) convertView.getResources().getDimension(
+ R.dimen.thumbnail_length)
+ );
+ return convertView;
+ }
+
+ private View.OnClickListener secondaryActionListener = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ FeedItem item = (FeedItem) v.getTag();
+ actionButtonCallback.onActionButtonPressed(item);
+ }
+ };
+
+
+ static class Holder {
+ TextView title;
+ TextView pubDate;
+ ImageView queueStatus;
+ ImageView imageView;
+ ImageView statusPlaying;
+ ProgressBar downloadProgress;
+ TextView txtvDuration;
+ ImageButton butSecondary;
+ }
+
+ public interface ItemAccess {
+ int getUnreadItemsCount();
+
+ int getRecentItemsCount();
+
+ FeedItem getUnreadItem(int position);
+
+ FeedItem getRecentItem(int position);
+
+ int getItemDownloadProgressPercent(FeedItem item);
+
+ boolean isInQueue(FeedItem item);
+ }
+}
diff --git a/src/de/danoeh/antennapod/adapter/QueueListAdapter.java b/src/de/danoeh/antennapod/adapter/QueueListAdapter.java
new file mode 100644
index 000000000..c671f4a5c
--- /dev/null
+++ b/src/de/danoeh/antennapod/adapter/QueueListAdapter.java
@@ -0,0 +1,155 @@
+package de.danoeh.antennapod.adapter;
+
+import android.content.Context;
+import android.text.format.DateUtils;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.*;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.asynctask.ImageLoader;
+import de.danoeh.antennapod.feed.FeedItem;
+import de.danoeh.antennapod.feed.FeedMedia;
+import de.danoeh.antennapod.storage.DownloadRequester;
+import de.danoeh.antennapod.util.Converter;
+
+/**
+ * List adapter for the queue.
+ */
+public class QueueListAdapter extends BaseAdapter {
+
+
+ private final Context context;
+ private final ItemAccess itemAccess;
+ private final ActionButtonCallback actionButtonCallback;
+ private final ActionButtonUtils actionButtonUtils;
+
+ public QueueListAdapter(Context context, ItemAccess itemAccess, ActionButtonCallback actionButtonCallback) {
+ super();
+ this.context = context;
+ this.itemAccess = itemAccess;
+ this.actionButtonUtils = new ActionButtonUtils(context);
+ this.actionButtonCallback = actionButtonCallback;
+
+ }
+
+ @Override
+ public int getCount() {
+ return itemAccess.getCount();
+ }
+
+ @Override
+ public Object getItem(int position) {
+ return itemAccess.getItem(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ Holder holder;
+ final FeedItem item = (FeedItem) getItem(position);
+ if (item == null) return null;
+
+ if (convertView == null) {
+ holder = new Holder();
+ LayoutInflater inflater = (LayoutInflater) context
+ .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ convertView = inflater.inflate(R.layout.queue_listitem,
+ null);
+ holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
+ holder.pubDate = (TextView) convertView
+ .findViewById(R.id.txtvPublished);
+ holder.butSecondary = (ImageButton) convertView
+ .findViewById(R.id.butSecondaryAction);
+ holder.statusPlaying = (ImageView) convertView
+ .findViewById(R.id.statusPlaying);
+ holder.downloadProgress = (ProgressBar) convertView
+ .findViewById(R.id.pbar_download_progress);
+ holder.imageView = (ImageView) convertView.findViewById(R.id.imgvImage);
+ holder.txtvDuration = (TextView) convertView.findViewById(R.id.txtvDuration);
+ convertView.setTag(holder);
+ } else {
+ holder = (Holder) convertView.getTag();
+ }
+
+ holder.title.setText(item.getTitle());
+ holder.pubDate.setText(DateUtils.formatDateTime(context, item.getPubDate().getTime(), DateUtils.FORMAT_SHOW_DATE));
+ FeedItem.State state = item.getState();
+
+ if (state == FeedItem.State.PLAYING) {
+ holder.statusPlaying.setVisibility(View.VISIBLE);
+ } else {
+ holder.statusPlaying.setVisibility(View.INVISIBLE);
+ }
+
+ FeedMedia media = item.getMedia();
+ if (media != null) {
+ final boolean isDownloadingMedia = DownloadRequester.getInstance().isDownloadingFile(media);
+
+ if (media.getDuration() > 0) {
+ holder.txtvDuration.setText(Converter.getDurationStringLong(media.getDuration()));
+ } else {
+ holder.txtvDuration.setText("");
+ }
+
+ if (isDownloadingMedia) {
+ holder.downloadProgress.setVisibility(View.VISIBLE);
+ holder.txtvDuration.setVisibility(View.GONE);
+ } else {
+ holder.txtvDuration.setVisibility(View.VISIBLE);
+ holder.downloadProgress.setVisibility(View.GONE);
+ }
+ if (!media.isDownloaded()) {
+ if (isDownloadingMedia) {
+ // item is being downloaded
+ holder.downloadProgress.setProgress(itemAccess.getItemDownloadProgressPercent(item));
+ }
+ }
+ }
+
+ actionButtonUtils.configureActionButton(holder.butSecondary, item);
+ holder.butSecondary.setFocusable(false);
+ holder.butSecondary.setTag(item);
+ holder.butSecondary.setOnClickListener(secondaryActionListener);
+
+
+ ImageLoader.getInstance().loadThumbnailBitmap(
+ item,
+ holder.imageView,
+ (int) convertView.getResources().getDimension(
+ R.dimen.thumbnail_length)
+ );
+ return convertView;
+ }
+
+ private View.OnClickListener secondaryActionListener = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ FeedItem item = (FeedItem) v.getTag();
+ actionButtonCallback.onActionButtonPressed(item);
+ }
+ };
+
+
+ static class Holder {
+ TextView title;
+ TextView pubDate;
+ ImageView imageView;
+ ImageView statusPlaying;
+ ProgressBar downloadProgress;
+ TextView txtvDuration;
+ ImageButton butSecondary;
+ }
+
+ public interface ItemAccess {
+ int getCount();
+
+ FeedItem getItem(int position);
+
+ int getItemDownloadProgressPercent(FeedItem item);
+ }
+}
diff --git a/src/de/danoeh/antennapod/adapter/SearchlistAdapter.java b/src/de/danoeh/antennapod/adapter/SearchlistAdapter.java
index 926a5a5ad..5c6af3943 100644
--- a/src/de/danoeh/antennapod/adapter/SearchlistAdapter.java
+++ b/src/de/danoeh/antennapod/adapter/SearchlistAdapter.java
@@ -5,6 +5,7 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
+import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import de.danoeh.antennapod.R;
@@ -17,14 +18,32 @@ import de.danoeh.antennapod.feed.SearchResult;
import java.util.List;
/** List adapter for search activity. */
-public class SearchlistAdapter extends ArrayAdapter<SearchResult> {
+public class SearchlistAdapter extends BaseAdapter {
- public SearchlistAdapter(Context context, int textViewResourceId,
- List<SearchResult> objects) {
- super(context, textViewResourceId, objects);
- }
+ private final Context context;
+ private final ItemAccess itemAccess;
+
+ public SearchlistAdapter(Context context, ItemAccess itemAccess) {
+ this.context = context;
+ this.itemAccess = itemAccess;
+ }
+
+ @Override
+ public int getCount() {
+ return itemAccess.getCount();
+ }
- @Override
+ @Override
+ public SearchResult getItem(int position) {
+ return itemAccess.getItem(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return 0;
+ }
+
+ @Override
public View getView(int position, View convertView, ViewGroup parent) {
final Holder holder;
SearchResult result = getItem(position);
@@ -33,7 +52,7 @@ public class SearchlistAdapter extends ArrayAdapter<SearchResult> {
// Inflate Layout
if (convertView == null) {
holder = new Holder();
- LayoutInflater inflater = (LayoutInflater) getContext()
+ LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.searchlist_item, null);
@@ -78,4 +97,9 @@ public class SearchlistAdapter extends ArrayAdapter<SearchResult> {
TextView subtitle;
}
+ public static interface ItemAccess {
+ int getCount();
+ SearchResult getItem(int position);
+ }
+
}
diff --git a/src/de/danoeh/antennapod/asynctask/DownloadObserver.java b/src/de/danoeh/antennapod/asynctask/DownloadObserver.java
index 40388cde5..1c5003ab3 100644
--- a/src/de/danoeh/antennapod/asynctask/DownloadObserver.java
+++ b/src/de/danoeh/antennapod/asynctask/DownloadObserver.java
@@ -23,9 +23,9 @@ public class DownloadObserver {
/**
* Time period between update notifications.
*/
- public static final int WAITING_INTERVAL_MS = 1000;
+ public static final int WAITING_INTERVAL_MS = 3000;
- private final Activity activity;
+ private volatile Activity activity;
private final Handler handler;
private final Callback callback;
@@ -57,19 +57,31 @@ public class DownloadObserver {
public void onResume() {
if (BuildConfig.DEBUG) Log.d(TAG, "DownloadObserver resumed");
activity.registerReceiver(contentChangedReceiver, new IntentFilter(DownloadService.ACTION_DOWNLOADS_CONTENT_CHANGED));
- activity.bindService(new Intent(activity, DownloadService.class), mConnection, 0);
+ connectToDownloadService();
}
public void onPause() {
if (BuildConfig.DEBUG) Log.d(TAG, "DownloadObserver paused");
- activity.unregisterReceiver(contentChangedReceiver);
- activity.unbindService(mConnection);
+ try {
+ activity.unregisterReceiver(contentChangedReceiver);
+ } catch (IllegalArgumentException e) {
+ e.printStackTrace();
+ }
+ try {
+ activity.unbindService(mConnection);
+ } catch (IllegalArgumentException e) {
+ e.printStackTrace();
+ }
stopRefresher();
}
private BroadcastReceiver contentChangedReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
+ // reconnect to DownloadService if connection has been closed
+ if (downloadService == null) {
+ connectToDownloadService();
+ }
callback.onContentChanged();
startRefresher();
}
@@ -81,6 +93,10 @@ public class DownloadObserver {
void onDownloadDataAvailable(List<Downloader> downloaderList);
}
+ private void connectToDownloadService() {
+ activity.bindService(new Intent(activity, DownloadService.class), mConnection, 0);
+ }
+
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceDisconnected(ComponentName className) {
downloadService = null;
@@ -138,13 +154,21 @@ public class DownloadObserver {
@Override
public void run() {
callback.onContentChanged();
- List<Downloader> downloaderList = downloadService.getDownloads();
- if (downloaderList == null || downloaderList.isEmpty()) {
- Thread.currentThread().interrupt();
+ if (downloadService != null) {
+ List<Downloader> downloaderList = downloadService.getDownloads();
+ if (downloaderList == null || downloaderList.isEmpty()) {
+ Thread.currentThread().interrupt();
+ }
}
}
});
}
}
+ public void setActivity(Activity activity) {
+ if (activity == null) throw new IllegalArgumentException("activity = null");
+ this.activity = activity;
+ }
+
}
+
diff --git a/src/de/danoeh/antennapod/dialog/FeedItemDialog.java b/src/de/danoeh/antennapod/dialog/FeedItemDialog.java
new file mode 100644
index 000000000..932f9aec9
--- /dev/null
+++ b/src/de/danoeh/antennapod/dialog/FeedItemDialog.java
@@ -0,0 +1,335 @@
+package de.danoeh.antennapod.dialog;
+
+import android.app.Dialog;
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.TypedArray;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Build;
+import android.os.Bundle;
+import android.support.v7.widget.PopupMenu;
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.MenuItem;
+import android.view.View;
+import android.webkit.WebSettings;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+import android.widget.ImageButton;
+import android.widget.Toast;
+import de.danoeh.antennapod.BuildConfig;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.adapter.DefaultActionButtonCallback;
+import de.danoeh.antennapod.feed.FeedItem;
+import de.danoeh.antennapod.feed.FeedMedia;
+import de.danoeh.antennapod.preferences.UserPreferences;
+import de.danoeh.antennapod.storage.DBTasks;
+import de.danoeh.antennapod.storage.DBWriter;
+import de.danoeh.antennapod.storage.DownloadRequestException;
+import de.danoeh.antennapod.storage.DownloadRequester;
+import de.danoeh.antennapod.util.QueueAccess;
+import de.danoeh.antennapod.util.ShownotesProvider;
+import de.danoeh.antennapod.util.menuhandler.FeedItemMenuHandler;
+import org.apache.commons.lang3.StringEscapeUtils;
+import org.shredzone.flattr4j.model.User;
+
+import java.util.Collection;
+import java.util.concurrent.Callable;
+
+/**
+ * Shows information about a specific FeedItem and provides actions like playing, downloading, etc.
+ */
+public class FeedItemDialog extends Dialog {
+ private static final String TAG = "FeedItemDialog";
+
+ private FeedItem item;
+ private QueueAccess queue;
+
+ private View header;
+ private WebView webvDescription;
+ private ImageButton butAction1;
+ private ImageButton butAction2;
+ private ImageButton butMore;
+ private PopupMenu popupMenu;
+
+ public static FeedItemDialog newInstace(Context context, FeedItem item, QueueAccess queue) {
+ if (useDarkThemeWorkAround()) {
+ return new FeedItemDialog(context, R.style.Theme_AntennaPod_Dark, item, queue);
+ } else {
+ return new FeedItemDialog(context, item, queue);
+ }
+ }
+
+ public FeedItemDialog(Context context, int theme, FeedItem item, QueueAccess queue) {
+ super(context, theme);
+ if (item == null) throw new IllegalArgumentException("item = null");
+ if (queue == null) throw new IllegalArgumentException("queue = null");
+ this.item = item;
+ this.queue = queue;
+ }
+
+ private FeedItemDialog(Context context, FeedItem item, QueueAccess queue) {
+ this(context, 0, item, queue);
+ }
+
+ /**
+ * Returns true if the dialog should use a dark theme. This has to be done on Gingerbread devices
+ * because dialogs are only available in a dark theme.
+ */
+ private static boolean useDarkThemeWorkAround() {
+ return Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1
+ && UserPreferences.getTheme() != R.style.Theme_AntennaPod_Dark;
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.feeditem_dialog);
+
+ header = findViewById(R.id.header);
+ webvDescription = (WebView) findViewById(R.id.webview);
+ butAction1 = (ImageButton) findViewById(R.id.butAction1);
+ butAction2 = (ImageButton) findViewById(R.id.butAction2);
+ butMore = (ImageButton) findViewById(R.id.butMoreActions);
+ popupMenu = new PopupMenu(getContext(), butMore);
+
+ webvDescription.setWebViewClient(new WebViewClient());
+ setTitle(item.getTitle());
+
+ if (UserPreferences.getTheme() == R.style.Theme_AntennaPod_Dark) {
+ if (Build.VERSION.SDK_INT >= 11
+ && Build.VERSION.SDK_INT <= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
+ webvDescription.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
+ }
+ webvDescription.setBackgroundColor(getContext().getResources().getColor(
+ R.color.black));
+ }
+ webvDescription.getSettings().setUseWideViewPort(false);
+ webvDescription.getSettings().setLayoutAlgorithm(
+ WebSettings.LayoutAlgorithm.NARROW_COLUMNS);
+ webvDescription.getSettings().setLoadWithOverviewMode(true);
+ webvDescription.setWebViewClient(new WebViewClient() {
+
+ @Override
+ public boolean shouldOverrideUrlLoading(WebView view, String url) {
+ Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
+ try {
+ getContext().startActivity(intent);
+ } catch (ActivityNotFoundException e) {
+ e.printStackTrace();
+ return false;
+ }
+ return true;
+ }
+ });
+
+ loadDescriptionWebview(item);
+
+ butAction1.setOnClickListener(new View.OnClickListener() {
+ DefaultActionButtonCallback actionButtonCallback = new DefaultActionButtonCallback(getContext());
+
+ @Override
+
+ public void onClick(View v) {
+ FeedMedia media = item.getMedia();
+ if (media == null) {
+ return;
+ }
+ actionButtonCallback.onActionButtonPressed(item);
+
+ }
+ }
+ );
+
+ butAction2.setOnClickListener(new View.OnClickListener()
+
+ {
+ @Override
+ public void onClick(View v) {
+ FeedMedia media = item.getMedia();
+ if (media == null) {
+ return;
+ }
+
+ if (!media.isDownloaded()) {
+ DBTasks.playMedia(getContext(), media, true, true, true);
+ dismiss();
+ } else {
+ DBWriter.deleteFeedMediaOfItem(getContext(), media.getId());
+ }
+ }
+ }
+ );
+
+ butMore.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ popupMenu.getMenu().clear();
+ popupMenu.inflate(R.menu.feeditem_dialog);
+ FeedItemMenuHandler.onPrepareMenu(popupMenuInterface, item, true, queue);
+ popupMenu.show();
+ }
+ }
+ );
+
+ popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
+ @Override
+ public boolean onMenuItemClick(MenuItem menuItem) {
+
+ try {
+ return FeedItemMenuHandler.onMenuItemClicked(getContext(), menuItem.getItemId(), item);
+ } catch (DownloadRequestException e) {
+ e.printStackTrace();
+ Toast.makeText(getContext(), e.getMessage(), Toast.LENGTH_LONG).show();
+ return true;
+ }
+ }
+ }
+ );
+
+ updateMenuAppearance();
+ }
+
+
+
+ private final FeedItemMenuHandler.MenuInterface popupMenuInterface = new FeedItemMenuHandler.MenuInterface() {
+ @Override
+ public void setItemVisibility(int id, boolean visible) {
+ MenuItem item = popupMenu.getMenu().findItem(id);
+ if (item != null) {
+ item.setVisible(visible);
+ }
+ }
+ };
+
+ public void updateMenuAppearance() {
+ if (item == null || queue == null) {
+ Log.w(TAG, "UpdateMenuAppearance called while item or queue was null");
+ return;
+ }
+ FeedMedia media = item.getMedia();
+ if (media == null) {
+ header.setVisibility(View.GONE);
+ } else {
+ header.setVisibility(View.VISIBLE);
+ boolean isDownloading = DownloadRequester.getInstance().isDownloadingFile(media);
+ TypedArray drawables = getContext().obtainStyledAttributes(new int[]{R.attr.av_play,
+ R.attr.av_download, R.attr.action_stream, R.attr.content_discard, R.attr.navigation_cancel});
+
+ if (!media.isDownloaded()) {
+ butAction2.setImageDrawable(drawables.getDrawable(2));
+ butAction2.setContentDescription(getContext().getString(R.string.stream_label));
+ } else {
+ butAction2.setImageDrawable(drawables.getDrawable(3));
+ butAction2.setContentDescription(getContext().getString(R.string.remove_episode_lable));
+ }
+
+ if (isDownloading) {
+ butAction1.setImageDrawable(drawables.getDrawable(4));
+ butAction1.setContentDescription(getContext().getString(R.string.cancel_download_label));
+ } else if (media.isDownloaded()) {
+ butAction1.setImageDrawable(drawables.getDrawable(0));
+ butAction1.setContentDescription(getContext().getString(R.string.play_label));
+ } else {
+ butAction1.setImageDrawable(drawables.getDrawable(1));
+ butAction1.setContentDescription(getContext().getString(R.string.download_label));
+ }
+
+ drawables.recycle();
+ }
+ }
+
+
+ private void loadDescriptionWebview(final ShownotesProvider shownotesProvider) {
+ AsyncTask<Void, Void, Void> loadTask = new AsyncTask<Void, Void, Void>() {
+ String data;
+
+
+ private String applyWebviewStyle(String textColor, String data) {
+ final String WEBVIEW_STYLE = "<html><head><style type=\"text/css\"> @font-face { font-family: 'Roboto-Light'; src: url('file:///android_asset/Roboto-Light.ttf'); } * { color: %s; font-family: roboto-Light; font-size: 11pt; } a { font-style: normal; text-decoration: none; font-weight: normal; color: #00A8DF; } img { display: block; margin: 10 auto; max-width: %s; height: auto; } body { margin: %dpx %dpx %dpx %dpx; }</style></head><body>%s</body></html>";
+ final int pageMargin = (int) TypedValue.applyDimension(
+ TypedValue.COMPLEX_UNIT_DIP, 8, getContext().getResources()
+ .getDisplayMetrics()
+ );
+ return String.format(WEBVIEW_STYLE, textColor, "100%", pageMargin,
+ pageMargin, pageMargin, pageMargin, data);
+ }
+
+
+ @Override
+ protected void onPostExecute(Void result) {
+ super.onPostExecute(result);
+ // /webvDescription.loadData(url, "text/html", "utf-8");
+ if (FeedItemDialog.this.isShowing() && webvDescription != null) {
+ webvDescription.loadDataWithBaseURL(null, data, "text/html",
+ "utf-8", "about:blank");
+ if (BuildConfig.DEBUG)
+ Log.d(TAG, "Webview loaded");
+ }
+ }
+
+
+ @Override
+ protected Void doInBackground(Void... params) {
+ if (BuildConfig.DEBUG)
+ Log.d(TAG, "Loading Webview");
+ try {
+ Callable<String> shownotesLoadTask = shownotesProvider.loadShownotes();
+ final String shownotes = shownotesLoadTask.call();
+
+ data = StringEscapeUtils.unescapeHtml4(shownotes);
+ TypedArray res = getContext()
+ .getTheme()
+ .obtainStyledAttributes(
+ new int[]{android.R.attr.textColorPrimary});
+ int colorResource;
+ if (useDarkThemeWorkAround()) {
+ colorResource = getContext().getResources().getColor(R.color.black);
+ } else {
+ colorResource = res.getColor(0, 0);
+ }
+ String colorString = String.format("#%06X",
+ 0xFFFFFF & colorResource);
+ Log.i(TAG, "text color: " + colorString);
+ res.recycle();
+ data = applyWebviewStyle(colorString, data);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ };
+ loadTask.execute();
+ }
+
+ public void setItem(FeedItem item) {
+ if (item == null) throw new IllegalArgumentException("item = null");
+ this.item = item;
+ }
+
+ public void setItemFromCollection(Collection<FeedItem> items) {
+ for (FeedItem item : items) {
+ if (item.getId() == this.item.getId()) {
+ setItem(item);
+ break;
+ }
+ }
+ }
+
+ public void setQueue(QueueAccess queue) {
+ if (queue == null) throw new IllegalArgumentException("queue = null");
+ this.queue = queue;
+ }
+
+ public FeedItem getItem() {
+ return item;
+ }
+
+ public QueueAccess getQueue() {
+ return queue;
+ }
+}
diff --git a/src/de/danoeh/antennapod/fragment/AddFeedFragment.java b/src/de/danoeh/antennapod/fragment/AddFeedFragment.java
new file mode 100644
index 000000000..f5ae5a777
--- /dev/null
+++ b/src/de/danoeh/antennapod/fragment/AddFeedFragment.java
@@ -0,0 +1,76 @@
+package de.danoeh.antennapod.fragment;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.EditText;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.DefaultOnlineFeedViewActivity;
+import de.danoeh.antennapod.activity.MainActivity;
+import de.danoeh.antennapod.activity.OnlineFeedViewActivity;
+import de.danoeh.antennapod.activity.OpmlImportFromPathActivity;
+import de.danoeh.antennapod.fragment.gpodnet.GpodnetMainFragment;
+
+/**
+ * Provides actions for adding new podcast subscriptions
+ */
+public class AddFeedFragment extends Fragment {
+ private static final String TAG = "AddFeedFragment";
+
+ /**
+ * Preset value for url text field.
+ */
+ public static final String ARG_FEED_URL = "feedurl";
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ super.onCreateView(inflater, container, savedInstanceState);
+ View root = inflater.inflate(R.layout.addfeed, container, false);
+
+ final EditText etxtFeedurl = (EditText) root.findViewById(R.id.etxtFeedurl);
+
+ Bundle args = getArguments();
+ if (args != null && args.getString(ARG_FEED_URL) != null) {
+ etxtFeedurl.setText(args.getString(ARG_FEED_URL));
+ }
+
+ Button butBrowserGpoddernet = (Button) root.findViewById(R.id.butBrowseGpoddernet);
+ Button butOpmlImport = (Button) root.findViewById(R.id.butOpmlImport);
+ Button butConfirm = (Button) root.findViewById(R.id.butConfirm);
+
+ final MainActivity activity = (MainActivity) getActivity();
+ activity.getMainActivtyActionBar().setTitle(R.string.add_feed_label);
+
+ butBrowserGpoddernet.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ activity.loadChildFragment(new GpodnetMainFragment());
+ }
+ });
+
+ butOpmlImport.setOnClickListener(new View.OnClickListener() {
+
+ @Override
+ public void onClick(View v) {
+ startActivity(new Intent(getActivity(),
+ OpmlImportFromPathActivity.class));
+ }
+ });
+
+ butConfirm.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Intent intent = new Intent(getActivity(), DefaultOnlineFeedViewActivity.class);
+ intent.putExtra(OnlineFeedViewActivity.ARG_FEEDURL, etxtFeedurl.getText().toString());
+ intent.putExtra(OnlineFeedViewActivity.ARG_TITLE, getString(R.string.add_feed_label));
+ startActivity(intent);
+ }
+ });
+
+ return root;
+ }
+}
diff --git a/src/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java b/src/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java
new file mode 100644
index 000000000..51c92e234
--- /dev/null
+++ b/src/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java
@@ -0,0 +1,164 @@
+package de.danoeh.antennapod.fragment;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.support.v4.app.ListFragment;
+import android.view.View;
+import de.danoeh.antennapod.adapter.DownloadedEpisodesListAdapter;
+import de.danoeh.antennapod.feed.EventDistributor;
+import de.danoeh.antennapod.feed.FeedItem;
+import de.danoeh.antennapod.storage.DBReader;
+import de.danoeh.antennapod.storage.DBWriter;
+
+import java.util.List;
+
+/**
+ * Displays all running downloads and provides a button to delete them
+ */
+public class CompletedDownloadsFragment extends ListFragment {
+ private static final int EVENTS = EventDistributor.DOWNLOAD_HANDLED |
+ EventDistributor.DOWNLOADLOG_UPDATE |
+ EventDistributor.QUEUE_UPDATE |
+ EventDistributor.UNREAD_ITEMS_UPDATE;
+
+ private List<FeedItem> items;
+ private DownloadedEpisodesListAdapter listAdapter;
+
+ private boolean viewCreated = false;
+ private boolean itemsLoaded = false;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ startItemLoader();
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ EventDistributor.getInstance().register(contentUpdate);
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ EventDistributor.getInstance().unregister(contentUpdate);
+ stopItemLoader();
+ }
+
+ @Override
+ public void onDetach() {
+ super.onDetach();
+ stopItemLoader();
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ listAdapter = null;
+ viewCreated = false;
+ }
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ if (viewCreated && itemsLoaded) {
+ onFragmentLoaded();
+ }
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ viewCreated = true;
+ if (itemsLoaded && getActivity() != null) {
+ onFragmentLoaded();
+ }
+ }
+
+ private void onFragmentLoaded() {
+ if (listAdapter == null) {
+ listAdapter = new DownloadedEpisodesListAdapter(getActivity(), itemAccess);
+ setListAdapter(listAdapter);
+ }
+ listAdapter.notifyDataSetChanged();
+ }
+
+ private DownloadedEpisodesListAdapter.ItemAccess itemAccess = new DownloadedEpisodesListAdapter.ItemAccess() {
+ @Override
+ public int getCount() {
+ return (items != null) ? items.size() : 0;
+ }
+
+ @Override
+ public FeedItem getItem(int position) {
+ return (items != null) ? items.get(position) : null;
+ }
+
+ @Override
+ public void onFeedItemSecondaryAction(FeedItem item) {
+ DBWriter.deleteFeedMediaOfItem(getActivity(), item.getMedia().getId());
+ }
+ };
+
+ private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
+ @Override
+ public void update(EventDistributor eventDistributor, Integer arg) {
+ if ((arg & EVENTS) != 0) {
+ startItemLoader();
+ }
+ }
+ };
+
+ private ItemLoader itemLoader;
+
+ private void startItemLoader() {
+ if (itemLoader != null) {
+ itemLoader.cancel(true);
+ }
+ itemLoader = new ItemLoader();
+ itemLoader.execute();
+ }
+
+ private void stopItemLoader() {
+ if (itemLoader != null) {
+ itemLoader.cancel(true);
+ }
+ }
+
+ private class ItemLoader extends AsyncTask<Void, Void, List<FeedItem>> {
+
+ @Override
+ protected void onPreExecute() {
+ super.onPreExecute();
+ if (!itemsLoaded && viewCreated) {
+ setListShown(false);
+ }
+ }
+
+ @Override
+ protected void onPostExecute(List<FeedItem> feedItems) {
+ super.onPostExecute(feedItems);
+ setListShown(true);
+ if (feedItems != null) {
+ items = feedItems;
+ itemsLoaded = true;
+ if (viewCreated && getActivity() != null) {
+ onFragmentLoaded();
+ }
+ }
+ }
+
+ @Override
+ protected List<FeedItem> doInBackground(Void... params) {
+ Context context = getActivity();
+ if (context != null) {
+ return DBReader.getDownloadedItems(context);
+ }
+ return null;
+ }
+ }
+}
diff --git a/src/de/danoeh/antennapod/fragment/DownloadLogFragment.java b/src/de/danoeh/antennapod/fragment/DownloadLogFragment.java
new file mode 100644
index 000000000..d81ba4b86
--- /dev/null
+++ b/src/de/danoeh/antennapod/fragment/DownloadLogFragment.java
@@ -0,0 +1,121 @@
+package de.danoeh.antennapod.fragment;
+
+import android.content.Context;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.support.v4.app.ListFragment;
+import android.view.View;
+import de.danoeh.antennapod.adapter.DownloadLogAdapter;
+import de.danoeh.antennapod.feed.EventDistributor;
+import de.danoeh.antennapod.service.download.DownloadStatus;
+import de.danoeh.antennapod.storage.DBReader;
+
+import java.util.List;
+
+/**
+ * Shows the download log
+ */
+public class DownloadLogFragment extends ListFragment {
+
+ private List<DownloadStatus> downloadLog;
+ private DownloadLogAdapter adapter;
+
+ private boolean viewsCreated = false;
+ private boolean itemsLoaded = false;
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ EventDistributor.getInstance().register(contentUpdate);
+ startItemLoader();
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ EventDistributor.getInstance().unregister(contentUpdate);
+ stopItemLoader();
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ viewsCreated = true;
+ if (itemsLoaded) {
+ onFragmentLoaded();
+ }
+ }
+
+ private void onFragmentLoaded() {
+ if (adapter == null) {
+ adapter = new DownloadLogAdapter(getActivity(), itemAccess);
+ setListAdapter(adapter);
+ }
+ setListShown(true);
+ adapter.notifyDataSetChanged();
+
+ }
+
+ private DownloadLogAdapter.ItemAccess itemAccess = new DownloadLogAdapter.ItemAccess() {
+
+ @Override
+ public int getCount() {
+ return (downloadLog != null) ? downloadLog.size() : 0;
+ }
+
+ @Override
+ public DownloadStatus getItem(int position) {
+ return (downloadLog != null) ? downloadLog.get(position) : null;
+ }
+ };
+
+ private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
+
+ @Override
+ public void update(EventDistributor eventDistributor, Integer arg) {
+ if ((arg & EventDistributor.DOWNLOADLOG_UPDATE) != 0) {
+ startItemLoader();
+ }
+ }
+ };
+
+ private ItemLoader itemLoader;
+
+ private void startItemLoader() {
+ if (itemLoader != null) {
+ itemLoader.cancel(true);
+ }
+ itemLoader = new ItemLoader();
+ itemLoader.execute();
+ }
+
+ private void stopItemLoader() {
+ if (itemLoader != null) {
+ itemLoader.cancel(true);
+ }
+ }
+
+ private class ItemLoader extends AsyncTask<Void, Void, List<DownloadStatus>> {
+
+ @Override
+ protected void onPostExecute(List<DownloadStatus> downloadStatuses) {
+ super.onPostExecute(downloadStatuses);
+ if (downloadStatuses != null) {
+ downloadLog = downloadStatuses;
+ itemsLoaded = true;
+ if (viewsCreated) {
+ onFragmentLoaded();
+ }
+ }
+ }
+
+ @Override
+ protected List<DownloadStatus> doInBackground(Void... params) {
+ Context context = getActivity();
+ if (context != null) {
+ return DBReader.getDownloadLog(context);
+ }
+ return null;
+ }
+ }
+}
diff --git a/src/de/danoeh/antennapod/fragment/DownloadsFragment.java b/src/de/danoeh/antennapod/fragment/DownloadsFragment.java
new file mode 100644
index 000000000..5a71cb36b
--- /dev/null
+++ b/src/de/danoeh/antennapod/fragment/DownloadsFragment.java
@@ -0,0 +1,145 @@
+package de.danoeh.antennapod.fragment;
+
+import android.app.Activity;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentPagerAdapter;
+import android.support.v4.app.FragmentTransaction;
+import android.support.v4.view.ViewPager;
+import android.support.v7.app.ActionBar;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.MainActivity;
+
+/**
+ * Shows the CompletedDownloadsFragment and the RunningDownloadsFragment
+ */
+public class DownloadsFragment extends Fragment {
+
+ public static final String ARG_SELECTED_TAB = "selected_tab";
+
+ public static final int POS_RUNNING = 0;
+ public static final int POS_COMPLETED = 1;
+ public static final int POS_LOG = 2;
+
+ private ViewPager pager;
+ private MainActivity activity;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ super.onCreateView(inflater, container, savedInstanceState);
+ View root = inflater.inflate(R.layout.pager_fragment, container, false);
+ pager = (ViewPager) root.findViewById(R.id.pager);
+ DownloadsPagerAdapter pagerAdapter = new DownloadsPagerAdapter(getChildFragmentManager(), getResources());
+ pager.setAdapter(pagerAdapter);
+ final ActionBar actionBar = activity.getMainActivtyActionBar();
+ actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
+ ActionBar.TabListener tabListener = new ActionBar.TabListener() {
+ @Override
+ public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
+ pager.setCurrentItem(tab.getPosition());
+ }
+
+ @Override
+ public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
+
+ }
+
+ @Override
+ public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
+
+ }
+ };
+ actionBar.removeAllTabs();
+ actionBar.addTab(actionBar.newTab()
+ .setText(R.string.downloads_running_label)
+ .setTabListener(tabListener));
+ actionBar.addTab(actionBar.newTab()
+ .setText(R.string.downloads_completed_label)
+ .setTabListener(tabListener));
+ actionBar.addTab(actionBar.newTab()
+ .setText(R.string.downloads_log_label)
+ .setTabListener(tabListener));
+
+ pager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
+ @Override
+ public void onPageSelected(int position) {
+ super.onPageSelected(position);
+ actionBar.setSelectedNavigationItem(position);
+ }
+ });
+ return root;
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ if (getArguments() != null) {
+ int tab = getArguments().getInt(ARG_SELECTED_TAB);
+ pager.setCurrentItem(tab, false);
+ }
+ }
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ this.activity = (MainActivity) activity;
+ }
+
+ @Override
+ public void onDetach() {
+ super.onDetach();
+ activity.getMainActivtyActionBar().removeAllTabs();
+ activity.getMainActivtyActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
+ }
+
+ public class DownloadsPagerAdapter extends FragmentPagerAdapter {
+
+
+
+
+ Resources resources;
+
+ public DownloadsPagerAdapter(FragmentManager fm, Resources resources) {
+ super(fm);
+ this.resources = resources;
+ }
+
+ @Override
+ public Fragment getItem(int position) {
+ switch (position) {
+ case POS_RUNNING:
+ return new RunningDownloadsFragment();
+ case POS_COMPLETED:
+ return new CompletedDownloadsFragment();
+ case POS_LOG:
+ return new DownloadLogFragment();
+ default:
+ return null;
+ }
+ }
+
+ @Override
+ public int getCount() {
+ return 3;
+ }
+
+ @Override
+ public CharSequence getPageTitle(int position) {
+ switch (position) {
+ case POS_RUNNING:
+ return resources.getString(R.string.downloads_running_label);
+ case POS_COMPLETED:
+ return resources.getString(R.string.downloads_completed_label);
+ case POS_LOG:
+ return resources.getString(R.string.downloads_log_label);
+ default:
+ return super.getPageTitle(position);
+ }
+ }
+ }
+}
diff --git a/src/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java b/src/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java
index 47cd3f244..db47cd8a4 100644
--- a/src/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java
+++ b/src/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java
@@ -29,8 +29,6 @@ public class ExternalPlayerFragment extends Fragment {
private ImageView imgvCover;
private ViewGroup layoutInfo;
private TextView txtvTitle;
- private TextView txtvPosition;
- private TextView txtvStatus;
private ImageButton butPlay;
private PlaybackController controller;
@@ -48,9 +46,7 @@ public class ExternalPlayerFragment extends Fragment {
imgvCover = (ImageView) root.findViewById(R.id.imgvCover);
layoutInfo = (ViewGroup) root.findViewById(R.id.layoutInfo);
txtvTitle = (TextView) root.findViewById(R.id.txtvTitle);
- txtvPosition = (TextView) root.findViewById(R.id.txtvPosition);
butPlay = (ImageButton) root.findViewById(R.id.butPlay);
- txtvStatus = (TextView) root.findViewById(R.id.txtvStatus);
layoutInfo.setOnClickListener(new OnClickListener() {
@@ -84,12 +80,6 @@ public class ExternalPlayerFragment extends Fragment {
@Override
public void onPositionObserverUpdate() {
- int duration = controller.getDuration();
- int position = controller.getPosition();
- if (duration != PlaybackController.INVALID_TIME
- && position != PlaybackController.INVALID_TIME) {
- txtvPosition.setText(getPositionString(position, duration));
- }
}
@Override
@@ -127,12 +117,10 @@ public class ExternalPlayerFragment extends Fragment {
@Override
public void postStatusMsg(int msg) {
- txtvStatus.setText(msg);
}
@Override
public void clearStatusMsg() {
- txtvStatus.setText("");
}
@Override
@@ -223,8 +211,6 @@ public class ExternalPlayerFragment extends Fragment {
(int) getActivity().getResources().getDimension(
R.dimen.external_player_height));
- txtvPosition.setText(getPositionString(media.getPosition(),
- media.getDuration()));
fragmentLayout.setVisibility(View.VISIBLE);
if (controller.isPlayingVideo()) {
butPlay.setVisibility(View.GONE);
diff --git a/src/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java b/src/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java
index 48c544457..bf6974982 100644
--- a/src/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java
+++ b/src/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java
@@ -236,7 +236,7 @@ public class ItemDescriptionFragment extends Fragment {
* value is inserted directly into the CSS String.
*/
private String applyWebviewStyle(String textColor, String data) {
- final String WEBVIEW_STYLE = "<html><head><style type=\"text/css\"> * { color: %s; font-family: Helvetica; line-height: 1.5em; font-size: 11pt; } a { font-style: normal; text-decoration: none; font-weight: normal; color: #00A8DF; } img { display: block; margin: 10 auto; max-width: %s; height: auto; } body { margin: %dpx %dpx %dpx %dpx; }</style></head><body>%s</body></html>";
+ final String WEBVIEW_STYLE = "<html><head><style type=\"text/css\"> @font-face { font-family: 'Roboto-Light'; src: url('file:///android_asset/Roboto-Light.ttf'); } * { color: %s; font-family: roboto-Light; font-size: 11pt; } a { font-style: normal; text-decoration: none; font-weight: normal; color: #00A8DF; } img { display: block; margin: 10 auto; max-width: %s; height: auto; } body { margin: %dpx %dpx %dpx %dpx; }</style></head><body>%s</body></html>";
final int pageMargin = (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, 8, getResources()
.getDisplayMetrics());
diff --git a/src/de/danoeh/antennapod/fragment/ItemlistFragment.java b/src/de/danoeh/antennapod/fragment/ItemlistFragment.java
index e5845dd76..82fe13c32 100644
--- a/src/de/danoeh/antennapod/fragment/ItemlistFragment.java
+++ b/src/de/danoeh/antennapod/fragment/ItemlistFragment.java
@@ -2,326 +2,409 @@ package de.danoeh.antennapod.fragment;
import android.annotation.SuppressLint;
import android.content.Context;
-import android.content.Intent;
+import android.content.DialogInterface;
import android.os.AsyncTask;
import android.os.Bundle;
+import android.os.Handler;
import android.support.v4.app.ListFragment;
import android.support.v7.app.ActionBarActivity;
+import android.support.v7.widget.SearchView;
+import android.text.util.Linkify;
import android.util.Log;
import android.view.*;
-import android.view.ContextMenu.ContextMenuInfo;
+import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import de.danoeh.antennapod.BuildConfig;
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.activity.ItemviewActivity;
-import de.danoeh.antennapod.adapter.ActionButtonCallback;
+import de.danoeh.antennapod.activity.MainActivity;
+import de.danoeh.antennapod.adapter.DefaultActionButtonCallback;
import de.danoeh.antennapod.adapter.InternalFeedItemlistAdapter;
+import de.danoeh.antennapod.asynctask.DownloadObserver;
+import de.danoeh.antennapod.asynctask.FeedRemover;
+import de.danoeh.antennapod.asynctask.ImageLoader;
+import de.danoeh.antennapod.dialog.ConfirmationDialog;
import de.danoeh.antennapod.dialog.DownloadRequestErrorDialogCreator;
+import de.danoeh.antennapod.dialog.FeedItemDialog;
import de.danoeh.antennapod.feed.EventDistributor;
import de.danoeh.antennapod.feed.Feed;
import de.danoeh.antennapod.feed.FeedItem;
+import de.danoeh.antennapod.feed.FeedMedia;
import de.danoeh.antennapod.service.download.DownloadService;
+import de.danoeh.antennapod.service.download.Downloader;
import de.danoeh.antennapod.storage.DBReader;
import de.danoeh.antennapod.storage.DownloadRequestException;
import de.danoeh.antennapod.storage.DownloadRequester;
import de.danoeh.antennapod.util.QueueAccess;
import de.danoeh.antennapod.util.menuhandler.FeedItemMenuHandler;
+import de.danoeh.antennapod.util.menuhandler.FeedMenuHandler;
+import de.danoeh.antennapod.util.menuhandler.MenuItemUtils;
import java.util.List;
-/** Displays a list of FeedItems. */
+/**
+ * Displays a list of FeedItems.
+ */
@SuppressLint("ValidFragment")
public class ItemlistFragment extends ListFragment {
- private static final String TAG = "ItemlistFragment";
-
- private static final int EVENTS = EventDistributor.DOWNLOAD_HANDLED
- | EventDistributor.DOWNLOAD_QUEUED
- | EventDistributor.QUEUE_UPDATE
- | EventDistributor.UNREAD_ITEMS_UPDATE;
-
- public static final String EXTRA_SELECTED_FEEDITEM = "extra.de.danoeh.antennapod.activity.selected_feeditem";
- public static final String ARGUMENT_FEED_ID = "argument.de.danoeh.antennapod.feed_id";
- protected InternalFeedItemlistAdapter fila;
-
- private Feed feed;
- protected List<Long> queue;
-
- protected FeedItem selectedItem = null;
- protected boolean contextMenuClosed = true;
-
- /** Argument for FeeditemlistAdapter */
- protected boolean showFeedtitle;
-
- private AsyncTask<Long, Void, Feed> currentLoadTask;
-
- public ItemlistFragment(boolean showFeedtitle) {
- super();
- this.showFeedtitle = showFeedtitle;
- }
-
- public ItemlistFragment() {
- }
-
- /**
- * Creates new ItemlistFragment which shows the Feeditems of a specific
- * feed. Sets 'showFeedtitle' to false
- *
- * @param feedId
- * The id of the feed to show
- * @return the newly created instance of an ItemlistFragment
- */
- public static ItemlistFragment newInstance(long feedId) {
- ItemlistFragment i = new ItemlistFragment();
- i.showFeedtitle = false;
- Bundle b = new Bundle();
- b.putLong(ARGUMENT_FEED_ID, feedId);
- i.setArguments(b);
- return i;
- }
-
- private InternalFeedItemlistAdapter.ItemAccess itemAccessRef;
- protected InternalFeedItemlistAdapter.ItemAccess itemAccess() {
- if (itemAccessRef == null) {
- itemAccessRef = new InternalFeedItemlistAdapter.ItemAccess() {
-
- @Override
- public FeedItem getItem(int position) {
- return (feed != null) ? feed.getItemAtIndex(true, position) : null;
- }
+ private static final String TAG = "ItemlistFragment";
- @Override
- public int getCount() {
- return (feed != null) ? feed.getNumOfItems(true) : 0;
- }
+ private static final int EVENTS = EventDistributor.DOWNLOAD_HANDLED
+ | EventDistributor.DOWNLOAD_QUEUED
+ | EventDistributor.QUEUE_UPDATE
+ | EventDistributor.UNREAD_ITEMS_UPDATE;
- @Override
- public boolean isInQueue(FeedItem item) {
- return (queue != null) && queue.contains(item.getId());
- }
- };
- }
- return itemAccessRef;
+ public static final String EXTRA_SELECTED_FEEDITEM = "extra.de.danoeh.antennapod.activity.selected_feeditem";
+ public static final String ARGUMENT_FEED_ID = "argument.de.danoeh.antennapod.feed_id";
+
+ protected InternalFeedItemlistAdapter adapter;
+
+ private long feedID;
+ private Feed feed;
+ protected QueueAccess queue;
+
+ private boolean itemsLoaded = false;
+ private boolean viewsCreated = false;
+
+ private DownloadObserver downloadObserver;
+ private List<Downloader> downloaderList;
+
+ private FeedItemDialog feedItemDialog;
+
+
+ /**
+ * Creates new ItemlistFragment which shows the Feeditems of a specific
+ * feed. Sets 'showFeedtitle' to false
+ *
+ * @param feedId The id of the feed to show
+ * @return the newly created instance of an ItemlistFragment
+ */
+ public static ItemlistFragment newInstance(long feedId) {
+ ItemlistFragment i = new ItemlistFragment();
+ Bundle b = new Bundle();
+ b.putLong(ARGUMENT_FEED_ID, feedId);
+ i.setArguments(b);
+ return i;
}
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- return inflater.inflate(R.layout.feeditemlist, container, false);
- }
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setRetainInstance(true);
+ setHasOptionsMenu(true);
+
+ Bundle args = getArguments();
+ if (args == null) throw new IllegalArgumentException("args invalid");
+ feedID = args.getLong(ARGUMENT_FEED_ID);
+ }
@Override
public void onStart() {
super.onStart();
EventDistributor.getInstance().register(contentUpdate);
- loadData();
+ if (downloadObserver != null) {
+ downloadObserver.setActivity(getActivity());
+ downloadObserver.onResume();
+ }
+ if (viewsCreated && itemsLoaded) {
+ onFragmentLoaded();
+ }
}
@Override
public void onStop() {
super.onStop();
EventDistributor.getInstance().unregister(contentUpdate);
- if (currentLoadTask != null) {
- currentLoadTask.cancel(true);
- }
+ stopItemLoader();
}
- protected synchronized void loadData() {
- final long feedId;
- if (feed == null) {
- feedId = getArguments().getLong(ARGUMENT_FEED_ID);
- } else {
- feedId = feed.getId();
- }
- if (currentLoadTask != null) {
- currentLoadTask.cancel(true);
+ @Override
+ public void onResume() {
+ super.onResume();
+ updateProgressBarVisibility();
+ startItemLoader();
+ }
+
+ @Override
+ public void onDetach() {
+ super.onDetach();
+ stopItemLoader();
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ resetViewState();
+ }
+
+ private void resetViewState() {
+ adapter = null;
+ viewsCreated = false;
+ if (downloadObserver != null) {
+ downloadObserver.onPause();
}
- AsyncTask<Long, Void, Feed> loadTask = new AsyncTask<Long, Void, Feed>(){
- private volatile List<Long> queueRef;
+ feedItemDialog = null;
+ }
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ super.onCreateOptionsMenu(menu, inflater);
+ FeedMenuHandler.onCreateOptionsMenu(inflater, menu);
+
+ final SearchView sv = new SearchView(getActivity());
+ MenuItemUtils.addSearchItem(menu, sv);
+ sv.setQueryHint(getString(R.string.search_hint));
+ sv.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
- protected Feed doInBackground(Long... longs) {
- Context context = ItemlistFragment.this.getActivity();
- if (context != null) {
- Feed result = DBReader.getFeed(context, longs[0]);
- if (result != null) {
- result.setItems(DBReader.getFeedItemList(context, result));
- queueRef = DBReader.getQueueIDList(context);
- return result;
- }
+ public boolean onQueryTextSubmit(String s) {
+ sv.clearFocus();
+ if (itemsLoaded) {
+ ((MainActivity) getActivity()).loadChildFragment(SearchFragment.newInstance(s, feed.getId()));
}
- return null;
+ return true;
}
@Override
- protected void onPostExecute(Feed result) {
- super.onPostExecute(result);
- if (result != null && result.getItems() != null) {
- feed = result;
- if (queueRef != null) {
- queue = queueRef;
- } else {
- Log.e(TAG, "Could not load queue");
- }
- setEmptyViewIfListIsEmpty();
- if (fila != null) {
- fila.notifyDataSetChanged();
+ public boolean onQueryTextChange(String s) {
+ return false;
+ }
+ });
+ }
+
+ @Override
+ public void onPrepareOptionsMenu(Menu menu) {
+ FeedMenuHandler.onPrepareOptionsMenu(menu, feed);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (!super.onOptionsItemSelected(item)) {
+ try {
+ if (!FeedMenuHandler.onOptionsItemClicked(getActivity(), item, feed)) {
+ switch (item.getItemId()) {
+ case R.id.remove_item:
+ final FeedRemover remover = new FeedRemover(
+ getActivity(), feed) {
+ @Override
+ protected void onPostExecute(Void result) {
+ super.onPostExecute(result);
+ ((MainActivity)getActivity()).loadNavFragment(MainActivity.POS_NEW, null);
+ }
+ };
+ ConfirmationDialog conDialog = new ConfirmationDialog(getActivity(),
+ R.string.remove_feed_label,
+ R.string.feed_delete_confirmation_msg) {
+
+ @Override
+ public void onConfirmButtonPressed(
+ DialogInterface dialog) {
+ dialog.dismiss();
+ remover.executeAsync();
+ }
+ };
+ conDialog.createNewDialog().show();
+ return true;
+ default:
+ return false;
+
}
} else {
- if (result == null) {
- Log.e(TAG, "Could not load feed with id " + feedId);
- } else if (result.getItems() == null) {
- Log.e(TAG, "Could not load feed items");
- }
+ return true;
}
+ } catch (DownloadRequestException e) {
+ e.printStackTrace();
+ DownloadRequestErrorDialogCreator.newRequestErrorDialog(getActivity(), e.getMessage());
+ return true;
}
- };
- currentLoadTask = loadTask;
- loadTask.execute(feedId);
+ } else {
+ return true;
+ }
+
}
- private void setEmptyViewIfListIsEmpty() {
- if (getListView() != null && feed != null && feed.getItems() != null) {
- if (feed.getItems().isEmpty()) {
- ((TextView) getActivity().findViewById(android.R.id.empty)).setText(R.string.no_items_label);
- }
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ ((ActionBarActivity) getActivity()).getSupportActionBar().setTitle("");
+
+ viewsCreated = true;
+ if (itemsLoaded) {
+ onFragmentLoaded();
}
}
- protected InternalFeedItemlistAdapter createListAdapter() {
- return new InternalFeedItemlistAdapter(getActivity(), itemAccess(),
- adapterCallback, showFeedtitle);
- }
-
- @Override
- public void onResume() {
- super.onResume();
- getActivity().runOnUiThread(new Runnable() {
-
- @Override
- public void run() {
- fila.notifyDataSetChanged();
- }
- });
- updateProgressBarVisibility();
- }
-
- @Override
- public void onListItemClick(ListView l, View v, int position, long id) {
- FeedItem selection = fila.getItem(position - l.getHeaderViewsCount());
- Intent showItem = new Intent(getActivity(), ItemviewActivity.class);
- showItem.putExtra(FeedlistFragment.EXTRA_SELECTED_FEED, selection
- .getFeed().getId());
- showItem.putExtra(EXTRA_SELECTED_FEEDITEM, selection.getId());
-
- startActivity(showItem);
- }
-
- private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
-
- @Override
- public void update(EventDistributor eventDistributor, Integer arg) {
- if ((EVENTS & arg) != 0) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Received contentUpdate Intent.");
- if ((EventDistributor.DOWNLOAD_QUEUED & arg) != 0) {
- updateProgressBarVisibility();
- } else {
- if (feed != null) {
- loadData();
- }
- updateProgressBarVisibility();
- }
- }
- }
- };
-
- private void updateProgressBarVisibility() {
- if (feed != null) {
- if (DownloadService.isRunning
- && DownloadRequester.getInstance().isDownloadingFile(feed)) {
+ @Override
+ public void onListItemClick(ListView l, View v, int position, long id) {
+ FeedItem selection = adapter.getItem(position - l.getHeaderViewsCount());
+ feedItemDialog = FeedItemDialog.newInstace(getActivity(), selection, queue);
+ feedItemDialog.show();
+ }
+
+ private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
+
+ @Override
+ public void update(EventDistributor eventDistributor, Integer arg) {
+ if ((EVENTS & arg) != 0) {
+ if (BuildConfig.DEBUG)
+ Log.d(TAG, "Received contentUpdate Intent.");
+ if ((EventDistributor.DOWNLOAD_QUEUED & arg) != 0) {
+ updateProgressBarVisibility();
+ } else {
+ startItemLoader();
+ updateProgressBarVisibility();
+ }
+ }
+ }
+ };
+
+ private void updateProgressBarVisibility() {
+ if (feed != null) {
+ if (DownloadService.isRunning
+ && DownloadRequester.getInstance().isDownloadingFile(feed)) {
((ActionBarActivity) getActivity())
- .setSupportProgressBarIndeterminateVisibility(true);
- } else {
+ .setSupportProgressBarIndeterminateVisibility(true);
+ } else {
((ActionBarActivity) getActivity())
- .setSupportProgressBarIndeterminateVisibility(false);
- }
+ .setSupportProgressBarIndeterminateVisibility(false);
+ }
getActivity().supportInvalidateOptionsMenu();
- }
- }
-
- protected ActionButtonCallback adapterCallback = new ActionButtonCallback() {
-
- @Override
- public void onActionButtonPressed(FeedItem item) {
- selectedItem = item;
- contextMenuClosed = true;
- getListView().showContextMenu();
- }
- };
-
- @Override
- public void onViewCreated(View view, Bundle savedInstanceState) {
- fila = createListAdapter();
- setListAdapter(fila);
- this.getListView().setItemsCanFocus(true);
- getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
- registerForContextMenu(getListView());
- getListView().setOnItemLongClickListener(null);
- }
-
- @Override
- public void onCreateContextMenu(final ContextMenu menu, View v,
- ContextMenuInfo menuInfo) {
- super.onCreateContextMenu(menu, v, menuInfo);
- if (!contextMenuClosed) { // true if context menu was cancelled before
- selectedItem = null;
- }
- contextMenuClosed = false;
- getListView().setOnItemLongClickListener(null);
- if (selectedItem != null) {
- new MenuInflater(ItemlistFragment.this.getActivity()).inflate(
- R.menu.feeditem, menu);
-
- menu.setHeaderTitle(selectedItem.getTitle());
- FeedItemMenuHandler.onPrepareMenu(
- new FeedItemMenuHandler.MenuInterface() {
-
- @Override
- public void setItemVisibility(int id, boolean visible) {
- menu.findItem(id).setVisible(visible);
- }
- }, selectedItem, false, QueueAccess.IDListAccess(queue));
-
- }
- }
-
- @Override
- public boolean onContextItemSelected(android.view.MenuItem item) {
- boolean handled = false;
-
- if (selectedItem != null) {
-
- try {
- handled = FeedItemMenuHandler.onMenuItemClicked(
- getActivity(), item.getItemId(), selectedItem);
- } catch (DownloadRequestException e) {
- e.printStackTrace();
- DownloadRequestErrorDialogCreator.newRequestErrorDialog(
- getActivity(), e.getMessage());
- }
- if (handled) {
- fila.notifyDataSetChanged();
- }
-
- }
- selectedItem = null;
- contextMenuClosed = true;
- return handled;
- }
-
- public InternalFeedItemlistAdapter getListAdapter() {
- return fila;
- }
+ }
+ }
+
+ private void onFragmentLoaded() {
+ if (adapter == null) {
+ getListView().setAdapter(null);
+ setupHeaderView();
+ adapter = new InternalFeedItemlistAdapter(getActivity(), itemAccess, new DefaultActionButtonCallback(getActivity()), false);
+ setListAdapter(adapter);
+ downloadObserver = new DownloadObserver(getActivity(), new Handler(), downloadObserverCallback);
+ downloadObserver.onResume();
+ }
+ setListShown(true);
+ adapter.notifyDataSetChanged();
+
+ if (feedItemDialog != null && feedItemDialog.isShowing()) {
+ feedItemDialog.setItemFromCollection(feed.getItems());
+ feedItemDialog.setQueue(queue);
+ feedItemDialog.updateMenuAppearance();
+ }
+ getActivity().supportInvalidateOptionsMenu();
+ }
+ private DownloadObserver.Callback downloadObserverCallback = new DownloadObserver.Callback() {
+ @Override
+ public void onContentChanged() {
+ if (adapter != null) {
+ adapter.notifyDataSetChanged();
+ }
+ if (feedItemDialog != null && feedItemDialog.isShowing()) {
+ feedItemDialog.updateMenuAppearance();
+ }
+ }
+
+ @Override
+ public void onDownloadDataAvailable(List<Downloader> downloaderList) {
+ ItemlistFragment.this.downloaderList = downloaderList;
+ if (adapter != null) {
+ adapter.notifyDataSetChanged();
+ }
+ }
+ };
+
+ private void setupHeaderView() {
+ if (getListView() == null || feed == null) {
+ Log.e(TAG, "Unable to setup listview: listView = null or feed = null");
+ return;
+ }
+ LayoutInflater inflater = (LayoutInflater)
+ getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ View header = inflater.inflate(R.layout.feeditemlist_header, null);
+ getListView().addHeaderView(header);
+
+ TextView txtvTitle = (TextView) header.findViewById(R.id.txtvTitle);
+ TextView txtvAuthor = (TextView) header.findViewById(R.id.txtvAuthor);
+ TextView txtvLink = (TextView) header.findViewById(R.id.txtvLink);
+ ImageView imgvCover = (ImageView) header.findViewById(R.id.imgvCover);
+
+ txtvTitle.setText(feed.getTitle());
+ txtvAuthor.setText(feed.getAuthor());
+ txtvLink.setText(feed.getLink());
+ Linkify.addLinks(txtvLink, Linkify.WEB_URLS);
+ ImageLoader.getInstance().loadThumbnailBitmap(feed.getImage(), imgvCover,
+ (int) getResources().getDimension(R.dimen.thumbnail_length_onlinefeedview));
+ }
+
+ private InternalFeedItemlistAdapter.ItemAccess itemAccess = new InternalFeedItemlistAdapter.ItemAccess() {
+
+ @Override
+ public FeedItem getItem(int position) {
+ return (feed != null) ? feed.getItemAtIndex(true, position) : null;
+ }
+
+ @Override
+ public int getCount() {
+ return (feed != null) ? feed.getNumOfItems(true) : 0;
+ }
+
+ @Override
+ public boolean isInQueue(FeedItem item) {
+ return (queue != null) && queue.contains(item.getId());
+ }
+
+ @Override
+ public int getItemDownloadProgressPercent(FeedItem item) {
+ if (downloaderList != null) {
+ for (Downloader downloader : downloaderList) {
+ if (downloader.getDownloadRequest().getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA
+ && downloader.getDownloadRequest().getFeedfileId() == item.getMedia().getId()) {
+ return downloader.getDownloadRequest().getProgressPercent();
+ }
+ }
+ }
+ return 0;
+ }
+ };
+
+ private ItemLoader itemLoader;
+
+ private void startItemLoader() {
+ if (itemLoader != null) {
+ itemLoader.cancel(true);
+ }
+ itemLoader = new ItemLoader();
+ itemLoader.execute(feedID);
+ }
+
+ private void stopItemLoader() {
+ if (itemLoader != null) {
+ itemLoader.cancel(true);
+ }
+ }
+
+ private class ItemLoader extends AsyncTask<Long, Void, Object[]> {
+ @Override
+ protected Object[] doInBackground(Long... params) {
+ long feedID = params[0];
+ Context context = getActivity();
+ if (context != null) {
+ return new Object[]{DBReader.getFeed(context, feedID),
+ QueueAccess.IDListAccess(DBReader.getQueueIDList(context))};
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ protected void onPostExecute(Object[] res) {
+ super.onPostExecute(res);
+ if (res != null) {
+ feed = (Feed) res[0];
+ queue = (QueueAccess) res[1];
+ itemsLoaded = true;
+ if (viewsCreated) {
+ onFragmentLoaded();
+ }
+ }
+ }
+ }
}
diff --git a/src/de/danoeh/antennapod/fragment/NewEpisodesFragment.java b/src/de/danoeh/antennapod/fragment/NewEpisodesFragment.java
new file mode 100644
index 000000000..3e67599f0
--- /dev/null
+++ b/src/de/danoeh/antennapod/fragment/NewEpisodesFragment.java
@@ -0,0 +1,381 @@
+package de.danoeh.antennapod.fragment;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.Handler;
+import android.support.v4.app.Fragment;
+import android.support.v7.app.ActionBarActivity;
+import android.support.v7.widget.SearchView;
+import android.view.*;
+import android.widget.AdapterView;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+import android.widget.Toast;
+import com.mobeta.android.dslv.DragSortListView;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.MainActivity;
+import de.danoeh.antennapod.adapter.DefaultActionButtonCallback;
+import de.danoeh.antennapod.adapter.NewEpisodesListAdapter;
+import de.danoeh.antennapod.asynctask.DownloadObserver;
+import de.danoeh.antennapod.dialog.FeedItemDialog;
+import de.danoeh.antennapod.feed.EventDistributor;
+import de.danoeh.antennapod.feed.Feed;
+import de.danoeh.antennapod.feed.FeedItem;
+import de.danoeh.antennapod.feed.FeedMedia;
+import de.danoeh.antennapod.service.download.DownloadService;
+import de.danoeh.antennapod.service.download.Downloader;
+import de.danoeh.antennapod.storage.DBReader;
+import de.danoeh.antennapod.storage.DBTasks;
+import de.danoeh.antennapod.storage.DBWriter;
+import de.danoeh.antennapod.storage.DownloadRequester;
+import de.danoeh.antennapod.util.QueueAccess;
+import de.danoeh.antennapod.util.menuhandler.MenuItemUtils;
+
+import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * Shows unread or recently published episodes
+ */
+public class NewEpisodesFragment extends Fragment {
+ private static final String TAG = "NewEpisodesFragment";
+ private static final int EVENTS = EventDistributor.DOWNLOAD_HANDLED |
+ EventDistributor.DOWNLOAD_QUEUED |
+ EventDistributor.QUEUE_UPDATE |
+ EventDistributor.UNREAD_ITEMS_UPDATE;
+
+ private static final int RECENT_EPISODES_LIMIT = 150;
+
+ private DragSortListView listView;
+ private NewEpisodesListAdapter listAdapter;
+ private TextView txtvEmpty;
+ private ProgressBar progLoading;
+
+ private List<FeedItem> unreadItems;
+ private List<FeedItem> recentItems;
+ private QueueAccess queueAccess;
+ private List<Downloader> downloaderList;
+
+ private boolean itemsLoaded = false;
+ private boolean viewsCreated = false;
+
+ private AtomicReference<MainActivity> activity = new AtomicReference<MainActivity>();
+
+ private DownloadObserver downloadObserver = null;
+
+ private FeedItemDialog feedItemDialog;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setRetainInstance(true);
+ setHasOptionsMenu(true);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ startItemLoader();
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ EventDistributor.getInstance().register(contentUpdate);
+ this.activity.set((MainActivity) getActivity());
+ if (downloadObserver != null) {
+ downloadObserver.setActivity(getActivity());
+ downloadObserver.onResume();
+ }
+ if (viewsCreated && itemsLoaded) {
+ onFragmentLoaded();
+ }
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ EventDistributor.getInstance().unregister(contentUpdate);
+ stopItemLoader();
+ }
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ this.activity.set((MainActivity) getActivity());
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ resetViewState();
+ }
+
+ private void resetViewState() {
+ listAdapter = null;
+ activity.set(null);
+ viewsCreated = false;
+ if (downloadObserver != null) {
+ downloadObserver.onPause();
+ }
+ feedItemDialog = null;
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ super.onCreateOptionsMenu(menu, inflater);
+ inflater.inflate(R.menu.new_episodes, menu);
+
+ final SearchView sv = new SearchView(getActivity());
+ MenuItemUtils.addSearchItem(menu, sv);
+ sv.setQueryHint(getString(R.string.search_hint));
+ sv.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
+ @Override
+ public boolean onQueryTextSubmit(String s) {
+ sv.clearFocus();
+ ((MainActivity) getActivity()).loadChildFragment(SearchFragment.newInstance(s));
+ return true;
+ }
+
+ @Override
+ public boolean onQueryTextChange(String s) {
+ return false;
+ }
+ });
+ }
+
+ @Override
+ public void onPrepareOptionsMenu(Menu menu) {
+ super.onPrepareOptionsMenu(menu);
+ menu.findItem(R.id.mark_all_read_item).setVisible(unreadItems != null && !unreadItems.isEmpty());
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (!super.onOptionsItemSelected(item)) {
+ switch (item.getItemId()) {
+ case R.id.refresh_item:
+ List<Feed> feeds = ((MainActivity) getActivity()).getFeeds();
+ if (feeds != null) {
+ DBTasks.refreshAllFeeds(getActivity(), feeds);
+ }
+ return true;
+ case R.id.mark_all_read_item:
+ DBWriter.markAllItemsRead(getActivity());
+ Toast.makeText(getActivity(), R.string.mark_all_read_msg, Toast.LENGTH_SHORT).show();
+ return true;
+ default:
+ return false;
+ }
+ } else {
+ return true;
+ }
+
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ super.onCreateView(inflater, container, savedInstanceState);
+ ((MainActivity) getActivity()).getSupportActionBar().setTitle(R.string.new_episodes_label);
+
+ View root = inflater.inflate(R.layout.new_episodes_fragment, container, false);
+ listView = (DragSortListView) root.findViewById(android.R.id.list);
+ txtvEmpty = (TextView) root.findViewById(android.R.id.empty);
+ progLoading = (ProgressBar) root.findViewById(R.id.progLoading);
+
+ listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ FeedItem item = (FeedItem) listAdapter.getItem(position - listView.getHeaderViewsCount());
+ if (item != null) {
+ feedItemDialog = FeedItemDialog.newInstace(activity.get(), item, queueAccess);
+ feedItemDialog.show();
+ }
+
+ }
+ });
+
+ if (!itemsLoaded) {
+ progLoading.setVisibility(View.VISIBLE);
+ txtvEmpty.setVisibility(View.GONE);
+ }
+
+ viewsCreated = true;
+
+ if (itemsLoaded && activity.get() != null) {
+ onFragmentLoaded();
+ }
+
+ return root;
+ }
+
+ private void onFragmentLoaded() {
+ if (listAdapter == null) {
+ listAdapter = new NewEpisodesListAdapter(activity.get(), itemAccess, new DefaultActionButtonCallback(activity.get()));
+ listView.setAdapter(listAdapter);
+ listView.setEmptyView(txtvEmpty);
+ downloadObserver = new DownloadObserver(activity.get(), new Handler(), downloadObserverCallback);
+ downloadObserver.onResume();
+ }
+ if (feedItemDialog != null && feedItemDialog.isShowing()) {
+ feedItemDialog.setQueue(queueAccess);
+ feedItemDialog.setItemFromCollection(unreadItems);
+ feedItemDialog.setItemFromCollection(recentItems);
+ feedItemDialog.updateMenuAppearance();
+ }
+ listAdapter.notifyDataSetChanged();
+ getActivity().supportInvalidateOptionsMenu();
+ updateProgressBarVisibility();
+ }
+
+ private DownloadObserver.Callback downloadObserverCallback = new DownloadObserver.Callback() {
+ @Override
+ public void onContentChanged() {
+ if (listAdapter != null) {
+ listAdapter.notifyDataSetChanged();
+ }
+ if (feedItemDialog != null && feedItemDialog.isShowing()) {
+ feedItemDialog.updateMenuAppearance();
+ }
+ }
+
+ @Override
+ public void onDownloadDataAvailable(List<Downloader> downloaderList) {
+ NewEpisodesFragment.this.downloaderList = downloaderList;
+ if (listAdapter != null) {
+ listAdapter.notifyDataSetChanged();
+ }
+ }
+ };
+
+ private NewEpisodesListAdapter.ItemAccess itemAccess = new NewEpisodesListAdapter.ItemAccess() {
+
+
+ @Override
+ public int getUnreadItemsCount() {
+ return (itemsLoaded) ? unreadItems.size() : 0;
+ }
+
+ @Override
+ public int getRecentItemsCount() {
+ return (itemsLoaded) ? recentItems.size() : 0;
+ }
+
+ @Override
+ public FeedItem getUnreadItem(int position) {
+ return (itemsLoaded) ? unreadItems.get(position) : null;
+ }
+
+ @Override
+ public FeedItem getRecentItem(int position) {
+ return (itemsLoaded) ? recentItems.get(position) : null;
+ }
+
+ @Override
+ public int getItemDownloadProgressPercent(FeedItem item) {
+ if (downloaderList != null) {
+ for (Downloader downloader : downloaderList) {
+ if (downloader.getDownloadRequest().getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA
+ && downloader.getDownloadRequest().getFeedfileId() == item.getMedia().getId()) {
+ return downloader.getDownloadRequest().getProgressPercent();
+ }
+ }
+ }
+ return 0;
+ }
+
+ @Override
+ public boolean isInQueue(FeedItem item) {
+ if (itemsLoaded) {
+ return queueAccess.contains(item.getId());
+ } else {
+ return false;
+ }
+ }
+
+
+ };
+
+ private void updateProgressBarVisibility() {
+ if (DownloadService.isRunning
+ && DownloadRequester.getInstance().isDownloadingFeeds()) {
+ ((ActionBarActivity) getActivity())
+ .setSupportProgressBarIndeterminateVisibility(true);
+ } else {
+ ((ActionBarActivity) getActivity())
+ .setSupportProgressBarIndeterminateVisibility(false);
+ }
+ getActivity().supportInvalidateOptionsMenu();
+
+ }
+
+ private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
+ @Override
+ public void update(EventDistributor eventDistributor, Integer arg) {
+ if ((arg & EVENTS) != 0) {
+ startItemLoader();
+ updateProgressBarVisibility();
+ }
+ }
+ };
+
+ private ItemLoader itemLoader;
+
+ private void startItemLoader() {
+ if (itemLoader != null) {
+ itemLoader.cancel(true);
+ }
+ itemLoader = new ItemLoader();
+ itemLoader.execute();
+ }
+
+ private void stopItemLoader() {
+ if (itemLoader != null) {
+ itemLoader.cancel(true);
+ }
+ }
+
+ private class ItemLoader extends AsyncTask<Void, Void, Object[]> {
+
+ @Override
+ protected void onPreExecute() {
+ super.onPreExecute();
+ if (viewsCreated && !itemsLoaded) {
+ listView.setVisibility(View.GONE);
+ txtvEmpty.setVisibility(View.GONE);
+ progLoading.setVisibility(View.VISIBLE);
+ }
+ }
+
+ @Override
+ protected Object[] doInBackground(Void... params) {
+ Context context = activity.get();
+ if (context != null) {
+ return new Object[]{DBReader.getUnreadItemsList(context),
+ DBReader.getRecentlyPublishedEpisodes(context, RECENT_EPISODES_LIMIT),
+ QueueAccess.IDListAccess(DBReader.getQueueIDList(context))};
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ protected void onPostExecute(Object[] lists) {
+ super.onPostExecute(lists);
+ listView.setVisibility(View.VISIBLE);
+ progLoading.setVisibility(View.GONE);
+
+ if (lists != null) {
+ unreadItems = (List<FeedItem>) lists[0];
+ recentItems = (List<FeedItem>) lists[1];
+ queueAccess = (QueueAccess) lists[2];
+ itemsLoaded = true;
+ if (viewsCreated && activity.get() != null) {
+ onFragmentLoaded();
+ }
+ }
+ }
+ }
+}
diff --git a/src/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java b/src/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java
index d6524853f..6369a51c1 100644
--- a/src/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java
+++ b/src/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java
@@ -1,112 +1,279 @@
package de.danoeh.antennapod.fragment;
+import android.app.Activity;
import android.content.Context;
+import android.content.res.TypedArray;
import android.os.AsyncTask;
import android.os.Bundle;
-import android.util.Log;
-import de.danoeh.antennapod.BuildConfig;
+import android.os.Handler;
+import android.support.v4.app.ListFragment;
+import android.support.v4.view.MenuItemCompat;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.ListView;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.adapter.ActionButtonCallback;
+import de.danoeh.antennapod.adapter.DefaultActionButtonCallback;
import de.danoeh.antennapod.adapter.InternalFeedItemlistAdapter;
+import de.danoeh.antennapod.asynctask.DownloadObserver;
+import de.danoeh.antennapod.dialog.FeedItemDialog;
import de.danoeh.antennapod.feed.EventDistributor;
import de.danoeh.antennapod.feed.FeedItem;
+import de.danoeh.antennapod.feed.FeedMedia;
+import de.danoeh.antennapod.service.download.Downloader;
import de.danoeh.antennapod.storage.DBReader;
+import de.danoeh.antennapod.storage.DBWriter;
+import de.danoeh.antennapod.util.QueueAccess;
import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
-public class PlaybackHistoryFragment extends ItemlistFragment {
- private static final String TAG = "PlaybackHistoryFragment";
+public class PlaybackHistoryFragment extends ListFragment {
+ private static final String TAG = "PlaybackHistoryFragment";
private List<FeedItem> playbackHistory;
+ private QueueAccess queue;
+ private InternalFeedItemlistAdapter adapter;
- public PlaybackHistoryFragment() {
- super(true);
- }
+ private boolean itemsLoaded = false;
+ private boolean viewsCreated = false;
+
+ private AtomicReference<Activity> activity = new AtomicReference<Activity>();
+
+ private DownloadObserver downloadObserver;
+ private List<Downloader> downloaderList;
+
+ private FeedItemDialog feedItemDialog;
- InternalFeedItemlistAdapter.ItemAccess itemAccessRef;
@Override
- protected InternalFeedItemlistAdapter.ItemAccess itemAccess() {
- if (itemAccessRef == null) {
- itemAccessRef = new InternalFeedItemlistAdapter.ItemAccess() {
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setRetainInstance(true);
+ setHasOptionsMenu(true);
+ }
- @Override
- public FeedItem getItem(int position) {
- return (playbackHistory != null) ? playbackHistory.get(position) : null;
- }
+ @Override
+ public void onResume() {
+ super.onResume();
+ startItemLoader();
+ }
- @Override
- public int getCount() {
- return (playbackHistory != null) ? playbackHistory.size() : 0;
- }
+ @Override
+ public void onStart() {
+ super.onStart();
+ EventDistributor.getInstance().register(contentUpdate);
+ }
- @Override
- public boolean isInQueue(FeedItem item) {
- return (queue != null) ? queue.contains(item.getId()) : false;
- }
- };
+ @Override
+ public void onStop() {
+ super.onStop();
+ EventDistributor.getInstance().unregister(contentUpdate);
+ stopItemLoader();
+ }
+
+ @Override
+ public void onDetach() {
+ super.onDetach();
+ stopItemLoader();
+ activity.set(null);
+ }
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ this.activity.set(activity);
+ if (downloadObserver != null) {
+ downloadObserver.setActivity(activity);
+ downloadObserver.onResume();
+ }
+ if (viewsCreated && itemsLoaded) {
+ onFragmentLoaded();
}
- return itemAccessRef;
}
@Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- EventDistributor.getInstance().register(historyUpdate);
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- EventDistributor.getInstance().unregister(historyUpdate);
- }
-
- private EventDistributor.EventListener historyUpdate = new EventDistributor.EventListener() {
-
- @Override
- public void update(EventDistributor eventDistributor, Integer arg) {
- if ((EventDistributor.PLAYBACK_HISTORY_UPDATE & arg) != 0) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Received content update");
- loadData();
- }
-
- }
- };
+ public void onDestroyView() {
+ super.onDestroyView();
+ adapter = null;
+ viewsCreated = false;
+ if (downloadObserver != null) {
+ downloadObserver.onPause();
+ }
+ feedItemDialog = null;
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ viewsCreated = true;
+ if (itemsLoaded) {
+ onFragmentLoaded();
+ }
+ }
@Override
- protected void loadData() {
- AsyncTask<Void, Void, Void> loadTask = new AsyncTask<Void, Void, Void>() {
- private volatile List<FeedItem> phRef;
- private volatile List<Long> queueRef;
-
- @Override
- protected Void doInBackground(Void... voids) {
- Context context = PlaybackHistoryFragment.this.getActivity();
- if (context != null) {
- queueRef = DBReader.getQueueIDList(context);
- phRef = DBReader.getPlaybackHistory(context);
+ public void onListItemClick(ListView l, View v, int position, long id) {
+ super.onListItemClick(l, v, position, id);
+ FeedItem item = adapter.getItem(position - l.getHeaderViewsCount());
+ if (item != null) {
+ feedItemDialog = FeedItemDialog.newInstace(activity.get(), item, queue);
+ feedItemDialog.show();
+ }
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ super.onCreateOptionsMenu(menu, inflater);
+ MenuItem clearHistory = menu.add(Menu.NONE, R.id.clear_history_item, Menu.CATEGORY_CONTAINER, R.string.clear_history_label);
+ MenuItemCompat.setShowAsAction(clearHistory, MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);
+ TypedArray drawables = getActivity().obtainStyledAttributes(new int[] {R.attr.content_discard});
+ clearHistory.setIcon(drawables.getDrawable(0));
+ drawables.recycle();
+ }
+
+ @Override
+ public void onPrepareOptionsMenu(Menu menu) {
+ super.onPrepareOptionsMenu(menu);
+ menu.findItem(R.id.clear_history_item).setVisible(playbackHistory != null && !playbackHistory.isEmpty());
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (!super.onOptionsItemSelected(item)) {
+ switch(item.getItemId()) {
+ case R.id.clear_history_item:
+ DBWriter.clearPlaybackHistory(getActivity());
+ return true;
+ default:
+ return false;
+ }
+ } else {
+ return true;
+ }
+ }
+
+ private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
+
+ @Override
+ public void update(EventDistributor eventDistributor, Integer arg) {
+ if ((arg & EventDistributor.PLAYBACK_HISTORY_UPDATE) != 0) {
+ startItemLoader();
+ getActivity().supportInvalidateOptionsMenu();
+ }
+ }
+ };
+
+ private void onFragmentLoaded() {
+ if (adapter == null) {
+ adapter = new InternalFeedItemlistAdapter(getActivity(), itemAccess, new DefaultActionButtonCallback(activity.get()), true);
+ setListAdapter(adapter);
+ downloadObserver = new DownloadObserver(activity.get(), new Handler(), downloadObserverCallback);
+ downloadObserver.onResume();
+ }
+ setListShown(true);
+ adapter.notifyDataSetChanged();
+ if (feedItemDialog != null && feedItemDialog.isShowing()) {
+ feedItemDialog.setItemFromCollection(playbackHistory);
+ feedItemDialog.setQueue(queue);
+ feedItemDialog.updateMenuAppearance();
+ }
+ getActivity().supportInvalidateOptionsMenu();
+ }
+
+ private DownloadObserver.Callback downloadObserverCallback = new DownloadObserver.Callback() {
+ @Override
+ public void onContentChanged() {
+ if (adapter != null) {
+ adapter.notifyDataSetChanged();
+ }
+ if (feedItemDialog != null && feedItemDialog.isShowing()) {
+ feedItemDialog.updateMenuAppearance();
+ }
+ }
+
+ @Override
+ public void onDownloadDataAvailable(List<Downloader> downloaderList) {
+ PlaybackHistoryFragment.this.downloaderList = downloaderList;
+ if (adapter != null) {
+ adapter.notifyDataSetChanged();
+ }
+ }
+ };
+
+ private InternalFeedItemlistAdapter.ItemAccess itemAccess = new InternalFeedItemlistAdapter.ItemAccess() {
+ @Override
+ public boolean isInQueue(FeedItem item) {
+ return (queue != null) ? queue.contains(item.getId()) : false;
+ }
+
+ @Override
+ public int getItemDownloadProgressPercent(FeedItem item) {
+ if (downloaderList != null) {
+ for (Downloader downloader : downloaderList) {
+ if (downloader.getDownloadRequest().getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA
+ && downloader.getDownloadRequest().getFeedfileId() == item.getMedia().getId()) {
+ return downloader.getDownloadRequest().getProgressPercent();
+ }
}
+ }
+ return 0;
+ }
+
+ @Override
+ public int getCount() {
+ return (playbackHistory != null) ? playbackHistory.size() : 0;
+ }
+
+ @Override
+ public FeedItem getItem(int position) {
+ return (playbackHistory != null) ? playbackHistory.get(position) : null;
+ }
+ };
+
+ private ItemLoader itemLoader;
+
+ private void startItemLoader() {
+ if (itemLoader != null) {
+ itemLoader.cancel(true);
+ }
+ itemLoader = new ItemLoader();
+ itemLoader.execute();
+ }
+
+ private void stopItemLoader() {
+ if (itemLoader != null) {
+ itemLoader.cancel(true);
+ }
+ }
+
+ private class ItemLoader extends AsyncTask<Void, Void, Object[]> {
+
+ @Override
+ protected Object[] doInBackground(Void... params) {
+ Context context = activity.get();
+ if (context != null) {
+ List<FeedItem> ph = DBReader.getPlaybackHistory(context);
+ DBReader.loadFeedDataOfFeedItemlist(context, ph);
+ return new Object[]{ph,
+ QueueAccess.IDListAccess(DBReader.getQueueIDList(context))};
+ } else {
return null;
}
+ }
- @Override
- protected void onPostExecute(Void aVoid) {
- super.onPostExecute(aVoid);
- if (queueRef != null && phRef != null) {
- queue = queueRef;
- playbackHistory = phRef;
- Log.i(TAG, "Number of items in playback history: " + playbackHistory.size());
- if (fila != null) {
- fila.notifyDataSetChanged();
- }
- } else {
- if (queueRef == null) {
- Log.e(TAG, "Could not load queue");
- }
- if (phRef == null) {
- Log.e(TAG, "Could not load playback history");
- }
+ @Override
+ protected void onPostExecute(Object[] res) {
+ super.onPostExecute(res);
+ if (res != null) {
+ playbackHistory = (List<FeedItem>) res[0];
+ queue = (QueueAccess) res[1];
+ itemsLoaded = true;
+ if (viewsCreated) {
+ onFragmentLoaded();
}
}
- };
- loadTask.execute();
+ }
}
}
diff --git a/src/de/danoeh/antennapod/fragment/QueueFragment.java b/src/de/danoeh/antennapod/fragment/QueueFragment.java
new file mode 100644
index 000000000..086e8f062
--- /dev/null
+++ b/src/de/danoeh/antennapod/fragment/QueueFragment.java
@@ -0,0 +1,349 @@
+package de.danoeh.antennapod.fragment;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Parcelable;
+import android.support.v4.app.Fragment;
+import android.support.v4.view.MenuItemCompat;
+import android.support.v7.widget.SearchView;
+import android.util.Log;
+import android.view.*;
+import android.widget.AdapterView;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+import com.mobeta.android.dslv.DragSortListView;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.MainActivity;
+import de.danoeh.antennapod.adapter.DefaultActionButtonCallback;
+import de.danoeh.antennapod.adapter.QueueListAdapter;
+import de.danoeh.antennapod.asynctask.DownloadObserver;
+import de.danoeh.antennapod.dialog.FeedItemDialog;
+import de.danoeh.antennapod.feed.EventDistributor;
+import de.danoeh.antennapod.feed.FeedItem;
+import de.danoeh.antennapod.feed.FeedMedia;
+import de.danoeh.antennapod.service.download.Downloader;
+import de.danoeh.antennapod.storage.DBReader;
+import de.danoeh.antennapod.storage.DBWriter;
+import de.danoeh.antennapod.util.QueueAccess;
+import de.danoeh.antennapod.util.UndoBarController;
+import de.danoeh.antennapod.util.gui.FeedItemUndoToken;
+import de.danoeh.antennapod.util.menuhandler.MenuItemUtils;
+
+import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * Shows all items in the queue
+ */
+public class QueueFragment extends Fragment {
+ private static final String TAG = "QueueFragment";
+ private static final int EVENTS = EventDistributor.DOWNLOAD_HANDLED |
+ EventDistributor.DOWNLOAD_QUEUED |
+ EventDistributor.QUEUE_UPDATE;
+
+ private DragSortListView listView;
+ private QueueListAdapter listAdapter;
+ private TextView txtvEmpty;
+ private ProgressBar progLoading;
+ private UndoBarController undoBarController;
+
+ private List<FeedItem> queue;
+ private List<Downloader> downloaderList;
+
+ private boolean itemsLoaded = false;
+ private boolean viewsCreated = false;
+
+ private AtomicReference<Activity> activity = new AtomicReference<Activity>();
+
+ private DownloadObserver downloadObserver = null;
+
+ private FeedItemDialog feedItemDialog;
+
+ /**
+ * Download observer updates won't result in an upate of the list adapter if this is true.
+ */
+ private boolean blockDownloadObserverUpdate = false;
+
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setRetainInstance(true);
+ setHasOptionsMenu(true);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ startItemLoader();
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ EventDistributor.getInstance().register(contentUpdate);
+ this.activity.set((MainActivity) getActivity());
+ if (downloadObserver != null) {
+ downloadObserver.setActivity(getActivity());
+ downloadObserver.onResume();
+ }
+ if (viewsCreated && itemsLoaded) {
+ onFragmentLoaded();
+ }
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ EventDistributor.getInstance().unregister(contentUpdate);
+ stopItemLoader();
+ }
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ this.activity.set((MainActivity) activity);
+ }
+
+ private void resetViewState() {
+ listAdapter = null;
+ undoBarController = null;
+ activity.set(null);
+ viewsCreated = false;
+ blockDownloadObserverUpdate = false;
+ if (downloadObserver != null) {
+ downloadObserver.onPause();
+ }
+ feedItemDialog = null;
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ resetViewState();
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ super.onCreateOptionsMenu(menu, inflater);
+ final SearchView sv = new SearchView(getActivity());
+ MenuItemUtils.addSearchItem(menu, sv);
+ sv.setQueryHint(getString(R.string.search_hint));
+ sv.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
+ @Override
+ public boolean onQueryTextSubmit(String s) {
+ sv.clearFocus();
+ ((MainActivity) getActivity()).loadChildFragment(SearchFragment.newInstance(s));
+ return true;
+ }
+
+ @Override
+ public boolean onQueryTextChange(String s) {
+ return false;
+ }
+ });
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ super.onCreateView(inflater, container, savedInstanceState);
+ ((MainActivity) getActivity()).getSupportActionBar().setTitle(R.string.queue_label);
+
+ View root = inflater.inflate(R.layout.queue_fragment, container, false);
+ listView = (DragSortListView) root.findViewById(android.R.id.list);
+ txtvEmpty = (TextView) root.findViewById(android.R.id.empty);
+ progLoading = (ProgressBar) root.findViewById(R.id.progLoading);
+ listView.setEmptyView(txtvEmpty);
+
+ listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ FeedItem item = (FeedItem) listAdapter.getItem(position - listView.getHeaderViewsCount());
+ if (item != null) {
+ feedItemDialog = FeedItemDialog.newInstace(activity.get(), item, QueueAccess.ItemListAccess(queue));
+ feedItemDialog.show();
+ }
+ }
+ });
+
+ undoBarController = new UndoBarController(root.findViewById(R.id.undobar), new UndoBarController.UndoListener() {
+ @Override
+ public void onUndo(Parcelable token) {
+ // Perform the undo
+ FeedItemUndoToken undoToken = (FeedItemUndoToken) token;
+ if (token != null) {
+ long itemId = undoToken.getFeedItemId();
+ int position = undoToken.getPosition();
+ DBWriter.addQueueItemAt(getActivity(), itemId, position, false);
+ }
+ }
+ });
+
+ listView.setDragSortListener(new DragSortListView.DragSortListener() {
+ @Override
+ public void drag(int from, int to) {
+ Log.d(TAG, "drag");
+ blockDownloadObserverUpdate = true;
+ }
+
+ @Override
+ public void drop(int from, int to) {
+ Log.d(TAG, "drop");
+ blockDownloadObserverUpdate = false;
+ stopItemLoader();
+ final FeedItem item = queue.remove(from);
+ queue.add(to, item);
+ listAdapter.notifyDataSetChanged();
+ DBWriter.moveQueueItem(getActivity(), from, to, true);
+ }
+
+ @Override
+ public void remove(int which) {
+ stopItemLoader();
+ FeedItem item = (FeedItem) listView.getAdapter().getItem(which);
+ DBWriter.removeQueueItem(getActivity(), item.getId(), true);
+ undoBarController.showUndoBar(false,
+ getString(R.string.removed_from_queue), new FeedItemUndoToken(item,
+ which)
+ );
+ }
+ });
+
+ if (!itemsLoaded) {
+ progLoading.setVisibility(View.VISIBLE);
+ txtvEmpty.setVisibility(View.GONE);
+ }
+
+ viewsCreated = true;
+
+ if (itemsLoaded && activity.get() != null) {
+ onFragmentLoaded();
+ }
+
+ return root;
+ }
+
+ private void onFragmentLoaded() {
+ if (listAdapter == null) {
+ listAdapter = new QueueListAdapter(activity.get(), itemAccess, new DefaultActionButtonCallback(activity.get()));
+ listView.setAdapter(listAdapter);
+ downloadObserver = new DownloadObserver(activity.get(), new Handler(), downloadObserverCallback);
+ downloadObserver.onResume();
+ }
+ listAdapter.notifyDataSetChanged();
+ if (feedItemDialog != null && feedItemDialog.isShowing()) {
+ feedItemDialog.setQueue(QueueAccess.ItemListAccess(queue));
+ feedItemDialog.setItemFromCollection(queue);
+ feedItemDialog.updateMenuAppearance();
+ }
+ }
+
+ private DownloadObserver.Callback downloadObserverCallback = new DownloadObserver.Callback() {
+ @Override
+ public void onContentChanged() {
+ if (listAdapter != null && !blockDownloadObserverUpdate) {
+ listAdapter.notifyDataSetChanged();
+ }
+ if (feedItemDialog != null && feedItemDialog.isShowing()) {
+ feedItemDialog.updateMenuAppearance();
+ }
+ }
+
+ @Override
+ public void onDownloadDataAvailable(List<Downloader> downloaderList) {
+ QueueFragment.this.downloaderList = downloaderList;
+ if (listAdapter != null && !blockDownloadObserverUpdate) {
+ listAdapter.notifyDataSetChanged();
+ }
+ }
+ };
+
+ private QueueListAdapter.ItemAccess itemAccess = new QueueListAdapter.ItemAccess() {
+ @Override
+ public int getCount() {
+ return (itemsLoaded) ? queue.size() : 0;
+ }
+
+ @Override
+ public FeedItem getItem(int position) {
+ return (itemsLoaded) ? queue.get(position) : null;
+ }
+
+ @Override
+ public int getItemDownloadProgressPercent(FeedItem item) {
+ if (downloaderList != null) {
+ for (Downloader downloader : downloaderList) {
+ if (downloader.getDownloadRequest().getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA
+ && downloader.getDownloadRequest().getFeedfileId() == item.getMedia().getId()) {
+ return downloader.getDownloadRequest().getProgressPercent();
+ }
+ }
+ }
+ return 0;
+ }
+ };
+
+ private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
+ @Override
+ public void update(EventDistributor eventDistributor, Integer arg) {
+ if ((arg & EVENTS) != 0) {
+ startItemLoader();
+ }
+ }
+ };
+
+ private ItemLoader itemLoader;
+
+ private void startItemLoader() {
+ if (itemLoader != null) {
+ itemLoader.cancel(true);
+ }
+ itemLoader = new ItemLoader();
+ itemLoader.execute();
+ }
+
+ private void stopItemLoader() {
+ if (itemLoader != null) {
+ itemLoader.cancel(true);
+ }
+ }
+
+ private class ItemLoader extends AsyncTask<Void, Void, List<FeedItem>> {
+ @Override
+ protected void onPreExecute() {
+ super.onPreExecute();
+ if (viewsCreated && !itemsLoaded) {
+ listView.setVisibility(View.GONE);
+ txtvEmpty.setVisibility(View.GONE);
+ progLoading.setVisibility(View.VISIBLE);
+ }
+ }
+
+ @Override
+ protected void onPostExecute(List<FeedItem> feedItems) {
+ super.onPostExecute(feedItems);
+ listView.setVisibility(View.VISIBLE);
+ progLoading.setVisibility(View.GONE);
+
+ if (feedItems != null) {
+ queue = feedItems;
+ itemsLoaded = true;
+ if (viewsCreated && activity.get() != null) {
+ onFragmentLoaded();
+ }
+ }
+ }
+
+ @Override
+ protected List<FeedItem> doInBackground(Void... params) {
+ Context context = activity.get();
+ if (context != null) {
+ return DBReader.getQueue(context);
+ }
+ return null;
+ }
+ }
+}
diff --git a/src/de/danoeh/antennapod/fragment/RunningDownloadsFragment.java b/src/de/danoeh/antennapod/fragment/RunningDownloadsFragment.java
new file mode 100644
index 000000000..89c30e34b
--- /dev/null
+++ b/src/de/danoeh/antennapod/fragment/RunningDownloadsFragment.java
@@ -0,0 +1,69 @@
+package de.danoeh.antennapod.fragment;
+
+import android.os.Bundle;
+import android.os.Handler;
+import android.support.v4.app.ListFragment;
+import android.view.View;
+import de.danoeh.antennapod.adapter.DownloadlistAdapter;
+import de.danoeh.antennapod.asynctask.DownloadObserver;
+import de.danoeh.antennapod.service.download.Downloader;
+import de.danoeh.antennapod.storage.DownloadRequester;
+
+import java.util.List;
+
+/**
+ * Displays all running downloads and provides actions to cancel them
+ */
+public class RunningDownloadsFragment extends ListFragment {
+ private static final String TAG = "RunningDownloadsFragment";
+
+ private DownloadObserver downloadObserver;
+ private List<Downloader> downloaderList;
+
+
+ @Override
+ public void onDetach() {
+ super.onDetach();
+ if (downloadObserver != null) {
+ downloadObserver.onPause();
+ }
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ final DownloadlistAdapter downloadlistAdapter = new DownloadlistAdapter(getActivity(), itemAccess);
+ setListAdapter(downloadlistAdapter);
+
+ downloadObserver = new DownloadObserver(getActivity(), new Handler(), new DownloadObserver.Callback() {
+ @Override
+ public void onContentChanged() {
+ downloadlistAdapter.notifyDataSetChanged();
+ }
+
+ @Override
+ public void onDownloadDataAvailable(List<Downloader> downloaderList) {
+ RunningDownloadsFragment.this.downloaderList = downloaderList;
+ downloadlistAdapter.notifyDataSetChanged();
+ }
+ });
+ downloadObserver.onResume();
+ }
+
+ private DownloadlistAdapter.ItemAccess itemAccess = new DownloadlistAdapter.ItemAccess() {
+ @Override
+ public int getCount() {
+ return (downloaderList != null) ? downloaderList.size() : 0;
+ }
+
+ @Override
+ public Downloader getItem(int position) {
+ return (downloaderList != null) ? downloaderList.get(position) : null;
+ }
+
+ @Override
+ public void onSecondaryActionClick(Downloader downloader) {
+ DownloadRequester.getInstance().cancelDownload(getActivity(), downloader.getDownloadRequest().getSource());
+ }
+ };
+}
diff --git a/src/de/danoeh/antennapod/fragment/SearchFragment.java b/src/de/danoeh/antennapod/fragment/SearchFragment.java
new file mode 100644
index 000000000..566695465
--- /dev/null
+++ b/src/de/danoeh/antennapod/fragment/SearchFragment.java
@@ -0,0 +1,247 @@
+package de.danoeh.antennapod.fragment;
+
+import android.content.Context;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.support.v4.app.ListFragment;
+import android.support.v4.view.MenuItemCompat;
+import android.support.v7.app.ActionBarActivity;
+import android.support.v7.widget.SearchView;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.ListView;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.MainActivity;
+import de.danoeh.antennapod.adapter.SearchlistAdapter;
+import de.danoeh.antennapod.dialog.FeedItemDialog;
+import de.danoeh.antennapod.feed.*;
+import de.danoeh.antennapod.storage.DBReader;
+import de.danoeh.antennapod.storage.FeedSearcher;
+import de.danoeh.antennapod.util.QueueAccess;
+
+import java.util.List;
+
+/**
+ * Performs a search operation on all feeds or one specific feed and displays the search result.
+ */
+public class SearchFragment extends ListFragment {
+ private static final String TAG = "SearchFragment";
+
+ private static final String ARG_QUERY = "query";
+ private static final String ARG_FEED = "feed";
+
+ private SearchlistAdapter searchAdapter;
+ private List<SearchResult> searchResults;
+
+ private boolean viewCreated = false;
+ private boolean itemsLoaded = false;
+
+ private QueueAccess queue;
+
+ private FeedItemDialog feedItemDialog;
+
+ /**
+ * Create a new SearchFragment that searches all feeds.
+ */
+ public static SearchFragment newInstance(String query) {
+ if (query == null) query = "";
+ SearchFragment fragment = new SearchFragment();
+ Bundle args = new Bundle();
+ args.putString(ARG_QUERY, query);
+ args.putLong(ARG_FEED, 0);
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ /**
+ * Create a new SearchFragment that searches one specific feed.
+ */
+ public static SearchFragment newInstance(String query, long feed) {
+ SearchFragment fragment = newInstance(query);
+ fragment.getArguments().putLong(ARG_FEED, feed);
+ return fragment;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setRetainInstance(true);
+ setHasOptionsMenu(true);
+ startSearchTask();
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ EventDistributor.getInstance().register(contentUpdate);
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ stopSearchTask();
+ EventDistributor.getInstance().unregister(contentUpdate);
+ }
+
+ @Override
+ public void onDetach() {
+ super.onDetach();
+ stopSearchTask();
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ searchAdapter = null;
+ viewCreated = false;
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ ((ActionBarActivity) getActivity()).getSupportActionBar().setTitle(R.string.search_label);
+ viewCreated = true;
+ if (itemsLoaded) {
+ onFragmentLoaded();
+ }
+ }
+
+ @Override
+ public void onListItemClick(ListView l, View v, int position, long id) {
+ super.onListItemClick(l, v, position, id);
+ SearchResult result = (SearchResult) l.getAdapter().getItem(position);
+ FeedComponent comp = result.getComponent();
+ if (comp.getClass() == Feed.class) {
+ ((MainActivity)getActivity()).loadFeedFragment(comp.getId());
+ } else {
+ if (comp.getClass() == FeedItem.class) {
+ feedItemDialog = FeedItemDialog.newInstace(getActivity(), (FeedItem) comp, queue);
+ feedItemDialog.show();
+ }
+ }
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ super.onCreateOptionsMenu(menu, inflater);
+ MenuItem item = menu.add(Menu.NONE, R.id.search_item, Menu.NONE, R.string.search_label);
+ MenuItemCompat.setShowAsAction(item, MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);
+ final SearchView sv = new SearchView(getActivity());
+ sv.setQueryHint(getString(R.string.search_hint));
+ sv.setQuery(getArguments().getString(ARG_QUERY), false);
+ sv.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
+ @Override
+ public boolean onQueryTextSubmit(String s) {
+ getArguments().putString(ARG_QUERY, s);
+ itemsLoaded = false;
+ startSearchTask();
+ return true;
+ }
+
+ @Override
+ public boolean onQueryTextChange(String s) {
+ return false;
+ }
+ });
+ MenuItemCompat.setActionView(item, sv);
+ }
+
+ private final EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
+ @Override
+ public void update(EventDistributor eventDistributor, Integer arg) {
+ if ((arg & (EventDistributor.DOWNLOAD_QUEUED)) != 0) {
+ feedItemDialog.updateMenuAppearance();
+ }
+ if ((arg & (EventDistributor.UNREAD_ITEMS_UPDATE
+ | EventDistributor.DOWNLOAD_HANDLED
+ | EventDistributor.QUEUE_UPDATE)) != 0) {
+ startSearchTask();
+ }
+ }
+ };
+
+ private void onFragmentLoaded() {
+ if (searchAdapter == null) {
+ searchAdapter = new SearchlistAdapter(getActivity(), itemAccess);
+ setListAdapter(searchAdapter);
+ }
+ searchAdapter.notifyDataSetChanged();
+ setListShown(true);
+ if (feedItemDialog != null && feedItemDialog.isShowing()) {
+ feedItemDialog.setQueue(queue);
+ for (SearchResult result : searchResults) {
+ FeedComponent comp = result.getComponent();
+ if (comp.getClass() == FeedItem.class && ((FeedItem) comp).getId() == feedItemDialog.getItem().getId()) {
+ feedItemDialog.setItem((FeedItem) comp);
+ }
+ }
+ feedItemDialog.updateMenuAppearance();
+ }
+ }
+
+ private final SearchlistAdapter.ItemAccess itemAccess = new SearchlistAdapter.ItemAccess() {
+ @Override
+ public int getCount() {
+ return (searchResults != null) ? searchResults.size() : 0;
+ }
+
+ @Override
+ public SearchResult getItem(int position) {
+ return (searchResults != null) ? searchResults.get(position) : null;
+ }
+ };
+
+ private SearchTask searchTask;
+
+ private void startSearchTask() {
+ if (searchTask != null) {
+ searchTask.cancel(true);
+ }
+ searchTask = new SearchTask();
+ searchTask.execute(getArguments());
+ }
+
+ private void stopSearchTask() {
+ if (searchTask != null) {
+ searchTask.cancel(true);
+ }
+ }
+
+ private class SearchTask extends AsyncTask<Bundle, Void, Object[]> {
+ @Override
+ protected Object[] doInBackground(Bundle... params) {
+ String query = params[0].getString(ARG_QUERY);
+ long feed = params[0].getLong(ARG_FEED);
+ Context context = getActivity();
+ if (context != null) {
+ return new Object[]{FeedSearcher.performSearch(context, query, feed),
+ QueueAccess.IDListAccess(DBReader.getQueueIDList(context))};
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ protected void onPreExecute() {
+ super.onPreExecute();
+ if (viewCreated && !itemsLoaded) {
+ setListShown(false);
+ }
+ }
+
+ @Override
+ protected void onPostExecute(Object[] results) {
+ super.onPostExecute(results);
+ if (results != null) {
+ itemsLoaded = true;
+ searchResults = (List<SearchResult>) results[0];
+ queue = (QueueAccess) results[1];
+ if (viewCreated) {
+ onFragmentLoaded();
+ }
+ }
+ }
+ }
+}
diff --git a/src/de/danoeh/antennapod/fragment/gpodnet/GpodnetMainFragment.java b/src/de/danoeh/antennapod/fragment/gpodnet/GpodnetMainFragment.java
new file mode 100644
index 000000000..ec8f69368
--- /dev/null
+++ b/src/de/danoeh/antennapod/fragment/gpodnet/GpodnetMainFragment.java
@@ -0,0 +1,131 @@
+package de.danoeh.antennapod.fragment.gpodnet;
+
+import android.app.Activity;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentPagerAdapter;
+import android.support.v4.app.FragmentTransaction;
+import android.support.v4.view.ViewPager;
+import android.support.v7.app.ActionBar;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.MainActivity;
+
+/**
+ * Main navigation hub for gpodder.net podcast directory
+ */
+public class GpodnetMainFragment extends Fragment {
+
+ private ViewPager pager;
+ private MainActivity activity;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ super.onCreateView(inflater, container, savedInstanceState);
+ View root = inflater.inflate(R.layout.pager_fragment, container, false);
+ pager = (ViewPager) root.findViewById(R.id.pager);
+ GpodnetPagerAdapter pagerAdapter = new GpodnetPagerAdapter(getChildFragmentManager(), getResources());
+ pager.setAdapter(pagerAdapter);
+ final ActionBar actionBar = activity.getMainActivtyActionBar();
+ actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
+ ActionBar.TabListener tabListener = new ActionBar.TabListener() {
+ @Override
+ public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
+ pager.setCurrentItem(tab.getPosition());
+ }
+
+ @Override
+ public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
+
+ }
+
+ @Override
+ public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
+
+ }
+ };
+ actionBar.removeAllTabs();
+ actionBar.addTab(actionBar.newTab()
+ .setText(R.string.gpodnet_taglist_header)
+ .setTabListener(tabListener));
+ actionBar.addTab(actionBar.newTab()
+ .setText(R.string.gpodnet_toplist_header)
+ .setTabListener(tabListener));
+ actionBar.setTitle(R.string.gpodnet_main_label);
+
+ pager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
+ @Override
+ public void onPageSelected(int position) {
+ super.onPageSelected(position);
+ actionBar.setSelectedNavigationItem(position);
+ }
+ });
+ return root;
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ activity.getMainActivtyActionBar().removeAllTabs();
+ activity.getMainActivtyActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
+ }
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ this.activity = (MainActivity) activity;
+ }
+
+ public class GpodnetPagerAdapter extends FragmentPagerAdapter {
+
+
+ private static final int NUM_PAGES = 2;
+ private static final int POS_TAGS = 0;
+ private static final int POS_TOPLIST = 1;
+ private static final int POS_SUGGESTIONS = 2;
+
+ Resources resources;
+
+ public GpodnetPagerAdapter(FragmentManager fm, Resources resources) {
+ super(fm);
+ this.resources = resources;
+ }
+
+ @Override
+ public Fragment getItem(int i) {
+ switch (i) {
+ case POS_TAGS:
+ return new TagListFragment();
+ case POS_TOPLIST:
+ return new PodcastTopListFragment();
+ case POS_SUGGESTIONS:
+ return new SuggestionListFragment();
+ default:
+ return null;
+ }
+ }
+
+ @Override
+ public CharSequence getPageTitle(int position) {
+ switch (position) {
+ case POS_TAGS:
+ return getString(R.string.gpodnet_taglist_header);
+ case POS_TOPLIST:
+ return getString(R.string.gpodnet_toplist_header);
+ case POS_SUGGESTIONS:
+ return getString(R.string.gpodnet_suggestions_header);
+ default:
+ return super.getPageTitle(position);
+ }
+ }
+
+ @Override
+ public int getCount() {
+ return NUM_PAGES;
+ }
+ }
+}
diff --git a/src/de/danoeh/antennapod/fragment/gpodnet/PodcastListFragment.java b/src/de/danoeh/antennapod/fragment/gpodnet/PodcastListFragment.java
index 4164429b2..837df0594 100644
--- a/src/de/danoeh/antennapod/fragment/gpodnet/PodcastListFragment.java
+++ b/src/de/danoeh/antennapod/fragment/gpodnet/PodcastListFragment.java
@@ -5,19 +5,22 @@ import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.Fragment;
+import android.support.v7.widget.*;
import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
+import android.view.*;
import android.widget.*;
+import android.widget.SearchView;
import de.danoeh.antennapod.BuildConfig;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.DefaultOnlineFeedViewActivity;
+import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.activity.OnlineFeedViewActivity;
import de.danoeh.antennapod.adapter.gpodnet.PodcastListAdapter;
+import de.danoeh.antennapod.fragment.SearchFragment;
import de.danoeh.antennapod.gpoddernet.GpodnetService;
import de.danoeh.antennapod.gpoddernet.GpodnetServiceException;
import de.danoeh.antennapod.gpoddernet.model.GpodnetPodcast;
+import de.danoeh.antennapod.util.menuhandler.MenuItemUtils;
import java.util.List;
@@ -33,8 +36,34 @@ public abstract class PodcastListFragment extends Fragment {
private Button butRetry;
@Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setHasOptionsMenu(true);
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ super.onCreateOptionsMenu(menu, inflater);
+ final android.support.v7.widget.SearchView sv = new android.support.v7.widget.SearchView(getActivity());
+ MenuItemUtils.addSearchItem(menu, sv);
+ sv.setQueryHint(getString(R.string.gpodnet_search_hint));
+ sv.setOnQueryTextListener(new android.support.v7.widget.SearchView.OnQueryTextListener() {
+ @Override
+ public boolean onQueryTextSubmit(String s) {
+ sv.clearFocus();
+ ((MainActivity) getActivity()).loadChildFragment(SearchListFragment.newInstance(s));
+ return true;
+ }
+
+ @Override
+ public boolean onQueryTextChange(String s) {
+ return false;
+ }
+ });
+ }
+
+ @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- setRetainInstance(true);
View root = inflater.inflate(R.layout.gpodnet_podcast_list, container, false);
gridView = (GridView) root.findViewById(R.id.gridView);
diff --git a/src/de/danoeh/antennapod/fragment/gpodnet/SearchListFragment.java b/src/de/danoeh/antennapod/fragment/gpodnet/SearchListFragment.java
index 322d13097..79d0c5d6f 100644
--- a/src/de/danoeh/antennapod/fragment/gpodnet/SearchListFragment.java
+++ b/src/de/danoeh/antennapod/fragment/gpodnet/SearchListFragment.java
@@ -1,14 +1,21 @@
package de.danoeh.antennapod.fragment.gpodnet;
import android.os.Bundle;
+import android.support.v7.widget.SearchView;
+import android.view.Menu;
+import android.view.MenuInflater;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.MainActivity;
+import de.danoeh.antennapod.fragment.SearchFragment;
import de.danoeh.antennapod.gpoddernet.GpodnetService;
import de.danoeh.antennapod.gpoddernet.GpodnetServiceException;
import de.danoeh.antennapod.gpoddernet.model.GpodnetPodcast;
+import de.danoeh.antennapod.util.menuhandler.MenuItemUtils;
import java.util.List;
/**
- * Created by daniel on 23.08.13.
+ * Performs a search on the gpodder.net directory and displays the results.
*/
public class SearchListFragment extends PodcastListFragment {
private static final String ARG_QUERY = "query";
@@ -26,6 +33,7 @@ public class SearchListFragment extends PodcastListFragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+
if (getArguments() != null && getArguments().containsKey(ARG_QUERY)) {
this.query = getArguments().getString(ARG_QUERY);
} else {
@@ -34,6 +42,27 @@ public class SearchListFragment extends PodcastListFragment {
}
@Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ final SearchView sv = new SearchView(getActivity());
+ MenuItemUtils.addSearchItem(menu, sv);
+ sv.setQueryHint(getString(R.string.gpodnet_search_hint));
+ sv.setQuery(query, false);
+ sv.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
+ @Override
+ public boolean onQueryTextSubmit(String s) {
+ sv.clearFocus();
+ changeQuery(s);
+ return true;
+ }
+
+ @Override
+ public boolean onQueryTextChange(String s) {
+ return false;
+ }
+ });
+ }
+
+ @Override
protected List<GpodnetPodcast> loadPodcastData(GpodnetService service) throws GpodnetServiceException {
return service.searchPodcasts(query, 0);
}
diff --git a/src/de/danoeh/antennapod/fragment/gpodnet/TagFragment.java b/src/de/danoeh/antennapod/fragment/gpodnet/TagFragment.java
new file mode 100644
index 000000000..f016290bf
--- /dev/null
+++ b/src/de/danoeh/antennapod/fragment/gpodnet/TagFragment.java
@@ -0,0 +1,47 @@
+package de.danoeh.antennapod.fragment.gpodnet;
+
+import android.os.Bundle;
+import de.danoeh.antennapod.activity.MainActivity;
+import de.danoeh.antennapod.gpoddernet.GpodnetService;
+import de.danoeh.antennapod.gpoddernet.GpodnetServiceException;
+import de.danoeh.antennapod.gpoddernet.model.GpodnetPodcast;
+import de.danoeh.antennapod.gpoddernet.model.GpodnetTag;
+
+import java.util.List;
+
+/**
+ * Shows all podcasts from gpodder.net that belong to a specific tag.
+ * Use the newInstance method of this class to create a new TagFragment.
+ */
+public class TagFragment extends PodcastListFragment {
+
+ private static final String TAG = "TagFragment";
+ private static final int PODCAST_COUNT = 50;
+
+ private GpodnetTag tag;
+
+ public static TagFragment newInstance(String tagName) {
+ if (tagName == null) throw new IllegalArgumentException("tagName = null");
+ TagFragment fragment = new TagFragment();
+ Bundle args = new Bundle();
+ args.putString("tag", tagName);
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ Bundle args = getArguments();
+ if (args == null || args.getString("tag") == null) throw new IllegalArgumentException("args invalid");
+
+ tag = new GpodnetTag(args.getString("tag"));
+ ((MainActivity) getActivity()).getMainActivtyActionBar().setTitle(tag.getName());
+ }
+
+ @Override
+ protected List<GpodnetPodcast> loadPodcastData(GpodnetService service) throws GpodnetServiceException {
+ return service.getPodcastsForTag(tag, PODCAST_COUNT);
+ }
+}
diff --git a/src/de/danoeh/antennapod/fragment/gpodnet/TagListFragment.java b/src/de/danoeh/antennapod/fragment/gpodnet/TagListFragment.java
index fcb9d01c5..80e896c0f 100644
--- a/src/de/danoeh/antennapod/fragment/gpodnet/TagListFragment.java
+++ b/src/de/danoeh/antennapod/fragment/gpodnet/TagListFragment.java
@@ -1,18 +1,23 @@
package de.danoeh.antennapod.fragment.gpodnet;
import android.content.Context;
-import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.ListFragment;
+import android.support.v7.widget.SearchView;
+import android.view.Menu;
+import android.view.MenuInflater;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.TextView;
-import de.danoeh.antennapod.activity.gpoddernet.GpodnetTagActivity;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.MainActivity;
+import de.danoeh.antennapod.fragment.SearchFragment;
import de.danoeh.antennapod.gpoddernet.GpodnetService;
import de.danoeh.antennapod.gpoddernet.GpodnetServiceException;
import de.danoeh.antennapod.gpoddernet.model.GpodnetTag;
+import de.danoeh.antennapod.util.menuhandler.MenuItemUtils;
import java.util.ArrayList;
import java.util.List;
@@ -22,17 +27,42 @@ public class TagListFragment extends ListFragment {
private static final int COUNT = 50;
@Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setHasOptionsMenu(true);
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ super.onCreateOptionsMenu(menu, inflater);
+ final SearchView sv = new SearchView(getActivity());
+ MenuItemUtils.addSearchItem(menu, sv);
+ sv.setQueryHint(getString(R.string.search_hint));
+ sv.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
+ @Override
+ public boolean onQueryTextSubmit(String s) {
+ sv.clearFocus();
+ ((MainActivity) getActivity()).loadChildFragment(SearchFragment.newInstance(s));
+ return true;
+ }
+
+ @Override
+ public boolean onQueryTextChange(String s) {
+ return false;
+ }
+ });
+ }
+
+ @Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
- setRetainInstance(true);
getListView().setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
String selectedTag = (String) getListAdapter().getItem(position);
- Intent intent = new Intent(getActivity(), GpodnetTagActivity.class);
- intent.putExtra(GpodnetTagActivity.ARG_TAGNAME, selectedTag);
- startActivity(intent);
+ MainActivity activity = (MainActivity) getActivity();
+ activity.loadChildFragment(TagFragment.newInstance(selectedTag));
}
});
diff --git a/src/de/danoeh/antennapod/service/download/DownloadService.java b/src/de/danoeh/antennapod/service/download/DownloadService.java
index f5883babc..c7f3b8573 100644
--- a/src/de/danoeh/antennapod/service/download/DownloadService.java
+++ b/src/de/danoeh/antennapod/service/download/DownloadService.java
@@ -13,6 +13,7 @@ import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.media.MediaMetadataRetriever;
import android.os.Binder;
+import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.support.v4.app.NotificationCompat;
@@ -23,7 +24,10 @@ import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.DownloadActivity;
import de.danoeh.antennapod.activity.DownloadAuthenticationActivity;
import de.danoeh.antennapod.activity.DownloadLogActivity;
+import de.danoeh.antennapod.activity.MainActivity;
+import de.danoeh.antennapod.adapter.NavListAdapter;
import de.danoeh.antennapod.feed.*;
+import de.danoeh.antennapod.fragment.DownloadsFragment;
import de.danoeh.antennapod.storage.*;
import de.danoeh.antennapod.syndication.handler.FeedHandler;
import de.danoeh.antennapod.syndication.handler.UnsupportedFeedtypeException;
@@ -274,11 +278,18 @@ public class DownloadService extends Service {
@SuppressLint("NewApi")
private void setupNotificationBuilders() {
- PendingIntent pIntent = PendingIntent.getActivity(this, 0, new Intent(
- this, DownloadActivity.class),
+ Intent intent = new Intent(this, MainActivity.class);
+ intent.putExtra(MainActivity.EXTRA_NAV_TYPE, NavListAdapter.VIEW_TYPE_NAV);
+ intent.putExtra(MainActivity.EXTRA_NAV_INDEX, MainActivity.POS_DOWNLOADS);
+ Bundle args = new Bundle();
+ args.putInt(DownloadsFragment.ARG_SELECTED_TAB, DownloadsFragment.POS_RUNNING);
+ intent.putExtra(MainActivity.EXTRA_FRAGMENT_ARGS, args);
+
+ PendingIntent pIntent = PendingIntent.getActivity(this, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT
);
+
Bitmap icon = BitmapFactory.decodeResource(getResources(),
R.drawable.stat_notify_sync);
@@ -490,6 +501,13 @@ public class DownloadService extends Service {
if (createReport) {
if (BuildConfig.DEBUG)
Log.d(TAG, "Creating report");
+ Intent intent = new Intent(this, MainActivity.class);
+ intent.putExtra(MainActivity.EXTRA_NAV_TYPE, NavListAdapter.VIEW_TYPE_NAV);
+ intent.putExtra(MainActivity.EXTRA_NAV_INDEX, MainActivity.POS_DOWNLOADS);
+ Bundle args = new Bundle();
+ args.putInt(DownloadsFragment.ARG_SELECTED_TAB, DownloadsFragment.POS_LOG);
+ intent.putExtra(MainActivity.EXTRA_FRAGMENT_ARGS, args);
+
// create notification object
Notification notification = new NotificationCompat.Builder(this)
.setTicker(
@@ -507,8 +525,7 @@ public class DownloadService extends Service {
R.drawable.stat_notify_sync)
)
.setContentIntent(
- PendingIntent.getActivity(this, 0, new Intent(this,
- DownloadLogActivity.class), 0)
+ PendingIntent.getActivity(this, 0, intent, 0)
)
.setAutoCancel(true).getNotification();
NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
diff --git a/src/de/danoeh/antennapod/storage/DBReader.java b/src/de/danoeh/antennapod/storage/DBReader.java
index 8d4785bd4..859ff2473 100644
--- a/src/de/danoeh/antennapod/storage/DBReader.java
+++ b/src/de/danoeh/antennapod/storage/DBReader.java
@@ -504,6 +504,32 @@ public final class DBReader {
return itemIds;
}
+
+ /**
+ * Loads a list of FeedItems sorted by pubDate in descending order.
+ *
+ * @param context A context that is used for opening a database connection.
+ * @param limit The maximum number of episodes that should be loaded.
+ * */
+ public static List<FeedItem> getRecentlyPublishedEpisodes(Context context, int limit) {
+ if (BuildConfig.DEBUG)
+ Log.d(TAG, "Extracting recently published items list");
+
+ PodDBAdapter adapter = new PodDBAdapter(context);
+ adapter.open();
+
+ Cursor itemlistCursor = adapter.getRecentlyPublishedItemsCursor(limit);
+ List<FeedItem> items = extractItemlistFromCursor(adapter,
+ itemlistCursor);
+ itemlistCursor.close();
+
+ loadFeedDataOfFeedItemlist(context, items);
+
+ adapter.close();
+
+ return items;
+ }
+
/**
* Loads the playback history from the database. A FeedItem is in the playback history if playback of the correpsonding episode
* has been completed at least once.
diff --git a/src/de/danoeh/antennapod/storage/PodDBAdapter.java b/src/de/danoeh/antennapod/storage/PodDBAdapter.java
index 8e2d10711..40a71a75d 100644
--- a/src/de/danoeh/antennapod/storage/PodDBAdapter.java
+++ b/src/de/danoeh/antennapod/storage/PodDBAdapter.java
@@ -999,6 +999,11 @@ public class PodDBAdapter {
}
+ public final Cursor getRecentlyPublishedItemsCursor(int limit) {
+ Cursor c = db.query(TABLE_NAME_FEED_ITEMS, FEEDITEM_SEL_FI_SMALL, null, null, null, null, KEY_PUBDATE + " DESC LIMIT " + limit);
+ return c;
+ }
+
public Cursor getDownloadedItemsCursor() {
final String query = "SELECT " + SEL_FI_SMALL_STR + " FROM " + TABLE_NAME_FEED_ITEMS
+ " INNER JOIN " + TABLE_NAME_FEED_MEDIA + " ON "
diff --git a/src/de/danoeh/antennapod/util/gui/FeedItemUndoToken.java b/src/de/danoeh/antennapod/util/gui/FeedItemUndoToken.java
new file mode 100644
index 000000000..b920559db
--- /dev/null
+++ b/src/de/danoeh/antennapod/util/gui/FeedItemUndoToken.java
@@ -0,0 +1,55 @@
+package de.danoeh.antennapod.util.gui;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import de.danoeh.antennapod.feed.FeedItem;
+
+/**
+ * Used by an UndoBarController for saving a removed FeedItem
+ */
+public class FeedItemUndoToken implements Parcelable {
+ private long itemId;
+ private long feedId;
+ private int position;
+
+ public FeedItemUndoToken(FeedItem item, int position) {
+ this.itemId = item.getId();
+ this.feedId = item.getFeed().getId();
+ this.position = position;
+ }
+
+ private FeedItemUndoToken(Parcel in) {
+ itemId = in.readLong();
+ feedId = in.readLong();
+ position = in.readInt();
+ }
+
+ public static final Parcelable.Creator<FeedItemUndoToken> CREATOR = new Parcelable.Creator<FeedItemUndoToken>() {
+ public FeedItemUndoToken createFromParcel(Parcel in) {
+ return new FeedItemUndoToken(in);
+ }
+
+ public FeedItemUndoToken[] newArray(int size) {
+ return new FeedItemUndoToken[size];
+ }
+ };
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeLong(itemId);
+ out.writeLong(feedId);
+ out.writeInt(position);
+ }
+
+ public long getFeedItemId() {
+ return itemId;
+ }
+
+ public int getPosition() {
+ return position;
+ }
+}
+
diff --git a/src/de/danoeh/antennapod/util/menuhandler/MenuItemUtils.java b/src/de/danoeh/antennapod/util/menuhandler/MenuItemUtils.java
new file mode 100644
index 000000000..e75fa394a
--- /dev/null
+++ b/src/de/danoeh/antennapod/util/menuhandler/MenuItemUtils.java
@@ -0,0 +1,20 @@
+package de.danoeh.antennapod.util.menuhandler;
+
+import android.support.v4.view.MenuItemCompat;
+import android.support.v7.widget.SearchView;
+import android.view.Menu;
+import android.view.MenuItem;
+import de.danoeh.antennapod.R;
+
+/**
+ * Utilities for menu items
+ */
+public class MenuItemUtils {
+
+ public static MenuItem addSearchItem(Menu menu, SearchView searchView) {
+ MenuItem item = menu.add(Menu.NONE, R.id.search_item, Menu.NONE, R.string.search_label);
+ MenuItemCompat.setShowAsAction(item, MenuItemCompat.SHOW_AS_ACTION_IF_ROOM);
+ MenuItemCompat.setActionView(item, searchView);
+ return item;
+ }
+}