diff options
Diffstat (limited to 'app/src')
43 files changed, 885 insertions, 576 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 5836bb699..ee454ce8a 100644 --- a/app/src/androidTest/java/de/test/antennapod/handler/FeedHandlerTest.java +++ b/app/src/androidTest/java/de/test/antennapod/handler/FeedHandlerTest.java @@ -162,7 +162,7 @@ public class FeedHandlerTest extends InstrumentationTestCase { if (withImage) { image = new FeedImage(0, "image", null, "http://example.com/picture", false); } - Feed feed = new Feed(0, new Date(), "title", "http://example.com", "This is the description", + Feed feed = new Feed(0, null, "title", "http://example.com", "This is the description", "http://example.com/payment", "Daniel", "en", null, "http://example.com/feed", image, file.getAbsolutePath(), "http://example.com/feed", true); feed.setItems(new ArrayList<FeedItem>()); 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 d7a170c17..7862e986d 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 @@ -115,7 +115,7 @@ 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); + Feed f = new Feed(0, null, "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<>()); 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 f06d2f2a6..5c3d32960 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 @@ -48,7 +48,7 @@ public class PlaybackServiceTaskManagerTest extends InstrumentationTestCase { private List<FeedItem> writeTestQueue(String pref) { final Context c = getInstrumentation().getTargetContext(); final int NUM_ITEMS = 10; - Feed f = new Feed(0, new Date(), "title", "link", "d", null, null, null, null, "id", null, "null", "url", false); + Feed f = new Feed(0, null, "title", "link", "d", null, null, null, null, "id", null, "null", "url", false); f.setItems(new ArrayList<>()); for (int i = 0; i < NUM_ITEMS; i++) { f.getItems().add(new FeedItem(0, pref + i, pref + i, "link", new Date(), FeedItem.PLAYED, f)); diff --git a/app/src/androidTest/java/de/test/antennapod/storage/DBCleanupTests.java b/app/src/androidTest/java/de/test/antennapod/storage/DBCleanupTests.java index afdaeead0..7300df395 100644 --- a/app/src/androidTest/java/de/test/antennapod/storage/DBCleanupTests.java +++ b/app/src/androidTest/java/de/test/antennapod/storage/DBCleanupTests.java @@ -87,7 +87,7 @@ public class DBCleanupTests extends InstrumentationTestCase { public void testPerformAutoCleanupShouldDelete() throws IOException { final int NUM_ITEMS = EPISODE_CACHE_SIZE * 2; - Feed feed = new Feed("url", new Date(), "title"); + Feed feed = new Feed("url", null, "title"); List<FeedItem> items = new ArrayList<>(); feed.setItems(items); List<File> files = new ArrayList<>(); @@ -143,7 +143,7 @@ public class DBCleanupTests extends InstrumentationTestCase { public void testPerformAutoCleanupHandleUnplayed() throws IOException { final int NUM_ITEMS = EPISODE_CACHE_SIZE * 2; - Feed feed = new Feed("url", new Date(), "title"); + Feed feed = new Feed("url", null, "title"); List<FeedItem> items = new ArrayList<FeedItem>(); feed.setItems(items); List<File> files = new ArrayList<File>(); @@ -159,7 +159,7 @@ public class DBCleanupTests extends InstrumentationTestCase { public void testPerformAutoCleanupShouldNotDeleteBecauseInQueue() throws IOException { final int NUM_ITEMS = EPISODE_CACHE_SIZE * 2; - Feed feed = new Feed("url", new Date(), "title"); + Feed feed = new Feed("url", null, "title"); List<FeedItem> items = new ArrayList<>(); feed.setItems(items); List<File> files = new ArrayList<>(); @@ -198,7 +198,7 @@ public class DBCleanupTests extends InstrumentationTestCase { public void testPerformAutoCleanupShouldNotDeleteBecauseFavorite() throws IOException { final int NUM_ITEMS = EPISODE_CACHE_SIZE * 2; - Feed feed = new Feed("url", new Date(), "title"); + Feed feed = new Feed("url", null, "title"); List<FeedItem> items = new ArrayList<>(); feed.setItems(items); List<File> files = new ArrayList<>(); diff --git a/app/src/androidTest/java/de/test/antennapod/storage/DBNullCleanupAlgorithmTest.java b/app/src/androidTest/java/de/test/antennapod/storage/DBNullCleanupAlgorithmTest.java index 18a8d63d1..7205b42c4 100644 --- a/app/src/androidTest/java/de/test/antennapod/storage/DBNullCleanupAlgorithmTest.java +++ b/app/src/androidTest/java/de/test/antennapod/storage/DBNullCleanupAlgorithmTest.java @@ -82,7 +82,7 @@ public class DBNullCleanupAlgorithmTest extends InstrumentationTestCase { public void testPerformAutoCleanupShouldNotDelete() throws IOException { final int NUM_ITEMS = EPISODE_CACHE_SIZE * 2; - Feed feed = new Feed("url", new Date(), "title"); + Feed feed = new Feed("url", null, "title"); List<FeedItem> items = new ArrayList<>(); feed.setItems(items); List<File> files = new ArrayList<>(); diff --git a/app/src/androidTest/java/de/test/antennapod/storage/DBQueueCleanupAlgorithmTest.java b/app/src/androidTest/java/de/test/antennapod/storage/DBQueueCleanupAlgorithmTest.java index 890897f43..3bd508eaf 100644 --- a/app/src/androidTest/java/de/test/antennapod/storage/DBQueueCleanupAlgorithmTest.java +++ b/app/src/androidTest/java/de/test/antennapod/storage/DBQueueCleanupAlgorithmTest.java @@ -32,7 +32,7 @@ public class DBQueueCleanupAlgorithmTest extends DBCleanupTests { public void testPerformAutoCleanupHandleUnplayed() throws IOException { final int NUM_ITEMS = EPISODE_CACHE_SIZE * 2; - Feed feed = new Feed("url", new Date(), "title"); + Feed feed = new Feed("url", null, "title"); List<FeedItem> items = new ArrayList<>(); feed.setItems(items); List<File> files = new ArrayList<>(); 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 3988669ce..0fc3b1892 100644 --- a/app/src/androidTest/java/de/test/antennapod/storage/DBReaderTest.java +++ b/app/src/androidTest/java/de/test/antennapod/storage/DBReaderTest.java @@ -54,10 +54,10 @@ public class DBReaderTest extends InstrumentationTestCase { PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); - Feed feed1 = new Feed(0, new Date(), "A", "link", "d", null, null, null, "rss", "A", null, "", "", true); - Feed feed2 = new Feed(0, new Date(), "b", "link", "d", null, null, null, "rss", "b", null, "", "", true); - Feed feed3 = new Feed(0, new Date(), "C", "link", "d", null, null, null, "rss", "C", null, "", "", true); - Feed feed4 = new Feed(0, new Date(), "d", "link", "d", null, null, null, "rss", "d", null, "", "", true); + Feed feed1 = new Feed(0, null, "A", "link", "d", null, null, null, "rss", "A", null, "", "", true); + Feed feed2 = new Feed(0, null, "b", "link", "d", null, null, null, "rss", "b", null, "", "", true); + Feed feed3 = new Feed(0, null, "C", "link", "d", null, null, null, "rss", "C", null, "", "", true); + Feed feed4 = new Feed(0, null, "d", "link", "d", null, null, null, "rss", "d", null, "", "", true); adapter.setCompleteFeed(feed1); adapter.setCompleteFeed(feed2); adapter.setCompleteFeed(feed3); 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 1894d6585..5b2393d45 100644 --- a/app/src/androidTest/java/de/test/antennapod/storage/DBTasksTest.java +++ b/app/src/androidTest/java/de/test/antennapod/storage/DBTasksTest.java @@ -1,13 +1,9 @@ package de.test.antennapod.storage; import android.content.Context; -import android.content.SharedPreferences; -import android.preference.PreferenceManager; import android.test.FlakyTest; import android.test.InstrumentationTestCase; -import java.io.File; -import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.Date; @@ -15,14 +11,11 @@ import java.util.List; 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.preferences.UserPreferences; import de.danoeh.antennapod.core.storage.DBReader; import de.danoeh.antennapod.core.storage.DBTasks; import de.danoeh.antennapod.core.storage.PodDBAdapter; -import static de.test.antennapod.storage.DBTestUtils.saveFeedlist; - /** * Test class for DBTasks */ @@ -57,7 +50,7 @@ public class DBTasksTest extends InstrumentationTestCase { public void testUpdateFeedNewFeed() { final int NUM_ITEMS = 10; - Feed feed = new Feed("url", new Date(), "title"); + Feed feed = new Feed("url", null, "title"); feed.setItems(new ArrayList<>()); for (int i = 0; i < NUM_ITEMS; i++) { feed.getItems().add(new FeedItem(0, "item " + i, "id " + i, "link " + i, new Date(), FeedItem.UNPLAYED, feed)); @@ -75,8 +68,8 @@ public class DBTasksTest extends InstrumentationTestCase { /** Two feeds with the same title, but different download URLs should be treated as different feeds. */ public void testUpdateFeedSameTitle() { - Feed feed1 = new Feed("url1", new Date(), "title"); - Feed feed2 = new Feed("url2", new Date(), "title"); + Feed feed1 = new Feed("url1", null, "title"); + Feed feed2 = new Feed("url2", null, "title"); feed1.setItems(new ArrayList<>()); feed2.setItems(new ArrayList<>()); @@ -91,7 +84,7 @@ public class DBTasksTest extends InstrumentationTestCase { final int NUM_ITEMS_OLD = 10; final int NUM_ITEMS_NEW = 10; - final Feed feed = new Feed("url", new Date(), "title"); + final Feed feed = new Feed("url", null, "title"); feed.setItems(new ArrayList<>()); for (int i = 0; i < NUM_ITEMS_OLD; i++) { feed.getItems().add(new FeedItem(0, "item " + i, "id " + i, "link " + i, new Date(i), FeedItem.PLAYED, feed)); 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 0af8afa83..78b807710 100644 --- a/app/src/androidTest/java/de/test/antennapod/storage/DBTestUtils.java +++ b/app/src/androidTest/java/de/test/antennapod/storage/DBTestUtils.java @@ -44,7 +44,7 @@ public class DBTestUtils { PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); for (int i = 0; i < numFeeds; i++) { - Feed f = new Feed(0, new Date(), "feed " + i, "link" + i, "descr", null, null, + Feed f = new Feed(0, null, "feed " + i, "link" + i, "descr", null, null, null, null, "id" + i, null, null, "url" + i, false, new FlattrStatus(), false, null, null, false); f.setItems(new ArrayList<>()); for (int j = 0; j < numItems; j++) { 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 eaae9323c..0e1d19f7b 100644 --- a/app/src/androidTest/java/de/test/antennapod/storage/DBWriterTest.java +++ b/app/src/androidTest/java/de/test/antennapod/storage/DBWriterTest.java @@ -59,13 +59,14 @@ public class DBWriterTest extends InstrumentationTestCase { adapter.close(); } - public void testSetFeedMediaPlaybackInformation() throws IOException, ExecutionException, InterruptedException { + public void testSetFeedMediaPlaybackInformation() + throws IOException, ExecutionException, InterruptedException, TimeoutException { final int POSITION = 50; final long LAST_PLAYED_TIME = 1000; final int PLAYED_DURATION = 60; final int DURATION = 100; - Feed feed = new Feed("url", new Date(), "title"); + Feed feed = new Feed("url", null, "title"); List<FeedItem> items = new ArrayList<>(); feed.setItems(items); FeedItem item = new FeedItem(0, "Item", "Item", "url", new Date(), FeedItem.PLAYED, feed); @@ -73,13 +74,13 @@ public class DBWriterTest extends InstrumentationTestCase { FeedMedia media = new FeedMedia(0, item, DURATION, 1, 1, "mime_type", "dummy path", "download_url", true, null, 0, 0); item.setMedia(media); - DBWriter.setFeedItem(item).get(); + DBWriter.setFeedItem(item).get(TIMEOUT, TimeUnit.SECONDS); media.setPosition(POSITION); media.setLastPlayedTime(LAST_PLAYED_TIME); media.setPlayedDuration(PLAYED_DURATION); - DBWriter.setFeedMediaPlaybackInformation(item.getMedia()).get(); + DBWriter.setFeedMediaPlaybackInformation(item.getMedia()).get(TIMEOUT, TimeUnit.SECONDS); FeedItem itemFromDb = DBReader.getFeedItem(item.getId()); FeedMedia mediaFromDb = itemFromDb.getMedia(); @@ -90,12 +91,13 @@ public class DBWriterTest extends InstrumentationTestCase { assertEquals(DURATION, mediaFromDb.getDuration()); } - public void testDeleteFeedMediaOfItemFileExists() throws IOException, ExecutionException, InterruptedException { + public void testDeleteFeedMediaOfItemFileExists() + throws IOException, ExecutionException, InterruptedException, TimeoutException { File dest = new File(getInstrumentation().getTargetContext().getExternalFilesDir(TEST_FOLDER), "testFile"); assertTrue(dest.createNewFile()); - Feed feed = new Feed("url", new Date(), "title"); + Feed feed = new Feed("url", null, "title"); List<FeedItem> items = new ArrayList<>(); feed.setItems(items); FeedItem item = new FeedItem(0, "Item", "Item", "url", new Date(), FeedItem.PLAYED, feed); @@ -112,7 +114,8 @@ public class DBWriterTest extends InstrumentationTestCase { assertTrue(media.getId() != 0); assertTrue(item.getId() != 0); - DBWriter.deleteFeedMediaOfItem(getInstrumentation().getTargetContext(), media.getId()).get(); + DBWriter.deleteFeedMediaOfItem(getInstrumentation().getTargetContext(), media.getId()) + .get(TIMEOUT, TimeUnit.SECONDS); media = DBReader.getFeedMedia(media.getId()); assertNotNull(media); assertFalse(dest.exists()); @@ -124,7 +127,7 @@ public class DBWriterTest extends InstrumentationTestCase { File destFolder = getInstrumentation().getTargetContext().getExternalFilesDir(TEST_FOLDER); assertNotNull(destFolder); - Feed feed = new Feed("url", new Date(), "title"); + Feed feed = new Feed("url", null, "title"); feed.setItems(new ArrayList<>()); // create Feed image @@ -197,7 +200,7 @@ public class DBWriterTest extends InstrumentationTestCase { File destFolder = getInstrumentation().getTargetContext().getExternalFilesDir(TEST_FOLDER); assertNotNull(destFolder); - Feed feed = new Feed("url", new Date(), "title"); + Feed feed = new Feed("url", null, "title"); feed.setItems(new ArrayList<>()); feed.setImage(null); @@ -253,7 +256,7 @@ public class DBWriterTest extends InstrumentationTestCase { File destFolder = getInstrumentation().getTargetContext().getExternalFilesDir(TEST_FOLDER); assertNotNull(destFolder); - Feed feed = new Feed("url", new Date(), "title"); + Feed feed = new Feed("url", null, "title"); feed.setItems(null); // create Feed image @@ -290,7 +293,7 @@ public class DBWriterTest extends InstrumentationTestCase { File destFolder = getInstrumentation().getTargetContext().getExternalFilesDir(TEST_FOLDER); assertNotNull(destFolder); - Feed feed = new Feed("url", new Date(), "title"); + Feed feed = new Feed("url", null, "title"); feed.setItems(new ArrayList<>()); // create Feed image @@ -342,7 +345,7 @@ public class DBWriterTest extends InstrumentationTestCase { File destFolder = getInstrumentation().getTargetContext().getExternalFilesDir(TEST_FOLDER); assertNotNull(destFolder); - Feed feed = new Feed("url", new Date(), "title"); + Feed feed = new Feed("url", null, "title"); feed.setItems(new ArrayList<>()); // create Feed image @@ -400,7 +403,7 @@ public class DBWriterTest extends InstrumentationTestCase { File destFolder = getInstrumentation().getTargetContext().getExternalFilesDir(TEST_FOLDER); assertNotNull(destFolder); - Feed feed = new Feed("url", new Date(), "title"); + Feed feed = new Feed("url", null, "title"); feed.setItems(new ArrayList<>()); // create Feed image @@ -472,7 +475,7 @@ public class DBWriterTest extends InstrumentationTestCase { File destFolder = getInstrumentation().getTargetContext().getExternalFilesDir(TEST_FOLDER); assertNotNull(destFolder); - Feed feed = new Feed("url", new Date(), "title"); + Feed feed = new Feed("url", null, "title"); feed.setItems(new ArrayList<FeedItem>()); // create Feed image @@ -528,7 +531,7 @@ public class DBWriterTest extends InstrumentationTestCase { private FeedMedia playbackHistorySetup(Date playbackCompletionDate) { final Context context = getInstrumentation().getTargetContext(); - Feed feed = new Feed("url", new Date(), "title"); + Feed feed = new Feed("url", null, "title"); feed.setItems(new ArrayList<FeedItem>()); 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, 0); @@ -542,9 +545,10 @@ public class DBWriterTest extends InstrumentationTestCase { return media; } - public void testAddItemToPlaybackHistoryNotPlayedYet() throws ExecutionException, InterruptedException { + public void testAddItemToPlaybackHistoryNotPlayedYet() + throws ExecutionException, InterruptedException, TimeoutException { FeedMedia media = playbackHistorySetup(null); - DBWriter.addItemToPlaybackHistory(media).get(); + DBWriter.addItemToPlaybackHistory(media).get(TIMEOUT, TimeUnit.SECONDS); PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); media = DBReader.getFeedMedia(media.getId()); @@ -554,11 +558,12 @@ public class DBWriterTest extends InstrumentationTestCase { assertNotNull(media.getPlaybackCompletionDate()); } - public void testAddItemToPlaybackHistoryAlreadyPlayed() throws ExecutionException, InterruptedException { + public void testAddItemToPlaybackHistoryAlreadyPlayed() + throws ExecutionException, InterruptedException, TimeoutException { final long OLD_DATE = 0; FeedMedia media = playbackHistorySetup(new Date(OLD_DATE)); - DBWriter.addItemToPlaybackHistory(media).get(); + DBWriter.addItemToPlaybackHistory(media).get(TIMEOUT, TimeUnit.SECONDS); PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); media = DBReader.getFeedMedia(media.getId()); @@ -571,7 +576,7 @@ public class DBWriterTest extends InstrumentationTestCase { private Feed queueTestSetupMultipleItems(final int NUM_ITEMS) throws InterruptedException, ExecutionException, TimeoutException { final Context context = getInstrumentation().getTargetContext(); - Feed feed = new Feed("url", new Date(), "title"); + Feed feed = new Feed("url", null, "title"); feed.setItems(new ArrayList<>()); for (int i = 0; i < NUM_ITEMS; i++) { FeedItem item = new FeedItem(0, "title " + i, "id " + i, "link " + i, new Date(), FeedItem.PLAYED, feed); @@ -598,7 +603,7 @@ public class DBWriterTest extends InstrumentationTestCase { public void testAddQueueItemSingleItem() throws InterruptedException, ExecutionException, TimeoutException { final Context context = getInstrumentation().getTargetContext(); - Feed feed = new Feed("url", new Date(), "title"); + Feed feed = new Feed("url", null, "title"); feed.setItems(new ArrayList<>()); FeedItem item = new FeedItem(0, "title", "id", "link", new Date(), FeedItem.PLAYED, feed); feed.getItems().add(item); @@ -622,7 +627,7 @@ public class DBWriterTest extends InstrumentationTestCase { public void testAddQueueItemSingleItemAlreadyInQueue() throws InterruptedException, ExecutionException, TimeoutException { final Context context = getInstrumentation().getTargetContext(); - Feed feed = new Feed("url", new Date(), "title"); + Feed feed = new Feed("url", null, "title"); feed.setItems(new ArrayList<>()); FeedItem item = new FeedItem(0, "title", "id", "link", new Date(), FeedItem.PLAYED, feed); feed.getItems().add(item); @@ -688,7 +693,7 @@ public class DBWriterTest extends InstrumentationTestCase { public void testRemoveQueueItem() throws InterruptedException, ExecutionException, TimeoutException { final int NUM_ITEMS = 10; final Context context = getInstrumentation().getTargetContext(); - Feed feed = new Feed("url", new Date(), "title"); + Feed feed = new Feed("url", null, "title"); feed.setItems(new ArrayList<>()); for (int i = 0; i < NUM_ITEMS; i++) { FeedItem item = new FeedItem(0, "title " + i, "id " + i, "link " + i, new Date(), FeedItem.PLAYED, feed); @@ -733,7 +738,7 @@ public class DBWriterTest extends InstrumentationTestCase { public void testMoveQueueItem() throws InterruptedException, ExecutionException, TimeoutException { final int NUM_ITEMS = 10; - Feed feed = new Feed("url", new Date(), "title"); + Feed feed = new Feed("url", null, "title"); feed.setItems(new ArrayList<>()); for (int i = 0; i < NUM_ITEMS; i++) { FeedItem item = new FeedItem(0, "title " + i, "id " + i, "link " + i, new Date(), FeedItem.PLAYED, feed); @@ -779,7 +784,7 @@ public class DBWriterTest extends InstrumentationTestCase { public void testMarkFeedRead() throws InterruptedException, ExecutionException, TimeoutException { final int NUM_ITEMS = 10; - Feed feed = new Feed("url", new Date(), "title"); + Feed feed = new Feed("url", null, "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(), FeedItem.UNPLAYED, feed); @@ -805,7 +810,7 @@ public class DBWriterTest extends InstrumentationTestCase { public void testMarkAllItemsReadSameFeed() throws InterruptedException, ExecutionException, TimeoutException { final int NUM_ITEMS = 10; - Feed feed = new Feed("url", new Date(), "title"); + Feed feed = new Feed("url", null, "title"); feed.setItems(new ArrayList<>()); for (int i = 0; i < NUM_ITEMS; i++) { FeedItem item = new FeedItem(0, "title " + i, "id " + i, "link " + i, new Date(), FeedItem.UNPLAYED, feed); 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 e456f3891..4e214cf81 100644 --- a/app/src/androidTest/java/de/test/antennapod/ui/MainActivityTest.java +++ b/app/src/androidTest/java/de/test/antennapod/ui/MainActivityTest.java @@ -142,6 +142,7 @@ public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActiv return ((MainActivity) solo.getCurrentActivity()).getSupportActionBar().getTitle().toString(); } + @SuppressWarnings("unchecked") @FlakyTest(tolerance = 3) public void testGoToPreferences() { openNavDrawer(); 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 13abbb1cc..432d4a4e6 100644 --- a/app/src/androidTest/java/de/test/antennapod/ui/UITestUtils.java +++ b/app/src/androidTest/java/de/test/antennapod/ui/UITestUtils.java @@ -143,7 +143,7 @@ public class UITestUtils { for (int i = 0; i < NUM_FEEDS; i++) { File bitmapFile = newBitmapFile("image" + i); FeedImage image = new FeedImage(0, "image " + i, null, hostFile(bitmapFile), false); - Feed feed = new Feed(0, new Date(), "Title " + i, "http://example.com/" + i, "Description of feed " + i, + Feed feed = new Feed(0, null, "Title " + i, "http://example.com/" + i, "Description of feed " + i, "http://example.com/pay/feed" + i, "author " + i, "en", Feed.TYPE_RSS2, "feed" + i, image, null, "http://example.com/feed/src/" + i, false); image.setOwner(feed); diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 4e7863730..9d7bbee67 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,8 +1,8 @@ <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="de.danoeh.antennapod" - android:versionCode="1050003" - android:versionName="1.5.0.3"> + android:versionCode="1050004" + android:versionName="1.5.0.4"> <!-- Version code schema: "1.2.3-SNAPSHOT" -> 1020300 diff --git a/app/src/main/java/de/danoeh/antennapod/PodcastApp.java b/app/src/main/java/de/danoeh/antennapod/PodcastApp.java index c1d4bc4fd..829a49a15 100644 --- a/app/src/main/java/de/danoeh/antennapod/PodcastApp.java +++ b/app/src/main/java/de/danoeh/antennapod/PodcastApp.java @@ -57,8 +57,8 @@ public class PodcastApp extends Application { singleton = this; PodDBAdapter.init(this); - UpdateManager.init(this); UserPreferences.init(this); + UpdateManager.init(this); PlaybackPreferences.init(this); NetworkUtils.init(this); EventDistributor.getInstance(); diff --git a/app/src/main/java/de/danoeh/antennapod/UpdateManager.java b/app/src/main/java/de/danoeh/antennapod/UpdateManager.java index b1d7fffc8..0b3c43381 100644 --- a/app/src/main/java/de/danoeh/antennapod/UpdateManager.java +++ b/app/src/main/java/de/danoeh/antennapod/UpdateManager.java @@ -5,14 +5,18 @@ import android.content.Context; import android.content.SharedPreferences; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.os.Build; import android.util.Log; +import org.antennapod.audio.MediaPlayer; + 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.preferences.UserPreferences; import de.danoeh.antennapod.core.storage.DBReader; import de.danoeh.antennapod.core.storage.DBWriter; @@ -83,6 +87,11 @@ public class UpdateManager { } }.start(); } + if(oldVersionCode < 1050004) { + if(MediaPlayer.isPrestoLibraryInstalled(context) && Build.VERSION.SDK_INT >= 16) { + UserPreferences.enableSonic(true); + } + } } } 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 12bae2f51..8af6f3552 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java @@ -518,6 +518,11 @@ public class AudioplayerActivity extends MediaplayerActivity implements NavDrawe } @Override + public int getReclaimableItems() { + return (navDrawerData != null) ? navDrawerData.reclaimableSpace : 0; + } + + @Override public int getFeedCounter(long feedId) { return navDrawerData != null ? navDrawerData.feedCounters.get(feedId) : 0; } diff --git a/app/src/main/java/de/danoeh/antennapod/activity/DirectoryChooserActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/DirectoryChooserActivity.java index 25dc64232..62e85120d 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/DirectoryChooserActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/DirectoryChooserActivity.java @@ -6,8 +6,8 @@ import android.os.Bundle; import android.os.Environment; import android.os.FileObserver; import android.support.v4.app.NavUtils; -import android.support.v7.app.ActionBarActivity; import android.support.v7.app.AlertDialog; +import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.Menu; import android.view.MenuInflater; @@ -34,7 +34,8 @@ import de.danoeh.antennapod.core.preferences.UserPreferences; * Let's the user choose a directory on the storage device. The selected folder * will be sent back to the starting activity as an activity result. */ -public class DirectoryChooserActivity extends ActionBarActivity { +public class DirectoryChooserActivity extends AppCompatActivity { + private static final String TAG = "DirectoryChooserActivit"; private static final String CREATE_DIRECTORY_NAME = "AntennaPod"; @@ -250,8 +251,7 @@ public class DirectoryChooserActivity extends ActionBarActivity { @Override public boolean onPrepareOptionsMenu(Menu menu) { super.onPrepareOptionsMenu(menu); - menu.findItem(R.id.new_folder_item) - .setVisible(isValidFile(selectedDir)); + menu.findItem(R.id.new_folder_item).setVisible(isValidFile(selectedDir)); return true; } @@ -333,4 +333,5 @@ public class DirectoryChooserActivity extends ActionBarActivity { private boolean isValidFile(File file) { return file != null && file.isDirectory() && file.canRead() && file.canWrite(); } + } 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 edb973a0c..9116decb0 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/FeedInfoActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/FeedInfoActivity.java @@ -224,10 +224,12 @@ public class FeedInfoActivity extends ActionBarActivity { etxtFilterText.setText(filter.getIncludeFilter()); rdoFilterInclude.setChecked(true); rdoFilterExclude.setChecked(false); + filterInclude = true; } else if (filter.excludeOnly()) { etxtFilterText.setText(filter.getExcludeFilter()); rdoFilterInclude.setChecked(false); rdoFilterExclude.setChecked(true); + filterInclude = false; } else { Log.d(TAG, "No filter set"); rdoFilterInclude.setChecked(false); 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 f96764b42..bd7da7c03 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java @@ -644,10 +644,14 @@ public class MainActivity extends AppCompatActivity implements NavDrawerActivity } @Override + public int getReclaimableItems() { + return (navDrawerData != null) ? navDrawerData.reclaimableSpace : 0; + } + + @Override public int getFeedCounter(long feedId) { return navDrawerData != null ? navDrawerData.feedCounters.get(feedId) : 0; } - }; private void loadData() { 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 8c2b7f838..c7426c006 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java @@ -35,7 +35,6 @@ import org.jsoup.nodes.Document; import java.io.File; import java.io.IOException; import java.util.ArrayList; -import java.util.Date; import java.util.List; import java.util.Map; @@ -258,7 +257,7 @@ public class OnlineFeedViewActivity extends ActionBarActivity { private void startFeedDownload(String url, String username, String password) { Log.d(TAG, "Starting feed download"); url = URLChecker.prepareURL(url); - feed = new Feed(url, new Date(0)); + feed = new Feed(url, null); if (username != null && password != null) { feed.setPreferences(new FeedPreferences(0, false, FeedPreferences.AutoDeleteAction.GLOBAL, username, password)); } @@ -410,7 +409,7 @@ public class OnlineFeedViewActivity extends ActionBarActivity { subscribeButton.setOnClickListener(v -> { try { - Feed f = new Feed(selectedDownloadUrl, new Date(0), feed.getTitle()); + Feed f = new Feed(selectedDownloadUrl, null, feed.getTitle()); f.setPreferences(feed.getPreferences()); this.feed = f; diff --git a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportBaseActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportBaseActivity.java index d974e0e1b..46dabec12 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportBaseActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportBaseActivity.java @@ -1,16 +1,27 @@ package de.danoeh.antennapod.activity; import android.content.Intent; +import android.content.pm.PackageManager; +import android.net.Uri; +import android.os.Environment; +import android.support.v4.app.ActivityCompat; import android.support.v7.app.ActionBarActivity; import android.util.Log; -import de.danoeh.antennapod.BuildConfig; -import de.danoeh.antennapod.asynctask.OpmlFeedQueuer; -import de.danoeh.antennapod.asynctask.OpmlImportWorker; -import de.danoeh.antennapod.core.opml.OpmlElement; +import com.afollestad.materialdialogs.MaterialDialog; + +import org.apache.commons.lang3.ArrayUtils; + +import java.io.InputStreamReader; import java.io.Reader; import java.util.ArrayList; +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.asynctask.OpmlFeedQueuer; +import de.danoeh.antennapod.asynctask.OpmlImportWorker; +import de.danoeh.antennapod.core.opml.OpmlElement; +import de.danoeh.antennapod.core.util.LangUtils; + /** * Base activity for Opml Import - e.g. with code what to do afterwards * */ @@ -19,22 +30,23 @@ public class OpmlImportBaseActivity extends ActionBarActivity { private static final String TAG = "OpmlImportBaseActivity"; private OpmlImportWorker importWorker; - /** + private static final int PERMISSION_REQUEST_READ_EXTERNAL_STORAGE = 5; + private Uri uri; + + /** * Handles the choices made by the user in the OpmlFeedChooserActivity and * starts the OpmlFeedQueuer if necessary. */ @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { - if (BuildConfig.DEBUG) - Log.d(TAG, "Received result"); + Log.d(TAG, "Received result"); if (resultCode == RESULT_CANCELED) { - if (BuildConfig.DEBUG) - Log.d(TAG, "Activity was cancelled"); - if (finishWhenCanceled()) - finish(); + Log.d(TAG, "Activity was cancelled"); + if (finishWhenCanceled()) { + finish(); + } } else { - int[] selected = data - .getIntArrayExtra(OpmlFeedChooserActivity.EXTRA_SELECTED_ITEMS); + int[] selected = data.getIntArrayExtra(OpmlFeedChooserActivity.EXTRA_SELECTED_ITEMS); if (selected != null && selected.length > 0) { OpmlFeedQueuer queuer = new OpmlFeedQueuer(this, selected) { @@ -50,35 +62,75 @@ public class OpmlImportBaseActivity extends ActionBarActivity { }; queuer.executeAsync(); } else { - if (BuildConfig.DEBUG) - Log.d(TAG, "No items were selected"); + Log.d(TAG, "No items were selected"); } } } - /** Starts the import process. */ - protected void startImport(Reader reader) { + protected void importUri(Uri uri) { + this.uri = uri; + if(uri.toString().contains(Environment.getExternalStorageDirectory().toString())) { + int permission = ActivityCompat.checkSelfPermission(this, android.Manifest.permission.READ_EXTERNAL_STORAGE); + if (permission != PackageManager.PERMISSION_GRANTED) { + requestPermission(); + return; + } + } + startImport(); + } + + private void requestPermission() { + String[] permissions = { android.Manifest.permission.READ_EXTERNAL_STORAGE }; + ActivityCompat.requestPermissions(this, permissions, PERMISSION_REQUEST_READ_EXTERNAL_STORAGE); + } - if (reader != null) { - importWorker = new OpmlImportWorker(this, reader) { + @Override + public void onRequestPermissionsResult(int requestCode, + String[] permissions, + int[] grantResults) { + if (requestCode != PERMISSION_REQUEST_READ_EXTERNAL_STORAGE) { + return; + } + if (grantResults.length > 0 && ArrayUtils.contains(grantResults, PackageManager.PERMISSION_GRANTED)) { + startImport(); + } else { + new MaterialDialog.Builder(this) + .content(R.string.opml_import_ask_read_permission) + .positiveText(android.R.string.ok) + .negativeText(R.string.cancel_label) + .onPositive((dialog, which) -> requestPermission()) + .onNegative((dialog, which) -> finish()) + .show(); + } + } + + /** Starts the import process. */ + protected void startImport() { + try { + Reader mReader = new InputStreamReader(getContentResolver().openInputStream(uri), LangUtils.UTF_8); + importWorker = new OpmlImportWorker(this, mReader) { @Override protected void onPostExecute(ArrayList<OpmlElement> result) { super.onPostExecute(result); if (result != null) { - if (BuildConfig.DEBUG) - Log.d(TAG, "Parsing was successful"); + Log.d(TAG, "Parsing was successful"); OpmlImportHolder.setReadElements(result); startActivityForResult(new Intent( OpmlImportBaseActivity.this, OpmlFeedChooserActivity.class), 0); } else { - if (BuildConfig.DEBUG) - Log.d(TAG, "Parser error occurred"); + Log.d(TAG, "Parser error occurred"); } } }; importWorker.executeAsync(); + } catch (Exception e) { + Log.d(TAG, Log.getStackTraceString(e)); + new MaterialDialog.Builder(this) + .content("Cannot open OPML file: " + e.getMessage()) + .positiveText(android.R.string.ok) + .show(); } } diff --git a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportFromIntentActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportFromIntentActivity.java index 46e5f0e8e..ab4b0d0ee 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportFromIntentActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportFromIntentActivity.java @@ -2,25 +2,14 @@ package de.danoeh.antennapod.activity; import android.net.Uri; import android.os.Bundle; -import android.support.v7.app.AlertDialog; -import android.util.Log; import de.danoeh.antennapod.core.preferences.UserPreferences; -import de.danoeh.antennapod.core.util.LangUtils; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.InputStreamReader; -import java.io.Reader; -import java.net.URL; /** Lets the user start the OPML-import process. */ public class OpmlImportFromIntentActivity extends OpmlImportBaseActivity { private static final String TAG = "OpmlImportFromIntentAct"; - @Override protected void onCreate(Bundle savedInstanceState) { setTheme(UserPreferences.getTheme()); @@ -28,15 +17,8 @@ public class OpmlImportFromIntentActivity extends OpmlImportBaseActivity { getSupportActionBar().setDisplayHomeAsUpEnabled(true); - try { - Uri uri = getIntent().getData(); - - Reader mReader = new InputStreamReader(getContentResolver().openInputStream(uri), LangUtils.UTF_8); - startImport(mReader); - } catch (Exception e) { - new AlertDialog.Builder(this).setMessage("Cannot open XML - Reason: " + e.getMessage()).show(); - } - + Uri uri = getIntent().getData(); + importUri(uri); } @Override 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 6e3991739..15d97cc2c 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportFromPathActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportFromPathActivity.java @@ -11,16 +11,9 @@ import android.view.View; import android.widget.Button; import android.widget.TextView; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.InputStreamReader; -import java.io.Reader; - 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; /** @@ -114,19 +107,6 @@ public class OpmlImportFromPathActivity extends OpmlImportBaseActivity { } } - private void startImport(File file) { - Reader mReader = null; - try { - mReader = new InputStreamReader(new FileInputStream(file), - LangUtils.UTF_8); - Log.d(TAG, "Parsing " + file.toString()); - startImport(mReader); - } catch (FileNotFoundException e) { - Log.d(TAG, "File not found which really should be there"); - // this should never happen as it is a file we have just chosen - } - } - /* * Creates an implicit intent to launch a file manager which lets * the user choose a specific OPML-file to import from. @@ -155,13 +135,7 @@ public class OpmlImportFromPathActivity extends OpmlImportBaseActivity { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK && requestCode == CHOOSE_OPML_FILE) { Uri uri = data.getData(); - - try { - Reader mReader = new InputStreamReader(getContentResolver().openInputStream(uri), LangUtils.UTF_8); - startImport(mReader); - } catch (FileNotFoundException e) { - Log.d(TAG, "File not found"); - } + importUri(uri); } } diff --git a/app/src/main/java/de/danoeh/antennapod/activity/StorageErrorActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/StorageErrorActivity.java index b02e82f0b..e980764ec 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/StorageErrorActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/StorageErrorActivity.java @@ -1,30 +1,109 @@ package de.danoeh.antennapod.activity; +import android.Manifest; +import android.app.Activity; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.os.Build; import android.os.Bundle; -import android.support.v7.app.ActionBarActivity; +import android.support.v4.app.ActivityCompat; +import android.support.v4.content.ContextCompat; +import android.support.v7.app.AlertDialog; +import android.support.v7.app.AppCompatActivity; +import android.text.Html; import android.text.TextUtils; import android.util.Log; +import android.widget.Button; + +import com.afollestad.materialdialogs.MaterialDialog; + +import java.io.File; +import java.util.ArrayList; +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.Converter; import de.danoeh.antennapod.core.util.StorageUtils; /** Is show if there is now external storage available. */ -public class StorageErrorActivity extends ActionBarActivity { +public class StorageErrorActivity extends AppCompatActivity { + private static final String TAG = "StorageErrorActivity"; + private static final String[] EXTERNAL_STORAGE_PERMISSIONS = { + Manifest.permission.READ_EXTERNAL_STORAGE, + Manifest.permission.WRITE_EXTERNAL_STORAGE }; + private static final int PERMISSION_REQUEST_EXTERNAL_STORAGE = 42; + @Override protected void onCreate(Bundle savedInstanceState) { setTheme(UserPreferences.getTheme()); super.onCreate(savedInstanceState); setContentView(R.layout.storage_error); - } + + Button btnChooseDataFolder = (Button) findViewById(R.id.btnChooseDataFolder); + btnChooseDataFolder.setOnClickListener(v -> { + if (Build.VERSION_CODES.KITKAT <= Build.VERSION.SDK_INT && + Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) { + showChooseDataFolderDialog(); + } else { + openDirectoryChooser(); + } + }); + if (Build.VERSION.SDK_INT == Build.VERSION_CODES.M) { + int readPermission = ActivityCompat.checkSelfPermission(this, + Manifest.permission.READ_EXTERNAL_STORAGE); + int writePermission = ActivityCompat.checkSelfPermission(this, + Manifest.permission.WRITE_EXTERNAL_STORAGE); + if (readPermission != PackageManager.PERMISSION_GRANTED || + writePermission != PackageManager.PERMISSION_GRANTED) { + requestPermission(); + } + } + } + + private void requestPermission() { + ActivityCompat.requestPermissions(this, EXTERNAL_STORAGE_PERMISSIONS, + PERMISSION_REQUEST_EXTERNAL_STORAGE); + } + + private void openDirectoryChooser() { + Intent intent = new Intent(this, DirectoryChooserActivity.class); + startActivityForResult(intent, DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED); + } + + @Override + public void onRequestPermissionsResult(int requestCode, + String[] permissions, + int[] grantResults) { + if (requestCode != PERMISSION_REQUEST_EXTERNAL_STORAGE || grantResults.length != 2) { + return; + } + if (grantResults[0] != PackageManager.PERMISSION_GRANTED || + grantResults[1] != PackageManager.PERMISSION_GRANTED) { + new MaterialDialog.Builder(this) + .content(R.string.choose_data_directory_permission_rationale) + .positiveText(android.R.string.ok) + .onPositive((dialog, which) -> requestPermission()) + .onNegative((dialog, which) -> finish()) + .show(); + } + } + + @Override + protected void onResume() { + super.onResume(); + if (StorageUtils.storageAvailable()) { + leaveErrorState(); + } else { + registerReceiver(mediaUpdate, new IntentFilter(Intent.ACTION_MEDIA_MOUNTED)); + } + } @Override protected void onPause() { @@ -32,18 +111,102 @@ public class StorageErrorActivity extends ActionBarActivity { try { unregisterReceiver(mediaUpdate); } catch (IllegalArgumentException e) { - + Log.e(TAG, Log.getStackTraceString(e)); } } - @Override - protected void onResume() { - super.onResume(); - if (StorageUtils.storageAvailable()) { - leaveErrorState(); - } else { - registerReceiver(mediaUpdate, new IntentFilter( - Intent.ACTION_MEDIA_MOUNTED)); + // see PreferenceController.showChooseDataFolderDialog() + private void showChooseDataFolderDialog() { + File dataFolder = UserPreferences.getDataFolder(null); + if(dataFolder == null) { + new MaterialDialog.Builder(this) + .title(R.string.error_label) + .content(R.string.external_storage_error_msg) + .neutralText(android.R.string.ok) + .show(); + return; + } + String dataFolderPath = dataFolder.getAbsolutePath(); + int selectedIndex = -1; + File[] mediaDirs = ContextCompat.getExternalFilesDirs(this, null); + List<String> folders = new ArrayList<>(mediaDirs.length); + List<CharSequence> choices = new ArrayList<>(mediaDirs.length); + for(int i=0; i < mediaDirs.length; i++) { + if(mediaDirs[i] == null) { + continue; + } + String path = mediaDirs[i].getAbsolutePath(); + folders.add(path); + if(dataFolderPath.equals(path)) { + selectedIndex = i; + } + int index = path.indexOf("Android"); + String choice; + if(index >= 0) { + choice = path.substring(0, index); + } else { + choice = path; + } + long bytes = StorageUtils.getFreeSpaceAvailable(path); + String freeSpace = String.format(getString(R.string.free_space_label), + Converter.byteToString(bytes)); + choices.add(Html.fromHtml("<html><small>" + choice + " [" + freeSpace + "]" + + "</small></html>")); + } + if(choices.size() == 0) { + new MaterialDialog.Builder(this) + .title(R.string.error_label) + .content(R.string.external_storage_error_msg) + .neutralText(android.R.string.ok) + .show(); + return; + } + MaterialDialog dialog = new MaterialDialog.Builder(this) + .title(R.string.choose_data_directory) + .content(R.string.choose_data_directory_message) + .items(choices.toArray(new CharSequence[choices.size()])) + .itemsCallbackSingleChoice(selectedIndex, (dialog1, itemView, which, text) -> { + String folder = folders.get(which); + UserPreferences.setDataFolder(folder); + leaveErrorState(); + return true; + }) + .negativeText(R.string.cancel_label) + .cancelable(true) + .build(); + dialog.show(); + } + + public void onActivityResult(int requestCode, int resultCode, Intent data) { + if (resultCode == Activity.RESULT_OK && + requestCode == DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED) { + String dir = data.getStringExtra(DirectoryChooserActivity.RESULT_SELECTED_DIR); + + File path; + if (dir != null) { + path = new File(dir); + } else { + path = getExternalFilesDir(null); + } + String message = null; + if(!path.exists()) { + message = String.format(getString(R.string.folder_does_not_exist_error), dir); + } else if(!path.canRead()) { + message = String.format(getString(R.string.folder_not_readable_error), dir); + } else if(!path.canWrite()) { + message = String.format(getString(R.string.folder_not_writable_error), dir); + } + + if(message == null) { + Log.d(TAG, "Setting data folder: " + dir); + UserPreferences.setDataFolder(dir); + leaveErrorState(); + } else { + AlertDialog.Builder ab = new AlertDialog.Builder(this); + ab.setMessage(message); + ab.setPositiveButton(android.R.string.ok, null); + ab.show(); + } } } @@ -58,13 +221,10 @@ public class StorageErrorActivity extends ActionBarActivity { public void onReceive(Context context, Intent intent) { if (TextUtils.equals(intent.getAction(), Intent.ACTION_MEDIA_MOUNTED)) { if (intent.getBooleanExtra("read-only", true)) { - if (BuildConfig.DEBUG) - Log.d(TAG, "Media was mounted; Finishing activity"); + Log.d(TAG, "Media was mounted; Finishing activity"); leaveErrorState(); } else { - if (BuildConfig.DEBUG) - Log.d(TAG, - "Media seemed to have been mounted read only"); + Log.d(TAG, "Media seemed to have been mounted read only"); } } } 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 582538fb8..893c92907 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java @@ -13,8 +13,6 @@ import android.widget.Toast; import com.joanzapata.iconify.Iconify; import com.joanzapata.iconify.widget.IconButton; -import java.util.Date; - import de.danoeh.antennapod.R; import de.danoeh.antennapod.core.dialog.DownloadRequestErrorDialogCreator; import de.danoeh.antennapod.core.feed.Feed; @@ -123,9 +121,8 @@ public class DownloadLogAdapter extends BaseAdapter { if(holder.typeId == Feed.FEEDFILETYPE_FEED) { Feed feed = DBReader.getFeed(holder.id); if (feed != null) { - feed.setLastUpdate(new Date(0)); // force refresh try { - DBTasks.refreshFeed(context, feed); + DBTasks.forceRefreshFeed(context, feed); } catch (DownloadRequestException e) { e.printStackTrace(); } 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 ca747b9b0..53dedd496 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/DownloadedEpisodesListAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/DownloadedEpisodesListAdapter.java @@ -25,13 +25,10 @@ public class DownloadedEpisodesListAdapter extends BaseAdapter { private final Context context; private final ItemAccess itemAccess; - private final int imageSize; - public DownloadedEpisodesListAdapter(Context context, ItemAccess itemAccess) { super(); this.context = context; this.itemAccess = itemAccess; - this.imageSize = (int) context.getResources().getDimension(R.dimen.thumbnail_length_downloaded_item); } @Override @@ -52,7 +49,7 @@ public class DownloadedEpisodesListAdapter extends BaseAdapter { @Override public View getView(int position, View convertView, ViewGroup parent) { Holder holder; - final FeedItem item = (FeedItem) getItem(position); + final FeedItem item = getItem(position); if (item == null) return null; if (convertView == null) { @@ -61,44 +58,44 @@ public class DownloadedEpisodesListAdapter extends BaseAdapter { .getSystemService(Context.LAYOUT_INFLATER_SERVICE); convertView = inflater.inflate(R.layout.downloaded_episodeslist_item, parent, false); + holder.imageView = (ImageView) convertView.findViewById(R.id.imgvImage); holder.title = (TextView) convertView.findViewById(R.id.txtvTitle); + holder.txtvSize = (TextView) convertView.findViewById(R.id.txtvSize); + holder.queueStatus = (ImageView) convertView.findViewById(R.id.imgvInPlaylist); holder.pubDate = (TextView) convertView .findViewById(R.id.txtvPublished); holder.butSecondary = (ImageButton) convertView .findViewById(R.id.butSecondaryAction); - holder.imageView = (ImageView) convertView.findViewById(R.id.imgvImage); - holder.txtvSize = (TextView) convertView.findViewById(R.id.txtvSize); convertView.setTag(holder); } else { holder = (Holder) convertView.getTag(); } + Glide.with(context) + .load(item.getImageUri()) + .placeholder(R.color.light_gray) + .error(R.color.light_gray) + .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY) + .fitCenter() + .dontAnimate() + .into(holder.imageView); + holder.title.setText(item.getTitle()); + holder.txtvSize.setText(Converter.byteToString(item.getMedia().getSize())); + holder.queueStatus.setVisibility(item.isTagged(FeedItem.TAG_QUEUE) ? View.VISIBLE : View.GONE); String pubDateStr = DateUtils.formatAbbrev(context, item.getPubDate()); holder.pubDate.setText(pubDateStr); - holder.txtvSize.setText(Converter.byteToString(item.getMedia().getSize())); - FeedItem.State state = item.getState(); + FeedItem.State state = item.getState(); if (state == FeedItem.State.PLAYING) { holder.butSecondary.setEnabled(false); } else { holder.butSecondary.setEnabled(true); } - holder.butSecondary.setFocusable(false); holder.butSecondary.setTag(item); holder.butSecondary.setOnClickListener(secondaryActionListener); - - Glide.with(context) - .load(item.getImageUri()) - .placeholder(R.color.light_gray) - .error(R.color.light_gray) - .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY) - .fitCenter() - .dontAnimate() - .into(holder.imageView); - return convertView; } @@ -112,10 +109,11 @@ public class DownloadedEpisodesListAdapter extends BaseAdapter { static class Holder { - TextView title; - TextView pubDate; ImageView imageView; + TextView title; TextView txtvSize; + ImageView queueStatus; + TextView pubDate; ImageButton butSecondary; } diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistDescriptionAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistDescriptionAdapter.java index 9011c8b02..5b205e91f 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistDescriptionAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistDescriptionAdapter.java @@ -6,11 +6,13 @@ import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.TextView; -import de.danoeh.antennapod.R; -import de.danoeh.antennapod.core.feed.FeedItem; import java.util.List; +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.core.feed.FeedItem; +import de.danoeh.antennapod.core.util.DateUtils; + /** * List adapter for showing a list of FeedItems with their title and description. */ @@ -33,6 +35,7 @@ public class FeedItemlistDescriptionAdapter extends ArrayAdapter<FeedItem> { .getSystemService(Context.LAYOUT_INFLATER_SERVICE); convertView = inflater.inflate(R.layout.itemdescription_listitem, parent, false); holder.title = (TextView) convertView.findViewById(R.id.txtvTitle); + holder.pubDate = (TextView) convertView.findViewById(R.id.txtvPubDate); holder.description = (TextView) convertView.findViewById(R.id.txtvDescription); convertView.setTag(holder); @@ -41,15 +44,20 @@ public class FeedItemlistDescriptionAdapter extends ArrayAdapter<FeedItem> { } holder.title.setText(item.getTitle()); + holder.pubDate.setText(DateUtils.formatAbbrev(getContext(), item.getPubDate())); if (item.getDescription() != null) { - holder.description.setText(item.getDescription()); + String description = item.getDescription() + .replaceAll("\n", " ") + .replaceAll("\\s+", " ") + .trim(); + holder.description.setText(description); } - return convertView; } static class Holder { TextView title; + TextView pubDate; TextView description; } } 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 d43e30d8f..269614d35 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java @@ -228,7 +228,11 @@ public class NavListAdapter extends BaseAdapter } } else if(tag.equals(DownloadsFragment.TAG) && UserPreferences.isEnableAutodownload()) { int epCacheSize = UserPreferences.getEpisodeCacheSize(); - if(itemAccess.getNumberOfDownloadedItems() >= epCacheSize) { + // don't count episodes that can be reclaimed + int spaceUsed = itemAccess.getNumberOfDownloadedItems() - + itemAccess.getReclaimableItems(); + + if (spaceUsed >= epCacheSize) { holder.count.setText("{md-disc-full 150%}"); Iconify.addIcons(holder.count); holder.count.setVisibility(View.VISIBLE); @@ -335,6 +339,7 @@ public class NavListAdapter extends BaseAdapter int getQueueSize(); int getNumberOfNewItems(); int getNumberOfDownloadedItems(); + int getReclaimableItems(); int getFeedCounter(long feedId); } diff --git a/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlFeedQueuer.java b/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlFeedQueuer.java index 00327bce0..cc27b6c9d 100644 --- a/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlFeedQueuer.java +++ b/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlFeedQueuer.java @@ -6,7 +6,6 @@ import android.content.Context; import android.os.AsyncTask; import java.util.Arrays; -import java.util.Date; import de.danoeh.antennapod.activity.OpmlImportHolder; import de.danoeh.antennapod.core.R; @@ -47,7 +46,7 @@ public class OpmlFeedQueuer extends AsyncTask<Void, Void, Void> { for (int idx = 0; idx < selection.length; idx++) { OpmlElement element = OpmlImportHolder.getReadElements().get( selection[idx]); - Feed feed = new Feed(element.getXmlUrl(), new Date(0), + Feed feed = new Feed(element.getXmlUrl(), null, element.getText()); try { requester.downloadFeed(context.getApplicationContext(), feed); diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java b/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java index 6432ebd4e..ac7a9efee 100644 --- a/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java @@ -1,7 +1,6 @@ package de.danoeh.antennapod.dialog; import android.content.res.TypedArray; -import android.graphics.Color; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.support.v4.app.ActivityCompat; @@ -18,10 +17,6 @@ import android.widget.Button; import android.widget.ListView; import android.widget.Toast; -import com.joanzapata.iconify.Icon; -import com.joanzapata.iconify.IconDrawable; -import com.joanzapata.iconify.fonts.FontAwesomeIcons; - import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -39,6 +34,14 @@ public class EpisodesApplyActionFragment extends Fragment { public String TAG = "EpisodeActionFragment"; + public static final int ACTION_QUEUE = 1; + public static final int ACTION_MARK_PLAYED = 2; + public static final int ACTION_MARK_UNPLAYED = 4; + public static final int ACTION_DOWNLOAD = 8; + public static final int ACTION_REMOVE = 16; + public static final int ACTION_ALL = ACTION_QUEUE | ACTION_MARK_PLAYED | ACTION_MARK_UNPLAYED + | ACTION_DOWNLOAD | ACTION_REMOVE; + private ListView mListView; private ArrayAdapter<String> mAdapter; @@ -48,27 +51,26 @@ public class EpisodesApplyActionFragment extends Fragment { private Button btnDownload; private Button btnDelete; - private final Map<Long,FeedItem> idMap; - private final List<FeedItem> episodes; + private final Map<Long,FeedItem> idMap = new ArrayMap<>(); + private final List<FeedItem> episodes = new ArrayList<>(); + private int actions; private final List<String> titles = new ArrayList(); private final LongList checkedIds = new LongList(); private MenuItem mSelectToggle; - private int textColor; - - public EpisodesApplyActionFragment() { - this.episodes = new ArrayList<>(); - this.idMap = new ArrayMap<>(); + public static EpisodesApplyActionFragment newInstance(List<FeedItem> items) { + return newInstance(items, ACTION_ALL); } - public void setEpisodes(List<FeedItem> episodes) { - this.episodes.clear(); - this.episodes.addAll(episodes); - this.idMap.clear(); - for(FeedItem episode : episodes) { - this.idMap.put(episode.getId(), episode); + public static EpisodesApplyActionFragment newInstance(List<FeedItem> items, int actions) { + EpisodesApplyActionFragment f = new EpisodesApplyActionFragment(); + f.episodes.addAll(items); + for(FeedItem episode : items) { + f.idMap.put(episode.getId(), episode); } + f.actions = actions; + return f; } @Override @@ -103,16 +105,48 @@ public class EpisodesApplyActionFragment extends Fragment { mListView.setAdapter(mAdapter); checkAll(); + int lastVisibleDiv = 0; btnAddToQueue = (Button) view.findViewById(R.id.btnAddToQueue); - btnAddToQueue.setOnClickListener(v -> queueChecked()); + if((actions & ACTION_QUEUE) != 0) { + btnAddToQueue.setOnClickListener(v -> queueChecked()); + lastVisibleDiv = R.id.divider1; + } else { + btnAddToQueue.setVisibility(View.GONE); + view.findViewById(R.id.divider1).setVisibility(View.GONE); + } btnMarkAsPlayed = (Button) view.findViewById(R.id.btnMarkAsPlayed); - btnMarkAsPlayed.setOnClickListener(v -> markedCheckedPlayed()); + if((actions & ACTION_MARK_PLAYED) != 0) { + btnMarkAsPlayed.setOnClickListener(v -> markedCheckedPlayed()); + lastVisibleDiv = R.id.divider2; + } else { + btnMarkAsPlayed.setVisibility(View.GONE); + view.findViewById(R.id.divider2).setVisibility(View.GONE); + } btnMarkAsUnplayed = (Button) view.findViewById(R.id.btnMarkAsUnplayed); - btnMarkAsUnplayed.setOnClickListener(v -> markedCheckedUnplayed()); + if((actions & ACTION_MARK_UNPLAYED) != 0) { + btnMarkAsUnplayed.setOnClickListener(v -> markedCheckedUnplayed()); + lastVisibleDiv = R.id.divider3; + } else { + btnMarkAsUnplayed.setVisibility(View.GONE); + view.findViewById(R.id.divider3).setVisibility(View.GONE); + } btnDownload = (Button) view.findViewById(R.id.btnDownload); - btnDownload.setOnClickListener(v -> downloadChecked()); + if((actions & ACTION_DOWNLOAD) != 0) { + btnDownload.setOnClickListener(v -> downloadChecked()); + lastVisibleDiv = R.id.divider4; + } else { + btnDownload.setVisibility(View.GONE); + view.findViewById(R.id.divider4).setVisibility(View.GONE); + } btnDelete = (Button) view.findViewById(R.id.btnDelete); - btnDelete.setOnClickListener(v -> deleteChecked()); + if((actions & ACTION_REMOVE) != 0) { + btnDelete.setOnClickListener(v -> deleteChecked()); + } else { + btnDelete.setVisibility(View.GONE); + if(lastVisibleDiv > 0) { + view.findViewById(lastVisibleDiv).setVisibility(View.GONE); + } + } return view; } @@ -122,11 +156,6 @@ public class EpisodesApplyActionFragment extends Fragment { 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(); - mSelectToggle = menu.findItem(R.id.select_toggle); mSelectToggle.setOnMenuItemClickListener(item -> { if (checkedIds.size() == episodes.size()) { @@ -140,22 +169,21 @@ public class EpisodesApplyActionFragment extends Fragment { @Override public void onPrepareOptionsMenu (Menu menu) { - /* - * Prepare icon for select toggle button - */ + // Prepare icon for select toggle button - // Find icon attribute int[] icon = new int[1]; - if(checkedIds.size() == episodes.size()) icon[0] = R.attr.ic_check_box; - else if(checkedIds.size() == 0) icon[0] = R.attr.ic_check_box_outline; - else icon[0] = R.attr.ic_indeterminate_check_box; + if (checkedIds.size() == episodes.size()) { + icon[0] = R.attr.ic_check_box; + } else if (checkedIds.size() == 0) { + icon[0] = R.attr.ic_check_box_outline; + } else { + icon[0] = R.attr.ic_indeterminate_check_box; + } - // Get Drawable from attribute TypedArray a = getActivity().obtainStyledAttributes(icon); Drawable iconDrawable = a.getDrawable(0); a.recycle(); - // Set icon mSelectToggle.setIcon(iconDrawable); } @@ -189,6 +217,14 @@ public class EpisodesApplyActionFragment extends Fragment { checkDownloaded(false); resId = R.string.selected_not_downloaded_label; break; + case R.id.check_queued: + checkQueued(true); + resId = R.string.selected_queued_label; + break; + case R.id.check_not_queued: + checkQueued(false); + resId = R.string.selected_not_queued_label; + break; case R.id.sort_title_a_z: sortByTitle(false); return true; @@ -310,6 +346,17 @@ public class EpisodesApplyActionFragment extends Fragment { refreshCheckboxes(); } + private void checkQueued(boolean isQueued) { + for (FeedItem episode : episodes) { + if(episode.isTagged(FeedItem.TAG_QUEUE) == isQueued) { + checkedIds.add(episode.getId()); + } else { + checkedIds.remove(episode.getId()); + } + } + refreshCheckboxes(); + } + private void refreshTitles() { titles.clear(); for(FeedItem episode : episodes) { diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java index ce1d753e8..96abdd835 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java @@ -68,7 +68,7 @@ public class ChaptersFragment extends ListFragment implements AudioplayerContent this.media = media; adapter.setMedia(media); adapter.notifyDataSetChanged(); - if(media.getChapters() == null) { + if(media == null || media.getChapters() == null || media.getChapters().size() == 0) { setEmptyText(getString(R.string.no_items_label)); } else { setEmptyText(null); diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java index 954c4c9e2..a53c85f1c 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java @@ -1,12 +1,20 @@ package de.danoeh.antennapod.fragment; -import android.app.Activity; +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Color; import android.os.Bundle; import android.support.v4.app.ListFragment; import android.util.Log; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; import android.view.View; import android.widget.ListView; +import com.joanzapata.iconify.IconDrawable; +import com.joanzapata.iconify.fonts.FontAwesomeIcons; + import java.util.List; import de.danoeh.antennapod.R; @@ -14,8 +22,10 @@ import de.danoeh.antennapod.activity.MainActivity; import de.danoeh.antennapod.adapter.DownloadedEpisodesListAdapter; import de.danoeh.antennapod.core.feed.EventDistributor; 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.storage.DBWriter; +import de.danoeh.antennapod.dialog.EpisodesApplyActionFragment; import rx.Observable; import rx.Subscription; import rx.android.schedulers.AndroidSchedulers; @@ -28,22 +38,21 @@ public class CompletedDownloadsFragment extends ListFragment { private static final String TAG = CompletedDownloadsFragment.class.getSimpleName(); - private static final int EVENTS = - EventDistributor.DOWNLOAD_HANDLED | - EventDistributor.DOWNLOADLOG_UPDATE | - EventDistributor.UNREAD_ITEMS_UPDATE; + private static final int EVENTS = EventDistributor.DOWNLOAD_HANDLED | + EventDistributor.DOWNLOADLOG_UPDATE | + EventDistributor.UNREAD_ITEMS_UPDATE; private List<FeedItem> items; private DownloadedEpisodesListAdapter listAdapter; private boolean viewCreated = false; - private boolean itemsLoaded = false; private Subscription subscription; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + setHasOptionsMenu(true); loadItems(); } @@ -81,9 +90,9 @@ public class CompletedDownloadsFragment extends ListFragment { } @Override - public void onAttach(Activity activity) { - super.onAttach(activity); - if (viewCreated && itemsLoaded) { + public void onAttach(Context context) { + super.onAttach(context); + if (viewCreated && items != null) { onFragmentLoaded(); } } @@ -99,7 +108,7 @@ public class CompletedDownloadsFragment extends ListFragment { lv.setPadding(0, vertPadding, 0, vertPadding); viewCreated = true; - if (itemsLoaded && getActivity() != null) { + if (items != null && getActivity() != null) { onFragmentLoaded(); } } @@ -111,7 +120,6 @@ public class CompletedDownloadsFragment extends ListFragment { if (item != null) { ((MainActivity) getActivity()).loadChildFragment(ItemFragment.newInstance(item.getId())); } - } private void onFragmentLoaded() { @@ -121,6 +129,43 @@ public class CompletedDownloadsFragment extends ListFragment { } setListShown(true); listAdapter.notifyDataSetChanged(); + getActivity().supportInvalidateOptionsMenu(); + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + if(!isAdded()) { + return; + } + super.onCreateOptionsMenu(menu, inflater); + if(items != null) { + inflater.inflate(R.menu.downloads_completed, menu); + MenuItem episodeActions = menu.findItem(R.id.episode_actions); + if(items.size() > 0) { + int[] attrs = {R.attr.action_bar_icon_color}; + TypedArray ta = getActivity().obtainStyledAttributes(UserPreferences.getTheme(), attrs); + int textColor = ta.getColor(0, Color.GRAY); + ta.recycle(); + episodeActions.setIcon(new IconDrawable(getActivity(), + FontAwesomeIcons.fa_gears).color(textColor).actionBarSize()); + episodeActions.setVisible(true); + } else { + episodeActions.setVisible(false); + } + } + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.episode_actions: + EpisodesApplyActionFragment fragment = EpisodesApplyActionFragment + .newInstance(items, EpisodesApplyActionFragment.ACTION_REMOVE); + ((MainActivity) getActivity()).loadChildFragment(fragment); + return true; + default: + return false; + } } private DownloadedEpisodesListAdapter.ItemAccess itemAccess = new DownloadedEpisodesListAdapter.ItemAccess() { @@ -157,7 +202,7 @@ public class CompletedDownloadsFragment extends ListFragment { if(subscription != null) { subscription.unsubscribe(); } - if (!itemsLoaded && viewCreated) { + if (items == null && viewCreated) { setListShown(false); } subscription = Observable.fromCallable(() -> DBReader.getDownloadedItems()) @@ -166,7 +211,6 @@ public class CompletedDownloadsFragment extends ListFragment { .subscribe(result -> { if (result != null) { items = result; - itemsLoaded = true; if (viewCreated && getActivity() != null) { onFragmentLoaded(); } 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 7a9b73982..303d273bc 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java @@ -252,8 +252,8 @@ public class ItemlistFragment extends ListFragment { if (!FeedMenuHandler.onOptionsItemClicked(getActivity(), item, feed)) { switch (item.getItemId()) { case R.id.episode_actions: - EpisodesApplyActionFragment fragment = new EpisodesApplyActionFragment(); - fragment.setEpisodes(feed.getItems()); + EpisodesApplyActionFragment fragment = EpisodesApplyActionFragment + .newInstance(feed.getItems()); ((MainActivity)getActivity()).loadChildFragment(fragment); return true; case R.id.remove_item: 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 830e9d419..38030f4ea 100644 --- a/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java +++ b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java @@ -63,10 +63,10 @@ public class FeedMenuHandler { final Feed selectedFeed) throws DownloadRequestException { switch (item.getItemId()) { case R.id.refresh_item: - DBTasks.refreshFeed(context, selectedFeed); + DBTasks.forceRefreshFeed(context, selectedFeed); break; case R.id.refresh_complete_item: - DBTasks.refreshCompleteFeed(context, selectedFeed); + DBTasks.forceRefreshCompleteFeed(context, selectedFeed); break; case R.id.filter_items: showFilterDialog(context, selectedFeed); 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 785944768..c563d278f 100644 --- a/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java +++ b/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java @@ -1,12 +1,13 @@ package de.danoeh.antennapod.preferences; +import android.Manifest; import android.annotation.SuppressLint; import android.app.Activity; import android.app.TimePickerDialog; import android.content.Context; -import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; +import android.content.pm.PackageManager; import android.content.res.Resources; import android.net.Uri; import android.net.wifi.WifiConfiguration; @@ -18,6 +19,7 @@ import android.preference.ListPreference; import android.preference.Preference; import android.preference.PreferenceManager; import android.preference.PreferenceScreen; +import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; import android.support.v7.app.AlertDialog; import android.text.Editable; @@ -85,6 +87,11 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc private CheckBoxPreference[] selectedNetworks; + private static final String[] EXTERNAL_STORAGE_PERMISSIONS = { + Manifest.permission.READ_EXTERNAL_STORAGE, + Manifest.permission.WRITE_EXTERNAL_STORAGE }; + private static final int PERMISSION_REQUEST_EXTERNAL_STORAGE = 41; + public PreferenceController(PreferenceUI ui) { this.ui = ui; PreferenceManager.getDefaultSharedPreferences(ui.getActivity().getApplicationContext()) @@ -121,54 +128,51 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc // disable expanded notification option on unsupported android versions ui.findPreference(PreferenceController.PREF_EXPANDED_NOTIFICATION).setEnabled(false); ui.findPreference(PreferenceController.PREF_EXPANDED_NOTIFICATION).setOnPreferenceClickListener( - new Preference.OnPreferenceClickListener() { - - @Override - public boolean onPreferenceClick(Preference preference) { - Toast toast = Toast.makeText(activity, R.string.pref_expand_notify_unsupport_toast, Toast.LENGTH_SHORT); - toast.show(); - return true; - } + preference -> { + Toast toast = Toast.makeText(activity, + R.string.pref_expand_notify_unsupport_toast, Toast.LENGTH_SHORT); + toast.show(); + return true; } ); } - ui.findPreference(PreferenceController.PREF_FLATTR_REVOKE).setOnPreferenceClickListener( - new Preference.OnPreferenceClickListener() { - - @Override - public boolean onPreferenceClick(Preference preference) { - FlattrUtils.revokeAccessToken(activity); - checkItemVisibility(); - return true; - } - + preference -> { + FlattrUtils.revokeAccessToken(activity); + checkItemVisibility(); + return true; } ); - ui.findPreference(PreferenceController.PREF_ABOUT).setOnPreferenceClickListener( - new Preference.OnPreferenceClickListener() { - - @Override - public boolean onPreferenceClick(Preference preference) { - activity.startActivity(new Intent( - activity, AboutActivity.class)); - return true; - } - + preference -> { + activity.startActivity(new Intent(activity, AboutActivity.class)); + return true; } ); - ui.findPreference(PreferenceController.PREF_OPML_EXPORT).setOnPreferenceClickListener( - new Preference.OnPreferenceClickListener() { - - @Override - public boolean onPreferenceClick(Preference preference) { - new OpmlExportWorker(activity) - .executeAsync(); - - return true; + preference -> { + new OpmlExportWorker(activity).executeAsync(); + return true; + } + ); + ui.findPreference(PreferenceController.PREF_CHOOSE_DATA_DIR).setOnPreferenceClickListener( + preference -> { + if (Build.VERSION_CODES.KITKAT <= Build.VERSION.SDK_INT && + Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) { + showChooseDataFolderDialog(); + } else { + int readPermission = ActivityCompat.checkSelfPermission( + activity, Manifest.permission.READ_EXTERNAL_STORAGE); + int writePermission = ActivityCompat.checkSelfPermission( + activity, Manifest.permission.WRITE_EXTERNAL_STORAGE); + if (readPermission == PackageManager.PERMISSION_GRANTED && + writePermission == PackageManager.PERMISSION_GRANTED) { + openDirectoryChooser(); + } else { + requestPermission(); + } } + return true; } ); ui.findPreference(PreferenceController.PREF_CHOOSE_DATA_DIR) @@ -185,40 +189,29 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc } return true; } - } - ); + } + ); ui.findPreference(UserPreferences.PREF_THEME) .setOnPreferenceChangeListener( - new Preference.OnPreferenceChangeListener() { - - @Override - public boolean onPreferenceChange( - Preference preference, Object newValue) { - Intent i = new Intent(activity, MainActivity.class); - i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK - | Intent.FLAG_ACTIVITY_NEW_TASK); - activity.finish(); - activity.startActivity(i); - return true; - } + (preference, newValue) -> { + Intent i = new Intent(activity, MainActivity.class); + i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK + | Intent.FLAG_ACTIVITY_NEW_TASK); + activity.finish(); + activity.startActivity(i); + return true; } ); ui.findPreference(UserPreferences.PREF_HIDDEN_DRAWER_ITEMS) - .setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(Preference preference) { - showDrawerPreferencesDialog(); - return true; - } + .setOnPreferenceClickListener(preference -> { + showDrawerPreferencesDialog(); + return true; }); ui.findPreference(UserPreferences.PREF_UPDATE_INTERVAL) - .setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(Preference preference) { - showUpdateIntervalTimePreferencesDialog(); - return true; - } + .setOnPreferenceClickListener(preference -> { + showUpdateIntervalTimePreferencesDialog(); + return true; }); ui.findPreference(UserPreferences.PREF_ENABLE_AUTODL).setOnPreferenceChangeListener( @@ -234,38 +227,30 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc }); ui.findPreference(UserPreferences.PREF_ENABLE_AUTODL_WIFI_FILTER) .setOnPreferenceChangeListener( - new Preference.OnPreferenceChangeListener() { - - @Override - public boolean onPreferenceChange( - Preference preference, Object newValue) { - if (newValue instanceof Boolean) { - setSelectedNetworksEnabled((Boolean) newValue); - return true; - } else { - return false; - } + (preference, newValue) -> { + if (newValue instanceof Boolean) { + setSelectedNetworksEnabled((Boolean) newValue); + return true; + } else { + return false; } } ); ui.findPreference(UserPreferences.PREF_PARALLEL_DOWNLOADS) .setOnPreferenceChangeListener( - new Preference.OnPreferenceChangeListener() { - @Override - public boolean onPreferenceChange(Preference preference, Object o) { - if (o instanceof String) { - try { - int value = Integer.valueOf((String) o); - if (1 <= value && value <= 50) { - setParallelDownloadsText(value); - return true; - } - } catch (NumberFormatException e) { - return false; + (preference, o) -> { + if (o instanceof String) { + try { + int value = Integer.valueOf((String) o); + if (1 <= value && value <= 50) { + setParallelDownloadsText(value); + return true; } + } catch (NumberFormatException e) { + return false; } - return false; } + return false; } ); // validate and set correct value: number of downloads between 1 and 50 (inclusive) @@ -298,102 +283,79 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc }); ui.findPreference(UserPreferences.PREF_EPISODE_CACHE_SIZE) .setOnPreferenceChangeListener( - new Preference.OnPreferenceChangeListener() { - @Override - public boolean onPreferenceChange(Preference preference, Object o) { - if (o instanceof String) { - setEpisodeCacheSizeText(UserPreferences.readEpisodeCacheSize((String) o)); - } - return true; + (preference, o) -> { + if (o instanceof String) { + setEpisodeCacheSizeText(UserPreferences.readEpisodeCacheSize((String) o)); } + return true; } ); ui.findPreference(PreferenceController.PREF_PLAYBACK_SPEED_LAUNCHER) - .setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(Preference preference) { - VariableSpeedDialog.showDialog(activity); - return true; - } + .setOnPreferenceClickListener(preference -> { + VariableSpeedDialog.showDialog(activity); + return true; }); - ui.findPreference(PreferenceController.PREF_GPODNET_SETLOGIN_INFORMATION).setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(Preference preference) { - AuthenticationDialog dialog = new AuthenticationDialog(activity, - R.string.pref_gpodnet_setlogin_information_title, false, false, GpodnetPreferences.getUsername(), - null) { - - @Override - protected void onConfirmed(String username, String password, boolean saveUsernamePassword) { - GpodnetPreferences.setPassword(password); - } - }; - dialog.show(); - return true; - } - }); - ui.findPreference(PreferenceController.PREF_GPODNET_LOGOUT).setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(Preference preference) { - GpodnetPreferences.logout(); - Toast toast = Toast.makeText(activity, R.string.pref_gpodnet_logout_toast, Toast.LENGTH_SHORT); - toast.show(); - updateGpodnetPreferenceScreen(); - return true; - } - }); - ui.findPreference(PreferenceController.PREF_GPODNET_HOSTNAME).setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(Preference preference) { - GpodnetSetHostnameDialog.createDialog(activity).setOnDismissListener(new DialogInterface.OnDismissListener() { - @Override - public void onDismiss(DialogInterface dialog) { - updateGpodnetPreferenceScreen(); - } + ui.findPreference(PreferenceController.PREF_GPODNET_SETLOGIN_INFORMATION) + .setOnPreferenceClickListener(preference -> { + AuthenticationDialog dialog = new AuthenticationDialog(activity, + R.string.pref_gpodnet_setlogin_information_title, false, false, GpodnetPreferences.getUsername(), + null) { + + @Override + protected void onConfirmed(String username, String password, boolean saveUsernamePassword) { + GpodnetPreferences.setPassword(password); + } + }; + dialog.show(); + return true; + }); + ui.findPreference(PreferenceController.PREF_GPODNET_LOGOUT).setOnPreferenceClickListener( + preference -> { + GpodnetPreferences.logout(); + Toast toast = Toast.makeText(activity, R.string.pref_gpodnet_logout_toast, Toast.LENGTH_SHORT); + toast.show(); + updateGpodnetPreferenceScreen(); + return true; + }); + ui.findPreference(PreferenceController.PREF_GPODNET_HOSTNAME).setOnPreferenceClickListener( + preference -> { + GpodnetSetHostnameDialog.createDialog(activity).setOnDismissListener(dialog -> updateGpodnetPreferenceScreen()); + return true; }); - return true; - } - }); - ui.findPreference(PreferenceController.PREF_AUTO_FLATTR_PREFS).setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(Preference preference) { - AutoFlattrPreferenceDialog.newAutoFlattrPreferenceDialog(activity, - new AutoFlattrPreferenceDialog.AutoFlattrPreferenceDialogInterface() { - @Override - public void onCancelled() { + ui.findPreference(PreferenceController.PREF_AUTO_FLATTR_PREFS) + .setOnPreferenceClickListener(preference -> { + AutoFlattrPreferenceDialog.newAutoFlattrPreferenceDialog(activity, + new AutoFlattrPreferenceDialog.AutoFlattrPreferenceDialogInterface() { + @Override + public void onCancelled() { - } + } - @Override - public void onConfirmed(boolean autoFlattrEnabled, float autoFlattrValue) { - UserPreferences.setAutoFlattrSettings(autoFlattrEnabled, autoFlattrValue); - checkItemVisibility(); - } - }); - return true; - } - }); - 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; + @Override + public void onConfirmed(boolean autoFlattrEnabled, float autoFlattrValue) { + UserPreferences.setAutoFlattrSettings(autoFlattrEnabled, autoFlattrValue); + checkItemVisibility(); } - return false; - } + }); + return true; + }); + ui.findPreference(UserPreferences.PREF_IMAGE_CACHE_SIZE).setOnPreferenceChangeListener( + (preference, 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; + } + ); ui.findPreference("prefSendCrashReport").setOnPreferenceClickListener(preference -> { Intent emailIntent = new Intent(Intent.ACTION_SEND); emailIntent.setType("text/plain"); @@ -427,7 +389,12 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc requestCode == DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED) { String dir = data.getStringExtra(DirectoryChooserActivity.RESULT_SELECTED_DIR); - File path = new File(dir); + File path; + if(dir != null) { + path = new File(dir); + } else { + path = ui.getActivity().getExternalFilesDir(null); + } String message = null; final Context context= ui.getActivity().getApplicationContext(); if(!path.exists()) { @@ -628,35 +595,31 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc List<String> prefValues = Arrays.asList(UserPreferences .getAutodownloadSelectedNetworks()); PreferenceScreen prefScreen = (PreferenceScreen) ui.findPreference(PreferenceController.AUTO_DL_PREF_SCREEN); - Preference.OnPreferenceClickListener clickListener = new Preference.OnPreferenceClickListener() { - - @Override - public boolean onPreferenceClick(Preference preference) { - if (preference instanceof CheckBoxPreference) { - String key = preference.getKey(); - ArrayList<String> prefValuesList = new ArrayList<String>( - Arrays.asList(UserPreferences - .getAutodownloadSelectedNetworks()) - ); - boolean newValue = ((CheckBoxPreference) preference) - .isChecked(); - Log.d(TAG, "Selected network " + key + ". New state: " + newValue); - - int index = prefValuesList.indexOf(key); - if (index >= 0 && newValue == false) { - // remove network - prefValuesList.remove(index); - } else if (index < 0 && newValue == true) { - prefValuesList.add(key); - } - - UserPreferences.setAutodownloadSelectedNetworks( - prefValuesList.toArray(new String[prefValuesList.size()]) - ); - return true; - } else { - return false; + Preference.OnPreferenceClickListener clickListener = preference -> { + if (preference instanceof CheckBoxPreference) { + String key = preference.getKey(); + ArrayList<String> prefValuesList = new ArrayList<String>( + Arrays.asList(UserPreferences + .getAutodownloadSelectedNetworks()) + ); + boolean newValue = ((CheckBoxPreference) preference) + .isChecked(); + Log.d(TAG, "Selected network " + key + ". New state: " + newValue); + + int index = prefValuesList.indexOf(key); + if (index >= 0 && newValue == false) { + // remove network + prefValuesList.remove(index); + } else if (index < 0 && newValue == true) { + prefValuesList.add(key); } + + UserPreferences.setAutodownloadSelectedNetworks( + prefValuesList.toArray(new String[prefValuesList.size()]) + ); + return true; + } else { + return false; } }; // create preference for each known network. attach listener and set @@ -703,7 +666,6 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc checked[i] = true; } } - AlertDialog.Builder builder = new AlertDialog.Builder(context); builder.setTitle(R.string.drawer_preferences); builder.setMultiChoiceItems(navTitles, checked, (dialog, which, isChecked) -> { @@ -713,16 +675,26 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc hiddenDrawerItems.add(NAV_DRAWER_TAGS[which]); } }); - builder.setPositiveButton(R.string.confirm_label, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - UserPreferences.setHiddenDrawerItems(hiddenDrawerItems); - } + builder.setPositiveButton(R.string.confirm_label, (dialog, which) -> { + UserPreferences.setHiddenDrawerItems(hiddenDrawerItems); }); builder.setNegativeButton(R.string.cancel_label, null); builder.create().show(); } + // CHOOSE DATA FOLDER + + private void requestPermission() { + ActivityCompat.requestPermissions(ui.getActivity(), EXTERNAL_STORAGE_PERMISSIONS, + PERMISSION_REQUEST_EXTERNAL_STORAGE); + } + + private void openDirectoryChooser() { + Activity activity = ui.getActivity(); + Intent intent = new Intent(activity, DirectoryChooserActivity.class); + activity.startActivityForResult(intent, DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED); + } + private void showChooseDataFolderDialog() { Context context = ui.getActivity(); File dataFolder = UserPreferences.getDataFolder(null); @@ -786,6 +758,8 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc dialog.show(); } + // UPDATE TIME/INTERVAL DIALOG + private void showUpdateIntervalTimePreferencesDialog() { final Context context = ui.getActivity(); @@ -795,38 +769,34 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc builder.positiveText(R.string.pref_autoUpdateIntervallOrTime_Interval); builder.negativeText(R.string.pref_autoUpdateIntervallOrTime_TimeOfDay); builder.neutralText(R.string.pref_autoUpdateIntervallOrTime_Disable); - builder.callback(new MaterialDialog.ButtonCallback() { - @Override - public void onPositive(MaterialDialog dialog) { - 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); - long currInterval = UserPreferences.getUpdateInterval(); - int checkedItem = -1; - if(currInterval > 0) { - String currIntervalStr = String.valueOf(TimeUnit.MILLISECONDS.toHours(currInterval)); - checkedItem = ArrayUtils.indexOf(values, currIntervalStr); - } - builder.setSingleChoiceItems(entries, checkedItem, (dialog1, which) -> { - int hours = Integer.valueOf(values[which]); - UserPreferences.setUpdateInterval(hours); - dialog1.dismiss(); - setUpdateIntervalText(); - }); - builder.setNegativeButton(context.getString(R.string.cancel_label), null); - builder.show(); + builder.onPositive((dialog, which) -> { + AlertDialog.Builder builder1 = new AlertDialog.Builder(context); + builder1.setTitle(context.getString(R.string.pref_autoUpdateIntervallOrTime_Interval)); + final String[] values = context.getResources().getStringArray(R.array.update_intervall_values); + final String[] entries = getUpdateIntervalEntries(values); + long currInterval = UserPreferences.getUpdateInterval(); + int checkedItem = -1; + if(currInterval > 0) { + String currIntervalStr = String.valueOf(TimeUnit.MILLISECONDS.toHours(currInterval)); + checkedItem = ArrayUtils.indexOf(values, currIntervalStr); } - - @Override - public void onNegative(MaterialDialog dialog) { - int hourOfDay = 7, minute = 0; - int[] updateTime = UserPreferences.getUpdateTimeOfDay(); - if (updateTime.length == 2) { - hourOfDay = updateTime[0]; - minute = updateTime[1]; - } - TimePickerDialog timePickerDialog = new TimePickerDialog(context, + builder1.setSingleChoiceItems(entries, checkedItem, (dialog1, which1) -> { + int hours = Integer.valueOf(values[which1]); + UserPreferences.setUpdateInterval(hours); + dialog1.dismiss(); + setUpdateIntervalText(); + }); + builder1.setNegativeButton(context.getString(R.string.cancel_label), null); + builder1.show(); + }); + builder.onNegative((dialog, 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, (view, selectedHourOfDay, selectedMinute) -> { if (view.getTag() == null) { // onTimeSet() may get called twice! view.setTag("TAGGED"); @@ -834,17 +804,13 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc setUpdateIntervalText(); } }, hourOfDay, minute, DateFormat.is24HourFormat(context)); - timePickerDialog.setTitle(context.getString(R.string.pref_autoUpdateIntervallOrTime_TimeOfDay)); - timePickerDialog.show(); - } - - @Override - public void onNeutral(MaterialDialog dialog) { - UserPreferences.setUpdateInterval(0); - setUpdateIntervalText(); - } + timePickerDialog.setTitle(context.getString(R.string.pref_autoUpdateIntervallOrTime_TimeOfDay)); + timePickerDialog.show(); + }); + builder.onNeutral((dialog, which) -> { + UserPreferences.setUpdateInterval(0); + setUpdateIntervalText(); }); - builder.forceStacking(true); builder.show(); } diff --git a/app/src/main/java/de/danoeh/antennapod/receiver/SPAReceiver.java b/app/src/main/java/de/danoeh/antennapod/receiver/SPAReceiver.java index ef6330f82..8201fe3e2 100644 --- a/app/src/main/java/de/danoeh/antennapod/receiver/SPAReceiver.java +++ b/app/src/main/java/de/danoeh/antennapod/receiver/SPAReceiver.java @@ -8,7 +8,6 @@ import android.util.Log; import android.widget.Toast; import java.util.Arrays; -import java.util.Date; import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; @@ -35,7 +34,7 @@ public class SPAReceiver extends BroadcastReceiver{ if (feedUrls != null) { if (BuildConfig.DEBUG) Log.d(TAG, "Received feeds list: " + Arrays.toString(feedUrls)); for (String url : feedUrls) { - Feed f = new Feed(url, new Date(0)); + Feed f = new Feed(url, null); try { DownloadRequester.getInstance().downloadFeed(context, f); } catch (DownloadRequestException e) { diff --git a/app/src/main/res/layout/downloaded_episodeslist_item.xml b/app/src/main/res/layout/downloaded_episodeslist_item.xml index 6b5f7369a..760b6b9db 100644 --- a/app/src/main/res/layout/downloaded_episodeslist_item.xml +++ b/app/src/main/res/layout/downloaded_episodeslist_item.xml @@ -22,7 +22,7 @@ <RelativeLayout android:layout_width="0dp" - android:layout_height="match_parent" + android:layout_height="@dimen/thumbnail_length_downloaded_item" android:layout_marginLeft="@dimen/listitem_threeline_textleftpadding" android:layout_marginRight="@dimen/listitem_threeline_textrightpadding" android:layout_marginTop="@dimen/listitem_threeline_verticalpadding" @@ -48,7 +48,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" - android:layout_below="@id/txtvTitle" + android:layout_alignParentBottom="true" tools:text="23 MB" tools:background="@android:color/holo_green_dark" /> @@ -58,10 +58,23 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" - android:layout_below="@id/txtvTitle" + android:layout_alignParentBottom="true" + android:layout_marginLeft="8dp" tools:text="Jan 23" tools:background="@android:color/holo_green_dark" /> + <ImageView + android:id="@+id/imgvInPlaylist" + android:layout_width="@dimen/enc_icons_size" + android:layout_height="@dimen/enc_icons_size" + android:layout_toLeftOf="@id/txtvPublished" + android:layout_alignParentBottom="true" + android:contentDescription="@string/in_queue_label" + android:src="?attr/stat_playlist" + android:visibility="visible" + tools:src="@drawable/ic_list_white_24dp" + tools:background="@android:color/holo_red_light" /> + </RelativeLayout> <include layout="@layout/vertical_list_divider"/> diff --git a/app/src/main/res/layout/episodes_apply_action_fragment.xml b/app/src/main/res/layout/episodes_apply_action_fragment.xml index d63088662..e9a2e2e23 100644 --- a/app/src/main/res/layout/episodes_apply_action_fragment.xml +++ b/app/src/main/res/layout/episodes_apply_action_fragment.xml @@ -1,16 +1,16 @@ -<RelativeLayout - xmlns:android="http://schemas.android.com/apk/res/android" +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:id="@+id/bottomBar" - android:layout_width="wrap_content" + android:layout_width="match_parent" android:layout_height="68dp" android:layout_alignParentBottom="true" - android:orientation="horizontal" android:gravity="center_vertical" + android:orientation="horizontal" android:padding="4dp"> <Button @@ -18,103 +18,98 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" + android:background="@android:color/transparent" android:drawableTop="?attr/content_new" android:text="@string/add_to_queue_label" - android:textSize="10sp" - android:background="@android:color/transparent"/> + android:textSize="10sp" /> - <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" /> + <View + android:id="@+id/divider1" + 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:background="@android:color/transparent" android:drawableTop="?attr/navigation_accept" android:text="@string/mark_read_label" - android:textSize="10sp" - android:background="@android:color/transparent"/> + android:textSize="10sp" /> - <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" /> + <View + android:id="@+id/divider2" + 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:background="@android:color/transparent" android:drawableTop="?attr/navigation_cancel" android:text="@string/mark_unread_label" - android:textSize="10sp" - android:background="@android:color/transparent"/> + android:textSize="10sp" /> - <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" /> + <View + android:id="@+id/divider3" + 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:background="@android:color/transparent" android:drawableTop="?attr/av_download" android:text="@string/download_label" - android:textSize="10sp" - android:background="@android:color/transparent"/> + android:textSize="10sp" /> - <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" /> + <View + android:id="@+id/divider4" + 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:background="@android:color/transparent" android:drawableTop="?attr/content_discard" android:text="@string/remove_episode_lable" - android:textSize="10sp" - android:background="@android:color/transparent"/> + android:textSize="10sp" /> </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" /> + android:layout_width="match_parent" + android:layout_height="1dp" + android:layout_above="@id/bottomBar" + android:background="?android:attr/listDivider" + android:paddingBottom="4dp" + 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> - + android:layout_above="@id/divider"/> </RelativeLayout> diff --git a/app/src/main/res/layout/itemdescription_listitem.xml b/app/src/main/res/layout/itemdescription_listitem.xml index ca8f974bf..51bc9a5eb 100644 --- a/app/src/main/res/layout/itemdescription_listitem.xml +++ b/app/src/main/res/layout/itemdescription_listitem.xml @@ -1,30 +1,55 @@ <?xml version="1.0" encoding="utf-8"?> -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" +<RelativeLayout + xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" - android:layout_height="match_parent" - android:orientation="vertical" + android:layout_height="wrap_content" + android:paddingTop="8dp" + android:paddingLeft="16dp" + android:paddingRight="16dp" + android:paddingBottom="8dp" tools:background="@android:color/holo_orange_light"> <TextView + android:id="@+id/txtvPubDate" + style="@android:style/TextAppearance.Small" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignParentRight="true" + android:layout_alignParentTop="true" + android:layout_marginLeft="8dp" + android:textSize="14sp" + android:textColor="?android:textColorSecondary" + android:ellipsize="end" + android:lines="1" + tools:text="22 Jan 2016" + tools:background="@android:color/holo_green_dark" /> + + <TextView android:id="@+id/txtvTitle" - style="@style/AntennaPod.TextView.ListItemPrimaryTitle" - android:layout_width="match_parent" + android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_margin="16dp" + android:layout_alignParentLeft="true" + android:layout_alignParentTop="true" + android:layout_toLeftOf="@id/txtvPubDate" + android:textSize="16sp" + android:textColor="?android:attr/textColorPrimary" + android:ellipsize="end" + android:maxLines="2" tools:text="Feed item title" tools:background="@android:color/holo_green_dark" /> <TextView android:id="@+id/txtvDescription" - style="@style/AntennaPod.TextView.ListItemSecondaryTitle" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginBottom="16dp" - android:layout_marginLeft="16dp" - android:layout_marginRight="16dp" - android:lines="3" + android:layout_below="@id/txtvTitle" + android:textSize="14sp" + android:textColor="?android:attr/textColorSecondary" + android:ellipsize="end" + android:maxLines="3" tools:text="Feed item description" tools:background="@android:color/holo_green_dark" /> -</LinearLayout> + +</RelativeLayout> diff --git a/app/src/main/res/layout/storage_error.xml b/app/src/main/res/layout/storage_error.xml index c1ee77262..8ff28b3c1 100644 --- a/app/src/main/res/layout/storage_error.xml +++ b/app/src/main/res/layout/storage_error.xml @@ -1,25 +1,32 @@ <?xml version="1.0" encoding="utf-8"?> -<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" - android:layout_height="match_parent" > + android:layout_height="match_parent" + android:orientation="vertical" + android:gravity="center" + android:padding="16dp"> <ImageView android:id="@+id/imageView1" android:contentDescription="@string/external_storage_error_msg" - android:layout_width="30dp" - android:layout_height="30dp" - android:layout_centerHorizontal="true" - android:layout_centerVertical="true" - android:layout_margin="16dp" - android:src="@android:drawable/stat_notify_sdcard_usb" /> + android:layout_width="36dp" + android:layout_height="36dp" + android:layout_margin="8dp" + android:src="?attr/ic_sd_storage" /> <TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_below="@+id/imageView1" - android:layout_centerHorizontal="true" android:layout_margin="8dp" android:text="@string/external_storage_error_msg" /> -</RelativeLayout>
\ No newline at end of file + <Button + android:id="@+id/btnChooseDataFolder" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_margin="8dp" + android:text="@string/choose_data_directory"/> + +</LinearLayout> diff --git a/app/src/main/res/menu/directory_chooser.xml b/app/src/main/res/menu/directory_chooser.xml index 7735ffd2c..3f860d636 100644 --- a/app/src/main/res/menu/directory_chooser.xml +++ b/app/src/main/res/menu/directory_chooser.xml @@ -1,14 +1,16 @@ <?xml version="1.0" encoding="utf-8"?> -<menu xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:custom="http://schemas.android.com/apk/res-auto"> +<menu + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:custom="http://schemas.android.com/apk/res-auto"> + <item android:id="@+id/new_folder_item" android:title="@string/create_folder_label" - custom:showAsAction="ifRoom|withText"/> + android:icon="?attr/ic_create_new_folder" + custom:showAsAction="ifRoom|withText" /> <item android:id="@+id/set_to_default_folder_item" - custom:showAsAction="collapseActionView" - android:title="@string/set_to_default_folder"/> - + android:title="@string/set_to_default_folder" + custom:showAsAction="collapseActionView" /> -</menu>
\ No newline at end of file +</menu> diff --git a/app/src/main/res/menu/downloads_completed.xml b/app/src/main/res/menu/downloads_completed.xml new file mode 100644 index 000000000..dc2996893 --- /dev/null +++ b/app/src/main/res/menu/downloads_completed.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?> +<menu + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:custom="http://schemas.android.com/apk/res-auto"> + + <item + android:id="@+id/episode_actions" + android:menuCategory="container" + android:title="@string/episode_actions" + custom:showAsAction="always"> + </item> + +</menu> diff --git a/app/src/main/res/menu/episodes_apply_action_options.xml b/app/src/main/res/menu/episodes_apply_action_options.xml index 90cba0966..3df88046d 100644 --- a/app/src/main/res/menu/episodes_apply_action_options.xml +++ b/app/src/main/res/menu/episodes_apply_action_options.xml @@ -42,6 +42,10 @@ android:title="@string/downloaded_label"/> <item android:id="@+id/check_not_downloaded" android:title="@string/not_downloaded_label"/> + <item android:id="@+id/check_queued" + android:title="@string/queued_label"/> + <item android:id="@+id/check_not_queued" + android:title="@string/not_queued_label"/> </menu> </item> |