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/handler/FeedHandlerTest.java25
-rw-r--r--app/src/androidTest/java/de/test/antennapod/service/download/HttpDownloaderTest.java2
-rw-r--r--app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceMediaPlayerTest.java24
-rw-r--r--app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceTaskManagerTest.java2
-rw-r--r--app/src/androidTest/java/de/test/antennapod/storage/DBReaderTest.java48
-rw-r--r--app/src/androidTest/java/de/test/antennapod/storage/DBTasksTest.java56
-rw-r--r--app/src/androidTest/java/de/test/antennapod/storage/DBTestUtils.java2
-rw-r--r--app/src/androidTest/java/de/test/antennapod/storage/DBWriterTest.java34
-rw-r--r--app/src/androidTest/java/de/test/antennapod/ui/MainActivityTest.java2
-rw-r--r--app/src/androidTest/java/de/test/antennapod/ui/PreferencesTest.java38
-rw-r--r--app/src/androidTest/java/de/test/antennapod/ui/UITestUtils.java5
-rw-r--r--app/src/androidTest/java/de/test/antennapod/util/playback/TimelineTest.java2
-rw-r--r--app/src/main/AndroidManifest.xml14
-rw-r--r--app/src/main/assets/LICENSE_GLIDE.txt94
-rw-r--r--app/src/main/assets/LICENSE_PICASSO.txt13
-rw-r--r--app/src/main/assets/LICENSE_STACKBLUR.txt71
-rw-r--r--app/src/main/java/de/danoeh/antennapod/AppConfig.java7
-rw-r--r--app/src/main/java/de/danoeh/antennapod/PodcastApp.java13
-rw-r--r--app/src/main/java/de/danoeh/antennapod/UpdateManager.java88
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java82
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/DefaultOnlineFeedViewActivity.java12
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/FeedInfoActivity.java101
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java152
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java17
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/OpmlImportFromPathActivity.java53
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java7
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/ActionButtonUtils.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/AdapterUtils.java15
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesListAdapter.java69
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/DefaultActionButtonCallback.java20
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java14
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/DownloadedEpisodesListAdapter.java12
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java16
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java20
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/QueueListAdapter.java76
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/SearchlistAdapter.java20
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/gpodnet/PodcastListAdapter.java12
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/itunes/ItunesAdapter.java68
-rw-r--r--app/src/main/java/de/danoeh/antennapod/config/ApplicationCallbacksImpl.java5
-rw-r--r--app/src/main/java/de/danoeh/antennapod/config/ClientConfigurator.java1
-rw-r--r--app/src/main/java/de/danoeh/antennapod/config/StorageCallbacksImpl.java153
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java414
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/TimeDialog.java6
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java35
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java10
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java16
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java65
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java129
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java87
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java18
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java6
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java19
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java33
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/RunningDownloadsFragment.java11
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/PodcastListFragment.java5
-rw-r--r--app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java68
-rw-r--r--app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java18
-rw-r--r--app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java134
-rw-r--r--app/src/main/java/de/danoeh/antennapod/receiver/ConnectivityActionReceiver.java17
-rw-r--r--app/src/main/java/de/danoeh/antennapod/service/PlayerWidgetService.java2
-rw-r--r--app/src/main/res/layout-v14/authentication_dialog.xml10
-rw-r--r--app/src/main/res/layout-v14/download_authentication_activity.xml10
-rw-r--r--app/src/main/res/layout/addfeed.xml53
-rw-r--r--app/src/main/res/layout/authentication_dialog.xml10
-rw-r--r--app/src/main/res/layout/cover_fragment.xml4
-rw-r--r--app/src/main/res/layout/download_authentication_activity.xml10
-rw-r--r--app/src/main/res/layout/episodes_apply_action_fragment.xml120
-rw-r--r--app/src/main/res/layout/feedinfo.xml57
-rw-r--r--app/src/main/res/layout/feeditem_fragment_header.xml3
-rw-r--r--app/src/main/res/layout/fragment_itunes_search.xml2
-rw-r--r--app/src/main/res/layout/gpodnet_podcast_list.xml2
-rw-r--r--app/src/main/res/layout/gpodnetauth_credentials.xml10
-rw-r--r--app/src/main/res/layout/new_episodes_listitem.xml42
-rw-r--r--app/src/main/res/layout/queue_fragment.xml30
-rw-r--r--app/src/main/res/layout/queue_listitem.xml37
-rw-r--r--app/src/main/res/menu/allepisodes_context.xml27
-rw-r--r--app/src/main/res/menu/episodes_apply_action_options.xml55
-rw-r--r--app/src/main/res/menu/feedinfo.xml6
-rw-r--r--app/src/main/res/menu/feeditem_options.xml29
-rw-r--r--app/src/main/res/menu/feeditemlist_context.xml28
-rw-r--r--app/src/main/res/menu/feedlist.xml34
-rw-r--r--app/src/main/res/menu/mediaplayer.xml35
-rw-r--r--app/src/main/res/menu/nav_feed_context.xml19
-rw-r--r--app/src/main/res/menu/queue_context.xml29
-rw-r--r--app/src/main/res/xml/preferences.xml55
-rw-r--r--app/src/main/templates/about.html10
88 files changed, 2347 insertions, 944 deletions
diff --git a/app/src/androidTest/java/de/test/antennapod/handler/FeedHandlerTest.java b/app/src/androidTest/java/de/test/antennapod/handler/FeedHandlerTest.java
index 52067c971..13a0e3f78 100644
--- a/app/src/androidTest/java/de/test/antennapod/handler/FeedHandlerTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/handler/FeedHandlerTest.java
@@ -2,15 +2,9 @@ package de.test.antennapod.handler;
import android.content.Context;
import android.test.InstrumentationTestCase;
-import de.danoeh.antennapod.core.feed.*;
-import de.danoeh.antennapod.core.syndication.handler.FeedHandler;
-import de.danoeh.antennapod.core.syndication.handler.UnsupportedFeedtypeException;
-import de.test.antennapod.util.syndication.feedgenerator.AtomGenerator;
-import de.test.antennapod.util.syndication.feedgenerator.FeedGenerator;
-import de.test.antennapod.util.syndication.feedgenerator.RSS2Generator;
+
import org.xml.sax.SAXException;
-import javax.xml.parsers.ParserConfigurationException;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -19,6 +13,19 @@ import java.util.ArrayList;
import java.util.Date;
import java.util.List;
+import javax.xml.parsers.ParserConfigurationException;
+
+import de.danoeh.antennapod.core.feed.Chapter;
+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.syndication.handler.FeedHandler;
+import de.danoeh.antennapod.core.syndication.handler.UnsupportedFeedtypeException;
+import de.test.antennapod.util.syndication.feedgenerator.AtomGenerator;
+import de.test.antennapod.util.syndication.feedgenerator.FeedGenerator;
+import de.test.antennapod.util.syndication.feedgenerator.RSS2Generator;
+
/**
* Tests for FeedHandler
*/
@@ -162,10 +169,10 @@ public class FeedHandlerTest extends InstrumentationTestCase {
for (int i = 0; i < numItems; i++) {
FeedItem item = new FeedItem(0, "item-" + i, "http://example.com/item-" + i,
- "http://example.com/items/" + i, new Date(i*60000), false, feed);
+ "http://example.com/items/" + i, new Date(i*60000), FeedItem.UNPLAYED, feed);
feed.getItems().add(item);
if (withFeedMedia) {
- item.setMedia(new FeedMedia(0, item, 4711, 0, 100, "audio/mp3", null, "http://example.com/media-" + i,
+ item.setMedia(new FeedMedia(0, item, 4711, 0, 1024*1024, "audio/mp3", null, "http://example.com/media-" + i,
false, null, 0));
}
}
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 443fbed7e..4a5883c64 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
@@ -43,7 +43,7 @@ public class HttpDownloaderTest extends InstrumentationTestCase {
@Override
protected void setUp() throws Exception {
super.setUp();
- UserPreferences.createInstance(getInstrumentation().getTargetContext());
+ UserPreferences.init(getInstrumentation().getTargetContext());
destDir = getInstrumentation().getTargetContext().getExternalFilesDir(DOWNLOAD_DIR);
assertNotNull(destDir);
assertTrue(destDir.exists());
diff --git a/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceMediaPlayerTest.java b/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceMediaPlayerTest.java
index aac4c245a..42fa84d20 100644
--- a/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceMediaPlayerTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceMediaPlayerTest.java
@@ -3,15 +3,9 @@ package de.test.antennapod.service.playback;
import android.content.Context;
import android.media.RemoteControlClient;
import android.test.InstrumentationTestCase;
-import de.danoeh.antennapod.core.feed.Feed;
-import de.danoeh.antennapod.core.feed.FeedItem;
-import de.danoeh.antennapod.core.feed.FeedMedia;
-import de.danoeh.antennapod.core.service.playback.PlaybackServiceMediaPlayer;
-import de.danoeh.antennapod.core.service.playback.PlayerStatus;
-import de.danoeh.antennapod.core.storage.PodDBAdapter;
-import de.danoeh.antennapod.core.util.playback.Playable;
-import de.test.antennapod.util.service.download.HTTPBin;
+
import junit.framework.AssertionFailedError;
+
import org.apache.commons.io.IOUtils;
import java.io.File;
@@ -23,6 +17,16 @@ import java.util.Date;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import de.danoeh.antennapod.core.feed.Feed;
+import de.danoeh.antennapod.core.feed.FeedItem;
+import de.danoeh.antennapod.core.feed.FeedMedia;
+import de.danoeh.antennapod.core.feed.FeedPreferences;
+import de.danoeh.antennapod.core.service.playback.PlaybackServiceMediaPlayer;
+import de.danoeh.antennapod.core.service.playback.PlayerStatus;
+import de.danoeh.antennapod.core.storage.PodDBAdapter;
+import de.danoeh.antennapod.core.util.playback.Playable;
+import de.test.antennapod.util.service.download.HTTPBin;
+
/**
* Test class for PlaybackServiceMediaPlayer
*/
@@ -113,8 +117,10 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
private Playable writeTestPlayable(String downloadUrl, String fileUrl) {
final Context c = getInstrumentation().getTargetContext();
Feed f = new Feed(0, new Date(), "f", "l", "d", null, null, null, null, "i", null, null, "l", false);
+ FeedPreferences prefs = new FeedPreferences(f.getId(), false, FeedPreferences.AutoDeleteAction.NO, null, null);
+ f.setPreferences(prefs);
f.setItems(new ArrayList<FeedItem>());
- FeedItem i = new FeedItem(0, "t", "i", "l", new Date(), false, f);
+ FeedItem i = new FeedItem(0, "t", "i", "l", new Date(), FeedItem.UNPLAYED, f);
f.getItems().add(i);
FeedMedia media = new FeedMedia(0, i, 0, 0, 0, "audio/wav", fileUrl, downloadUrl, fileUrl != null, null, 0);
i.setMedia(media);
diff --git a/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceTaskManagerTest.java b/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceTaskManagerTest.java
index d74128c2f..edb576249 100644
--- a/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceTaskManagerTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceTaskManagerTest.java
@@ -51,7 +51,7 @@ public class PlaybackServiceTaskManagerTest extends InstrumentationTestCase {
Feed f = new Feed(0, new Date(), "title", "link", "d", null, null, null, null, "id", null, "null", "url", false);
f.setItems(new ArrayList<FeedItem>());
for (int i = 0; i < NUM_ITEMS; i++) {
- f.getItems().add(new FeedItem(0, pref + i, pref + i, "link", new Date(), true, f));
+ f.getItems().add(new FeedItem(0, pref + i, pref + i, "link", new Date(), FeedItem.PLAYED, f));
}
PodDBAdapter adapter = new PodDBAdapter(c);
adapter.open();
diff --git a/app/src/androidTest/java/de/test/antennapod/storage/DBReaderTest.java b/app/src/androidTest/java/de/test/antennapod/storage/DBReaderTest.java
index 95d2ce58a..11a34813a 100644
--- a/app/src/androidTest/java/de/test/antennapod/storage/DBReaderTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/storage/DBReaderTest.java
@@ -42,38 +42,6 @@ public class DBReaderTest extends InstrumentationTestCase {
adapter.close();
}
- private void expiredFeedListTestHelper(long lastUpdate, long expirationTime, boolean shouldReturn) {
- final Context context = getInstrumentation().getTargetContext();
- Feed feed = new Feed(0, new Date(lastUpdate), "feed", "link", "descr", null,
- null, null, null, "feed", null, null, "url", false, new FlattrStatus(), false, null, null, false);
- feed.setItems(new ArrayList<FeedItem>());
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- adapter.setCompleteFeed(feed);
- adapter.close();
-
- assertTrue(feed.getId() != 0);
- List<Feed> expiredFeeds = DBReader.getExpiredFeedsList(context, expirationTime);
- assertNotNull(expiredFeeds);
- if (shouldReturn) {
- assertTrue(expiredFeeds.size() == 1);
- assertTrue(expiredFeeds.get(0).getId() == feed.getId());
- } else {
- assertTrue(expiredFeeds.isEmpty());
- }
- }
-
- public void testGetExpiredFeedsListShouldReturnFeed() {
- final long expirationTime = 1000 * 60 * 60; // 1 hour
- expiredFeedListTestHelper(System.currentTimeMillis() - expirationTime - 1, expirationTime, true);
- }
-
- public void testGetExpiredFeedsListShouldNotReturnFeed() {
- final long expirationTime = 1000 * 60 * 60; // 1 hour
- expiredFeedListTestHelper(System.currentTimeMillis() - expirationTime / 2, expirationTime, false);
- }
-
-
public void testGetFeedList() {
final Context context = getInstrumentation().getTargetContext();
List<Feed> feeds = saveFeedlist(context, 10, 0, false);
@@ -277,7 +245,7 @@ public class DBReaderTest extends InstrumentationTestCase {
int i = random.nextInt(numItems);
if (!unread.contains(items.get(i))) {
FeedItem item = items.get(i);
- item.setRead(false);
+ item.setPlayed(false);
unread.add(item);
}
}
@@ -297,7 +265,7 @@ public class DBReaderTest extends InstrumentationTestCase {
assertNotNull(unreadSaved);
assertTrue(unread.size() == unreadSaved.size());
for (FeedItem item : unreadSaved) {
- assertFalse(item.isRead());
+ assertFalse(item.isPlayed());
}
}
@@ -310,11 +278,11 @@ public class DBReaderTest extends InstrumentationTestCase {
for (int i = 0; i < unread.size(); i++) {
unreadIds[i] = unread.get(i).getId();
}
- LongList unreadSaved = DBReader.getNewItemIds(context);
+ List<FeedItem> unreadSaved = DBReader.getUnreadItemsList(context);
assertNotNull(unreadSaved);
assertTrue(unread.size() == unreadSaved.size());
for(int i=0; i < unreadSaved.size(); i++) {
- long savedId = unreadSaved.get(i);
+ long savedId = unreadSaved.get(i).getId();
boolean found = false;
for (long id : unreadIds) {
if (id == savedId) {
@@ -385,13 +353,13 @@ public class DBReaderTest extends InstrumentationTestCase {
final int NUM_FEEDS = 10;
final int NUM_ITEMS = 10;
final int NUM_QUEUE = 1;
- final int NUM_UNREAD = 2;
+ final int NUM_NEW = 2;
List<Feed> feeds = DBTestUtils.saveFeedlist(context, NUM_FEEDS, NUM_ITEMS, true);
PodDBAdapter adapter = new PodDBAdapter(context);
adapter.open();
- for (int i = 0; i < NUM_UNREAD; i++) {
+ for (int i = 0; i < NUM_NEW; i++) {
FeedItem item = feeds.get(0).getItems().get(i);
- item.setRead(false);
+ item.setNew();
adapter.setSingleFeedItem(item);
}
List<FeedItem> queue = new ArrayList<FeedItem>();
@@ -405,7 +373,7 @@ public class DBReaderTest extends InstrumentationTestCase {
DBReader.NavDrawerData navDrawerData = DBReader.getNavDrawerData(context);
assertEquals(NUM_FEEDS, navDrawerData.feeds.size());
- assertEquals(NUM_UNREAD, navDrawerData.numNewItems);
+ assertEquals(NUM_NEW, navDrawerData.numNewItems);
assertEquals(NUM_QUEUE, navDrawerData.queueSize);
}
diff --git a/app/src/androidTest/java/de/test/antennapod/storage/DBTasksTest.java b/app/src/androidTest/java/de/test/antennapod/storage/DBTasksTest.java
index 16f50cf28..944fc7792 100644
--- a/app/src/androidTest/java/de/test/antennapod/storage/DBTasksTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/storage/DBTasksTest.java
@@ -12,6 +12,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
+import java.util.concurrent.TimeUnit;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedItem;
@@ -66,6 +67,8 @@ public class DBTasksTest extends InstrumentationTestCase {
SharedPreferences.Editor prefEdit = PreferenceManager.getDefaultSharedPreferences(context.getApplicationContext()).edit();
prefEdit.putString(UserPreferences.PREF_EPISODE_CACHE_SIZE, Integer.toString(EPISODE_CACHE_SIZE));
prefEdit.commit();
+
+ UserPreferences.init(context);
}
@FlakyTest(tolerance = 3)
@@ -77,7 +80,7 @@ public class DBTasksTest extends InstrumentationTestCase {
feed.setItems(items);
List<File> files = new ArrayList<File>();
for (int i = 0; i < NUM_ITEMS; i++) {
- FeedItem item = new FeedItem(0, "title", "id", "link", new Date(), true, feed);
+ FeedItem item = new FeedItem(0, "title", "id", "link", new Date(), FeedItem.PLAYED, feed);
File f = new File(destFolder, "file " + i);
assertTrue(f.createNewFile());
@@ -115,7 +118,7 @@ public class DBTasksTest extends InstrumentationTestCase {
feed.setItems(items);
List<File> files = new ArrayList<File>();
for (int i = 0; i < NUM_ITEMS; i++) {
- FeedItem item = new FeedItem(0, "title", "id", "link", new Date(), false, feed);
+ FeedItem item = new FeedItem(0, "title", "id", "link", new Date(), FeedItem.UNPLAYED, feed);
File f = new File(destFolder, "file " + i);
assertTrue(f.createNewFile());
@@ -150,7 +153,7 @@ public class DBTasksTest extends InstrumentationTestCase {
feed.setItems(items);
List<File> files = new ArrayList<File>();
for (int i = 0; i < NUM_ITEMS; i++) {
- FeedItem item = new FeedItem(0, "title", "id", "link", new Date(), true, feed);
+ FeedItem item = new FeedItem(0, "title", "id", "link", new Date(), FeedItem.PLAYED, feed);
File f = new File(destFolder, "file " + i);
assertTrue(f.createNewFile());
@@ -207,14 +210,14 @@ public class DBTasksTest extends InstrumentationTestCase {
Feed feed = new Feed("url", new Date(), "title");
feed.setItems(new ArrayList<FeedItem>());
for (int i = 0; i < NUM_ITEMS; i++) {
- feed.getItems().add(new FeedItem(0, "item " + i, "id " + i, "link " + i, new Date(), false, feed));
+ feed.getItems().add(new FeedItem(0, "item " + i, "id " + i, "link " + i, new Date(), FeedItem.UNPLAYED, feed));
}
Feed newFeed = DBTasks.updateFeed(context, feed)[0];
assertTrue(newFeed == feed);
assertTrue(feed.getId() != 0);
for (FeedItem item : feed.getItems()) {
- assertFalse(item.isRead());
+ assertFalse(item.isPlayed());
assertTrue(item.getId() != 0);
}
}
@@ -241,7 +244,7 @@ public class DBTasksTest extends InstrumentationTestCase {
final Feed feed = new Feed("url", new Date(), "title");
feed.setItems(new ArrayList<FeedItem>());
for (int i = 0; i < NUM_ITEMS_OLD; i++) {
- feed.getItems().add(new FeedItem(0, "item " + i, "id " + i, "link " + i, new Date(i), true, feed));
+ feed.getItems().add(new FeedItem(0, "item " + i, "id " + i, "link " + i, new Date(i), FeedItem.PLAYED, feed));
}
PodDBAdapter adapter = new PodDBAdapter(context);
adapter.open();
@@ -260,7 +263,7 @@ public class DBTasksTest extends InstrumentationTestCase {
}
for (int i = NUM_ITEMS_OLD; i < NUM_ITEMS_NEW + NUM_ITEMS_OLD; i++) {
- feed.getItems().add(0, new FeedItem(0, "item " + i, "id " + i, "link " + i, new Date(i), true, feed));
+ feed.getItems().add(0, new FeedItem(0, "item " + i, "id " + i, "link " + i, new Date(i), FeedItem.UNPLAYED, feed));
}
final Feed newFeed = DBTasks.updateFeed(context, feed)[0];
@@ -274,7 +277,6 @@ public class DBTasksTest extends InstrumentationTestCase {
updatedFeedTest(feedFromDB, feedID, itemIDs, NUM_ITEMS_OLD, NUM_ITEMS_NEW);
}
- @FlakyTest(tolerance = 3)
private void updatedFeedTest(final Feed newFeed, long feedID, List<Long> itemIDs, final int NUM_ITEMS_OLD, final int NUM_ITEMS_NEW) {
assertTrue(newFeed.getId() == feedID);
assertTrue(newFeed.getItems().size() == NUM_ITEMS_NEW + NUM_ITEMS_OLD);
@@ -284,7 +286,7 @@ public class DBTasksTest extends InstrumentationTestCase {
FeedItem item = newFeed.getItems().get(i);
assertTrue(item.getFeed() == newFeed);
assertTrue(item.getId() == itemIDs.get(i));
- assertTrue(item.isRead());
+ assertTrue(item.isPlayed());
assertTrue(item.getPubDate().getTime() >= lastDate.getTime());
lastDate = item.getPubDate();
}
@@ -292,43 +294,9 @@ public class DBTasksTest extends InstrumentationTestCase {
FeedItem item = newFeed.getItems().get(i);
assertTrue(item.getFeed() == newFeed);
assertTrue(item.getId() != 0);
- assertFalse(item.isRead());
+ assertFalse(item.isPlayed());
assertTrue(item.getPubDate().getTime() >= lastDate.getTime());
lastDate = item.getPubDate();
}
}
-
- @FlakyTest(tolerance = 3)
- private void expiredFeedListTestHelper(long lastUpdate, long expirationTime, boolean shouldReturn) {
- UserPreferences.setUpdateInterval(context, expirationTime);
- Feed feed = new Feed(0, new Date(lastUpdate), "feed", "link", "descr", null,
- null, null, null, "feed", null, null, "url", false, new FlattrStatus(), false, null, null, false);
- feed.setItems(new ArrayList<FeedItem>());
- PodDBAdapter adapter = new PodDBAdapter(context);
- adapter.open();
- adapter.setCompleteFeed(feed);
- adapter.close();
-
- assertTrue(feed.getId() != 0);
- List<Feed> expiredFeeds = DBTasks.getExpiredFeeds(context);
- assertNotNull(expiredFeeds);
- if (shouldReturn) {
- assertTrue(expiredFeeds.size() == 1);
- assertTrue(expiredFeeds.get(0).getId() == feed.getId());
- } else {
- assertTrue(expiredFeeds.isEmpty());
- }
- }
-
- @FlakyTest(tolerance = 3)
- public void testGetExpiredFeedsTestShouldReturn() {
- final long expirationTime = 1000 * 60 * 60;
- expiredFeedListTestHelper(System.currentTimeMillis() - expirationTime - 1, expirationTime, true);
- }
-
- @FlakyTest(tolerance = 3)
- public void testGetExpiredFeedsTestShouldNotReturn() {
- final long expirationTime = 1000 * 60 * 60;
- expiredFeedListTestHelper(System.currentTimeMillis() - expirationTime / 2, expirationTime, false);
- }
}
diff --git a/app/src/androidTest/java/de/test/antennapod/storage/DBTestUtils.java b/app/src/androidTest/java/de/test/antennapod/storage/DBTestUtils.java
index 4f33cd798..c6f702f3d 100644
--- a/app/src/androidTest/java/de/test/antennapod/storage/DBTestUtils.java
+++ b/app/src/androidTest/java/de/test/antennapod/storage/DBTestUtils.java
@@ -51,7 +51,7 @@ public class DBTestUtils {
f.setItems(new ArrayList<FeedItem>());
for (int j = 0; j < numItems; j++) {
FeedItem item = new FeedItem(0, "item " + j, "id" + j, "link" + j, new Date(),
- true, f, withChapters);
+ FeedItem.PLAYED, f, withChapters);
if (withMedia) {
FeedMedia media = new FeedMedia(item, "url" + j, 1, "audio/mp3");
item.setMedia(media);
diff --git a/app/src/androidTest/java/de/test/antennapod/storage/DBWriterTest.java b/app/src/androidTest/java/de/test/antennapod/storage/DBWriterTest.java
index f3b0c9165..c5fa2f131 100644
--- a/app/src/androidTest/java/de/test/antennapod/storage/DBWriterTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/storage/DBWriterTest.java
@@ -65,7 +65,7 @@ public class DBWriterTest extends InstrumentationTestCase {
Feed feed = new Feed("url", new Date(), "title");
List<FeedItem> items = new ArrayList<FeedItem>();
feed.setItems(items);
- FeedItem item = new FeedItem(0, "Item", "Item", "url", new Date(), true, feed);
+ FeedItem item = new FeedItem(0, "Item", "Item", "url", new Date(), FeedItem.PLAYED, feed);
FeedMedia media = new FeedMedia(0, item, 1, 1, 1, "mime_type", dest.getAbsolutePath(), "download_url", true, null, 0);
item.setMedia(media);
@@ -104,7 +104,7 @@ public class DBWriterTest extends InstrumentationTestCase {
List<File> itemFiles = new ArrayList<File>();
// create items with downloaded media files
for (int i = 0; i < 10; i++) {
- FeedItem item = new FeedItem(0, "Item " + i, "Item" + i, "url", new Date(), true, feed, true);
+ FeedItem item = new FeedItem(0, "Item " + i, "Item" + i, "url", new Date(), FeedItem.PLAYED, feed, true);
feed.getItems().add(item);
File enc = new File(destFolder, "file " + i);
@@ -171,7 +171,7 @@ public class DBWriterTest extends InstrumentationTestCase {
List<File> itemFiles = new ArrayList<File>();
// create items with downloaded media files
for (int i = 0; i < 10; i++) {
- FeedItem item = new FeedItem(0, "Item " + i, "Item" + i, "url", new Date(), true, feed);
+ FeedItem item = new FeedItem(0, "Item " + i, "Item" + i, "url", new Date(), FeedItem.PLAYED, feed);
feed.getItems().add(item);
File enc = new File(destFolder, "file " + i);
@@ -268,7 +268,7 @@ public class DBWriterTest extends InstrumentationTestCase {
// create items
for (int i = 0; i < 10; i++) {
- FeedItem item = new FeedItem(0, "Item " + i, "Item" + i, "url", new Date(), true, feed);
+ FeedItem item = new FeedItem(0, "Item " + i, "Item" + i, "url", new Date(), FeedItem.PLAYED, feed);
feed.getItems().add(item);
}
@@ -320,7 +320,7 @@ public class DBWriterTest extends InstrumentationTestCase {
// create items with images
for (int i = 0; i < 10; i++) {
- FeedItem item = new FeedItem(0, "Item " + i, "Item" + i, "url", new Date(), true, feed);
+ FeedItem item = new FeedItem(0, "Item " + i, "Item" + i, "url", new Date(), FeedItem.PLAYED, feed);
feed.getItems().add(item);
File itemImageFile = new File(destFolder, "item-image-" + i);
FeedImage itemImage = new FeedImage(0, "item-image" + i, itemImageFile.getAbsolutePath(), "url", true);
@@ -378,7 +378,7 @@ public class DBWriterTest extends InstrumentationTestCase {
List<File> itemFiles = new ArrayList<File>();
// create items with downloaded media files
for (int i = 0; i < 10; i++) {
- FeedItem item = new FeedItem(0, "Item " + i, "Item" + i, "url", new Date(), true, feed);
+ FeedItem item = new FeedItem(0, "Item " + i, "Item" + i, "url", new Date(), FeedItem.PLAYED, feed);
feed.getItems().add(item);
File enc = new File(destFolder, "file " + i);
@@ -450,7 +450,7 @@ public class DBWriterTest extends InstrumentationTestCase {
List<File> itemFiles = new ArrayList<File>();
// create items with downloaded media files
for (int i = 0; i < 10; i++) {
- FeedItem item = new FeedItem(0, "Item " + i, "Item" + i, "url", new Date(), true, feed);
+ FeedItem item = new FeedItem(0, "Item " + i, "Item" + i, "url", new Date(), FeedItem.PLAYED, feed);
feed.getItems().add(item);
File enc = new File(destFolder, "file " + i);
@@ -496,7 +496,7 @@ public class DBWriterTest extends InstrumentationTestCase {
final Context context = getInstrumentation().getTargetContext();
Feed feed = new Feed("url", new Date(), "title");
feed.setItems(new ArrayList<FeedItem>());
- FeedItem item = new FeedItem(0, "title", "id", "link", new Date(), true, feed);
+ FeedItem item = new FeedItem(0, "title", "id", "link", new Date(), FeedItem.PLAYED, feed);
FeedMedia media = new FeedMedia(0, item, 10, 0, 1, "mime", null, "url", false, playbackCompletionDate, 0);
feed.getItems().add(item);
item.setMedia(media);
@@ -543,7 +543,7 @@ public class DBWriterTest extends InstrumentationTestCase {
Feed feed = new Feed("url", new Date(), "title");
feed.setItems(new ArrayList<FeedItem>());
for (int i = 0; i < NUM_ITEMS; i++) {
- FeedItem item = new FeedItem(0, "title " + i, "id " + i, "link " + i, new Date(), true, feed);
+ FeedItem item = new FeedItem(0, "title " + i, "id " + i, "link " + i, new Date(), FeedItem.PLAYED, feed);
feed.getItems().add(item);
}
@@ -569,7 +569,7 @@ public class DBWriterTest extends InstrumentationTestCase {
final Context context = getInstrumentation().getTargetContext();
Feed feed = new Feed("url", new Date(), "title");
feed.setItems(new ArrayList<FeedItem>());
- FeedItem item = new FeedItem(0, "title", "id", "link", new Date(), true, feed);
+ FeedItem item = new FeedItem(0, "title", "id", "link", new Date(), FeedItem.PLAYED, feed);
feed.getItems().add(item);
PodDBAdapter adapter = new PodDBAdapter(context);
@@ -593,7 +593,7 @@ public class DBWriterTest extends InstrumentationTestCase {
final Context context = getInstrumentation().getTargetContext();
Feed feed = new Feed("url", new Date(), "title");
feed.setItems(new ArrayList<FeedItem>());
- FeedItem item = new FeedItem(0, "title", "id", "link", new Date(), true, feed);
+ FeedItem item = new FeedItem(0, "title", "id", "link", new Date(), FeedItem.PLAYED, feed);
feed.getItems().add(item);
PodDBAdapter adapter = new PodDBAdapter(context);
@@ -661,7 +661,7 @@ public class DBWriterTest extends InstrumentationTestCase {
Feed feed = new Feed("url", new Date(), "title");
feed.setItems(new ArrayList<FeedItem>());
for (int i = 0; i < NUM_ITEMS; i++) {
- FeedItem item = new FeedItem(0, "title " + i, "id " + i, "link " + i, new Date(), true, feed);
+ FeedItem item = new FeedItem(0, "title " + i, "id " + i, "link " + i, new Date(), FeedItem.PLAYED, feed);
feed.getItems().add(item);
}
@@ -707,7 +707,7 @@ public class DBWriterTest extends InstrumentationTestCase {
Feed feed = new Feed("url", new Date(), "title");
feed.setItems(new ArrayList<FeedItem>());
for (int i = 0; i < NUM_ITEMS; i++) {
- FeedItem item = new FeedItem(0, "title " + i, "id " + i, "link " + i, new Date(), true, feed);
+ FeedItem item = new FeedItem(0, "title " + i, "id " + i, "link " + i, new Date(), FeedItem.PLAYED, feed);
feed.getItems().add(item);
}
@@ -754,7 +754,7 @@ public class DBWriterTest extends InstrumentationTestCase {
Feed feed = new Feed("url", new Date(), "title");
feed.setItems(new ArrayList<FeedItem>());
for (int i = 0; i < NUM_ITEMS; i++) {
- FeedItem item = new FeedItem(0, "title " + i, "id " + i, "link " + i, new Date(), false, feed);
+ FeedItem item = new FeedItem(0, "title " + i, "id " + i, "link " + i, new Date(), FeedItem.UNPLAYED, feed);
feed.getItems().add(item);
}
@@ -771,7 +771,7 @@ public class DBWriterTest extends InstrumentationTestCase {
DBWriter.markFeedRead(context, feed.getId()).get(TIMEOUT, TimeUnit.SECONDS);
List<FeedItem> loadedItems = DBReader.getFeedItemList(context, feed);
for (FeedItem item : loadedItems) {
- assertTrue(item.isRead());
+ assertTrue(item.isPlayed());
}
}
@@ -781,7 +781,7 @@ public class DBWriterTest extends InstrumentationTestCase {
Feed feed = new Feed("url", new Date(), "title");
feed.setItems(new ArrayList<FeedItem>());
for (int i = 0; i < NUM_ITEMS; i++) {
- FeedItem item = new FeedItem(0, "title " + i, "id " + i, "link " + i, new Date(), false, feed);
+ FeedItem item = new FeedItem(0, "title " + i, "id " + i, "link " + i, new Date(), FeedItem.UNPLAYED, feed);
feed.getItems().add(item);
}
@@ -798,7 +798,7 @@ public class DBWriterTest extends InstrumentationTestCase {
DBWriter.markAllItemsRead(context).get(TIMEOUT, TimeUnit.SECONDS);
List<FeedItem> loadedItems = DBReader.getFeedItemList(context, feed);
for (FeedItem item : loadedItems) {
- assertTrue(item.isRead());
+ assertTrue(item.isPlayed());
}
}
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 0326174e3..65c962f01 100644
--- a/app/src/androidTest/java/de/test/antennapod/ui/MainActivityTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/ui/MainActivityTest.java
@@ -78,7 +78,7 @@ public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActiv
openNavDrawer();
solo.clickOnText(solo.getString(R.string.add_feed_label));
solo.enterText(0, feed.getDownload_url());
- solo.clickOnButton(0);
+ solo.clickOnButton(solo.getString(R.string.confirm_label));
solo.waitForActivity(DefaultOnlineFeedViewActivity.class);
solo.waitForView(R.id.butSubscribe);
assertEquals(solo.getString(R.string.subscribe_label), solo.getButton(0).getText().toString());
diff --git a/app/src/androidTest/java/de/test/antennapod/ui/PreferencesTest.java b/app/src/androidTest/java/de/test/antennapod/ui/PreferencesTest.java
index eb1cb9c71..a6af6c544 100644
--- a/app/src/androidTest/java/de/test/antennapod/ui/PreferencesTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/ui/PreferencesTest.java
@@ -39,7 +39,7 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
Timeout.setLargeTimeout(1000);
context = getInstrumentation().getTargetContext();
res = getActivity().getResources();
- UserPreferences.createInstance(context);
+ UserPreferences.init(context);
}
@Override
@@ -231,7 +231,7 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
return pauseForFocusLoss != UserPreferences.shouldPauseForFocusLoss();
}
}, Timeout.getLargeTimeout());
- solo.clickOnText(solo.getString(R.string.pref_auto_delete_title));
+ solo.clickOnText(solo.getString(R.string.pref_pausePlaybackForFocusLoss_title));
solo.waitForCondition(new Condition() {
@Override
public boolean isSatisfied() {
@@ -241,9 +241,9 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
}
public void testDisableUpdateInterval() {
- solo.clickOnText(solo.getString(R.string.pref_autoUpdateIntervall_title));
+ solo.clickOnText(solo.getString(R.string.pref_autoUpdateIntervallOrTime_sum));
solo.waitForDialogToOpen();
- solo.clickOnText(solo.getString(R.string.pref_update_interval_hours_manual));
+ solo.clickOnText(solo.getString(R.string.pref_autoUpdateIntervallOrTime_Disable));
solo.waitForCondition(new Condition() {
@Override
public boolean isSatisfied() {
@@ -253,7 +253,9 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
}
public void testSetUpdateInterval() {
- solo.clickOnText(solo.getString(R.string.pref_autoUpdateIntervall_title));
+ solo.clickOnText(solo.getString(R.string.pref_autoUpdateIntervallOrTime_title));
+ solo.waitForDialogToOpen();
+ solo.clickOnText(solo.getString(R.string.pref_autoUpdateIntervallOrTime_Interval));
solo.waitForDialogToOpen();
String search = "12 " + solo.getString(R.string.pref_update_interval_hours_plural);
solo.clickOnText(search);
@@ -424,30 +426,4 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference
}
}, Timeout.getLargeTimeout());
}
-
- @FlakyTest(tolerance = 3)
- public void testAbout() throws IOException {
- int numViews = 0, numLinks = 0;
- InputStream input = getActivity().getResources().getAssets().open("about.html");
- List<String> lines = IOUtils.readLines(input);
- input.close();
- for(String line : lines) {
- if(line.contains("(View)")) {
- numViews++;
- } else if(line.contains("(Link)")) {
- numLinks++;
- }
- }
- for(int i=0; i < numViews; i++) {
- solo.clickOnText(solo.getString(R.string.about_pref));
- solo.clickOnText("(View)", i);
- solo.goBack();
- }
- for(int i=0; i < numLinks; i++) {
- solo.clickOnText(solo.getString(R.string.about_pref));
- solo.clickOnText("(Link)", i);
- solo.goBack();
- }
- }
-
}
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 613826932..7bbc6e462 100644
--- a/app/src/androidTest/java/de/test/antennapod/ui/UITestUtils.java
+++ b/app/src/androidTest/java/de/test/antennapod/ui/UITestUtils.java
@@ -111,6 +111,9 @@ public class UITestUtils {
private File newMediaFile(String name) throws IOException {
File mediaFile = new File(hostedMediaDir, name);
+ if(mediaFile.exists()) {
+ mediaFile.delete();
+ }
Assert.assertFalse(mediaFile.exists());
InputStream in = context.getAssets().open("testfile.mp3");
@@ -142,7 +145,7 @@ public class UITestUtils {
List<FeedItem> items = new ArrayList<FeedItem>();
for (int j = 0; j < NUM_ITEMS_PER_FEED; j++) {
FeedItem item = new FeedItem(j, "Feed " + (i+1) + ": Item " + (j+1), "item" + j,
- "http://example.com/feed" + i + "/item/" + j, new Date(), false, feed);
+ "http://example.com/feed" + i + "/item/" + j, new Date(), FeedItem.UNPLAYED, feed);
items.add(item);
File mediaFile = newMediaFile("feed-" + i + "-episode-" + j + ".mp3");
diff --git a/app/src/androidTest/java/de/test/antennapod/util/playback/TimelineTest.java b/app/src/androidTest/java/de/test/antennapod/util/playback/TimelineTest.java
index 2c56b71cc..7e535e12c 100644
--- a/app/src/androidTest/java/de/test/antennapod/util/playback/TimelineTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/util/playback/TimelineTest.java
@@ -31,7 +31,7 @@ public class TimelineTest extends InstrumentationTestCase {
}
private Playable newTestPlayable(List<Chapter> chapters, String shownotes) {
- FeedItem item = new FeedItem(0, "Item", "item-id", "http://example.com/item", new Date(), true, null);
+ FeedItem item = new FeedItem(0, "Item", "item-id", "http://example.com/item", new Date(), FeedItem.PLAYED, null);
item.setChapters(chapters);
item.setContentEncoded(shownotes);
FeedMedia media = new FeedMedia(item, "http://example.com/episode", 100, "audio/mp3");
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 25b350aba..5d630ca06 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,9 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="de.danoeh.antennapod"
- android:versionCode="62"
- android:versionName="1.2.2">
-
+ android:versionCode="1030006"
+ android:versionName="1.3">
+ <!--
+ Version code schema:
+ "1.2.3-SNAPSHOT" -> 1020300
+ "1.2.3-RC4" -> 1020304
+ -->
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
@@ -322,6 +326,10 @@
android:scheme="package"/>
</intent-filter>
</receiver>
+
+ <meta-data
+ android:name="de.danoeh.antennapod.core.glide.ApGlideModule"
+ android:value="GlideModule" />
</application>
</manifest>
diff --git a/app/src/main/assets/LICENSE_GLIDE.txt b/app/src/main/assets/LICENSE_GLIDE.txt
new file mode 100644
index 000000000..f5111eeab
--- /dev/null
+++ b/app/src/main/assets/LICENSE_GLIDE.txt
@@ -0,0 +1,94 @@
+License for everything not in third_party and not otherwise marked:
+
+Copyright 2014 Google, Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are
+permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice, this list of
+ conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ of conditions and the following disclaimer in the documentation and/or other materials
+ provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY GOOGLE, INC. ``AS IS'' AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE, INC. OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+The views and conclusions contained in the software and documentation are those of the
+authors and should not be interpreted as representing official policies, either expressed
+or implied, of Google, Inc.
+---------------------------------------------------------------------------------------------
+License for third_party/disklrucache:
+
+Copyright 2012 Jake Wharton
+Copyright 2011 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+---------------------------------------------------------------------------------------------
+License for third_party/gif_decoder:
+
+Copyright (c) 2013 Xcellent Creations, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+---------------------------------------------------------------------------------------------
+License for third_party/gif_encoder/AnimatedGifEncoder.java and
+third_party/gif_encoder/LZWEncoder.java:
+
+No copyright asserted on the source code of this class. May be used for any
+purpose, however, refer to the Unisys LZW patent for restrictions on use of
+the associated LZWEncoder class. Please forward any corrections to
+kweiner@fmsware.com.
+
+-----------------------------------------------------------------------------
+License for third_party/gif_encoder/NeuQuant.java
+
+Copyright (c) 1994 Anthony Dekker
+
+NEUQUANT Neural-Net quantization algorithm by Anthony Dekker, 1994. See
+"Kohonen neural networks for optimal colour quantization" in "Network:
+Computation in Neural Systems" Vol. 5 (1994) pp 351-367. for a discussion of
+the algorithm.
+
+Any party obtaining a copy of these files from the author, directly or
+indirectly, is granted, free of charge, a full and unrestricted irrevocable,
+world-wide, paid up, royalty-free, nonexclusive right and license to deal in
+this software and documentation files (the "Software"), including without
+limitation the rights to use, copy, modify, merge, publish, distribute,
+sublicense, and/or sell copies of the Software, and to permit persons who
+receive copies from any such party to do so, with the only requirement being
+that this copyright notice remain intact.
diff --git a/app/src/main/assets/LICENSE_PICASSO.txt b/app/src/main/assets/LICENSE_PICASSO.txt
deleted file mode 100644
index 0bf6b9f8e..000000000
--- a/app/src/main/assets/LICENSE_PICASSO.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-Copyright 2013 Square, Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
diff --git a/app/src/main/assets/LICENSE_STACKBLUR.txt b/app/src/main/assets/LICENSE_STACKBLUR.txt
new file mode 100644
index 000000000..b66736ccb
--- /dev/null
+++ b/app/src/main/assets/LICENSE_STACKBLUR.txt
@@ -0,0 +1,71 @@
+Apache License, Version 2.0
+
+Version 2.0, January 2004
+
+http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
+
+"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
+
+"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
+
+"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
+
+"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
+
+"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
+
+"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
+
+"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
+
+"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
+
+"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
+
+You must give any other recipients of the Work or Derivative Works a copy of this License; and
+You must cause any modified files to carry prominent notices stating that You changed the files; and
+You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
+If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
+
+You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
+5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work
+To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives.
+
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/app/src/main/java/de/danoeh/antennapod/AppConfig.java b/app/src/main/java/de/danoeh/antennapod/AppConfig.java
deleted file mode 100644
index 24f13d4a3..000000000
--- a/app/src/main/java/de/danoeh/antennapod/AppConfig.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package de.danoeh.antennapod;
-
-public final class AppConfig {
- /** Should be used when setting User-Agent header for HTTP-requests. */
- public final static String USER_AGENT = "AntennaPod/0.9.9.4";
-
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/PodcastApp.java b/app/src/main/java/de/danoeh/antennapod/PodcastApp.java
index 451094909..f47fe3944 100644
--- a/app/src/main/java/de/danoeh/antennapod/PodcastApp.java
+++ b/app/src/main/java/de/danoeh/antennapod/PodcastApp.java
@@ -1,12 +1,14 @@
package de.danoeh.antennapod;
import android.app.Application;
+import android.content.Intent;
import android.content.res.Configuration;
-import de.danoeh.antennapod.core.asynctask.PicassoProvider;
import de.danoeh.antennapod.core.feed.EventDistributor;
import de.danoeh.antennapod.core.preferences.PlaybackPreferences;
import de.danoeh.antennapod.core.preferences.UserPreferences;
+import de.danoeh.antennapod.core.service.FeedMediaSizeService;
+import de.danoeh.antennapod.core.util.NetworkUtils;
import de.danoeh.antennapod.spa.SPAUtil;
/** Main application class. */
@@ -37,12 +39,15 @@ public class PodcastApp extends Application {
singleton = this;
LOGICAL_DENSITY = getResources().getDisplayMetrics().density;
- PicassoProvider.setupPicassoInstance(this);
- UserPreferences.createInstance(this);
- PlaybackPreferences.createInstance(this);
+ UpdateManager.init(this);
+ UserPreferences.init(this);
+ PlaybackPreferences.init(this);
+ NetworkUtils.init(this);
EventDistributor.getInstance();
SPAUtil.sendSPAppsQueryFeedsIntent(this);
+
+ startService(new Intent(this, FeedMediaSizeService.class));
}
public static float getLogicalDensity() {
diff --git a/app/src/main/java/de/danoeh/antennapod/UpdateManager.java b/app/src/main/java/de/danoeh/antennapod/UpdateManager.java
new file mode 100644
index 000000000..2f6bb1b50
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/UpdateManager.java
@@ -0,0 +1,88 @@
+package de.danoeh.antennapod;
+
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.util.Log;
+
+import java.io.File;
+import java.util.List;
+
+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.storage.DBReader;
+import de.danoeh.antennapod.core.storage.DBWriter;
+
+/*
+ * This class's job is do perform maintenance tasks whenever the app has been updated
+ */
+public class UpdateManager {
+
+ public static final String TAG = UpdateManager.class.getSimpleName();
+
+ private static final String PREF_NAME = "app_version";
+ private static final String KEY_VERSION_CODE = "version_code";
+
+ private static int currentVersionCode;
+
+ private static Context context;
+ private static SharedPreferences prefs;
+
+ public static void init(Context context) {
+ UpdateManager.context = context;
+ prefs = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
+ PackageManager pm = context.getPackageManager();
+ try {
+ PackageInfo info = pm.getPackageInfo(context.getPackageName(), 0);
+ currentVersionCode = info.versionCode;
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(TAG, "Failed to obtain package info for package name: " + context.getPackageName(), e);
+ currentVersionCode = 0;
+ return;
+ }
+ final int oldVersionCode = getStoredVersionCode();
+ Log.d(TAG, "old: " + oldVersionCode + ", current: " + currentVersionCode);
+ if(oldVersionCode < currentVersionCode) {
+ onUpgrade(oldVersionCode, currentVersionCode);
+ setCurrentVersionCode();
+ }
+ }
+
+ public static int getStoredVersionCode() {
+ return prefs.getInt(KEY_VERSION_CODE, -1);
+ }
+
+ public static void setCurrentVersionCode() {
+ prefs.edit().putInt(KEY_VERSION_CODE, currentVersionCode).apply();
+ }
+
+ private static void onUpgrade(final int oldVersionCode, final int newVersionCode) {
+ if(oldVersionCode < 1030099) {
+ // delete the now obsolete image cache
+ // from now on, Glide will handle caching images
+ new Thread() {
+ public void run() {
+ List<Feed> feeds = DBReader.getFeedList(context);
+ for (Feed podcast : feeds) {
+ List<FeedItem> episodes = DBReader.getFeedItemList(context, podcast);
+ for (FeedItem episode : episodes) {
+ FeedImage image = episode.getImage();
+ if (image != null && image.isDownloaded() && image.getFile_url() != null) {
+ File imageFile = new File(image.getFile_url());
+ if (imageFile.exists()) {
+ imageFile.delete();
+ }
+ image.setFile_url(null); // calls setDownloaded(false)
+ DBWriter.setFeedImage(context, image);
+ }
+ }
+ }
+ }
+ }.start();
+ }
+ }
+
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java
index b59f6ba35..294acd427 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java
@@ -1,5 +1,6 @@
package de.danoeh.antennapod.activity;
+import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
@@ -13,6 +14,8 @@ import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.widget.Toolbar;
import android.util.Log;
+import android.view.ContextMenu;
+import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
@@ -24,21 +27,26 @@ import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.TextView;
-import com.squareup.picasso.Picasso;
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.load.engine.DiskCacheStrategy;
import org.apache.commons.lang3.StringUtils;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.adapter.ChapterListAdapter;
import de.danoeh.antennapod.adapter.NavListAdapter;
+import de.danoeh.antennapod.core.asynctask.FeedRemover;
+import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
import de.danoeh.antennapod.core.feed.Chapter;
import de.danoeh.antennapod.core.feed.EventDistributor;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.MediaType;
import de.danoeh.antennapod.core.feed.SimpleChapter;
+import de.danoeh.antennapod.core.glide.ApGlideSettings;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.service.playback.PlaybackService;
import de.danoeh.antennapod.core.storage.DBReader;
+import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.util.playback.ExternalMedia;
import de.danoeh.antennapod.core.util.playback.Playable;
import de.danoeh.antennapod.core.util.playback.PlaybackController;
@@ -430,6 +438,7 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc
drawerLayout.closeDrawer(navDrawer);
}
});
+ registerForContextMenu(navList);
drawerToggle.syncState();
findViewById(R.id.nav_settings).setOnClickListener(new View.OnClickListener() {
@@ -549,9 +558,13 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc
}
txtvTitle.setText(media.getEpisodeTitle());
getSupportActionBar().setTitle("");
- Picasso.with(this)
+ Glide.with(this)
.load(media.getImageUri())
- .fit()
+ .placeholder(R.color.light_gray)
+ .error(R.color.light_gray)
+ .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
+ .fitCenter()
+ .dontAnimate()
.into(butShowCover);
setNavButtonVisibility();
@@ -634,6 +647,65 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc
}
}
+ @Override
+ public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
+ super.onCreateContextMenu(menu, v, menuInfo);
+ if(v.getId() != R.id.nav_list) {
+ return;
+ }
+ AdapterView.AdapterContextMenuInfo adapterInfo = (AdapterView.AdapterContextMenuInfo) menuInfo;
+ int position = adapterInfo.position;
+ if(position < navAdapter.getSubscriptionOffset()) {
+ return;
+ }
+ MenuInflater inflater = getMenuInflater();
+ inflater.inflate(R.menu.nav_feed_context, menu);
+ Feed feed = navDrawerData.feeds.get(position - navAdapter.getSubscriptionOffset());
+ menu.setHeaderTitle(feed.getTitle());
+ // episodes are not loaded, so we cannot check if the podcast has new or unplayed ones!
+ }
+
+ @Override
+ public boolean onContextItemSelected(MenuItem item) {
+ AdapterView.AdapterContextMenuInfo menuInfo = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
+ if(menuInfo.targetView.getParent() instanceof ListView == false
+ || ((ListView)menuInfo.targetView.getParent()).getId() != R.id.nav_list) {
+ return false;
+ }
+ int position = menuInfo.position;
+ Feed feed = navDrawerData.feeds.get(position - navAdapter.getSubscriptionOffset());
+ switch(item.getItemId()) {
+ case R.id.mark_all_seen_item:
+ DBWriter.markFeedSeen(this, feed.getId());
+ return true;
+ case R.id.mark_all_read_item:
+ DBWriter.markFeedRead(this, feed.getId());
+ return true;
+ case R.id.remove_item:
+ final FeedRemover remover = new FeedRemover(this, feed) {
+ @Override
+ protected void onPostExecute(Void result) {
+ super.onPostExecute(result);
+ }
+ };
+ ConfirmationDialog conDialog = new ConfirmationDialog(this,
+ R.string.remove_feed_label,
+ R.string.feed_delete_confirmation_msg) {
+ @Override
+ public void onConfirmButtonPressed(
+ DialogInterface dialog) {
+ dialog.dismiss();
+ remover.executeAsync();
+ }
+ };
+ conDialog.createNewDialog().show();
+ return true;
+ default:
+ return super.onContextItemSelected(item);
+ }
+ }
+
+
private DBReader.NavDrawerData navDrawerData;
private AsyncTask<Void, Void, DBReader.NavDrawerData> loadTask;
@@ -708,8 +780,8 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc
}
@Override
- public int getNumberOfUnreadFeedItems(long feedId) {
- return (navDrawerData != null) ? navDrawerData.numUnreadFeedItems.get(feedId) : 0;
+ public int getFeedCounter(long feedId) {
+ return navDrawerData != null ? navDrawerData.feedCounters.get(feedId) : 0;
}
};
}
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 287ae3568..0993ed6d6 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/DefaultOnlineFeedViewActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/DefaultOnlineFeedViewActivity.java
@@ -17,7 +17,8 @@ import android.widget.ListView;
import android.widget.Spinner;
import android.widget.TextView;
-import com.squareup.picasso.Picasso;
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.load.engine.DiskCacheStrategy;
import org.apache.commons.lang3.StringUtils;
import org.jsoup.Jsoup;
@@ -36,6 +37,7 @@ import de.danoeh.antennapod.core.dialog.DownloadRequestErrorDialogCreator;
import de.danoeh.antennapod.core.feed.EventDistributor;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedItem;
+import de.danoeh.antennapod.core.glide.ApGlideSettings;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DownloadRequestException;
import de.danoeh.antennapod.core.storage.DownloadRequester;
@@ -124,9 +126,13 @@ public class DefaultOnlineFeedViewActivity extends OnlineFeedViewActivity {
subscribeButton = (Button) header.findViewById(R.id.butSubscribe);
if (feed.getImage() != null && StringUtils.isNotBlank(feed.getImage().getDownload_url())) {
- Picasso.with(this)
+ Glide.with(this)
.load(feed.getImage().getDownload_url())
- .fit()
+ .placeholder(R.color.light_gray)
+ .error(R.color.light_gray)
+ .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
+ .fitCenter()
+ .dontAnimate()
.into(cover);
}
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/FeedInfoActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/FeedInfoActivity.java
index 5f76a20a8..9cdaf2fc6 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/FeedInfoActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/FeedInfoActivity.java
@@ -2,6 +2,9 @@ package de.danoeh.antennapod.activity;
import android.content.ClipData;
import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
@@ -12,24 +15,31 @@ import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.ImageView;
+import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.joanzapata.android.iconify.Iconify;
-import com.squareup.picasso.Picasso;
import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
import de.danoeh.antennapod.core.dialog.DownloadRequestErrorDialogCreator;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedPreferences;
+import de.danoeh.antennapod.core.glide.ApGlideSettings;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.storage.DownloadRequestException;
+import de.danoeh.antennapod.core.util.IntentUtils;
import de.danoeh.antennapod.core.util.LangUtils;
import de.danoeh.antennapod.menuhandler.FeedMenuHandler;
@@ -38,6 +48,7 @@ import de.danoeh.antennapod.menuhandler.FeedMenuHandler;
*/
public class FeedInfoActivity extends ActionBarActivity {
private static final String TAG = "FeedInfoActivity";
+ private boolean autoDeleteChanged = false;
public static final String EXTRA_FEED_ID = "de.danoeh.antennapod.extra.feedId";
@@ -52,6 +63,7 @@ public class FeedInfoActivity extends ActionBarActivity {
private EditText etxtUsername;
private EditText etxtPassword;
private CheckBox cbxAutoDownload;
+ private Spinner spnAutoDelete;
private final View.OnClickListener copyUrlToClipboard = new View.OnClickListener() {
@Override
@@ -89,6 +101,7 @@ public class FeedInfoActivity extends ActionBarActivity {
txtvAuthor = (TextView) findViewById(R.id.txtvAuthor);
txtvUrl = (TextView) findViewById(R.id.txtvUrl);
cbxAutoDownload = (CheckBox) findViewById(R.id.cbxAutoDownload);
+ spnAutoDelete = (Spinner) findViewById(R.id.spnAutoDelete);
etxtUsername = (EditText) findViewById(R.id.etxtUsername);
etxtPassword = (EditText) findViewById(R.id.etxtPassword);
@@ -108,13 +121,18 @@ public class FeedInfoActivity extends ActionBarActivity {
Log.d(TAG, "Language is " + feed.getLanguage());
Log.d(TAG, "Author is " + feed.getAuthor());
Log.d(TAG, "URL is " + feed.getDownload_url());
+ FeedPreferences prefs = feed.getPreferences();
imgvCover.post(new Runnable() {
@Override
public void run() {
- Picasso.with(FeedInfoActivity.this)
+ Glide.with(FeedInfoActivity.this)
.load(feed.getImageUri())
- .fit()
+ .placeholder(R.color.light_gray)
+ .error(R.color.light_gray)
+ .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
+ .fitCenter()
+ .dontAnimate()
.into(imgvCover);
}
});
@@ -133,17 +151,49 @@ public class FeedInfoActivity extends ActionBarActivity {
Iconify.addIcons(txtvUrl);
cbxAutoDownload.setEnabled(UserPreferences.isEnableAutodownload());
- cbxAutoDownload.setChecked(feed.getPreferences().getAutoDownload());
+ cbxAutoDownload.setChecked(prefs.getAutoDownload());
cbxAutoDownload.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
feed.getPreferences().setAutoDownload(checked);
feed.savePreferences(FeedInfoActivity.this);
+ ApplyToEpisodesDialog dialog = new ApplyToEpisodesDialog(FeedInfoActivity.this,
+ feed, checked);
+ dialog.createNewDialog().show();
}
});
+ spnAutoDelete.setOnItemSelectedListener(new OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
+ FeedPreferences.AutoDeleteAction auto_delete_action;
+ switch (parent.getSelectedItemPosition()) {
+ case 0:
+ auto_delete_action = FeedPreferences.AutoDeleteAction.GLOBAL;
+ break;
+
+ case 1:
+ auto_delete_action = FeedPreferences.AutoDeleteAction.YES;
+ break;
+
+ case 2:
+ auto_delete_action = FeedPreferences.AutoDeleteAction.NO;
+ break;
+
+ default: // TODO - add exceptions here
+ return;
+ }
+ feed.getPreferences().setAutoDeleteAction(auto_delete_action);// p
+ autoDeleteChanged = true;
+ }
+ @Override
+ public void onNothingSelected(AdapterView<?> parent) {
+ // Another interface callback
+ }
+ });
+ spnAutoDelete.setSelection(prefs.getAutoDeleteAction().ordinal());
- etxtUsername.setText(feed.getPreferences().getUsername());
- etxtPassword.setText(feed.getPreferences().getPassword());
+ etxtUsername.setText(prefs.getUsername());
+ etxtPassword.setText(prefs.getPassword());
etxtUsername.addTextChangedListener(authTextWatcher);
etxtPassword.addTextChangedListener(authTextWatcher);
@@ -181,13 +231,18 @@ public class FeedInfoActivity extends ActionBarActivity {
@Override
protected void onPause() {
super.onPause();
- if (feed != null && authInfoChanged) {
- Log.d(TAG, "Auth info changed, saving credentials");
+ if (feed != null) {
FeedPreferences prefs = feed.getPreferences();
- prefs.setUsername(etxtUsername.getText().toString());
- prefs.setPassword(etxtPassword.getText().toString());
- DBWriter.setFeedPreferences(this, prefs);
+ if (authInfoChanged) {
+ Log.d(TAG, "Auth info changed, saving credentials");
+ prefs.setUsername(etxtUsername.getText().toString());
+ prefs.setPassword(etxtPassword.getText().toString());
+ }
+ if (authInfoChanged || autoDeleteChanged) {
+ DBWriter.setFeedPreferences(this, prefs);
+ }
authInfoChanged = false;
+ autoDeleteChanged = false;
}
}
@@ -205,7 +260,8 @@ public class FeedInfoActivity extends ActionBarActivity {
menu.findItem(R.id.support_item).setVisible(
feed != null && feed.getPaymentLink() != null);
menu.findItem(R.id.share_link_item).setVisible(feed != null && feed.getLink() != null);
- menu.findItem(R.id.visit_website_item).setVisible(feed != null && feed.getLink() != null);
+ menu.findItem(R.id.visit_website_item).setVisible(feed != null && feed.getLink() != null &&
+ IntentUtils.isCallable(this, new Intent(Intent.ACTION_VIEW, Uri.parse(feed.getLink()))));
return true;
}
@@ -226,4 +282,25 @@ public class FeedInfoActivity extends ActionBarActivity {
return super.onOptionsItemSelected(item);
}
}
+
+ private class ApplyToEpisodesDialog extends ConfirmationDialog {
+
+ private final Feed feed;
+ private final boolean autoDownload;
+
+ public ApplyToEpisodesDialog(Context context, Feed feed, boolean autoDownload) {
+ super(context, R.string.auto_download_apply_to_items_title,
+ R.string.auto_download_apply_to_items_message);
+ this.feed = feed;
+ this.autoDownload = autoDownload;
+ setPositiveText(R.string.yes);
+ setNegativeText(R.string.no);
+ }
+
+ @Override
+ public void onConfirmButtonPressed(DialogInterface dialog) {
+ DBWriter.setFeedsItemsAutoDownload(context, feed, autoDownload);
+ }
+ }
+
}
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 254749cd6..7eee1558b 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java
@@ -1,6 +1,7 @@
package de.danoeh.antennapod.activity;
import android.app.AlertDialog;
+import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
@@ -19,6 +20,8 @@ import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.widget.Toolbar;
import android.util.Log;
+import android.view.ContextMenu;
+import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
@@ -31,11 +34,15 @@ import java.util.List;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.adapter.NavListAdapter;
+import de.danoeh.antennapod.core.asynctask.FeedRemover;
+import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
+import de.danoeh.antennapod.core.event.ProgressEvent;
import de.danoeh.antennapod.core.feed.EventDistributor;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.QueueEvent;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.storage.DBReader;
+import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.util.StorageUtils;
import de.danoeh.antennapod.fragment.AddFeedFragment;
import de.danoeh.antennapod.fragment.AllEpisodesFragment;
@@ -92,9 +99,10 @@ public class MainActivity extends ActionBarActivity implements NavDrawerActivity
private ActionBarDrawerToggle drawerToggle;
- private CharSequence drawerTitle;
private CharSequence currentTitle;
+ private ProgressDialog pd;
+
@Override
public void onCreate(Bundle savedInstanceState) {
setTheme(UserPreferences.getNoTitleTheme());
@@ -107,7 +115,7 @@ public class MainActivity extends ActionBarActivity implements NavDrawerActivity
setSupportActionBar(toolbar);
getSupportActionBar().setElevation(3.0f);
- drawerTitle = currentTitle = getTitle();
+ currentTitle = getTitle();
drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
navList = (ListView) findViewById(R.id.nav_list);
@@ -136,6 +144,7 @@ public class MainActivity extends ActionBarActivity implements NavDrawerActivity
navList.setAdapter(navAdapter);
navList.setOnItemClickListener(navListClickListener);
navList.setOnItemLongClickListener(newListLongClickListener);
+ registerForContextMenu(navList);
navAdapter.registerDataSetObserver(new DataSetObserver() {
@Override
@@ -161,9 +170,9 @@ public class MainActivity extends ActionBarActivity implements NavDrawerActivity
String lastFragment = getLastNavFragment();
if(ArrayUtils.contains(NAV_DRAWER_TAGS, lastFragment)) {
loadFragment(lastFragment, null);
+ } else {
+ loadFeedFragmentById(Integer.valueOf(lastFragment), null);
}
- // else: lastFragment contains feed id - drawer data is not loaded yet,
- // so loading is postponed until then
}
externalPlayerFragment = new ExternalPlayerFragment();
transaction.replace(R.id.playerFragment, externalPlayerFragment);
@@ -173,6 +182,7 @@ public class MainActivity extends ActionBarActivity implements NavDrawerActivity
}
private void saveLastNavFragment(String tag) {
+ Log.d(TAG, "saveLastNavFragment(tag: " + tag +")");
SharedPreferences prefs = getSharedPreferences(PREF_NAME, MODE_PRIVATE);
SharedPreferences.Editor edit = prefs.edit();
if(tag != null) {
@@ -185,7 +195,9 @@ public class MainActivity extends ActionBarActivity implements NavDrawerActivity
private String getLastNavFragment() {
SharedPreferences prefs = getSharedPreferences(PREF_NAME, MODE_PRIVATE);
- return prefs.getString(PREF_LAST_FRAGMENT_TAG, QueueFragment.TAG);
+ String lastFragment = prefs.getString(PREF_LAST_FRAGMENT_TAG, QueueFragment.TAG);
+ Log.d(TAG, "getLastNavFragment() -> " + lastFragment);
+ return lastFragment;
}
private void checkFirstLaunch() {
@@ -251,6 +263,7 @@ public class MainActivity extends ActionBarActivity implements NavDrawerActivity
}
public void loadFragment(int index, Bundle args) {
+ Log.d(TAG, "loadFragment(index: " + index + ", args: " + args +")");
if (index < navAdapter.getSubscriptionOffset()) {
String tag = navAdapter.getTags().get(index);
loadFragment(tag, args);
@@ -261,7 +274,7 @@ public class MainActivity extends ActionBarActivity implements NavDrawerActivity
}
public void loadFragment(final String tag, Bundle args) {
- Log.d(TAG, "loadFragment(\"" + tag + "\", " + args + ")");
+ Log.d(TAG, "loadFragment(tag: " + tag + ", args: " + args + ")");
Fragment fragment = null;
switch (tag) {
case QueueFragment.TAG:
@@ -297,32 +310,20 @@ public class MainActivity extends ActionBarActivity implements NavDrawerActivity
return;
}
Feed feed = itemAccess.getItem(relPos);
- long feedId = feed.getId();
+ loadFeedFragmentById(feed.getId(), args);
+ }
+
+ public void loadFeedFragmentById(long feedId, Bundle args) {
Fragment fragment = ItemlistFragment.newInstance(feedId);
if(args != null) {
fragment.setArguments(args);
}
- saveLastNavFragment(String.valueOf(feed.getId()));
+ saveLastNavFragment(String.valueOf(feedId));
currentTitle = "";
getSupportActionBar().setTitle(currentTitle);
loadFragment(fragment);
}
- public void loadFeedFragmentById(long feedId) {
- if (navDrawerData != null) {
- int relPos = -1;
- List<Feed> feeds = navDrawerData.feeds;
- for (int i = 0; relPos < 0 && i < feeds.size(); i++) {
- if (feeds.get(i).getId() == feedId) {
- relPos = i;
- }
- }
- if(relPos >= 0) {
- loadFeedFragmentByPosition(relPos, null);
- }
- }
- }
-
private void loadFragment(Fragment fragment) {
FragmentManager fragmentManager = getSupportFragmentManager();
// clear back stack
@@ -362,15 +363,19 @@ public class MainActivity extends ActionBarActivity implements NavDrawerActivity
}
private int getSelectedNavListIndex() {
- String lastFragment = getLastNavFragment();
- int tagIndex = navAdapter.getTags().indexOf(lastFragment);
+ String currentFragment = getLastNavFragment();
+ if(currentFragment == null) {
+ // should not happen, but better safe than sorry
+ return -1;
+ }
+ int tagIndex = navAdapter.getTags().indexOf(currentFragment);
if(tagIndex >= 0) {
return tagIndex;
- } else if(ArrayUtils.contains(NAV_DRAWER_TAGS, lastFragment)) {
+ } else if(ArrayUtils.contains(NAV_DRAWER_TAGS, currentFragment)) {
// the fragment was just hidden
return -1;
} else { // last fragment was not a list, but a feed
- long feedId = Long.parseLong(lastFragment);
+ long feedId = Long.parseLong(currentFragment);
if (navDrawerData != null) {
List<Feed> feeds = navDrawerData.feeds;
for (int i = 0; i < feeds.size(); i++) {
@@ -465,6 +470,9 @@ public class MainActivity extends ActionBarActivity implements NavDrawerActivity
cancelLoadTask();
EventDistributor.getInstance().unregister(contentUpdate);
EventBus.getDefault().unregister(this);
+ if(pd != null) {
+ pd.dismiss();
+ }
}
@Override
@@ -481,6 +489,67 @@ public class MainActivity extends ActionBarActivity implements NavDrawerActivity
}
}
+ @Override
+ public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
+ super.onCreateContextMenu(menu, v, menuInfo);
+ if(v.getId() != R.id.nav_list) {
+ return;
+ }
+ AdapterView.AdapterContextMenuInfo adapterInfo = (AdapterView.AdapterContextMenuInfo) menuInfo;
+ int position = adapterInfo.position;
+ if(position < navAdapter.getSubscriptionOffset()) {
+ return;
+ }
+ MenuInflater inflater = getMenuInflater();
+ inflater.inflate(R.menu.nav_feed_context, menu);
+ Feed feed = navDrawerData.feeds.get(position - navAdapter.getSubscriptionOffset());
+ menu.setHeaderTitle(feed.getTitle());
+ // episodes are not loaded, so we cannot check if the podcast has new or unplayed ones!
+ }
+
+ @Override
+ public boolean onContextItemSelected(MenuItem item) {
+ AdapterView.AdapterContextMenuInfo menuInfo = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
+ if(menuInfo.targetView.getParent() instanceof ListView == false
+ || ((ListView)menuInfo.targetView.getParent()).getId() != R.id.nav_list) {
+ return false;
+ }
+ final int position = menuInfo.position;
+ Feed feed = navDrawerData.feeds.get(position - navAdapter.getSubscriptionOffset());
+ switch(item.getItemId()) {
+ case R.id.mark_all_seen_item:
+ DBWriter.markFeedSeen(this, feed.getId());
+ return true;
+ case R.id.mark_all_read_item:
+ DBWriter.markFeedRead(this, feed.getId());
+ return true;
+ case R.id.remove_item:
+ final FeedRemover remover = new FeedRemover(this, feed) {
+ @Override
+ protected void onPostExecute(Void result) {
+ super.onPostExecute(result);
+ if(getSelectedNavListIndex() == position) {
+ loadFragment(NewEpisodesFragment.TAG, null);
+ }
+ }
+ };
+ ConfirmationDialog conDialog = new ConfirmationDialog(this,
+ R.string.remove_feed_label,
+ R.string.feed_delete_confirmation_msg) {
+ @Override
+ public void onConfirmButtonPressed(
+ DialogInterface dialog) {
+ dialog.dismiss();
+ remover.executeAsync();
+ }
+ };
+ conDialog.createNewDialog().show();
+ return true;
+ default:
+ return super.onContextItemSelected(item);
+ }
+ }
+
private DBReader.NavDrawerData navDrawerData;
private AsyncTask<Void, Void, DBReader.NavDrawerData> loadTask;
private int selectedNavListIndex = 0;
@@ -520,8 +589,8 @@ public class MainActivity extends ActionBarActivity implements NavDrawerActivity
}
@Override
- public int getNumberOfUnreadFeedItems(long feedId) {
- return (navDrawerData != null) ? navDrawerData.numUnreadFeedItems.get(feedId) : 0;
+ public int getFeedCounter(long feedId) {
+ return navDrawerData != null ? navDrawerData.feedCounters.get(feedId) : 0;
}
};
@@ -542,13 +611,6 @@ public class MainActivity extends ActionBarActivity implements NavDrawerActivity
navDrawerData = result;
navAdapter.notifyDataSetChanged();
- String lastFragment = getLastNavFragment();
- if(!ArrayUtils.contains(NAV_DRAWER_TAGS, lastFragment)) {
- long feedId = Long.valueOf(lastFragment);
- loadFeedFragmentById(feedId);
- saveLastNavFragment(null);
- }
-
if (handleIntent) {
handleNavIntent();
}
@@ -568,6 +630,24 @@ public class MainActivity extends ActionBarActivity implements NavDrawerActivity
loadData();
}
+ public void onEventMainThread(ProgressEvent event) {
+ Log.d(TAG, "onEvent(" + event + ")");
+ switch(event.action) {
+ case START:
+ pd = new ProgressDialog(this);
+ pd.setMessage(event.message);
+ pd.setIndeterminate(true);
+ pd.setCancelable(false);
+ pd.show();
+ break;
+ case END:
+ if(pd != null) {
+ pd.dismiss();
+ }
+ break;
+ }
+ }
+
private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
@Override
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java
index 0cd388b9d..b83e9bc15 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java
@@ -278,6 +278,7 @@ public abstract class MediaplayerActivity extends ActionBarActivity
startActivity(intent);
return true;
} else if (media != null) {
+ FeedItem feedItem = ((FeedMedia) media).getItem();
switch (item.getItemId()) {
case R.id.disable_sleeptimer_item:
if (controller.serviceAvailable()) {
@@ -333,12 +334,20 @@ public abstract class MediaplayerActivity extends ActionBarActivity
break;
case R.id.support_item:
if (media instanceof FeedMedia) {
- FeedItem feedItem = ((FeedMedia) media).getItem();
DBTasks.flattrItemIfLoggedIn(this, feedItem);
}
break;
case R.id.share_link_item:
- ShareUtils.shareLink(this, media.getWebsiteLink());
+ ShareUtils.shareFeedItemLink(this, feedItem);
+ break;
+ case R.id.share_download_url_item:
+ ShareUtils.shareFeedItemDownloadLink(this, feedItem);
+ break;
+ case R.id.share_link_with_position_item:
+ ShareUtils.shareFeedItemLink(this, feedItem, true);
+ break;
+ case R.id.share_download_url_with_position_item:
+ ShareUtils.shareFeedItemDownloadLink(this, feedItem, true);
break;
case R.id.skip_episode_item:
sendBroadcast(new Intent(
@@ -471,7 +480,7 @@ public abstract class MediaplayerActivity extends ActionBarActivity
checked = i;
}
choices[i] = String.valueOf(values[i]) + " "
- + getString(R.string.time_unit_seconds);
+ + getString(R.string.time_seconds);
}
choice = values[checked];
AlertDialog.Builder builder = new AlertDialog.Builder(MediaplayerActivity.this);
@@ -519,7 +528,7 @@ public abstract class MediaplayerActivity extends ActionBarActivity
checked = i;
}
choices[i] = String.valueOf(values[i]) + " "
- + getString(R.string.time_unit_seconds);
+ + getString(R.string.time_seconds);
}
choice = values[checked];
AlertDialog.Builder builder = new AlertDialog.Builder(MediaplayerActivity.this);
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 2b1b13ae6..3ab384012 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java
@@ -180,7 +180,7 @@ public abstract class OnlineFeedViewActivity extends ActionBarActivity {
url = URLChecker.prepareURL(url);
feed = new Feed(url, new Date(0));
if (username != null && password != null) {
- feed.setPreferences(new FeedPreferences(0, false, username, password));
+ feed.setPreferences(new FeedPreferences(0, false, FeedPreferences.AutoDeleteAction.GLOBAL, username, password));
}
String fileUrl = new File(getExternalCacheDir(),
FileNameGenerator.generateFileName(feed.getDownload_url())).toString();
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 feb3989bc..2ec987d1a 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportFromPathActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportFromPathActivity.java
@@ -2,7 +2,6 @@ package de.danoeh.antennapod.activity;
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;
@@ -18,11 +17,10 @@ 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.IntentUtils;
import de.danoeh.antennapod.core.util.LangUtils;
import de.danoeh.antennapod.core.util.StorageUtils;
@@ -72,38 +70,33 @@ public class OpmlImportFromPathActivity extends OpmlImportBaseActivity {
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(false == IntentUtils.isCallable(getApplicationContext(), intentPickAction)) {
+ intentPickAction.setData(null);
+ if(false == IntentUtils.isCallable(getApplicationContext(), intentPickAction)) {
+ 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++;
- }
+ 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++;
- }
+ if(false == IntentUtils.isCallable(getApplicationContext(), intentGetContentAction)) {
+ 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);
}
@@ -137,7 +130,7 @@ public class OpmlImportFromPathActivity extends OpmlImportBaseActivity {
try {
mReader = new InputStreamReader(new FileInputStream(file),
LangUtils.UTF_8);
- if (BuildConfig.DEBUG) Log.d(TAG, "Parsing " + file.toString());
+ Log.d(TAG, "Parsing " + file.toString());
startImport(mReader);
} catch (FileNotFoundException e) {
Log.d(TAG, "File not found which really should be there");
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java
index 3802de2a6..94970d833 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java
@@ -60,10 +60,13 @@ public class PreferenceActivity extends ActionBarActivity {
root.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
setContentView(root);
- prefFragment = new MainFragment();
- getFragmentManager().beginTransaction().replace(R.id.content, prefFragment).commit();
+ // we need to create the PreferenceController before the MainFragment
+ // since the MainFragment depends on the preferenceController already being created
preferenceController = new PreferenceController(preferenceUI);
+
+ prefFragment = new MainFragment();
+ getFragmentManager().beginTransaction().replace(R.id.content, prefFragment).commit();
}
@Override
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 8e347a819..aca2b359a 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/ActionButtonUtils.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/ActionButtonUtils.java
@@ -88,7 +88,7 @@ public class ActionButtonUtils {
butSecondary.setContentDescription(context.getString(labels[0]));
}
} else {
- if (item.isRead()) {
+ if (item.isPlayed()) {
butSecondary.setVisibility(View.INVISIBLE);
} else {
butSecondary.setVisibility(View.VISIBLE);
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/AdapterUtils.java b/app/src/main/java/de/danoeh/antennapod/adapter/AdapterUtils.java
index e22b31361..d3ee08546 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/AdapterUtils.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/AdapterUtils.java
@@ -36,18 +36,19 @@ public class AdapterUtils {
|| state == FeedItem.State.IN_PROGRESS) {
if (media.getDuration() > 0) {
episodeProgress.setVisibility(View.VISIBLE);
- episodeProgress
- .setProgress((int) (((double) media
+ episodeProgress.setProgress((int) (((double) media
.getPosition()) / media.getDuration() * 100));
- txtvPos.setText(Converter
- .getDurationStringLong(media.getDuration()
+ txtvPos.setText(Converter.getDurationStringLong(media.getDuration()
- media.getPosition()));
}
} else if (!media.isDownloaded()) {
- txtvPos.setText(Converter.byteToString(media.getSize()));
+ if(media.getSize() > 0) {
+ txtvPos.setText(Converter.byteToString(media.getSize()));
+ } else {
+ txtvPos.setText("");
+ }
} else {
- txtvPos.setText(Converter.getDurationStringLong(media
- .getDuration()));
+ txtvPos.setText(Converter.getDurationStringLong(media.getDuration()));
}
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesListAdapter.java
index d96326053..4b6ee8f91 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesListAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesListAdapter.java
@@ -1,6 +1,8 @@
package de.danoeh.antennapod.adapter;
import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
import android.text.format.DateUtils;
import android.view.LayoutInflater;
import android.view.View;
@@ -11,11 +13,18 @@ import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
-import com.squareup.picasso.Picasso;
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.load.engine.DiskCacheStrategy;
+import com.bumptech.glide.load.resource.drawable.GlideDrawable;
+import com.bumptech.glide.request.animation.GlideAnimation;
+import com.bumptech.glide.request.target.GlideDrawableImageViewTarget;
+
+import java.lang.ref.WeakReference;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
+import de.danoeh.antennapod.core.glide.ApGlideSettings;
import de.danoeh.antennapod.core.storage.DownloadRequester;
import de.danoeh.antennapod.core.util.Converter;
@@ -72,6 +81,7 @@ public class AllEpisodesListAdapter extends BaseAdapter {
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.new_episodes_listitem,
parent, false);
+ holder.placeholder = (TextView) convertView.findViewById(R.id.txtvPlaceholder);
holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
holder.pubDate = (TextView) convertView
.findViewById(R.id.txtvPublished);
@@ -82,16 +92,18 @@ public class AllEpisodesListAdapter extends BaseAdapter {
.findViewById(R.id.imgvInPlaylist);
holder.progress = (ProgressBar) convertView
.findViewById(R.id.pbar_progress);
- holder.imageView = (ImageView) convertView.findViewById(R.id.imgvImage);
+ holder.cover = (ImageView) convertView.findViewById(R.id.imgvCover);
holder.txtvDuration = (TextView) convertView.findViewById(R.id.txtvDuration);
convertView.setTag(holder);
} else {
holder = (Holder) convertView.getTag();
}
+ holder.placeholder.setVisibility(View.VISIBLE);
+ holder.placeholder.setText(item.getFeed().getTitle());
holder.title.setText(item.getTitle());
holder.pubDate.setText(DateUtils.formatDateTime(context, item.getPubDate().getTime(), DateUtils.FORMAT_ABBREV_ALL));
- if (showOnlyNewEpisodes || item.isRead() || false == itemAccess.isNew(item)) {
+ if (showOnlyNewEpisodes || false == item.isNew()) {
holder.statusUnread.setVisibility(View.INVISIBLE);
} else {
holder.statusUnread.setVisibility(View.VISIBLE);
@@ -141,14 +153,54 @@ public class AllEpisodesListAdapter extends BaseAdapter {
holder.butSecondary.setTag(item);
holder.butSecondary.setOnClickListener(secondaryActionListener);
- Picasso.with(context)
+ Glide.with(context)
.load(item.getImageUri())
- .fit()
- .into(holder.imageView);
+ .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
+ .fitCenter()
+ .dontAnimate()
+ .into(new CoverTarget(item.getFeed().getImageUri(), holder.placeholder, holder.cover));
return convertView;
}
+ private class CoverTarget extends GlideDrawableImageViewTarget {
+
+ private final WeakReference<Uri> fallback;
+ private final WeakReference<TextView> placeholder;
+ private final WeakReference<ImageView> cover;
+
+ public CoverTarget(Uri fallbackUri, TextView txtvPlaceholder, ImageView imgvCover) {
+ super(imgvCover);
+ fallback = new WeakReference<>(fallbackUri);
+ placeholder = new WeakReference<>(txtvPlaceholder);
+ cover = new WeakReference<>(imgvCover);
+ }
+
+ @Override
+ public void onLoadFailed(Exception e, Drawable errorDrawable) {
+ Uri fallbackUri = fallback.get();
+ TextView txtvPlaceholder = placeholder.get();
+ ImageView imgvCover = cover.get();
+ if(fallbackUri != null && txtvPlaceholder != null && imgvCover != null) {
+ Glide.with(context)
+ .load(fallbackUri)
+ .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
+ .fitCenter()
+ .dontAnimate()
+ .into(new CoverTarget(null, txtvPlaceholder, imgvCover));
+ }
+ }
+
+ @Override
+ public void onResourceReady(GlideDrawable drawable, GlideAnimation anim) {
+ super.onResourceReady(drawable, anim);
+ TextView txtvPlaceholder = placeholder.get();
+ if(txtvPlaceholder != null) {
+ txtvPlaceholder.setVisibility(View.INVISIBLE);
+ }
+ }
+ }
+
private View.OnClickListener secondaryActionListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
@@ -159,11 +211,12 @@ public class AllEpisodesListAdapter extends BaseAdapter {
static class Holder {
+ TextView placeholder;
TextView title;
TextView pubDate;
View statusUnread;
ImageView queueStatus;
- ImageView imageView;
+ ImageView cover;
ProgressBar progress;
TextView txtvDuration;
ImageButton butSecondary;
@@ -179,7 +232,5 @@ public class AllEpisodesListAdapter extends BaseAdapter {
boolean isInQueue(FeedItem item);
- boolean isNew(FeedItem item);
-
}
}
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 223fe17f6..c3486f2f2 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/DefaultActionButtonCallback.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/DefaultActionButtonCallback.java
@@ -12,11 +12,8 @@ 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.preferences.UserPreferences;
import de.danoeh.antennapod.core.service.playback.PlaybackService;
-import de.danoeh.antennapod.core.gpoddernet.model.GpodnetEpisodeAction;
-import de.danoeh.antennapod.core.preferences.GpodnetPreferences;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBTasks;
import de.danoeh.antennapod.core.storage.DBWriter;
@@ -61,7 +58,7 @@ public class DefaultActionButtonCallback implements ActionButtonCallback {
boolean isDownloading = DownloadRequester.getInstance().isDownloadingFile(media);
if (!isDownloading && !media.isDownloaded()) {
LongList queueIds = DBReader.getQueueIDList(context);
- if (NetworkUtils.isDownloadAllowed(context) || userAllowedMobileDownloads()) {
+ if (NetworkUtils.isDownloadAllowed() || userAllowedMobileDownloads()) {
try {
DBTasks.downloadFeedItems(context, item);
Toast.makeText(context, R.string.status_downloading_label, Toast.LENGTH_SHORT).show();
@@ -95,21 +92,8 @@ public class DefaultActionButtonCallback implements ActionButtonCallback {
}
}
} else {
- if (!item.isRead()) {
+ if (!item.isPlayed()) {
DBWriter.markItemRead(context, item, true, true);
-
- if(GpodnetPreferences.loggedIn()) {
- // gpodder: send played action
- FeedMedia media = item.getMedia();
- GpodnetEpisodeAction action = new GpodnetEpisodeAction.Builder(item, GpodnetEpisodeAction.Action.PLAY)
- .currentDeviceId()
- .currentTimestamp()
- .started(media.getDuration() / 1000)
- .position(media.getDuration() / 1000)
- .total(media.getDuration() / 1000)
- .build();
- GpodnetPreferences.enqueueEpisodeAction(action);
- }
}
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java
index f29cfdf2f..0eb15da8c 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java
@@ -124,11 +124,15 @@ public class DownloadLogAdapter extends BaseAdapter {
ButtonHolder holder = (ButtonHolder) v.getTag();
if(holder.typeId == Feed.FEEDFILETYPE_FEED) {
Feed feed = DBReader.getFeed(context, holder.id);
- feed.setLastUpdate(new Date(0)); // force refresh
- try {
- DBTasks.refreshFeed(context, feed);
- } catch (DownloadRequestException e) {
- e.printStackTrace();
+ if (feed != null) {
+ feed.setLastUpdate(new Date(0)); // force refresh
+ try {
+ DBTasks.refreshFeed(context, feed);
+ } catch (DownloadRequestException e) {
+ e.printStackTrace();
+ }
+ } else {
+ Log.wtf(TAG, "Could not find feed for feed id: " + holder.id);
}
} else if(holder.typeId == FeedMedia.FEEDFILETYPE_FEEDMEDIA) {
FeedMedia media = DBReader.getFeedMedia(context, holder.id);
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/DownloadedEpisodesListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/DownloadedEpisodesListAdapter.java
index 15e0a7a33..2b1eccea5 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/DownloadedEpisodesListAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/DownloadedEpisodesListAdapter.java
@@ -10,10 +10,12 @@ import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
-import com.squareup.picasso.Picasso;
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.load.engine.DiskCacheStrategy;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.feed.FeedItem;
+import de.danoeh.antennapod.core.glide.ApGlideSettings;
import de.danoeh.antennapod.core.util.Converter;
/**
@@ -88,9 +90,13 @@ public class DownloadedEpisodesListAdapter extends BaseAdapter {
holder.butSecondary.setOnClickListener(secondaryActionListener);
- Picasso.with(context)
+ Glide.with(context)
.load(item.getImageUri())
- .fit()
+ .placeholder(R.color.light_gray)
+ .error(R.color.light_gray)
+ .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
+ .fitCenter()
+ .dontAnimate()
.into(holder.imageView);
return convertView;
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 b39e23d42..56e2bb1bd 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java
@@ -33,13 +33,17 @@ public class FeedItemlistAdapter extends BaseAdapter {
private final Context context;
private boolean showFeedtitle;
private int selectedItemIndex;
+ /** true if played items should be made partially transparent */
+ private boolean makePlayedItemsTransparent;
private final ActionButtonUtils actionButtonUtils;
public static final int SELECTION_NONE = -1;
public FeedItemlistAdapter(Context context,
ItemAccess itemAccess,
- ActionButtonCallback callback, boolean showFeedtitle) {
+ ActionButtonCallback callback,
+ boolean showFeedtitle,
+ boolean makePlayedItemsTransparent) {
super();
this.callback = callback;
this.context = context;
@@ -47,6 +51,7 @@ public class FeedItemlistAdapter extends BaseAdapter {
this.showFeedtitle = showFeedtitle;
this.selectedItemIndex = SELECTION_NONE;
this.actionButtonUtils = new ActionButtonUtils(context);
+ this.makePlayedItemsTransparent = makePlayedItemsTransparent;
}
@Override
@@ -106,18 +111,18 @@ public class FeedItemlistAdapter extends BaseAdapter {
StringBuilder buffer = new StringBuilder(item.getTitle());
if (showFeedtitle) {
- buffer.append("(");
+ buffer.append(" (");
buffer.append(item.getFeed().getTitle());
buffer.append(")");
}
holder.title.setText(buffer.toString());
- if(false == item.isRead() && itemAccess.isNew(item)) {
+ if(item.isNew()) {
holder.statusUnread.setVisibility(View.VISIBLE);
} else {
holder.statusUnread.setVisibility(View.INVISIBLE);
}
- if(item.isRead()) {
+ if(item.isPlayed() && makePlayedItemsTransparent) {
ViewHelper.setAlpha(convertView, 0.5f);
} else {
ViewHelper.setAlpha(convertView, 1.0f);
@@ -180,7 +185,6 @@ public class FeedItemlistAdapter extends BaseAdapter {
convertView.setVisibility(View.GONE);
}
return convertView;
-
}
private final OnClickListener butActionListener = new OnClickListener() {
@@ -221,8 +225,6 @@ public class FeedItemlistAdapter extends BaseAdapter {
FeedItem getItem(int position);
- boolean isNew(FeedItem item);
-
}
}
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 0d2d5cfa0..3c91cbbbb 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java
@@ -15,7 +15,8 @@ import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
-import com.squareup.picasso.Picasso;
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.load.engine.DiskCacheStrategy;
import org.apache.commons.lang3.ArrayUtils;
@@ -27,6 +28,7 @@ import java.util.List;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.core.feed.Feed;
+import de.danoeh.antennapod.core.glide.ApGlideSettings;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.fragment.AddFeedFragment;
import de.danoeh.antennapod.fragment.AllEpisodesFragment;
@@ -259,9 +261,13 @@ public class NavListAdapter extends BaseAdapter
holder = (FeedHolder) convertView.getTag();
}
- Picasso.with(context)
+ Glide.with(context)
.load(feed.getImageUri())
- .fit()
+ .placeholder(R.color.light_gray)
+ .error(R.color.light_gray)
+ .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
+ .fitCenter()
+ .dontAnimate()
.into(holder.image);
holder.title.setText(feed.getTitle());
@@ -276,10 +282,10 @@ public class NavListAdapter extends BaseAdapter
p.addRule(RelativeLayout.LEFT_OF, R.id.txtvCount);
holder.failure.setVisibility(View.GONE);
}
- int feedUnreadItems = itemAccess.getNumberOfUnreadFeedItems(feed.getId());
- if(feedUnreadItems > 0) {
+ int counter = itemAccess.getFeedCounter(feed.getId());
+ if(counter > 0) {
holder.count.setVisibility(View.VISIBLE);
- holder.count.setText(String.valueOf(feedUnreadItems));
+ holder.count.setText(String.valueOf(counter));
holder.count.setTypeface(holder.title.getTypeface());
} else {
holder.count.setVisibility(View.GONE);
@@ -306,7 +312,7 @@ public class NavListAdapter extends BaseAdapter
int getSelectedItemIndex();
int getQueueSize();
int getNumberOfNewItems();
- int getNumberOfUnreadFeedItems(long feedId);
+ int getFeedCounter(long feedId);
}
}
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 bba5a00a9..60c125fda 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/QueueListAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/QueueListAdapter.java
@@ -1,7 +1,10 @@
package de.danoeh.antennapod.adapter;
import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
import android.text.format.DateUtils;
+import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -11,11 +14,18 @@ import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
-import com.squareup.picasso.Picasso;
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.load.engine.DiskCacheStrategy;
+import com.bumptech.glide.load.resource.drawable.GlideDrawable;
+import com.bumptech.glide.request.animation.GlideAnimation;
+import com.bumptech.glide.request.target.GlideDrawableImageViewTarget;
+
+import java.lang.ref.WeakReference;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
+import de.danoeh.antennapod.core.glide.ApGlideSettings;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.storage.DownloadRequester;
import de.danoeh.antennapod.core.util.Converter;
@@ -25,6 +35,7 @@ import de.danoeh.antennapod.core.util.Converter;
*/
public class QueueListAdapter extends BaseAdapter {
+ private static final String TAG = QueueListAdapter.class.getSimpleName();
private final Context context;
private final ItemAccess itemAccess;
@@ -76,7 +87,8 @@ public class QueueListAdapter extends BaseAdapter {
convertView = inflater.inflate(R.layout.queue_listitem,
parent, false);
holder.dragHandle = (ImageView) convertView.findViewById(R.id.drag_handle);
- holder.imageView = (ImageView) convertView.findViewById(R.id.imgvImage);
+ holder.placeholder = (TextView) convertView.findViewById(R.id.txtvPlaceholder);
+ holder.cover = (ImageView) convertView.findViewById(R.id.imgvCover);
holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
holder.pubDate = (TextView) convertView.findViewById(R.id.txtvPubDate);
holder.progressLeft = (TextView) convertView.findViewById(R.id.txtvProgressLeft);
@@ -86,7 +98,6 @@ public class QueueListAdapter extends BaseAdapter {
.findViewById(R.id.butSecondaryAction);
holder.progress = (ProgressBar) convertView
.findViewById(R.id.progressBar);
- holder.imageView = (ImageView) convertView.findViewById(R.id.imgvImage);
convertView.setTag(holder);
} else {
holder = (Holder) convertView.getTag();
@@ -98,10 +109,11 @@ public class QueueListAdapter extends BaseAdapter {
holder.dragHandle.setVisibility(View.VISIBLE);
}
+ holder.placeholder.setText(item.getFeed().getTitle());
+
holder.title.setText(item.getTitle());
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"));
@@ -129,7 +141,11 @@ public class QueueListAdapter extends BaseAdapter {
holder.progressRight.setText(Converter.getDurationStringLong(media.getDuration()));
}
} else {
- holder.progressLeft.setText(Converter.byteToString(media.getSize()));
+ if(media.getSize() > 0) {
+ holder.progressLeft.setText(Converter.byteToString(media.getSize()));
+ } else {
+ holder.progressLeft.setText("");
+ }
holder.progressRight.setText(Converter.getDurationStringLong(media.getDuration()));
holder.progress.setVisibility(View.GONE);
}
@@ -140,14 +156,54 @@ public class QueueListAdapter extends BaseAdapter {
holder.butSecondary.setTag(item);
holder.butSecondary.setOnClickListener(secondaryActionListener);
- Picasso.with(context)
+ Glide.with(context)
.load(item.getImageUri())
- .fit()
- .into(holder.imageView);
+ .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
+ .fitCenter()
+ .dontAnimate()
+ .into(new CoverTarget(item.getFeed().getImageUri(), holder.placeholder, holder.cover));
return convertView;
}
+ private class CoverTarget extends GlideDrawableImageViewTarget {
+
+ private final WeakReference<Uri> fallback;
+ private final WeakReference<TextView> placeholder;
+ private final WeakReference<ImageView> cover;
+
+ public CoverTarget(Uri fallbackUri, TextView txtvPlaceholder, ImageView imgvCover) {
+ super(imgvCover);
+ fallback = new WeakReference<>(fallbackUri);
+ placeholder = new WeakReference<>(txtvPlaceholder);
+ cover = new WeakReference<>(imgvCover);
+ }
+
+ @Override
+ public void onLoadFailed(Exception e, Drawable errorDrawable) {
+ Uri fallbackUri = fallback.get();
+ TextView txtvPlaceholder = placeholder.get();
+ ImageView imgvCover = cover.get();
+ if(fallbackUri != null && txtvPlaceholder != null && imgvCover != null) {
+ Glide.with(context)
+ .load(fallbackUri)
+ .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
+ .fitCenter()
+ .dontAnimate()
+ .into(new CoverTarget(null, txtvPlaceholder, imgvCover));
+ }
+ }
+
+ @Override
+ public void onResourceReady(GlideDrawable drawable, GlideAnimation anim) {
+ super.onResourceReady(drawable, anim);
+ TextView txtvPlaceholder = placeholder.get();
+ if(txtvPlaceholder != null) {
+ txtvPlaceholder.setVisibility(View.INVISIBLE);
+ }
+ }
+ }
+
private View.OnClickListener secondaryActionListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
@@ -156,10 +212,10 @@ public class QueueListAdapter extends BaseAdapter {
}
};
-
static class Holder {
ImageView dragHandle;
- ImageView imageView;
+ ImageView cover;
+ TextView placeholder;
TextView title;
TextView pubDate;
TextView progressLeft;
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/SearchlistAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/SearchlistAdapter.java
index cedce7903..83f5dcb4d 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/SearchlistAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/SearchlistAdapter.java
@@ -8,13 +8,15 @@ import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
-import com.squareup.picasso.Picasso;
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.load.engine.DiskCacheStrategy;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedComponent;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.SearchResult;
+import de.danoeh.antennapod.core.glide.ApGlideSettings;
/**
* List adapter for search activity.
@@ -73,9 +75,13 @@ public class SearchlistAdapter extends BaseAdapter {
holder.title.setText(feed.getTitle());
holder.subtitle.setVisibility(View.GONE);
- Picasso.with(context)
+ Glide.with(context)
.load(feed.getImageUri())
- .fit()
+ .placeholder(R.color.light_gray)
+ .error(R.color.light_gray)
+ .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
+ .fitCenter()
+ .dontAnimate()
.into(holder.cover);
} else if (component.getClass() == FeedItem.class) {
@@ -86,9 +92,13 @@ public class SearchlistAdapter extends BaseAdapter {
holder.subtitle.setText(result.getSubtitle());
}
- Picasso.with(context)
+ Glide.with(context)
.load(item.getFeed().getImageUri())
- .fit()
+ .placeholder(R.color.light_gray)
+ .error(R.color.light_gray)
+ .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
+ .fitCenter()
+ .dontAnimate()
.into(holder.cover);
}
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 b85709c5e..743f9fc86 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
@@ -8,13 +8,15 @@ import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
-import com.squareup.picasso.Picasso;
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.load.engine.DiskCacheStrategy;
import org.apache.commons.lang3.StringUtils;
import java.util.List;
import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.glide.ApGlideSettings;
import de.danoeh.antennapod.core.gpoddernet.model.GpodnetPodcast;
/**
@@ -49,9 +51,13 @@ public class PodcastListAdapter extends ArrayAdapter<GpodnetPodcast> {
}
if (StringUtils.isNotBlank(podcast.getLogoUrl())) {
- Picasso.with(convertView.getContext())
+ Glide.with(convertView.getContext())
.load(podcast.getLogoUrl())
- .fit()
+ .placeholder(R.color.light_gray)
+ .error(R.color.light_gray)
+ .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
+ .fitCenter()
+ .dontAnimate()
.into(holder.image);
}
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
index 4fc2838b7..08ffdd197 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/itunes/ItunesAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/itunes/ItunesAdapter.java
@@ -1,23 +1,18 @@
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 com.bumptech.glide.Glide;
+import com.bumptech.glide.load.engine.DiskCacheStrategy;
+
import org.json.JSONException;
import org.json.JSONObject;
-import java.io.IOException;
import java.util.List;
import de.danoeh.antennapod.R;
@@ -46,55 +41,6 @@ public class ItunesAdapter extends ArrayAdapter<ItunesAdapter.Podcast> {
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
@@ -121,7 +67,13 @@ public class ItunesAdapter extends ArrayAdapter<ItunesAdapter.Podcast> {
viewHolder.titleView.setText(podcast.title);
//Update the empty imageView with the image from the feed
- new FetchImageTask(podcast,viewHolder.coverView).execute();
+ Glide.with(context)
+ .load(podcast.imageUrl)
+ .placeholder(R.color.light_gray)
+ .diskCacheStrategy(DiskCacheStrategy.NONE)
+ .fitCenter()
+ .dontAnimate()
+ .into(viewHolder.coverView);
//Feed the grid view
return view;
diff --git a/app/src/main/java/de/danoeh/antennapod/config/ApplicationCallbacksImpl.java b/app/src/main/java/de/danoeh/antennapod/config/ApplicationCallbacksImpl.java
index 4d9be5d78..008aacfa5 100644
--- a/app/src/main/java/de/danoeh/antennapod/config/ApplicationCallbacksImpl.java
+++ b/app/src/main/java/de/danoeh/antennapod/config/ApplicationCallbacksImpl.java
@@ -8,7 +8,6 @@ import android.content.Intent;
import de.danoeh.antennapod.PodcastApp;
import de.danoeh.antennapod.activity.StorageErrorActivity;
import de.danoeh.antennapod.core.ApplicationCallbacks;
-import de.danoeh.antennapod.core.preferences.UserPreferences;
public class ApplicationCallbacksImpl implements ApplicationCallbacks {
@@ -22,8 +21,4 @@ public class ApplicationCallbacksImpl implements ApplicationCallbacks {
return new Intent(context, StorageErrorActivity.class);
}
- @Override
- public void setUpdateInterval(long updateInterval) {
- UserPreferences.restartUpdateAlarm(updateInterval, updateInterval);
- }
}
diff --git a/app/src/main/java/de/danoeh/antennapod/config/ClientConfigurator.java b/app/src/main/java/de/danoeh/antennapod/config/ClientConfigurator.java
index 10666aa36..932b9d22f 100644
--- a/app/src/main/java/de/danoeh/antennapod/config/ClientConfigurator.java
+++ b/app/src/main/java/de/danoeh/antennapod/config/ClientConfigurator.java
@@ -14,7 +14,6 @@ public class ClientConfigurator {
ClientConfig.downloadServiceCallbacks = new DownloadServiceCallbacksImpl();
ClientConfig.gpodnetCallbacks = new GpodnetCallbacksImpl();
ClientConfig.playbackServiceCallbacks = new PlaybackServiceCallbacksImpl();
- ClientConfig.storageCallbacks = new StorageCallbacksImpl();
ClientConfig.flattrCallbacks = new FlattrCallbacksImpl();
ClientConfig.dbTasksCallbacks = new DBTasksCallbacksImpl();
}
diff --git a/app/src/main/java/de/danoeh/antennapod/config/StorageCallbacksImpl.java b/app/src/main/java/de/danoeh/antennapod/config/StorageCallbacksImpl.java
deleted file mode 100644
index 943e05690..000000000
--- a/app/src/main/java/de/danoeh/antennapod/config/StorageCallbacksImpl.java
+++ /dev/null
@@ -1,153 +0,0 @@
-package de.danoeh.antennapod.config;
-
-
-import android.content.ContentValues;
-import android.database.Cursor;
-import android.database.sqlite.SQLiteDatabase;
-import android.util.Log;
-
-import de.danoeh.antennapod.core.StorageCallbacks;
-import de.danoeh.antennapod.core.storage.PodDBAdapter;
-
-public class StorageCallbacksImpl implements StorageCallbacks {
-
- @Override
- public int getDatabaseVersion() {
- return 15;
- }
-
- @Override
- public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
- Log.w("DBAdapter", "Upgrading from version " + oldVersion + " to "
- + newVersion + ".");
- if (oldVersion <= 1) {
- db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS + " ADD COLUMN "
- + PodDBAdapter.KEY_TYPE + " TEXT");
- }
- if (oldVersion <= 2) {
- db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_SIMPLECHAPTERS
- + " ADD COLUMN " + PodDBAdapter.KEY_LINK + " TEXT");
- }
- if (oldVersion <= 3) {
- db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_ITEMS
- + " ADD COLUMN " + PodDBAdapter.KEY_ITEM_IDENTIFIER + " TEXT");
- }
- if (oldVersion <= 4) {
- db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS + " ADD COLUMN "
- + PodDBAdapter.KEY_FEED_IDENTIFIER + " TEXT");
- }
- if (oldVersion <= 5) {
- db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_DOWNLOAD_LOG
- + " ADD COLUMN " + PodDBAdapter.KEY_REASON_DETAILED + " TEXT");
- db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_DOWNLOAD_LOG
- + " ADD COLUMN " + PodDBAdapter.KEY_DOWNLOADSTATUS_TITLE + " TEXT");
- }
- if (oldVersion <= 6) {
- db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_SIMPLECHAPTERS
- + " ADD COLUMN " + PodDBAdapter.KEY_CHAPTER_TYPE + " INTEGER");
- }
- if (oldVersion <= 7) {
- db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_MEDIA
- + " ADD COLUMN " + PodDBAdapter.KEY_PLAYBACK_COMPLETION_DATE
- + " INTEGER");
- }
- if (oldVersion <= 8) {
- final int KEY_ID_POSITION = 0;
- final int KEY_MEDIA_POSITION = 1;
-
- // Add feeditem column to feedmedia table
- db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_MEDIA
- + " ADD COLUMN " + PodDBAdapter.KEY_FEEDITEM
- + " INTEGER");
- Cursor feeditemCursor = db.query(PodDBAdapter.TABLE_NAME_FEED_ITEMS,
- new String[]{PodDBAdapter.KEY_ID, PodDBAdapter.KEY_MEDIA}, "? > 0",
- new String[]{PodDBAdapter.KEY_MEDIA}, null, null, null);
- if (feeditemCursor.moveToFirst()) {
- db.beginTransaction();
- ContentValues contentValues = new ContentValues();
- do {
- long mediaId = feeditemCursor.getLong(KEY_MEDIA_POSITION);
- contentValues.put(PodDBAdapter.KEY_FEEDITEM, feeditemCursor.getLong(KEY_ID_POSITION));
- db.update(PodDBAdapter.TABLE_NAME_FEED_MEDIA, contentValues, PodDBAdapter.KEY_ID + "=?", new String[]{String.valueOf(mediaId)});
- contentValues.clear();
- } while (feeditemCursor.moveToNext());
- db.setTransactionSuccessful();
- db.endTransaction();
- }
- feeditemCursor.close();
- }
- if (oldVersion <= 9) {
- db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
- + " ADD COLUMN " + PodDBAdapter.KEY_AUTO_DOWNLOAD
- + " INTEGER DEFAULT 1");
- }
- if (oldVersion <= 10) {
- db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
- + " ADD COLUMN " + PodDBAdapter.KEY_FLATTR_STATUS
- + " INTEGER");
- db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_ITEMS
- + " ADD COLUMN " + PodDBAdapter.KEY_FLATTR_STATUS
- + " INTEGER");
- db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_MEDIA
- + " ADD COLUMN " + PodDBAdapter.KEY_PLAYED_DURATION
- + " INTEGER");
- }
- if (oldVersion <= 11) {
- db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
- + " ADD COLUMN " + PodDBAdapter.KEY_USERNAME
- + " TEXT");
- db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
- + " ADD COLUMN " + PodDBAdapter.KEY_PASSWORD
- + " TEXT");
- db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_ITEMS
- + " ADD COLUMN " + PodDBAdapter.KEY_IMAGE
- + " INTEGER");
- }
- if (oldVersion <= 12) {
- db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
- + " ADD COLUMN " + PodDBAdapter.KEY_IS_PAGED + " INTEGER DEFAULT 0");
- db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
- + " ADD COLUMN " + PodDBAdapter.KEY_NEXT_PAGE_LINK + " TEXT");
- }
- if (oldVersion <= 13) {
- // remove duplicate rows in "Chapters" table that were created because of a bug.
- db.execSQL(String.format("DELETE FROM %s WHERE %s NOT IN " +
- "(SELECT MIN(%s) as %s FROM %s GROUP BY %s,%s,%s,%s,%s)",
- PodDBAdapter.TABLE_NAME_SIMPLECHAPTERS,
- PodDBAdapter.KEY_ID,
- PodDBAdapter.KEY_ID,
- PodDBAdapter.KEY_ID,
- PodDBAdapter.TABLE_NAME_SIMPLECHAPTERS,
- PodDBAdapter.KEY_TITLE,
- PodDBAdapter.KEY_START,
- PodDBAdapter.KEY_FEEDITEM,
- PodDBAdapter.KEY_LINK,
- PodDBAdapter.KEY_CHAPTER_TYPE));
- }
- if(oldVersion <= 14) {
-
- db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_ITEMS
- + " ADD COLUMN " + PodDBAdapter.KEY_AUTO_DOWNLOAD + " INTEGER");
- db.execSQL("UPDATE " + PodDBAdapter.TABLE_NAME_FEED_ITEMS
- + " SET " + PodDBAdapter.KEY_AUTO_DOWNLOAD + " = "
- + "(SELECT " + PodDBAdapter.KEY_AUTO_DOWNLOAD
- + " FROM " + PodDBAdapter.TABLE_NAME_FEEDS
- + " WHERE " + PodDBAdapter.TABLE_NAME_FEEDS + "." + PodDBAdapter.KEY_ID
- + " = " + PodDBAdapter.TABLE_NAME_FEED_ITEMS + "." + PodDBAdapter.KEY_FEED + ")");
-
- db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
- + " ADD COLUMN " + PodDBAdapter.KEY_HIDE + " TEXT");
-
-
- db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
- + " ADD COLUMN " + PodDBAdapter.KEY_LAST_UPDATE_FAILED + " INTEGER DEFAULT 0");
-
- // create indexes
- db.execSQL(PodDBAdapter.CREATE_INDEX_FEEDITEMS_FEED);
- db.execSQL(PodDBAdapter.CREATE_INDEX_FEEDITEMS_IMAGE);
- db.execSQL(PodDBAdapter.CREATE_INDEX_FEEDMEDIA_FEEDITEM);
- db.execSQL(PodDBAdapter.CREATE_INDEX_QUEUE_FEEDITEM);
- db.execSQL(PodDBAdapter.CREATE_INDEX_SIMPLECHAPTERS_FEEDITEM);
- }
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java b/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java
new file mode 100644
index 000000000..8a4a4efbf
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java
@@ -0,0 +1,414 @@
+package de.danoeh.antennapod.dialog;
+
+import android.content.res.TypedArray;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.support.v4.app.ActivityCompat;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.ListView;
+import android.widget.Toast;
+
+import com.joanzapata.android.iconify.IconDrawable;
+import com.joanzapata.android.iconify.Iconify;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.dialog.DownloadRequestErrorDialogCreator;
+import de.danoeh.antennapod.core.feed.FeedItem;
+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.util.LongList;
+
+public class EpisodesApplyActionFragment extends Fragment {
+
+ public String TAG = "EpisodeActionFragment";
+
+ private ListView mListView;
+ private ArrayAdapter<String> mAdapter;
+
+ private Button btnAddToQueue;
+ private Button btnMarkAsPlayed;
+ private Button btnMarkAsUnplayed;
+ private Button btnDownload;
+ private Button btnDelete;
+
+ private final Map<Long,FeedItem> idMap;
+ private final List<FeedItem> episodes;
+ private final List<String> titles = new ArrayList();
+ private final LongList checkedIds = new LongList();
+
+ private MenuItem mSelectToggle;
+
+ private int textColor;
+
+ public EpisodesApplyActionFragment(List<FeedItem> episodes) {
+ this.episodes = episodes;
+ this.idMap = new HashMap<>(episodes.size());
+ for(FeedItem episode : episodes) {
+ this.idMap.put(episode.getId(), episode);
+ }
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setHasOptionsMenu(true);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ View view = inflater.inflate(R.layout.episodes_apply_action_fragment, container, false);
+
+ mListView = (ListView) view.findViewById(android.R.id.list);
+ mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
+ mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+ public void onItemClick(AdapterView<?> ListView, View view, int position, long rowId) {
+ long id = episodes.get(position).getId();
+ if (checkedIds.contains(id)) {
+ checkedIds.remove(id);
+ } else {
+ checkedIds.add(id);
+ }
+ refreshCheckboxes();
+ }
+ });
+
+ for(FeedItem episode : episodes) {
+ titles.add(episode.getTitle());
+ }
+
+ mAdapter = new ArrayAdapter<>(getActivity(),
+ android.R.layout.simple_list_item_multiple_choice, titles);
+ mListView.setAdapter(mAdapter);
+ checkAll();
+
+ btnAddToQueue = (Button) view.findViewById(R.id.btnAddToQueue);
+ btnAddToQueue.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ queueChecked();
+ }
+ });
+ btnMarkAsPlayed = (Button) view.findViewById(R.id.btnMarkAsPlayed);
+ btnMarkAsPlayed.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ markedCheckedPlayed();
+ }
+ });
+ btnMarkAsUnplayed = (Button) view.findViewById(R.id.btnMarkAsUnplayed);
+ btnMarkAsUnplayed.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ markedCheckedUnplayed();
+ }
+ });
+ btnDownload = (Button) view.findViewById(R.id.btnDownload);
+ btnDownload.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ downloadChecked();
+ }
+ });
+ btnDelete = (Button) view.findViewById(R.id.btnDelete);
+ btnDelete.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ deleteChecked();
+ }
+ });
+
+ return view;
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ super.onCreateOptionsMenu(menu, inflater);
+ inflater.inflate(R.menu.episodes_apply_action_options, menu);
+
+ int[] attrs = { android.R.attr.textColor };
+ TypedArray ta = getActivity().obtainStyledAttributes(attrs);
+ textColor = ta.getColor(0, Color.GRAY);
+ ta.recycle();
+
+ menu.findItem(R.id.sort).setIcon(new IconDrawable(getActivity(),
+ Iconify.IconValue.fa_sort).color(textColor).actionBarSize());
+
+ mSelectToggle = menu.findItem(R.id.select_toggle);
+ mSelectToggle.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
+ @Override
+ public boolean onMenuItemClick(MenuItem item) {
+ if (checkedIds.size() == episodes.size()) {
+ checkNone();
+ } else {
+ checkAll();
+ }
+ return true;
+ }
+ });
+
+ menu.findItem(R.id.select_options).setIcon(new IconDrawable(getActivity(),
+ Iconify.IconValue.fa_caret_down).color(textColor).actionBarSize());
+ }
+
+ @Override
+ public void onPrepareOptionsMenu (Menu menu) {
+ Iconify.IconValue iVal;
+ if(checkedIds.size() == episodes.size()) {
+ iVal = Iconify.IconValue.fa_check_square_o;
+ } else if(checkedIds.size() == 0) {
+ iVal = Iconify.IconValue.fa_square_o;
+ } else {
+ iVal = Iconify.IconValue.fa_minus_square_o;
+ }
+ mSelectToggle.setIcon(new IconDrawable(getActivity(), iVal).color(textColor).actionBarSize());
+
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ int resId = 0;
+ switch(item.getItemId()) {
+ case R.id.select_options:
+ return true;
+ case R.id.check_all:
+ checkAll();
+ resId = R.string.selected_all_label;
+ break;
+ case R.id.check_none:
+ checkNone();
+ resId = R.string.deselected_all_label;
+ break;
+ case R.id.check_played:
+ checkPlayed(true);
+ resId = R.string.selected_played_label;
+ break;
+ case R.id.check_unplayed:
+ checkPlayed(false);
+ resId = R.string.selected_unplayed_label;
+ break;
+ case R.id.check_downloaded:
+ checkDownloaded(true);
+ resId = R.string.selected_downloaded_label;
+ break;
+ case R.id.check_not_downloaded:
+ checkDownloaded(false);
+ resId = R.string.selected_not_downloaded_label;
+ break;
+ case R.id.sort_title_a_z:
+ sortByTitle(false);
+ return true;
+ case R.id.sort_title_z_a:
+ sortByTitle(true);
+ return true;
+ case R.id.sort_date_new_old:
+ sortByDate(true);
+ return true;
+ case R.id.sort_date_old_new:
+ sortByDate(false);
+ return true;
+ case R.id.sort_duration_long_short:
+ sortByDuration(true);
+ return true;
+ case R.id.sort_duration_short_long:
+ sortByDuration(false);
+ return true;
+ }
+ if(resId != 0) {
+ Toast.makeText(getActivity(), resId, Toast.LENGTH_SHORT).show();
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ private void sortByTitle(final boolean reverse) {
+ Collections.sort(episodes, new Comparator<FeedItem>() {
+ @Override
+ public int compare(FeedItem lhs, FeedItem rhs) {
+ if (reverse) {
+ return -1 * lhs.getTitle().compareTo(rhs.getTitle());
+ } else {
+ return lhs.getTitle().compareTo(rhs.getTitle());
+ }
+ }
+ });
+ refreshTitles();
+ refreshCheckboxes();
+ }
+
+ private void sortByDate(final boolean reverse) {
+ Collections.sort(episodes, new Comparator<FeedItem>() {
+ @Override
+ public int compare(FeedItem lhs, FeedItem rhs) {
+ if (lhs.getPubDate() == null) {
+ return -1;
+ } else if (rhs.getPubDate() == null) {
+ return 1;
+ }
+ int code = lhs.getPubDate().compareTo(rhs.getPubDate());
+ if (reverse) {
+ return -1 * code;
+ } else {
+ return code;
+ }
+ }
+ });
+ refreshTitles();
+ refreshCheckboxes();
+ }
+
+ private void sortByDuration(final boolean reverse) {
+ Collections.sort(episodes, new Comparator<FeedItem>() {
+ @Override
+ public int compare(FeedItem lhs, FeedItem rhs) {
+ int ordering;
+ if (false == lhs.hasMedia()) {
+ ordering = 1;
+ } else if (false == rhs.hasMedia()) {
+ ordering = -1;
+ } else {
+ ordering = lhs.getMedia().getDuration() - rhs.getMedia().getDuration();
+ }
+ if(reverse) {
+ return -1 * ordering;
+ } else {
+ return ordering;
+ }
+ }
+ });
+ refreshTitles();
+ refreshCheckboxes();
+ }
+
+ private void checkAll() {
+ for (FeedItem episode : episodes) {
+ if(false == checkedIds.contains(episode.getId())) {
+ checkedIds.add(episode.getId());
+ }
+ }
+ refreshCheckboxes();
+ }
+
+ private void checkNone() {
+ checkedIds.clear();
+ refreshCheckboxes();
+ }
+
+ private void checkPlayed(boolean isPlayed) {
+ for (FeedItem episode : episodes) {
+ if(episode.isPlayed() == isPlayed) {
+ if(!checkedIds.contains(episode.getId())) {
+ checkedIds.add(episode.getId());
+ }
+ } else {
+ if(checkedIds.contains(episode.getId())) {
+ checkedIds.remove(episode.getId());
+ }
+ }
+ }
+ refreshCheckboxes();
+ }
+
+ private void checkDownloaded(boolean isDownloaded) {
+ for (FeedItem episode : episodes) {
+ if(episode.hasMedia() && episode.getMedia().isDownloaded() == isDownloaded) {
+ if(!checkedIds.contains(episode.getId())) {
+ checkedIds.add(episode.getId());
+ }
+ } else {
+ if(checkedIds.contains(episode.getId())) {
+ checkedIds.remove(episode.getId());
+ }
+ }
+ }
+ refreshCheckboxes();
+ }
+
+ private void refreshTitles() {
+ titles.clear();
+ for(FeedItem episode : episodes) {
+ titles.add(episode.getTitle());
+ }
+ mAdapter.notifyDataSetChanged();
+ }
+
+ private void refreshCheckboxes() {
+ for (int i = 0; i < episodes.size(); i++) {
+ FeedItem episode = episodes.get(i);
+ boolean checked = checkedIds.contains(episode.getId());
+ mListView.setItemChecked(i, checked);
+ }
+ ActivityCompat.invalidateOptionsMenu(EpisodesApplyActionFragment.this.getActivity());
+ }
+
+ private void queueChecked() {
+ LongList orderedIds = new LongList();
+ for(FeedItem episode : episodes) {
+ if(checkedIds.contains(episode.getId())) {
+ orderedIds.add((episode.getId()));
+ }
+ }
+ DBWriter.addQueueItem(getActivity(), false, orderedIds.toArray());
+ close();
+ }
+
+ private void markedCheckedPlayed() {
+ DBWriter.markItemRead(getActivity(), true, checkedIds.toArray());
+ close();
+ }
+
+ private void markedCheckedUnplayed() {
+ DBWriter.markItemRead(getActivity(), false, checkedIds.toArray());
+ close();
+ }
+
+ private void downloadChecked() {
+ // download the check episodes in the same order as they are currently displayed
+ List<FeedItem> toDownload = new ArrayList<FeedItem>(checkedIds.size());
+ for(FeedItem episode : episodes) {
+ if(checkedIds.contains(episode.getId())) {
+ toDownload.add(episode);
+ }
+ }
+ try {
+ DBTasks.downloadFeedItems(getActivity(), toDownload.toArray(new FeedItem[0]));
+ } catch (DownloadRequestException e) {
+ e.printStackTrace();
+ DownloadRequestErrorDialogCreator.newRequestErrorDialog(getActivity(), e.getMessage());
+ }
+ close();
+ }
+
+ private void deleteChecked() {
+ for(long id : checkedIds.toArray()) {
+ FeedItem episode = idMap.get(id);
+ if(episode.hasMedia()) {
+ DBWriter.deleteFeedMediaOfItem(getActivity(), episode.getMedia().getId());
+ }
+ }
+ close();
+ }
+
+ private void close() {
+ getActivity().getSupportFragmentManager().popBackStack();
+ }
+
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/TimeDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/TimeDialog.java
index 6561d501e..5c4d4c430 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/TimeDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/TimeDialog.java
@@ -39,9 +39,9 @@ public abstract class TimeDialog extends Dialog {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
- String[] spinnerContent = new String[]{context.getString(R.string.time_unit_seconds),
- context.getString(R.string.time_unit_minutes),
- context.getString(R.string.time_unit_hours)};
+ String[] spinnerContent = new String[]{context.getString(R.string.time_seconds),
+ context.getString(R.string.time_minutes),
+ context.getString(R.string.time_hours)};
setContentView(R.layout.time_dialog);
etxtTime = (EditText) findViewById(R.id.etxtTime);
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java
index ff5485251..b4c4f1822 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java
@@ -30,8 +30,8 @@ import java.util.concurrent.atomic.AtomicReference;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
-import de.danoeh.antennapod.adapter.DefaultActionButtonCallback;
import de.danoeh.antennapod.adapter.AllEpisodesListAdapter;
+import de.danoeh.antennapod.adapter.DefaultActionButtonCallback;
import de.danoeh.antennapod.core.asynctask.DownloadObserver;
import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
import de.danoeh.antennapod.core.feed.EventDistributor;
@@ -72,10 +72,10 @@ public class AllEpisodesFragment extends Fragment {
private TextView txtvEmpty;
private ProgressBar progLoading;
private ContextMenu contextMenu;
+ private AdapterView.AdapterContextMenuInfo lastMenuInfo = null;
private List<FeedItem> episodes;
private LongList queuedItemsIds;
- private LongList newItemsIds;
private List<Downloader> downloaderList;
private boolean itemsLoaded = false;
@@ -341,12 +341,16 @@ public class AllEpisodesFragment extends Fragment {
}
contextMenu = menu;
- FeedItemMenuHandler.onPrepareMenu(contextMenuInterface, item, true, queuedItemsIds);
+ lastMenuInfo = (AdapterView.AdapterContextMenuInfo) menuInfo;
+ FeedItemMenuHandler.onPrepareMenu(getActivity(), contextMenuInterface, item, true, queuedItemsIds);
}
@Override
public boolean onContextItemSelected(MenuItem item) {
AdapterView.AdapterContextMenuInfo menuInfo = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
+ if(menuInfo == null) {
+ menuInfo = lastMenuInfo;
+ }
FeedItem selectedItem = itemAccess.getItem(menuInfo.position);
if (selectedItem == null) {
@@ -380,14 +384,7 @@ public class AllEpisodesFragment extends Fragment {
private DownloadObserver.Callback downloadObserverCallback = new DownloadObserver.Callback() {
@Override
- public void onContentChanged() {
- if (listAdapter != null) {
- listAdapter.notifyDataSetChanged();
- }
- }
-
- @Override
- public void onDownloadDataAvailable(List<Downloader> downloaderList) {
+ public void onContentChanged(List<Downloader> downloaderList) {
AllEpisodesFragment.this.downloaderList = downloaderList;
if (listAdapter != null) {
listAdapter.notifyDataSetChanged();
@@ -434,18 +431,6 @@ public class AllEpisodesFragment extends Fragment {
return false;
}
}
-
- @Override
- public boolean isNew(FeedItem item) {
- if (itemsLoaded) {
- // should actually never be called in NewEpisodesFragment, but better safe than sorry
- return showOnlyNewEpisodes || newItemsIds.contains(item.getId());
- } else {
- return false;
- }
- }
-
-
};
private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
@@ -510,8 +495,7 @@ public class AllEpisodesFragment extends Fragment {
} else {
return new Object[]{
DBReader.getRecentlyPublishedEpisodes(context, RECENT_EPISODES_LIMIT),
- DBReader.getQueueIDList(context),
- DBReader.getNewItemIds(context)
+ DBReader.getQueueIDList(context)
};
}
} else {
@@ -528,7 +512,6 @@ public class AllEpisodesFragment extends Fragment {
if (lists != null) {
episodes = (List<FeedItem>) lists[0];
queuedItemsIds = (LongList) lists[1];
- newItemsIds = (LongList) lists[2];
itemsLoaded = true;
if (viewsCreated && activity.get() != null) {
onFragmentLoaded();
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java
index 3076f8136..a1667cce0 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java
@@ -10,12 +10,14 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
-import com.squareup.picasso.Picasso;
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.load.engine.DiskCacheStrategy;
import de.danoeh.antennapod.BuildConfig;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.AudioplayerActivity;
import de.danoeh.antennapod.activity.AudioplayerActivity.AudioplayerContentFragment;
+import de.danoeh.antennapod.core.glide.ApGlideSettings;
import de.danoeh.antennapod.core.util.playback.Playable;
/**
@@ -80,8 +82,12 @@ public class CoverFragment extends Fragment implements
public void run() {
Context c = getActivity();
if (c != null) {
- Picasso.with(c)
+ Glide.with(c)
.load(media.getImageUri())
+ .placeholder(R.color.light_gray)
+ .error(R.color.light_gray)
+ .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
+ .dontAnimate()
.into(imgvCover);
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java
index fdb128f03..634c3c546 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java
@@ -11,9 +11,11 @@ import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
-import com.squareup.picasso.Picasso;
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.load.engine.DiskCacheStrategy;
import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.glide.ApGlideSettings;
import de.danoeh.antennapod.core.service.playback.PlaybackService;
import de.danoeh.antennapod.core.util.Converter;
import de.danoeh.antennapod.core.util.playback.Playable;
@@ -55,7 +57,7 @@ public class ExternalPlayerFragment extends Fragment {
public void onClick(View v) {
Log.d(TAG, "layoutInfo was clicked");
- if (controller.getMedia() != null) {
+ if (controller != null && controller.getMedia() != null) {
startActivity(PlaybackService.getPlayerActivityIntent(
getActivity(), controller.getMedia()));
}
@@ -192,14 +194,18 @@ public class ExternalPlayerFragment extends Fragment {
private boolean loadMediaInfo() {
Log.d(TAG, "Loading media info");
- if (controller.serviceAvailable()) {
+ if (controller != null && controller.serviceAvailable()) {
Playable media = controller.getMedia();
if (media != null) {
txtvTitle.setText(media.getEpisodeTitle());
- Picasso.with(getActivity())
+ Glide.with(getActivity())
.load(media.getImageUri())
- .fit()
+ .placeholder(R.color.light_gray)
+ .error(R.color.light_gray)
+ .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
+ .fitCenter()
+ .dontAnimate()
.into(imgvCover);
fragmentLayout.setVisibility(View.VISIBLE);
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java
index a7c6d62e6..9693e6886 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java
@@ -25,12 +25,12 @@ import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Toast;
-import de.danoeh.antennapod.BuildConfig;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.util.Converter;
+import de.danoeh.antennapod.core.util.IntentUtils;
import de.danoeh.antennapod.core.util.ShareUtils;
import de.danoeh.antennapod.core.util.ShownotesProvider;
import de.danoeh.antennapod.core.util.playback.Playable;
@@ -104,8 +104,7 @@ public class ItemDescriptionFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Creating view");
+ Log.d(TAG, "Creating view");
webvDescription = new WebView(getActivity());
if (UserPreferences.getTheme() == R.style.Theme_AntennaPod_Dark) {
if (Build.VERSION.SDK_INT >= 11
@@ -141,8 +140,7 @@ public class ItemDescriptionFragment extends Fragment {
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Page finished");
+ Log.d(TAG, "Page finished");
// Restoring the scroll position might not always work
view.postDelayed(new Runnable() {
@@ -163,15 +161,13 @@ public class ItemDescriptionFragment extends Fragment {
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Fragment attached");
+ Log.d(TAG, "Fragment attached");
}
@Override
public void onDetach() {
super.onDetach();
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Fragment detached");
+ Log.d(TAG, "Fragment detached");
if (webViewLoader != null) {
webViewLoader.cancel(true);
}
@@ -180,8 +176,7 @@ public class ItemDescriptionFragment extends Fragment {
@Override
public void onDestroy() {
super.onDestroy();
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Fragment destroyed");
+ Log.d(TAG, "Fragment destroyed");
if (webViewLoader != null) {
webViewLoader.cancel(true);
}
@@ -195,8 +190,7 @@ public class ItemDescriptionFragment extends Fragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Creating fragment");
+ Log.d(TAG, "Creating fragment");
Bundle args = getArguments();
saveState = args.getBoolean(ARG_SAVE_STATE, false);
highlightTimecodes = args.getBoolean(ARG_HIGHLIGHT_TIMECODES, false);
@@ -258,11 +252,7 @@ public class ItemDescriptionFragment extends Fragment {
WebView.HitTestResult r = webvDescription.getHitTestResult();
if (r != null
&& r.getType() == WebView.HitTestResult.SRC_ANCHOR_TYPE) {
- if (BuildConfig.DEBUG)
- Log.d(TAG,
- "Link of webview was long-pressed. Extra: "
- + r.getExtra()
- );
+ Log.d(TAG, "Link of webview was long-pressed. Extra: " + r.getExtra());
selectedURL = r.getExtra();
webvDescription.showContextMenu();
return true;
@@ -281,8 +271,10 @@ public class ItemDescriptionFragment extends Fragment {
switch (item.getItemId()) {
case R.id.open_in_browser_item:
Uri uri = Uri.parse(selectedURL);
- getActivity()
- .startActivity(new Intent(Intent.ACTION_VIEW, uri));
+ final Intent intent = new Intent(Intent.ACTION_VIEW, uri);
+ if(IntentUtils.isCallable(getActivity(), intent)) {
+ getActivity().startActivity(intent);
+ }
break;
case R.id.share_url_item:
ShareUtils.shareLink(getActivity(), selectedURL);
@@ -331,8 +323,12 @@ public class ItemDescriptionFragment extends Fragment {
R.string.go_to_position_label);
menu.setHeaderTitle(Converter.getDurationStringLong(Timeline.getTimecodeLinkTime(selectedURL)));
} else {
- menu.add(Menu.NONE, R.id.open_in_browser_item, Menu.NONE,
- R.string.open_in_browser_label);
+ Uri uri = Uri.parse(selectedURL);
+ final Intent intent = new Intent(Intent.ACTION_VIEW, uri);
+ if(IntentUtils.isCallable(getActivity(), intent)) {
+ menu.add(Menu.NONE, R.id.open_in_browser_item, Menu.NONE,
+ R.string.open_in_browser_label);
+ }
menu.add(Menu.NONE, R.id.copy_url_item, Menu.NONE,
R.string.copy_url_label);
menu.add(Menu.NONE, R.id.share_url_item, Menu.NONE,
@@ -358,8 +354,7 @@ public class ItemDescriptionFragment extends Fragment {
// /webvDescription.loadData(url, "text/html", "utf-8");
webvDescription.loadDataWithBaseURL(null, data, "text/html",
"utf-8", "about:blank");
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Webview loaded");
+ Log.d(TAG, "Webview loaded");
webViewLoader = null;
}
@@ -370,8 +365,7 @@ public class ItemDescriptionFragment extends Fragment {
@Override
protected Void doInBackground(Void... params) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Loading Webview");
+ Log.d(TAG, "Loading Webview");
try {
Activity activity = getActivity();
if (activity != null) {
@@ -397,24 +391,17 @@ public class ItemDescriptionFragment extends Fragment {
private void savePreference() {
if (saveState) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Saving preferences");
+ Log.d(TAG, "Saving preferences");
SharedPreferences prefs = getActivity().getSharedPreferences(PREF,
Activity.MODE_PRIVATE);
SharedPreferences.Editor editor = prefs.edit();
if (media != null && webvDescription != null) {
- if (BuildConfig.DEBUG)
- Log.d(TAG,
- "Saving scroll position: "
- + webvDescription.getScrollY()
- );
+ Log.d(TAG, "Saving scroll position: " + webvDescription.getScrollY());
editor.putInt(PREF_SCROLL_Y, webvDescription.getScrollY());
editor.putString(PREF_PLAYABLE_ID, media.getIdentifier()
.toString());
} else {
- if (BuildConfig.DEBUG)
- Log.d(TAG,
- "savePreferences was called while media or webview was null");
+ Log.d(TAG, "savePreferences was called while media or webview was null");
editor.putInt(PREF_SCROLL_Y, -1);
editor.putString(PREF_PLAYABLE_ID, "");
}
@@ -424,8 +411,7 @@ public class ItemDescriptionFragment extends Fragment {
private boolean restoreFromPreference() {
if (saveState) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Restoring from preferences");
+ Log.d(TAG, "Restoring from preferences");
Activity activity = getActivity();
if (activity != null) {
SharedPreferences prefs = activity.getSharedPreferences(
@@ -435,8 +421,7 @@ public class ItemDescriptionFragment extends Fragment {
if (scrollY != -1 && media != null
&& id.equals(media.getIdentifier().toString())
&& webvDescription != null) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Restored scroll Position: " + scrollY);
+ Log.d(TAG, "Restored scroll Position: " + scrollY);
webvDescription.scrollTo(webvDescription.getScrollX(),
scrollY);
return true;
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 51a1e2252..4edb7f36f 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java
@@ -1,7 +1,8 @@
package de.danoeh.antennapod.fragment;
import android.annotation.TargetApi;
-import android.content.ActivityNotFoundException;
+import android.content.ClipData;
+import android.content.Context;
import android.content.Intent;
import android.content.res.TypedArray;
import android.net.Uri;
@@ -18,7 +19,9 @@ import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.Log;
+import android.view.ContextMenu;
import android.view.LayoutInflater;
+import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
@@ -32,7 +35,8 @@ import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
-import com.squareup.picasso.Picasso;
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.load.engine.DiskCacheStrategy;
import java.util.List;
@@ -45,6 +49,7 @@ 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.QueueEvent;
+import de.danoeh.antennapod.core.glide.ApGlideSettings;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.service.download.Downloader;
import de.danoeh.antennapod.core.storage.DBReader;
@@ -53,7 +58,9 @@ 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.IntentUtils;
import de.danoeh.antennapod.core.util.LongList;
+import de.danoeh.antennapod.core.util.ShareUtils;
import de.danoeh.antennapod.core.util.playback.Timeline;
import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
import de.greenrobot.event.EventBus;
@@ -107,6 +114,11 @@ public class ItemFragment extends Fragment implements LoaderManager.LoaderCallba
private ImageButton butMore;
private PopupMenu popupMenu;
+ /**
+ * URL that was selected via long-press.
+ */
+ private String selectedURL;
+
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -194,20 +206,19 @@ public class ItemFragment extends Fragment implements LoaderManager.LoaderCallba
webvDescription.getSettings().setLayoutAlgorithm(
WebSettings.LayoutAlgorithm.NARROW_COLUMNS);
webvDescription.getSettings().setLoadWithOverviewMode(true);
+ webvDescription.setOnLongClickListener(webViewLongClickListener);
webvDescription.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
- try {
+ if(IntentUtils.isCallable(getActivity(), intent)) {
startActivity(intent);
- } catch (ActivityNotFoundException e) {
- e.printStackTrace();
- return true;
}
return true;
}
});
+ registerForContextMenu(webvDescription);
imgvCover = (ImageView) header.findViewById(R.id.imgvCover);
progbarDownload = (ProgressBar) header.findViewById(R.id.progbarDownload);
@@ -272,10 +283,10 @@ public class ItemFragment extends Fragment implements LoaderManager.LoaderCallba
popupMenu.getMenu().clear();
popupMenu.inflate(R.menu.feeditem_options);
if (item.hasMedia()) {
- FeedItemMenuHandler.onPrepareMenu(popupMenuInterface, item, true, queue);
+ FeedItemMenuHandler.onPrepareMenu(getActivity(), popupMenuInterface, item, true, queue);
} else {
// these are already available via button1 and button2
- FeedItemMenuHandler.onPrepareMenu(popupMenuInterface, item, true, queue,
+ FeedItemMenuHandler.onPrepareMenu(getActivity(), popupMenuInterface, item, true, queue,
R.id.mark_read_item, R.id.visit_website_item);
}
popupMenu.show();
@@ -313,7 +324,7 @@ public class ItemFragment extends Fragment implements LoaderManager.LoaderCallba
private void onFragmentLoaded() {
- progbarLoading.setVisibility(View.GONE);
+ progbarLoading.setVisibility(View.INVISIBLE);
if (webviewData != null) {
webvDescription.loadDataWithBaseURL(null, webviewData, "text/html",
"utf-8", "about:blank");
@@ -327,10 +338,16 @@ public class ItemFragment extends Fragment implements LoaderManager.LoaderCallba
txtvTitle.setText(item.getTitle());
txtvPublished.setText(DateUtils.formatDateTime(getActivity(), item.getPubDate().getTime(), DateUtils.FORMAT_ABBREV_ALL));
- Picasso.with(getActivity()).load(item.getImageUri())
- .fit()
+ Glide.with(getActivity())
+ .load(item.getImageUri())
+ .placeholder(R.color.light_gray)
+ .error(R.color.light_gray)
+ .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
+ .fitCenter()
+ .dontAnimate()
.into(imgvCover);
- progbarDownload.setVisibility(View.GONE);
+
+ progbarDownload.setVisibility(View.INVISIBLE);
if (item.hasMedia() && downloaderList != null) {
for (Downloader downloader : downloaderList) {
if (downloader.getDownloadRequest().getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA
@@ -346,7 +363,7 @@ public class ItemFragment extends Fragment implements LoaderManager.LoaderCallba
TypedArray drawables = getActivity().obtainStyledAttributes(new int[]{R.attr.navigation_accept,
R.attr.location_web_site});
- if (!item.isRead()) {
+ if (!item.isPlayed()) {
butAction1.setCompoundDrawablesWithIntrinsicBounds(drawables.getDrawable(0), null, null, null);
butAction1.setText(getActivity().getString(R.string.mark_read_label));
butAction1.setVisibility(View.VISIBLE);
@@ -398,6 +415,83 @@ public class ItemFragment extends Fragment implements LoaderManager.LoaderCallba
getLoaderManager().restartLoader(0, null, ItemFragment.this);
}
+ private View.OnLongClickListener webViewLongClickListener = new View.OnLongClickListener() {
+
+ @Override
+ public boolean onLongClick(View v) {
+ WebView.HitTestResult r = webvDescription.getHitTestResult();
+ if (r != null
+ && r.getType() == WebView.HitTestResult.SRC_ANCHOR_TYPE) {
+ Log.d(TAG, "Link of webview was long-pressed. Extra: " + r.getExtra());
+ selectedURL = r.getExtra();
+ webvDescription.showContextMenu();
+ return true;
+ }
+ selectedURL = null;
+ return false;
+ }
+ };
+
+ @Override
+ public boolean onContextItemSelected(MenuItem item) {
+ boolean handled = selectedURL != null;
+ if (selectedURL != null) {
+ switch (item.getItemId()) {
+ case R.id.open_in_browser_item:
+ Uri uri = Uri.parse(selectedURL);
+ final Intent intent = new Intent(Intent.ACTION_VIEW, uri);
+ if(IntentUtils.isCallable(getActivity(), intent)) {
+ getActivity().startActivity(intent);
+ }
+ break;
+ case R.id.share_url_item:
+ ShareUtils.shareLink(getActivity(), selectedURL);
+ break;
+ case R.id.copy_url_item:
+ if (android.os.Build.VERSION.SDK_INT >= 11) {
+ ClipData clipData = ClipData.newPlainText(selectedURL,
+ selectedURL);
+ android.content.ClipboardManager cm = (android.content.ClipboardManager) getActivity()
+ .getSystemService(Context.CLIPBOARD_SERVICE);
+ cm.setPrimaryClip(clipData);
+ } else {
+ android.text.ClipboardManager cm = (android.text.ClipboardManager) getActivity()
+ .getSystemService(Context.CLIPBOARD_SERVICE);
+ cm.setText(selectedURL);
+ }
+ Toast t = Toast.makeText(getActivity(),
+ R.string.copied_url_msg, Toast.LENGTH_SHORT);
+ t.show();
+ break;
+ default:
+ handled = false;
+ break;
+
+ }
+ selectedURL = null;
+ }
+ return handled;
+ }
+
+ @Override
+ public void onCreateContextMenu(ContextMenu menu, View v,
+ ContextMenu.ContextMenuInfo menuInfo) {
+ if (selectedURL != null) {
+ super.onCreateContextMenu(menu, v, menuInfo);
+ Uri uri = Uri.parse(selectedURL);
+ final Intent intent = new Intent(Intent.ACTION_VIEW, uri);
+ if(IntentUtils.isCallable(getActivity(), intent)) {
+ menu.add(Menu.NONE, R.id.open_in_browser_item, Menu.NONE,
+ R.string.open_in_browser_label);
+ }
+ menu.add(Menu.NONE, R.id.copy_url_item, Menu.NONE,
+ R.string.copy_url_label);
+ menu.add(Menu.NONE, R.id.share_url_item, Menu.NONE,
+ R.string.share_url_label);
+ menu.setHeaderTitle(selectedURL);
+ }
+ }
+
@Override
public Loader<Pair<FeedItem,LongList>> onCreateLoader(int id, Bundle args) {
return new DBTaskLoader<Pair<FeedItem,LongList>>(getActivity()) {
@@ -445,14 +539,7 @@ public class ItemFragment extends Fragment implements LoaderManager.LoaderCallba
private final DownloadObserver.Callback downloadObserverCallback = new DownloadObserver.Callback() {
@Override
- public void onContentChanged() {
- if (itemsLoaded && getActivity() != null) {
- updateAppearance();
- }
- }
-
- @Override
- public void onDownloadDataAvailable(List<Downloader> downloaderList) {
+ public void onContentChanged(List<Downloader> downloaderList) {
ItemFragment.this.downloaderList = downloaderList;
if (itemsLoaded && getActivity() != null) {
updateAppearance();
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 a9cbe8291..63ebf234e 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java
@@ -4,13 +4,16 @@ import android.annotation.SuppressLint;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
+import android.content.res.TypedArray;
+import android.graphics.Color;
+import android.graphics.LightingColorFilter;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
+import android.support.v4.app.Fragment;
import android.support.v4.app.ListFragment;
import android.support.v4.view.MenuItemCompat;
-
import android.support.v7.app.ActionBarActivity;
import android.support.v7.widget.SearchView;
import android.util.Log;
@@ -29,8 +32,10 @@ import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.TextView;
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.load.engine.DiskCacheStrategy;
+import com.joanzapata.android.iconify.IconDrawable;
import com.joanzapata.android.iconify.Iconify;
-import com.squareup.picasso.Picasso;
import org.apache.commons.lang3.Validate;
@@ -43,7 +48,6 @@ import de.danoeh.antennapod.adapter.DefaultActionButtonCallback;
import de.danoeh.antennapod.adapter.FeedItemlistAdapter;
import de.danoeh.antennapod.core.asynctask.DownloadObserver;
import de.danoeh.antennapod.core.asynctask.FeedRemover;
-import de.danoeh.antennapod.core.asynctask.PicassoProvider;
import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
import de.danoeh.antennapod.core.dialog.DownloadRequestErrorDialogCreator;
import de.danoeh.antennapod.core.feed.EventDistributor;
@@ -53,6 +57,8 @@ import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedItemFilter;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.feed.QueueEvent;
+import de.danoeh.antennapod.core.glide.ApGlideSettings;
+import de.danoeh.antennapod.core.glide.FastBlurTransformation;
import de.danoeh.antennapod.core.service.download.DownloadService;
import de.danoeh.antennapod.core.service.download.Downloader;
import de.danoeh.antennapod.core.storage.DBReader;
@@ -61,6 +67,7 @@ import de.danoeh.antennapod.core.storage.DownloadRequestException;
import de.danoeh.antennapod.core.storage.DownloadRequester;
import de.danoeh.antennapod.core.util.LongList;
import de.danoeh.antennapod.core.util.gui.MoreContentListFooterUtil;
+import de.danoeh.antennapod.dialog.EpisodesApplyActionFragment;
import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
import de.danoeh.antennapod.menuhandler.FeedMenuHandler;
import de.danoeh.antennapod.menuhandler.MenuItemUtils;
@@ -83,12 +90,11 @@ public class ItemlistFragment extends ListFragment {
protected FeedItemlistAdapter adapter;
private ContextMenu contextMenu;
+ private AdapterView.AdapterContextMenuInfo lastMenuInfo = null;
private long feedID;
private Feed feed;
private LongList queuedItemsIds;
- private LongList newItemsIds;
-
private boolean itemsLoaded = false;
private boolean viewsCreated = false;
@@ -155,6 +161,7 @@ public class ItemlistFragment extends ListFragment {
@Override
public void onResume() {
super.onResume();
+ Log.d(TAG, "onResume()");
updateProgressBarVisibility();
startItemLoader();
}
@@ -217,6 +224,18 @@ public class ItemlistFragment extends ListFragment {
return false;
}
});
+ if(feed == null || feed.getLink() == null) {
+ menu.findItem(R.id.share_link_item).setVisible(false);
+ menu.findItem(R.id.visit_website_item).setVisible(false);
+ }
+ int[] attrs = { android.R.attr.textColor };
+ TypedArray ta = getActivity().obtainStyledAttributes(attrs);
+ int textColor = ta.getColor(0, Color.GRAY);
+ ta.recycle();
+
+ menu.findItem(R.id.episode_actions).setIcon(new IconDrawable(getActivity(),
+ Iconify.IconValue.fa_gears).color(textColor).actionBarSize());
+
isUpdatingFeed = MenuItemUtils.updateRefreshMenuItem(menu, R.id.refresh_item, updateRefreshMenuItemChecker);
}
}
@@ -234,6 +253,10 @@ public class ItemlistFragment extends ListFragment {
try {
if (!FeedMenuHandler.onOptionsItemClicked(getActivity(), item, feed)) {
switch (item.getItemId()) {
+ case R.id.episode_actions:
+ Fragment fragment = new EpisodesApplyActionFragment(feed.getItems());
+ ((MainActivity)getActivity()).loadChildFragment(fragment);
+ return true;
case R.id.remove_item:
final FeedRemover remover = new FeedRemover(
getActivity(), feed) {
@@ -302,12 +325,16 @@ public class ItemlistFragment extends ListFragment {
}
contextMenu = menu;
- FeedItemMenuHandler.onPrepareMenu(contextMenuInterface, item, true, queuedItemsIds);
+ lastMenuInfo = (AdapterView.AdapterContextMenuInfo) menuInfo;
+ FeedItemMenuHandler.onPrepareMenu(getActivity(), contextMenuInterface, item, true, queuedItemsIds);
}
@Override
public boolean onContextItemSelected(MenuItem item) {
AdapterView.AdapterContextMenuInfo menuInfo = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
+ if(menuInfo == null) {
+ menuInfo = lastMenuInfo;
+ }
// because of addHeaderView(), positions are increased by 1!
FeedItem selectedItem = itemAccess.getItem(menuInfo.position-1);
@@ -396,12 +423,15 @@ public class ItemlistFragment extends ListFragment {
private boolean insideOnFragmentLoaded = false;
private void onFragmentLoaded() {
+ if(!isVisible()) {
+ return;
+ }
insideOnFragmentLoaded = true;
if (adapter == null) {
setListAdapter(null);
setupHeaderView();
setupFooterView();
- adapter = new FeedItemlistAdapter(getActivity(), itemAccess, new DefaultActionButtonCallback(getActivity()), false);
+ adapter = new FeedItemlistAdapter(getActivity(), itemAccess, new DefaultActionButtonCallback(getActivity()), false, true);
setListAdapter(adapter);
downloadObserver = new DownloadObserver(getActivity(), new Handler(), downloadObserverCallback);
downloadObserver.onResume();
@@ -421,6 +451,10 @@ public class ItemlistFragment extends ListFragment {
}
private void refreshHeaderView() {
+ if (getListView() == null || feed == null) {
+ Log.e(TAG, "Unable to setup listview: listView = null or feed = null");
+ return;
+ }
if(feed.hasLastUpdateFailed()) {
txtvFailure.setVisibility(View.VISIBLE);
} else {
@@ -448,14 +482,7 @@ public class ItemlistFragment extends ListFragment {
private DownloadObserver.Callback downloadObserverCallback = new DownloadObserver.Callback() {
@Override
- public void onContentChanged() {
- if (adapter != null) {
- adapter.notifyDataSetChanged();
- }
- }
-
- @Override
- public void onDownloadDataAvailable(List<Downloader> downloaderList) {
+ public void onContentChanged(List<Downloader> downloaderList) {
ItemlistFragment.this.downloaderList = downloaderList;
if (adapter != null) {
adapter.notifyDataSetChanged();
@@ -485,17 +512,26 @@ public class ItemlistFragment extends ListFragment {
txtvTitle.setText(feed.getTitle());
txtvAuthor.setText(feed.getAuthor());
- Picasso.with(getActivity())
+
+ // https://github.com/bumptech/glide/issues/529
+ imgvBackground.setColorFilter(new LightingColorFilter(0xff828282, 0x000000));
+
+ Glide.with(getActivity())
.load(feed.getImageUri())
.placeholder(R.color.image_readability_tint)
.error(R.color.image_readability_tint)
- .transform(PicassoProvider.blurTransformation)
- .resize(PicassoProvider.BLUR_IMAGE_SIZE, PicassoProvider.BLUR_IMAGE_SIZE)
+ .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
+ .transform(new FastBlurTransformation(getActivity()))
+ .dontAnimate()
.into(imgvBackground);
- Picasso.with(getActivity())
+ Glide.with(getActivity())
.load(feed.getImageUri())
- .fit()
+ .placeholder(R.color.light_gray)
+ .error(R.color.light_gray)
+ .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
+ .fitCenter()
+ .dontAnimate()
.into(imgvCover);
butShowInfo.setOnClickListener(new View.OnClickListener() {
@@ -558,11 +594,6 @@ public class ItemlistFragment extends ListFragment {
}
@Override
- public boolean isNew(FeedItem item) {
- return (newItemsIds != null) && newItemsIds.contains(item.getId());
- }
-
- @Override
public int getItemDownloadProgressPercent(FeedItem item) {
if (downloaderList != null) {
for (Downloader downloader : downloaderList) {
@@ -599,13 +630,12 @@ public class ItemlistFragment extends ListFragment {
Context context = getActivity();
if (context != null) {
Feed feed = DBReader.getFeed(context, feedID);
- if(feed.getItemFilter() != null) {
+ if(feed != null && feed.getItemFilter() != null) {
FeedItemFilter filter = feed.getItemFilter();
feed.setItems(filter.filter(context, feed.getItems()));
}
LongList queuedItemsIds = DBReader.getQueueIDList(context);
- LongList newItemsIds = DBReader.getNewItemIds(context);
- return new Object[] { feed, queuedItemsIds, newItemsIds };
+ return new Object[] { feed, queuedItemsIds };
} else {
return null;
}
@@ -617,7 +647,6 @@ public class ItemlistFragment extends ListFragment {
if (res != null) {
feed = (Feed) res[0];
queuedItemsIds = (LongList) res[1];
- newItemsIds = res[2] == null ? null : (LongList) res[2];
itemsLoaded = true;
if (viewsCreated) {
onFragmentLoaded();
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java
index 16789d694..edd4da7fe 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java
@@ -22,6 +22,8 @@ import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
@@ -31,7 +33,7 @@ import de.danoeh.antennapod.activity.OnlineFeedViewActivity;
import de.danoeh.antennapod.adapter.itunes.ItunesAdapter;
import de.danoeh.antennapod.core.preferences.UserPreferences;
-import static de.danoeh.antennapod.adapter.itunes.ItunesAdapter.*;
+import static de.danoeh.antennapod.adapter.itunes.ItunesAdapter.Podcast;
//Searches iTunes store for given string and displays results in a list
public class ItunesSearchFragment extends Fragment {
@@ -160,8 +162,18 @@ public class ItunesSearchFragment extends Fragment {
*
* @param query Search string
*/
- public SearchTask(String query){
- this.query = query;
+ public SearchTask(String query) {
+ String encodedQuery = null;
+ try {
+ encodedQuery = URLEncoder.encode(query, "UTF-8");
+ } catch(UnsupportedEncodingException e) {
+ // this won't ever be thrown
+ }
+ if(encodedQuery != null) {
+ this.query = encodedQuery;
+ } else {
+ this.query = query; // failsafe
+ }
}
//Get the podcast data
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 4bce3c7ba..9a25674b6 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java
@@ -72,7 +72,7 @@ public class NewEpisodesFragment extends AllEpisodesFragment {
Log.d(TAG, "remove(" + which + ")");
stopItemLoader();
FeedItem item = (FeedItem) listView.getAdapter().getItem(which);
- DBWriter.markItemRead(getActivity(), item.getId(), true);
+ DBWriter.markItemRead(getActivity(), true, item.getId());
undoBarController.showUndoBar(false,
getString(R.string.marked_as_read_label), new FeedItemUndoToken(item,
which)
@@ -88,7 +88,7 @@ public class NewEpisodesFragment extends AllEpisodesFragment {
public void onUndo(FeedItemUndoToken token) {
if (token != null) {
long itemId = token.getFeedItemId();
- DBWriter.markItemRead(context, itemId, false);
+ DBWriter.markItemRead(context, false, itemId);
}
}
@Override
@@ -97,7 +97,7 @@ public class NewEpisodesFragment extends AllEpisodesFragment {
long itemId = token.getFeedItemId();
FeedItem item = DBReader.getFeedItem(context, itemId);
FeedMedia media = item.getMedia();
- if(media != null && media.hasAlmostEnded() && UserPreferences.isAutoDelete()) {
+ if(media != null && media.hasAlmostEnded() && item.getFeed().getPreferences().getCurrentAutoDelete()) {
DBWriter.deleteFeedMediaOfItem(context, media.getId());
}
}
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 9099829d8..b094133d3 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java
@@ -192,7 +192,10 @@ public class PlaybackHistoryFragment extends ListFragment {
private void onFragmentLoaded() {
if (adapter == null) {
- adapter = new FeedItemlistAdapter(getActivity(), itemAccess, new DefaultActionButtonCallback(activity.get()), true);
+ // played items shoudln't be transparent for this fragment since, *all* items
+ // in this fragment will, by definition, be played. So it serves no purpose and can make
+ // it harder to read.
+ adapter = new FeedItemlistAdapter(getActivity(), itemAccess, new DefaultActionButtonCallback(activity.get()), true, false);
setListAdapter(adapter);
downloadObserver = new DownloadObserver(activity.get(), new Handler(), downloadObserverCallback);
downloadObserver.onResume();
@@ -204,14 +207,7 @@ public class PlaybackHistoryFragment extends ListFragment {
private DownloadObserver.Callback downloadObserverCallback = new DownloadObserver.Callback() {
@Override
- public void onContentChanged() {
- if (adapter != null) {
- adapter.notifyDataSetChanged();
- }
- }
-
- @Override
- public void onDownloadDataAvailable(List<Downloader> downloaderList) {
+ public void onContentChanged(List<Downloader> downloaderList) {
PlaybackHistoryFragment.this.downloaderList = downloaderList;
if (adapter != null) {
adapter.notifyDataSetChanged();
@@ -226,11 +222,6 @@ public class PlaybackHistoryFragment extends ListFragment {
}
@Override
- public boolean isNew(FeedItem item) {
- return false;
- }
-
- @Override
public int getItemDownloadProgressPercent(FeedItem item) {
if (downloaderList != null) {
for (Downloader downloader : downloaderList) {
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 d82c7b8f7..24c9fc425 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java
@@ -47,6 +47,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.LongList;
import de.danoeh.antennapod.core.util.QueueSorter;
import de.danoeh.antennapod.core.util.gui.FeedItemUndoToken;
@@ -66,12 +67,14 @@ public class QueueFragment extends Fragment {
EventDistributor.DOWNLOAD_QUEUED |
EventDistributor.PLAYER_STATUS_UPDATE;
+ private TextView infoBar;
private DragSortListView listView;
private QueueListAdapter listAdapter;
private TextView txtvEmpty;
private ProgressBar progLoading;
private ContextMenu contextMenu;
+ private AdapterView.AdapterContextMenuInfo lastMenuInfo = null;
private UndoBarController<FeedItemUndoToken> undoBarController;
@@ -325,16 +328,20 @@ public class QueueFragment extends Fragment {
}
contextMenu = menu;
+ lastMenuInfo = (AdapterView.AdapterContextMenuInfo) menuInfo;
LongList queueIds = new LongList(queue.size());
for(FeedItem queueItem : queue) {
queueIds.add(queueItem.getId());
}
- FeedItemMenuHandler.onPrepareMenu(contextMenuInterface, item, true, queueIds);
+ FeedItemMenuHandler.onPrepareMenu(getActivity(), contextMenuInterface, item, true, queueIds);
}
@Override
public boolean onContextItemSelected(MenuItem item) {
AdapterView.AdapterContextMenuInfo menuInfo = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
+ if(menuInfo == null) {
+ menuInfo = lastMenuInfo;
+ }
FeedItem selectedItem = itemAccess.getItem(menuInfo.position);
if (selectedItem == null) {
@@ -358,6 +365,7 @@ public class QueueFragment extends Fragment {
((MainActivity) getActivity()).getSupportActionBar().setTitle(R.string.queue_label);
View root = inflater.inflate(R.layout.queue_fragment, container, false);
+ infoBar = (TextView) root.findViewById(R.id.info_bar);
listView = (DragSortListView) root.findViewById(android.R.id.list);
txtvEmpty = (TextView) root.findViewById(android.R.id.empty);
progLoading = (ProgressBar) root.findViewById(R.id.progLoading);
@@ -426,7 +434,7 @@ public class QueueFragment extends Fragment {
long itemId = token.getFeedItemId();
FeedItem item = DBReader.getFeedItem(context, itemId);
FeedMedia media = item.getMedia();
- if(media != null && media.hasAlmostEnded() && UserPreferences.isAutoDelete()) {
+ if(media != null && media.hasAlmostEnded() && item.getFeed().getPreferences().getCurrentAutoDelete()) {
DBWriter.deleteFeedMediaOfItem(context, media.getId());
}
}
@@ -464,18 +472,25 @@ public class QueueFragment extends Fragment {
// we need to refresh the options menu because it sometimes
// needs data that may have just been loaded.
getActivity().supportInvalidateOptionsMenu();
- }
- private DownloadObserver.Callback downloadObserverCallback = new DownloadObserver.Callback() {
- @Override
- public void onContentChanged() {
- if (listAdapter != null && !blockDownloadObserverUpdate) {
- listAdapter.notifyDataSetChanged();
+ // refresh information bar
+ String info = queue.size() + getString(R.string.episodes_suffix);
+ if(queue.size() > 0) {
+ long duration = 0;
+ for(FeedItem item : queue) {
+ if(item.getMedia() != null) {
+ duration += item.getMedia().getDuration();
+ }
}
+ info += " \u2022 ";
+ info += Converter.getDurationStringLocalized(getActivity(), duration);
}
+ infoBar.setText(info);
+ }
+ private DownloadObserver.Callback downloadObserverCallback = new DownloadObserver.Callback() {
@Override
- public void onDownloadDataAvailable(List<Downloader> downloaderList) {
+ public void onContentChanged(List<Downloader> downloaderList) {
QueueFragment.this.downloaderList = downloaderList;
if (listAdapter != null && !blockDownloadObserverUpdate) {
listAdapter.notifyDataSetChanged();
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/RunningDownloadsFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/RunningDownloadsFragment.java
index b1b61f74b..eb4d18328 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/RunningDownloadsFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/RunningDownloadsFragment.java
@@ -3,6 +3,7 @@ package de.danoeh.antennapod.fragment;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.ListFragment;
+import android.util.Log;
import android.view.View;
import android.widget.ListView;
import android.widget.Toast;
@@ -24,7 +25,7 @@ import de.danoeh.antennapod.core.storage.DownloadRequester;
* Displays all running downloads and provides actions to cancel them
*/
public class RunningDownloadsFragment extends ListFragment {
- private static final String TAG = "RunningDownloadsFragment";
+ private static final String TAG = "RunningDownloadsFrag";
private DownloadObserver downloadObserver;
private List<Downloader> downloaderList;
@@ -53,12 +54,8 @@ public class RunningDownloadsFragment extends ListFragment {
downloadObserver = new DownloadObserver(getActivity(), new Handler(), new DownloadObserver.Callback() {
@Override
- public void onContentChanged() {
- downloadlistAdapter.notifyDataSetChanged();
- }
-
- @Override
- public void onDownloadDataAvailable(List<Downloader> downloaderList) {
+ public void onContentChanged(List<Downloader> downloaderList) {
+ Log.d(TAG, "onContentChanged: downloaderList.size() == " + downloaderList.size());
RunningDownloadsFragment.this.downloaderList = downloaderList;
downloadlistAdapter.notifyDataSetChanged();
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java
index fc6225409..975493ce9 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java
@@ -120,7 +120,7 @@ public class SearchFragment extends ListFragment {
SearchResult result = (SearchResult) l.getAdapter().getItem(position);
FeedComponent comp = result.getComponent();
if (comp.getClass() == Feed.class) {
- ((MainActivity) getActivity()).loadFeedFragmentById(comp.getId());
+ ((MainActivity) getActivity()).loadFeedFragmentById(comp.getId(), null);
} else {
if (comp.getClass() == FeedItem.class) {
FeedItem item = (FeedItem) comp;
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/PodcastListFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/PodcastListFragment.java
index 6139a4901..623c6faa7 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/PodcastListFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/PodcastListFragment.java
@@ -62,7 +62,10 @@ public abstract class PodcastListFragment extends Fragment {
@Override
public boolean onQueryTextSubmit(String s) {
sv.clearFocus();
- ((MainActivity) getActivity()).loadChildFragment(SearchListFragment.newInstance(s));
+ MainActivity activity = (MainActivity)getActivity();
+ if (activity != null) {
+ activity.loadChildFragment(SearchListFragment.newInstance(s));
+ }
return true;
}
diff --git a/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java
index fe1a09149..3e2fdf24f 100644
--- a/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java
+++ b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java
@@ -4,6 +4,7 @@ import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.util.Log;
+import android.widget.Toast;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.feed.FeedItem;
@@ -16,7 +17,7 @@ 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;
-import de.danoeh.antennapod.core.storage.DownloadRequester;
+import de.danoeh.antennapod.core.util.IntentUtils;
import de.danoeh.antennapod.core.util.LongList;
import de.danoeh.antennapod.core.util.ShareUtils;
@@ -56,7 +57,7 @@ public class FeedItemMenuHandler {
* @param queueAccess Used for testing if the queue contains the selected item
* @return Returns true if selectedItem is not null.
*/
- public static boolean onPrepareMenu(MenuInterface mi, FeedItem selectedItem,
+ public static boolean onPrepareMenu(Context context, MenuInterface mi, FeedItem selectedItem,
boolean showExtendedMenu, LongList queueAccess) {
if (selectedItem == null) {
return false;
@@ -84,8 +85,19 @@ public class FeedItemMenuHandler {
if (!(!isInQueue && selectedItem.getMedia() != null)) {
mi.setItemVisibility(R.id.add_to_queue_item, false);
}
+
if (!showExtendedMenu || selectedItem.getLink() == null) {
+ mi.setItemVisibility(R.id.visit_website_item, false);
mi.setItemVisibility(R.id.share_link_item, false);
+ mi.setItemVisibility(R.id.share_link_with_position_item, false);
+ }
+ if (!showExtendedMenu || !hasMedia || selectedItem.getMedia().getDownload_url() == null) {
+ mi.setItemVisibility(R.id.share_download_url_item, false);
+ mi.setItemVisibility(R.id.share_download_url_with_position_item, false);
+ }
+ if(false == hasMedia || selectedItem.getMedia().getPosition() <= 0) {
+ mi.setItemVisibility(R.id.share_link_with_position_item, false);
+ mi.setItemVisibility(R.id.share_download_url_with_position_item, false);
}
if (!(state == FeedItem.State.UNREAD || state == FeedItem.State.IN_PROGRESS)) {
@@ -108,10 +120,6 @@ public class FeedItemMenuHandler {
mi.setItemVisibility(R.id.deactivate_auto_download, false);
}
- if (!showExtendedMenu || selectedItem.getLink() == null) {
- mi.setItemVisibility(R.id.visit_website_item, false);
- }
-
if (selectedItem.getPaymentLink() == null || !selectedItem.getFlattrStatus().flattrable()) {
mi.setItemVisibility(R.id.support_item, false);
}
@@ -125,21 +133,19 @@ public class FeedItemMenuHandler {
* @param excludeIds Menu item that should be excluded
* @return true if selectedItem is not null.
*/
- public static boolean onPrepareMenu(MenuInterface mi,
- FeedItem selectedItem, boolean showExtendedMenu, LongList queueAccess, int... excludeIds) {
- boolean rc = onPrepareMenu(mi, selectedItem, showExtendedMenu, queueAccess);
+ public static boolean onPrepareMenu(Context context, MenuInterface mi, FeedItem selectedItem,
+ boolean showExtendedMenu, LongList queueAccess, int... excludeIds) {
+ boolean rc = onPrepareMenu(context, mi, selectedItem, showExtendedMenu, queueAccess);
if (rc && excludeIds != null) {
for (int id : excludeIds) {
mi.setItemVisibility(id, false);
}
}
-
return rc;
}
public static boolean onMenuItemClicked(Context context, int menuItemId,
FeedItem selectedItem) throws DownloadRequestException {
- DownloadRequester requester = DownloadRequester.getInstance();
switch (menuItemId) {
case R.id.skip_episode_item:
context.sendBroadcast(new Intent(PlaybackService.ACTION_SKIP_CURRENT_EPISODE));
@@ -148,22 +154,25 @@ public class FeedItemMenuHandler {
DBWriter.deleteFeedMediaOfItem(context, selectedItem.getMedia().getId());
break;
case R.id.mark_read_item:
- selectedItem.setRead(true);
+ selectedItem.setPlayed(true);
DBWriter.markItemRead(context, selectedItem, true, false);
if(GpodnetPreferences.loggedIn()) {
FeedMedia media = selectedItem.getMedia();
- GpodnetEpisodeAction actionPlay = new GpodnetEpisodeAction.Builder(selectedItem, Action.PLAY)
- .currentDeviceId()
- .currentTimestamp()
- .started(media.getDuration() / 1000)
- .position(media.getDuration() / 1000)
- .total(media.getDuration() / 1000)
- .build();
- GpodnetPreferences.enqueueEpisodeAction(actionPlay);
+ // not all items have media, Gpodder only cares about those that do
+ if (media != null) {
+ GpodnetEpisodeAction actionPlay = new GpodnetEpisodeAction.Builder(selectedItem, Action.PLAY)
+ .currentDeviceId()
+ .currentTimestamp()
+ .started(media.getDuration() / 1000)
+ .position(media.getDuration() / 1000)
+ .total(media.getDuration() / 1000)
+ .build();
+ GpodnetPreferences.enqueueEpisodeAction(actionPlay);
+ }
}
break;
case R.id.mark_unread_item:
- selectedItem.setRead(false);
+ selectedItem.setPlayed(false);
DBWriter.markItemRead(context, selectedItem, false, false);
if(GpodnetPreferences.loggedIn()) {
GpodnetEpisodeAction actionNew = new GpodnetEpisodeAction.Builder(selectedItem, Action.NEW)
@@ -198,7 +207,13 @@ public class FeedItemMenuHandler {
break;
case R.id.visit_website_item:
Uri uri = Uri.parse(selectedItem.getLink());
- context.startActivity(new Intent(Intent.ACTION_VIEW, uri));
+ Intent intent = new Intent(Intent.ACTION_VIEW, uri);
+ if(IntentUtils.isCallable(context, intent)) {
+ context.startActivity(intent);
+ } else {
+ Toast.makeText(context, context.getString(R.string.download_error_malformed_url),
+ Toast.LENGTH_SHORT);
+ }
break;
case R.id.support_item:
DBTasks.flattrItemIfLoggedIn(context, selectedItem);
@@ -206,6 +221,15 @@ public class FeedItemMenuHandler {
case R.id.share_link_item:
ShareUtils.shareFeedItemLink(context, selectedItem);
break;
+ case R.id.share_download_url_item:
+ ShareUtils.shareFeedItemDownloadLink(context, selectedItem);
+ break;
+ case R.id.share_link_with_position_item:
+ ShareUtils.shareFeedItemLink(context, selectedItem, true);
+ break;
+ case R.id.share_download_url_with_position_item:
+ ShareUtils.shareFeedItemDownloadLink(context, selectedItem, true);
+ break;
default:
Log.d(TAG, "Unknown menuItemId: " + menuItemId);
return false;
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 7bd8fedc9..3df59724d 100644
--- a/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java
+++ b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java
@@ -9,6 +9,7 @@ import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
+import android.widget.Toast;
import java.util.ArrayList;
import java.util.Arrays;
@@ -20,6 +21,7 @@ import de.danoeh.antennapod.core.feed.Feed;
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.util.IntentUtils;
import de.danoeh.antennapod.core.util.ShareUtils;
/**
@@ -39,11 +41,11 @@ public class FeedMenuHandler {
}
Log.d(TAG, "Preparing options menu");
- menu.findItem(R.id.mark_all_read_item).setVisible(selectedFeed.hasNewItems());
- if (selectedFeed.getPaymentLink() != null && selectedFeed.getFlattrStatus().flattrable())
+ if (selectedFeed.getPaymentLink() != null && selectedFeed.getFlattrStatus().flattrable()) {
menu.findItem(R.id.support_item).setVisible(true);
- else
+ } else {
menu.findItem(R.id.support_item).setVisible(false);
+ }
menu.findItem(R.id.refresh_complete_item).setVisible(selectedFeed.isPaged());
@@ -83,7 +85,13 @@ public class FeedMenuHandler {
break;
case R.id.visit_website_item:
Uri uri = Uri.parse(selectedFeed.getLink());
- context.startActivity(new Intent(Intent.ACTION_VIEW, uri));
+ Intent intent = new Intent(Intent.ACTION_VIEW, uri);
+ if(IntentUtils.isCallable(context, intent)) {
+ context.startActivity(intent);
+ } else {
+ Toast.makeText(context, context.getString(R.string.download_error_malformed_url),
+ Toast.LENGTH_SHORT);
+ }
break;
case R.id.support_item:
DBTasks.flattrFeedIfLoggedIn(context, selectedFeed);
@@ -91,7 +99,7 @@ public class FeedMenuHandler {
case R.id.share_link_item:
ShareUtils.shareFeedlink(context, selectedFeed);
break;
- case R.id.share_source_item:
+ case R.id.share_download_url_item:
ShareUtils.shareFeedDownloadLink(context, selectedFeed);
break;
default:
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 f387b7524..39edfe582 100644
--- a/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java
+++ b/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java
@@ -2,6 +2,7 @@ package de.danoeh.antennapod.preferences;
import android.app.Activity;
import android.app.AlertDialog;
+import android.app.TimePickerDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
@@ -16,8 +17,10 @@ import android.preference.Preference;
import android.preference.PreferenceScreen;
import android.text.Editable;
import android.text.TextWatcher;
+import android.text.format.DateFormat;
import android.util.Log;
import android.widget.EditText;
+import android.widget.TimePicker;
import android.widget.Toast;
import java.io.File;
@@ -33,12 +36,9 @@ import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.activity.PreferenceActivity;
import de.danoeh.antennapod.activity.PreferenceActivityGingerbread;
import de.danoeh.antennapod.asynctask.OpmlExportWorker;
-import de.danoeh.antennapod.core.asynctask.FlattrClickWorker;
import de.danoeh.antennapod.core.preferences.GpodnetPreferences;
import de.danoeh.antennapod.core.preferences.UserPreferences;
-import de.danoeh.antennapod.core.util.flattr.FlattrStatus;
import de.danoeh.antennapod.core.util.flattr.FlattrUtils;
-import de.danoeh.antennapod.core.util.flattr.SimpleFlattrThing;
import de.danoeh.antennapod.dialog.AuthenticationDialog;
import de.danoeh.antennapod.dialog.AutoFlattrPreferenceDialog;
import de.danoeh.antennapod.dialog.GpodnetSetHostnameDialog;
@@ -49,7 +49,6 @@ import de.danoeh.antennapod.dialog.VariableSpeedDialog;
*/
public class PreferenceController {
private static final String TAG = "PreferenceController";
- public static final String PREF_FLATTR_THIS_APP = "prefFlattrThisApp";
public static final String PREF_FLATTR_SETTINGS = "prefFlattrSettings";
public static final String PREF_FLATTR_AUTH = "pref_flattr_authenticate";
public static final String PREF_FLATTR_REVOKE = "prefRevokeAccess";
@@ -105,23 +104,6 @@ public class PreferenceController {
);
}
- ui.findPreference(PreferenceController.PREF_FLATTR_THIS_APP).setOnPreferenceClickListener(
- new Preference.OnPreferenceClickListener() {
-
- @Override
- public boolean onPreferenceClick(Preference preference) {
- new FlattrClickWorker(activity,
- new SimpleFlattrThing(activity.getString(R.string.app_name),
- FlattrUtils.APP_URL,
- new FlattrStatus(FlattrStatus.STATUS_QUEUE)
- )
- ).executeAsync();
-
- return true;
- }
- }
- );
-
ui.findPreference(PreferenceController.PREF_FLATTR_REVOKE).setOnPreferenceClickListener(
new Preference.OnPreferenceClickListener() {
@@ -200,6 +182,15 @@ public class PreferenceController {
}
});
+ ui.findPreference(UserPreferences.PREF_UPDATE_INTERVAL)
+ .setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
+ showUpdateIntervalTimePreferencesDialog();
+ return true;
+ }
+ });
+
ui.findPreference(UserPreferences.PREF_ENABLE_AUTODL)
.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
@@ -345,14 +336,33 @@ public class PreferenceController {
@Override
public void onConfirmed(boolean autoFlattrEnabled, float autoFlattrValue) {
- UserPreferences.setAutoFlattrSettings(activity, autoFlattrEnabled, autoFlattrValue);
+ UserPreferences.setAutoFlattrSettings(autoFlattrEnabled, autoFlattrValue);
checkItemVisibility();
}
});
return true;
}
});
- buildUpdateIntervalPreference();
+ ui.findPreference(UserPreferences.PREF_IMAGE_CACHE_SIZE)
+ .setOnPreferenceChangeListener(
+ new Preference.OnPreferenceChangeListener() {
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object o) {
+ if (o instanceof String) {
+ int newValue = Integer.valueOf((String) o) * 1024 * 1024;
+ if(newValue != UserPreferences.getImageCacheSize()) {
+ AlertDialog.Builder dialog = new AlertDialog.Builder(ui.getActivity());
+ dialog.setTitle(android.R.string.dialog_alert_title);
+ dialog.setMessage(R.string.pref_restart_required);
+ dialog.setPositiveButton(android.R.string.ok, null);
+ dialog.show();
+ }
+ return true;
+ }
+ return false;
+ }
+ }
+ );
buildSmartMarkAsPlayedPreference();
buildAutodownloadSelectedNetworsPreference();
setSelectedNetworksEnabled(UserPreferences
@@ -385,12 +395,8 @@ public class PreferenceController {
ui.findPreference(PreferenceController.PREF_GPODNET_HOSTNAME).setSummary(GpodnetPreferences.getHostname());
}
- private void buildUpdateIntervalPreference() {
+ private String[] getUpdateIntervalEntries(final String[] values) {
final Resources res = ui.getActivity().getResources();
-
- ListPreference pref = (ListPreference) ui.findPreference(UserPreferences.PREF_UPDATE_INTERVAL);
- String[] values = res.getStringArray(
- R.array.update_intervall_values);
String[] entries = new String[values.length];
for (int x = 0; x < values.length; x++) {
Integer v = Integer.parseInt(values[x]);
@@ -399,19 +405,15 @@ public class PreferenceController {
entries[x] = res.getString(R.string.pref_update_interval_hours_manual);
break;
case 1:
- entries[x] = v
- + " "
- + res.getString(R.string.pref_update_interval_hours_singular);
+ entries[x] = v + " " + res.getString(R.string.pref_update_interval_hours_singular);
break;
default:
- entries[x] = v + " "
- + res.getString(R.string.pref_update_interval_hours_plural);
+ entries[x] = v + " " + res.getString(R.string.pref_update_interval_hours_plural);
break;
}
}
- pref.setEntries(entries);
-
+ return entries;
}
private void buildSmartMarkAsPlayedPreference() {
@@ -426,7 +428,7 @@ public class PreferenceController {
entries[x] = res.getString(R.string.pref_smart_mark_as_played_disabled);
} else {
Integer v = Integer.parseInt(values[x]);
- entries[x] = v + " " + res.getString(R.string.time_unit_seconds);
+ entries[x] = res.getQuantityString(R.plurals.time_seconds_quantified, v);
}
}
pref.setEntries(entries);
@@ -529,9 +531,7 @@ public class PreferenceController {
}
UserPreferences.setAutodownloadSelectedNetworks(
- activity, prefValuesList
- .toArray(new String[prefValuesList
- .size()])
+ prefValuesList.toArray(new String[prefValuesList.size()])
);
return true;
} else {
@@ -606,7 +606,63 @@ public class PreferenceController {
builder.create().show();
}
+ private void showUpdateIntervalTimePreferencesDialog() {
+ final Context context = ui.getActivity();
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(context);
+ builder.setTitle(R.string.pref_autoUpdateIntervallOrTime_title);
+ builder.setMessage(R.string.pref_autoUpdateIntervallOrTime_message);
+ builder.setNegativeButton(R.string.pref_autoUpdateIntervallOrTime_Disable, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ UserPreferences.setUpdateInterval(0);
+ }
+ });
+ builder.setNeutralButton(R.string.pref_autoUpdateIntervallOrTime_Interval, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(context);
+ builder.setTitle(context.getString(R.string.pref_autoUpdateIntervallOrTime_Interval));
+ final String[] values = context.getResources().getStringArray(R.array.update_intervall_values);
+ final String[] entries = getUpdateIntervalEntries(values);
+ builder.setSingleChoiceItems(entries, -1, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ int hours = Integer.valueOf(values[which]);
+ UserPreferences.setUpdateInterval(hours);
+ dialog.dismiss();
+ }
+ });
+ builder.setNegativeButton(context.getString(R.string.cancel_label), null);
+ builder.show();
+ }
+ });
+ builder.setPositiveButton(R.string.pref_autoUpdateIntervallOrTime_TimeOfDay, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ int hourOfDay = 7, minute = 0;
+ int[] updateTime = UserPreferences.getUpdateTimeOfDay();
+ if (updateTime.length == 2) {
+ hourOfDay = updateTime[0];
+ minute = updateTime[1];
+ }
+ TimePickerDialog timePickerDialog = new TimePickerDialog(context, new TimePickerDialog.OnTimeSetListener() {
+ @Override
+ public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
+ if (view.getTag() == null) { // onTimeSet() may get called twice!
+ view.setTag("TAGGED");
+ UserPreferences.setUpdateTimeOfDay(hourOfDay, minute);
+ }
+ }
+ }, hourOfDay, minute, DateFormat.is24HourFormat(context));
+ timePickerDialog.setTitle(context.getString(R.string.pref_autoUpdateIntervallOrTime_TimeOfDay));
+ timePickerDialog.show();
+ }
+ }
+ );
+ builder.show();
+ }
public static interface PreferenceUI {
diff --git a/app/src/main/java/de/danoeh/antennapod/receiver/ConnectivityActionReceiver.java b/app/src/main/java/de/danoeh/antennapod/receiver/ConnectivityActionReceiver.java
index f55a7603f..2615ec5c8 100644
--- a/app/src/main/java/de/danoeh/antennapod/receiver/ConnectivityActionReceiver.java
+++ b/app/src/main/java/de/danoeh/antennapod/receiver/ConnectivityActionReceiver.java
@@ -9,24 +9,20 @@ import android.util.Log;
import org.apache.commons.lang3.StringUtils;
-import de.danoeh.antennapod.core.BuildConfig;
import de.danoeh.antennapod.core.storage.DBTasks;
import de.danoeh.antennapod.core.storage.DownloadRequester;
import de.danoeh.antennapod.core.util.NetworkUtils;
public class ConnectivityActionReceiver extends BroadcastReceiver {
- private static final String TAG = "ConnectivityActionReceiver";
+ private static final String TAG = "ConnectivityActionRecvr";
@Override
public void onReceive(final Context context, Intent intent) {
if (StringUtils.equals(intent.getAction(), ConnectivityManager.CONNECTIVITY_ACTION)) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Received intent");
+ Log.d(TAG, "Received intent");
- if (NetworkUtils.autodownloadNetworkAvailable(context)) {
- if (BuildConfig.DEBUG)
- Log.d(TAG,
- "auto-dl network available, starting auto-download");
+ if (NetworkUtils.autodownloadNetworkAvailable()) {
+ Log.d(TAG, "auto-dl network available, starting auto-download");
DBTasks.autodownloadUndownloadedItems(context);
} else { // if new network is Wi-Fi, finish ongoing downloads,
// otherwise cancel all downloads
@@ -34,12 +30,9 @@ public class ConnectivityActionReceiver extends BroadcastReceiver {
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo ni = cm.getActiveNetworkInfo();
if (ni == null || ni.getType() != ConnectivityManager.TYPE_WIFI) {
- if (BuildConfig.DEBUG)
- Log.i(TAG,
- "Device is no longer connected to Wi-Fi. Cancelling ongoing downloads");
+ Log.i(TAG, "Device is no longer connected to Wi-Fi. Cancelling ongoing downloads");
DownloadRequester.getInstance().cancelAllDownloads(context);
}
-
}
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/service/PlayerWidgetService.java b/app/src/main/java/de/danoeh/antennapod/service/PlayerWidgetService.java
index 1fe9e2cf9..990b3bd54 100644
--- a/app/src/main/java/de/danoeh/antennapod/service/PlayerWidgetService.java
+++ b/app/src/main/java/de/danoeh/antennapod/service/PlayerWidgetService.java
@@ -62,7 +62,7 @@ public class PlayerWidgetService extends Service {
DBWriter.markItemRead(this, item, true, false);
DBWriter.removeQueueItem(this, item, false);
DBWriter.addItemToPlaybackHistory(this, media);
- if (UserPreferences.isAutoDelete()) {
+ if (item.getFeed().getPreferences().getCurrentAutoDelete()) {
Log.d(TAG, "Delete " + media.toString());
DBWriter.deleteFeedMediaOfItem(this, media.getId());
}
diff --git a/app/src/main/res/layout-v14/authentication_dialog.xml b/app/src/main/res/layout-v14/authentication_dialog.xml
index ed05dab1c..00e74c9e1 100644
--- a/app/src/main/res/layout-v14/authentication_dialog.xml
+++ b/app/src/main/res/layout-v14/authentication_dialog.xml
@@ -15,7 +15,10 @@
android:layout_height="0dp"
android:layout_weight="1"
android:layout_margin="16dp"
- android:hint="@string/username_label"/>
+ android:hint="@string/username_label"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ android:cursorVisible="true"/>
<EditText
android:id="@+id/etxtPassword"
@@ -24,7 +27,10 @@
android:layout_weight="1"
android:layout_margin="16dp"
android:inputType="textPassword"
- android:hint="@string/password_label"/>
+ android:hint="@string/password_label"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ android:cursorVisible="true"/>
<CheckBox
android:id="@+id/chkSaveUsernamePassword"
diff --git a/app/src/main/res/layout-v14/download_authentication_activity.xml b/app/src/main/res/layout-v14/download_authentication_activity.xml
index c1fe55ceb..8d2c7fb17 100644
--- a/app/src/main/res/layout-v14/download_authentication_activity.xml
+++ b/app/src/main/res/layout-v14/download_authentication_activity.xml
@@ -31,7 +31,10 @@
android:layout_margin="16dp"
android:id="@+id/etxtUsername"
android:hint="@string/username_label"
- android:layout_below="@id/txtvDescription"/>
+ android:layout_below="@id/txtvDescription"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ android:cursorVisible="true"/>
<EditText
android:layout_width="match_parent"
@@ -40,7 +43,10 @@
android:id="@+id/etxtPassword"
android:hint="@string/password_label"
android:inputType="textPassword"
- android:layout_below="@id/etxtUsername"/>
+ android:layout_below="@id/etxtUsername"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ android:cursorVisible="true"/>
<RelativeLayout
android:id="@+id/footer"
diff --git a/app/src/main/res/layout/addfeed.xml b/app/src/main/res/layout/addfeed.xml
index b7babbafa..dff24c650 100644
--- a/app/src/main/res/layout/addfeed.xml
+++ b/app/src/main/res/layout/addfeed.xml
@@ -15,26 +15,33 @@
android:orientation="vertical">
<TextView
- android:id="@+id/txtvFeedurl"
+ android:id="@+id/txtvPodcastDirectories"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/AntennaPod.TextView.Heading"
- android:text="@string/txtvfeedurl_label"/>
+ android:text="@string/podcastdirectories_label"/>
- <EditText
- android:id="@+id/etxtFeedurl"
+ <TextView
+ android:id="@+id/txtvPodcastDirectoriesDescr"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="4dp"
- android:hint="@string/etxtFeedurlHint"
- android:inputType="textUri"/>
+ android:text="@string/podcastdirectories_descr"
+ android:textSize="@dimen/text_size_medium"
+ android:layout_marginTop="4dp"/>
<Button
- android:id="@+id/butConfirm"
+ android:id="@+id/butSearchItunes"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
- android:text="@string/confirm_label"/>
+ android:text="@string/search_itunes_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"/>
<View
android:id="@+id/divider1"
@@ -44,34 +51,30 @@
android:background="?android:attr/listDivider"/>
<TextView
- android:id="@+id/txtvPodcastDirectories"
+ android:id="@+id/txtvFeedurl"
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_marginTop="4dp"/>
+ android:text="@string/txtvfeedurl_label"/>
- <Button
- android:id="@+id/butBrowseGpoddernet"
+ <EditText
+ android:id="@+id/etxtFeedurl"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="8dp"
- android:text="@string/browse_gpoddernet_label"/>
+ android:layout_marginTop="4dp"
+ android:hint="@string/etxtFeedurlHint"
+ android:inputType="textUri"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ android:cursorVisible="true"/>
<Button
- android:id="@+id/butSearchItunes"
+ android:id="@+id/butConfirm"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
- android:text="@string/search_itunes_label"/>
+ android:text="@string/confirm_label"/>
<View
android:id="@+id/divider2"
diff --git a/app/src/main/res/layout/authentication_dialog.xml b/app/src/main/res/layout/authentication_dialog.xml
index 82260eb43..e18ab42eb 100644
--- a/app/src/main/res/layout/authentication_dialog.xml
+++ b/app/src/main/res/layout/authentication_dialog.xml
@@ -16,7 +16,10 @@
android:layout_height="0dp"
android:layout_weight="1"
android:layout_margin="16dp"
- android:hint="@string/username_label"/>
+ android:hint="@string/username_label"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ android:cursorVisible="true"/>
<EditText
android:id="@+id/etxtPassword"
@@ -25,7 +28,10 @@
android:layout_weight="1"
android:layout_margin="16dp"
android:inputType="textPassword"
- android:hint="@string/password_label"/>
+ android:hint="@string/password_label"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ android:cursorVisible="true"/>
<CheckBox
android:id="@+id/chkSaveUsernamePassword"
diff --git a/app/src/main/res/layout/cover_fragment.xml b/app/src/main/res/layout/cover_fragment.xml
index 18540aa1f..4bbdeae06 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="centerInside"
+ android:scaleType="fitCenter"
tools:src="@android:drawable/sym_def_app_icon" />
-</RelativeLayout> \ No newline at end of file
+</RelativeLayout>
diff --git a/app/src/main/res/layout/download_authentication_activity.xml b/app/src/main/res/layout/download_authentication_activity.xml
index 69106c9b3..b035f2516 100644
--- a/app/src/main/res/layout/download_authentication_activity.xml
+++ b/app/src/main/res/layout/download_authentication_activity.xml
@@ -31,7 +31,10 @@
android:layout_margin="16dp"
android:id="@+id/etxtUsername"
android:hint="@string/username_label"
- android:layout_below="@id/txtvDescription"/>
+ android:layout_below="@id/txtvDescription"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ android:cursorVisible="true"/>
<EditText
android:layout_width="match_parent"
@@ -40,7 +43,10 @@
android:id="@+id/etxtPassword"
android:hint="@string/password_label"
android:inputType="textPassword"
- android:layout_below="@id/etxtUsername"/>
+ android:layout_below="@id/etxtUsername"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ android:cursorVisible="true"/>
<LinearLayout
android:id="@+id/footer"
diff --git a/app/src/main/res/layout/episodes_apply_action_fragment.xml b/app/src/main/res/layout/episodes_apply_action_fragment.xml
new file mode 100644
index 000000000..d63088662
--- /dev/null
+++ b/app/src/main/res/layout/episodes_apply_action_fragment.xml
@@ -0,0 +1,120 @@
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+
+ <LinearLayout
+ android:id="@+id/bottomBar"
+ android:layout_width="wrap_content"
+ android:layout_height="68dp"
+ android:layout_alignParentBottom="true"
+ android:orientation="horizontal"
+ android:gravity="center_vertical"
+ android:padding="4dp">
+
+ <Button
+ android:id="@+id/btnAddToQueue"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:drawableTop="?attr/content_new"
+ android:text="@string/add_to_queue_label"
+ android:textSize="10sp"
+ android:background="@android:color/transparent"/>
+
+ <View xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="1dp"
+ android:layout_height="match_parent"
+ android:layout_margin="4dp"
+ android:background="?android:attr/listDivider"
+ tools:background="@android:color/holo_red_dark" />
+
+ <Button
+ android:id="@+id/btnMarkAsPlayed"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:drawableTop="?attr/navigation_accept"
+ android:text="@string/mark_read_label"
+ android:textSize="10sp"
+ android:background="@android:color/transparent"/>
+
+ <View xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="1dp"
+ android:layout_height="match_parent"
+ android:layout_margin="4dp"
+ android:background="?android:attr/listDivider"
+ tools:background="@android:color/holo_red_dark" />
+
+ <Button
+ android:id="@+id/btnMarkAsUnplayed"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:drawableTop="?attr/navigation_cancel"
+ android:text="@string/mark_unread_label"
+ android:textSize="10sp"
+ android:background="@android:color/transparent"/>
+
+ <View xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="1dp"
+ android:layout_height="match_parent"
+ android:layout_margin="4dp"
+ android:background="?android:attr/listDivider"
+ tools:background="@android:color/holo_red_dark" />
+
+ <Button
+ android:id="@+id/btnDownload"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:drawableTop="?attr/av_download"
+ android:text="@string/download_label"
+ android:textSize="10sp"
+ android:background="@android:color/transparent"/>
+
+ <View xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="1dp"
+ android:layout_height="match_parent"
+ android:layout_margin="4dp"
+ android:background="?android:attr/listDivider"
+ tools:background="@android:color/holo_red_dark" />
+
+ <Button
+ android:id="@+id/btnDelete"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:drawableTop="?attr/content_discard"
+ android:text="@string/remove_episode_lable"
+ android:textSize="10sp"
+ android:background="@android:color/transparent"/>
+
+ </LinearLayout>
+
+ <View
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/divider"
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="?android:attr/listDivider"
+ android:paddingBottom="4dp"
+ android:layout_above="@id/bottomBar"
+ tools:background="@android:color/holo_red_dark" />
+
+ <ListView
+ android:id="@android:id/list"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_above="@id/divider">
+
+ </ListView>
+
+
+</RelativeLayout>
diff --git a/app/src/main/res/layout/feedinfo.xml b/app/src/main/res/layout/feedinfo.xml
index db897865c..edae51847 100644
--- a/app/src/main/res/layout/feedinfo.xml
+++ b/app/src/main/res/layout/feedinfo.xml
@@ -20,8 +20,8 @@
<ImageView
android:id="@+id/imgvCover"
android:contentDescription="@string/cover_label"
- android:layout_width="70dp"
- android:layout_height="70dp"
+ android:layout_width="80dp"
+ android:layout_height="80dp"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
tools:src="@drawable/ic_stat_antenna_default"
@@ -33,7 +33,9 @@
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="8dp"
+ android:layout_alignTop="@id/imgvCover"
android:layout_toRightOf="@id/imgvCover"
+ android:layout_alignBottom="@id/imgvCover"
style="@style/AntennaPod.TextView.Heading"
tools:text="Feed title"
tools:background="@android:color/holo_green_dark"/>
@@ -52,7 +54,7 @@
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
- android:scrollbarStyle="outsideInset"
+ android:scrollbarStyle="outsideOverlay"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingBottom="8dp">
@@ -119,7 +121,6 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="8dp"
- android:layout_marginBottom="8dp"
app:layout_row="2"
app:layout_column="0"
android:lines="1"
@@ -129,10 +130,13 @@
<TextView
android:id="@+id/txtvUrl"
- android:layout_width="wrap_content"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
+ android:paddingBottom="4dp"
app:layout_row="2"
app:layout_column="1"
+ app:layout_gravity="fill"
+ android:maxLines="4"
tools:text="http://www.example.com/feed"
tools:background="@android:color/holo_green_dark"/>
@@ -155,7 +159,38 @@
android:enabled="false"
android:textColor="?android:attr/textColorPrimary"
tools:background="@android:color/holo_red_light"
- android:checked="false"/>
+ android:checked="false" />
+
+ <android.support.v7.widget.GridLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dp"
+ app:columnCount="2"
+ app:rowCount="1">
+
+ <TextView
+ android:id="@+id/txtvFeedAutoDelete"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/auto_delete_label"
+ app:layout_row="0"
+ app:layout_column="0"
+ app:layout_gravity="center_vertical"
+ android:layout_marginRight="10dp" />
+
+ <Spinner
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:id="@+id/spnAutoDelete"
+ android:entries="@array/spnAutoDeleteItems"
+ android:layout_marginTop="8dp"
+ app:layout_row="0"
+ app:layout_column="1"
+ android:spinnerMode="dropdown"
+ app:layout_gravity="center"
+ android:dropDownWidth="wrap_content"
+ android:clickable="true" />
+ </android.support.v7.widget.GridLayout>
<TextView
android:id="@+id/txtvAuthentication"
@@ -200,7 +235,10 @@
android:layout_height="wrap_content"
app:layout_row="0"
app:layout_column="1"
- android:hint="@string/username_label"/>
+ android:hint="@string/username_label"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ android:cursorVisible="true"/>
<TextView
android:id="@+id/txtvPassword"
@@ -211,7 +249,10 @@
app:layout_row="1"
app:layout_column="0"
android:text="@string/password_label"
- android:textColor="?android:attr/textColorPrimary"/>
+ android:textColor="?android:attr/textColorPrimary"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ android:cursorVisible="true"/>
<EditText
android:id="@+id/etxtPassword"
diff --git a/app/src/main/res/layout/feeditem_fragment_header.xml b/app/src/main/res/layout/feeditem_fragment_header.xml
index a21488306..2534dddbe 100644
--- a/app/src/main/res/layout/feeditem_fragment_header.xml
+++ b/app/src/main/res/layout/feeditem_fragment_header.xml
@@ -89,10 +89,9 @@
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginBottom="16dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
- android:visibility="gone" />
+ android:visibility="invisible" />
<LinearLayout
android:layout_width="match_parent"
diff --git a/app/src/main/res/layout/fragment_itunes_search.xml b/app/src/main/res/layout/fragment_itunes_search.xml
index 17ffe349b..e57c59554 100644
--- a/app/src/main/res/layout/fragment_itunes_search.xml
+++ b/app/src/main/res/layout/fragment_itunes_search.xml
@@ -14,7 +14,7 @@ tools:context="de.danoeh.antennapod.activity.ITunesSearchActivity">
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
- android:columnWidth="200dp"
+ android:columnWidth="400dp"
android:gravity="center"
android:horizontalSpacing="8dp"
android:numColumns="auto_fit"
diff --git a/app/src/main/res/layout/gpodnet_podcast_list.xml b/app/src/main/res/layout/gpodnet_podcast_list.xml
index 05df70f31..d8b06e4f7 100644
--- a/app/src/main/res/layout/gpodnet_podcast_list.xml
+++ b/app/src/main/res/layout/gpodnet_podcast_list.xml
@@ -10,7 +10,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
- android:columnWidth="200dp"
+ android:columnWidth="400dp"
android:gravity="center"
android:horizontalSpacing="8dp"
android:numColumns="auto_fit"
diff --git a/app/src/main/res/layout/gpodnetauth_credentials.xml b/app/src/main/res/layout/gpodnetauth_credentials.xml
index 8436570fc..13c5977f8 100644
--- a/app/src/main/res/layout/gpodnetauth_credentials.xml
+++ b/app/src/main/res/layout/gpodnetauth_credentials.xml
@@ -30,7 +30,10 @@
android:layout_height="wrap_content"
android:hint="@string/username_label"
android:layout_below="@id/txtvDescription"
- android:layout_margin="8dp"/>
+ android:layout_margin="8dp"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ android:cursorVisible="true"/>
<EditText
android:id="@+id/etxtPassword"
@@ -39,7 +42,10 @@
android:hint="@string/password_label"
android:layout_below="@id/etxtUsername"
android:inputType="textPassword"
- android:layout_margin="8dp"/>
+ android:layout_margin="8dp"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ android:cursorVisible="true"/>
<Button
android:id="@+id/butLogin"
diff --git a/app/src/main/res/layout/new_episodes_listitem.xml b/app/src/main/res/layout/new_episodes_listitem.xml
index ff1318fc8..ec5ab1e6a 100644
--- a/app/src/main/res/layout/new_episodes_listitem.xml
+++ b/app/src/main/res/layout/new_episodes_listitem.xml
@@ -7,18 +7,36 @@
android:orientation="horizontal"
tools:background="@android:color/darker_gray">
- <ImageView
- android:id="@+id/imgvImage"
- android:layout_width="@dimen/thumbnail_length_itemlist"
- android:layout_height="@dimen/thumbnail_length_itemlist"
- android:layout_gravity="center_vertical"
- android:layout_marginBottom="@dimen/listitem_threeline_verticalpadding"
- android:layout_marginLeft="@dimen/listitem_threeline_horizontalpadding"
- android:layout_marginTop="@dimen/listitem_threeline_verticalpadding"
- android:contentDescription="@string/cover_label"
- android:scaleType="centerCrop"
- tools:src="@drawable/ic_stat_antenna_default"
- tools:background="@android:color/holo_green_dark" />
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+ <TextView
+ android:id="@+id/txtvPlaceholder"
+ android:layout_width="@dimen/thumbnail_length_itemlist"
+ android:layout_height="@dimen/thumbnail_length_itemlist"
+ android:layout_gravity="center_vertical"
+ android:layout_marginBottom="@dimen/listitem_threeline_verticalpadding"
+ android:layout_marginLeft="@dimen/listitem_threeline_horizontalpadding"
+ android:layout_marginTop="@dimen/listitem_threeline_verticalpadding"
+ android:background="@color/light_gray"
+ android:ellipsize="end"
+ android:maxLines="3"
+ android:gravity="center"/>
+
+ <ImageView
+ android:id="@+id/imgvCover"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_alignLeft="@id/txtvPlaceholder"
+ android:layout_alignTop="@id/txtvPlaceholder"
+ android:layout_alignRight="@id/txtvPlaceholder"
+ android:layout_alignBottom="@id/txtvPlaceholder"
+ android:contentDescription="@string/cover_label"
+ tools:src="@drawable/ic_stat_antenna_default"
+ tools:background="@android:color/holo_green_dark" />
+
+ </RelativeLayout>
<RelativeLayout
android:layout_width="0dp"
diff --git a/app/src/main/res/layout/queue_fragment.xml b/app/src/main/res/layout/queue_fragment.xml
index 307d95a8d..339369971 100644
--- a/app/src/main/res/layout/queue_fragment.xml
+++ b/app/src/main/res/layout/queue_fragment.xml
@@ -1,18 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:dslv="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
+ <TextView
+ android:id="@+id/info_bar"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentTop="true"
+ android:gravity="center"
+ android:textSize="12sp"
+ android:text="42 episodes \u2022 5 hours 17 minutes"/>
+
+ <View
+ android:id="@+id/divider"
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:layout_below="@id/info_bar"
+ android:background="?android:attr/listDivider"/>
+
<com.mobeta.android.dslv.DragSortListView
android:id="@android:id/list"
android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_height="wrap_content"
android:clipToPadding="false"
- android:paddingBottom="@dimen/list_vertical_padding"
- android:paddingTop="@dimen/list_vertical_padding"
android:scrollbarStyle="outsideOverlay"
+ android:layout_below="@+id/divider"
dslv:collapsed_height="2dp"
dslv:drag_enabled="true"
dslv:drag_handle_id="@id/drag_handle"
@@ -31,7 +46,7 @@
android:id="@id/android:empty"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_gravity="center"
+ android:layout_centerInParent="true"
android:gravity="center"
android:text="@string/no_items_label" />
@@ -39,12 +54,13 @@
android:id="@+id/progLoading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="center"
+ android:layout_centerInParent="true"
android:indeterminateOnly="true"
android:visibility="gone" />
<LinearLayout
android:id="@+id/undobar"
+ android:layout_alignParentBottom="true"
style="@style/UndoBar">
<TextView
@@ -57,4 +73,4 @@
</LinearLayout>
-</FrameLayout>
+</RelativeLayout>
diff --git a/app/src/main/res/layout/queue_listitem.xml b/app/src/main/res/layout/queue_listitem.xml
index 39e9c72a5..38076ff51 100644
--- a/app/src/main/res/layout/queue_listitem.xml
+++ b/app/src/main/res/layout/queue_listitem.xml
@@ -21,17 +21,32 @@
tools:src="@drawable/ic_drag_handle"
tools:background="@android:color/holo_green_dark" />
- <ImageView
- android:id="@+id/imgvImage"
- android:layout_width="@dimen/thumbnail_length_queue_item"
- android:layout_height="@dimen/thumbnail_length_queue_item"
- android:layout_gravity="center_vertical"
- android:layout_marginBottom="@dimen/listitem_threeline_verticalpadding"
- android:layout_marginTop="@dimen/listitem_threeline_verticalpadding"
- android:contentDescription="@string/cover_label"
- android:scaleType="centerCrop"
- tools:src="@drawable/ic_stat_antenna_default"
- tools:background="@android:color/holo_green_dark"/>
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+ <TextView
+ android:id="@+id/txtvPlaceholder"
+ android:layout_width="@dimen/thumbnail_length_queue_item"
+ android:layout_height="@dimen/thumbnail_length_queue_item"
+ android:layout_marginBottom="@dimen/listitem_threeline_verticalpadding"
+ android:layout_marginTop="@dimen/listitem_threeline_verticalpadding"
+ android:layout_gravity="center_vertical"
+ android:gravity="center"
+ android:background="@color/light_gray"
+ android:maxLines="3"
+ android:ellipsize="end"/>
+ <ImageView
+ android:id="@+id/imgvCover"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignLeft="@id/txtvPlaceholder"
+ android:layout_alignTop="@id/txtvPlaceholder"
+ android:layout_alignRight="@id/txtvPlaceholder"
+ android:layout_alignBottom="@id/txtvPlaceholder"
+ android:contentDescription="@string/cover_label"
+ tools:src="@drawable/ic_stat_antenna_default"
+ tools:background="@android:color/holo_green_dark"/>
+ </RelativeLayout>
<RelativeLayout
android:layout_width="0dp"
diff --git a/app/src/main/res/menu/allepisodes_context.xml b/app/src/main/res/menu/allepisodes_context.xml
index f89ad5065..171e509a8 100644
--- a/app/src/main/res/menu/allepisodes_context.xml
+++ b/app/src/main/res/menu/allepisodes_context.xml
@@ -40,13 +40,32 @@
android:title="@string/deactivate_auto_download" />
<item
- android:id="@+id/share_link_item"
- android:menuCategory="container"
- android:title="@string/share_link_label" />
- <item
android:id="@+id/visit_website_item"
android:menuCategory="container"
android:title="@string/visit_website_label" />
+ <item
+ android:id="@+id/share_item"
+ android:menuCategory="container"
+ android:title="@string/share_label">
+ <menu>
+ <item
+ android:id="@+id/share_link_item"
+ android:menuCategory="container"
+ android:title="@string/share_link_label" />
+ <item
+ android:id="@+id/share_link_with_position_item"
+ android:menuCategory="container"
+ android:title="@string/share_link_with_position_label" />
+ <item
+ android:id="@+id/share_download_url_item"
+ android:menuCategory="container"
+ android:title="@string/share_item_url_label" />
+ <item
+ android:id="@+id/share_download_url_with_position_item"
+ android:menuCategory="container"
+ android:title="@string/share_item_url_with_position_label" />
+ </menu>
+ </item>
<item
android:id="@+id/support_item"
diff --git a/app/src/main/res/menu/episodes_apply_action_options.xml b/app/src/main/res/menu/episodes_apply_action_options.xml
new file mode 100644
index 000000000..88bef8d1f
--- /dev/null
+++ b/app/src/main/res/menu/episodes_apply_action_options.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
+
+ <item
+ android:id="@+id/sort"
+ android:title="@string/sort"
+ app:showAsAction="always">
+ <menu>
+ <item android:id="@+id/sort_title"
+ android:title="@string/sort_title"/>
+ <item android:id="@+id/sort_title_a_z"
+ android:title="@string/sort_title_a_z"/>
+ <item android:id="@+id/sort_title_z_a"
+ android:title="@string/sort_title_z_a"/>
+ <item android:id="@+id/sort_date_new_old"
+ android:title="@string/sort_date_new_old"/>
+ <item android:id="@+id/sort_date_old_new"
+ android:title="@string/sort_date_old_new"/>
+ <item android:id="@+id/sort_duration_short_long"
+ android:title="@string/sort_duration_short_long"/>
+ <item android:id="@+id/sort_duration_long_short"
+ android:title="@string/sort_duration_long_short"/>
+ </menu>
+ </item>
+
+ <item
+ android:id="@+id/select_toggle"
+ android:title="@string/select_all_label"
+ app:showAsAction="always"/>
+
+ <item
+ android:id="@+id/select_options"
+ android:title="@string/all_label"
+ app:showAsAction="always">
+
+ <menu>
+ <item android:id="@+id/select_label"
+ android:title="@string/select_label"/>
+ <item android:id="@+id/check_all"
+ android:title="@string/all_label"/>
+ <item android:id="@+id/check_none"
+ android:title="@string/none_label"/>
+ <item android:id="@+id/check_played"
+ android:title="@string/played_label"/>
+ <item android:id="@+id/check_unplayed"
+ android:title="@string/unplayed_label"/>
+ <item android:id="@+id/check_downloaded"
+ android:title="@string/downloaded_label"/>
+ <item android:id="@+id/check_not_downloaded"
+ android:title="@string/not_downloaded_label"/>
+ </menu>
+ </item>
+
+</menu>
diff --git a/app/src/main/res/menu/feedinfo.xml b/app/src/main/res/menu/feedinfo.xml
index be50cb87d..9fdd56b6c 100644
--- a/app/src/main/res/menu/feedinfo.xml
+++ b/app/src/main/res/menu/feedinfo.xml
@@ -20,9 +20,9 @@
android:title="@string/share_link_label">
</item>
<item
- android:id="@+id/share_source_item"
+ android:id="@+id/share_download_url_item"
custom:showAsAction="collapseActionView"
- android:title="@string/share_source_label">
+ android:title="@string/share_feed_url_label">
</item>
-</menu> \ No newline at end of file
+</menu>
diff --git a/app/src/main/res/menu/feeditem_options.xml b/app/src/main/res/menu/feeditem_options.xml
index f8e9b9c75..650912ea2 100644
--- a/app/src/main/res/menu/feeditem_options.xml
+++ b/app/src/main/res/menu/feeditem_options.xml
@@ -48,17 +48,36 @@
</item>
<item
- android:id="@+id/share_link_item"
- custom:showAsAction="collapseActionView"
- android:title="@string/share_link_label">
- </item>
- <item
android:id="@+id/visit_website_item"
android:icon="?attr/location_web_site"
custom:showAsAction="ifRoom|collapseActionView"
android:title="@string/visit_website_label">
</item>
<item
+ android:id="@+id/share_item"
+ android:menuCategory="container"
+ android:title="@string/share_label">
+ <menu>
+ <item
+ android:id="@+id/share_link_item"
+ android:menuCategory="container"
+ android:title="@string/share_link_label" />
+ <item
+ android:id="@+id/share_link_with_position_item"
+ android:menuCategory="container"
+ android:title="@string/share_link_with_position_label" />
+ <item
+ android:id="@+id/share_download_url_item"
+ android:menuCategory="container"
+ android:title="@string/share_item_url_label" />
+ <item
+ android:id="@+id/share_download_url_with_position_item"
+ android:menuCategory="container"
+ android:title="@string/share_item_url_with_position_label" />
+ </menu>
+ </item>
+
+ <item
android:id="@+id/support_item"
custom:showAsAction="collapseActionView"
android:title="@string/support_label">
diff --git a/app/src/main/res/menu/feeditemlist_context.xml b/app/src/main/res/menu/feeditemlist_context.xml
index f89ad5065..7b10e5cce 100644
--- a/app/src/main/res/menu/feeditemlist_context.xml
+++ b/app/src/main/res/menu/feeditemlist_context.xml
@@ -40,13 +40,33 @@
android:title="@string/deactivate_auto_download" />
<item
- android:id="@+id/share_link_item"
- android:menuCategory="container"
- android:title="@string/share_link_label" />
- <item
android:id="@+id/visit_website_item"
android:menuCategory="container"
android:title="@string/visit_website_label" />
+ <item
+ android:id="@+id/share_item"
+ android:menuCategory="container"
+ android:title="@string/share_label">
+ <menu>
+ <item
+ android:id="@+id/share_link_item"
+ android:menuCategory="container"
+ android:title="@string/share_link_label" />
+ <item
+ android:id="@+id/share_link_with_position_item"
+ android:menuCategory="container"
+ android:title="@string/share_link_with_position_label" />
+ <item
+ android:id="@+id/share_download_url_item"
+ android:menuCategory="container"
+ android:title="@string/share_item_url_label" />
+ <item
+ android:id="@+id/share_download_url_with_position_item"
+ android:menuCategory="container"
+ android:title="@string/share_item_url_with_position_label" />
+ </menu>
+ </item>
+
<item
android:id="@+id/support_item"
diff --git a/app/src/main/res/menu/feedlist.xml b/app/src/main/res/menu/feedlist.xml
index e0da72667..54b90f5c6 100644
--- a/app/src/main/res/menu/feedlist.xml
+++ b/app/src/main/res/menu/feedlist.xml
@@ -10,6 +10,12 @@
custom:showAsAction="always">
</item>
<item
+ android:id="@+id/episode_actions"
+ android:menuCategory="container"
+ android:title="@string/episode_actions"
+ custom:showAsAction="always">
+ </item>
+ <item
android:id="@+id/refresh_item"
android:icon="?attr/navigation_refresh"
android:menuCategory="container"
@@ -31,18 +37,34 @@
android:title="@string/search_label"/>
<item
- android:id="@+id/mark_all_read_item"
- android:menuCategory="container"
- android:title="@string/mark_all_read_label"
- custom:showAsAction="collapseActionView">
- </item>
- <item
android:id="@+id/support_item"
android:menuCategory="container"
android:title="@string/support_label"
android:visible="false"
custom:showAsAction="collapseActionView">
</item>
+
+ <item
+ android:id="@+id/visit_website_item"
+ android:icon="?attr/location_web_site"
+ android:menuCategory="container"
+ custom:showAsAction="collapseActionView"
+ android:title="@string/visit_website_label"
+ android:visible="true">
+ </item>
+ <item
+ android:id="@+id/share_link_item"
+ android:menuCategory="container"
+ custom:showAsAction="collapseActionView"
+ android:title="@string/share_link_label">
+ </item>
+ <item
+ android:id="@+id/share_download_url_item"
+ android:menuCategory="container"
+ custom:showAsAction="collapseActionView"
+ android:title="@string/share_feed_url_label">
+ </item>
+
<item
android:id="@+id/remove_item"
android:icon="?attr/content_discard"
diff --git a/app/src/main/res/menu/mediaplayer.xml b/app/src/main/res/menu/mediaplayer.xml
index 288e44401..053e68552 100644
--- a/app/src/main/res/menu/mediaplayer.xml
+++ b/app/src/main/res/menu/mediaplayer.xml
@@ -13,11 +13,14 @@
custom:showAsAction="collapseActionView"
android:title="@string/set_sleeptimer_label">
</item>
+
<item
- android:id="@+id/share_link_item"
+ android:id="@+id/skip_episode_item"
custom:showAsAction="collapseActionView"
- android:title="@string/share_link_label">
+ android:title="@string/skip_episode_label"
+ android:visible="true">
</item>
+
<item
android:id="@+id/visit_website_item"
android:icon="?attr/location_web_site"
@@ -26,15 +29,33 @@
android:visible="false">
</item>
<item
+ android:id="@+id/share_item"
+ android:menuCategory="container"
+ android:title="@string/share_label">
+ <menu>
+ <item
+ android:id="@+id/share_link_item"
+ android:menuCategory="container"
+ android:title="@string/share_link_label" />
+ <item
+ android:id="@+id/share_link_with_position_item"
+ android:menuCategory="container"
+ android:title="@string/share_link_with_position_label" />
+ <item
+ android:id="@+id/share_download_url_item"
+ android:menuCategory="container"
+ android:title="@string/share_item_url_label" />
+ <item
+ android:id="@+id/share_download_url_with_position_item"
+ android:menuCategory="container"
+ android:title="@string/share_item_url_with_position_label" />
+ </menu>
+ </item>
+ <item
android:id="@+id/support_item"
custom:showAsAction="collapseActionView"
android:title="@string/support_label"
android:visible="false">
</item>
- <item
- android:id="@id/skip_episode_item"
- custom:showAsAction="collapseActionView"
- android:title="@string/skip_episode_label"
- android:visible="true"/>
</menu> \ No newline at end of file
diff --git a/app/src/main/res/menu/nav_feed_context.xml b/app/src/main/res/menu/nav_feed_context.xml
new file mode 100644
index 000000000..4bf067d25
--- /dev/null
+++ b/app/src/main/res/menu/nav_feed_context.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item
+ android:id="@+id/mark_all_seen_item"
+ android:menuCategory="container"
+ android:title="@string/mark_all_seen_label" />
+
+ <item
+ android:id="@+id/mark_all_read_item"
+ android:menuCategory="container"
+ android:title="@string/mark_all_read_label" />
+
+ <item
+ android:id="@+id/remove_item"
+ android:menuCategory="container"
+ android:title="@string/remove_feed_label" />
+
+</menu>
diff --git a/app/src/main/res/menu/queue_context.xml b/app/src/main/res/menu/queue_context.xml
index 6ab2daabf..d09f3c84c 100644
--- a/app/src/main/res/menu/queue_context.xml
+++ b/app/src/main/res/menu/queue_context.xml
@@ -36,21 +36,38 @@
android:id="@+id/activate_auto_download"
android:menuCategory="container"
android:title="@string/activate_auto_download" />
-
<item
android:id="@+id/deactivate_auto_download"
android:menuCategory="container"
android:title="@string/deactivate_auto_download" />
<item
- android:id="@+id/share_link_item"
- android:menuCategory="container"
- android:title="@string/share_link_label" />
- <item
android:id="@+id/visit_website_item"
android:menuCategory="container"
android:title="@string/visit_website_label" />
-
+ <item
+ android:id="@+id/share_item"
+ android:menuCategory="container"
+ android:title="@string/share_label">
+ <menu>
+ <item
+ android:id="@+id/share_link_item"
+ android:menuCategory="container"
+ android:title="@string/share_link_label" />
+ <item
+ android:id="@+id/share_link_with_position_item"
+ android:menuCategory="container"
+ android:title="@string/share_link_with_position_label" />
+ <item
+ android:id="@+id/share_download_url_item"
+ android:menuCategory="container"
+ android:title="@string/share_item_url_label" />
+ <item
+ android:id="@+id/share_download_url_with_position_item"
+ android:menuCategory="container"
+ android:title="@string/share_item_url_with_position_label" />
+ </menu>
+ </item>
<item
android:id="@+id/support_item"
android:menuCategory="container"
diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml
index e848915cf..35fb60c58 100644
--- a/app/src/main/res/xml/preferences.xml
+++ b/app/src/main/res/xml/preferences.xml
@@ -9,10 +9,29 @@
android:key="prefTheme"
android:summary="@string/pref_set_theme_sum"
android:defaultValue="0"/>
- <Preference
- android:key="prefHiddenDrawerItems"
- android:summary="@string/pref_nav_drawer_items_sum"
- android:title="@string/pref_nav_drawer_items_title" />
+ <PreferenceScreen
+ android:key="prefDrawerSettings"
+ android:summary="@string/pref_nav_drawer_sum"
+ android:title="@string/pref_nav_drawer_title">
+ <Preference
+ android:key="prefHiddenDrawerItems"
+ android:summary="@string/pref_nav_drawer_items_sum"
+ android:title="@string/pref_nav_drawer_items_title" />
+ <ListPreference
+ android:entryValues="@array/nav_drawer_feed_order_values"
+ android:entries="@array/nav_drawer_feed_order_options"
+ android:title="@string/pref_nav_drawer_feed_order_title"
+ android:key="prefDrawerFeedOrder"
+ android:summary="@string/pref_nav_drawer_feed_order_sum"
+ android:defaultValue="0"/>
+ <ListPreference
+ android:entryValues="@array/nav_drawer_feed_counter_values"
+ android:entries="@array/nav_drawer_feed_counter_options"
+ android:title="@string/pref_nav_drawer_feed_counter_title"
+ android:key="prefDrawerFeedIndicator"
+ android:summary="@string/pref_nav_drawer_feed_counter_sum"
+ android:defaultValue="0"/>
+ </PreferenceScreen>
<CheckBoxPreference
android:defaultValue="false"
android:enabled="true"
@@ -25,6 +44,12 @@
android:key="prefPersistNotify"
android:summary="@string/pref_persistNotify_sum"
android:title="@string/pref_persistNotify_title"/>
+ <CheckBoxPreference
+ android:defaultValue="true"
+ android:enabled="true"
+ android:key="prefShowDownloadReport"
+ android:summary="@string/pref_showDownloadReport_sum"
+ android:title="@string/pref_showDownloadReport_title"/>
</PreferenceCategory>
<PreferenceCategory android:title="@string/queue_label">
@@ -90,13 +115,10 @@
</PreferenceCategory>
<PreferenceCategory android:title="@string/network_pref">
- <ListPreference
- android:defaultValue="0"
- android:entries="@array/update_intervall_values"
- android:entryValues="@array/update_intervall_values"
+ <Preference
android:key="prefAutoUpdateIntervall"
- android:summary="@string/pref_autoUpdateIntervall_sum"
- android:title="@string/pref_autoUpdateIntervall_title"/>
+ android:summary="@string/pref_autoUpdateIntervallOrTime_sum"
+ android:title="@string/pref_autoUpdateIntervallOrTime_title"/>
<CheckBoxPreference
android:defaultValue="false"
android:enabled="true"
@@ -182,11 +204,13 @@
<Preference
android:title="@string/choose_data_directory"
android:key="prefChooseDataDir"/>
- <Preference
- android:key="prefFlattrThisApp"
- android:summary="@string/pref_flattr_this_app_sum"
- android:title="@string/pref_flattr_this_app_title">
- </Preference>
+ <ListPreference
+ android:entryValues="@array/image_cache_size_values"
+ android:entries="@array/image_cache_size_options"
+ android:title="@string/pref_image_cache_size_title"
+ android:key="prefImageCacheSize"
+ android:summary="@string/pref_image_cache_size_sum"
+ android:defaultValue="100"/>
<Preference
android:key="prefOpmlExport"
android:title="@string/opml_export_label"/>
@@ -194,7 +218,6 @@
android:key="prefAbout"
android:title="@string/about_pref"/>
-
</PreferenceCategory>
</PreferenceScreen>
diff --git a/app/src/main/templates/about.html b/app/src/main/templates/about.html
index 3313fa12f..2aca7ca4d 100644
--- a/app/src/main/templates/about.html
+++ b/app/src/main/templates/about.html
@@ -41,7 +41,8 @@
<div id="header" align="center">
<img src="logo.png" alt="Logo" width="100px" height="100px"/>
- <p>AntennaPod, Version @versionname@, Build @versioncode@</p>
+ <p>AntennaPod, Version @versionname@</p>
+ <p>Commit: @commit@</p>
<p>Created by Daniel Oeh</p>
@@ -67,8 +68,11 @@ licensed under the Apache 2.0 license <a href="LICENSE_PRESTO.txt">(View)</a>
<h2>jsoup <a href="http://jsoup.org/">(Link)</a></h2>
licensed under the MIT license <a href="LICENSE_JSOUP.txt">(View)</a>
-<h2>Picasso <a href="https://github.com/square/picasso">(Link)</a></h2>
-licensed under the Apache 2.0 license <a href="LICENSE_PICASSO.txt">(View)</a>
+<h2>Glide <a href="https://github.com/bumptech/glide/">(Link)</a></h2>
+licensed under the Simplified BSD license <a href="LICENSE_GLIDE.txt">(View)</a>
+
+<h2>StackBlur <a href="https://github.com/kikoso/android-stackblur">(Link)</a></h2>
+licensed under the Apache 2.0 license <a href="LICENSE_STACKBLUR.txt">(View)</a>
<h2>OkHttp <a href="https://github.com/square/okhttp">(Link)</a></h2>
licensed under the Apache 2.0 license <a href="LICENSE_OKHTTP.txt">(View)</a>