summaryrefslogtreecommitdiff
path: root/app/src
diff options
context:
space:
mode:
Diffstat (limited to 'app/src')
-rw-r--r--app/src/androidTest/java/de/test/antennapod/service/download/HttpDownloaderTest.java11
-rw-r--r--app/src/androidTest/java/de/test/antennapod/ui/MainActivityTest.java31
-rw-r--r--app/src/androidTest/java/de/test/antennapod/ui/PlaybackTest.java23
-rw-r--r--app/src/androidTest/java/de/test/antennapod/ui/UITestUtils.java19
-rw-r--r--app/src/androidTest/java/de/test/antennapod/util/service/download/HTTPBin.java28
-rw-r--r--app/src/main/AndroidManifest.xml4
-rw-r--r--app/src/main/assets/about.html2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/DefaultOnlineFeedViewActivity.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java27
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/OpmlImportFromPathActivity.java189
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/ActionButtonUtils.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/DefaultActionButtonCallback.java12
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java1
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java6
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/NewEpisodesListAdapter.java10
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/QueueListAdapter.java57
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/gpodnet/PodcastListAdapter.java15
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/gpodnet/TagListAdapter.java54
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/itunes/ItunesAdapter.java187
-rw-r--r--app/src/main/java/de/danoeh/antennapod/asynctask/OpmlFeedQueuer.java11
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java10
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java52
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java13
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java3
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java193
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java92
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java113
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagFragment.java12
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagListFragment.java19
-rw-r--r--app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java19
-rw-r--r--app/src/main/java/de/danoeh/antennapod/menuhandler/MenuItemUtils.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/preferences/CustomEditTextPreference.java33
-rw-r--r--app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java62
-rw-r--r--app/src/main/java/de/danoeh/antennapod/receiver/PowerConnectionReceiver.java11
-rw-r--r--app/src/main/java/de/danoeh/antennapod/receiver/SPAReceiver.java12
-rw-r--r--app/src/main/res/layout/addfeed.xml173
-rw-r--r--app/src/main/res/layout/cover_fragment.xml2
-rw-r--r--app/src/main/res/layout/feeditem_fragment_header.xml25
-rw-r--r--app/src/main/res/layout/fragment_itunes_search.xml26
-rw-r--r--app/src/main/res/layout/gpodnet_podcast_listitem.xml54
-rw-r--r--app/src/main/res/layout/gpodnet_tag_listitem.xml34
-rw-r--r--app/src/main/res/layout/itunes_podcast_listitem.xml38
-rw-r--r--app/src/main/res/layout/new_episodes_fragment.xml17
-rw-r--r--app/src/main/res/layout/opml_import.xml80
-rw-r--r--app/src/main/res/layout/queue_fragment.xml19
-rw-r--r--app/src/main/res/layout/queue_listitem.xml57
-rw-r--r--app/src/main/res/menu/feedlist.xml2
-rw-r--r--app/src/main/res/menu/new_episodes.xml2
-rw-r--r--app/src/main/res/menu/queue.xml9
-rw-r--r--app/src/main/res/xml/preferences.xml18
52 files changed, 1563 insertions, 338 deletions
diff --git a/app/src/androidTest/java/de/test/antennapod/service/download/HttpDownloaderTest.java b/app/src/androidTest/java/de/test/antennapod/service/download/HttpDownloaderTest.java
index 65b1145a2..443fbed7e 100644
--- a/app/src/androidTest/java/de/test/antennapod/service/download/HttpDownloaderTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/service/download/HttpDownloaderTest.java
@@ -2,7 +2,12 @@ package de.test.antennapod.service.download;
import android.test.InstrumentationTestCase;
import android.util.Log;
+
+import java.io.File;
+import java.io.IOException;
+
import de.danoeh.antennapod.core.feed.FeedFile;
+import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.service.download.DownloadRequest;
import de.danoeh.antennapod.core.service.download.DownloadStatus;
import de.danoeh.antennapod.core.service.download.Downloader;
@@ -10,9 +15,6 @@ import de.danoeh.antennapod.core.service.download.HttpDownloader;
import de.danoeh.antennapod.core.util.DownloadError;
import de.test.antennapod.util.service.download.HTTPBin;
-import java.io.File;
-import java.io.IOException;
-
public class HttpDownloaderTest extends InstrumentationTestCase {
private static final String TAG = "HttpDownloaderTest";
private static final String DOWNLOAD_DIR = "testdownloads";
@@ -41,6 +43,7 @@ public class HttpDownloaderTest extends InstrumentationTestCase {
@Override
protected void setUp() throws Exception {
super.setUp();
+ UserPreferences.createInstance(getInstrumentation().getTargetContext());
destDir = getInstrumentation().getTargetContext().getExternalFilesDir(DOWNLOAD_DIR);
assertNotNull(destDir);
assertTrue(destDir.exists());
@@ -90,7 +93,7 @@ public class HttpDownloaderTest extends InstrumentationTestCase {
}
public void testGzip() {
- download("http://httpbin.org/gzip", "testGzip", true);
+ download(HTTPBin.BASE_URL + "/gzip/100", "testGzip", true);
}
public void test404() {
diff --git a/app/src/androidTest/java/de/test/antennapod/ui/MainActivityTest.java b/app/src/androidTest/java/de/test/antennapod/ui/MainActivityTest.java
index ce7b790e0..b092264cd 100644
--- a/app/src/androidTest/java/de/test/antennapod/ui/MainActivityTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/ui/MainActivityTest.java
@@ -3,12 +3,13 @@ package de.test.antennapod.ui;
import android.content.Context;
import android.content.SharedPreferences;
import android.test.ActivityInstrumentationTestCase2;
-import android.view.View;
+import android.widget.ListView;
+
import com.robotium.solo.Solo;
+
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.DefaultOnlineFeedViewActivity;
import de.danoeh.antennapod.activity.MainActivity;
-import de.danoeh.antennapod.activity.PreferenceActivityGingerbread;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.storage.PodDBAdapter;
import de.danoeh.antennapod.preferences.PreferenceController;
@@ -49,10 +50,14 @@ public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActiv
super.tearDown();
}
+ private void openNavDrawer() {
+ solo.clickOnScreen(50, 50);
+ }
+
public void testAddFeed() throws Exception {
uiTestUtils.addHostedFeedData();
final Feed feed = uiTestUtils.hostedFeeds.get(0);
- solo.setNavigationDrawer(Solo.OPENED);
+ openNavDrawer();
solo.clickOnText(solo.getString(R.string.add_feed_label));
solo.enterText(0, feed.getDownload_url());
solo.clickOnButton(0);
@@ -65,39 +70,43 @@ public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActiv
public void testClickNavDrawer() throws Exception {
uiTestUtils.addLocalFeedData(false);
- final View home = solo.getView(UITestUtils.HOME_VIEW);
// all episodes
+ openNavDrawer();
+ solo.clickOnText(solo.getString(R.string.new_episodes_label));
solo.waitForView(android.R.id.list);
- assertEquals(solo.getString(R.string.all_episodes_label), getActionbarTitle());
+ assertEquals(solo.getString(R.string.new_episodes_label), getActionbarTitle());
+
// queue
- solo.clickOnView(home);
+ openNavDrawer();
solo.clickOnText(solo.getString(R.string.queue_label));
solo.waitForView(android.R.id.list);
assertEquals(solo.getString(R.string.queue_label), getActionbarTitle());
// downloads
- solo.clickOnView(home);
+ openNavDrawer();
solo.clickOnText(solo.getString(R.string.downloads_label));
solo.waitForView(android.R.id.list);
assertEquals(solo.getString(R.string.downloads_label), getActionbarTitle());
// playback history
- solo.clickOnView(home);
+ openNavDrawer();
solo.clickOnText(solo.getString(R.string.playback_history_label));
solo.waitForView(android.R.id.list);
assertEquals(solo.getString(R.string.playback_history_label), getActionbarTitle());
// add podcast
- solo.clickOnView(home);
+ openNavDrawer();
solo.clickOnText(solo.getString(R.string.add_feed_label));
solo.waitForView(R.id.txtvFeedurl);
assertEquals(solo.getString(R.string.add_feed_label), getActionbarTitle());
// podcasts
+ ListView list = (ListView)solo.getView(R.id.nav_list);
for (int i = 0; i < uiTestUtils.hostedFeeds.size(); i++) {
Feed f = uiTestUtils.hostedFeeds.get(i);
- solo.clickOnView(home);
+ solo.clickOnScreen(50, 50); // open nav drawer
+ solo.scrollListToLine(list, i);
solo.clickOnText(f.getTitle());
solo.waitForView(android.R.id.list);
assertEquals("", getActionbarTitle());
@@ -109,7 +118,7 @@ public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActiv
}
public void testGoToPreferences() {
- solo.setNavigationDrawer(Solo.CLOSED);
+ openNavDrawer();
solo.clickOnMenuItem(solo.getString(R.string.settings_label));
solo.waitForActivity(PreferenceController.getPreferenceActivity());
}
diff --git a/app/src/androidTest/java/de/test/antennapod/ui/PlaybackTest.java b/app/src/androidTest/java/de/test/antennapod/ui/PlaybackTest.java
index 2235ee6f4..346ef6c18 100644
--- a/app/src/androidTest/java/de/test/antennapod/ui/PlaybackTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/ui/PlaybackTest.java
@@ -5,7 +5,11 @@ import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.test.ActivityInstrumentationTestCase2;
import android.widget.TextView;
+
import com.robotium.solo.Solo;
+
+import java.util.List;
+
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.AudioplayerActivity;
import de.danoeh.antennapod.activity.MainActivity;
@@ -16,8 +20,6 @@ import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.storage.PodDBAdapter;
-import java.util.List;
-
/**
* Test cases for starting and ending playback from the MainActivity and AudioPlayerActivity
*/
@@ -40,6 +42,7 @@ public class PlaybackTest extends ActivityInstrumentationTestCase2<MainActivity>
PodDBAdapter adapter = new PodDBAdapter(getInstrumentation().getTargetContext());
adapter.open();
adapter.close();
+
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getInstrumentation().getTargetContext());
prefs.edit().putBoolean(UserPreferences.PREF_UNPAUSE_ON_HEADSET_RECONNECT, false).commit();
prefs.edit().putBoolean(UserPreferences.PREF_PAUSE_ON_HEADSET_DISCONNECT, false).commit();
@@ -59,6 +62,10 @@ public class PlaybackTest extends ActivityInstrumentationTestCase2<MainActivity>
super.tearDown();
}
+ private void openNavDrawer() {
+ solo.clickOnScreen(50, 50);
+ }
+
private void setContinuousPlaybackPreference(boolean value) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getInstrumentation().getTargetContext());
prefs.edit().putBoolean(UserPreferences.PREF_FOLLOW_QUEUE, value).commit();
@@ -71,7 +78,9 @@ public class PlaybackTest extends ActivityInstrumentationTestCase2<MainActivity>
private void startLocalPlayback() {
assertTrue(solo.waitForActivity(MainActivity.class));
- solo.setNavigationDrawer(Solo.CLOSED);
+ openNavDrawer();
+ solo.clickOnText(solo.getString(R.string.new_episodes_label));
+ solo.waitForView(android.R.id.list);
solo.clickOnView(solo.getView(R.id.butSecondaryAction));
assertTrue(solo.waitForActivity(AudioplayerActivity.class));
assertTrue(solo.waitForView(solo.getView(R.id.butPlay)));
@@ -79,10 +88,10 @@ public class PlaybackTest extends ActivityInstrumentationTestCase2<MainActivity>
private void startLocalPlaybackFromQueue() {
assertTrue(solo.waitForActivity(MainActivity.class));
- solo.clickOnView(solo.getView(UITestUtils.HOME_VIEW));
+ openNavDrawer();
solo.clickOnText(solo.getString(R.string.queue_label));
assertTrue(solo.waitForView(solo.getView(R.id.butSecondaryAction)));
- solo.clickOnImageButton(0);
+ solo.clickOnImageButton(1);
assertTrue(solo.waitForActivity(AudioplayerActivity.class));
assertTrue(solo.waitForView(solo.getView(R.id.butPlay)));
}
@@ -108,7 +117,7 @@ public class PlaybackTest extends ActivityInstrumentationTestCase2<MainActivity>
setContinuousPlaybackPreference(false);
uiTestUtils.addLocalFeedData(true);
List<FeedItem> queue = DBReader.getQueue(getInstrumentation().getTargetContext());
- FeedItem second = queue.get(1);
+ FeedItem second = queue.get(0);
startLocalPlaybackFromQueue();
assertTrue(solo.waitForText(second.getTitle()));
@@ -147,4 +156,6 @@ public class PlaybackTest extends ActivityInstrumentationTestCase2<MainActivity>
public void testReplayEpisodeContinuousPlaybackOff() throws Exception {
replayEpisodeCheck(false);
}
+
+
}
diff --git a/app/src/androidTest/java/de/test/antennapod/ui/UITestUtils.java b/app/src/androidTest/java/de/test/antennapod/ui/UITestUtils.java
index 55fffb80a..249cb0dd6 100644
--- a/app/src/androidTest/java/de/test/antennapod/ui/UITestUtils.java
+++ b/app/src/androidTest/java/de/test/antennapod/ui/UITestUtils.java
@@ -5,12 +5,8 @@ import android.content.Context;
import android.graphics.Bitmap;
import android.os.Build;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.core.feed.*;
-import de.danoeh.antennapod.core.storage.PodDBAdapter;
-import de.test.antennapod.util.service.download.HTTPBin;
-import de.test.antennapod.util.syndication.feedgenerator.RSS2Generator;
import junit.framework.Assert;
+
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
@@ -23,6 +19,16 @@ import java.util.ArrayList;
import java.util.Date;
import java.util.List;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.feed.EventDistributor;
+import de.danoeh.antennapod.core.feed.Feed;
+import de.danoeh.antennapod.core.feed.FeedImage;
+import de.danoeh.antennapod.core.feed.FeedItem;
+import de.danoeh.antennapod.core.feed.FeedMedia;
+import de.danoeh.antennapod.core.storage.PodDBAdapter;
+import de.test.antennapod.util.service.download.HTTPBin;
+import de.test.antennapod.util.syndication.feedgenerator.RSS2Generator;
+
/**
* Utility methods for UI tests.
* Starts a web server that hosts feeds, episodes and images.
@@ -174,7 +180,8 @@ public class UITestUtils {
feed.setDownloaded(true);
if (feed.getImage() != null) {
FeedImage image = feed.getImage();
- image.setFile_url(image.getDownload_url());
+ int fileId = Integer.parseInt(StringUtils.substringAfter(image.getDownload_url(), "files/"));
+ image.setFile_url(server.accessFile(fileId).getAbsolutePath());
image.setDownloaded(true);
}
if (downloadEpisodes) {
diff --git a/app/src/androidTest/java/de/test/antennapod/util/service/download/HTTPBin.java b/app/src/androidTest/java/de/test/antennapod/util/service/download/HTTPBin.java
index 5cb723446..2f2c3fe5b 100644
--- a/app/src/androidTest/java/de/test/antennapod/util/service/download/HTTPBin.java
+++ b/app/src/androidTest/java/de/test/antennapod/util/service/download/HTTPBin.java
@@ -2,15 +2,28 @@ package de.test.antennapod.util.service.download;
import android.util.Base64;
import android.util.Log;
-import de.danoeh.antennapod.BuildConfig;
+
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
-import java.io.*;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
import java.net.URLConnection;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
import java.util.zip.GZIPOutputStream;
+import de.danoeh.antennapod.BuildConfig;
+
/**
* Http server for testing purposes
* <p/>
@@ -264,7 +277,7 @@ public class HTTPBin extends NanoHTTPD {
private Response getGzippedResponse(int size) throws IOException {
try {
- Thread.sleep(5000);
+ Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
@@ -272,14 +285,15 @@ public class HTTPBin extends NanoHTTPD {
Random random = new Random(System.currentTimeMillis());
random.nextBytes(buffer);
- ByteArrayOutputStream compressed = new ByteArrayOutputStream();
+ ByteArrayOutputStream compressed = new ByteArrayOutputStream(buffer.length);
GZIPOutputStream gzipOutputStream = new GZIPOutputStream(compressed);
gzipOutputStream.write(buffer);
+ gzipOutputStream.close();
InputStream inputStream = new ByteArrayInputStream(compressed.toByteArray());
Response response = new Response(Response.Status.OK, MIME_PLAIN, inputStream);
- response.addHeader("Content-encoding", "gzip");
- response.addHeader("Content-length", String.valueOf(compressed.size()));
+ response.addHeader("Content-Encoding", "gzip");
+ response.addHeader("Content-Length", String.valueOf(compressed.size()));
return response;
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 5b00941de..a04b1df07 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="de.danoeh.antennapod"
- android:versionCode="44"
- android:versionName="1.0">
+ android:versionCode="49"
+ android:versionName="1.1">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
diff --git a/app/src/main/assets/about.html b/app/src/main/assets/about.html
index 3398dbb67..d8face548 100644
--- a/app/src/main/assets/about.html
+++ b/app/src/main/assets/about.html
@@ -41,7 +41,7 @@
<div id="header" align="center">
<img src="logo.png" alt="Logo" width="100px" height="100px"/>
- <p>AntennaPod, Version 1.0</p>
+ <p>AntennaPod, Version 1.1</p>
<p>Copyright © 2014 Daniel Oeh</p>
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/DefaultOnlineFeedViewActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/DefaultOnlineFeedViewActivity.java
index 8401b41a7..287ae3568 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/DefaultOnlineFeedViewActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/DefaultOnlineFeedViewActivity.java
@@ -138,7 +138,7 @@ public class DefaultOnlineFeedViewActivity extends OnlineFeedViewActivity {
@Override
public void onClick(View v) {
try {
- Feed f = new Feed(selectedDownloadUrl, new Date(), feed.getTitle());
+ Feed f = new Feed(selectedDownloadUrl, new Date(0), feed.getTitle());
f.setPreferences(feed.getPreferences());
DefaultOnlineFeedViewActivity.this.feed = f;
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java
index b3e95f0c0..2efee838d 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java
@@ -66,8 +66,8 @@ public class MainActivity extends ActionBarActivity implements NavDrawerActivity
public static final String SAVE_TITLE = "title";
- public static final int POS_NEW = 0,
- POS_QUEUE = 1,
+ public static final int POS_QUEUE = 0,
+ POS_NEW = 1,
POS_DOWNLOADS = 2,
POS_HISTORY = 3,
POS_ADD = 4;
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java
index 9f028000e..3b03ed2db 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java
@@ -13,9 +13,21 @@ import android.widget.ArrayAdapter;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
+
+import org.apache.commons.lang3.StringUtils;
+import org.xml.sax.SAXException;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.parsers.ParserConfigurationException;
+
import de.danoeh.antennapod.BuildConfig;
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.dialog.AuthenticationDialog;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedPreferences;
import de.danoeh.antennapod.core.preferences.UserPreferences;
@@ -31,16 +43,7 @@ import de.danoeh.antennapod.core.util.FileNameGenerator;
import de.danoeh.antennapod.core.util.StorageUtils;
import de.danoeh.antennapod.core.util.URLChecker;
import de.danoeh.antennapod.core.util.syndication.FeedDiscoverer;
-import org.apache.commons.lang3.StringUtils;
-import org.xml.sax.SAXException;
-
-import javax.xml.parsers.ParserConfigurationException;
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
+import de.danoeh.antennapod.dialog.AuthenticationDialog;
/**
* Downloads a feed from a feed URL and parses it. Subclasses can display the
@@ -181,7 +184,7 @@ public abstract class OnlineFeedViewActivity extends ActionBarActivity {
if (BuildConfig.DEBUG)
Log.d(TAG, "Starting feed download");
url = URLChecker.prepareURL(url);
- feed = new Feed(url, new Date());
+ feed = new Feed(url, new Date(0));
if (username != null && password != null) {
feed.setPreferences(new FeedPreferences(0, false, username, password));
}
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportFromPathActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportFromPathActivity.java
index 162a8f2e5..c1bbb7e52 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportFromPathActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportFromPathActivity.java
@@ -1,7 +1,9 @@
package de.danoeh.antennapod.activity;
-import android.app.AlertDialog;
-import android.content.DialogInterface;
+import android.content.ActivityNotFoundException;
+import android.content.Intent;
+import android.content.pm.ResolveInfo;
+import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
@@ -10,23 +12,31 @@ import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
-import android.widget.Toast;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.List;
+
import de.danoeh.antennapod.BuildConfig;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.util.LangUtils;
import de.danoeh.antennapod.core.util.StorageUtils;
-import java.io.*;
-
/**
* Lets the user start the OPML-import process from a path
*/
public class OpmlImportFromPathActivity extends OpmlImportBaseActivity {
+
private static final String TAG = "OpmlImportFromPathActivity";
- private TextView txtvPath;
- private Button butStart;
- private String importPath;
+
+ private static final int CHOOSE_OPML_FILE = 1;
+
+ private Intent intentPickAction;
+ private Intent intentGetContentAction;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -36,47 +46,74 @@ public class OpmlImportFromPathActivity extends OpmlImportBaseActivity {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
setContentView(R.layout.opml_import);
- txtvPath = (TextView) findViewById(R.id.txtvPath);
- butStart = (Button) findViewById(R.id.butStartImport);
+ final TextView txtvHeaderExplanation1 = (TextView) findViewById(R.id.txtvHeadingExplanation1);
+ final TextView txtvExplanation1 = (TextView) findViewById(R.id.txtvExplanation1);
+ final TextView txtvHeaderExplanation2 = (TextView) findViewById(R.id.txtvHeadingExplanation2);
+ final TextView txtvExplanation2 = (TextView) findViewById(R.id.txtvExplanation2);
+ final TextView txtvHeaderExplanation3 = (TextView) findViewById(R.id.txtvHeadingExplanation3);
- butStart.setOnClickListener(new OnClickListener() {
+ Button butChooseFilesystem = (Button) findViewById(R.id.butChooseFileFromFilesystem);
+ butChooseFilesystem.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
- checkFolderForFiles();
+ chooseFileFromFilesystem();
}
});
+
+ Button butChooseExternal = (Button) findViewById(R.id.butChooseFileFromExternal);
+ butChooseExternal.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ chooseFileFromExternal();
+ }
+ });
+
+ int nextOption = 1;
+ intentPickAction = new Intent(Intent.ACTION_PICK);
+ intentPickAction.setData(Uri.parse("file://"));
+ List<ResolveInfo> intentActivities = getPackageManager()
+ .queryIntentActivities(intentPickAction, CHOOSE_OPML_FILE);
+ if(intentActivities.size() == 0) {
+ intentPickAction.setData(null);
+ intentActivities = getPackageManager()
+ .queryIntentActivities(intentPickAction, CHOOSE_OPML_FILE);
+ if(intentActivities.size() == 0) {
+ txtvHeaderExplanation1.setVisibility(View.GONE);
+ txtvExplanation1.setVisibility(View.GONE);
+ findViewById(R.id.divider1).setVisibility(View.GONE);
+ butChooseFilesystem.setVisibility(View.GONE);
+ }
+ }
+ if(txtvExplanation1.getVisibility() == View.VISIBLE) {
+ txtvHeaderExplanation1.setText("Option " + nextOption);
+ nextOption++;
+ }
+
+ intentGetContentAction = new Intent(Intent.ACTION_GET_CONTENT);
+ intentGetContentAction.addCategory(Intent.CATEGORY_OPENABLE);
+ intentGetContentAction.setType("*/*");
+ intentActivities = getPackageManager()
+ .queryIntentActivities(intentGetContentAction, CHOOSE_OPML_FILE);
+ if(intentActivities.size() == 0) {
+ txtvHeaderExplanation2.setVisibility(View.GONE);
+ txtvExplanation2.setVisibility(View.GONE);
+ findViewById(R.id.divider2).setVisibility(View.GONE);
+ butChooseExternal.setVisibility(View.GONE);
+ } else {
+ txtvHeaderExplanation2.setText("Option " + nextOption);
+ nextOption++;
+ }
+
+ txtvHeaderExplanation3.setText("Option " + nextOption);
}
@Override
protected void onResume() {
super.onResume();
StorageUtils.checkStorageAvailability(this);
- setImportPath();
}
- /**
- * Sets the importPath variable and makes txtvPath display the import
- * directory.
- */
- private void setImportPath() {
- File importDir = UserPreferences.getDataFolder(this, UserPreferences.IMPORT_DIR);
- boolean success = true;
- if (!importDir.exists()) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Import directory doesn't exist. Creating...");
- success = importDir.mkdir();
- if (!success) {
- Log.e(TAG, "Could not create directory");
- }
- }
- if (success) {
- txtvPath.setText(importDir.toString());
- importPath = importDir.toString();
- } else {
- txtvPath.setText(R.string.opml_directory_error);
- }
- }
@Override
public boolean onCreateOptionsMenu(Menu menu) {
@@ -95,32 +132,6 @@ public class OpmlImportFromPathActivity extends OpmlImportBaseActivity {
}
}
- /**
- * Looks at the contents of the import directory and decides what to do. If
- * more than one file is in the directory, a dialog will be created to let
- * the user choose which item to import
- */
- private void checkFolderForFiles() {
- File dir = new File(importPath);
- if (dir.isDirectory()) {
- File[] fileList = dir.listFiles();
- if (fileList.length == 1) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Found one file, choosing that one.");
- startImport(fileList[0]);
- } else if (fileList.length > 1) {
- Log.w(TAG, "Import directory contains more than one file.");
- askForFile(dir);
- } else {
- Log.e(TAG, "Import directory is empty");
- Toast toast = Toast
- .makeText(this, R.string.opml_import_error_dir_empty,
- Toast.LENGTH_LONG);
- toast.show();
- }
- }
- }
-
private void startImport(File file) {
Reader mReader = null;
try {
@@ -134,38 +145,36 @@ public class OpmlImportFromPathActivity extends OpmlImportBaseActivity {
}
}
- /**
- * Asks the user to choose from a list of files in a directory and returns
- * his choice.
+ /*
+ * Creates an implicit intent to launch a file manager which lets
+ * the user choose a specific OPML-file to import from.
*/
- private void askForFile(File dir) {
- final File[] fileList = dir.listFiles();
- String[] fileNames = dir.list();
-
- AlertDialog.Builder dialog = new AlertDialog.Builder(this);
- dialog.setTitle(R.string.choose_file_to_import_label);
- dialog.setNeutralButton(android.R.string.cancel,
- new DialogInterface.OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Dialog was cancelled");
- dialog.dismiss();
- }
- });
- dialog.setItems(fileNames, new DialogInterface.OnClickListener() {
+ private void chooseFileFromFilesystem() {
+ try {
+ startActivityForResult(intentPickAction, CHOOSE_OPML_FILE);
+ } catch (ActivityNotFoundException e) {
+ Log.e(TAG, "No activity found. Should never happen...");
+ }
+ }
- @Override
- public void onClick(DialogInterface dialog, int which) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "File at index " + which + " was chosen");
- dialog.dismiss();
- startImport(fileList[which]);
- }
- });
- dialog.create().show();
+ private void chooseFileFromExternal() {
+ try {
+ startActivityForResult(intentGetContentAction, CHOOSE_OPML_FILE);
+ } catch (ActivityNotFoundException e) {
+ Log.e(TAG, "No activity found. Should never happen...");
+ }
}
+ /**
+ * Gets the path of the file chosen with chooseFileToImport()
+ */
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ if (resultCode == RESULT_OK && requestCode == CHOOSE_OPML_FILE) {
+ String filename = data.getData().getPath();
+ startImport(new File(filename));
+ }
+ }
}
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/ActionButtonUtils.java b/app/src/main/java/de/danoeh/antennapod/adapter/ActionButtonUtils.java
index c35bb9694..8d3e73429 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/ActionButtonUtils.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/ActionButtonUtils.java
@@ -57,7 +57,7 @@ public class ActionButtonUtils {
} else {
// item is not being downloaded
butSecondary.setVisibility(View.VISIBLE);
- if (media.isPlaying()) {
+ if (media.isCurrentlyPlaying()) {
butSecondary.setImageDrawable(drawables.getDrawable(3));
} else {
butSecondary
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/DefaultActionButtonCallback.java b/app/src/main/java/de/danoeh/antennapod/adapter/DefaultActionButtonCallback.java
index 800462023..14644dd68 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/DefaultActionButtonCallback.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/DefaultActionButtonCallback.java
@@ -1,6 +1,7 @@
package de.danoeh.antennapod.adapter;
import android.content.Context;
+import android.content.Intent;
import android.widget.Toast;
import org.apache.commons.lang3.Validate;
@@ -9,6 +10,7 @@ import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.dialog.DownloadRequestErrorDialogCreator;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
+import de.danoeh.antennapod.core.service.playback.PlaybackService;
import de.danoeh.antennapod.core.storage.DBTasks;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.storage.DownloadRequestException;
@@ -46,7 +48,15 @@ public class DefaultActionButtonCallback implements ActionButtonCallback {
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);
+ if (item.hasMedia() && item.getMedia().isCurrentlyPlaying()) {
+ context.sendBroadcast(new Intent(PlaybackService.ACTION_PAUSE_PLAY_CURRENT_EPISODE));
+ }
+ else if (item.hasMedia() && item.getMedia().isCurrentlyPaused()) {
+ context.sendBroadcast(new Intent(PlaybackService.ACTION_RESUME_PLAY_CURRENT_EPISODE));
+ }
+ else {
+ DBTasks.playMedia(context, media, false, true, false);
+ }
}
} else {
if (!item.isRead()) {
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java
index 8f1a838f9..d56bfc587 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java
@@ -9,6 +9,7 @@ import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.*;
import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.feed.EventDistributor;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.feed.MediaType;
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java
index a0ba0f794..05783e3ee 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java
@@ -25,7 +25,7 @@ public class NavListAdapter extends BaseAdapter {
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.all_episodes_label, R.string.queue_label, R.string.downloads_label, R.string.playback_history_label, R.string.add_feed_label};
+ public static final int[] NAV_TITLES = {R.string.queue_label, R.string.new_episodes_label, R.string.downloads_label, R.string.playback_history_label, R.string.add_feed_label};
private final Drawable[] drawables;
@@ -38,7 +38,7 @@ public class NavListAdapter extends BaseAdapter {
this.itemAccess = itemAccess;
this.context = context;
- TypedArray ta = context.obtainStyledAttributes(new int[]{R.attr.ic_new, R.attr.stat_playlist,
+ TypedArray ta = context.obtainStyledAttributes(new int[]{R.attr.stat_playlist, R.attr.ic_new,
R.attr.av_download, R.attr.ic_history, R.attr.content_new});
drawables = new Drawable[]{ta.getDrawable(0), ta.getDrawable(1), ta.getDrawable(2),
ta.getDrawable(3), ta.getDrawable(4)};
@@ -132,7 +132,7 @@ public class NavListAdapter extends BaseAdapter {
} else {
holder.count.setVisibility(View.GONE);
}
- } else if (NAV_TITLES[position] == R.string.all_episodes_label) {
+ } else if (NAV_TITLES[position] == R.string.new_episodes_label) {
int unreadItems = itemAccess.getNumberOfUnreadItems();
if (unreadItems > 0) {
holder.count.setVisibility(View.VISIBLE);
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/NewEpisodesListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/NewEpisodesListAdapter.java
index 1f98ec158..2d481a7ef 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/NewEpisodesListAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/NewEpisodesListAdapter.java
@@ -1,6 +1,7 @@
package de.danoeh.antennapod.adapter;
import android.content.Context;
+import android.graphics.Color;
import android.text.format.DateUtils;
import android.view.LayoutInflater;
import android.view.View;
@@ -11,9 +12,11 @@ import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
+import com.nineoldandroids.view.ViewHelper;
import com.squareup.picasso.Picasso;
import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.feed.EventDistributor;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.storage.DownloadRequester;
@@ -139,6 +142,13 @@ public class NewEpisodesListAdapter extends BaseAdapter {
.fit()
.into(holder.imageView);
+ if (item.isRead()) {
+ // grey it out
+ ViewHelper.setAlpha(convertView, .2f);
+ } else {
+ ViewHelper.setAlpha(convertView, 1.0f);
+ }
+
return convertView;
}
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/QueueListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/QueueListAdapter.java
index d5b85575b..a256dc129 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/QueueListAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/QueueListAdapter.java
@@ -1,6 +1,7 @@
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;
@@ -13,9 +14,11 @@ import android.widget.TextView;
import com.squareup.picasso.Picasso;
import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.feed.EventDistributor;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.storage.DownloadRequester;
+import de.danoeh.antennapod.core.util.Converter;
/**
* List adapter for the queue.
@@ -64,12 +67,16 @@ public class QueueListAdapter extends BaseAdapter {
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.queue_listitem,
parent, false);
+ holder.imageView = (ImageView) convertView.findViewById(R.id.imgvImage);
holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
+ holder.pubDate = (TextView) convertView.findViewById(R.id.txtvPubDate);
+ holder.progressLeft = (TextView) convertView.findViewById(R.id.txtvProgressLeft);
+ holder.progressRight = (TextView) convertView
+ .findViewById(R.id.txtvProgressRight);
holder.butSecondary = (ImageButton) convertView
.findViewById(R.id.butSecondaryAction);
- holder.position = (TextView) convertView.findViewById(R.id.txtvPosition);
holder.progress = (ProgressBar) convertView
- .findViewById(R.id.pbar_download_progress);
+ .findViewById(R.id.progressBar);
holder.imageView = (ImageView) convertView.findViewById(R.id.imgvImage);
convertView.setTag(holder);
} else {
@@ -77,19 +84,39 @@ public class QueueListAdapter extends BaseAdapter {
}
holder.title.setText(item.getTitle());
+ FeedMedia media = item.getMedia();
- AdapterUtils.updateEpisodePlaybackProgress(item, context.getResources(), holder.position, holder.progress);
- FeedMedia media = item.getMedia();
+ holder.title.setText(item.getTitle());
+ String pubDate = DateUtils.formatDateTime(context, item.getPubDate().getTime(), DateUtils.FORMAT_ABBREV_ALL);
+ holder.pubDate.setText(pubDate.replace(" ", "\n"));
+
if (media != null) {
final boolean isDownloadingMedia = DownloadRequester.getInstance().isDownloadingFile(media);
-
- if (!media.isDownloaded()) {
- if (isDownloadingMedia) {
- // item is being downloaded
+ FeedItem.State state = item.getState();
+ if (isDownloadingMedia) {
+ holder.progressLeft.setText(Converter.byteToString(itemAccess.getItemDownloadedBytes(item)));
+ if(itemAccess.getItemDownloadSize(item) > 0) {
+ holder.progressRight.setText(Converter.byteToString(itemAccess.getItemDownloadSize(item)));
+ } else {
+ holder.progressRight.setText(Converter.byteToString(media.getSize()));
+ }
+ holder.progress.setProgress(itemAccess.getItemDownloadProgressPercent(item));
+ holder.progress.setVisibility(View.VISIBLE);
+ } else if (state == FeedItem.State.PLAYING
+ || state == FeedItem.State.IN_PROGRESS) {
+ if (media.getDuration() > 0) {
+ int progress = (int) (100.0 * media.getPosition() / media.getDuration());
+ holder.progress.setProgress(progress);
holder.progress.setVisibility(View.VISIBLE);
- holder.progress.setProgress(itemAccess.getItemDownloadProgressPercent(item));
+ holder.progressLeft.setText(Converter
+ .getDurationStringLong(media.getPosition()));
+ holder.progressRight.setText(Converter.getDurationStringLong(media.getDuration()));
}
+ } else {
+ holder.progressLeft.setText(Converter.byteToString(media.getSize()));
+ holder.progressRight.setText(Converter.getDurationStringLong(media.getDuration()));
+ holder.progress.setVisibility(View.GONE);
}
}
@@ -116,18 +143,20 @@ public class QueueListAdapter extends BaseAdapter {
static class Holder {
- TextView title;
ImageView imageView;
- TextView position;
+ TextView title;
+ TextView pubDate;
+ TextView progressLeft;
+ TextView progressRight;
ProgressBar progress;
ImageButton butSecondary;
}
public interface ItemAccess {
- int getCount();
-
FeedItem getItem(int position);
-
+ int getCount();
+ long getItemDownloadedBytes(FeedItem item);
+ long getItemDownloadSize(FeedItem item);
int getItemDownloadProgressPercent(FeedItem item);
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/gpodnet/PodcastListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/gpodnet/PodcastListAdapter.java
index 58af2c4d5..b85709c5e 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/gpodnet/PodcastListAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/gpodnet/PodcastListAdapter.java
@@ -39,16 +39,15 @@ public class PodcastListAdapter extends ArrayAdapter<GpodnetPodcast> {
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.gpodnet_podcast_listitem, parent, false);
- holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
holder.image = (ImageView) convertView.findViewById(R.id.imgvCover);
-
+ holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
+ holder.subscribers = (TextView) convertView.findViewById(R.id.txtvSubscribers);
+ holder.url = (TextView) convertView.findViewById(R.id.txtvUrl);
convertView.setTag(holder);
} else {
holder = (Holder) convertView.getTag();
}
- holder.title.setText(podcast.getTitle());
-
if (StringUtils.isNotBlank(podcast.getLogoUrl())) {
Picasso.with(convertView.getContext())
.load(podcast.getLogoUrl())
@@ -56,11 +55,17 @@ public class PodcastListAdapter extends ArrayAdapter<GpodnetPodcast> {
.into(holder.image);
}
+ holder.title.setText(podcast.getTitle());
+ holder.subscribers.setText(String.valueOf(podcast.getSubscribers()));
+ holder.url.setText(podcast.getUrl());
+
return convertView;
}
static class Holder {
- TextView title;
ImageView image;
+ TextView title;
+ TextView subscribers;
+ TextView url;
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/gpodnet/TagListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/gpodnet/TagListAdapter.java
new file mode 100644
index 000000000..b4eadefb5
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/gpodnet/TagListAdapter.java
@@ -0,0 +1,54 @@
+package de.danoeh.antennapod.adapter.gpodnet;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.TextView;
+
+import java.util.List;
+
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.gpoddernet.model.GpodnetTag;
+
+/**
+ * Adapter for displaying a list of GPodnetPodcast-Objects.
+ */
+public class TagListAdapter extends ArrayAdapter<GpodnetTag> {
+
+ public TagListAdapter(Context context, int resource, List<GpodnetTag> objects) {
+ super(context, resource, objects);
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ Holder holder;
+
+ GpodnetTag tag = getItem(position);
+
+ // Inflate Layout
+ if (convertView == null) {
+ holder = new Holder();
+ LayoutInflater inflater = (LayoutInflater) getContext()
+ .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+ convertView = inflater.inflate(R.layout.gpodnet_tag_listitem, parent, false);
+ holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
+ holder.usage = (TextView) convertView.findViewById(R.id.txtvUsage);
+ convertView.setTag(holder);
+ } else {
+ holder = (Holder) convertView.getTag();
+ }
+
+ holder.title.setText(tag.getTitle());
+ holder.usage.setText(String.valueOf(tag.getUsage()));
+
+ return convertView;
+ }
+
+ static class Holder {
+ TextView title;
+ TextView usage;
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/itunes/ItunesAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/itunes/ItunesAdapter.java
new file mode 100644
index 000000000..4fc2838b7
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/itunes/ItunesAdapter.java
@@ -0,0 +1,187 @@
+package de.danoeh.antennapod.adapter.itunes;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.AsyncTask;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.IOException;
+import java.util.List;
+
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.MainActivity;
+
+public class ItunesAdapter extends ArrayAdapter<ItunesAdapter.Podcast> {
+ /**
+ * Related Context
+ */
+ private final Context context;
+
+ /**
+ * List holding the podcasts found in the search
+ */
+ private final List<Podcast> data;
+
+ /**
+ * Constructor.
+ *
+ * @param context Related context
+ * @param objects Search result
+ */
+ public ItunesAdapter(Context context, List<Podcast> objects) {
+ super(context, 0, objects);
+ this.data = objects;
+ this.context = context;
+ }
+
+ /**
+ * Updates the given ImageView with the image in the given Podcast's imageUrl
+ */
+ class FetchImageTask extends AsyncTask<Void,Void,Bitmap>{
+ /**
+ * Current podcast
+ */
+ private final Podcast podcast;
+
+ /**
+ * ImageView to be updated
+ */
+ private final ImageView imageView;
+
+ /**
+ * Constructor
+ *
+ * @param podcast Podcast that has the image
+ * @param imageView UI image to be updated
+ */
+ FetchImageTask(Podcast podcast, ImageView imageView){
+ this.podcast = podcast;
+ this.imageView = imageView;
+ }
+
+ //Get the image from the url
+ @Override
+ protected Bitmap doInBackground(Void... params) {
+ HttpClient client = new DefaultHttpClient();
+ HttpGet get = new HttpGet(podcast.imageUrl);
+ try {
+ HttpResponse response = client.execute(get);
+ return BitmapFactory.decodeStream(response.getEntity().getContent());
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ //Set the background image for the podcast
+ @Override
+ protected void onPostExecute(Bitmap img) {
+ super.onPostExecute(img);
+ if(img!=null) {
+ imageView.setImageBitmap(img);
+ }
+ }
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ //Current podcast
+ Podcast podcast = data.get(position);
+
+ //ViewHolder
+ PodcastViewHolder viewHolder;
+
+ //Resulting view
+ View view;
+
+ //Handle view holder stuff
+ if(convertView == null) {
+ view = ((MainActivity) context).getLayoutInflater()
+ .inflate(R.layout.itunes_podcast_listitem, parent, false);
+ viewHolder = new PodcastViewHolder(view);
+ view.setTag(viewHolder);
+ } else {
+ view = convertView;
+ viewHolder = (PodcastViewHolder) view.getTag();
+ }
+
+ //Set the title
+ viewHolder.titleView.setText(podcast.title);
+
+ //Update the empty imageView with the image from the feed
+ new FetchImageTask(podcast,viewHolder.coverView).execute();
+
+ //Feed the grid view
+ return view;
+ }
+
+ /**
+ * View holder object for the GridView
+ */
+ class PodcastViewHolder {
+
+ /**
+ * ImageView holding the Podcast image
+ */
+ public final ImageView coverView;
+
+ /**
+ * TextView holding the Podcast title
+ */
+ public final TextView titleView;
+
+
+ /**
+ * Constructor
+ * @param view GridView cell
+ */
+ PodcastViewHolder(View view){
+ coverView = (ImageView) view.findViewById(R.id.imgvCover);
+ titleView = (TextView) view.findViewById(R.id.txtvTitle);
+ }
+ }
+
+ /**
+ * Represents an individual podcast on the iTunes Store.
+ */
+ public static class Podcast { //TODO: Move this out eventually. Possibly to core.itunes.model
+
+ /**
+ * The name of the podcast
+ */
+ public final String title;
+
+ /**
+ * URL of the podcast image
+ */
+ public final String imageUrl;
+ /**
+ * URL of the podcast feed
+ */
+ public final String feedUrl;
+
+ /**
+ * Constructor.
+ *
+ * @param json object holding the podcast information
+ * @throws JSONException
+ */
+ public Podcast(JSONObject json) throws JSONException {
+ title = json.getString("collectionName");
+ imageUrl = json.getString("artworkUrl100");
+ feedUrl = json.getString("feedUrl");
+ }
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlFeedQueuer.java b/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlFeedQueuer.java
index cb9197b8e..00327bce0 100644
--- a/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlFeedQueuer.java
+++ b/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlFeedQueuer.java
@@ -4,16 +4,17 @@ import android.annotation.SuppressLint;
import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
-import de.danoeh.antennapod.core.R;
+
+import java.util.Arrays;
+import java.util.Date;
+
import de.danoeh.antennapod.activity.OpmlImportHolder;
+import de.danoeh.antennapod.core.R;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.opml.OpmlElement;
import de.danoeh.antennapod.core.storage.DownloadRequestException;
import de.danoeh.antennapod.core.storage.DownloadRequester;
-import java.util.Arrays;
-import java.util.Date;
-
/** Queues items for download in the background. */
public class OpmlFeedQueuer extends AsyncTask<Void, Void, Void> {
private Context context;
@@ -46,7 +47,7 @@ public class OpmlFeedQueuer extends AsyncTask<Void, Void, Void> {
for (int idx = 0; idx < selection.length; idx++) {
OpmlElement element = OpmlImportHolder.getReadElements().get(
selection[idx]);
- Feed feed = new Feed(element.getXmlUrl(), new Date(),
+ Feed feed = new Feed(element.getXmlUrl(), new Date(0),
element.getText());
try {
requester.downloadFeed(context.getApplicationContext(), feed);
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java
index f5ae5a777..e4ae1683b 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java
@@ -8,6 +8,7 @@ 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;
@@ -41,10 +42,18 @@ public class AddFeedFragment extends Fragment {
Button butBrowserGpoddernet = (Button) root.findViewById(R.id.butBrowseGpoddernet);
Button butOpmlImport = (Button) root.findViewById(R.id.butOpmlImport);
Button butConfirm = (Button) root.findViewById(R.id.butConfirm);
+ Button butSearchITunes = (Button) root.findViewById(R.id.butSearchItunes);
final MainActivity activity = (MainActivity) getActivity();
activity.getMainActivtyActionBar().setTitle(R.string.add_feed_label);
+ butSearchITunes.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ activity.loadChildFragment(new ItunesSearchFragment());
+ }
+ });
+
butBrowserGpoddernet.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
@@ -53,7 +62,6 @@ public class AddFeedFragment extends Fragment {
});
butOpmlImport.setOnClickListener(new View.OnClickListener() {
-
@Override
public void onClick(View v) {
startActivity(new Intent(getActivity(),
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java
index c40fce351..0f6f7d53c 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java
@@ -1,25 +1,35 @@
package de.danoeh.antennapod.fragment;
import android.content.Context;
+import android.content.res.TypedArray;
import android.os.AsyncTask;
import android.os.Bundle;
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 java.util.List;
+
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.adapter.DownloadLogAdapter;
import de.danoeh.antennapod.core.feed.EventDistributor;
import de.danoeh.antennapod.core.service.download.DownloadStatus;
import de.danoeh.antennapod.core.storage.DBReader;
-
-import java.util.List;
+import de.danoeh.antennapod.core.storage.DBWriter;
+import de.danoeh.antennapod.menuhandler.MenuItemUtils;
+import de.danoeh.antennapod.menuhandler.NavDrawerActivity;
/**
* Shows the download log
*/
public class DownloadLogFragment extends ListFragment {
+ private static final String TAG = "DownloadLogFragment";
+
private List<DownloadStatus> downloadLog;
private DownloadLogAdapter adapter;
@@ -29,6 +39,7 @@ public class DownloadLogFragment extends ListFragment {
@Override
public void onStart() {
super.onStart();
+ setHasOptionsMenu(true);
EventDistributor.getInstance().register(contentUpdate);
startItemLoader();
}
@@ -63,7 +74,7 @@ public class DownloadLogFragment extends ListFragment {
}
setListShown(true);
adapter.notifyDataSetChanged();
-
+ getActivity().supportInvalidateOptionsMenu();
}
private DownloadLogAdapter.ItemAccess itemAccess = new DownloadLogAdapter.ItemAccess() {
@@ -105,6 +116,41 @@ public class DownloadLogFragment extends ListFragment {
}
}
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ super.onCreateOptionsMenu(menu, inflater);
+ if (itemsLoaded && !MenuItemUtils.isActivityDrawerOpen((NavDrawerActivity) getActivity())) {
+ 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);
+ if (itemsLoaded && !MenuItemUtils.isActivityDrawerOpen((NavDrawerActivity) getActivity())) {
+ menu.findItem(R.id.clear_history_item).setVisible(downloadLog != null && !downloadLog.isEmpty());
+ }
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (!super.onOptionsItemSelected(item)) {
+ switch (item.getItemId()) {
+ case R.id.clear_history_item:
+ DBWriter.clearDownloadLog(getActivity());
+ return true;
+ default:
+ return false;
+ }
+ } else {
+ return true;
+ }
+ }
+
private class ItemLoader extends AsyncTask<Void, Void, List<DownloadStatus>> {
@Override
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java
index ac9e744ed..e80bf5f14 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java
@@ -16,6 +16,7 @@ import android.support.v4.util.Pair;
import android.support.v7.widget.PopupMenu;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
+import android.text.format.DateUtils;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
@@ -49,6 +50,7 @@ import de.danoeh.antennapod.core.storage.DBTasks;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.storage.DownloadRequestException;
import de.danoeh.antennapod.core.storage.DownloadRequester;
+import de.danoeh.antennapod.core.util.Converter;
import de.danoeh.antennapod.core.util.QueueAccess;
import de.danoeh.antennapod.core.util.playback.Timeline;
import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
@@ -91,6 +93,8 @@ public class ItemFragment extends Fragment implements LoaderManager.LoaderCallba
private View header;
private WebView webvDescription;
private TextView txtvTitle;
+ private TextView txtvDuration;
+ private TextView txtvPublished;
private ImageView imgvCover;
private ProgressBar progbarDownload;
private ProgressBar progbarLoading;
@@ -166,6 +170,8 @@ public class ItemFragment extends Fragment implements LoaderManager.LoaderCallba
header = inflater.inflate(R.layout.feeditem_fragment_header, toolbar, false);
root = (ViewGroup) layout.findViewById(R.id.content_root);
txtvTitle = (TextView) header.findViewById(R.id.txtvTitle);
+ txtvDuration = (TextView) header.findViewById(R.id.txtvDuration);
+ txtvPublished = (TextView) header.findViewById(R.id.txtvPublished);
if (Build.VERSION.SDK_INT >= 14) { // ellipsize is causing problems on old versions, see #448
txtvTitle.setEllipsize(TextUtils.TruncateAt.END);
}
@@ -313,6 +319,8 @@ public class ItemFragment extends Fragment implements LoaderManager.LoaderCallba
private void updateAppearance() {
txtvTitle.setText(item.getTitle());
+ txtvPublished.setText(DateUtils.formatDateTime(getActivity(), item.getPubDate().getTime(), DateUtils.FORMAT_ABBREV_ALL));
+
Picasso.with(getActivity()).load(item.getImageUri())
.fit()
.into(imgvCover);
@@ -348,7 +356,10 @@ public class ItemFragment extends Fragment implements LoaderManager.LoaderCallba
}
drawables.recycle();
- } else {
+ } else {if(media.getDuration() > 0) {
+ txtvDuration.setText(Converter.getDurationStringLong(media.getDuration()));
+ }
+
boolean isDownloading = DownloadRequester.getInstance().isDownloadingFile(media);
TypedArray drawables = getActivity().obtainStyledAttributes(new int[]{R.attr.av_play,
R.attr.av_download, R.attr.action_stream, R.attr.content_discard, R.attr.navigation_cancel});
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java
index 5312beeeb..acb07626c 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java
@@ -66,7 +66,8 @@ public class ItemlistFragment extends ListFragment {
private static final int EVENTS = EventDistributor.DOWNLOAD_HANDLED
| EventDistributor.DOWNLOAD_QUEUED
| EventDistributor.QUEUE_UPDATE
- | EventDistributor.UNREAD_ITEMS_UPDATE;
+ | EventDistributor.UNREAD_ITEMS_UPDATE
+ | EventDistributor.PLAYER_STATUS_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";
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java
new file mode 100644
index 000000000..c14b0cc6e
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java
@@ -0,0 +1,193 @@
+package de.danoeh.antennapod.fragment;
+
+import android.content.Intent;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.support.v7.widget.SearchView;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.GridView;
+
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.util.EntityUtils;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.DefaultOnlineFeedViewActivity;
+import de.danoeh.antennapod.activity.OnlineFeedViewActivity;
+import de.danoeh.antennapod.adapter.itunes.ItunesAdapter;
+
+import static de.danoeh.antennapod.adapter.itunes.ItunesAdapter.*;
+
+//Searches iTunes store for given string and displays results in a list
+public class ItunesSearchFragment extends Fragment {
+ final String TAG = "ItunesSearchFragment";
+ /**
+ * Search input field
+ */
+ private SearchView searchView;
+
+ /**
+ * Adapter responsible with the search results
+ */
+ private ItunesAdapter adapter;
+
+ /**
+ * List of podcasts retreived from the search
+ */
+ private List<Podcast> searchResults;
+
+ /**
+ * Replace adapter data with provided search results from SearchTask.
+ * @param result List of Podcast objects containing search results
+ */
+ void updateData(List<Podcast> result) {
+ this.searchResults = result;
+ adapter.clear();
+
+ //ArrayAdapter.addAll() requires minsdk > 10
+ for(Podcast p: result) {
+ adapter.add(p);
+ }
+
+ adapter.notifyDataSetInvalidated();
+ }
+
+ /**
+ * Constructor
+ */
+ public ItunesSearchFragment() {
+ // Required empty public constructor
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ adapter = new ItunesAdapter(getActivity(), new ArrayList<Podcast>());
+
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ // Inflate the layout for this fragment
+ View view = inflater.inflate(R.layout.fragment_itunes_search, container, false);
+ GridView gridView = (GridView) view.findViewById(R.id.gridView);
+ gridView.setAdapter(adapter);
+
+ //Show information about the podcast when the list item is clicked
+ gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ Intent intent = new Intent(getActivity(),
+ DefaultOnlineFeedViewActivity.class);
+
+ //Tell the OnlineFeedViewActivity where to go
+ String url = searchResults.get(position).feedUrl;
+ intent.putExtra(OnlineFeedViewActivity.ARG_FEEDURL, url);
+
+ intent.putExtra(DefaultOnlineFeedViewActivity.ARG_TITLE, "iTunes");
+ startActivity(intent);
+ }
+ });
+
+ //Configure search input view to be expanded by default with a visible submit button
+ searchView = (SearchView) view.findViewById(R.id.itunes_search_view);
+ searchView.setIconifiedByDefault(false);
+ searchView.setIconified(false);
+ searchView.setSubmitButtonEnabled(true);
+ searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
+ @Override
+ public boolean onQueryTextSubmit(String s) {
+ //This prevents onQueryTextSubmit() from being called twice when keyboard is used
+ //to submit the query.
+ searchView.clearFocus();
+ new SearchTask(s).execute();
+ return false;
+ }
+
+ @Override
+ public boolean onQueryTextChange(String s) {
+ return false;
+ }
+ });
+
+ return view;
+ }
+
+ /**
+ * Search the iTunes store for podcasts using the given query
+ */
+ class SearchTask extends AsyncTask<Void,Void,Void> {
+ /**
+ * Incomplete iTunes API search URL
+ */
+ final String apiUrl = "https://itunes.apple.com/search?media=podcast&term=%s";
+
+ /**
+ * Search terms
+ */
+ final String query;
+
+ /**
+ * Search result
+ */
+ final List<Podcast> taskData = new ArrayList<>();
+
+ /**
+ * Constructor
+ *
+ * @param query Search string
+ */
+ public SearchTask(String query){
+ this.query = query;
+ }
+
+ //Get the podcast data
+ @Override
+ protected Void doInBackground(Void... params) {
+
+ //Spaces in the query need to be replaced with '+' character.
+ String formattedUrl = String.format(apiUrl, query).replace(' ', '+');
+
+ HttpClient client = new DefaultHttpClient();
+ HttpGet get = new HttpGet(formattedUrl);
+
+ try {
+ HttpResponse response = client.execute(get);
+ String resultString = EntityUtils.toString(response.getEntity());
+ JSONObject result = new JSONObject(resultString);
+ JSONArray j = result.getJSONArray("results");
+
+ for (int i = 0; i < j.length(); i++){
+ JSONObject podcastJson = j.getJSONObject(i);
+ Podcast podcast = new Podcast(podcastJson);
+ taskData.add(podcast);
+ }
+
+ } catch (IOException | JSONException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ //Save the data and update the list
+ @Override
+ protected void onPostExecute(Void aVoid) {
+ super.onPostExecute(aVoid);
+ updateData(taskData);
+ }
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java
index d97ede0ef..8bc4099a9 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java
@@ -2,12 +2,15 @@ package de.danoeh.antennapod.fragment;
import android.app.Activity;
import android.content.Context;
+import android.content.DialogInterface;
import android.content.SharedPreferences;
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.v7.widget.SearchView;
+import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
@@ -29,6 +32,7 @@ import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.adapter.DefaultActionButtonCallback;
import de.danoeh.antennapod.adapter.NewEpisodesListAdapter;
import de.danoeh.antennapod.core.asynctask.DownloadObserver;
+import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
import de.danoeh.antennapod.core.feed.EventDistributor;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedItem;
@@ -41,6 +45,8 @@ import de.danoeh.antennapod.core.storage.DBTasks;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.storage.DownloadRequester;
import de.danoeh.antennapod.core.util.QueueAccess;
+import de.danoeh.antennapod.core.util.gui.FeedItemUndoToken;
+import de.danoeh.antennapod.core.util.gui.UndoBarController;
import de.danoeh.antennapod.menuhandler.MenuItemUtils;
import de.danoeh.antennapod.menuhandler.NavDrawerActivity;
@@ -52,18 +58,22 @@ public class NewEpisodesFragment extends Fragment {
private static final int EVENTS = EventDistributor.DOWNLOAD_HANDLED |
EventDistributor.DOWNLOAD_QUEUED |
EventDistributor.QUEUE_UPDATE |
- EventDistributor.UNREAD_ITEMS_UPDATE;
+ EventDistributor.UNREAD_ITEMS_UPDATE |
+ EventDistributor.PLAYER_STATUS_UPDATE;
private static final int RECENT_EPISODES_LIMIT = 150;
private static final String PREF_NAME = "PrefNewEpisodesFragment";
private static final String PREF_EPISODE_FILTER_BOOL = "newEpisodeFilterEnabled";
-
+ private static final String PREF_KEY_LIST_TOP = "list_top";
+ private static final String PREF_KEY_LIST_SELECTION = "list_selection";
private DragSortListView listView;
private NewEpisodesListAdapter listAdapter;
private TextView txtvEmpty;
private ProgressBar progLoading;
+ private UndoBarController undoBarController;
+
private List<FeedItem> unreadItems;
private List<FeedItem> recentItems;
private QueueAccess queueAccess;
@@ -109,6 +119,12 @@ public class NewEpisodesFragment extends Fragment {
}
@Override
+ public void onPause() {
+ super.onPause();
+ saveScrollPosition();
+ }
+
+ @Override
public void onStop() {
super.onStop();
EventDistributor.getInstance().unregister(contentUpdate);
@@ -127,10 +143,35 @@ public class NewEpisodesFragment extends Fragment {
resetViewState();
}
+ private void saveScrollPosition() {
+ SharedPreferences prefs = getActivity().getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
+ SharedPreferences.Editor editor = prefs.edit();
+ View v = listView.getChildAt(0);
+ int top = (v == null) ? 0 : (v.getTop() - listView.getPaddingTop());
+ editor.putInt(PREF_KEY_LIST_SELECTION, listView.getFirstVisiblePosition());
+ editor.putInt(PREF_KEY_LIST_TOP, top);
+ editor.commit();
+ }
+
+ private void restoreScrollPosition() {
+ SharedPreferences prefs = getActivity().getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
+ int listSelection = prefs.getInt(PREF_KEY_LIST_SELECTION, 0);
+ int top = prefs.getInt(PREF_KEY_LIST_TOP, 0);
+ if(listSelection > 0 || top > 0) {
+ listView.setSelectionFromTop(listSelection, top);
+ // restore once, then forget
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putInt(PREF_KEY_LIST_SELECTION, 0);
+ editor.putInt(PREF_KEY_LIST_TOP, 0);
+ editor.commit();
+ }
+ }
+
private void resetViewState() {
listAdapter = null;
activity.set(null);
viewsCreated = false;
+ undoBarController = null;
if (downloadObserver != null) {
downloadObserver.onPause();
}
@@ -190,8 +231,19 @@ public class NewEpisodesFragment extends Fragment {
}
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();
+ ConfirmationDialog conDialog = new ConfirmationDialog(getActivity(),
+ R.string.mark_all_read_label,
+ R.string.mark_all_read_confirmation_msg) {
+
+ @Override
+ public void onConfirmButtonPressed(
+ DialogInterface dialog) {
+ dialog.dismiss();
+ DBWriter.markAllItemsRead(getActivity());
+ Toast.makeText(getActivity(), R.string.mark_all_read_msg, Toast.LENGTH_SHORT).show();
+ }
+ };
+ conDialog.createNewDialog().show();
return true;
case R.id.episode_filter_item:
boolean newVal = !item.isChecked();
@@ -210,7 +262,7 @@ public class NewEpisodesFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
- ((MainActivity) getActivity()).getSupportActionBar().setTitle(R.string.all_episodes_label);
+ ((MainActivity) getActivity()).getSupportActionBar().setTitle(R.string.new_episodes_label);
View root = inflater.inflate(R.layout.new_episodes_fragment, container, false);
@@ -229,6 +281,33 @@ public class NewEpisodesFragment extends Fragment {
}
});
+ listView.setRemoveListener(new DragSortListView.RemoveListener() {
+ @Override
+ public void remove(int which) {
+ Log.d(TAG, "remove("+which+")");
+ stopItemLoader();
+ FeedItem item = (FeedItem) listView.getAdapter().getItem(which);
+ DBWriter.markItemRead(getActivity(), item.getId(), true);
+ undoBarController.showUndoBar(false,
+ getString(R.string.marked_as_read_label), new FeedItemUndoToken(item,
+ which)
+ );
+ }
+ });
+
+ 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.markItemRead(getActivity(), itemId, false);
+ }
+ }
+ });
+
final int secondColor = (UserPreferences.getTheme() == R.style.Theme_AntennaPod_Dark) ? R.color.swipe_refresh_secondary_color_dark : R.color.swipe_refresh_secondary_color_light;
if (!itemsLoaded) {
@@ -254,6 +333,7 @@ public class NewEpisodesFragment extends Fragment {
downloadObserver.onResume();
}
listAdapter.notifyDataSetChanged();
+ restoreScrollPosition();
getActivity().supportInvalidateOptionsMenu();
updateShowOnlyEpisodesListViewState();
}
@@ -332,7 +412,7 @@ public class NewEpisodesFragment extends Fragment {
private void updateShowOnlyEpisodes() {
SharedPreferences prefs = getActivity().getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
- showOnlyNewEpisodes = prefs.getBoolean(PREF_EPISODE_FILTER_BOOL, false);
+ showOnlyNewEpisodes = prefs.getBoolean(PREF_EPISODE_FILTER_BOOL, true);
}
private void setShowOnlyNewEpisodes(boolean newVal) {
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java
index f6d2d5d07..ab38af106 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java
@@ -34,6 +34,8 @@ import de.danoeh.antennapod.menuhandler.NavDrawerActivity;
public class PlaybackHistoryFragment extends ListFragment {
private static final String TAG = "PlaybackHistoryFragment";
+ private static final int EVENTS = EventDistributor.PLAYBACK_HISTORY_UPDATE |
+ EventDistributor.PLAYER_STATUS_UPDATE;
private List<FeedItem> playbackHistory;
private QueueAccess queue;
@@ -167,7 +169,7 @@ public class PlaybackHistoryFragment extends ListFragment {
@Override
public void update(EventDistributor eventDistributor, Integer arg) {
- if ((arg & EventDistributor.PLAYBACK_HISTORY_UPDATE) != 0) {
+ if ((arg & EVENTS) != 0) {
startItemLoader();
getActivity().supportInvalidateOptionsMenu();
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java
index ca8543b4c..70a231cad 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java
@@ -2,10 +2,12 @@ package de.danoeh.antennapod.fragment;
import android.app.Activity;
import android.content.Context;
+import android.content.DialogInterface;
+import android.content.SharedPreferences;
import android.os.AsyncTask;
-import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
+import android.os.Parcelable;
import android.support.v4.app.Fragment;
import android.support.v7.widget.SearchView;
import android.util.Log;
@@ -30,6 +32,7 @@ import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.adapter.DefaultActionButtonCallback;
import de.danoeh.antennapod.adapter.QueueListAdapter;
import de.danoeh.antennapod.core.asynctask.DownloadObserver;
+import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
import de.danoeh.antennapod.core.feed.EventDistributor;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedItem;
@@ -41,6 +44,8 @@ import de.danoeh.antennapod.core.storage.DBTasks;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.storage.DownloadRequester;
import de.danoeh.antennapod.core.util.QueueSorter;
+import de.danoeh.antennapod.core.util.gui.FeedItemUndoToken;
+import de.danoeh.antennapod.core.util.gui.UndoBarController;
import de.danoeh.antennapod.menuhandler.MenuItemUtils;
import de.danoeh.antennapod.menuhandler.NavDrawerActivity;
@@ -51,13 +56,16 @@ 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;
+ EventDistributor.QUEUE_UPDATE |
+ EventDistributor.PLAYER_STATUS_UPDATE;
private DragSortListView listView;
private QueueListAdapter listAdapter;
private TextView txtvEmpty;
private ProgressBar progLoading;
+ private UndoBarController undoBarController;
+
private List<FeedItem> queue;
private List<Downloader> downloaderList;
@@ -65,6 +73,10 @@ public class QueueFragment extends Fragment {
private boolean viewsCreated = false;
private boolean isUpdatingFeeds = false;
+ private static final String PREFS = "QueueFragment";
+ private static final String PREF_KEY_LIST_TOP = "list_top";
+ private static final String PREF_KEY_LIST_SELECTION = "list_selection";
+
private AtomicReference<Activity> activity = new AtomicReference<Activity>();
private DownloadObserver downloadObserver = null;
@@ -103,6 +115,12 @@ public class QueueFragment extends Fragment {
}
@Override
+ public void onPause() {
+ super.onPause();
+ saveScrollPosition();
+ }
+
+ @Override
public void onStop() {
super.onStop();
EventDistributor.getInstance().unregister(contentUpdate);
@@ -115,10 +133,35 @@ public class QueueFragment extends Fragment {
this.activity.set((MainActivity) activity);
}
+ private void saveScrollPosition() {
+ SharedPreferences prefs = getActivity().getSharedPreferences(PREFS, Context.MODE_PRIVATE);
+ SharedPreferences.Editor editor = prefs.edit();
+ View v = listView.getChildAt(0);
+ int top = (v == null) ? 0 : (v.getTop() - listView.getPaddingTop());
+ editor.putInt(PREF_KEY_LIST_SELECTION, listView.getFirstVisiblePosition());
+ editor.putInt(PREF_KEY_LIST_TOP, top);
+ editor.commit();
+ }
+
+ private void restoreScrollPosition() {
+ SharedPreferences prefs = getActivity().getSharedPreferences(PREFS, Context.MODE_PRIVATE);
+ int listSelection = prefs.getInt(PREF_KEY_LIST_SELECTION, 0);
+ int top = prefs.getInt(PREF_KEY_LIST_TOP, 0);
+ if(listSelection > 0 || top > 0) {
+ listView.setSelectionFromTop(listSelection, top);
+ // restore once, then forget
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putInt(PREF_KEY_LIST_SELECTION, 0);
+ editor.putInt(PREF_KEY_LIST_TOP, 0);
+ editor.commit();
+ }
+ }
+
private void resetViewState() {
unregisterForContextMenu(listView);
listAdapter = null;
activity.set(null);
+ undoBarController = null;
viewsCreated = false;
blockDownloadObserverUpdate = false;
if (downloadObserver != null) {
@@ -175,6 +218,21 @@ public class QueueFragment extends Fragment {
DBTasks.refreshAllFeeds(getActivity(), feeds);
}
return true;
+ case R.id.clear_queue:
+ // make sure the user really wants to clear the queue
+ ConfirmationDialog conDialog = new ConfirmationDialog(getActivity(),
+ R.string.clear_queue_label,
+ R.string.clear_queue_confirmation_msg) {
+
+ @Override
+ public void onConfirmButtonPressed(
+ DialogInterface dialog) {
+ dialog.dismiss();
+ DBWriter.clearQueue(getActivity());
+ }
+ };
+ conDialog.createNewDialog().show();
+ return true;
case R.id.queue_sort_alpha_asc:
QueueSorter.sort(getActivity(), QueueSorter.Rule.ALPHA_ASC, true);
return true;
@@ -285,9 +343,31 @@ public class QueueFragment extends Fragment {
@Override
public void remove(int which) {
+ Log.d(TAG, "remove("+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)
+ );
}
});
+ 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);
+ }
+ }
+ });
+
+
registerForContextMenu(listView);
if (!itemsLoaded) {
@@ -313,6 +393,8 @@ public class QueueFragment extends Fragment {
}
listAdapter.notifyDataSetChanged();
+ restoreScrollPosition();
+
// we need to refresh the options menu because it sometimes
// needs data that may have just been loaded.
getActivity().supportInvalidateOptionsMenu();
@@ -347,6 +429,33 @@ public class QueueFragment extends Fragment {
}
@Override
+ public long getItemDownloadedBytes(FeedItem item) {
+ if (downloaderList != null) {
+ for (Downloader downloader : downloaderList) {
+ if (downloader.getDownloadRequest().getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA
+ && downloader.getDownloadRequest().getFeedfileId() == item.getMedia().getId()) {
+ Log.d(TAG, "downloaded bytes: " + downloader.getDownloadRequest().getSoFar());
+ return downloader.getDownloadRequest().getSoFar();
+ }
+ }
+ }
+ return 0;
+ }
+
+ @Override
+ public long getItemDownloadSize(FeedItem item) {
+ if (downloaderList != null) {
+ for (Downloader downloader : downloaderList) {
+ if (downloader.getDownloadRequest().getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA
+ && downloader.getDownloadRequest().getFeedfileId() == item.getMedia().getId()) {
+ Log.d(TAG, "downloaded size: " + downloader.getDownloadRequest().getSize());
+ return downloader.getDownloadRequest().getSize();
+ }
+ }
+ }
+ return 0;
+ }
+ @Override
public int getItemDownloadProgressPercent(FeedItem item) {
if (downloaderList != null) {
for (Downloader downloader : downloaderList) {
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagFragment.java
index c8cdbcfed..e2450f03d 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagFragment.java
@@ -24,11 +24,11 @@ public class TagFragment extends PodcastListFragment {
private GpodnetTag tag;
- public static TagFragment newInstance(String tagName) {
- Validate.notNull(tagName);
+ public static TagFragment newInstance(GpodnetTag tag) {
+ Validate.notNull(tag);
TagFragment fragment = new TagFragment();
Bundle args = new Bundle();
- args.putString("tag", tagName);
+ args.putParcelable("tag", tag);
fragment.setArguments(args);
return fragment;
}
@@ -38,14 +38,14 @@ public class TagFragment extends PodcastListFragment {
super.onCreate(savedInstanceState);
Bundle args = getArguments();
- Validate.isTrue(args != null && args.getString("tag") != null, "args invalid");
- tag = new GpodnetTag(args.getString("tag"));
+ Validate.isTrue(args != null && args.getParcelable("tag") != null, "args invalid");
+ tag = args.getParcelable("tag");
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
- ((MainActivity) getActivity()).getMainActivtyActionBar().setTitle(tag.getName());
+ ((MainActivity) getActivity()).getMainActivtyActionBar().setTitle(tag.getTitle());
}
@Override
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagListFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagListFragment.java
index 24e0e4caa..cc87407b4 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagListFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagListFragment.java
@@ -10,14 +10,13 @@ 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 java.util.ArrayList;
import java.util.List;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
+import de.danoeh.antennapod.adapter.gpodnet.TagListAdapter;
import de.danoeh.antennapod.core.gpoddernet.GpodnetService;
import de.danoeh.antennapod.core.gpoddernet.GpodnetServiceException;
import de.danoeh.antennapod.core.gpoddernet.model.GpodnetTag;
@@ -67,9 +66,9 @@ public class TagListFragment extends ListFragment {
getListView().setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- String selectedTag = (String) getListAdapter().getItem(position);
+ GpodnetTag tag = (GpodnetTag) getListAdapter().getItem(position);
MainActivity activity = (MainActivity) getActivity();
- activity.loadChildFragment(TagFragment.newInstance(selectedTag));
+ activity.loadChildFragment(TagFragment.newInstance(tag));
}
});
@@ -77,6 +76,12 @@ public class TagListFragment extends ListFragment {
}
@Override
+ public void onResume() {
+ super.onResume();
+ ((MainActivity) getActivity()).getMainActivtyActionBar().setTitle(R.string.add_feed_label);
+ }
+
+ @Override
public void onDestroyView() {
super.onDestroyView();
cancelLoadTask();
@@ -121,11 +126,7 @@ public class TagListFragment extends ListFragment {
final Context context = getActivity();
if (context != null) {
if (gpodnetTags != null) {
- List<String> tagNames = new ArrayList<String>();
- for (GpodnetTag tag : gpodnetTags) {
- tagNames.add(tag.getName());
- }
- setListAdapter(new ArrayAdapter<String>(context, android.R.layout.simple_list_item_1, tagNames));
+ setListAdapter(new TagListAdapter(context, android.R.layout.simple_list_item_1, gpodnetTags));
} else if (exception != null) {
TextView txtvError = new TextView(getActivity());
txtvError.setText(exception.getMessage());
diff --git a/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java
index b62fd22b2..efb4adb01 100644
--- a/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java
+++ b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java
@@ -1,6 +1,7 @@
package de.danoeh.antennapod.menuhandler;
import android.content.Context;
+import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.util.Log;
@@ -10,6 +11,7 @@ import android.view.MenuItem;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.BuildConfig;
+import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.storage.DBTasks;
import de.danoeh.antennapod.core.storage.DBWriter;
@@ -51,8 +53,8 @@ public class FeedMenuHandler {
*
* @throws DownloadRequestException
*/
- public static boolean onOptionsItemClicked(Context context, MenuItem item,
- Feed selectedFeed) throws DownloadRequestException {
+ public static boolean onOptionsItemClicked(final Context context, final MenuItem item,
+ final Feed selectedFeed) throws DownloadRequestException {
switch (item.getItemId()) {
case R.id.refresh_item:
DBTasks.refreshFeed(context, selectedFeed);
@@ -61,7 +63,18 @@ public class FeedMenuHandler {
DBTasks.refreshCompleteFeed(context, selectedFeed);
break;
case R.id.mark_all_read_item:
- DBWriter.markFeedRead(context, selectedFeed.getId());
+ ConfirmationDialog conDialog = new ConfirmationDialog(context,
+ R.string.mark_all_read_label,
+ R.string.mark_all_read_feed_confirmation_msg) {
+
+ @Override
+ public void onConfirmButtonPressed(
+ DialogInterface dialog) {
+ dialog.dismiss();
+ DBWriter.markFeedRead(context, selectedFeed.getId());
+ }
+ };
+ conDialog.createNewDialog().show();
break;
case R.id.visit_website_item:
Uri uri = Uri.parse(selectedFeed.getLink());
diff --git a/app/src/main/java/de/danoeh/antennapod/menuhandler/MenuItemUtils.java b/app/src/main/java/de/danoeh/antennapod/menuhandler/MenuItemUtils.java
index 05d6ded4d..fc942ce20 100644
--- a/app/src/main/java/de/danoeh/antennapod/menuhandler/MenuItemUtils.java
+++ b/app/src/main/java/de/danoeh/antennapod/menuhandler/MenuItemUtils.java
@@ -14,7 +14,7 @@ public class MenuItemUtils extends de.danoeh.antennapod.core.menuhandler.MenuIte
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.setShowAsAction(item, MenuItemCompat.SHOW_AS_ACTION_ALWAYS);
MenuItemCompat.setActionView(item, searchView);
return item;
}
diff --git a/app/src/main/java/de/danoeh/antennapod/preferences/CustomEditTextPreference.java b/app/src/main/java/de/danoeh/antennapod/preferences/CustomEditTextPreference.java
new file mode 100644
index 000000000..898a56004
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/preferences/CustomEditTextPreference.java
@@ -0,0 +1,33 @@
+package de.danoeh.antennapod.preferences;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.os.Build;
+import android.preference.EditTextPreference;
+import android.util.AttributeSet;
+
+import de.danoeh.antennapod.R;
+
+public class CustomEditTextPreference extends EditTextPreference {
+
+ public CustomEditTextPreference(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ public CustomEditTextPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public CustomEditTextPreference(Context context) {
+ super(context);
+ }
+
+ @Override
+ protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {
+ if(Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
+ builder.setInverseBackgroundForced(true);
+ getEditText().setTextColor(getContext().getResources().getColor(R.color.black));
+ }
+ }
+
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java b/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java
index ffac05321..227ea8dfb 100644
--- a/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java
+++ b/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java
@@ -9,10 +9,14 @@ import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.preference.CheckBoxPreference;
+import android.preference.EditTextPreference;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceScreen;
+import android.text.Editable;
+import android.text.TextWatcher;
import android.util.Log;
+import android.widget.EditText;
import android.widget.Toast;
import java.io.File;
@@ -59,8 +63,6 @@ public class PreferenceController {
public static final String PREF_GPODNET_LOGOUT = "pref_gpodnet_logout";
public static final String PREF_GPODNET_HOSTNAME = "pref_gpodnet_hostname";
public static final String PREF_EXPANDED_NOTIFICATION = "prefExpandNotify";
- private static final String PREF_PERSISTENT_NOTIFICATION = "prefPersistNotify";
-
private final PreferenceUI ui;
@@ -216,6 +218,52 @@ public class PreferenceController {
}
}
);
+ ui.findPreference(UserPreferences.PREF_PARALLEL_DOWNLOADS)
+ .setOnPreferenceChangeListener(
+ new Preference.OnPreferenceChangeListener() {
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object o) {
+ if (o instanceof String) {
+ try {
+ int value = Integer.valueOf((String) o);
+ if (1 <= value && value <= 50) {
+ setParallelDownloadsText(value);
+ return true;
+ }
+ } catch(NumberFormatException e) {
+ return false;
+ }
+ }
+ return false;
+ }
+ }
+ );
+ // validate and set correct value: number of downloads between 1 and 50 (inclusive)
+ final EditText ev = ((EditTextPreference)ui.findPreference(UserPreferences.PREF_PARALLEL_DOWNLOADS)).getEditText();
+ ev.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {}
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ if(s.length() > 0) {
+ try {
+ int value = Integer.valueOf(s.toString());
+ if (value <= 0) {
+ ev.setText("1");
+ } else if (value > 50) {
+ ev.setText("50");
+ }
+ } catch(NumberFormatException e) {
+ ev.setText("6");
+ }
+ ev.setSelection(ev.getText().length());
+ }
+ }
+ });
ui.findPreference(UserPreferences.PREF_EPISODE_CACHE_SIZE)
.setOnPreferenceChangeListener(
new Preference.OnPreferenceChangeListener() {
@@ -302,6 +350,7 @@ public class PreferenceController {
public void onResume() {
checkItemVisibility();
+ setParallelDownloadsText(UserPreferences.getParallelDownloads());
setEpisodeCacheSizeText(UserPreferences.getEpisodeCacheSize());
setDataFolderText();
updateGpodnetPreferenceScreen();
@@ -381,6 +430,15 @@ public class PreferenceController {
.setEnabled(UserPreferences.isEnableAutodownload());
}
+
+ private void setParallelDownloadsText(int downloads) {
+ final Resources res = ui.getActivity().getResources();
+
+ String s = Integer.toString(downloads)
+ + res.getString(R.string.parallel_downloads_suffix);
+ ui.findPreference(UserPreferences.PREF_PARALLEL_DOWNLOADS).setSummary(s);
+ }
+
private void setEpisodeCacheSizeText(int cacheSize) {
final Resources res = ui.getActivity().getResources();
diff --git a/app/src/main/java/de/danoeh/antennapod/receiver/PowerConnectionReceiver.java b/app/src/main/java/de/danoeh/antennapod/receiver/PowerConnectionReceiver.java
index 0e7784381..f050e031d 100644
--- a/app/src/main/java/de/danoeh/antennapod/receiver/PowerConnectionReceiver.java
+++ b/app/src/main/java/de/danoeh/antennapod/receiver/PowerConnectionReceiver.java
@@ -13,16 +13,19 @@ import de.danoeh.antennapod.core.storage.DownloadRequester;
// modified from http://developer.android.com/training/monitoring-device-state/battery-monitoring.html
// and ConnectivityActionReceiver.java
+// Updated based on http://stackoverflow.com/questions/20833241/android-charge-intent-has-no-extra-data
+// Since the intent doesn't have the EXTRA_STATUS like the android.com article says it does
+// (though it used to)
public class PowerConnectionReceiver extends BroadcastReceiver {
private static final String TAG = "PowerConnectionReceiver";
@Override
public void onReceive(Context context, Intent intent) {
- int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
- boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING ||
- status == BatteryManager.BATTERY_STATUS_FULL;
+ final String action = intent.getAction();
- if (isCharging) {
+ Log.d(TAG, "charging intent: " + action);
+
+ if (Intent.ACTION_POWER_CONNECTED.equals(action)) {
Log.d(TAG, "charging, starting auto-download");
// we're plugged in, this is a great time to auto-download if everything else is
// right. So, even if the user allows auto-dl on battery, let's still start
diff --git a/app/src/main/java/de/danoeh/antennapod/receiver/SPAReceiver.java b/app/src/main/java/de/danoeh/antennapod/receiver/SPAReceiver.java
index 359a546f6..d15108bfe 100644
--- a/app/src/main/java/de/danoeh/antennapod/receiver/SPAReceiver.java
+++ b/app/src/main/java/de/danoeh/antennapod/receiver/SPAReceiver.java
@@ -5,15 +5,17 @@ import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.widget.Toast;
+
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.Arrays;
+import java.util.Date;
+
import de.danoeh.antennapod.BuildConfig;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.storage.DownloadRequestException;
import de.danoeh.antennapod.core.storage.DownloadRequester;
-import org.apache.commons.lang3.StringUtils;
-
-import java.util.Arrays;
-import java.util.Date;
/**
* Receives intents from AntennaPod Single Purpose apps
@@ -34,7 +36,7 @@ public class SPAReceiver extends BroadcastReceiver{
if (feedUrls != null) {
if (BuildConfig.DEBUG) Log.d(TAG, "Received feeds list: " + Arrays.toString(feedUrls));
for (String url : feedUrls) {
- Feed f = new Feed(url, new Date());
+ Feed f = new Feed(url, new Date(0));
try {
DownloadRequester.getInstance().downloadFeed(context, f);
} catch (DownloadRequestException e) {
diff --git a/app/src/main/res/layout/addfeed.xml b/app/src/main/res/layout/addfeed.xml
index 09502eb7b..b7babbafa 100644
--- a/app/src/main/res/layout/addfeed.xml
+++ b/app/src/main/res/layout/addfeed.xml
@@ -1,100 +1,107 @@
<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:orientation="vertical">
+<ScrollView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:scrollbars="vertical">
- <ScrollView
+ <LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_alignParentTop="true"
- android:scrollbars="vertical">
+ android:paddingTop="8dp"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:paddingBottom="8dp"
+ android:orientation="vertical">
- <RelativeLayout
+ <TextView
+ android:id="@+id/txtvFeedurl"
android:layout_width="match_parent"
- android:layout_height="wrap_content">
+ android:layout_height="wrap_content"
+ style="@style/AntennaPod.TextView.Heading"
+ android:text="@string/txtvfeedurl_label"/>
- <TextView
- android:id="@+id/txtvFeedurl"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentTop="true"
- android:layout_margin="16dp"
- style="@style/AntennaPod.TextView.Heading"
- android:text="@string/txtvfeedurl_label"/>
+ <EditText
+ android:id="@+id/etxtFeedurl"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="4dp"
+ android:hint="@string/etxtFeedurlHint"
+ android:inputType="textUri"/>
- <EditText
- android:id="@+id/etxtFeedurl"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_below="@id/txtvFeedurl"
- android:layout_margin="8dp"
- android:hint="@string/etxtFeedurlHint"
- android:inputType="textUri"/>
+ <Button
+ android:id="@+id/butConfirm"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dp"
+ android:text="@string/confirm_label"/>
- <Button
- android:id="@+id/butConfirm"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_below="@id/etxtFeedurl"
- android:layout_margin="8dp"
- android:text="@string/confirm_label"/>
+ <View
+ android:id="@+id/divider1"
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:layout_margin="16dp"
+ android:background="?android:attr/listDivider"/>
- <TextView
- android:id="@+id/txtvPodcastDirectories"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_below="@id/butConfirm"
- android:layout_margin="8dp"
- style="@style/AntennaPod.TextView.Heading"
- android:text="@string/podcastdirectories_label"/>
+ <TextView
+ android:id="@+id/txtvPodcastDirectories"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/divider1"
+ style="@style/AntennaPod.TextView.Heading"
+ android:text="@string/podcastdirectories_label"/>
- <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"/>
+ <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_marginTop="4dp"/>
- <Button
- android:id="@+id/butBrowseGpoddernet"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_below="@id/txtvPodcastDirectoriesDescr"
- android:layout_margin="8dp"
- android:text="@string/browse_gpoddernet_label"/>
+ <Button
+ android:id="@+id/butBrowseGpoddernet"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dp"
+ android:text="@string/browse_gpoddernet_label"/>
+ <Button
+ android:id="@+id/butSearchItunes"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dp"
+ android:text="@string/search_itunes_label"/>
- <TextView
- android:id="@+id/txtvOpmlImport"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_below="@id/butBrowseGpoddernet"
- android:layout_margin="8dp"
- style="@style/AntennaPod.TextView.Heading"
- android:text="@string/opml_import_label"/>
+ <View
+ android:id="@+id/divider2"
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:layout_margin="16dp"
+ android:background="?android:attr/listDivider"/>
+
+ <TextView
+ android:id="@+id/txtvOpmlImport"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ style="@style/AntennaPod.TextView.Heading"
+ android:text="@string/opml_import_label"/>
- <TextView
- android:id="@+id/txtvOpmlImportExpl"
- android:layout_width="match_parent"
- 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"/>
+ <TextView
+ android:id="@+id/txtvOpmlImportExpl"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="4dp"
+ android:textSize="@dimen/text_size_medium"
+ android:text="@string/opml_import_txtv_button_lable"/>
+
+ <Button
+ android:id="@+id/butOpmlImport"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dp"
+ android:text="@string/opml_import_label"/>
- <Button
- android:id="@+id/butOpmlImport"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_below="@id/txtvOpmlImportExpl"
- android:layout_marginBottom="8dp"
- android:layout_marginLeft="8dp"
- android:layout_marginRight="8dp"
- android:text="@string/opml_import_label"/>
- </RelativeLayout>
- </ScrollView>
+ </LinearLayout>
-</RelativeLayout> \ No newline at end of file
+</ScrollView>
diff --git a/app/src/main/res/layout/cover_fragment.xml b/app/src/main/res/layout/cover_fragment.xml
index 7d86346e3..18540aa1f 100644
--- a/app/src/main/res/layout/cover_fragment.xml
+++ b/app/src/main/res/layout/cover_fragment.xml
@@ -13,7 +13,7 @@
android:layout_height="match_parent"
android:layout_gravity="center"
android:adjustViewBounds="true"
- android:scaleType="centerCrop"
+ android:scaleType="centerInside"
tools:src="@android:drawable/sym_def_app_icon" />
</RelativeLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/feeditem_fragment_header.xml b/app/src/main/res/layout/feeditem_fragment_header.xml
index 5956ae062..a21488306 100644
--- a/app/src/main/res/layout/feeditem_fragment_header.xml
+++ b/app/src/main/res/layout/feeditem_fragment_header.xml
@@ -16,7 +16,7 @@
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:orientation="horizontal"
- android:paddingBottom="8dp">
+ android:paddingBottom="0dp">
<ImageView
android:id="@+id/imgvCover"
@@ -59,6 +59,29 @@
android:maxLines="5"
tools:text="Podcast title"
tools:background="@android:color/holo_green_dark" />
+
+ <TextView
+ android:id="@+id/txtvDuration"
+ style="@style/AntennaPod.TextView.ListItemSecondaryTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@id/imgvCover"
+ android:layout_below="@id/txtvTitle"
+ android:layout_marginLeft="16dp"
+ tools:text="00:42:23"
+ tools:background="@android:color/holo_green_dark"/>
+
+ <TextView
+ android:id="@+id/txtvPublished"
+ style="@style/AntennaPod.TextView.ListItemSecondaryTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toLeftOf="@id/butMoreActions"
+ android:layout_marginRight="8dp"
+ tools:text="Jan 23"
+ tools:background="@android:color/holo_green_dark"
+ android:layout_below="@+id/txtvTitle"/>
+
</RelativeLayout>
<ProgressBar
diff --git a/app/src/main/res/layout/fragment_itunes_search.xml b/app/src/main/res/layout/fragment_itunes_search.xml
new file mode 100644
index 000000000..17ffe349b
--- /dev/null
+++ b/app/src/main/res/layout/fragment_itunes_search.xml
@@ -0,0 +1,26 @@
+<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.ITunesSearchActivity">
+<android.support.v7.widget.SearchView
+ android:id="@+id/itunes_search_view"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ />
+<GridView
+ android:id="@+id/gridView"
+ android:layout_below="@id/itunes_search_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:clipToPadding="false"
+ android:columnWidth="200dp"
+ android:gravity="center"
+ android:horizontalSpacing="8dp"
+ android:numColumns="auto_fit"
+ android:paddingBottom="@dimen/list_vertical_padding"
+ android:paddingTop="@dimen/list_vertical_padding"
+ android:stretchMode="columnWidth"
+ android:verticalSpacing="8dp"
+ tools:listitem="@layout/gpodnet_podcast_listitem" />
+</RelativeLayout>
diff --git a/app/src/main/res/layout/gpodnet_podcast_listitem.xml b/app/src/main/res/layout/gpodnet_podcast_listitem.xml
index 2ade8e478..84c6c280e 100644
--- a/app/src/main/res/layout/gpodnet_podcast_listitem.xml
+++ b/app/src/main/res/layout/gpodnet_podcast_listitem.xml
@@ -23,16 +23,60 @@
tools:src="@drawable/ic_stat_antenna_default"
tools:background="@android:color/holo_green_dark" />
+ <LinearLayout
+ android:id="@+id/subscribers_container"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignTop="@id/txtvTitle"
+ android:layout_alignParentRight="true"
+ android:layout_marginRight="@dimen/listitem_threeline_horizontalpadding"
+ android:orientation="horizontal">
+
+ <ImageView
+ android:id="@+id/imgFeed"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_marginRight="-4dp"
+ android:src="?attr/feed" />
+
+ <TextView
+ android:id="@+id/txtvSubscribers"
+ style="@style/AntennaPod.TextView.ListItemSecondaryTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:lines="1"
+ tools:text="150"
+ tools:background="@android:color/holo_green_dark" />
+
+ </LinearLayout>
+
<TextView
android:id="@+id/txtvTitle"
style="@style/AntennaPod.TextView.ListItemPrimaryTitle"
- android:layout_width="match_parent"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- android:layout_marginBottom="@dimen/listitem_threeline_verticalpadding"
+ android:layout_marginBottom="@dimen/list_vertical_padding"
android:layout_marginRight="@dimen/listitem_threeline_horizontalpadding"
android:layout_toRightOf="@id/imgvCover"
- android:maxLines="1"
- tools:text="Podcast title"
+ android:layout_toLeftOf="@id/subscribers_container"
+ android:layout_alignTop="@id/imgvCover"
+ android:lines="1"
+ tools:text="Title"
tools:background="@android:color/holo_green_dark" />
+
+ <TextView
+ android:id="@+id/txtvUrl"
+ style="android:style/TextAppearance.Small"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginRight="@dimen/listitem_threeline_horizontalpadding"
+ android:layout_toRightOf="@id/imgvCover"
+ android:layout_below="@id/txtvTitle"
+ android:textSize="14sp"
+ android:textColor="?android:attr/textColorSecondary"
+ android:ellipsize="middle"
+ android:maxLines="2"
+ tools:text="http://www.example.com/feed"
+ tools:background="@android:color/holo_green_dark"/>
+
</RelativeLayout>
diff --git a/app/src/main/res/layout/gpodnet_tag_listitem.xml b/app/src/main/res/layout/gpodnet_tag_listitem.xml
new file mode 100644
index 000000000..9e545e59d
--- /dev/null
+++ b/app/src/main/res/layout/gpodnet_tag_listitem.xml
@@ -0,0 +1,34 @@
+<?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="wrap_content"
+ android:gravity="center_vertical"
+ tools:background="@android:color/darker_gray">
+
+ <TextView
+ android:id="@+id/txtvTitle"
+ style="@style/AntennaPod.TextView.ListItemPrimaryTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="@dimen/listitem_threeline_horizontalpadding"
+ android:layout_marginTop="@dimen/listitem_threeline_verticalpadding"
+ android:layout_marginBottom="@dimen/listitem_threeline_verticalpadding"
+ android:lines="1"
+ tools:text="Tag Title"
+ tools:background="@android:color/holo_green_dark" />
+
+ <TextView
+ android:id="@+id/txtvUsage"
+ style="@style/AntennaPod.TextView.ListItemSecondaryTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_marginRight="@dimen/listitem_threeline_horizontalpadding"
+ android:layout_marginTop="@dimen/listitem_threeline_verticalpadding"
+ android:layout_marginBottom="@dimen/listitem_threeline_verticalpadding"
+ tools:text="301"
+ tools:background="@android:color/holo_green_dark"/>
+
+</RelativeLayout>
diff --git a/app/src/main/res/layout/itunes_podcast_listitem.xml b/app/src/main/res/layout/itunes_podcast_listitem.xml
new file mode 100644
index 000000000..41b1f495f
--- /dev/null
+++ b/app/src/main/res/layout/itunes_podcast_listitem.xml
@@ -0,0 +1,38 @@
+<?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="@dimen/listitem_threeline_height"
+tools:background="@android:color/darker_gray">
+
+<ImageView
+ android:id="@+id/imgvCover"
+ android:layout_width="@dimen/thumbnail_length_itemlist"
+ android:layout_height="@dimen/thumbnail_length_itemlist"
+ android:layout_alignParentLeft="true"
+ android:layout_centerVertical="true"
+ android:layout_marginBottom="@dimen/listitem_threeline_verticalpadding"
+ android:layout_marginLeft="@dimen/listitem_threeline_horizontalpadding"
+ android:layout_marginRight="8dp"
+ android:layout_marginTop="@dimen/listitem_threeline_verticalpadding"
+ android:adjustViewBounds="true"
+ android:contentDescription="@string/cover_label"
+ android:cropToPadding="true"
+ android:scaleType="fitXY"
+ tools:src="@drawable/ic_stat_antenna_default"
+ tools:background="@android:color/holo_green_dark" />
+
+<TextView
+ android:id="@+id/txtvTitle"
+ style="@style/AntennaPod.TextView.ListItemPrimaryTitle"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_marginBottom="@dimen/listitem_threeline_verticalpadding"
+ android:layout_marginRight="@dimen/listitem_threeline_horizontalpadding"
+ android:layout_toRightOf="@id/imgvCover"
+ android:maxLines="1"
+ tools:text="Podcast title"
+ tools:background="@android:color/holo_green_dark" />
+</RelativeLayout>
diff --git a/app/src/main/res/layout/new_episodes_fragment.xml b/app/src/main/res/layout/new_episodes_fragment.xml
index 19db02f1d..e90171630 100644
--- a/app/src/main/res/layout/new_episodes_fragment.xml
+++ b/app/src/main/res/layout/new_episodes_fragment.xml
@@ -16,7 +16,8 @@
android:paddingBottom="@dimen/list_vertical_padding"
android:clipToPadding="false"
dslv:collapsed_height="2dp"
- dslv:drag_enabled="false"
+ 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"
@@ -49,4 +50,18 @@
tools:layout_height="64dp"
tools:background="@android:color/holo_red_light"/>
+ <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/app/src/main/res/layout/opml_import.xml b/app/src/main/res/layout/opml_import.xml
index 3e45a0400..5ece4f09f 100644
--- a/app/src/main/res/layout/opml_import.xml
+++ b/app/src/main/res/layout/opml_import.xml
@@ -1,32 +1,92 @@
<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout
+ 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"
android:orientation="vertical"
+ android:paddingTop="8dp"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:paddingBottom="8dp"
tools:background="@android:color/darker_gray">
<TextView
+ android:id="@+id/txtvHeadingExplanation1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_margin="8dp"
- android:text="@string/opml_import_explanation"
+ style="@style/AntennaPod.TextView.Heading"
+ android:text="@string/txtvfeedurl_label"/>
+
+ <TextView
+ android:id="@+id/txtvExplanation1"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/opml_import_explanation_1"
+ android:textSize="@dimen/text_size_medium"
+ android:layout_marginTop="4dp"
tools:background="@android:color/holo_green_dark" />
+ <Button
+ android:id="@+id/butChooseFileFromFilesystem"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:layout_marginTop="8dp"
+ android:text="@string/choose_file_from_filesystem" />
+
+ <View
+ android:id="@+id/divider1"
+ android:layout_width="fill_parent"
+ android:layout_height="1dp"
+ android:layout_margin="16dp"
+ android:background="?android:attr/listDivider"/>
+
<TextView
- android:id="@+id/txtvPath"
+ android:id="@+id/txtvHeadingExplanation2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_margin="8dp"
- tools:text="Path"
+ style="@style/AntennaPod.TextView.Heading"
+ android:text="@string/txtvfeedurl_label"/>
+
+ <TextView
+ android:id="@+id/txtvExplanation2"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/opml_import_explanation_2"
+ android:textSize="@dimen/text_size_medium"
+ android:layout_marginTop="4dp"
tools:background="@android:color/holo_green_dark" />
<Button
- android:id="@+id/butStartImport"
- android:layout_width="wrap_content"
+ android:id="@+id/butChooseFileFromExternal"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
- android:layout_margin="8dp"
- android:text="@string/start_import_label" />
+ android:layout_marginTop="8dp"
+ android:text="@string/choose_file_from_external_application" />
+
+ <View
+ android:id="@+id/divider2"
+ android:layout_width="fill_parent"
+ android:layout_height="1dp"
+ android:layout_margin="16dp"
+ android:background="?android:attr/listDivider"/>
+
+ <TextView
+ android:id="@+id/txtvHeadingExplanation3"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ style="@style/AntennaPod.TextView.Heading"
+ android:text="@string/txtvfeedurl_label"/>
+
+ <TextView
+ android:id="@+id/txtvExplanation3"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/opml_import_explanation_3"
+ android:textSize="@dimen/text_size_medium"
+ android:layout_marginTop="4dp"
+ tools:background="@android:color/holo_green_dark" />
</LinearLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/queue_fragment.xml b/app/src/main/res/layout/queue_fragment.xml
index d184eb28d..307d95a8d 100644
--- a/app/src/main/res/layout/queue_fragment.xml
+++ b/app/src/main/res/layout/queue_fragment.xml
@@ -20,7 +20,8 @@
dslv:float_alpha="0.6"
dslv:float_background_color="?attr/dragview_float_background"
dslv:max_drag_scroll_speed="0.5"
- dslv:remove_enabled="false"
+ dslv:remove_enabled="true"
+ dslv:remove_mode="flingRemove"
dslv:slide_shuffle_speed="0.3"
dslv:sort_enabled="true"
dslv:track_drag_sort="true"
@@ -42,4 +43,18 @@
android:indeterminateOnly="true"
android:visibility="gone" />
-</FrameLayout> \ No newline at end of file
+ <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>
diff --git a/app/src/main/res/layout/queue_listitem.xml b/app/src/main/res/layout/queue_listitem.xml
index 74c6ed785..bc5b951a2 100644
--- a/app/src/main/res/layout/queue_listitem.xml
+++ b/app/src/main/res/layout/queue_listitem.xml
@@ -9,11 +9,12 @@
<ImageView
android:id="@+id/drag_handle"
- android:layout_width="24dp"
+ android:layout_width="100dp"
android:layout_height="match_parent"
- android:layout_margin="8dp"
+ android:layout_marginLeft="8dp"
+ android:layout_marginRight="-64dp"
android:contentDescription="@string/drag_handle_content_description"
- android:scaleType="center"
+ android:scaleType="fitXY"
android:src="?attr/dragview_background"
tools:src="@drawable/ic_drag_handle"
tools:background="@android:color/holo_green_dark" />
@@ -32,7 +33,7 @@
<RelativeLayout
android:layout_width="0dp"
- android:layout_height="match_parent"
+ android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/listitem_threeline_verticalpadding"
android:layout_marginLeft="@dimen/listitem_threeline_textleftpadding"
android:layout_marginRight="@dimen/listitem_threeline_textrightpadding"
@@ -40,46 +41,72 @@
android:layout_weight="1"
tools:background="@android:color/holo_red_dark">
+ <!-- order is important, pubDate first! -->
+ <TextView
+ android:id="@+id/txtvPubDate"
+ style="@style/AntennaPod.TextView.ListItemSecondaryTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:lines="2"
+ android:layout_alignParentRight="true"
+ android:layout_alignParentTop="true"
+ android:layout_marginLeft="8dp"
+ android:gravity="right|bottom"
+ android:text="Feb\n12"
+ tools:background="@android:color/holo_blue_light" />
+
<TextView
android:id="@+id/txtvTitle"
style="@style/AntennaPod.TextView.ListItemPrimaryTitle"
- android:layout_width="0dp"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_toLeftOf="@id/txtvPubDate"
android:layout_alignParentLeft="true"
- android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:text="Queue item title"
+ android:ellipsize="end"
tools:background="@android:color/holo_blue_light" />
<RelativeLayout
android:id="@+id/bottom_bar"
android:layout_width="0dp"
android:layout_height="wrap_content"
+ android:layout_below="@id/txtvTitle"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
- android:layout_alignParentRight="true"
- android:layout_marginTop="16dp">
+ android:layout_alignParentRight="true">
<TextView
- android:id="@+id/txtvPosition"
+ android:id="@+id/txtvProgressLeft"
style="@style/AntennaPod.TextView.ListItemSecondaryTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
+ android:layout_marginBottom="0dp"
android:text="00:42:23"
- tools:background="@android:color/holo_blue_light" />
+ tools:background="@android:color/holo_blue_light"/>
+
+ <TextView
+ android:id="@+id/txtvProgressRight"
+ style="@style/AntennaPod.TextView.ListItemSecondaryTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_marginBottom="0dp"
+ tools:text="Jan 23"
+ tools:background="@android:color/holo_green_dark" />
<ProgressBar
- android:id="@+id/pbar_download_progress"
+ android:id="@+id/progressBar"
style="?android:attr/progressBarStyleHorizontal"
- android:layout_width="0dp"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_marginLeft="8dp"
- android:layout_toRightOf="@id/txtvPosition"
+ android:layout_below="@id/txtvProgressLeft"
+ android:layout_marginTop="-2dp"
android:max="100"
tools:background="@android:color/holo_blue_light" />
+
</RelativeLayout>
</RelativeLayout>
diff --git a/app/src/main/res/menu/feedlist.xml b/app/src/main/res/menu/feedlist.xml
index 8d2d9e367..b6512e828 100644
--- a/app/src/main/res/menu/feedlist.xml
+++ b/app/src/main/res/menu/feedlist.xml
@@ -7,7 +7,7 @@
android:icon="?attr/navigation_refresh"
android:menuCategory="container"
android:title="@string/refresh_label"
- custom:showAsAction="ifRoom">
+ custom:showAsAction="always">
</item>
<item
android:id="@+id/refresh_complete_item"
diff --git a/app/src/main/res/menu/new_episodes.xml b/app/src/main/res/menu/new_episodes.xml
index d74e70b3b..72661a17e 100644
--- a/app/src/main/res/menu/new_episodes.xml
+++ b/app/src/main/res/menu/new_episodes.xml
@@ -7,7 +7,7 @@
android:id="@+id/refresh_item"
android:title="@string/refresh_label"
android:menuCategory="container"
- custom:showAsAction="ifRoom"
+ custom:showAsAction="always"
android:icon="?attr/navigation_refresh"/>
<item
diff --git a/app/src/main/res/menu/queue.xml b/app/src/main/res/menu/queue.xml
index b85279e5a..c7dd4d371 100644
--- a/app/src/main/res/menu/queue.xml
+++ b/app/src/main/res/menu/queue.xml
@@ -7,10 +7,17 @@
android:id="@+id/refresh_item"
android:title="@string/refresh_label"
android:menuCategory="container"
- custom:showAsAction="ifRoom"
+ custom:showAsAction="always"
android:icon="?attr/navigation_refresh"/>
<item
+ android:id="@+id/clear_queue"
+ android:title="Clear Queue"
+ android:menuCategory="container"
+ custom:showAsAction="collapseActionView"
+ android:icon="?attr/navigation_accept"/>
+
+ <item
android:id="@+id/queue_sort"
android:title="@string/sort">
diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml
index 5169eac5a..6d14349d5 100644
--- a/app/src/main/res/xml/preferences.xml
+++ b/app/src/main/res/xml/preferences.xml
@@ -22,6 +22,17 @@
android:summary="@string/pref_persistNotify_sum"
android:title="@string/pref_persistNotify_title"/>
</PreferenceCategory>
+
+ <PreferenceCategory android:title="@string/queue_label">
+ <CheckBoxPreference
+ android:defaultValue="false"
+ android:enabled="true"
+ android:key="prefQueueAddToFront"
+ android:summary="@string/pref_queueAddToFront_sum"
+ android:title="@string/pref_queueAddToFront_title"/>
+ />
+ </PreferenceCategory>
+
<PreferenceCategory android:title="@string/playback_pref">
<CheckBoxPreference
android:defaultValue="true"
@@ -77,13 +88,17 @@
android:key="prefAutoUpdateIntervall"
android:summary="@string/pref_autoUpdateIntervall_sum"
android:title="@string/pref_autoUpdateIntervall_title"/>
-
<CheckBoxPreference
android:defaultValue="false"
android:enabled="true"
android:key="prefMobileUpdate"
android:summary="@string/pref_mobileUpdate_sum"
android:title="@string/pref_mobileUpdate_title"/>
+ <de.danoeh.antennapod.preferences.CustomEditTextPreference
+ android:defaultValue="6"
+ android:inputType="number"
+ android:key="prefParallelDownloads"
+ android:title="@string/pref_parallel_downloads_title"/>
<ListPreference
android:defaultValue="20"
android:entries="@array/episode_cache_size_entries"
@@ -111,6 +126,7 @@
</PreferenceScreen>
</PreferenceCategory>
+
<PreferenceCategory android:title="@string/services_label">
<PreferenceScreen
android:key="prefFlattrSettings"