diff options
Diffstat (limited to 'app/src')
13 files changed, 423 insertions, 74 deletions
diff --git a/app/src/androidTest/java/de/test/antennapod/storage/AutoDownloadTest.java b/app/src/androidTest/java/de/test/antennapod/storage/AutoDownloadTest.java new file mode 100644 index 000000000..c6beb2d42 --- /dev/null +++ b/app/src/androidTest/java/de/test/antennapod/storage/AutoDownloadTest.java @@ -0,0 +1,168 @@ +package de.test.antennapod.storage; + +import android.content.Context; +import android.content.Intent; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.test.core.app.ApplicationProvider; + +import org.awaitility.Awaitility; +import org.awaitility.core.ConditionTimeoutException; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.util.List; + +import de.danoeh.antennapod.core.ClientConfig; +import de.danoeh.antennapod.core.DBTasksCallbacks; +import de.danoeh.antennapod.core.feed.FeedItem; +import de.danoeh.antennapod.core.feed.FeedMedia; +import de.danoeh.antennapod.core.preferences.UserPreferences; +import de.danoeh.antennapod.core.service.playback.PlaybackService; +import de.danoeh.antennapod.core.storage.AutomaticDownloadAlgorithm; +import de.danoeh.antennapod.core.storage.DBReader; +import de.danoeh.antennapod.core.storage.DBTasks; +import de.danoeh.antennapod.core.storage.EpisodeCleanupAlgorithm; +import de.danoeh.antennapod.core.storage.PodDBAdapter; +import de.danoeh.antennapod.core.util.playback.Playable; +import de.test.antennapod.ui.UITestUtils; + +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +public class AutoDownloadTest { + + private Context context; + private UITestUtils stubFeedsServer; + + private DBTasksCallbacks dbTasksCallbacksOrig; + + @Before + public void setUp() throws Exception { + context = ApplicationProvider.getApplicationContext(); + + stubFeedsServer = new UITestUtils(context);; + stubFeedsServer.setup(); + + dbTasksCallbacksOrig = ClientConfig.dbTasksCallbacks; + + // create new database + PodDBAdapter.init(context); + PodDBAdapter.deleteDatabase(); + PodDBAdapter adapter = PodDBAdapter.getInstance(); + adapter.open(); + adapter.close(); + } + + @After + public void tearDown() throws Exception { + stubFeedsServer.tearDown(); + + context.sendBroadcast(new Intent(PlaybackService.ACTION_SHUTDOWN_PLAYBACK_SERVICE)); + Awaitility.await().until(() -> !PlaybackService.isRunning); + + ClientConfig.dbTasksCallbacks = dbTasksCallbacksOrig; + } + + /** + * A cross-functional test, ensuring playback's behavior works with Auto Download in boundary condition. + * + * Scenario: + * - For setting enqueue location AFTER_CURRENTLY_PLAYING + * - when playback of an episode is complete and the app advances to the next episode (continuous playback on) + * - when automatic download kicks in, + * - ensure the next episode is the current playing one, needed for AFTER_CURRENTLY_PLAYING enqueue location. + */ + @Test + public void downloadsEnqueuedToAfterCurrent_CurrentAdvancedToNextOnPlaybackComplete() throws Exception { + UserPreferences.setFollowQueue(true); // continuous playback + + // Setup: feeds and queue + // downloads 3 of them, leave some in new state (auto-downloadable) + stubFeedsServer.addLocalFeedData(false); + List<FeedItem> queue = DBReader.getQueue(); + assertTrue(queue.size() > 1); + FeedItem item0 = queue.get(0); + FeedItem item1 = queue.get(1); + + // Setup: enable automatic download + // it is not needed, as the actual automatic download is stubbed. + StubDownloadAlgorithm stubDownloadAlgorithm = new StubDownloadAlgorithm(); + useDownloadAlgorithm(stubDownloadAlgorithm); + + // Actual test + // Play the first one in the queue + playEpisode(item0); + + try { + // when playback is complete, advances to the next one, and auto download kicks in, + // ensure that currently playing has been advanced to the next one by this point. + Awaitility.await("advanced to the next episode") + .atMost(6000, MILLISECONDS) // the test mp3 media is 3-second long. twice should be enough + .until(() -> item1.equals(stubDownloadAlgorithm.getCurrentlyPlayingAtDownload())); + } catch (ConditionTimeoutException cte) { + FeedItem actual = stubDownloadAlgorithm.getCurrentlyPlayingAtDownload(); + fail("when auto download is triggered, the next episode should be playing: (" + + item1.getId() + ", " + item1.getTitle() + ") . " + + "Actual playing: (" + + (actual == null ? "" : actual.getId() + ", " + actual.getTitle()) + ")" + ); + } + + } + + private void playEpisode(@NonNull FeedItem item) { + FeedMedia media = item.getMedia(); + DBTasks.playMedia(context, media, false, true, true); + Awaitility.await("episode is playing") + .atMost(1000, MILLISECONDS) + .until(() -> item.equals(getCurrentlyPlaying())); + } + + private FeedItem getCurrentlyPlaying() { + Playable playable = Playable.PlayableUtils.createInstanceFromPreferences(context); + if (playable == null) { + return null; + } + return ((FeedMedia)playable).getItem(); + } + + private void useDownloadAlgorithm(final AutomaticDownloadAlgorithm downloadAlgorithm) { + DBTasksCallbacks dbTasksCallbacksStub = new DBTasksCallbacks() { + @Override + public AutomaticDownloadAlgorithm getAutomaticDownloadAlgorithm() { + return downloadAlgorithm; + } + + @Override + public EpisodeCleanupAlgorithm getEpisodeCacheCleanupAlgorithm() { + return dbTasksCallbacksOrig.getEpisodeCacheCleanupAlgorithm(); + } + }; + ClientConfig.dbTasksCallbacks = dbTasksCallbacksStub; + } + + private class StubDownloadAlgorithm implements AutomaticDownloadAlgorithm { + @Nullable + private FeedItem currentlyPlaying; + + @Override + public Runnable autoDownloadUndownloadedItems(Context context) { + return () -> { + if (currentlyPlaying == null) { + currentlyPlaying = getCurrentlyPlaying(); + } else { + throw new AssertionError("Stub automatic download should be invoked once and only once"); + } + }; + } + + @Nullable + FeedItem getCurrentlyPlayingAtDownload() { + return currentlyPlaying; + } + } +} 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 55ea16f13..cce4e5111 100644 --- a/app/src/androidTest/java/de/test/antennapod/storage/DBTasksTest.java +++ b/app/src/androidTest/java/de/test/antennapod/storage/DBTasksTest.java @@ -2,26 +2,31 @@ package de.test.antennapod.storage; import android.content.Context; +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.SmallTest; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Date; import java.util.List; -import androidx.test.InstrumentationRegistry; -import androidx.test.filters.LargeTest; -import androidx.test.filters.SmallTest; 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.DBWriter; import de.danoeh.antennapod.core.storage.PodDBAdapter; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import static de.danoeh.antennapod.core.util.FeedItemUtil.getIdList; import static java.util.Collections.singletonList; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; @@ -179,4 +184,82 @@ public class DBTasksTest { lastDate = item.getPubDate(); } } + + @Test + public void testAddQueueItemsInDownload_EnqueueEnabled() throws Exception { + // Setup test data / environment + UserPreferences.setEnqueueDownloadedEpisodes(true); + UserPreferences.setEnqueueLocation(UserPreferences.EnqueueLocation.BACK); + + List<FeedItem> fis1 = createSavedFeed("Feed 1", 2).getItems(); + List<FeedItem> fis2 = createSavedFeed("Feed 2", 3).getItems(); + + DBWriter.addQueueItem(context, fis1.get(0), fis2.get(0)).get(); + // the first item fis1.get(0) is already in the queue + FeedItem[] itemsToDownload = new FeedItem[]{ fis1.get(0), fis1.get(1), fis2.get(2), fis2.get(1) }; + + // Expectations: + List<FeedItem> expectedEnqueued = Arrays.asList(fis1.get(1), fis2.get(2), fis2.get(1)); + List<FeedItem> expectedQueue = new ArrayList<>(); + expectedQueue.addAll(DBReader.getQueue()); + expectedQueue.addAll(expectedEnqueued); + + // Run actual test and assert results + List<? extends FeedItem> actualEnqueued = + DBTasks.enqueueFeedItemsToDownload(context, itemsToDownload); + + assertEqualsByIds("Only items not in the queue are enqueued", expectedEnqueued, actualEnqueued); + assertEqualsByIds("Queue has new items appended", expectedQueue, DBReader.getQueue()); + } + + @Test + public void testAddQueueItemsInDownload_EnqueueDisabled() throws Exception { + // Setup test data / environment + UserPreferences.setEnqueueDownloadedEpisodes(false); + + List<FeedItem> fis1 = createSavedFeed("Feed 1", 2).getItems(); + List<FeedItem> fis2 = createSavedFeed("Feed 2", 3).getItems(); + + DBWriter.addQueueItem(context, fis1.get(0), fis2.get(0)).get(); + FeedItem[] itemsToDownload = new FeedItem[]{ fis1.get(0), fis1.get(1), fis2.get(2), fis2.get(1) }; + + // Expectations: + List<FeedItem> expectedEnqueued = Collections.emptyList(); + List<FeedItem> expectedQueue = DBReader.getQueue(); + + // Run actual test and assert results + List<? extends FeedItem> actualEnqueued = + DBTasks.enqueueFeedItemsToDownload(context, itemsToDownload); + + assertEqualsByIds("No item is enqueued", expectedEnqueued, actualEnqueued); + assertEqualsByIds("Queue is unchanged", expectedQueue, DBReader.getQueue()); + } + + private void assertEqualsByIds(String msg, List<? extends FeedItem> expected, List<? extends FeedItem> actual) { + // assert only the IDs, so that any differences are easily to spot. + List<Long> expectedIds = getIdList(expected); + List<Long> actualIds = getIdList(actual); + assertEquals(msg, expectedIds, actualIds); + } + + private Feed createSavedFeed(String title, int numFeedItems) { + final Feed feed = new Feed("url", null, title); + + if (numFeedItems > 0) { + List<FeedItem> items = new ArrayList<>(numFeedItems); + for (int i = 1; i <= numFeedItems; i++) { + FeedItem item = new FeedItem(0, "item " + i + " of " + title, "id", "link", + new Date(), FeedItem.UNPLAYED, feed); + items.add(item); + } + feed.setItems(items); + } + + PodDBAdapter adapter = PodDBAdapter.getInstance(); + adapter.open(); + adapter.setCompleteFeed(feed); + adapter.close(); + return feed; + } + } 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 42f4413d3..1e13bd5c3 100644 --- a/app/src/androidTest/java/de/test/antennapod/storage/DBWriterTest.java +++ b/app/src/androidTest/java/de/test/antennapod/storage/DBWriterTest.java @@ -4,12 +4,15 @@ import android.content.Context; import android.content.SharedPreferences; import android.database.Cursor; import android.preference.PreferenceManager; +import android.util.Log; + import androidx.test.InstrumentationRegistry; -import androidx.test.filters.LargeTest; import androidx.test.filters.MediumTest; -import android.util.Log; import org.awaitility.Awaitility; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; import java.io.File; import java.io.IOException; @@ -29,9 +32,7 @@ import de.danoeh.antennapod.core.storage.DBReader; import de.danoeh.antennapod.core.storage.DBWriter; import de.danoeh.antennapod.core.storage.PodDBAdapter; import de.danoeh.antennapod.core.util.Consumer; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import de.danoeh.antennapod.core.util.FeedItemUtil; import static androidx.test.InstrumentationRegistry.getInstrumentation; import static org.junit.Assert.assertEquals; @@ -475,11 +476,12 @@ public class DBWriterTest { assertFalse(OLD_DATE == media.getPlaybackCompletionDate().getTime()); } - private Feed queueTestSetupMultipleItems(final int NUM_ITEMS) throws InterruptedException, ExecutionException, TimeoutException { + private Feed queueTestSetupMultipleItems(final int numItems) throws InterruptedException, ExecutionException, TimeoutException { final Context context = getInstrumentation().getTargetContext(); + UserPreferences.setEnqueueLocation(UserPreferences.EnqueueLocation.BACK); Feed feed = new Feed("url", null, "title"); feed.setItems(new ArrayList<>()); - for (int i = 0; i < NUM_ITEMS; i++) { + for (int i = 0; i < numItems; i++) { FeedItem item = new FeedItem(0, "title " + i, "id " + i, "link " + i, new Date(), FeedItem.PLAYED, feed); feed.getItems().add(item); } @@ -573,12 +575,16 @@ public class DBWriterTest { Cursor cursor = adapter.getQueueIDCursor(); assertTrue(cursor.moveToFirst()); assertTrue(cursor.getCount() == NUM_ITEMS); + List<Long> expectedIds = FeedItemUtil.getIdList(feed.getItems()); + List<Long> actualIds = new ArrayList<>(); for (int i = 0; i < NUM_ITEMS; i++) { assertTrue(cursor.moveToPosition(i)); - assertTrue(cursor.getLong(0) == feed.getItems().get(i).getId()); + actualIds.add(cursor.getLong(0)); } cursor.close(); adapter.close(); + assertEquals("Bulk add to queue: result order should be the same as the order given", + expectedIds, actualIds); } @Test diff --git a/app/src/androidTest/java/de/test/antennapod/ui/PreferencesTest.java b/app/src/androidTest/java/de/test/antennapod/ui/PreferencesTest.java index 65bc7d745..f22e4b426 100644 --- a/app/src/androidTest/java/de/test/antennapod/ui/PreferencesTest.java +++ b/app/src/androidTest/java/de/test/antennapod/ui/PreferencesTest.java @@ -4,13 +4,14 @@ import android.content.Intent; import android.content.SharedPreferences; import android.content.res.Resources; import android.preference.PreferenceManager; -import androidx.test.filters.LargeTest; +import androidx.annotation.StringRes; +import androidx.test.filters.LargeTest; import androidx.test.rule.ActivityTestRule; + import com.robotium.solo.Solo; import com.robotium.solo.Timeout; -import de.test.antennapod.EspressoTestUtils; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -21,6 +22,7 @@ import java.util.concurrent.TimeUnit; import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.PreferenceActivity; import de.danoeh.antennapod.core.preferences.UserPreferences; +import de.danoeh.antennapod.core.preferences.UserPreferences.EnqueueLocation; import de.danoeh.antennapod.core.storage.APCleanupAlgorithm; import de.danoeh.antennapod.core.storage.APNullCleanupAlgorithm; import de.danoeh.antennapod.core.storage.APQueueCleanupAlgorithm; @@ -28,6 +30,7 @@ import de.danoeh.antennapod.core.storage.EpisodeCleanupAlgorithm; import de.danoeh.antennapod.fragment.EpisodesFragment; import de.danoeh.antennapod.fragment.QueueFragment; import de.danoeh.antennapod.fragment.SubscriptionFragment; +import de.test.antennapod.EspressoTestUtils; import static androidx.test.InstrumentationRegistry.getInstrumentation; import static androidx.test.espresso.Espresso.onView; @@ -126,13 +129,19 @@ public class PreferencesTest { } @Test - public void testEnqueueAtFront() { + public void testEnqueueLocation() { clickPreference(R.string.playback_pref); - final boolean enqueueAtFront = UserPreferences.enqueueAtFront(); - clickPreference(R.string.pref_queueAddToFront_title); - assertTrue(solo.waitForCondition(() -> enqueueAtFront != UserPreferences.enqueueAtFront(), Timeout.getLargeTimeout())); - clickPreference(R.string.pref_queueAddToFront_title); - assertTrue(solo.waitForCondition(() -> enqueueAtFront == UserPreferences.enqueueAtFront(), Timeout.getLargeTimeout())); + doTestEnqueueLocation(R.string.enqueue_location_after_current, EnqueueLocation.AFTER_CURRENTLY_PLAYING); + doTestEnqueueLocation(R.string.enqueue_location_front, EnqueueLocation.FRONT); + doTestEnqueueLocation(R.string.enqueue_location_back, EnqueueLocation.BACK); + } + + private void doTestEnqueueLocation(@StringRes int optionResId, EnqueueLocation expected) { + clickPreference(R.string.pref_enqueue_location_title); + onView(withText(optionResId)).perform(click()); + assertTrue(solo.waitForCondition( + () -> expected == UserPreferences.getEnqueueLocation(), + Timeout.getLargeTimeout())); } @Test diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 8224407a2..ba5f84a14 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -237,6 +237,7 @@ <activity android:name=".activity.OnlineFeedViewActivity" android:configChanges="orientation|screenSize" + android:theme="@style/Theme.AntennaPod.Dark.Translucent" android:label="@string/add_feed_label"> <meta-data android:name="android.support.PARENT_ACTIVITY" 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 5102095a7..10a315a9b 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java @@ -10,7 +10,6 @@ import android.os.Bundle; import androidx.annotation.NonNull; import androidx.annotation.UiThread; import androidx.core.app.NavUtils; -import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; import android.text.TextUtils; @@ -22,10 +21,8 @@ import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.ImageView; -import android.widget.LinearLayout; import android.widget.ListView; import android.widget.ProgressBar; -import android.widget.RelativeLayout; import android.widget.Spinner; import android.widget.TextView; @@ -98,10 +95,12 @@ public class OnlineFeedViewActivity extends AppCompatActivity { private Downloader downloader; private boolean isPaused; + private boolean didPressSubscribe = false; private Dialog dialog; - + private ListView listView; private Button subscribeButton; + private ProgressBar progressBar; private Disposable download; private Disposable parser; @@ -109,18 +108,12 @@ public class OnlineFeedViewActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { - setTheme(UserPreferences.getTheme()); + setTheme(UserPreferences.getTranslucentTheme()); super.onCreate(savedInstanceState); - ActionBar actionBar = getSupportActionBar(); - if (actionBar != null) { - actionBar.setDisplayHomeAsUpEnabled(true); - } - - if (actionBar != null && getIntent() != null && getIntent().hasExtra(ARG_TITLE)) { - actionBar.setTitle(getIntent().getStringExtra(ARG_TITLE)); - } - StorageUtils.checkStorageAvailability(this); + setContentView(R.layout.onlinefeedview_activity); + listView = findViewById(R.id.listview); + progressBar = findViewById(R.id.progressBar); String feedUrl = null; if (getIntent().hasExtra(ARG_FEEDURL)) { @@ -129,9 +122,6 @@ public class OnlineFeedViewActivity extends AppCompatActivity { || TextUtils.equals(getIntent().getAction(), Intent.ACTION_VIEW)) { feedUrl = TextUtils.equals(getIntent().getAction(), Intent.ACTION_SEND) ? getIntent().getStringExtra(Intent.EXTRA_TEXT) : getIntent().getDataString(); - if (actionBar != null) { - actionBar.setTitle(R.string.add_feed_label); - } } if (feedUrl == null) { @@ -156,19 +146,8 @@ public class OnlineFeedViewActivity extends AppCompatActivity { * Displays a progress indicator. */ private void setLoadingLayout() { - RelativeLayout rl = new RelativeLayout(this); - RelativeLayout.LayoutParams rlLayoutParams = new RelativeLayout.LayoutParams( - LinearLayout.LayoutParams.MATCH_PARENT, - LinearLayout.LayoutParams.MATCH_PARENT); - - ProgressBar pb = new ProgressBar(this); - pb.setIndeterminate(true); - RelativeLayout.LayoutParams pbLayoutParams = new RelativeLayout.LayoutParams( - LinearLayout.LayoutParams.WRAP_CONTENT, - LinearLayout.LayoutParams.WRAP_CONTENT); - pbLayoutParams.addRule(RelativeLayout.CENTER_IN_PARENT); - rl.addView(pb, pbLayoutParams); - addContentView(rl, rlLayoutParams); + progressBar.setVisibility(View.VISIBLE); + listView.setVisibility(View.GONE); } @Override @@ -222,6 +201,12 @@ public class OnlineFeedViewActivity extends AppCompatActivity { } @Override + public void finish() { + super.finish(); + overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out); + } + + @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: @@ -291,7 +276,7 @@ public class OnlineFeedViewActivity extends AppCompatActivity { .subscribe( feeds -> { OnlineFeedViewActivity.this.feeds = feeds; - setSubscribeButtonState(feed); + handleUpdatedFeedStatus(feed); }, error -> Log.e(TAG, Log.getStackTraceString(error)) ); } @@ -299,7 +284,7 @@ public class OnlineFeedViewActivity extends AppCompatActivity { @Subscribe(threadMode = ThreadMode.MAIN) public void onEventMainThread(DownloadEvent event) { Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]"); - setSubscribeButtonState(feed); + handleUpdatedFeedStatus(feed); } private void parseFeed() { @@ -374,11 +359,10 @@ public class OnlineFeedViewActivity extends AppCompatActivity { * This method is executed on the GUI thread. */ private void showFeedInformation(final Feed feed, Map<String, String> alternateFeedUrls) { - setContentView(R.layout.listview_activity); - + progressBar.setVisibility(View.GONE); + listView.setVisibility(View.VISIBLE); this.feed = feed; this.selectedDownloadUrl = feed.getDownload_url(); - ListView listView = findViewById(R.id.listview); listView.setSelector(android.R.color.transparent); LayoutInflater inflater = LayoutInflater.from(this); View header = inflater.inflate(R.layout.onlinefeedview_header, listView, false); @@ -424,11 +408,8 @@ public class OnlineFeedViewActivity extends AppCompatActivity { description.setText(feed.getDescription()); subscribeButton.setOnClickListener(v -> { - if(feedInFeedlist(feed)) { - // feed.getId() is always 0, we have to retrieve the id from the feed list from - // the database - Intent intent = MainActivity.getIntentToOpenFeed(this, getFeedId(feed)); - startActivity(intent); + if (feedInFeedlist(feed)) { + openFeed(); } else { Feed f = new Feed(selectedDownloadUrl, null, feed.getTitle()); f.setPreferences(feed.getPreferences()); @@ -439,7 +420,8 @@ public class OnlineFeedViewActivity extends AppCompatActivity { Log.e(TAG, Log.getStackTraceString(e)); DownloadRequestErrorDialogCreator.newRequestErrorDialog(this, e.getMessage()); } - setSubscribeButtonState(feed); + didPressSubscribe = true; + handleUpdatedFeedStatus(feed); } }); @@ -485,10 +467,18 @@ public class OnlineFeedViewActivity extends AppCompatActivity { } }); } - setSubscribeButtonState(feed); + handleUpdatedFeedStatus(feed); } - private void setSubscribeButtonState(Feed feed) { + private void openFeed() { + // feed.getId() is always 0, we have to retrieve the id from the feed list from + // the database + Intent intent = MainActivity.getIntentToOpenFeed(this, getFeedId(feed)); + finish(); + startActivity(intent); + } + + private void handleUpdatedFeedStatus(Feed feed) { if (subscribeButton != null && feed != null) { if (DownloadRequester.getInstance().isDownloadingFile(feed.getDownload_url())) { subscribeButton.setEnabled(false); @@ -496,6 +486,9 @@ public class OnlineFeedViewActivity extends AppCompatActivity { } else if (feedInFeedlist(feed)) { subscribeButton.setEnabled(true); subscribeButton.setText(R.string.open_podcast); + if (didPressSubscribe) { + openFeed(); + } } else { subscribeButton.setEnabled(true); subscribeButton.setText(R.string.subscribe_label); diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java index 5282a6bb2..f73735658 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java @@ -54,7 +54,8 @@ public class FavoriteEpisodesFragment extends EpisodesListFragment { emptyView.setTitle(R.string.no_fav_episodes_head_label); emptyView.setMessage(R.string.no_fav_episodes_label); - ItemTouchHelper.SimpleCallback simpleItemTouchCallback = new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) { + ItemTouchHelper.SimpleCallback simpleItemTouchCallback = new ItemTouchHelper.SimpleCallback(0, + ItemTouchHelper.LEFT) { @Override public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) { return false; diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java index 5dbb84bc7..2bfdd040b 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java @@ -54,7 +54,8 @@ public class NewEpisodesFragment extends EpisodesListFragment { emptyView.setTitle(R.string.no_new_episodes_head_label); emptyView.setMessage(R.string.no_new_episodes_label); - ItemTouchHelper.SimpleCallback simpleItemTouchCallback = new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) { + ItemTouchHelper.SimpleCallback simpleItemTouchCallback = new ItemTouchHelper.SimpleCallback(0, + ItemTouchHelper.RIGHT) { @Override public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) { return false; diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java index 8f54e0574..ce1276175 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java @@ -503,7 +503,8 @@ public class QueueFragment extends Fragment { registerForContextMenu(recyclerView); itemTouchHelper = new ItemTouchHelper( - new ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP | ItemTouchHelper.DOWN, ItemTouchHelper.RIGHT) { + new ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP | ItemTouchHelper.DOWN, + ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) { // Position tracking whilst dragging int dragFrom = -1; diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/PlaybackPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/PlaybackPreferencesFragment.java index 1795dfc29..5d9af14bd 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/PlaybackPreferencesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/PlaybackPreferencesFragment.java @@ -4,8 +4,15 @@ import android.app.Activity; import android.content.res.Resources; import android.os.Build; import android.os.Bundle; + +import androidx.annotation.NonNull; +import androidx.collection.ArrayMap; import androidx.preference.ListPreference; +import androidx.preference.Preference; import androidx.preference.PreferenceFragmentCompat; + +import java.util.Map; + import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.MediaplayerActivity; import de.danoeh.antennapod.activity.PreferenceActivity; @@ -63,6 +70,43 @@ public class PlaybackPreferencesFragment extends PreferenceFragmentCompat { behaviour.setEntries(R.array.video_background_behavior_options_without_pip); behaviour.setEntryValues(R.array.video_background_behavior_values_without_pip); } + + buildEnqueueLocationPreference(); + } + + private void buildEnqueueLocationPreference() { + final Resources res = requireActivity().getResources(); + final Map<String, String> options = new ArrayMap<>(); + { + String[] keys = res.getStringArray(R.array.enqueue_location_values); + String[] values = res.getStringArray(R.array.enqueue_location_options); + for (int i = 0; i < keys.length; i++) { + options.put(keys[i], values[i]); + } + } + + ListPreference pref = requirePreference(UserPreferences.PREF_ENQUEUE_LOCATION); + pref.setSummary(res.getString(R.string.pref_enqueue_location_sum, options.get(pref.getValue()))); + + pref.setOnPreferenceChangeListener((preference, newValue) -> { + if (!(newValue instanceof String)) { + return false; + } + String newValStr = (String)newValue; + pref.setSummary(res.getString(R.string.pref_enqueue_location_sum, options.get(newValStr))); + return true; + }); + } + + @NonNull + private <T extends Preference> T requirePreference(@NonNull CharSequence key) { + // Possibly put it to a common method in abstract base class + T result = findPreference(key); + if (result == null) { + throw new IllegalArgumentException("Preference with key '" + key + "' is not found"); + + } + return result; } private void buildSmartMarkAsPlayedPreference() { diff --git a/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceUpgrader.java b/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceUpgrader.java index 767f71bb6..455038960 100644 --- a/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceUpgrader.java +++ b/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceUpgrader.java @@ -7,6 +7,7 @@ import android.preference.PreferenceManager; import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; import de.danoeh.antennapod.core.preferences.UserPreferences; +import de.danoeh.antennapod.core.preferences.UserPreferences.EnqueueLocation; import de.danoeh.antennapod.core.util.download.AutoUpdateManager; import de.danoeh.antennapod.core.util.gui.NotificationUtils; @@ -75,6 +76,13 @@ public class PreferenceUpgrader { } UserPreferences.setQueueLocked(false); + + if (!prefs.contains(UserPreferences.PREF_ENQUEUE_LOCATION)) { + final String keyOldPrefEnqueueFront = "prefQueueAddToFront"; + boolean enqueueAtFront = prefs.getBoolean(keyOldPrefEnqueueFront, false); + EnqueueLocation enqueueLocation = enqueueAtFront ? EnqueueLocation.FRONT : EnqueueLocation.BACK; + UserPreferences.setEnqueueLocation(enqueueLocation); + } } } } diff --git a/app/src/main/res/layout/onlinefeedview_activity.xml b/app/src/main/res/layout/onlinefeedview_activity.xml new file mode 100644 index 000000000..b55993fcf --- /dev/null +++ b/app/src/main/res/layout/onlinefeedview_activity.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <androidx.cardview.widget.CardView + android:layout_width="match_parent" + android:layout_height="match_parent" + app:cardCornerRadius="4dp" + android:layout_margin="16dp" + android:elevation="16dp"> + + <FrameLayout + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <ProgressBar + style="?android:attr/progressBarStyle" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:id="@+id/progressBar" + android:layout_gravity="center"/> + <ListView + android:id="@+id/listview" + android:layout_width="match_parent" + android:layout_height="match_parent"/> + + </FrameLayout> + </androidx.cardview.widget.CardView> +</LinearLayout>
\ No newline at end of file diff --git a/app/src/main/res/xml/preferences_playback.xml b/app/src/main/res/xml/preferences_playback.xml index 2334e1b1c..b01105376 100644 --- a/app/src/main/res/xml/preferences_playback.xml +++ b/app/src/main/res/xml/preferences_playback.xml @@ -90,12 +90,13 @@ android:key="prefEnqueueDownloaded" android:summary="@string/pref_enqueue_downloaded_summary" android:title="@string/pref_enqueue_downloaded_title" /> - <SwitchPreference - android:defaultValue="false" - android:enabled="true" - android:key="prefQueueAddToFront" - android:summary="@string/pref_queueAddToFront_sum" - android:title="@string/pref_queueAddToFront_title"/> + <ListPreference + android:defaultValue="BACK" + android:entries="@array/enqueue_location_options" + android:entryValues="@array/enqueue_location_values" + android:key="prefEnqueueLocation" + android:title="@string/pref_enqueue_location_title" + app:useStockLayout="true"/> <SwitchPreference android:defaultValue="true" android:enabled="true" |