diff options
Diffstat (limited to 'app')
164 files changed, 1917 insertions, 1293 deletions
diff --git a/app/build.gradle b/app/build.gradle index 3996d7ba5..5f70d285f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -21,7 +21,7 @@ android { versionCode 1070396 versionName "1.7.3b" testApplicationId "de.test.antennapod" - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" generatedDensities = [] javaCompileOptions { @@ -131,18 +131,14 @@ dependencies { } else { System.out.println("app: free build hack, skipping some dependencies") } - implementation "com.android.support:support-v4:$supportVersion" - implementation "com.android.support:appcompat-v7:$supportVersion" - implementation "com.android.support:design:$supportVersion" - implementation "com.android.support:preference-v14:$supportVersion" - implementation "com.android.support:gridlayout-v7:$supportVersion" - implementation "com.android.support:recyclerview-v7:$supportVersion" - compileOnly 'com.google.android.wearable:wearable:2.2.0' - - // ViewModel and LiveData - implementation "android.arch.lifecycle:extensions:$lifecycle_version" - annotationProcessor "android.arch.lifecycle:compiler:$lifecycle_version" - + implementation "androidx.appcompat:appcompat:1.1.0" + implementation "androidx.preference:preference:1.1.0" + implementation "androidx.gridlayout:gridlayout:1.0.0" + implementation "androidx.recyclerview:recyclerview:1.0.0" + implementation "androidx.media:media:1.1.0" + implementation "com.google.android.material:material:1.0.0" + annotationProcessor "androidx.annotation:annotation:1.1.0" + compileOnly "com.google.android.wearable:wearable:$wearableSupportVersion" implementation "org.apache.commons:commons-lang3:$commonslangVersion" implementation "commons-io:commons-io:$commonsioVersion" implementation "org.jsoup:jsoup:$jsoupVersion" @@ -162,26 +158,21 @@ dependencies { transitive = true } implementation "com.yqritc:recyclerview-flexibledivider:$recyclerviewFlexibledividerVersion" - implementation("com.githang:viewpagerindicator:2.5.1@aar") { - exclude module: "support-v4" - } - + implementation "com.githang:viewpagerindicator:2.5.1@aar" implementation "com.github.shts:TriangleLabelView:$triangleLabelViewVersion" - implementation 'com.leinardi.android:speed-dial:1.0.2' // 1.0.2 uses support 27.1.1 ; newer versions use 28.0.0; - + implementation 'com.leinardi.android:speed-dial:3.0.0' implementation "com.github.AntennaPod:AntennaPod-AudioPlayer:$audioPlayerVersion" - implementation 'com.github.mfietz:fyydlin:v0.4.2' implementation 'com.github.ByteHamster:SearchPreference:v1.3.0' androidTestImplementation "org.awaitility:awaitility:$awaitilityVersion" androidTestImplementation 'com.nanohttpd:nanohttpd-webserver:2.1.1' androidTestImplementation "com.jayway.android.robotium:robotium-solo:$robotiumSoloVersion" - androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' - androidTestImplementation 'com.android.support.test.espresso:espresso-contrib:3.0.2' - androidTestImplementation 'com.android.support.test.espresso:espresso-intents:3.0.2' - androidTestImplementation 'com.android.support.test:runner:1.0.2' - androidTestImplementation 'com.android.support.test:rules:1.0.2' + androidTestImplementation "androidx.test.espresso:espresso-core:$espressoVersion" + androidTestImplementation "androidx.test.espresso:espresso-contrib:$espressoVersion" + androidTestImplementation "androidx.test.espresso:espresso-intents:$espressoVersion" + androidTestImplementation 'androidx.test:runner:1.2.0' + androidTestImplementation 'androidx.test:rules:1.2.0' } if (project.hasProperty("antennaPodServiceAccountEmail")) { @@ -193,20 +184,14 @@ if (project.hasProperty("antennaPodServiceAccountEmail")) { } } -// about.html is templatized so that we can automatically insert -// our version string in to it at build time. -task filterAbout { - inputs.files files(["src/main/templates/about.html", - "src/main/AndroidManifest.xml"]) - outputs.file "src/main/assets/about.html" -} doLast { - copy { - from "src/main/templates/about.html" - into "src/main/assets" - filter(ReplaceTokens, tokens: [versionname: android.defaultConfig.versionName, - commit : "git rev-parse --short HEAD".execute().text, - year : new Date().format('yyyy')]) - } +task filterAbout(type: Copy) { + from "src/main/templates/about.html" + into "src/main/assets" + filter(ReplaceTokens, tokens: [ + versionname: android.defaultConfig.versionName, + commit : "git rev-parse --short HEAD".execute().text, + year : new Date().format('yyyy')]) + outputs.upToDateWhen { false } } task copyTextFiles(type: Copy) { @@ -216,6 +201,7 @@ task copyTextFiles(type: Copy) { rename { String fileName -> fileName + ".txt" } + outputs.upToDateWhen { false } } preBuild.dependsOn filterAbout, copyTextFiles diff --git a/app/proguard.cfg b/app/proguard.cfg index 958048ef3..5309e833d 100644 --- a/app/proguard.cfg +++ b/app/proguard.cfg @@ -66,13 +66,13 @@ # for retrolambda -dontwarn java.lang.invoke.* --keep class android.support.v4.** { *; } --keep interface android.support.v4.** { *; } --keep class !android.support.v7.internal.view.menu.**,android.support.v7.** {*;} --keep interface android.support.v7.** { *; } --keep class com.google.android.wearable.** { *; } --dontwarn android.support.v4.** --dontwarn android.support.v7.** +-dontwarn com.google.android.material.** +-keep class com.google.android.material.** { *; } + +-dontwarn androidx.** +-keep class androidx.** { *; } +-keep interface androidx.** { *; } + -dontwarn com.google.android.wearable.** -keep class org.apache.commons.** { *; } diff --git a/app/src/androidTest/java/de/danoeh/antennapod/core/service/download/StubDownloader.java b/app/src/androidTest/java/de/danoeh/antennapod/core/service/download/StubDownloader.java new file mode 100644 index 000000000..e7fe079a6 --- /dev/null +++ b/app/src/androidTest/java/de/danoeh/antennapod/core/service/download/StubDownloader.java @@ -0,0 +1,52 @@ +package de.danoeh.antennapod.core.service.download; + +import androidx.annotation.NonNull; + +import de.danoeh.antennapod.core.util.Consumer; + +public class StubDownloader extends Downloader { + + private final long downloadTime; + + @NonNull + private final Consumer<DownloadStatus> onDownloadComplete; + + public StubDownloader(@NonNull DownloadRequest request, long downloadTime, @NonNull Consumer<DownloadStatus> onDownloadComplete) { + super(request); + this.downloadTime = downloadTime; + this.onDownloadComplete = onDownloadComplete; + } + + @Override + protected void download() { + try { + Thread.sleep(downloadTime); + } catch (Throwable t) { + t.printStackTrace(); + } + onDownloadComplete.accept(result); + } + + @NonNull + @Override + public DownloadRequest getDownloadRequest() { + return super.getDownloadRequest(); + } + + @NonNull + @Override + public DownloadStatus getResult() { + return super.getResult(); + } + + @Override + public boolean isFinished() { + return super.isFinished(); + } + + @Override + public void cancel() { + super.cancel(); + result.setCancelled(); + } +} diff --git a/app/src/androidTest/java/de/test/antennapod/EspressoTestUtils.java b/app/src/androidTest/java/de/test/antennapod/EspressoTestUtils.java index 9e86275fc..f895b4d5e 100644 --- a/app/src/androidTest/java/de/test/antennapod/EspressoTestUtils.java +++ b/app/src/androidTest/java/de/test/antennapod/EspressoTestUtils.java @@ -1,33 +1,31 @@ package de.test.antennapod; import android.content.Context; -import android.content.SharedPreferences; -import android.support.annotation.StringRes; -import android.support.test.InstrumentationRegistry; -import android.support.test.espresso.PerformException; -import android.support.test.espresso.UiController; -import android.support.test.espresso.ViewAction; -import android.support.test.espresso.contrib.DrawerActions; -import android.support.test.espresso.contrib.RecyclerViewActions; -import android.support.test.espresso.util.HumanReadables; -import android.support.test.espresso.util.TreeIterables; +import androidx.annotation.StringRes; +import androidx.test.InstrumentationRegistry; +import androidx.test.espresso.PerformException; +import androidx.test.espresso.UiController; +import androidx.test.espresso.ViewAction; +import androidx.test.espresso.contrib.DrawerActions; +import androidx.test.espresso.contrib.RecyclerViewActions; +import androidx.test.espresso.util.HumanReadables; +import androidx.test.espresso.util.TreeIterables; import android.view.View; import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.MainActivity; import de.danoeh.antennapod.core.storage.PodDBAdapter; import de.danoeh.antennapod.dialog.RatingDialog; -import de.danoeh.antennapod.fragment.QueueFragment; import org.hamcrest.Matcher; import java.io.File; import java.util.concurrent.TimeoutException; -import static android.support.test.espresso.Espresso.onView; -import static android.support.test.espresso.action.ViewActions.click; -import static android.support.test.espresso.matcher.ViewMatchers.hasDescendant; -import static android.support.test.espresso.matcher.ViewMatchers.isRoot; -import static android.support.test.espresso.matcher.ViewMatchers.withId; -import static android.support.test.espresso.matcher.ViewMatchers.withText; +import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.action.ViewActions.click; +import static androidx.test.espresso.matcher.ViewMatchers.hasDescendant; +import static androidx.test.espresso.matcher.ViewMatchers.isRoot; +import static androidx.test.espresso.matcher.ViewMatchers.withId; +import static androidx.test.espresso.matcher.ViewMatchers.withText; public class EspressoTestUtils { /** @@ -115,7 +113,7 @@ public class EspressoTestUtils { } public static void clickPreference(@StringRes int title) { - onView(withId(R.id.list)).perform( + onView(withId(R.id.recycler_view)).perform( RecyclerViewActions.actionOnItem(hasDescendant(withText(title)), click())); } diff --git a/app/src/androidTest/java/de/test/antennapod/entities/ExternalMediaTest.java b/app/src/androidTest/java/de/test/antennapod/entities/ExternalMediaTest.java index e8a87ecf1..b3c79367f 100644 --- a/app/src/androidTest/java/de/test/antennapod/entities/ExternalMediaTest.java +++ b/app/src/androidTest/java/de/test/antennapod/entities/ExternalMediaTest.java @@ -4,9 +4,9 @@ import android.annotation.SuppressLint; import android.content.SharedPreferences; import android.preference.PreferenceManager; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.LargeTest; -import android.support.test.filters.SmallTest; +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.LargeTest; +import androidx.test.filters.SmallTest; import de.danoeh.antennapod.core.feed.MediaType; import de.danoeh.antennapod.core.util.playback.ExternalMedia; import org.junit.After; diff --git a/app/src/androidTest/java/de/test/antennapod/feed/FeedFilterTest.java b/app/src/androidTest/java/de/test/antennapod/feed/FeedFilterTest.java index 8cd9b0fa1..4b81a4f2b 100644 --- a/app/src/androidTest/java/de/test/antennapod/feed/FeedFilterTest.java +++ b/app/src/androidTest/java/de/test/antennapod/feed/FeedFilterTest.java @@ -1,6 +1,6 @@ package de.test.antennapod.feed; -import android.support.test.filters.SmallTest; +import androidx.test.filters.SmallTest; import de.danoeh.antennapod.core.feed.FeedFilter; import de.danoeh.antennapod.core.feed.FeedItem; import org.junit.Test; diff --git a/app/src/androidTest/java/de/test/antennapod/feed/FeedItemTest.java b/app/src/androidTest/java/de/test/antennapod/feed/FeedItemTest.java index 9779b32a5..0b9a67d0a 100644 --- a/app/src/androidTest/java/de/test/antennapod/feed/FeedItemTest.java +++ b/app/src/androidTest/java/de/test/antennapod/feed/FeedItemTest.java @@ -1,6 +1,6 @@ package de.test.antennapod.feed; -import android.support.test.filters.SmallTest; +import androidx.test.filters.SmallTest; import de.danoeh.antennapod.core.feed.FeedItem; import org.junit.Test; diff --git a/app/src/androidTest/java/de/test/antennapod/gpodnet/GPodnetServiceTest.java b/app/src/androidTest/java/de/test/antennapod/gpodnet/GPodnetServiceTest.java index 91e31e73c..cd3847f17 100644 --- a/app/src/androidTest/java/de/test/antennapod/gpodnet/GPodnetServiceTest.java +++ b/app/src/androidTest/java/de/test/antennapod/gpodnet/GPodnetServiceTest.java @@ -4,7 +4,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import android.support.test.runner.AndroidJUnit4; +import androidx.test.runner.AndroidJUnit4; import de.danoeh.antennapod.core.gpoddernet.GpodnetService; import de.danoeh.antennapod.core.gpoddernet.GpodnetServiceException; import de.danoeh.antennapod.core.gpoddernet.model.GpodnetDevice; 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 dfb78d5a9..4f6bf0c1f 100644 --- a/app/src/androidTest/java/de/test/antennapod/handler/FeedHandlerTest.java +++ b/app/src/androidTest/java/de/test/antennapod/handler/FeedHandlerTest.java @@ -1,8 +1,8 @@ package de.test.antennapod.handler; import android.content.Context; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.SmallTest; +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.SmallTest; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -12,7 +12,6 @@ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; -import java.nio.file.Files; import java.util.ArrayList; import java.util.Date; import java.util.List; diff --git a/app/src/androidTest/java/de/test/antennapod/service/download/DownloadServiceTest.java b/app/src/androidTest/java/de/test/antennapod/service/download/DownloadServiceTest.java new file mode 100644 index 000000000..cb099cc85 --- /dev/null +++ b/app/src/androidTest/java/de/test/antennapod/service/download/DownloadServiceTest.java @@ -0,0 +1,127 @@ +package de.test.antennapod.service.download; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import org.awaitility.Awaitility; +import org.awaitility.core.ConditionTimeoutException; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import de.danoeh.antennapod.core.feed.Feed; +import de.danoeh.antennapod.core.feed.FeedItem; +import de.danoeh.antennapod.core.feed.FeedMedia; +import de.danoeh.antennapod.core.service.download.DownloadRequest; +import de.danoeh.antennapod.core.service.download.DownloadService; +import de.danoeh.antennapod.core.service.download.DownloadStatus; +import de.danoeh.antennapod.core.service.download.Downloader; +import de.danoeh.antennapod.core.service.download.StubDownloader; +import de.danoeh.antennapod.core.storage.DBReader; +import de.danoeh.antennapod.core.storage.DBWriter; +import de.danoeh.antennapod.core.storage.DownloadRequester; +import de.danoeh.antennapod.core.util.Consumer; + +import static de.test.antennapod.util.event.FeedItemEventListener.withFeedItemEventListener; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +/** + * @see HttpDownloaderTest for the test of actual download (and saving the file) + */ +@RunWith(AndroidJUnit4.class) +public class DownloadServiceTest { + + private CountDownLatch latch = null; + private Feed testFeed = null; + private FeedMedia testMedia11 = null; + + private DownloadService.DownloaderFactory origFactory = null; + + @Before + public void setUp() throws Exception { + origFactory = DownloadService.getDownloaderFactory(); + testFeed = setUpTestFeeds(); + testMedia11 = testFeed.getItemAtIndex(0).getMedia(); + } + + private Feed setUpTestFeeds() throws Exception { + Feed feed = new Feed("url", null, "Test Feed title 1"); + List<FeedItem> items = new ArrayList<>(); + feed.setItems(items); + FeedItem item1 = new FeedItem(0, "Item 1-1", "Item 1-1", "url", new Date(), FeedItem.NEW, feed); + items.add(item1); + FeedMedia media1 = new FeedMedia(0, item1, 123, 1, 1, "audio/mp3", null, "http://example.com/episode.mp3", false, null, 0, 0); + item1.setMedia(media1); + + DBWriter.setFeedItem(item1).get(); + return feed; + } + + + @After + public void tearDown() throws Exception { + DownloadService.setDownloaderFactory(origFactory); + } + + @Test + public void testEventsGeneratedCaseMediaDownloadSuccess() throws Exception { + // create a stub download that returns successful + // + // OPEN: Ideally, I'd like the download time long enough so that multiple in-progress DownloadEvents + // are generated (to simulate typical download), but it'll make download time quite long (1-2 seconds) + // to do so + DownloadService.setDownloaderFactory(new StubDownloaderFactory(50, downloadStatus -> { + downloadStatus.setSuccessful(); + })); + + withFeedItemEventListener(feedItemEventListener -> { + try { + assertEquals(0, feedItemEventListener.getEvents().size()); + assertFalse("The media in test should not yet been downloaded", + DBReader.getFeedMedia(testMedia11.getId()).isDownloaded()); + + DownloadRequester.getInstance().downloadMedia(InstrumentationRegistry.getTargetContext(), + testMedia11); + Awaitility.await() + .atMost(1000, TimeUnit.MILLISECONDS) + .until(() -> feedItemEventListener.getEvents().size() > 0); + assertTrue("After media download has completed, FeedMedia object in db should indicate so.", + DBReader.getFeedMedia(testMedia11.getId()).isDownloaded()); + } catch (ConditionTimeoutException cte) { + fail("The expected FeedItemEvent (for media download complete) has not been posted. " + + cte.getMessage()); + } + }); + } + + private static class StubDownloaderFactory implements DownloadService.DownloaderFactory { + private final long downloadTime; + + @NonNull + private final Consumer<DownloadStatus> onDownloadComplete; + + StubDownloaderFactory(long downloadTime, @NonNull Consumer<DownloadStatus> onDownloadComplete) { + this.downloadTime = downloadTime; + this.onDownloadComplete = onDownloadComplete; + } + + @Nullable + @Override + public Downloader create(@NonNull DownloadRequest request) { + return new StubDownloader(request, downloadTime, onDownloadComplete); + } + } + +} diff --git a/app/src/androidTest/java/de/test/antennapod/service/download/HttpDownloaderTest.java b/app/src/androidTest/java/de/test/antennapod/service/download/HttpDownloaderTest.java index 967bf431c..4530b7679 100644 --- a/app/src/androidTest/java/de/test/antennapod/service/download/HttpDownloaderTest.java +++ b/app/src/androidTest/java/de/test/antennapod/service/download/HttpDownloaderTest.java @@ -1,7 +1,7 @@ package de.test.antennapod.service.download; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.LargeTest; +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.LargeTest; import android.util.Log; import java.io.File; diff --git a/app/src/androidTest/java/de/test/antennapod/service/playback/CancelablePSMPCallback.java b/app/src/androidTest/java/de/test/antennapod/service/playback/CancelablePSMPCallback.java index 085e2c479..6bd519228 100644 --- a/app/src/androidTest/java/de/test/antennapod/service/playback/CancelablePSMPCallback.java +++ b/app/src/androidTest/java/de/test/antennapod/service/playback/CancelablePSMPCallback.java @@ -1,6 +1,6 @@ package de.test.antennapod.service.playback; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import de.danoeh.antennapod.core.feed.MediaType; import de.danoeh.antennapod.core.service.playback.PlaybackServiceMediaPlayer; import de.danoeh.antennapod.core.util.playback.Playable; diff --git a/app/src/androidTest/java/de/test/antennapod/service/playback/DefaultPSMPCallback.java b/app/src/androidTest/java/de/test/antennapod/service/playback/DefaultPSMPCallback.java index 113239908..5a16ab954 100644 --- a/app/src/androidTest/java/de/test/antennapod/service/playback/DefaultPSMPCallback.java +++ b/app/src/androidTest/java/de/test/antennapod/service/playback/DefaultPSMPCallback.java @@ -1,7 +1,7 @@ package de.test.antennapod.service.playback; -import android.support.annotation.NonNull; -import android.support.annotation.StringRes; +import androidx.annotation.NonNull; +import androidx.annotation.StringRes; import de.danoeh.antennapod.core.feed.MediaType; import de.danoeh.antennapod.core.service.playback.PlaybackServiceMediaPlayer; import de.danoeh.antennapod.core.util.playback.Playable; 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 502115cc3..c43818a73 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 @@ -2,8 +2,8 @@ package de.test.antennapod.service.playback; import android.content.Context; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.MediumTest; +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.MediumTest; import de.test.antennapod.EspressoTestUtils; import junit.framework.AssertionFailedError; @@ -32,7 +32,7 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; -import static android.support.test.InstrumentationRegistry.getInstrumentation; +import static androidx.test.InstrumentationRegistry.getInstrumentation; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; 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 9c0e90929..415ee9b68 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 @@ -1,9 +1,15 @@ package de.test.antennapod.service.playback; import android.content.Context; -import android.support.test.InstrumentationRegistry; -import android.support.test.annotation.UiThreadTest; -import android.support.test.filters.LargeTest; +import androidx.test.InstrumentationRegistry; +import androidx.test.annotation.UiThreadTest; +import androidx.test.filters.LargeTest; + +import org.awaitility.Awaitility; +import org.greenrobot.eventbus.EventBus; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; import java.util.ArrayList; import java.util.Date; @@ -15,14 +21,14 @@ import de.danoeh.antennapod.core.event.QueueEvent; import de.danoeh.antennapod.core.feed.EventDistributor; import de.danoeh.antennapod.core.feed.Feed; import de.danoeh.antennapod.core.feed.FeedItem; +import de.danoeh.antennapod.core.feed.FeedMedia; import de.danoeh.antennapod.core.service.playback.PlaybackServiceTaskManager; +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.playback.Playable; -import org.greenrobot.eventbus.EventBus; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import static de.test.antennapod.util.event.FeedItemEventListener.withFeedItemEventListener; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; @@ -124,6 +130,43 @@ public class PlaybackServiceTaskManagerTest { } @Test + public void testQueueUpdatedUponDownloadComplete() throws Exception { + final Context c = InstrumentationRegistry.getInstrumentation().getTargetContext(); + { // Setup test data + List<FeedItem> queue = writeTestQueue("a"); + FeedItem item = DBReader.getFeedItem(queue.get(0).getId()); + FeedMedia media = new FeedMedia(item, "http://example.com/episode.mp3", 12345, "audio/mp3"); + item.setMedia(media); + DBWriter.setFeedMedia(media).get(); + DBWriter.setFeedItem(item).get(); + } + + PlaybackServiceTaskManager pstm = new PlaybackServiceTaskManager(c, defaultPSTM); + final FeedItem testItem = pstm.getQueue().get(0); + assertFalse("The item should not yet be downloaded", testItem.getMedia().isDownloaded()); + + withFeedItemEventListener( feedItemEventListener -> { + // simulate download complete (in DownloadService.MediaHandlerThread) + FeedItem item = DBReader.getFeedItem(testItem.getId()); + item.getMedia().setDownloaded(true); + item.getMedia().setFile_url("file://123"); + item.setAutoDownload(false); + DBWriter.setFeedMedia(item.getMedia()).get(); + DBWriter.setFeedItem(item).get(); + + Awaitility.await() + .atMost(1000, TimeUnit.MILLISECONDS) + .until(() -> feedItemEventListener.getEvents().size() > 0); + + final FeedItem itemUpdated = pstm.getQueue().get(0); + assertTrue("media.isDownloaded() should be true - The queue in PlaybackService should be updated after download is completed", + itemUpdated.getMedia().isDownloaded()); + }); + + pstm.shutdown(); + } + + @Test public void testStartPositionSaver() throws InterruptedException { final Context c = InstrumentationRegistry.getInstrumentation().getTargetContext(); final int NUM_COUNTDOWNS = 2; 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 e78894e59..1acb96d01 100644 --- a/app/src/androidTest/java/de/test/antennapod/storage/DBCleanupTests.java +++ b/app/src/androidTest/java/de/test/antennapod/storage/DBCleanupTests.java @@ -10,9 +10,9 @@ import java.util.ArrayList; import java.util.Date; import java.util.List; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.LargeTest; -import android.support.test.filters.SmallTest; +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; 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 fe5091eb9..24cc80061 100644 --- a/app/src/androidTest/java/de/test/antennapod/storage/DBNullCleanupAlgorithmTest.java +++ b/app/src/androidTest/java/de/test/antennapod/storage/DBNullCleanupAlgorithmTest.java @@ -10,9 +10,9 @@ import java.util.ArrayList; import java.util.Date; import java.util.List; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.LargeTest; -import android.support.test.filters.SmallTest; +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; 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 3320aa545..de810c701 100644 --- a/app/src/androidTest/java/de/test/antennapod/storage/DBQueueCleanupAlgorithmTest.java +++ b/app/src/androidTest/java/de/test/antennapod/storage/DBQueueCleanupAlgorithmTest.java @@ -5,7 +5,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; -import android.support.test.filters.SmallTest; +import androidx.test.filters.SmallTest; import de.danoeh.antennapod.core.feed.Feed; import de.danoeh.antennapod.core.feed.FeedItem; import de.danoeh.antennapod.core.preferences.UserPreferences; 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 d99a409d3..647ab911f 100644 --- a/app/src/androidTest/java/de/test/antennapod/storage/DBReaderTest.java +++ b/app/src/androidTest/java/de/test/antennapod/storage/DBReaderTest.java @@ -7,9 +7,9 @@ import java.util.Date; import java.util.List; import java.util.Random; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.LargeTest; -import android.support.test.filters.SmallTest; +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; 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 6af12315c..55ea16f13 100644 --- a/app/src/androidTest/java/de/test/antennapod/storage/DBTasksTest.java +++ b/app/src/androidTest/java/de/test/antennapod/storage/DBTasksTest.java @@ -7,9 +7,9 @@ import java.util.Collections; import java.util.Date; import java.util.List; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.LargeTest; -import android.support.test.filters.SmallTest; +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; 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 7663bb3c9..42f4413d3 100644 --- a/app/src/androidTest/java/de/test/antennapod/storage/DBWriterTest.java +++ b/app/src/androidTest/java/de/test/antennapod/storage/DBWriterTest.java @@ -4,9 +4,9 @@ import android.content.Context; import android.content.SharedPreferences; import android.database.Cursor; import android.preference.PreferenceManager; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.LargeTest; -import android.support.test.filters.MediumTest; +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.LargeTest; +import androidx.test.filters.MediumTest; import android.util.Log; import org.awaitility.Awaitility; @@ -33,7 +33,7 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; -import static android.support.test.InstrumentationRegistry.getInstrumentation; +import static androidx.test.InstrumentationRegistry.getInstrumentation; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; 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 0c65bb2e6..9f16888fa 100644 --- a/app/src/androidTest/java/de/test/antennapod/ui/MainActivityTest.java +++ b/app/src/androidTest/java/de/test/antennapod/ui/MainActivityTest.java @@ -1,20 +1,16 @@ package de.test.antennapod.ui; import android.app.Activity; -import android.content.Context; import android.content.Intent; -import android.content.SharedPreferences; -import android.support.test.InstrumentationRegistry; -import android.support.test.espresso.intent.rule.IntentsTestRule; -import android.support.test.runner.AndroidJUnit4; +import androidx.test.InstrumentationRegistry; +import androidx.test.espresso.intent.rule.IntentsTestRule; +import androidx.test.runner.AndroidJUnit4; import com.robotium.solo.Solo; import com.robotium.solo.Timeout; import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.MainActivity; -import de.danoeh.antennapod.activity.OnlineFeedViewActivity; import de.danoeh.antennapod.core.feed.Feed; import de.danoeh.antennapod.core.storage.PodDBAdapter; -import de.danoeh.antennapod.dialog.RatingDialog; import de.test.antennapod.EspressoTestUtils; import org.junit.After; import org.junit.Before; @@ -24,11 +20,11 @@ import org.junit.runner.RunWith; import java.io.IOException; -import static android.support.test.InstrumentationRegistry.getInstrumentation; -import static android.support.test.espresso.Espresso.onView; -import static android.support.test.espresso.action.ViewActions.click; -import static android.support.test.espresso.contrib.ActivityResultMatchers.hasResultCode; -import static android.support.test.espresso.matcher.ViewMatchers.withText; +import static androidx.test.InstrumentationRegistry.getInstrumentation; +import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.action.ViewActions.click; +import static androidx.test.espresso.contrib.ActivityResultMatchers.hasResultCode; +import static androidx.test.espresso.matcher.ViewMatchers.withText; import static de.test.antennapod.EspressoTestUtils.clickPreference; import static de.test.antennapod.EspressoTestUtils.openNavDrawer; import static junit.framework.TestCase.assertTrue; diff --git a/app/src/androidTest/java/de/test/antennapod/ui/NavigationDrawerTest.java b/app/src/androidTest/java/de/test/antennapod/ui/NavigationDrawerTest.java index 548843636..360b55ce6 100644 --- a/app/src/androidTest/java/de/test/antennapod/ui/NavigationDrawerTest.java +++ b/app/src/androidTest/java/de/test/antennapod/ui/NavigationDrawerTest.java @@ -1,21 +1,17 @@ package de.test.antennapod.ui; -import android.content.Context; import android.content.Intent; -import android.content.SharedPreferences; -import android.support.test.InstrumentationRegistry; -import android.support.test.espresso.ViewInteraction; -import android.support.test.espresso.contrib.DrawerActions; -import android.support.test.espresso.intent.rule.IntentsTestRule; -import android.support.test.runner.AndroidJUnit4; +import androidx.test.InstrumentationRegistry; +import androidx.test.espresso.ViewInteraction; +import androidx.test.espresso.contrib.DrawerActions; +import androidx.test.espresso.intent.rule.IntentsTestRule; +import androidx.test.runner.AndroidJUnit4; import android.view.View; import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.MainActivity; import de.danoeh.antennapod.activity.PreferenceActivity; import de.danoeh.antennapod.core.feed.Feed; import de.danoeh.antennapod.core.preferences.UserPreferences; -import de.danoeh.antennapod.core.storage.PodDBAdapter; -import de.danoeh.antennapod.dialog.RatingDialog; import de.danoeh.antennapod.fragment.DownloadsFragment; import de.danoeh.antennapod.fragment.EpisodesFragment; import de.danoeh.antennapod.fragment.PlaybackHistoryFragment; @@ -33,15 +29,15 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import static android.support.test.espresso.Espresso.onView; -import static android.support.test.espresso.action.ViewActions.click; -import static android.support.test.espresso.action.ViewActions.longClick; -import static android.support.test.espresso.action.ViewActions.scrollTo; -import static android.support.test.espresso.intent.Intents.intended; -import static android.support.test.espresso.intent.matcher.IntentMatchers.hasComponent; -import static android.support.test.espresso.matcher.ViewMatchers.isRoot; -import static android.support.test.espresso.matcher.ViewMatchers.withId; -import static android.support.test.espresso.matcher.ViewMatchers.withText; +import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.action.ViewActions.click; +import static androidx.test.espresso.action.ViewActions.longClick; +import static androidx.test.espresso.action.ViewActions.scrollTo; +import static androidx.test.espresso.intent.Intents.intended; +import static androidx.test.espresso.intent.matcher.IntentMatchers.hasComponent; +import static androidx.test.espresso.matcher.ViewMatchers.isRoot; +import static androidx.test.espresso.matcher.ViewMatchers.withId; +import static androidx.test.espresso.matcher.ViewMatchers.withText; import static de.test.antennapod.EspressoTestUtils.waitForView; import static de.test.antennapod.NthMatcher.first; import static junit.framework.TestCase.assertTrue; diff --git a/app/src/androidTest/java/de/test/antennapod/ui/PlaybackSonicTest.java b/app/src/androidTest/java/de/test/antennapod/ui/PlaybackSonicTest.java index 22959917d..5b3530ea8 100644 --- a/app/src/androidTest/java/de/test/antennapod/ui/PlaybackSonicTest.java +++ b/app/src/androidTest/java/de/test/antennapod/ui/PlaybackSonicTest.java @@ -4,9 +4,9 @@ import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.preference.PreferenceManager; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.LargeTest; -import android.support.test.rule.ActivityTestRule; +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.LargeTest; +import androidx.test.rule.ActivityTestRule; import android.view.View; import android.widget.ListView; @@ -23,14 +23,13 @@ import de.danoeh.antennapod.core.service.playback.PlaybackService; import de.danoeh.antennapod.core.service.playback.PlayerStatus; import de.danoeh.antennapod.core.storage.DBReader; import de.danoeh.antennapod.core.storage.DBWriter; -import de.danoeh.antennapod.core.storage.PodDBAdapter; import de.test.antennapod.EspressoTestUtils; import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; -import static android.support.test.InstrumentationRegistry.getInstrumentation; +import static androidx.test.InstrumentationRegistry.getInstrumentation; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; diff --git a/app/src/androidTest/java/de/test/antennapod/ui/PlaybackTest.java b/app/src/androidTest/java/de/test/antennapod/ui/PlaybackTest.java index 57a1a4f80..ec5dc804e 100644 --- a/app/src/androidTest/java/de/test/antennapod/ui/PlaybackTest.java +++ b/app/src/androidTest/java/de/test/antennapod/ui/PlaybackTest.java @@ -4,9 +4,9 @@ import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.preference.PreferenceManager; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.LargeTest; -import android.support.test.rule.ActivityTestRule; +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.LargeTest; +import androidx.test.rule.ActivityTestRule; import android.view.View; import android.widget.ListView; 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 1063ac90a..b46af83c8 100644 --- a/app/src/androidTest/java/de/test/antennapod/ui/PreferencesTest.java +++ b/app/src/androidTest/java/de/test/antennapod/ui/PreferencesTest.java @@ -4,9 +4,9 @@ import android.content.Intent; import android.content.SharedPreferences; import android.content.res.Resources; import android.preference.PreferenceManager; -import android.support.test.filters.LargeTest; +import androidx.test.filters.LargeTest; -import android.support.test.rule.ActivityTestRule; +import androidx.test.rule.ActivityTestRule; import com.robotium.solo.Solo; import com.robotium.solo.Timeout; @@ -29,12 +29,12 @@ import de.danoeh.antennapod.fragment.EpisodesFragment; import de.danoeh.antennapod.fragment.QueueFragment; import de.danoeh.antennapod.fragment.SubscriptionFragment; -import static android.support.test.InstrumentationRegistry.getInstrumentation; -import static android.support.test.espresso.Espresso.onView; -import static android.support.test.espresso.action.ViewActions.click; -import static android.support.test.espresso.assertion.ViewAssertions.matches; -import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; -import static android.support.test.espresso.matcher.ViewMatchers.withText; +import static androidx.test.InstrumentationRegistry.getInstrumentation; +import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.action.ViewActions.click; +import static androidx.test.espresso.assertion.ViewAssertions.matches; +import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; +import static androidx.test.espresso.matcher.ViewMatchers.withText; import static de.test.antennapod.EspressoTestUtils.clickPreference; import static junit.framework.TestCase.assertEquals; import static junit.framework.TestCase.assertTrue; diff --git a/app/src/androidTest/java/de/test/antennapod/ui/QueueFragmentTest.java b/app/src/androidTest/java/de/test/antennapod/ui/QueueFragmentTest.java index d1023dd9e..7f0bf8fa2 100644 --- a/app/src/androidTest/java/de/test/antennapod/ui/QueueFragmentTest.java +++ b/app/src/androidTest/java/de/test/antennapod/ui/QueueFragmentTest.java @@ -1,9 +1,9 @@ package de.test.antennapod.ui; import android.content.Intent; -import android.support.test.espresso.Espresso; -import android.support.test.espresso.intent.rule.IntentsTestRule; -import android.support.test.runner.AndroidJUnit4; +import androidx.test.espresso.Espresso; +import androidx.test.espresso.intent.rule.IntentsTestRule; +import androidx.test.runner.AndroidJUnit4; import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.MainActivity; import de.danoeh.antennapod.fragment.QueueFragment; @@ -13,10 +13,10 @@ import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import static android.support.test.espresso.Espresso.onView; -import static android.support.test.espresso.action.ViewActions.click; -import static android.support.test.espresso.matcher.ViewMatchers.withContentDescription; -import static android.support.test.espresso.matcher.ViewMatchers.withText; +import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.action.ViewActions.click; +import static androidx.test.espresso.matcher.ViewMatchers.withContentDescription; +import static androidx.test.espresso.matcher.ViewMatchers.withText; /** * User interface tests for queue fragment diff --git a/app/src/androidTest/java/de/test/antennapod/ui/UITestUtilsTest.java b/app/src/androidTest/java/de/test/antennapod/ui/UITestUtilsTest.java index 7555bb69a..a183b648e 100644 --- a/app/src/androidTest/java/de/test/antennapod/ui/UITestUtilsTest.java +++ b/app/src/androidTest/java/de/test/antennapod/ui/UITestUtilsTest.java @@ -5,9 +5,9 @@ import java.net.HttpURLConnection; import java.net.URL; import java.util.List; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.LargeTest; -import android.support.test.filters.MediumTest; +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.LargeTest; +import androidx.test.filters.MediumTest; import de.danoeh.antennapod.core.feed.Feed; import de.danoeh.antennapod.core.feed.FeedItem; import org.junit.After; diff --git a/app/src/androidTest/java/de/test/antennapod/ui/VideoplayerActivityTest.java b/app/src/androidTest/java/de/test/antennapod/ui/VideoplayerActivityTest.java index c4dd032d7..ab16d7603 100644 --- a/app/src/androidTest/java/de/test/antennapod/ui/VideoplayerActivityTest.java +++ b/app/src/androidTest/java/de/test/antennapod/ui/VideoplayerActivityTest.java @@ -1,8 +1,8 @@ package de.test.antennapod.ui; import android.content.Intent; -import android.support.test.filters.MediumTest; -import android.support.test.rule.ActivityTestRule; +import androidx.test.filters.MediumTest; +import androidx.test.rule.ActivityTestRule; import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.VideoplayerActivity; @@ -10,10 +10,10 @@ import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; -import static android.support.test.espresso.Espresso.onView; -import static android.support.test.espresso.assertion.ViewAssertions.matches; -import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; -import static android.support.test.espresso.matcher.ViewMatchers.withId; +import static androidx.test.espresso.Espresso.onView; +import static androidx.test.espresso.assertion.ViewAssertions.matches; +import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; +import static androidx.test.espresso.matcher.ViewMatchers.withId; /** * Test class for VideoplayerActivity diff --git a/app/src/androidTest/java/de/test/antennapod/util/FilenameGeneratorTest.java b/app/src/androidTest/java/de/test/antennapod/util/FilenameGeneratorTest.java index ac98d2802..f2dfca92e 100644 --- a/app/src/androidTest/java/de/test/antennapod/util/FilenameGeneratorTest.java +++ b/app/src/androidTest/java/de/test/antennapod/util/FilenameGeneratorTest.java @@ -1,8 +1,8 @@ package de.test.antennapod.util; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.LargeTest; -import android.support.test.filters.SmallTest; +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.LargeTest; +import androidx.test.filters.SmallTest; import android.text.TextUtils; import java.io.File; diff --git a/app/src/androidTest/java/de/test/antennapod/util/URLCheckerTest.java b/app/src/androidTest/java/de/test/antennapod/util/URLCheckerTest.java index b96cb273b..5bc2f7bd8 100644 --- a/app/src/androidTest/java/de/test/antennapod/util/URLCheckerTest.java +++ b/app/src/androidTest/java/de/test/antennapod/util/URLCheckerTest.java @@ -1,6 +1,6 @@ package de.test.antennapod.util; -import android.support.test.filters.SmallTest; +import androidx.test.filters.SmallTest; import de.danoeh.antennapod.core.util.URLChecker; import org.junit.Test; diff --git a/app/src/androidTest/java/de/test/antennapod/util/event/FeedItemEventListener.java b/app/src/androidTest/java/de/test/antennapod/util/event/FeedItemEventListener.java new file mode 100644 index 000000000..601bba853 --- /dev/null +++ b/app/src/androidTest/java/de/test/antennapod/util/event/FeedItemEventListener.java @@ -0,0 +1,46 @@ +package de.test.antennapod.util.event; + +import androidx.annotation.NonNull; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; + +import java.util.ArrayList; +import java.util.List; + +import de.danoeh.antennapod.core.event.FeedItemEvent; +import io.reactivex.functions.Consumer; + +/** + * Test helpers to listen {@link FeedItemEvent} and handle them accordingly + * + */ +public class FeedItemEventListener { + private final List<FeedItemEvent> events = new ArrayList<>(); + + /** + * Provides an listener subscribing to {@link FeedItemEvent} that the callers can use + * + * Note: it uses RxJava's version of {@link Consumer} because it allows exceptions to be thrown. + */ + public static void withFeedItemEventListener(@NonNull Consumer<FeedItemEventListener> consumer) + throws Exception { + FeedItemEventListener feedItemEventListener = new FeedItemEventListener(); + try { + EventBus.getDefault().register(feedItemEventListener); + consumer.accept(feedItemEventListener); + } finally { + EventBus.getDefault().unregister(feedItemEventListener); + } + } + + @Subscribe + public void onEvent(FeedItemEvent event) { + events.add(event); + } + + @NonNull + public List<? extends FeedItemEvent> getEvents() { + return events; + } +} diff --git a/app/src/androidTest/java/de/test/antennapod/util/playback/TimelineTest.java b/app/src/androidTest/java/de/test/antennapod/util/playback/TimelineTest.java index df69859a0..c42695a57 100644 --- a/app/src/androidTest/java/de/test/antennapod/util/playback/TimelineTest.java +++ b/app/src/androidTest/java/de/test/antennapod/util/playback/TimelineTest.java @@ -2,8 +2,8 @@ package de.test.antennapod.util.playback; import android.content.Context; -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.SmallTest; +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.SmallTest; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; diff --git a/app/src/androidTest/java/de/test/antennapod/util/syndication/FeedDiscovererTest.java b/app/src/androidTest/java/de/test/antennapod/util/syndication/FeedDiscovererTest.java index d4837ef60..2dda77524 100644 --- a/app/src/androidTest/java/de/test/antennapod/util/syndication/FeedDiscovererTest.java +++ b/app/src/androidTest/java/de/test/antennapod/util/syndication/FeedDiscovererTest.java @@ -1,12 +1,11 @@ package de.test.antennapod.util.syndication; -import android.support.test.InstrumentationRegistry; +import androidx.test.InstrumentationRegistry; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import java.io.File; import java.io.FileOutputStream; -import java.nio.file.Files; import java.util.Map; import de.danoeh.antennapod.core.util.syndication.FeedDiscoverer; diff --git a/app/src/free/java/de/danoeh/antennapod/activity/CastEnabledActivity.java b/app/src/free/java/de/danoeh/antennapod/activity/CastEnabledActivity.java index 519d4c61b..aff1d6ea4 100644 --- a/app/src/free/java/de/danoeh/antennapod/activity/CastEnabledActivity.java +++ b/app/src/free/java/de/danoeh/antennapod/activity/CastEnabledActivity.java @@ -1,6 +1,6 @@ package de.danoeh.antennapod.activity; -import android.support.v7.app.AppCompatActivity; +import androidx.appcompat.app.AppCompatActivity; /** * Activity that allows for showing the MediaRouter button whenever there's a cast device in the diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c2c6f53c5..488d4e473 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -105,17 +105,6 @@ android:value="de.danoeh.antennapod.activity.MainActivity"/> </activity> - <activity - android:name=".activity.FeedInfoActivity" - android:label="@string/feed_info_label"> - </activity> - - <activity - android:name=".activity.FeedSettingsActivity" - android:windowSoftInputMode="stateHidden" - android:label="@string/feed_settings_label"> - </activity> - <service android:name=".core.service.PlayerWidgetJobService" android:permission="android.permission.BIND_JOB_SERVICE" @@ -151,13 +140,6 @@ android:value="de.danoeh.antennapod.activity.PreferenceActivity"/> </activity> <activity - android:name=".activity.StatisticsActivity" - android:label="@string/statistics_label"> - <meta-data - android:name="android.support.PARENT_ACTIVITY" - android:value="de.danoeh.antennapod.activity.PreferenceActivity"/> - </activity> - <activity android:name=".activity.ImportExportActivity" android:label="@string/import_export"> <meta-data @@ -357,7 +339,7 @@ <provider android:authorities="@string/provider_authority" - android:name="android.support.v4.content.FileProvider" + android:name="androidx.core.content.FileProvider" android:exported="false" android:grantUriPermissions="true"> <meta-data diff --git a/app/src/main/java/de/danoeh/antennapod/PodcastApp.java b/app/src/main/java/de/danoeh/antennapod/PodcastApp.java index cb2f597d6..94d281a45 100644 --- a/app/src/main/java/de/danoeh/antennapod/PodcastApp.java +++ b/app/src/main/java/de/danoeh/antennapod/PodcastApp.java @@ -63,6 +63,8 @@ public class PodcastApp extends Application { EventBus.builder() .addIndex(new ApEventBusIndex()) .addIndex(new ApCoreEventBusIndex()) + .logNoSubscriberMessages(false) + .sendNoSubscriberEvent(false) .installDefaultEventBus(); } diff --git a/app/src/main/java/de/danoeh/antennapod/activity/AboutActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/AboutActivity.java index 821e2f347..ef7ea2b16 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/AboutActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/AboutActivity.java @@ -1,12 +1,10 @@ package de.danoeh.antennapod.activity; -import android.content.Intent; import android.content.res.TypedArray; import android.graphics.Color; -import android.net.Uri; import android.os.Build; import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; +import androidx.appcompat.app.AppCompatActivity; import android.util.Log; import android.view.MenuItem; import android.view.View; 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 07c970197..8eb0b1e0b 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java @@ -1,7 +1,7 @@ package de.danoeh.antennapod.activity; import android.content.Intent; -import android.support.v4.view.ViewCompat; +import androidx.core.view.ViewCompat; import android.text.TextUtils; import android.util.Log; import android.view.View; @@ -12,6 +12,8 @@ import java.util.Locale; import java.util.concurrent.atomic.AtomicBoolean; import de.danoeh.antennapod.core.feed.MediaType; +import de.danoeh.antennapod.core.preferences.PlaybackPreferences; +import de.danoeh.antennapod.core.preferences.PlaybackSpeedHelper; import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.core.service.playback.PlaybackService; import de.danoeh.antennapod.dialog.VariableSpeedDialog; @@ -81,7 +83,7 @@ public class AudioplayerActivity extends MediaplayerInfoActivity { } float speed = 1.0f; if(controller.canSetPlaybackSpeed()) { - speed = UserPreferences.getPlaybackSpeed(); + speed = PlaybackSpeedHelper.getCurrentPlaybackSpeed(controller.getMedia()); } String speedStr = new DecimalFormat("0.00").format(speed); txtvPlaybackSpeed.setText(speedStr); @@ -105,7 +107,9 @@ public class AudioplayerActivity extends MediaplayerInfoActivity { String[] availableSpeeds = UserPreferences.getPlaybackSpeedArray(); DecimalFormatSymbols format = new DecimalFormatSymbols(Locale.US); format.setDecimalSeparator('.'); - String currentSpeed = new DecimalFormat("0.00", format).format(UserPreferences.getPlaybackSpeed()); + + float currentSpeedValue = controller.getCurrentPlaybackSpeedMultiplier(); + String currentSpeed = new DecimalFormat("0.00", format).format(currentSpeedValue); // Provide initial value in case the speed list has changed // out from under us @@ -127,6 +131,12 @@ public class AudioplayerActivity extends MediaplayerInfoActivity { break; } } + + try { + PlaybackPreferences.setCurrentlyPlayingTemporaryPlaybackSpeed(Float.parseFloat(newSpeed)); + } catch (NumberFormatException e) { + // Well this was awkward... + } UserPreferences.setPlaybackSpeed(newSpeed); controller.setPlaybackSpeed(Float.parseFloat(newSpeed)); onPositionObserverUpdate(); diff --git a/app/src/main/java/de/danoeh/antennapod/activity/BugReportActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/BugReportActivity.java index 7df973f9b..666eacfa8 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/BugReportActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/BugReportActivity.java @@ -4,8 +4,8 @@ import android.content.ClipData; import android.content.ClipboardManager; import android.content.Context; import android.os.Bundle; -import android.support.design.widget.Snackbar; -import android.support.v7.app.AppCompatActivity; +import com.google.android.material.snackbar.Snackbar; +import androidx.appcompat.app.AppCompatActivity; import android.widget.TextView; import de.danoeh.antennapod.CrashReportWriter; import de.danoeh.antennapod.R; 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 33def125e..49ce954bc 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/DirectoryChooserActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/DirectoryChooserActivity.java @@ -5,9 +5,9 @@ import android.content.Intent; import android.os.Bundle; import android.os.Environment; import android.os.FileObserver; -import android.support.v4.app.NavUtils; -import android.support.v7.app.AlertDialog; -import android.support.v7.app.AppCompatActivity; +import androidx.core.app.NavUtils; +import androidx.appcompat.app.AlertDialog; +import androidx.appcompat.app.AppCompatActivity; import android.util.Log; import android.view.Menu; import android.view.MenuInflater; diff --git a/app/src/main/java/de/danoeh/antennapod/activity/DownloadAuthenticationActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/DownloadAuthenticationActivity.java index 5e04d743d..08ebc6421 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/DownloadAuthenticationActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/DownloadAuthenticationActivity.java @@ -3,8 +3,8 @@ package de.danoeh.antennapod.activity; import android.app.Activity; import android.content.Intent; import android.os.Bundle; -import android.support.v7.app.ActionBar; -import android.support.v7.app.AppCompatActivity; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AppCompatActivity; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; diff --git a/app/src/main/java/de/danoeh/antennapod/activity/FeedInfoActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/FeedInfoActivity.java deleted file mode 100644 index 26e360bd3..000000000 --- a/app/src/main/java/de/danoeh/antennapod/activity/FeedInfoActivity.java +++ /dev/null @@ -1,225 +0,0 @@ -package de.danoeh.antennapod.activity; - -import android.content.ClipData; -import android.content.Context; -import android.content.Intent; -import android.graphics.LightingColorFilter; -import android.net.Uri; -import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; -import android.text.TextUtils; -import android.util.Log; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.widget.ImageView; -import android.widget.TextView; -import android.widget.Toast; - -import com.bumptech.glide.Glide; -import com.bumptech.glide.request.RequestOptions; -import com.joanzapata.iconify.Iconify; - -import org.apache.commons.lang3.StringUtils; -import org.jsoup.Jsoup; -import org.jsoup.nodes.Document; - -import de.danoeh.antennapod.R; -import de.danoeh.antennapod.core.dialog.DownloadRequestErrorDialogCreator; -import de.danoeh.antennapod.core.feed.Feed; -import de.danoeh.antennapod.core.glide.ApGlideSettings; -import de.danoeh.antennapod.core.glide.FastBlurTransformation; -import de.danoeh.antennapod.core.preferences.UserPreferences; -import de.danoeh.antennapod.core.storage.DBReader; -import de.danoeh.antennapod.core.storage.DownloadRequestException; -import de.danoeh.antennapod.core.util.IntentUtils; -import de.danoeh.antennapod.core.util.LangUtils; -import de.danoeh.antennapod.core.util.syndication.HtmlToPlainText; -import de.danoeh.antennapod.menuhandler.FeedMenuHandler; -import io.reactivex.Maybe; -import io.reactivex.MaybeOnSubscribe; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.disposables.Disposable; -import io.reactivex.schedulers.Schedulers; - -/** - * Displays information about a feed. - */ -public class FeedInfoActivity extends AppCompatActivity { - - public static final String EXTRA_FEED_ID = "de.danoeh.antennapod.extra.feedId"; - private static final String TAG = "FeedInfoActivity"; - private Feed feed; - - private ImageView imgvCover; - private TextView txtvTitle; - private TextView txtvDescription; - private TextView lblLanguage; - private TextView txtvLanguage; - private TextView lblAuthor; - private TextView txtvAuthor; - private TextView txtvUrl; - - private Disposable disposable; - - - private final View.OnClickListener copyUrlToClipboard = new View.OnClickListener() { - @Override - public void onClick(View v) { - if(feed != null && feed.getDownload_url() != null) { - String url = feed.getDownload_url(); - ClipData clipData = ClipData.newPlainText(url, url); - android.content.ClipboardManager cm = (android.content.ClipboardManager) FeedInfoActivity.this - .getSystemService(Context.CLIPBOARD_SERVICE); - cm.setPrimaryClip(clipData); - Toast t = Toast.makeText(FeedInfoActivity.this, R.string.copied_url_msg, Toast.LENGTH_SHORT); - t.show(); - } - } - }; - - @Override - protected void onCreate(Bundle savedInstanceState) { - setTheme(UserPreferences.getTheme()); - super.onCreate(savedInstanceState); - setContentView(R.layout.feedinfo); - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - long feedId = getIntent().getLongExtra(EXTRA_FEED_ID, -1); - - imgvCover = findViewById(R.id.imgvCover); - txtvTitle = findViewById(R.id.txtvTitle); - TextView txtvAuthorHeader = findViewById(R.id.txtvAuthor); - ImageView imgvBackground = findViewById(R.id.imgvBackground); - findViewById(R.id.butShowInfo).setVisibility(View.INVISIBLE); - findViewById(R.id.butShowSettings).setVisibility(View.INVISIBLE); - // https://github.com/bumptech/glide/issues/529 - imgvBackground.setColorFilter(new LightingColorFilter(0xff828282, 0x000000)); - - - txtvDescription = findViewById(R.id.txtvDescription); - lblLanguage = findViewById(R.id.lblLanguage); - txtvLanguage = findViewById(R.id.txtvLanguage); - lblAuthor = findViewById(R.id.lblAuthor); - txtvAuthor = findViewById(R.id.txtvDetailsAuthor); - txtvUrl = findViewById(R.id.txtvUrl); - - txtvUrl.setOnClickListener(copyUrlToClipboard); - - disposable = Maybe.create((MaybeOnSubscribe<Feed>) emitter -> { - Feed feed = DBReader.getFeed(feedId); - if (feed != null) { - emitter.onSuccess(feed); - } else { - emitter.onComplete(); - } - }) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(result -> { - feed = result; - Log.d(TAG, "Language is " + feed.getLanguage()); - Log.d(TAG, "Author is " + feed.getAuthor()); - Log.d(TAG, "URL is " + feed.getDownload_url()); - Glide.with(FeedInfoActivity.this) - .load(feed.getImageLocation()) - .apply(new RequestOptions() - .placeholder(R.color.light_gray) - .error(R.color.light_gray) - .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY) - .fitCenter() - .dontAnimate()) - .into(imgvCover); - Glide.with(FeedInfoActivity.this) - .load(feed.getImageLocation()) - .apply(new RequestOptions() - .placeholder(R.color.image_readability_tint) - .error(R.color.image_readability_tint) - .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY) - .transform(new FastBlurTransformation()) - .dontAnimate()) - .into(imgvBackground); - - txtvTitle.setText(feed.getTitle()); - - String description = feed.getDescription(); - if(description != null) { - if(Feed.TYPE_ATOM1.equals(feed.getType())) { - HtmlToPlainText formatter = new HtmlToPlainText(); - Document feedDescription = Jsoup.parse(feed.getDescription()); - description = StringUtils.trim(formatter.getPlainText(feedDescription)); - } - } else { - description = ""; - } - txtvDescription.setText(description); - - if (!TextUtils.isEmpty(feed.getAuthor())) { - txtvAuthor.setText(feed.getAuthor()); - txtvAuthorHeader.setText(feed.getAuthor()); - } else { - lblAuthor.setVisibility(View.GONE); - txtvAuthor.setVisibility(View.GONE); - } - if (!TextUtils.isEmpty(feed.getLanguage())) { - txtvLanguage.setText(LangUtils.getLanguageString(feed.getLanguage())); - } else { - lblLanguage.setVisibility(View.GONE); - txtvLanguage.setVisibility(View.GONE); - } - txtvUrl.setText(feed.getDownload_url() + " {fa-paperclip}"); - Iconify.addIcons(txtvUrl); - - supportInvalidateOptionsMenu(); - }, error -> { - Log.d(TAG, Log.getStackTraceString(error)); - finish(); - }, () -> { - Log.e(TAG, "Activity was started with invalid arguments"); - finish(); - }); - } - - @Override - public void onDestroy() { - super.onDestroy(); - if (disposable != null) { - disposable.dispose(); - } - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - super.onCreateOptionsMenu(menu); - MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.feedinfo, menu); - return true; - } - - @Override - public boolean onPrepareOptionsMenu(Menu menu) { - super.onPrepareOptionsMenu(menu); - menu.findItem(R.id.share_link_item).setVisible(feed != null && feed.getLink() != null); - menu.findItem(R.id.visit_website_item).setVisible(feed != null && feed.getLink() != null && - IntentUtils.isCallable(this, new Intent(Intent.ACTION_VIEW, Uri.parse(feed.getLink())))); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case android.R.id.home: - finish(); - return true; - default: - try { - return FeedMenuHandler.onOptionsItemClicked(this, item, feed); - } catch (DownloadRequestException e) { - e.printStackTrace(); - DownloadRequestErrorDialogCreator.newRequestErrorDialog(this, - e.getMessage()); - } - return super.onOptionsItemSelected(item); - } - } -} diff --git a/app/src/main/java/de/danoeh/antennapod/activity/FeedSettingsActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/FeedSettingsActivity.java deleted file mode 100644 index fbd19f88a..000000000 --- a/app/src/main/java/de/danoeh/antennapod/activity/FeedSettingsActivity.java +++ /dev/null @@ -1,130 +0,0 @@ -package de.danoeh.antennapod.activity; - -import android.arch.lifecycle.ViewModelProviders; -import android.graphics.LightingColorFilter; -import android.os.Bundle; -import android.support.v4.app.FragmentManager; -import android.support.v4.app.FragmentTransaction; -import android.support.v7.app.AppCompatActivity; -import android.text.TextUtils; -import android.util.Log; -import android.view.MenuItem; -import android.view.View; -import android.widget.ImageView; -import android.widget.TextView; -import com.bumptech.glide.Glide; -import com.bumptech.glide.request.RequestOptions; -import de.danoeh.antennapod.R; -import de.danoeh.antennapod.core.feed.Feed; -import de.danoeh.antennapod.core.glide.ApGlideSettings; -import de.danoeh.antennapod.core.glide.FastBlurTransformation; -import de.danoeh.antennapod.core.preferences.UserPreferences; -import de.danoeh.antennapod.fragment.FeedSettingsFragment; -import de.danoeh.antennapod.viewmodel.FeedSettingsViewModel; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.disposables.Disposable; -import io.reactivex.schedulers.Schedulers; - -/** - * Displays information about a feed. - */ -public class FeedSettingsActivity extends AppCompatActivity { - public static final String EXTRA_FEED_ID = "de.danoeh.antennapod.extra.feedId"; - private static final String TAG = "FeedSettingsActivity"; - private Feed feed; - private Disposable disposable; - private ImageView imgvCover; - private TextView txtvTitle; - private ImageView imgvBackground; - private TextView txtvAuthorHeader; - - @Override - protected void onCreate(Bundle savedInstanceState) { - setTheme(UserPreferences.getTheme()); - super.onCreate(savedInstanceState); - setContentView(R.layout.feedsettings); - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - - imgvCover = findViewById(R.id.imgvCover); - txtvTitle = findViewById(R.id.txtvTitle); - txtvAuthorHeader = findViewById(R.id.txtvAuthor); - imgvBackground = findViewById(R.id.imgvBackground); - findViewById(R.id.butShowInfo).setVisibility(View.INVISIBLE); - findViewById(R.id.butShowSettings).setVisibility(View.INVISIBLE); - // https://github.com/bumptech/glide/issues/529 - imgvBackground.setColorFilter(new LightingColorFilter(0xff828282, 0x000000)); - - long feedId = getIntent().getLongExtra(EXTRA_FEED_ID, -1); - disposable = ViewModelProviders.of(this).get(FeedSettingsViewModel.class).getFeed(feedId) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(result -> { - feed = result; - showFragment(); - showHeader(); - }, error -> { - Log.d(TAG, Log.getStackTraceString(error)); - finish(); - }, () -> { - Log.e(TAG, "Activity was started with invalid arguments"); - finish(); - }); - } - - private void showFragment() { - FeedSettingsFragment fragment = new FeedSettingsFragment(); - fragment.setArguments(getIntent().getExtras()); - - FragmentManager fragmentManager = getSupportFragmentManager(); - FragmentTransaction fragmentTransaction = - fragmentManager.beginTransaction(); - fragmentTransaction.replace(R.id.settings_fragment_container, fragment); - fragmentTransaction.commit(); - } - - private void showHeader() { - txtvTitle.setText(feed.getTitle()); - - if (!TextUtils.isEmpty(feed.getAuthor())) { - txtvAuthorHeader.setText(feed.getAuthor()); - } - - Glide.with(FeedSettingsActivity.this) - .load(feed.getImageLocation()) - .apply(new RequestOptions() - .placeholder(R.color.light_gray) - .error(R.color.light_gray) - .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY) - .fitCenter() - .dontAnimate()) - .into(imgvCover); - Glide.with(FeedSettingsActivity.this) - .load(feed.getImageLocation()) - .apply(new RequestOptions() - .placeholder(R.color.image_readability_tint) - .error(R.color.image_readability_tint) - .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY) - .transform(new FastBlurTransformation()) - .dontAnimate()) - .into(imgvBackground); - } - - @Override - public void onDestroy() { - super.onDestroy(); - if (disposable != null) { - disposable.dispose(); - } - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case android.R.id.home: - finish(); - return true; - default: - return super.onOptionsItemSelected(item); - } - } -} diff --git a/app/src/main/java/de/danoeh/antennapod/activity/ImportExportActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/ImportExportActivity.java index 9795c1240..f85a1cd77 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/ImportExportActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/ImportExportActivity.java @@ -7,10 +7,10 @@ import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.os.ParcelFileDescriptor; -import android.support.design.widget.Snackbar; -import android.support.v7.app.ActionBar; -import android.support.v7.app.AlertDialog; -import android.support.v7.app.AppCompatActivity; +import com.google.android.material.snackbar.Snackbar; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AlertDialog; +import androidx.appcompat.app.AppCompatActivity; import android.util.Log; import android.view.MenuItem; 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 08686bd02..6a38f8f0a 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java @@ -11,16 +11,16 @@ import android.database.DataSetObserver; import android.os.Build; import android.os.Bundle; import android.os.Handler; -import android.support.annotation.NonNull; -import android.support.annotation.VisibleForTesting; -import android.support.design.widget.Snackbar; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentManager; -import android.support.v4.app.FragmentTransaction; -import android.support.v4.widget.DrawerLayout; -import android.support.v7.app.ActionBarDrawerToggle; -import android.support.v7.app.AlertDialog; -import android.support.v7.widget.Toolbar; +import androidx.annotation.NonNull; +import androidx.annotation.VisibleForTesting; +import com.google.android.material.snackbar.Snackbar; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentTransaction; +import androidx.drawerlayout.widget.DrawerLayout; +import androidx.appcompat.app.ActionBarDrawerToggle; +import androidx.appcompat.app.AlertDialog; +import androidx.appcompat.widget.Toolbar; import android.util.Log; import android.util.TypedValue; import android.view.ContextMenu; @@ -47,7 +47,6 @@ import de.danoeh.antennapod.adapter.NavListAdapter; import de.danoeh.antennapod.core.asynctask.FeedRemover; import de.danoeh.antennapod.core.dialog.ConfirmationDialog; import de.danoeh.antennapod.core.event.MessageEvent; -import de.danoeh.antennapod.core.event.ProgressEvent; import de.danoeh.antennapod.core.event.QueueEvent; import de.danoeh.antennapod.core.feed.EventDistributor; import de.danoeh.antennapod.core.feed.Feed; @@ -70,6 +69,7 @@ import de.danoeh.antennapod.fragment.FeedItemlistFragment; import de.danoeh.antennapod.fragment.PlaybackHistoryFragment; import de.danoeh.antennapod.fragment.QueueFragment; import de.danoeh.antennapod.fragment.SubscriptionFragment; +import de.danoeh.antennapod.fragment.TransitionEffect; import de.danoeh.antennapod.menuhandler.NavDrawerActivity; import de.danoeh.antennapod.preferences.PreferenceUpgrader; import io.reactivex.Observable; @@ -378,15 +378,34 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi } } - public void loadChildFragment(Fragment fragment) { + public void loadChildFragment(Fragment fragment, TransitionEffect transition) { Validate.notNull(fragment); - FragmentManager fm = getSupportFragmentManager(); - fm.beginTransaction() - .replace(R.id.main_view, fragment, "main") + FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); + + switch (transition) { + case FADE: + transaction.setCustomAnimations(R.anim.fade_in, R.anim.fade_out); + break; + case FLIP: + transaction.setCustomAnimations( + R.anim.card_flip_left_in, + R.anim.card_flip_left_out, + R.anim.card_flip_right_in, + R.anim.card_flip_right_out); + break; + } + + transaction + .hide(getSupportFragmentManager().findFragmentByTag("main")) + .add(R.id.main_view, fragment, "main") .addToBackStack(null) .commit(); } + public void loadChildFragment(Fragment fragment) { + loadChildFragment(fragment, TransitionEffect.NONE); + } + public void dismissChildFragment() { getSupportFragmentManager().popBackStack(); } @@ -788,25 +807,6 @@ public class MainActivity extends CastEnabledActivity implements NavDrawerActivi } @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(ProgressEvent event) { - Log.d(TAG, "onEvent(" + event + ")"); - switch(event.action) { - case START: - pd = new ProgressDialog(this); - pd.setMessage(event.message); - pd.setIndeterminate(true); - pd.setCancelable(false); - pd.show(); - break; - case END: - if(pd != null) { - pd.dismiss(); - } - break; - } - } - - @Subscribe(threadMode = ThreadMode.MAIN) public void onEventMainThread(MessageEvent event) { Log.d(TAG, "onEvent(" + event + ")"); View parentLayout = findViewById(R.id.drawer_layout); diff --git a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java index 91c3796af..a060e258a 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java @@ -9,14 +9,14 @@ import android.content.pm.PackageManager; import android.content.res.TypedArray; import android.graphics.Color; import android.graphics.PixelFormat; -import android.net.Uri; import android.os.Build; import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.v4.app.ActivityCompat; -import android.support.v4.app.ActivityOptionsCompat; -import android.support.v4.content.ContextCompat; -import android.support.v7.app.AlertDialog; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.core.app.ActivityCompat; +import androidx.core.app.ActivityOptionsCompat; +import androidx.core.content.ContextCompat; +import androidx.appcompat.app.AlertDialog; import android.util.Log; import android.view.Menu; import android.view.MenuInflater; @@ -34,6 +34,7 @@ import com.joanzapata.iconify.IconDrawable; import com.joanzapata.iconify.fonts.FontAwesomeIcons; import de.danoeh.antennapod.R; +import de.danoeh.antennapod.core.event.PlaybackPositionEvent; import de.danoeh.antennapod.core.feed.FeedItem; import de.danoeh.antennapod.core.feed.FeedMedia; import de.danoeh.antennapod.core.feed.MediaType; @@ -63,6 +64,9 @@ import io.reactivex.Observable; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.Disposable; import io.reactivex.schedulers.Schedulers; +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; /** @@ -73,7 +77,8 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements private static final String TAG = "MediaplayerActivity"; private static final String PREFS = "MediaPlayerActivityPreferences"; private static final String PREF_SHOW_TIME_LEFT = "showTimeLeft"; - private static final int REQUEST_CODE_STORAGE = 42; + private static final int REQUEST_CODE_STORAGE_PLAY_VIDEO = 42; + private static final int REQUEST_CODE_STORAGE_PLAY_AUDIO = 43; PlaybackController controller; @@ -194,6 +199,11 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements }; } + @Subscribe(threadMode = ThreadMode.MAIN) + public void onEventMainThread(PlaybackPositionEvent event) { + onPositionObserverUpdate(); + } + private static TextView getTxtvFFFromActivity(MediaplayerActivity activity) { return activity.txtvFF; } @@ -274,6 +284,7 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements controller.init(); loadMediaInfo(); onPositionObserverUpdate(); + EventBus.getDefault().register(this); } @Override @@ -286,6 +297,7 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements if (disposable != null) { disposable.dispose(); } + EventBus.getDefault().unregister(this); super.onStop(); } @@ -845,10 +857,13 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_EXTERNAL_STORAGE)) { Toast.makeText(this, R.string.needs_storage_permission, Toast.LENGTH_LONG).show(); - } else { - ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, - REQUEST_CODE_STORAGE); } + + int code = REQUEST_CODE_STORAGE_PLAY_AUDIO; + if (type == MediaType.VIDEO) { + code = REQUEST_CODE_STORAGE_PLAY_VIDEO; + } + ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, code); return; } @@ -856,6 +871,7 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements ExternalMedia media = new ExternalMedia(intent.getData().getPath(), type); new PlaybackServiceStarter(this, media) + .callEvenIfRunning(true) .startWhenPrepared(true) .shouldStream(false) .prepareImmediately(true) @@ -863,18 +879,22 @@ public abstract class MediaplayerActivity extends CastEnabledActivity implements } @Override - public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { - if (requestCode == REQUEST_CODE_STORAGE) { - if (grantResults.length <= 0 || grantResults[0] != PackageManager.PERMISSION_GRANTED) { - Toast.makeText(this, R.string.needs_storage_permission, Toast.LENGTH_LONG).show(); + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, int[] grantResults) { + if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + if (requestCode == REQUEST_CODE_STORAGE_PLAY_AUDIO) { + playExternalMedia(getIntent(), MediaType.AUDIO); + } else if (requestCode == REQUEST_CODE_STORAGE_PLAY_VIDEO) { + playExternalMedia(getIntent(), MediaType.VIDEO); } + } else { + Toast.makeText(this, R.string.needs_storage_permission, Toast.LENGTH_LONG).show(); } } @Nullable private static FeedItem getFeedItem(@Nullable Playable playable) { - if ((playable != null) && (playable instanceof FeedMedia)) { - return ((FeedMedia)playable).getItem(); + if (playable instanceof FeedMedia) { + return ((FeedMedia) playable).getItem(); } else { return null; } diff --git a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerInfoActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerInfoActivity.java index 5210bdc06..016168b45 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerInfoActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerInfoActivity.java @@ -7,15 +7,15 @@ import android.content.SharedPreferences; import android.content.res.Configuration; import android.os.Build; import android.os.Bundle; -import android.support.design.widget.AppBarLayout; -import android.support.design.widget.Snackbar; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentManager; -import android.support.v4.app.FragmentStatePagerAdapter; -import android.support.v4.view.ViewPager; -import android.support.v4.widget.DrawerLayout; -import android.support.v7.app.ActionBarDrawerToggle; -import android.support.v7.widget.Toolbar; +import com.google.android.material.appbar.AppBarLayout; +import com.google.android.material.snackbar.Snackbar; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentStatePagerAdapter; +import androidx.viewpager.widget.ViewPager; +import androidx.drawerlayout.widget.DrawerLayout; +import androidx.appcompat.app.ActionBarDrawerToggle; +import androidx.appcompat.widget.Toolbar; import android.util.Log; import android.util.TypedValue; import android.view.ContextMenu; @@ -23,7 +23,6 @@ import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.widget.AdapterView; -import android.widget.Button; import android.widget.ImageButton; import android.widget.ListView; import android.widget.TextView; @@ -64,7 +63,6 @@ import io.reactivex.Observable; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.Disposable; import io.reactivex.schedulers.Schedulers; -import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; @@ -122,7 +120,6 @@ public abstract class MediaplayerInfoActivity extends MediaplayerActivity implem disposable.dispose(); } EventDistributor.getInstance().unregister(contentUpdate); - EventBus.getDefault().unregister(this); saveCurrentFragment(); } @@ -175,7 +172,6 @@ public abstract class MediaplayerInfoActivity extends MediaplayerActivity implem protected void onStart() { super.onStart(); EventDistributor.getInstance().register(contentUpdate); - EventBus.getDefault().register(this); 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 c38eb7d47..39715495a 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java @@ -7,12 +7,12 @@ import android.content.Intent; import android.graphics.LightingColorFilter; import android.os.Build; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.UiThread; -import android.support.v4.app.NavUtils; -import android.support.v7.app.ActionBar; -import android.support.v7.app.AlertDialog; -import android.support.v7.app.AppCompatActivity; +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; import android.util.Log; import android.view.LayoutInflater; diff --git a/app/src/main/java/de/danoeh/antennapod/activity/OpmlFeedChooserActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/OpmlFeedChooserActivity.java index 72759c59c..376074525 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/OpmlFeedChooserActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/OpmlFeedChooserActivity.java @@ -2,7 +2,7 @@ package de.danoeh.antennapod.activity; import android.content.Intent; import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; +import androidx.appcompat.app.AppCompatActivity; import android.util.SparseBooleanArray; import android.view.Menu; import android.view.MenuInflater; 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 c04ae051e..9caff0fc0 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportBaseActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportBaseActivity.java @@ -5,9 +5,9 @@ import android.content.pm.PackageManager; import android.net.Uri; import android.os.Build; import android.os.Environment; -import android.support.annotation.Nullable; -import android.support.v4.app.ActivityCompat; -import android.support.v7.app.AppCompatActivity; +import androidx.annotation.Nullable; +import androidx.core.app.ActivityCompat; +import androidx.appcompat.app.AppCompatActivity; import android.util.Log; import com.afollestad.materialdialogs.MaterialDialog; diff --git a/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java index 7e0ae173f..a0f9bf6d8 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/PreferenceActivity.java @@ -1,9 +1,9 @@ package de.danoeh.antennapod.activity; import android.os.Bundle; -import android.support.v7.app.ActionBar; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.preference.PreferenceFragmentCompat; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AppCompatActivity; +import androidx.preference.PreferenceFragmentCompat; import android.view.Menu; import android.view.MenuItem; import android.view.ViewGroup; diff --git a/app/src/main/java/de/danoeh/antennapod/activity/SplashActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/SplashActivity.java index 52102eee1..bd1ccaea4 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/SplashActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/SplashActivity.java @@ -5,9 +5,9 @@ import android.graphics.PorterDuff; import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.v4.graphics.drawable.DrawableCompat; -import android.support.v7.app.AppCompatActivity; +import androidx.annotation.Nullable; +import androidx.core.graphics.drawable.DrawableCompat; +import androidx.appcompat.app.AppCompatActivity; import android.widget.ProgressBar; import de.danoeh.antennapod.R; 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 20e34cc52..c9c9a0e2c 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/StorageErrorActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/StorageErrorActivity.java @@ -9,9 +9,9 @@ import android.content.IntentFilter; import android.content.pm.PackageManager; import android.os.Build; import android.os.Bundle; -import android.support.v4.app.ActivityCompat; -import android.support.v7.app.AlertDialog; -import android.support.v7.app.AppCompatActivity; +import androidx.core.app.ActivityCompat; +import androidx.appcompat.app.AlertDialog; +import androidx.appcompat.app.AppCompatActivity; import android.text.TextUtils; import android.util.Log; import android.widget.Button; diff --git a/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java index 78cc15b2c..2d28ea561 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java @@ -6,8 +6,8 @@ import android.graphics.drawable.ColorDrawable; import android.os.Build; import android.os.Bundle; import android.os.Handler; -import android.support.v4.view.WindowCompat; -import android.support.v7.app.ActionBar; +import androidx.core.view.WindowCompat; +import androidx.appcompat.app.ActionBar; import android.text.TextUtils; import android.util.Log; import android.util.Pair; diff --git a/app/src/main/java/de/danoeh/antennapod/activity/gpoddernet/GpodnetAuthenticationActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/gpoddernet/GpodnetAuthenticationActivity.java index 2d7898d5b..c79c611ce 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/gpoddernet/GpodnetAuthenticationActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/gpoddernet/GpodnetAuthenticationActivity.java @@ -2,11 +2,10 @@ package de.danoeh.antennapod.activity.gpoddernet; import android.content.Context; import android.content.Intent; -import android.content.res.Configuration; import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; +import androidx.appcompat.app.AppCompatActivity; import android.util.Log; import android.view.LayoutInflater; import android.view.MenuItem; diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java index 85b5e3985..5b735cd1f 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java @@ -1,10 +1,11 @@ package de.danoeh.antennapod.adapter; import android.os.Build; -import android.support.annotation.Nullable; -import android.support.v4.content.ContextCompat; -import android.support.v7.widget.RecyclerView; -import android.support.v7.widget.helper.ItemTouchHelper; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.core.content.ContextCompat; +import androidx.recyclerview.widget.RecyclerView; +import androidx.recyclerview.widget.ItemTouchHelper; import android.text.Layout; import android.util.Log; import android.view.ContextMenu; @@ -23,10 +24,12 @@ import android.widget.TextView; import com.joanzapata.iconify.Iconify; import java.lang.ref.WeakReference; +import java.util.List; import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.MainActivity; import de.danoeh.antennapod.adapter.actionbutton.ItemActionButton; +import de.danoeh.antennapod.core.event.PlaybackPositionEvent; import de.danoeh.antennapod.core.feed.FeedItem; import de.danoeh.antennapod.core.feed.FeedMedia; import de.danoeh.antennapod.core.storage.DownloadRequester; @@ -50,6 +53,7 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR private final boolean showOnlyNewEpisodes; private FeedItem selectedItem; + private Holder currentlyPlayingItem = null; private final int playingBackGroundColor; private final int normalBackGroundColor; @@ -165,8 +169,9 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR holder.progress.setVisibility(View.INVISIBLE); } - if(media.isCurrentlyPlaying()) { + if (media.isCurrentlyPlaying()) { holder.container.setBackgroundColor(playingBackGroundColor); + currentlyPlayingItem = holder; } else { holder.container.setBackgroundColor(normalBackGroundColor); } @@ -196,6 +201,22 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR .load(); } + @Override + public void onBindViewHolder(@NonNull Holder holder, int pos, List<Object> payload) { + onBindViewHolder(holder, pos); + + if (holder == currentlyPlayingItem && payload.size() == 1 && payload.get(0) instanceof PlaybackPositionEvent) { + PlaybackPositionEvent event = (PlaybackPositionEvent) payload.get(0); + holder.progress.setProgress((int) (100.0 * event.getPosition() / event.getDuration())); + } + } + + public void notifyCurrentlyPlayingItemChanged(PlaybackPositionEvent event) { + if (currentlyPlayingItem != null && currentlyPlayingItem.getAdapterPosition() != RecyclerView.NO_POSITION) { + notifyItemChanged(currentlyPlayingItem.getAdapterPosition(), event); + } + } + @Nullable public FeedItem getSelectedItem() { return selectedItem; diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/ChaptersListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/ChaptersListAdapter.java index c3fac7e18..f6e6da8b4 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/ChaptersListAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/ChaptersListAdapter.java @@ -1,8 +1,8 @@ package de.danoeh.antennapod.adapter; import android.content.Context; -import android.support.annotation.NonNull; -import android.support.v4.content.ContextCompat; +import androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; import android.text.Layout; import android.text.Selection; import android.text.Spannable; diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/CoverLoader.java b/app/src/main/java/de/danoeh/antennapod/adapter/CoverLoader.java index 33f925e3f..098e9a616 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/CoverLoader.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/CoverLoader.java @@ -1,9 +1,8 @@ package de.danoeh.antennapod.adapter; import android.graphics.drawable.Drawable; -import android.os.Handler; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import android.view.View; import android.widget.ImageView; import android.widget.TextView; diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/DataFolderAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/DataFolderAdapter.java index 74bc84878..9014de525 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/DataFolderAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/DataFolderAdapter.java @@ -2,9 +2,9 @@ package de.danoeh.antennapod.adapter; import android.app.Dialog; import android.content.Context; -import android.support.annotation.NonNull; -import android.support.v4.content.ContextCompat; -import android.support.v7.widget.RecyclerView; +import androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; +import androidx.recyclerview.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; 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 789c01a26..b8764c2ae 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java @@ -2,7 +2,7 @@ package de.danoeh.antennapod.adapter; import android.content.Context; import android.os.Build; -import android.support.v4.content.ContextCompat; +import androidx.core.content.ContextCompat; import android.text.Layout; import android.text.format.DateUtils; import android.util.Log; diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java index d090bc4b1..aec0f0c91 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java @@ -3,7 +3,7 @@ package de.danoeh.antennapod.adapter; import android.content.Context; import android.content.res.TypedArray; import android.os.Build; -import android.support.v4.content.ContextCompat; +import androidx.core.content.ContextCompat; import android.text.Layout; import android.view.LayoutInflater; import android.view.View; @@ -13,15 +13,18 @@ import android.widget.BaseAdapter; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.LinearLayout; +import android.widget.ListView; import android.widget.ProgressBar; import android.widget.TextView; import de.danoeh.antennapod.R; import de.danoeh.antennapod.adapter.actionbutton.ItemActionButton; +import de.danoeh.antennapod.core.event.PlaybackPositionEvent; import de.danoeh.antennapod.core.feed.FeedItem; import de.danoeh.antennapod.core.feed.FeedMedia; import de.danoeh.antennapod.core.feed.MediaType; import de.danoeh.antennapod.core.storage.DownloadRequester; +import de.danoeh.antennapod.core.util.Converter; import de.danoeh.antennapod.core.util.DateUtils; import de.danoeh.antennapod.core.util.LongList; import de.danoeh.antennapod.core.util.ThemeUtils; @@ -39,6 +42,8 @@ public class FeedItemlistAdapter extends BaseAdapter { private final int playingBackGroundColor; private final int normalBackGroundColor; + private int currentlyPlayingItem = -1; + public FeedItemlistAdapter(Context context, ItemAccess itemAccess, boolean showFeedtitle, @@ -176,8 +181,9 @@ public class FeedItemlistAdapter extends BaseAdapter { } typeDrawables.recycle(); - if(media.isCurrentlyPlaying()) { + if (media.isCurrentlyPlaying()) { holder.container.setBackgroundColor(playingBackGroundColor); + currentlyPlayingItem = position; } else { holder.container.setBackgroundColor(normalBackGroundColor); } @@ -195,6 +201,20 @@ public class FeedItemlistAdapter extends BaseAdapter { return convertView; } + public void notifyCurrentlyPlayingItemChanged(PlaybackPositionEvent event, ListView listView) { + if (currentlyPlayingItem != -1 && currentlyPlayingItem < getCount()) { + View view = listView.getChildAt(currentlyPlayingItem + - listView.getFirstVisiblePosition() + listView.getHeaderViewsCount()); + if (view == null) { + return; + } + Holder holder = (Holder) view.getTag(); + holder.episodeProgress.setVisibility(View.VISIBLE); + holder.episodeProgress.setProgress((int) (100.0 * event.getPosition() / event.getDuration())); + holder.lenSize.setText(Converter.getDurationStringLong(event.getDuration() - event.getPosition())); + } + } + static class Holder { LinearLayout container; TextView title; 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 be8e52cfc..50b11a15b 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java @@ -7,7 +7,7 @@ import android.content.res.TypedArray; import android.graphics.Typeface; import android.graphics.drawable.Drawable; import android.preference.PreferenceManager; -import android.support.v7.app.AlertDialog; +import androidx.appcompat.app.AlertDialog; import android.util.TypedValue; import android.view.LayoutInflater; import android.view.View; diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java index 30057dde3..fcdcb4ba6 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java @@ -1,11 +1,12 @@ package de.danoeh.antennapod.adapter; import android.os.Build; -import android.support.annotation.Nullable; -import android.support.v4.content.ContextCompat; -import android.support.v4.view.MotionEventCompat; -import android.support.v7.widget.RecyclerView; -import android.support.v7.widget.helper.ItemTouchHelper; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.core.content.ContextCompat; +import androidx.core.view.MotionEventCompat; +import androidx.recyclerview.widget.RecyclerView; +import androidx.recyclerview.widget.ItemTouchHelper; import android.text.Layout; import android.text.TextUtils; import android.util.Log; @@ -24,9 +25,11 @@ import android.widget.TextView; import com.joanzapata.iconify.Iconify; +import de.danoeh.antennapod.core.event.PlaybackPositionEvent; import org.apache.commons.lang3.ArrayUtils; import java.lang.ref.WeakReference; +import java.util.List; import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.MainActivity; @@ -57,6 +60,7 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap private boolean locked; private FeedItem selectedItem; + private ViewHolder currentlyPlayingItem = null; private final int playingBackGroundColor; private final int normalBackGroundColor; @@ -93,6 +97,18 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap }); } + @Override + public void onBindViewHolder(@NonNull ViewHolder holder, int pos, List<Object> payload) { + onBindViewHolder(holder, pos); + + if (holder == currentlyPlayingItem && payload.size() == 1 && payload.get(0) instanceof PlaybackPositionEvent) { + PlaybackPositionEvent event = (PlaybackPositionEvent) payload.get(0); + holder.progressBar.setProgress((int) (100.0 * event.getPosition() / event.getDuration())); + holder.progressLeft.setText(Converter.getDurationStringLong(event.getPosition())); + holder.progressRight.setText(Converter.getDurationStringLong(event.getDuration())); + } + } + @Nullable public FeedItem getSelectedItem() { return selectedItem; @@ -108,6 +124,12 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap return itemAccess.getCount(); } + public void notifyCurrentlyPlayingItemChanged(PlaybackPositionEvent event) { + if (currentlyPlayingItem != null && currentlyPlayingItem.getAdapterPosition() != RecyclerView.NO_POSITION) { + notifyItemChanged(currentlyPlayingItem.getAdapterPosition(), event); + } + } + public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnCreateContextMenuListener, @@ -287,6 +309,7 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap if(media.isCurrentlyPlaying()) { container.setBackgroundColor(playingBackGroundColor); + currentlyPlayingItem = this; } else { container.setBackgroundColor(normalBackGroundColor); } diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/StatisticsListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/StatisticsListAdapter.java index 31e82dbe0..f013f2a49 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/StatisticsListAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/StatisticsListAdapter.java @@ -1,31 +1,30 @@ package de.danoeh.antennapod.adapter; import android.content.Context; +import androidx.annotation.NonNull; +import androidx.appcompat.app.AlertDialog; +import androidx.recyclerview.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.TextView; - import com.bumptech.glide.Glide; - -import java.util.ArrayList; -import java.util.List; - import com.bumptech.glide.request.RequestOptions; import de.danoeh.antennapod.R; -import de.danoeh.antennapod.core.feed.Feed; import de.danoeh.antennapod.core.glide.ApGlideSettings; import de.danoeh.antennapod.core.storage.DBReader; import de.danoeh.antennapod.core.util.Converter; +import de.danoeh.antennapod.view.PieChartView; /** * Adapter for the statistics list */ -public class StatisticsListAdapter extends BaseAdapter { +public class StatisticsListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { + private static final int TYPE_HEADER = 0; + private static final int TYPE_FEED = 1; private final Context context; - private List<DBReader.StatisticsItem> feedTime = new ArrayList<>(); + private DBReader.StatisticsData statisticsData; private boolean countAll = true; public StatisticsListAdapter(Context context) { @@ -37,66 +36,102 @@ public class StatisticsListAdapter extends BaseAdapter { } @Override - public int getCount() { - return feedTime.size(); + public int getItemCount() { + return statisticsData.feedTime.size() + 1; } - @Override public DBReader.StatisticsItem getItem(int position) { - return feedTime.get(position); + if (position == 0) { + return null; + } + return statisticsData.feedTime.get(position - 1); } @Override - public long getItemId(int position) { - return feedTime.get(position).feed.getId(); + public int getItemViewType(int position) { + return position == 0 ? TYPE_HEADER : TYPE_FEED; } + @NonNull @Override - public View getView(int position, View convertView, ViewGroup parent) { - StatisticsHolder holder; - Feed feed = feedTime.get(position).feed; - - if (convertView == null) { - holder = new StatisticsHolder(); - LayoutInflater inflater = (LayoutInflater) context - .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - - convertView = inflater.inflate(R.layout.statistics_listitem, parent, false); + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + LayoutInflater inflater = LayoutInflater.from(context); + if (viewType == TYPE_HEADER) { + return new HeaderHolder(inflater.inflate(R.layout.statistics_listitem_total_time, parent, false)); + } + return new StatisticsHolder(inflater.inflate(R.layout.statistics_listitem, parent, false)); + } - holder.image = convertView.findViewById(R.id.imgvCover); - holder.title = convertView.findViewById(R.id.txtvTitle); - holder.time = convertView.findViewById(R.id.txtvTime); - convertView.setTag(holder); + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder h, int position) { + if (getItemViewType(position) == TYPE_HEADER) { + HeaderHolder holder = (HeaderHolder) h; + long time = countAll ? statisticsData.totalTimeCountAll : statisticsData.totalTime; + holder.totalTime.setText(Converter.shortLocalizedDuration(context, time)); + float[] dataValues = new float[statisticsData.feedTime.size()]; + for (int i = 0; i < statisticsData.feedTime.size(); i++) { + DBReader.StatisticsItem item = statisticsData.feedTime.get(i); + dataValues[i] = countAll ? item.timePlayedCountAll : item.timePlayed; + } + holder.pieChart.setData(dataValues); } else { - holder = (StatisticsHolder) convertView.getTag(); + StatisticsHolder holder = (StatisticsHolder) h; + DBReader.StatisticsItem statsItem = statisticsData.feedTime.get(position - 1); + Glide.with(context) + .load(statsItem.feed.getImageLocation()) + .apply(new RequestOptions() + .placeholder(R.color.light_gray) + .error(R.color.light_gray) + .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY) + .fitCenter() + .dontAnimate()) + .into(holder.image); + + holder.title.setText(statsItem.feed.getTitle()); + long time = countAll ? statsItem.timePlayedCountAll : statsItem.timePlayed; + holder.time.setText(Converter.shortLocalizedDuration(context, time)); + + holder.itemView.setOnClickListener(v -> { + AlertDialog.Builder dialog = new AlertDialog.Builder(context); + dialog.setTitle(statsItem.feed.getTitle()); + dialog.setMessage(context.getString(R.string.statistics_details_dialog, + countAll ? statsItem.episodesStartedIncludingMarked : statsItem.episodesStarted, + statsItem.episodes, Converter.shortLocalizedDuration(context, + countAll ? statsItem.timePlayedCountAll : statsItem.timePlayed), + Converter.shortLocalizedDuration(context, statsItem.time))); + dialog.setPositiveButton(android.R.string.ok, null); + dialog.show(); + }); } - - Glide.with(context) - .load(feed.getImageLocation()) - .apply(new RequestOptions() - .placeholder(R.color.light_gray) - .error(R.color.light_gray) - .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY) - .fitCenter() - .dontAnimate()) - .into(holder.image); - - holder.title.setText(feed.getTitle()); - holder.time.setText(Converter.shortLocalizedDuration(context, - countAll ? feedTime.get(position).timePlayedCountAll - : feedTime.get(position).timePlayed)); - return convertView; } - public void update(List<DBReader.StatisticsItem> feedTime) { - this.feedTime = feedTime; + public void update(DBReader.StatisticsData statistics) { + this.statisticsData = statistics; notifyDataSetChanged(); } - static class StatisticsHolder { + static class HeaderHolder extends RecyclerView.ViewHolder { + TextView totalTime; + PieChartView pieChart; + + HeaderHolder(View itemView) { + super(itemView); + totalTime = itemView.findViewById(R.id.total_time); + pieChart = itemView.findViewById(R.id.pie_chart); + } + } + + static class StatisticsHolder extends RecyclerView.ViewHolder { ImageView image; TextView title; TextView time; + + StatisticsHolder(View itemView) { + super(itemView); + image = itemView.findViewById(R.id.imgvCover); + title = itemView.findViewById(R.id.txtvTitle); + time = itemView.findViewById(R.id.txtvTime); + } } } diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/SubscriptionsAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/SubscriptionsAdapter.java index e0fb65c61..5d52eb263 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/SubscriptionsAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/SubscriptionsAdapter.java @@ -1,7 +1,7 @@ package de.danoeh.antennapod.adapter; import android.content.Context; -import android.support.v4.app.Fragment; +import androidx.fragment.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -30,7 +30,6 @@ public class SubscriptionsAdapter extends BaseAdapter implements AdapterView.OnI public static final Object ADD_ITEM_OBJ = new Object(); /** the position in the view that holds the add item; 0 is the first, -1 is the last position */ - private static final int ADD_POSITION = -1; private static final String TAG = "SubscriptionsAdapter"; private final WeakReference<MainActivity> mainActivityRef; @@ -41,28 +40,14 @@ public class SubscriptionsAdapter extends BaseAdapter implements AdapterView.OnI this.itemAccess = itemAccess; } - private int getAddTilePosition() { - if(ADD_POSITION < 0) { - return ADD_POSITION + getCount(); - } - return ADD_POSITION; - } - - private int getAdjustedPosition(int origPosition) { - return origPosition < getAddTilePosition() ? origPosition : origPosition - 1; - } - @Override public int getCount() { - return 1 + itemAccess.getCount(); + return itemAccess.getCount(); } @Override public Object getItem(int position) { - if (position == getAddTilePosition()) { - return ADD_ITEM_OBJ; - } - return itemAccess.getItem(getAdjustedPosition(position)); + return itemAccess.getItem(position); } @Override @@ -72,10 +57,7 @@ public class SubscriptionsAdapter extends BaseAdapter implements AdapterView.OnI @Override public long getItemId(int position) { - if (position == getAddTilePosition()) { - return 0; - } - return itemAccess.getItem(getAdjustedPosition(position)).getId(); + return itemAccess.getItem(position).getId(); } @Override @@ -98,20 +80,6 @@ public class SubscriptionsAdapter extends BaseAdapter implements AdapterView.OnI holder = (Holder) convertView.getTag(); } - if (position == getAddTilePosition()) { - holder.feedTitle.setText("{md-add 500%}\n\n" + mainActivityRef.get().getString(R.string.add_feed_label)); - holder.feedTitle.setVisibility(View.VISIBLE); - // prevent any accidental re-use of old values (not sure how that would happen...) - holder.count.setPrimaryText(""); - // make it go away, we don't need it for add feed - holder.count.setVisibility(View.INVISIBLE); - - // when this holder is reused, we could else end up with a cover image - Glide.with(mainActivityRef.get()).clear(holder.imageView); - - return convertView; - } - final Feed feed = (Feed) getItem(position); if (feed == null) return null; @@ -137,12 +105,8 @@ public class SubscriptionsAdapter extends BaseAdapter implements AdapterView.OnI @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { - if (position == getAddTilePosition()) { - mainActivityRef.get().loadChildFragment(new AddFeedFragment()); - } else { - Fragment fragment = FeedItemlistFragment.newInstance(getItemId(position)); - mainActivityRef.get().loadChildFragment(fragment); - } + Fragment fragment = FeedItemlistFragment.newInstance(getItemId(position)); + mainActivityRef.get().loadChildFragment(fragment); } static class Holder { diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/AddToQueueActionButton.java b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/AddToQueueActionButton.java index 3299db3ab..a8001eeb1 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/AddToQueueActionButton.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/AddToQueueActionButton.java @@ -1,8 +1,8 @@ package de.danoeh.antennapod.adapter.actionbutton; import android.content.Context; -import android.support.annotation.AttrRes; -import android.support.annotation.StringRes; +import androidx.annotation.AttrRes; +import androidx.annotation.StringRes; import de.danoeh.antennapod.R; import de.danoeh.antennapod.core.feed.FeedItem; diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/CancelDownloadActionButton.java b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/CancelDownloadActionButton.java index 1275a799b..10458ed46 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/CancelDownloadActionButton.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/CancelDownloadActionButton.java @@ -1,8 +1,8 @@ package de.danoeh.antennapod.adapter.actionbutton; import android.content.Context; -import android.support.annotation.AttrRes; -import android.support.annotation.StringRes; +import androidx.annotation.AttrRes; +import androidx.annotation.StringRes; import android.widget.Toast; import de.danoeh.antennapod.R; diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/DownloadActionButton.java b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/DownloadActionButton.java index c1559528e..55ca5471b 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/DownloadActionButton.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/DownloadActionButton.java @@ -1,9 +1,9 @@ package de.danoeh.antennapod.adapter.actionbutton; import android.content.Context; -import android.support.annotation.AttrRes; -import android.support.annotation.NonNull; -import android.support.annotation.StringRes; +import androidx.annotation.AttrRes; +import androidx.annotation.NonNull; +import androidx.annotation.StringRes; import android.widget.Toast; import de.danoeh.antennapod.R; diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/ItemActionButton.java b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/ItemActionButton.java index 6dbeccfc9..31e9fccb5 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/ItemActionButton.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/ItemActionButton.java @@ -2,9 +2,9 @@ package de.danoeh.antennapod.adapter.actionbutton; import android.content.Context; import android.content.res.TypedArray; -import android.support.annotation.AttrRes; -import android.support.annotation.NonNull; -import android.support.annotation.StringRes; +import androidx.annotation.AttrRes; +import androidx.annotation.NonNull; +import androidx.annotation.StringRes; import android.view.View; import android.widget.ImageButton; diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/MarkAsPlayedActionButton.java b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/MarkAsPlayedActionButton.java index 4d906cee5..354ded73d 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/MarkAsPlayedActionButton.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/MarkAsPlayedActionButton.java @@ -1,8 +1,8 @@ package de.danoeh.antennapod.adapter.actionbutton; import android.content.Context; -import android.support.annotation.AttrRes; -import android.support.annotation.StringRes; +import androidx.annotation.AttrRes; +import androidx.annotation.StringRes; import android.view.View; import de.danoeh.antennapod.R; diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/PlayActionButton.java b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/PlayActionButton.java index 3992c7240..23a7e03ad 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/PlayActionButton.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/PlayActionButton.java @@ -1,8 +1,8 @@ package de.danoeh.antennapod.adapter.actionbutton; import android.content.Context; -import android.support.annotation.AttrRes; -import android.support.annotation.StringRes; +import androidx.annotation.AttrRes; +import androidx.annotation.StringRes; import de.danoeh.antennapod.R; import de.danoeh.antennapod.core.feed.FeedItem; diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/itunes/ItunesAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/itunes/ItunesAdapter.java index f5213e4ab..cc3b6fba0 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/itunes/ItunesAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/itunes/ItunesAdapter.java @@ -1,7 +1,7 @@ package de.danoeh.antennapod.adapter.itunes; import android.content.Context; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; diff --git a/app/src/main/java/de/danoeh/antennapod/asynctask/DocumentFileExportWorker.java b/app/src/main/java/de/danoeh/antennapod/asynctask/DocumentFileExportWorker.java index 0e9572a82..339a98dfa 100644 --- a/app/src/main/java/de/danoeh/antennapod/asynctask/DocumentFileExportWorker.java +++ b/app/src/main/java/de/danoeh/antennapod/asynctask/DocumentFileExportWorker.java @@ -2,8 +2,8 @@ package de.danoeh.antennapod.asynctask; import android.content.Context; import android.net.Uri; -import android.support.annotation.NonNull; -import android.support.v4.provider.DocumentFile; +import androidx.annotation.NonNull; +import androidx.documentfile.provider.DocumentFile; import java.io.FileNotFoundException; import java.io.IOException; diff --git a/app/src/main/java/de/danoeh/antennapod/asynctask/ExportWorker.java b/app/src/main/java/de/danoeh/antennapod/asynctask/ExportWorker.java index 219725b01..40b101ddf 100644 --- a/app/src/main/java/de/danoeh/antennapod/asynctask/ExportWorker.java +++ b/app/src/main/java/de/danoeh/antennapod/asynctask/ExportWorker.java @@ -1,6 +1,6 @@ package de.danoeh.antennapod.asynctask; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import android.util.Log; import java.io.File; diff --git a/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlImportWorker.java b/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlImportWorker.java index 13b95907f..b88b58537 100644 --- a/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlImportWorker.java +++ b/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlImportWorker.java @@ -3,7 +3,7 @@ package de.danoeh.antennapod.asynctask; import android.app.ProgressDialog; import android.content.Context; import android.os.AsyncTask; -import android.support.v7.app.AlertDialog; +import androidx.appcompat.app.AlertDialog; import android.util.Log; import org.xmlpull.v1.XmlPullParserException; 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 ed35495fa..f6d08b7bf 100644 --- a/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java @@ -4,16 +4,16 @@ import android.app.AlertDialog; import android.content.res.TypedArray; import android.graphics.drawable.Drawable; import android.os.Bundle; -import android.support.annotation.IdRes; -import android.support.annotation.NonNull; -import android.support.annotation.PluralsRes; -import android.support.annotation.StringRes; -import android.support.design.widget.Snackbar; -import android.support.v4.app.ActivityCompat; -import android.support.v4.app.Fragment; -import android.support.v4.util.ArrayMap; -import android.support.v7.app.ActionBar; -import android.support.v7.app.AppCompatActivity; +import androidx.annotation.IdRes; +import androidx.annotation.NonNull; +import androidx.annotation.PluralsRes; +import androidx.annotation.StringRes; +import com.google.android.material.snackbar.Snackbar; +import androidx.core.app.ActivityCompat; +import androidx.fragment.app.Fragment; +import androidx.collection.ArrayMap; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AppCompatActivity; import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/FilterDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/FilterDialog.java index 607084c42..d2912f90f 100644 --- a/app/src/main/java/de/danoeh/antennapod/dialog/FilterDialog.java +++ b/app/src/main/java/de/danoeh/antennapod/dialog/FilterDialog.java @@ -1,7 +1,7 @@ package de.danoeh.antennapod.dialog; import android.content.Context; -import android.support.v7.app.AlertDialog; +import androidx.appcompat.app.AlertDialog; import android.text.TextUtils; import java.util.Arrays; diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/GpodnetSetHostnameDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/GpodnetSetHostnameDialog.java index 933ced0f9..17668586b 100644 --- a/app/src/main/java/de/danoeh/antennapod/dialog/GpodnetSetHostnameDialog.java +++ b/app/src/main/java/de/danoeh/antennapod/dialog/GpodnetSetHostnameDialog.java @@ -1,7 +1,7 @@ package de.danoeh.antennapod.dialog; import android.content.Context; -import android.support.v7.app.AlertDialog; +import androidx.appcompat.app.AlertDialog; import android.text.Editable; import android.text.InputType; import android.view.View; diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/PlaybackControlsDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/PlaybackControlsDialog.java index e8c7520b7..f53dbe57a 100644 --- a/app/src/main/java/de/danoeh/antennapod/dialog/PlaybackControlsDialog.java +++ b/app/src/main/java/de/danoeh/antennapod/dialog/PlaybackControlsDialog.java @@ -2,20 +2,21 @@ package de.danoeh.antennapod.dialog; import android.app.Dialog; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v4.app.DialogFragment; +import androidx.annotation.NonNull; +import androidx.fragment.app.DialogFragment; import android.widget.Button; import android.widget.CheckBox; import android.widget.SeekBar; import android.widget.TextView; import com.afollestad.materialdialogs.MaterialDialog; +import java.util.Locale; import de.danoeh.antennapod.R; +import de.danoeh.antennapod.core.preferences.PlaybackSpeedHelper; import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.core.util.Converter; +import de.danoeh.antennapod.core.util.playback.Playable; import de.danoeh.antennapod.core.util.playback.PlaybackController; -import java.util.Locale; - public class PlaybackControlsDialog extends DialogFragment { private static final float PLAYBACK_SPEED_STEP = 0.05f; private static final float DEFAULT_MIN_PLAYBACK_SPEED = 0.5f; @@ -206,9 +207,11 @@ public class PlaybackControlsDialog extends DialogFragment { } private float getCurrentSpeed() { - if (isPlayingVideo) { - return UserPreferences.getVideoPlaybackSpeed(); + Playable media = null; + if (controller != null) { + media = controller.getMedia(); } - return UserPreferences.getPlaybackSpeed(); + + return PlaybackSpeedHelper.getCurrentPlaybackSpeed(media); } } diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/ProxyDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/ProxyDialog.java index c1008a380..0499d02f1 100644 --- a/app/src/main/java/de/danoeh/antennapod/dialog/ProxyDialog.java +++ b/app/src/main/java/de/danoeh/antennapod/dialog/ProxyDialog.java @@ -4,7 +4,7 @@ import android.app.Dialog; import android.content.Context; import android.content.res.TypedArray; import android.os.Build; -import android.support.v4.content.ContextCompat; +import androidx.core.content.ContextCompat; import android.text.Editable; import android.text.TextUtils; import android.text.TextWatcher; diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/RatingDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/RatingDialog.java index 5969963f2..c49e9153e 100644 --- a/app/src/main/java/de/danoeh/antennapod/dialog/RatingDialog.java +++ b/app/src/main/java/de/danoeh/antennapod/dialog/RatingDialog.java @@ -2,11 +2,9 @@ package de.danoeh.antennapod.dialog; import android.app.Dialog; import android.content.Context; -import android.content.Intent; import android.content.SharedPreferences; -import android.net.Uri; -import android.support.annotation.Nullable; -import android.support.annotation.VisibleForTesting; +import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; import android.util.Log; import com.afollestad.materialdialogs.MaterialDialog; diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/VariableSpeedDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/VariableSpeedDialog.java index bf3faf89a..1cf34b2b3 100644 --- a/app/src/main/java/de/danoeh/antennapod/dialog/VariableSpeedDialog.java +++ b/app/src/main/java/de/danoeh/antennapod/dialog/VariableSpeedDialog.java @@ -5,7 +5,7 @@ import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.Build; -import android.support.v7.app.AlertDialog; +import androidx.appcompat.app.AlertDialog; import android.util.Log; import android.view.View; diff --git a/app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearchResult.java b/app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearchResult.java index ca9ed83d7..6535df5ef 100644 --- a/app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearchResult.java +++ b/app/src/main/java/de/danoeh/antennapod/discovery/PodcastSearchResult.java @@ -1,6 +1,6 @@ package de.danoeh.antennapod.discovery; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import de.danoeh.antennapod.core.gpoddernet.model.GpodnetPodcast; import de.mfietz.fyydlin.SearchHit; import org.json.JSONArray; diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java index 3ef010f88..b7bfe3438 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java @@ -2,20 +2,15 @@ package de.danoeh.antennapod.fragment; import android.content.Intent; import android.os.Bundle; -import android.provider.MediaStore; -import android.support.v4.app.Fragment; +import androidx.fragment.app.Fragment; import android.view.ContextMenu; -import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; -import android.view.inputmethod.EditorInfo; import android.widget.Button; import android.widget.EditText; -import android.widget.ImageView; -import android.widget.TextView; import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.MainActivity; import de.danoeh.antennapod.activity.OnlineFeedViewActivity; diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java index bb52b26b7..3949a03a9 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java @@ -1,9 +1,9 @@ package de.danoeh.antennapod.fragment; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.RecyclerView; +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; 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 bb8f4df9a..2df28b262 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/ChaptersFragment.java @@ -1,7 +1,7 @@ package de.danoeh.antennapod.fragment; import android.os.Bundle; -import android.support.v4.app.ListFragment; +import androidx.fragment.app.ListFragment; import android.util.Log; import android.view.View; import android.widget.ListView; diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/CombinedSearchFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/CombinedSearchFragment.java index 1d9020f0d..5ab781fe3 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/CombinedSearchFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/CombinedSearchFragment.java @@ -2,9 +2,9 @@ package de.danoeh.antennapod.fragment; import android.content.Intent; import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.support.v4.view.MenuItemCompat; -import android.support.v7.widget.SearchView; +import androidx.fragment.app.Fragment; +import androidx.core.view.MenuItemCompat; +import androidx.appcompat.widget.SearchView; import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; 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 705151062..1917e4c75 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java @@ -1,8 +1,8 @@ package de.danoeh.antennapod.fragment; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v4.app.ListFragment; +import androidx.annotation.NonNull; +import androidx.fragment.app.ListFragment; import android.util.Log; import android.view.Menu; import android.view.MenuInflater; diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java index db9dd9530..cf9ee6c41 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java @@ -1,8 +1,8 @@ package de.danoeh.antennapod.fragment; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v4.app.Fragment; +import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; import android.util.Log; import android.view.LayoutInflater; import android.view.View; diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java index 26b115b4b..528c50747 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java @@ -4,8 +4,8 @@ import android.app.AlertDialog; import android.app.Dialog; import android.content.res.TypedArray; import android.os.Bundle; -import android.support.v4.app.ListFragment; -import android.support.v4.view.MenuItemCompat; +import androidx.fragment.app.ListFragment; +import androidx.core.view.MenuItemCompat; import android.util.Log; import android.view.Menu; import android.view.MenuInflater; diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/DownloadsFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/DownloadsFragment.java index aa6029c84..b1bcdf404 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/DownloadsFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/DownloadsFragment.java @@ -4,11 +4,11 @@ import android.content.Context; import android.content.SharedPreferences; import android.content.res.Resources; import android.os.Bundle; -import android.support.design.widget.TabLayout; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentManager; -import android.support.v4.app.FragmentPagerAdapter; -import android.support.v4.view.ViewPager; +import com.google.android.material.tabs.TabLayout; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentPagerAdapter; +import androidx.viewpager.widget.ViewPager; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesFragment.java index ca21df661..8cdec9f38 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesFragment.java @@ -4,11 +4,11 @@ import android.content.Context; import android.content.SharedPreferences; import android.content.res.Resources; import android.os.Bundle; -import android.support.design.widget.TabLayout; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentManager; -import android.support.v4.app.FragmentPagerAdapter; -import android.support.v4.view.ViewPager; +import com.google.android.material.tabs.TabLayout; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentPagerAdapter; +import androidx.viewpager.widget.ViewPager; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java index c0c23685a..3fc67f795 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java @@ -4,13 +4,13 @@ import android.content.Context; import android.content.DialogInterface; import android.content.SharedPreferences; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v4.app.Fragment; -import android.support.v4.view.MenuItemCompat; -import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.RecyclerView; -import android.support.v7.widget.SearchView; -import android.support.v7.widget.SimpleItemAnimator; +import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; +import androidx.core.view.MenuItemCompat; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import androidx.appcompat.widget.SearchView; +import androidx.recyclerview.widget.SimpleItemAnimator; import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; @@ -24,6 +24,7 @@ import android.widget.Toast; import com.yqritc.recyclerviewflexibledivider.HorizontalDividerItemDecoration; +import de.danoeh.antennapod.core.event.PlaybackPositionEvent; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; @@ -384,6 +385,13 @@ public abstract class EpisodesListFragment extends Fragment { } } + @Subscribe(threadMode = ThreadMode.MAIN) + public void onEventMainThread(PlaybackPositionEvent event) { + if (listAdapter != null) { + listAdapter.notifyCurrentlyPlayingItemChanged(event); + } + } + protected boolean shouldUpdatedItemRemainInList(FeedItem item) { return true; } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java index 348c73b92..bbc33c6ca 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java @@ -3,8 +3,8 @@ package de.danoeh.antennapod.fragment; import android.content.Intent; import android.os.Build; import android.os.Bundle; -import android.support.v4.app.ActivityOptionsCompat; -import android.support.v4.app.Fragment; +import androidx.core.app.ActivityOptionsCompat; +import androidx.fragment.app.Fragment; import android.util.Log; import android.view.LayoutInflater; import android.view.View; @@ -18,7 +18,7 @@ import com.bumptech.glide.Glide; import com.bumptech.glide.request.RequestOptions; import de.danoeh.antennapod.R; -import de.danoeh.antennapod.core.event.ServiceEvent; +import de.danoeh.antennapod.core.event.PlaybackPositionEvent; import de.danoeh.antennapod.core.feed.MediaType; import de.danoeh.antennapod.core.glide.ApGlideSettings; import de.danoeh.antennapod.core.service.playback.PlaybackService; @@ -28,6 +28,9 @@ import io.reactivex.Maybe; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.Disposable; import io.reactivex.schedulers.Schedulers; +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; /** * Fragment which is supposed to be displayed outside of the MediaplayerActivity @@ -138,6 +141,7 @@ public class ExternalPlayerFragment extends Fragment { controller = setupPlaybackController(); controller.init(); loadMediaInfo(); + EventBus.getDefault().register(this); } @Override @@ -147,6 +151,12 @@ public class ExternalPlayerFragment extends Fragment { controller.release(); controller = null; } + EventBus.getDefault().unregister(this); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onEventMainThread(PlaybackPositionEvent event) { + onPositionObserverUpdate(); } @Override 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 536ebd468..5282a6bb2 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java @@ -1,13 +1,12 @@ package de.danoeh.antennapod.fragment; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.design.widget.Snackbar; -import android.support.v7.widget.RecyclerView; -import android.support.v7.widget.helper.ItemTouchHelper; +import androidx.annotation.NonNull; +import com.google.android.material.snackbar.Snackbar; +import androidx.recyclerview.widget.RecyclerView; +import androidx.recyclerview.widget.ItemTouchHelper; import android.util.Log; import android.view.LayoutInflater; -import android.view.Menu; import android.view.View; import android.view.ViewGroup; diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FeedInfoFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FeedInfoFragment.java new file mode 100644 index 000000000..6b270e220 --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/fragment/FeedInfoFragment.java @@ -0,0 +1,234 @@ +package de.danoeh.antennapod.fragment; + +import android.content.ClipData; +import android.content.Context; +import android.content.Intent; +import android.graphics.LightingColorFilter; +import android.net.Uri; +import android.os.Bundle; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import android.text.TextUtils; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; +import android.widget.Toast; +import com.bumptech.glide.Glide; +import com.bumptech.glide.request.RequestOptions; +import com.joanzapata.iconify.Iconify; +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.activity.MainActivity; +import de.danoeh.antennapod.core.dialog.DownloadRequestErrorDialogCreator; +import de.danoeh.antennapod.core.feed.Feed; +import de.danoeh.antennapod.core.glide.ApGlideSettings; +import de.danoeh.antennapod.core.glide.FastBlurTransformation; +import de.danoeh.antennapod.core.storage.DBReader; +import de.danoeh.antennapod.core.storage.DownloadRequestException; +import de.danoeh.antennapod.core.util.IntentUtils; +import de.danoeh.antennapod.core.util.LangUtils; +import de.danoeh.antennapod.core.util.syndication.HtmlToPlainText; +import de.danoeh.antennapod.menuhandler.FeedMenuHandler; +import io.reactivex.Maybe; +import io.reactivex.MaybeOnSubscribe; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.Disposable; +import io.reactivex.schedulers.Schedulers; +import org.apache.commons.lang3.StringUtils; +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; + +/** + * Displays information about a feed. + */ +public class FeedInfoFragment extends Fragment { + + private static final String EXTRA_FEED_ID = "de.danoeh.antennapod.extra.feedId"; + private static final String TAG = "FeedInfoActivity"; + + private Feed feed; + private Disposable disposable; + private ImageView imgvCover; + private TextView txtvTitle; + private TextView txtvDescription; + private TextView lblLanguage; + private TextView txtvLanguage; + private TextView lblAuthor; + private TextView txtvAuthor; + private TextView txtvUrl; + private TextView txtvAuthorHeader; + private ImageView imgvBackground; + + public static FeedInfoFragment newInstance(Feed feed) { + FeedInfoFragment fragment = new FeedInfoFragment(); + Bundle arguments = new Bundle(); + arguments.putLong(EXTRA_FEED_ID, feed.getId()); + fragment.setArguments(arguments); + return fragment; + } + + private final View.OnClickListener copyUrlToClipboard = new View.OnClickListener() { + @Override + public void onClick(View v) { + if(feed != null && feed.getDownload_url() != null) { + String url = feed.getDownload_url(); + ClipData clipData = ClipData.newPlainText(url, url); + android.content.ClipboardManager cm = (android.content.ClipboardManager) getContext() + .getSystemService(Context.CLIPBOARD_SERVICE); + cm.setPrimaryClip(clipData); + Toast t = Toast.makeText(getContext(), R.string.copied_url_msg, Toast.LENGTH_SHORT); + t.show(); + } + } + }; + + @Override + public void onResume() { + super.onResume(); + ((MainActivity)getActivity()).getSupportActionBar().setTitle(R.string.feed_info_label); + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View root = inflater.inflate(R.layout.feedinfo, null); + setHasOptionsMenu(true); + + imgvCover = root.findViewById(R.id.imgvCover); + txtvTitle = root.findViewById(R.id.txtvTitle); + txtvAuthorHeader = root.findViewById(R.id.txtvAuthor); + imgvBackground = root.findViewById(R.id.imgvBackground); + root.findViewById(R.id.butShowInfo).setVisibility(View.INVISIBLE); + root.findViewById(R.id.butShowSettings).setVisibility(View.INVISIBLE); + // https://github.com/bumptech/glide/issues/529 + imgvBackground.setColorFilter(new LightingColorFilter(0xff828282, 0x000000)); + + + txtvDescription = root.findViewById(R.id.txtvDescription); + lblLanguage = root.findViewById(R.id.lblLanguage); + txtvLanguage = root.findViewById(R.id.txtvLanguage); + lblAuthor = root.findViewById(R.id.lblAuthor); + txtvAuthor = root.findViewById(R.id.txtvDetailsAuthor); + txtvUrl = root.findViewById(R.id.txtvUrl); + + txtvUrl.setOnClickListener(copyUrlToClipboard); + postponeEnterTransition(); + return root; + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + long feedId = getArguments().getLong(EXTRA_FEED_ID); + disposable = Maybe.create((MaybeOnSubscribe<Feed>) emitter -> { + Feed feed = DBReader.getFeed(feedId); + if (feed != null) { + emitter.onSuccess(feed); + } else { + emitter.onComplete(); + } + }) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(result -> { + feed = result; + showFeed(); + }, error -> Log.d(TAG, Log.getStackTraceString(error)), + this::startPostponedEnterTransition); + } + + private void showFeed() { + Log.d(TAG, "Language is " + feed.getLanguage()); + Log.d(TAG, "Author is " + feed.getAuthor()); + Log.d(TAG, "URL is " + feed.getDownload_url()); + Glide.with(getContext()) + .load(feed.getImageLocation()) + .apply(new RequestOptions() + .placeholder(R.color.light_gray) + .error(R.color.light_gray) + .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY) + .fitCenter() + .dontAnimate()) + .into(imgvCover); + Glide.with(getContext()) + .load(feed.getImageLocation()) + .apply(new RequestOptions() + .placeholder(R.color.image_readability_tint) + .error(R.color.image_readability_tint) + .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY) + .transform(new FastBlurTransformation()) + .dontAnimate()) + .into(imgvBackground); + + txtvTitle.setText(feed.getTitle()); + + String description = feed.getDescription(); + if(description != null) { + if(Feed.TYPE_ATOM1.equals(feed.getType())) { + HtmlToPlainText formatter = new HtmlToPlainText(); + Document feedDescription = Jsoup.parse(feed.getDescription()); + description = StringUtils.trim(formatter.getPlainText(feedDescription)); + } + } else { + description = ""; + } + txtvDescription.setText(description); + + if (!TextUtils.isEmpty(feed.getAuthor())) { + txtvAuthor.setText(feed.getAuthor()); + txtvAuthorHeader.setText(feed.getAuthor()); + } else { + lblAuthor.setVisibility(View.GONE); + txtvAuthor.setVisibility(View.GONE); + } + if (!TextUtils.isEmpty(feed.getLanguage())) { + txtvLanguage.setText(LangUtils.getLanguageString(feed.getLanguage())); + } else { + lblLanguage.setVisibility(View.GONE); + txtvLanguage.setVisibility(View.GONE); + } + txtvUrl.setText(feed.getDownload_url() + " {fa-paperclip}"); + Iconify.addIcons(txtvUrl); + + getActivity().invalidateOptionsMenu(); + } + + @Override + public void onDestroy() { + super.onDestroy(); + if (disposable != null) { + disposable.dispose(); + } + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + super.onCreateOptionsMenu(menu, inflater); + inflater.inflate(R.menu.feedinfo, menu); + } + + @Override + public void onPrepareOptionsMenu(Menu menu) { + super.onPrepareOptionsMenu(menu); + menu.findItem(R.id.share_link_item).setVisible(feed != null && feed.getLink() != null); + menu.findItem(R.id.visit_website_item).setVisible(feed != null && feed.getLink() != null && + IntentUtils.isCallable(getContext(), new Intent(Intent.ACTION_VIEW, Uri.parse(feed.getLink())))); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + boolean handled = false; + try { + handled = FeedMenuHandler.onOptionsItemClicked(getContext(), item, feed); + } catch (DownloadRequestException e) { + e.printStackTrace(); + DownloadRequestErrorDialogCreator.newRequestErrorDialog(getContext(), e.getMessage()); + } + return handled || super.onOptionsItemSelected(item); + } +} diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java index 1aad74466..0c33dce5a 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java @@ -3,13 +3,12 @@ package de.danoeh.antennapod.fragment; import android.annotation.SuppressLint; import android.content.Context; import android.content.DialogInterface; -import android.content.Intent; import android.graphics.LightingColorFilter; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v4.app.ListFragment; -import android.support.v4.view.MenuItemCompat; -import android.support.v7.widget.SearchView; +import androidx.annotation.NonNull; +import androidx.fragment.app.ListFragment; +import androidx.core.view.MenuItemCompat; +import androidx.appcompat.widget.SearchView; import android.util.Log; import android.view.ContextMenu; import android.view.LayoutInflater; @@ -29,6 +28,7 @@ import com.bumptech.glide.request.RequestOptions; import com.joanzapata.iconify.Iconify; import com.joanzapata.iconify.widget.IconTextView; +import de.danoeh.antennapod.core.event.PlaybackPositionEvent; import org.apache.commons.lang3.Validate; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; @@ -37,8 +37,6 @@ import org.greenrobot.eventbus.ThreadMode; import java.util.List; import de.danoeh.antennapod.R; -import de.danoeh.antennapod.activity.FeedInfoActivity; -import de.danoeh.antennapod.activity.FeedSettingsActivity; import de.danoeh.antennapod.activity.MainActivity; import de.danoeh.antennapod.adapter.FeedItemlistAdapter; import de.danoeh.antennapod.core.asynctask.FeedRemover; @@ -140,37 +138,33 @@ public class FeedItemlistFragment extends ListFragment { } @Override - public void onStart() { - super.onStart(); + public void onHiddenChanged(boolean hidden) { + super.onHiddenChanged(hidden); + if (!hidden && getActivity() != null) { + ((MainActivity) getActivity()).getSupportActionBar().setTitle(""); + } + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + registerForContextMenu(getListView()); + EventDistributor.getInstance().register(contentUpdate); EventBus.getDefault().register(this); loadItems(); } @Override - public void onResume() { - super.onResume(); - ((MainActivity)getActivity()).getSupportActionBar().setTitle(""); - updateProgressBarVisibility(); - } + public void onDestroyView() { + super.onDestroyView(); - @Override - public void onStop() { - super.onStop(); EventDistributor.getInstance().unregister(contentUpdate); EventBus.getDefault().unregister(this); - if(disposable != null) { + if (disposable != null) { disposable.dispose(); } - } - - @Override - public void onDestroyView() { - super.onDestroyView(); - resetViewState(); - } - - private void resetViewState() { adapter = null; listFooter = null; } @@ -344,13 +338,6 @@ public class FeedItemlistFragment extends ListFragment { } @Override - public void onViewCreated(View view, Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - - registerForContextMenu(getListView()); - } - - @Override public void onListItemClick(ListView l, View v, int position, long id) { if(adapter == null) { return; @@ -398,6 +385,13 @@ public class FeedItemlistFragment extends ListFragment { } } + @Subscribe(threadMode = ThreadMode.MAIN) + public void onEventMainThread(PlaybackPositionEvent event) { + if (adapter != null) { + adapter.notifyCurrentlyPlayingItemChanged(event, getListView()); + } + } + private final EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() { @Override @@ -421,8 +415,9 @@ public class FeedItemlistFragment extends ListFragment { } - private void onFragmentLoaded() { - if(!isVisible()) { + private void displayList() { + if (getView() == null) { + Log.e(TAG, "Required root view is not yet created. Stop binding data to UI."); return; } if (adapter == null) { @@ -506,10 +501,8 @@ public class FeedItemlistFragment extends ListFragment { imgvCover.setOnClickListener(v -> showFeedInfo()); butShowSettings.setOnClickListener(v -> { if (feed != null) { - Intent startIntent = new Intent(getActivity(), FeedSettingsActivity.class); - startIntent.putExtra(FeedSettingsActivity.EXTRA_FEED_ID, - feed.getId()); - startActivity(startIntent); + FeedSettingsFragment fragment = FeedSettingsFragment.newInstance(feed); + ((MainActivity) getActivity()).loadChildFragment(fragment, TransitionEffect.FLIP); } }); headerCreated = true; @@ -517,10 +510,8 @@ public class FeedItemlistFragment extends ListFragment { private void showFeedInfo() { if (feed != null) { - Intent startIntent = new Intent(getActivity(), FeedInfoActivity.class); - startIntent.putExtra(FeedInfoActivity.EXTRA_FEED_ID, - feed.getId()); - startActivity(startIntent); + FeedInfoFragment fragment = FeedInfoFragment.newInstance(feed); + ((MainActivity) getActivity()).loadChildFragment(fragment, TransitionEffect.FLIP); } } @@ -626,7 +617,7 @@ public class FeedItemlistFragment extends ListFragment { .observeOn(AndroidSchedulers.mainThread()) .subscribe(result -> { feed = result.orElse(null); - onFragmentLoaded(); + displayList(); }, error -> Log.e(TAG, Log.getStackTraceString(error))); } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java index 4fb3d90f5..b745313aa 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java @@ -1,49 +1,134 @@ package de.danoeh.antennapod.fragment; -import android.arch.lifecycle.ViewModelProviders; import android.content.Context; import android.content.DialogInterface; import android.os.Bundle; -import android.support.v14.preference.SwitchPreference; -import android.support.v7.preference.ListPreference; -import android.support.v7.preference.PreferenceFragmentCompat; +import androidx.preference.SwitchPreference; +import androidx.preference.ListPreference; +import androidx.preference.PreferenceFragmentCompat; +import android.util.Log; import de.danoeh.antennapod.R; +import de.danoeh.antennapod.activity.MainActivity; import de.danoeh.antennapod.core.dialog.ConfirmationDialog; import de.danoeh.antennapod.core.feed.Feed; import de.danoeh.antennapod.core.feed.FeedFilter; import de.danoeh.antennapod.core.feed.FeedPreferences; 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.AuthenticationDialog; import de.danoeh.antennapod.dialog.EpisodeFilterDialog; -import de.danoeh.antennapod.viewmodel.FeedSettingsViewModel; +import io.reactivex.Maybe; +import io.reactivex.MaybeOnSubscribe; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.Disposable; +import io.reactivex.schedulers.Schedulers; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.util.Locale; -import static de.danoeh.antennapod.activity.FeedSettingsActivity.EXTRA_FEED_ID; +import static de.danoeh.antennapod.core.feed.FeedPreferences.SPEED_USE_GLOBAL; public class FeedSettingsFragment extends PreferenceFragmentCompat { private static final CharSequence PREF_EPISODE_FILTER = "episodeFilter"; + private static final String PREF_FEED_PLAYBACK_SPEED = "feedPlaybackSpeed"; + private static final DecimalFormat decimalFormat = new DecimalFormat("0.00", DecimalFormatSymbols.getInstance(Locale.US)); + private static final String EXTRA_FEED_ID = "de.danoeh.antennapod.extra.feedId"; + private static final String TAG = "FeedSettingsFragment"; + private Feed feed; + private Disposable disposable; private FeedPreferences feedPreferences; + public static FeedSettingsFragment newInstance(Feed feed) { + FeedSettingsFragment fragment = new FeedSettingsFragment(); + Bundle arguments = new Bundle(); + arguments.putLong(EXTRA_FEED_ID, feed.getId()); + fragment.setArguments(arguments); + return fragment; + } + @Override public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { addPreferencesFromResource(R.xml.feed_settings); + postponeEnterTransition(); long feedId = getArguments().getLong(EXTRA_FEED_ID); - ViewModelProviders.of(getActivity()).get(FeedSettingsViewModel.class).getFeed(feedId) + disposable = Maybe.create((MaybeOnSubscribe<Feed>) emitter -> { + Feed feed = DBReader.getFeed(feedId); + if (feed != null) { + emitter.onSuccess(feed); + } else { + emitter.onComplete(); + } + }) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) .subscribe(result -> { feed = result; feedPreferences = feed.getPreferences(); + ((MainActivity) getActivity()).getSupportActionBar().setSubtitle(feed.getTitle()); setupAutoDownloadPreference(); setupKeepUpdatedPreference(); setupAutoDeletePreference(); setupAuthentificationPreference(); setupEpisodeFilterPreference(); + setupPlaybackSpeedPreference(); updateAutoDeleteSummary(); updateAutoDownloadEnabled(); - }).dispose(); + updatePlaybackSpeedPreference(); + }, error -> Log.d(TAG, Log.getStackTraceString(error)), + this::startPostponedEnterTransition); + } + + @Override + public void onResume() { + super.onResume(); + ((MainActivity) getActivity()).getSupportActionBar().setTitle(R.string.feed_settings_label); + if (feed != null) { + ((MainActivity) getActivity()).getSupportActionBar().setSubtitle(feed.getTitle()); + } + } + + @Override + public void onStop() { + super.onStop(); + ((MainActivity) getActivity()).getSupportActionBar().setSubtitle(null); + } + + @Override + public void onDestroy() { + super.onDestroy(); + if (disposable != null) { + disposable.dispose(); + } + } + + private void setupPlaybackSpeedPreference() { + ListPreference feedPlaybackSpeedPreference = findPreference(PREF_FEED_PLAYBACK_SPEED); + + String[] speeds = UserPreferences.getPlaybackSpeedArray(); + + String[] values = new String[speeds.length + 1]; + values[0] = decimalFormat.format(SPEED_USE_GLOBAL); + + String[] entries = new String[speeds.length + 1]; + entries[0] = getString(R.string.feed_auto_download_global); + + System.arraycopy(speeds, 0, values, 1, speeds.length); + System.arraycopy(speeds, 0, entries, 1, speeds.length); + + feedPlaybackSpeedPreference.setEntryValues(values); + feedPlaybackSpeedPreference.setEntries(entries); + + feedPlaybackSpeedPreference.setOnPreferenceChangeListener((preference, newValue) -> { + feedPreferences.setFeedPlaybackSpeed(Float.parseFloat((String) newValue)); + feed.savePreferences(); + updatePlaybackSpeedPreference(); + return false; + }); } private void setupEpisodeFilterPreference() { @@ -95,8 +180,15 @@ public class FeedSettingsFragment extends PreferenceFragmentCompat { }); } + private void updatePlaybackSpeedPreference() { + ListPreference feedPlaybackSpeedPreference = findPreference(PREF_FEED_PLAYBACK_SPEED); + + float speedValue = feedPreferences.getFeedPlaybackSpeed(); + feedPlaybackSpeedPreference.setValue(decimalFormat.format(speedValue)); + } + private void updateAutoDeleteSummary() { - ListPreference autoDeletePreference = (ListPreference) findPreference("autoDelete"); + ListPreference autoDeletePreference = findPreference("autoDelete"); switch (feedPreferences.getAutoDeleteAction()) { case GLOBAL: @@ -170,7 +262,7 @@ public class FeedSettingsFragment extends PreferenceFragmentCompat { } @Override - public void onConfirmButtonPressed(DialogInterface dialog) { + public void onConfirmButtonPressed(DialogInterface dialog) { DBWriter.setFeedsItemsAutoDownload(feed, autoDownload); } } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FyydSearchFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FyydSearchFragment.java index 9c16cfe56..a3c3df340 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/FyydSearchFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/FyydSearchFragment.java @@ -2,9 +2,9 @@ package de.danoeh.antennapod.fragment; import android.content.Intent; import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.support.v4.view.MenuItemCompat; -import android.support.v7.widget.SearchView; +import androidx.fragment.app.Fragment; +import androidx.core.view.MenuItemCompat; +import androidx.appcompat.widget.SearchView; import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java index bfca90b2a..a97d60099 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java @@ -2,7 +2,6 @@ package de.danoeh.antennapod.fragment; import android.annotation.SuppressLint; import android.app.Activity; -import android.content.ActivityNotFoundException; import android.content.ClipData; import android.content.Context; import android.content.Intent; @@ -12,8 +11,8 @@ import android.graphics.Color; import android.net.Uri; import android.os.Build; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v4.app.Fragment; +import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; import android.util.Log; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java index 9395b0994..f17f8c645 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java @@ -6,10 +6,10 @@ import android.content.Intent; import android.net.Uri; import android.os.Build; import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.v4.app.Fragment; -import android.support.v4.content.ContextCompat; -import android.support.v4.view.GestureDetectorCompat; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.core.content.ContextCompat; +import androidx.core.view.GestureDetectorCompat; import android.text.Layout; import android.text.TextUtils; import android.util.Log; diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java index 80767bef2..673b58901 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItunesSearchFragment.java @@ -2,10 +2,10 @@ package de.danoeh.antennapod.fragment; import android.content.Intent; import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.support.v4.view.MenuItemCompat; -import android.support.v7.widget.SearchView; -import android.support.annotation.NonNull; +import androidx.fragment.app.Fragment; +import androidx.core.view.MenuItemCompat; +import androidx.appcompat.widget.SearchView; +import androidx.annotation.NonNull; import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; @@ -23,29 +23,15 @@ import com.afollestad.materialdialogs.MaterialDialog; import de.danoeh.antennapod.discovery.ItunesPodcastSearcher; import de.danoeh.antennapod.discovery.ItunesTopListLoader; import de.danoeh.antennapod.discovery.PodcastSearchResult; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; -import java.io.IOException; import java.util.ArrayList; import java.util.List; -import java.util.Locale; import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.OnlineFeedViewActivity; import de.danoeh.antennapod.adapter.itunes.ItunesAdapter; -import de.danoeh.antennapod.core.ClientConfig; -import de.danoeh.antennapod.core.service.download.AntennapodHttpClient; import de.danoeh.antennapod.menuhandler.MenuItemUtils; -import io.reactivex.Single; -import io.reactivex.SingleOnSubscribe; -import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.Disposable; -import io.reactivex.schedulers.Schedulers; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; //Searches iTunes store for given string and displays results in a list public class ItunesSearchFragment extends Fragment { @@ -167,7 +153,7 @@ public class ItunesSearchFragment extends Fragment { final SearchView sv = (SearchView) MenuItemCompat.getActionView(searchItem); MenuItemUtils.adjustTextColor(getActivity(), sv); sv.setQueryHint(getString(R.string.search_itunes_label)); - sv.setOnQueryTextListener(new android.support.v7.widget.SearchView.OnQueryTextListener() { + sv.setOnQueryTextListener(new androidx.appcompat.widget.SearchView.OnQueryTextListener() { @Override public boolean onQueryTextSubmit(String s) { sv.clearFocus(); 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 07667118d..5dbb84bc7 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java @@ -1,9 +1,9 @@ package de.danoeh.antennapod.fragment; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v7.widget.RecyclerView; -import android.support.v7.widget.helper.ItemTouchHelper; +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; +import androidx.recyclerview.widget.ItemTouchHelper; import android.view.LayoutInflater; import android.view.Menu; import android.view.View; diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java index e2060481f..f9fca87fc 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java @@ -2,9 +2,9 @@ package de.danoeh.antennapod.fragment; import android.content.res.TypedArray; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v4.app.ListFragment; -import android.support.v4.view.MenuItemCompat; +import androidx.annotation.NonNull; +import androidx.fragment.app.ListFragment; +import androidx.core.view.MenuItemCompat; import android.util.Log; import android.view.Menu; import android.view.MenuInflater; 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 a1f5dca18..b550669f3 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java @@ -4,15 +4,15 @@ import android.content.Context; import android.content.DialogInterface; import android.content.SharedPreferences; import android.os.Bundle; -import android.support.design.widget.Snackbar; -import android.support.v4.app.Fragment; -import android.support.v4.view.MenuItemCompat; -import android.support.v7.app.AlertDialog; -import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.RecyclerView; -import android.support.v7.widget.SearchView; -import android.support.v7.widget.SimpleItemAnimator; -import android.support.v7.widget.helper.ItemTouchHelper; +import com.google.android.material.snackbar.Snackbar; +import androidx.fragment.app.Fragment; +import androidx.core.view.MenuItemCompat; +import androidx.appcompat.app.AlertDialog; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import androidx.appcompat.widget.SearchView; +import androidx.recyclerview.widget.SimpleItemAnimator; +import androidx.recyclerview.widget.ItemTouchHelper; import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; @@ -26,6 +26,7 @@ import android.widget.TextView; import com.yqritc.recyclerviewflexibledivider.HorizontalDividerItemDecoration; +import de.danoeh.antennapod.core.event.PlaybackPositionEvent; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; @@ -43,6 +44,7 @@ import de.danoeh.antennapod.core.event.QueueEvent; import de.danoeh.antennapod.core.feed.EventDistributor; import de.danoeh.antennapod.core.feed.FeedItem; import de.danoeh.antennapod.core.feed.FeedMedia; +import de.danoeh.antennapod.core.preferences.PlaybackSpeedHelper; import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.core.service.download.DownloadService; import de.danoeh.antennapod.core.service.download.Downloader; @@ -213,6 +215,13 @@ public class QueueFragment extends Fragment { } } + @Subscribe(threadMode = ThreadMode.MAIN) + public void onEventMainThread(PlaybackPositionEvent event) { + if (recyclerAdapter != null) { + recyclerAdapter.notifyCurrentlyPlayingItemChanged(event); + } + } + private void saveScrollPosition() { int firstItem = layoutManager.findFirstVisibleItemPosition(); View firstItemView = layoutManager.findViewByPosition(firstItem); @@ -627,8 +636,8 @@ public class QueueFragment extends Fragment { String info = queue.size() + getString(R.string.episodes_suffix); if(queue.size() > 0) { long timeLeft = 0; - float playbackSpeed = UserPreferences.getPlaybackSpeed(); for(FeedItem item : queue) { + float playbackSpeed = PlaybackSpeedHelper.getCurrentPlaybackSpeed(item.getMedia()); if(item.getMedia() != null) { timeLeft += (long) ((item.getMedia().getDuration() - item.getMedia().getPosition()) diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/QuickFeedDiscoveryFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/QuickFeedDiscoveryFragment.java index e4213cc6b..226209740 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/QuickFeedDiscoveryFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/QuickFeedDiscoveryFragment.java @@ -2,7 +2,7 @@ package de.danoeh.antennapod.fragment; import android.content.Intent; import android.os.Bundle; -import android.support.v4.app.Fragment; +import androidx.fragment.app.Fragment; import android.util.Log; import android.view.LayoutInflater; import android.view.View; diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/RunningDownloadsFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/RunningDownloadsFragment.java index 2a7f7d12b..528fa7c32 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/RunningDownloadsFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/RunningDownloadsFragment.java @@ -1,7 +1,7 @@ package de.danoeh.antennapod.fragment; import android.os.Bundle; -import android.support.v4.app.ListFragment; +import androidx.fragment.app.ListFragment; import android.util.Log; import android.view.View; import android.widget.ListView; diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java index 0892bce0a..7f3c60e5d 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java @@ -2,11 +2,11 @@ package de.danoeh.antennapod.fragment; import android.content.Context; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v4.app.ListFragment; -import android.support.v4.view.MenuItemCompat; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.SearchView; +import androidx.annotation.NonNull; +import androidx.fragment.app.ListFragment; +import androidx.core.view.MenuItemCompat; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.SearchView; import android.util.Log; import android.view.Menu; import android.view.MenuInflater; diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java index ed315050b..253c99c4e 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java @@ -5,8 +5,8 @@ import android.content.Context; import android.content.DialogInterface; import android.content.SharedPreferences; import android.os.Bundle; -import android.support.annotation.StringRes; -import android.support.v4.app.Fragment; +import androidx.annotation.StringRes; +import androidx.fragment.app.Fragment; import android.util.Log; import android.view.ContextMenu; import android.view.LayoutInflater; @@ -18,6 +18,8 @@ import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.GridView; +import com.google.android.material.floatingactionbutton.FloatingActionButton; + import java.util.concurrent.Callable; import de.danoeh.antennapod.R; @@ -26,7 +28,6 @@ import de.danoeh.antennapod.adapter.SubscriptionsAdapter; import de.danoeh.antennapod.core.asynctask.FeedRemover; import de.danoeh.antennapod.core.dialog.ConfirmationDialog; import de.danoeh.antennapod.core.event.DownloadEvent; -import de.danoeh.antennapod.core.event.DownloaderUpdate; import de.danoeh.antennapod.core.feed.EventDistributor; import de.danoeh.antennapod.core.feed.Feed; import de.danoeh.antennapod.core.preferences.PlaybackPreferences; @@ -63,6 +64,7 @@ public class SubscriptionFragment extends Fragment { private GridView subscriptionGridLayout; private DBReader.NavDrawerData navDrawerData; private SubscriptionsAdapter subscriptionAdapter; + private FloatingActionButton subscriptionAddButton; private int mPosition = -1; private boolean isUpdatingFeeds = false; @@ -86,6 +88,7 @@ public class SubscriptionFragment extends Fragment { subscriptionGridLayout = root.findViewById(R.id.subscriptions_grid); subscriptionGridLayout.setNumColumns(prefs.getInt(PREF_NUM_COLUMNS, 3)); registerForContextMenu(subscriptionGridLayout); + subscriptionAddButton = root.findViewById(R.id.subscriptions_add); return root; } @@ -138,10 +141,16 @@ public class SubscriptionFragment extends Fragment { @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); - subscriptionAdapter = new SubscriptionsAdapter((MainActivity)getActivity(), itemAccess); + subscriptionAdapter = new SubscriptionsAdapter((MainActivity) getActivity(), itemAccess); subscriptionGridLayout.setAdapter(subscriptionAdapter); subscriptionGridLayout.setOnItemClickListener(subscriptionAdapter); + subscriptionAddButton.setOnClickListener(view -> { + if (getActivity() instanceof MainActivity) { + ((MainActivity) getActivity()).loadChildFragment(new AddFeedFragment()); + } + }); + if (getActivity() instanceof MainActivity) { ((MainActivity) getActivity()).getSupportActionBar().setTitle(R.string.subscriptions_label); } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/TransitionEffect.java b/app/src/main/java/de/danoeh/antennapod/fragment/TransitionEffect.java new file mode 100644 index 000000000..461fa9da3 --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/fragment/TransitionEffect.java @@ -0,0 +1,5 @@ +package de.danoeh.antennapod.fragment; + +public enum TransitionEffect { + NONE, FLIP, FADE +} diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/GpodnetMainFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/GpodnetMainFragment.java index 4dc114f9b..380f6741a 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/GpodnetMainFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/GpodnetMainFragment.java @@ -4,11 +4,11 @@ import android.content.Context; import android.content.SharedPreferences; import android.content.res.Resources; import android.os.Bundle; -import android.support.design.widget.TabLayout; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentManager; -import android.support.v4.app.FragmentPagerAdapter; -import android.support.v4.view.ViewPager; +import com.google.android.material.tabs.TabLayout; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentPagerAdapter; +import androidx.viewpager.widget.ViewPager; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/PodcastListFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/PodcastListFragment.java index 49851ebb4..1d6debbfe 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/PodcastListFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/PodcastListFragment.java @@ -4,9 +4,9 @@ import android.content.Context; import android.content.Intent; import android.os.AsyncTask; import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.support.v4.view.MenuItemCompat; -import android.support.v7.widget.SearchView; +import androidx.fragment.app.Fragment; +import androidx.core.view.MenuItemCompat; +import androidx.appcompat.widget.SearchView; import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; @@ -56,7 +56,7 @@ public abstract class PodcastListFragment extends Fragment { final SearchView sv = (SearchView) MenuItemCompat.getActionView(searchItem); MenuItemUtils.adjustTextColor(getActivity(), sv); sv.setQueryHint(getString(R.string.gpodnet_search_hint)); - sv.setOnQueryTextListener(new android.support.v7.widget.SearchView.OnQueryTextListener() { + sv.setOnQueryTextListener(new androidx.appcompat.widget.SearchView.OnQueryTextListener() { @Override public boolean onQueryTextSubmit(String s) { sv.clearFocus(); diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/SearchListFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/SearchListFragment.java index 10bd636dd..60fc1f446 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/SearchListFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/SearchListFragment.java @@ -1,8 +1,8 @@ package de.danoeh.antennapod.fragment.gpodnet; import android.os.Bundle; -import android.support.v4.view.MenuItemCompat; -import android.support.v7.widget.SearchView; +import androidx.core.view.MenuItemCompat; +import androidx.appcompat.widget.SearchView; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagFragment.java index d39829260..92cd4ca84 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagFragment.java @@ -1,7 +1,7 @@ package de.danoeh.antennapod.fragment.gpodnet; import android.os.Bundle; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import org.apache.commons.lang3.Validate; diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagListFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagListFragment.java index 1e46b1ac5..b5a95bc33 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagListFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/gpodnet/TagListFragment.java @@ -4,9 +4,9 @@ import android.app.Activity; import android.content.Context; import android.os.AsyncTask; import android.os.Bundle; -import android.support.v4.app.ListFragment; -import android.support.v4.view.MenuItemCompat; -import android.support.v7.widget.SearchView; +import androidx.fragment.app.ListFragment; +import androidx.core.view.MenuItemCompat; +import androidx.appcompat.widget.SearchView; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AutoDownloadPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AutoDownloadPreferencesFragment.java index a04615a00..121b7fef8 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AutoDownloadPreferencesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AutoDownloadPreferencesFragment.java @@ -1,29 +1,42 @@ package de.danoeh.antennapod.fragment.preferences; +import android.Manifest; import android.app.Activity; import android.content.Context; +import android.content.pm.PackageManager; import android.content.res.Resources; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiManager; +import android.os.Build; import android.os.Bundle; -import android.support.v7.preference.CheckBoxPreference; -import android.support.v7.preference.ListPreference; -import android.support.v7.preference.Preference; -import android.support.v7.preference.PreferenceFragmentCompat; -import android.support.v7.preference.PreferenceScreen; +import androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; +import androidx.preference.CheckBoxPreference; +import androidx.preference.ListPreference; +import androidx.preference.Preference; +import androidx.preference.PreferenceFragmentCompat; +import androidx.preference.PreferenceScreen; import android.util.Log; -import de.danoeh.antennapod.R; -import de.danoeh.antennapod.core.preferences.UserPreferences; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.activity.PreferenceActivity; +import de.danoeh.antennapod.core.preferences.UserPreferences; + public class AutoDownloadPreferencesFragment extends PreferenceFragmentCompat { private static final String TAG = "AutoDnldPrefFragment"; + + private static final int LOCATION_PERMISSION_REQUEST_CODE = 1; + private static final String PREF_KEY_LOCATION_PERMISSION_REQUEST_PROMPT = "prefAutoDownloadWifiFilterAndroid10PermissionPrompt"; + private CheckBoxPreference[] selectedNetworks; + private Preference prefPermissionRequestPromptOnAndroid10 = null; + @Override public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { addPreferencesFromResource(R.xml.preferences_autodownload); @@ -35,6 +48,12 @@ public class AutoDownloadPreferencesFragment extends PreferenceFragmentCompat { } @Override + public void onStart() { + super.onStart(); + ((PreferenceActivity) getActivity()).getSupportActionBar().setTitle(R.string.auto_download_label); + } + + @Override public void onResume() { super.onResume(); checkAutodownloadItemVisibility(UserPreferences.isEnableAutodownload()); @@ -175,10 +194,65 @@ public class AutoDownloadPreferencesFragment extends PreferenceFragmentCompat { } private void setSelectedNetworksEnabled(boolean b) { + if (showPermissionRequestPromptOnAndroid10IfNeeded(b)) { + return; + } + if (selectedNetworks != null) { for (Preference p : selectedNetworks) { p.setEnabled(b); } } } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + if (requestCode != LOCATION_PERMISSION_REQUEST_CODE) { + return; + } + if (permissions.length > 0 && permissions[0].equals(Manifest.permission.ACCESS_FINE_LOCATION) && + grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + buildAutodownloadSelectedNetworksPreference(); + } + } + + private boolean showPermissionRequestPromptOnAndroid10IfNeeded(boolean wifiFilterEnabled) { + if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) { + return false; + } + + // Cases Android 10(Q) or later + if (prefPermissionRequestPromptOnAndroid10 != null) { + getPreferenceScreen().removePreference(prefPermissionRequestPromptOnAndroid10); + prefPermissionRequestPromptOnAndroid10 = null; + } + + if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.ACCESS_FINE_LOCATION) + == PackageManager.PERMISSION_GRANTED) { + return false; + } + + // Case location permission not yet granted, permission-specific UI is needed + if (!wifiFilterEnabled) { + // Don't show the UI when WiFi filter disabled. + // it still return true, so that the caller knows + // it does not have required permission, and will not invoke codes that require so. + return true; + } + + Preference pref = new Preference(requireActivity()); + pref.setKey(PREF_KEY_LOCATION_PERMISSION_REQUEST_PROMPT); + pref.setTitle(R.string.autodl_wifi_filter_permission_title); + pref.setSummary(R.string.autodl_wifi_filter_permission_message); + pref.setIcon(R.drawable.ic_warning_red); + pref.setOnPreferenceClickListener(preference -> { + requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, LOCATION_PERMISSION_REQUEST_CODE); + return true; + }); + pref.setPersistent(false); + getPreferenceScreen().addPreference(pref); + prefPermissionRequestPromptOnAndroid10 = pref; + return true; + } + } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/GpodderPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/GpodderPreferencesFragment.java index 491922056..c6ae8e20c 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/GpodderPreferencesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/GpodderPreferencesFragment.java @@ -3,12 +3,13 @@ package de.danoeh.antennapod.fragment.preferences; import android.app.Activity; import android.content.SharedPreferences; import android.os.Bundle; -import android.support.v7.preference.Preference; -import android.support.v7.preference.PreferenceFragmentCompat; +import androidx.preference.Preference; +import androidx.preference.PreferenceFragmentCompat; import android.text.Html; import android.text.format.DateUtils; import android.widget.Toast; import de.danoeh.antennapod.R; +import de.danoeh.antennapod.activity.PreferenceActivity; import de.danoeh.antennapod.core.preferences.GpodnetPreferences; import de.danoeh.antennapod.core.service.GpodnetSyncService; import de.danoeh.antennapod.dialog.AuthenticationDialog; @@ -30,6 +31,12 @@ public class GpodderPreferencesFragment extends PreferenceFragmentCompat { } @Override + public void onStart() { + super.onStart(); + ((PreferenceActivity) getActivity()).getSupportActionBar().setTitle(R.string.gpodnet_main_label); + } + + @Override public void onResume() { super.onResume(); GpodnetPreferences.registerOnSharedPreferenceChangeListener(gpoddernetListener); diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/IntegrationsPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/IntegrationsPreferencesFragment.java index 229274b76..51f31eb92 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/IntegrationsPreferencesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/IntegrationsPreferencesFragment.java @@ -1,7 +1,7 @@ package de.danoeh.antennapod.fragment.preferences; import android.os.Bundle; -import android.support.v7.preference.PreferenceFragmentCompat; +import androidx.preference.PreferenceFragmentCompat; import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.PreferenceActivity; @@ -14,6 +14,12 @@ public class IntegrationsPreferencesFragment extends PreferenceFragmentCompat { setupIntegrationsScreen(); } + @Override + public void onStart() { + super.onStart(); + ((PreferenceActivity) getActivity()).getSupportActionBar().setTitle(R.string.integrations_label); + } + private void setupIntegrationsScreen() { findPreference(PREF_SCREEN_GPODDER).setOnPreferenceClickListener(preference -> { ((PreferenceActivity) getActivity()).openScreen(R.xml.preferences_gpodder); diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/MainPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/MainPreferencesFragment.java index 9f36e1355..00e69f1db 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/MainPreferencesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/MainPreferencesFragment.java @@ -1,20 +1,15 @@ package de.danoeh.antennapod.fragment.preferences; -import android.content.ActivityNotFoundException; import android.content.Intent; -import android.net.Uri; import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.preference.PreferenceFragmentCompat; -import android.util.Log; -import android.widget.Toast; +import androidx.appcompat.app.AppCompatActivity; +import androidx.preference.PreferenceFragmentCompat; import com.bytehamster.lib.preferencesearch.SearchConfiguration; import com.bytehamster.lib.preferencesearch.SearchPreference; import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.AboutActivity; import de.danoeh.antennapod.activity.BugReportActivity; import de.danoeh.antennapod.activity.PreferenceActivity; -import de.danoeh.antennapod.activity.StatisticsActivity; import de.danoeh.antennapod.core.util.IntentUtils; public class MainPreferencesFragment extends PreferenceFragmentCompat { @@ -38,6 +33,12 @@ public class MainPreferencesFragment extends PreferenceFragmentCompat { setupSearch(); } + @Override + public void onStart() { + super.onStart(); + ((PreferenceActivity) getActivity()).getSupportActionBar().setTitle(R.string.settings_label); + } + private void setupMainScreen() { findPreference(PREF_SCREEN_USER_INTERFACE).setOnPreferenceClickListener(preference -> { ((PreferenceActivity) getActivity()).openScreen(R.xml.preferences_user_interface); @@ -68,7 +69,8 @@ public class MainPreferencesFragment extends PreferenceFragmentCompat { ); findPreference(STATISTICS).setOnPreferenceClickListener( preference -> { - startActivity(new Intent(getActivity(), StatisticsActivity.class)); + getFragmentManager().beginTransaction().replace(R.id.content, new StatisticsFragment()) + .addToBackStack(getString(R.string.statistics_label)).commit(); return true; } ); diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/NetworkPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/NetworkPreferencesFragment.java index ac2436e25..440660942 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/NetworkPreferencesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/NetworkPreferencesFragment.java @@ -4,10 +4,10 @@ import android.app.TimePickerDialog; import android.content.Context; import android.content.res.Resources; import android.os.Bundle; -import android.support.v7.app.AlertDialog; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.preference.Preference; -import android.support.v7.preference.PreferenceFragmentCompat; +import androidx.appcompat.app.AlertDialog; +import androidx.appcompat.app.AppCompatActivity; +import androidx.preference.Preference; +import androidx.preference.PreferenceFragmentCompat; import android.text.format.DateFormat; import com.afollestad.materialdialogs.MaterialDialog; import de.danoeh.antennapod.R; @@ -31,6 +31,12 @@ public class NetworkPreferencesFragment extends PreferenceFragmentCompat { } @Override + public void onStart() { + super.onStart(); + ((PreferenceActivity) getActivity()).getSupportActionBar().setTitle(R.string.network_pref); + } + + @Override public void onResume() { super.onResume(); setUpdateIntervalText(); 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 e1714d4bd..1795dfc29 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,10 +4,11 @@ import android.app.Activity; import android.content.res.Resources; import android.os.Build; import android.os.Bundle; -import android.support.v7.preference.ListPreference; -import android.support.v7.preference.PreferenceFragmentCompat; +import androidx.preference.ListPreference; +import androidx.preference.PreferenceFragmentCompat; import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.MediaplayerActivity; +import de.danoeh.antennapod.activity.PreferenceActivity; import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.core.util.gui.PictureInPictureUtil; import de.danoeh.antennapod.dialog.VariableSpeedDialog; @@ -28,6 +29,12 @@ public class PlaybackPreferencesFragment extends PreferenceFragmentCompat { } @Override + public void onStart() { + super.onStart(); + ((PreferenceActivity) getActivity()).getSupportActionBar().setTitle(R.string.playback_pref); + } + + @Override public void onResume() { super.onResume(); checkSonicItemVisibility(); diff --git a/app/src/main/java/de/danoeh/antennapod/activity/StatisticsActivity.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/StatisticsFragment.java index 37199ccf7..2b5310837 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/StatisticsActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/StatisticsFragment.java @@ -1,25 +1,27 @@ -package de.danoeh.antennapod.activity; +package de.danoeh.antennapod.fragment.preferences; +import android.content.Context; import android.content.SharedPreferences; import android.os.Bundle; -import android.support.v7.app.AlertDialog; -import android.support.v7.app.AppCompatActivity; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.appcompat.app.AlertDialog; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; import android.util.Log; +import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; -import android.widget.AdapterView; -import android.widget.ListView; +import android.view.ViewGroup; import android.widget.ProgressBar; import android.widget.RadioButton; -import android.widget.TextView; - import de.danoeh.antennapod.R; +import de.danoeh.antennapod.activity.PreferenceActivity; import de.danoeh.antennapod.adapter.StatisticsListAdapter; -import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.core.storage.DBReader; -import de.danoeh.antennapod.core.util.Converter; import io.reactivex.Observable; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.Disposable; @@ -28,70 +30,63 @@ import io.reactivex.schedulers.Schedulers; /** * Displays the 'statistics' screen */ -public class StatisticsActivity extends AppCompatActivity - implements AdapterView.OnItemClickListener { - - private static final String TAG = StatisticsActivity.class.getSimpleName(); +public class StatisticsFragment extends Fragment { + private static final String TAG = StatisticsFragment.class.getSimpleName(); private static final String PREF_NAME = "StatisticsActivityPrefs"; private static final String PREF_COUNT_ALL = "countAll"; private Disposable disposable; - private TextView totalTimeTextView; - private ListView feedStatisticsList; + private RecyclerView feedStatisticsList; private ProgressBar progressBar; private StatisticsListAdapter listAdapter; private boolean countAll = false; private SharedPreferences prefs; @Override - protected void onCreate(Bundle savedInstanceState) { - setTheme(UserPreferences.getTheme()); + public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - getSupportActionBar().setDisplayShowHomeEnabled(true); - setContentView(R.layout.statistics_activity); - - prefs = getSharedPreferences(PREF_NAME, MODE_PRIVATE); + prefs = getContext().getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE); countAll = prefs.getBoolean(PREF_COUNT_ALL, false); + setHasOptionsMenu(true); + } - totalTimeTextView = findViewById(R.id.total_time); - feedStatisticsList = findViewById(R.id.statistics_list); - progressBar = findViewById(R.id.progressBar); - listAdapter = new StatisticsListAdapter(this); + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View root = inflater.inflate(R.layout.statistics_activity, container, false); + feedStatisticsList = root.findViewById(R.id.statistics_list); + progressBar = root.findViewById(R.id.progressBar); + listAdapter = new StatisticsListAdapter(getContext()); listAdapter.setCountAll(countAll); + feedStatisticsList.setLayoutManager(new LinearLayoutManager(getContext())); feedStatisticsList.setAdapter(listAdapter); - feedStatisticsList.setOnItemClickListener(this); + return root; } @Override - public void onResume() { - super.onResume(); + public void onStart() { + super.onStart(); + ((PreferenceActivity) getActivity()).getSupportActionBar().setTitle(R.string.statistics_label); refreshStatistics(); } @Override - public boolean onCreateOptionsMenu(Menu menu) { - super.onCreateOptionsMenu(menu); - MenuInflater inflater = getMenuInflater(); + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { inflater.inflate(R.menu.statistics, menu); - return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { - if (item.getItemId() == android.R.id.home) { - finish(); - return true; - } else if (item.getItemId() == R.id.statistics_mode) { + if (item.getItemId() == R.id.statistics_mode) { selectStatisticsMode(); return true; - } else { - return super.onOptionsItemSelected(item); } + return super.onOptionsItemSelected(item); } private void selectStatisticsMode() { - View contentView = View.inflate(this, R.layout.statistics_mode_select_dialog, null); - AlertDialog.Builder builder = new AlertDialog.Builder(this); + View contentView = View.inflate(getContext(), R.layout.statistics_mode_select_dialog, null); + AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); builder.setView(contentView); builder.setTitle(R.string.statistics_mode); @@ -113,7 +108,6 @@ public class StatisticsActivity extends AppCompatActivity private void refreshStatistics() { progressBar.setVisibility(View.VISIBLE); - totalTimeTextView.setVisibility(View.GONE); feedStatisticsList.setVisibility(View.GONE); loadStatistics(); } @@ -126,28 +120,9 @@ public class StatisticsActivity extends AppCompatActivity .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(result -> { - totalTimeTextView.setText(Converter - .shortLocalizedDuration(this, countAll ? result.totalTimeCountAll : result.totalTime)); - listAdapter.update(result.feedTime); + listAdapter.update(result); progressBar.setVisibility(View.GONE); - totalTimeTextView.setVisibility(View.VISIBLE); feedStatisticsList.setVisibility(View.VISIBLE); }, error -> Log.e(TAG, Log.getStackTraceString(error))); } - - @Override - public void onItemClick(AdapterView<?> parent, View view, int position, long id) { - DBReader.StatisticsItem stats = listAdapter.getItem(position); - - AlertDialog.Builder dialog = new AlertDialog.Builder(this); - dialog.setTitle(stats.feed.getTitle()); - dialog.setMessage(getString(R.string.statistics_details_dialog, - countAll ? stats.episodesStartedIncludingMarked : stats.episodesStarted, - stats.episodes, - Converter.shortLocalizedDuration(this, countAll ? - stats.timePlayedCountAll : stats.timePlayed), - Converter.shortLocalizedDuration(this, stats.time))); - dialog.setPositiveButton(android.R.string.ok, null); - dialog.show(); - } } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/StoragePreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/StoragePreferencesFragment.java index e36476c6f..2c1590c47 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/StoragePreferencesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/StoragePreferencesFragment.java @@ -12,17 +12,18 @@ import android.content.pm.ResolveInfo; import android.net.Uri; import android.os.Build; import android.os.Bundle; -import android.support.v4.app.ActivityCompat; -import android.support.v4.content.FileProvider; -import android.support.v4.provider.DocumentFile; -import android.support.v7.app.AlertDialog; -import android.support.v7.preference.PreferenceFragmentCompat; +import androidx.core.app.ActivityCompat; +import androidx.core.content.FileProvider; +import androidx.documentfile.provider.DocumentFile; +import androidx.appcompat.app.AlertDialog; +import androidx.preference.PreferenceFragmentCompat; import android.util.Log; import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.DirectoryChooserActivity; import de.danoeh.antennapod.activity.ImportExportActivity; import de.danoeh.antennapod.activity.OpmlImportFromPathActivity; +import de.danoeh.antennapod.activity.PreferenceActivity; import de.danoeh.antennapod.asynctask.DocumentFileExportWorker; import de.danoeh.antennapod.asynctask.ExportWorker; import de.danoeh.antennapod.core.export.ExportWriter; @@ -64,6 +65,12 @@ public class StoragePreferencesFragment extends PreferenceFragmentCompat { } @Override + public void onStart() { + super.onStart(); + ((PreferenceActivity) getActivity()).getSupportActionBar().setTitle(R.string.storage_pref); + } + + @Override public void onResume() { super.onResume(); setDataFolderText(); diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/UserInterfacePreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/UserInterfacePreferencesFragment.java index e1d44f7d3..191999cf7 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/UserInterfacePreferencesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/UserInterfacePreferencesFragment.java @@ -4,13 +4,14 @@ import android.content.Context; import android.content.Intent; import android.os.Build; import android.os.Bundle; -import android.support.design.widget.Snackbar; -import android.support.v7.app.AlertDialog; -import android.support.v7.preference.PreferenceFragmentCompat; +import com.google.android.material.snackbar.Snackbar; +import androidx.appcompat.app.AlertDialog; +import androidx.preference.PreferenceFragmentCompat; import android.widget.ListView; import android.widget.Toast; import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.MainActivity; +import de.danoeh.antennapod.activity.PreferenceActivity; import de.danoeh.antennapod.core.preferences.UserPreferences; import org.apache.commons.lang3.ArrayUtils; @@ -25,6 +26,12 @@ public class UserInterfacePreferencesFragment extends PreferenceFragmentCompat { setupInterfaceScreen(); } + @Override + public void onStart() { + super.onStart(); + ((PreferenceActivity) getActivity()).getSupportActionBar().setTitle(R.string.user_interface_label); + } + private void setupInterfaceScreen() { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { diff --git a/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java index add62b480..fb2675db9 100644 --- a/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java +++ b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java @@ -1,14 +1,11 @@ package de.danoeh.antennapod.menuhandler; import android.content.Context; -import android.content.Intent; -import android.net.Uri; import android.os.Handler; -import android.support.annotation.NonNull; -import android.support.design.widget.Snackbar; -import android.support.v4.app.Fragment; +import androidx.annotation.NonNull; +import com.google.android.material.snackbar.Snackbar; +import androidx.fragment.app.Fragment; import android.util.Log; -import android.widget.Toast; import de.danoeh.antennapod.R; import de.danoeh.antennapod.core.feed.FeedItem; 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 dbb3b6e7b..5d012168e 100644 --- a/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java +++ b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java @@ -2,25 +2,17 @@ package de.danoeh.antennapod.menuhandler; import android.content.Context; import android.content.DialogInterface; -import android.content.Intent; -import android.net.Uri; -import android.support.v7.app.AlertDialog; -import android.text.TextUtils; +import androidx.appcompat.app.AlertDialog; import android.util.Log; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; -import android.widget.Toast; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Iterator; import java.util.Set; import de.danoeh.antennapod.R; import de.danoeh.antennapod.core.dialog.ConfirmationDialog; import de.danoeh.antennapod.core.feed.Feed; -import de.danoeh.antennapod.core.feed.FeedItemFilter; import de.danoeh.antennapod.core.storage.DBTasks; import de.danoeh.antennapod.core.storage.DBWriter; import de.danoeh.antennapod.core.storage.DownloadRequestException; diff --git a/app/src/main/java/de/danoeh/antennapod/menuhandler/MenuItemUtils.java b/app/src/main/java/de/danoeh/antennapod/menuhandler/MenuItemUtils.java index 7b9fcad9b..4a57726b1 100644 --- a/app/src/main/java/de/danoeh/antennapod/menuhandler/MenuItemUtils.java +++ b/app/src/main/java/de/danoeh/antennapod/menuhandler/MenuItemUtils.java @@ -4,7 +4,7 @@ import android.content.Context; import android.content.res.TypedArray; import android.graphics.Color; import android.os.Build; -import android.support.v7.widget.SearchView; +import androidx.appcompat.widget.SearchView; import android.view.Menu; import android.view.MenuItem; import android.widget.EditText; diff --git a/app/src/main/java/de/danoeh/antennapod/preferences/MasterSwitchPreference.java b/app/src/main/java/de/danoeh/antennapod/preferences/MasterSwitchPreference.java index b810cbfa6..007457c24 100644 --- a/app/src/main/java/de/danoeh/antennapod/preferences/MasterSwitchPreference.java +++ b/app/src/main/java/de/danoeh/antennapod/preferences/MasterSwitchPreference.java @@ -4,8 +4,8 @@ import android.annotation.TargetApi; import android.content.Context; import android.graphics.Typeface; import android.os.Build; -import android.support.v14.preference.SwitchPreference; -import android.support.v7.preference.PreferenceViewHolder; +import androidx.preference.SwitchPreference; +import androidx.preference.PreferenceViewHolder; import android.util.AttributeSet; import android.util.TypedValue; import android.widget.TextView; diff --git a/app/src/main/java/de/danoeh/antennapod/preferences/NumberPickerPreference.java b/app/src/main/java/de/danoeh/antennapod/preferences/NumberPickerPreference.java index 50e76838c..a58986241 100644 --- a/app/src/main/java/de/danoeh/antennapod/preferences/NumberPickerPreference.java +++ b/app/src/main/java/de/danoeh/antennapod/preferences/NumberPickerPreference.java @@ -2,7 +2,7 @@ package de.danoeh.antennapod.preferences; import android.app.AlertDialog; import android.content.Context; -import android.support.v7.preference.Preference; +import androidx.preference.Preference; import android.text.InputFilter; import android.util.AttributeSet; import android.view.View; diff --git a/app/src/main/java/de/danoeh/antennapod/view/EmptyViewHandler.java b/app/src/main/java/de/danoeh/antennapod/view/EmptyViewHandler.java index 8b886e699..1516c4eb6 100644 --- a/app/src/main/java/de/danoeh/antennapod/view/EmptyViewHandler.java +++ b/app/src/main/java/de/danoeh/antennapod/view/EmptyViewHandler.java @@ -2,9 +2,9 @@ package de.danoeh.antennapod.view; import android.content.Context;
import android.graphics.drawable.Drawable;
-import android.support.annotation.AttrRes;
-import android.support.v4.content.ContextCompat;
-import android.support.v7.widget.RecyclerView;
+import androidx.annotation.AttrRes;
+import androidx.core.content.ContextCompat;
+import androidx.recyclerview.widget.RecyclerView;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
diff --git a/app/src/main/java/de/danoeh/antennapod/view/PieChartView.java b/app/src/main/java/de/danoeh/antennapod/view/PieChartView.java new file mode 100644 index 000000000..ada5401d8 --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/view/PieChartView.java @@ -0,0 +1,121 @@ +package de.danoeh.antennapod.view; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.ColorFilter; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.RectF; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; +import androidx.annotation.NonNull; +import androidx.appcompat.widget.AppCompatImageView; +import io.reactivex.annotations.Nullable; + +public class PieChartView extends AppCompatImageView { + private PieChartDrawable drawable; + + public PieChartView(Context context) { + super(context); + setup(); + } + + public PieChartView(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + setup(); + } + + public PieChartView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + setup(); + } + + @SuppressLint("ClickableViewAccessibility") + private void setup() { + drawable = new PieChartDrawable(); + setImageDrawable(drawable); + } + + /** + * Set array od names, array of values and array of colors. + */ + public void setData(float[] dataValues) { + drawable.dataValues = dataValues; + drawable.valueSum = 0; + for (float datum : dataValues) { + drawable.valueSum += datum; + } + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + int width = getMeasuredWidth(); + setMeasuredDimension(width, width / 2); + } + + private static class PieChartDrawable extends Drawable { + private static final float MIN_DEGREES = 10f; + private static final float PADDING_DEGREES = 3f; + private static final float STROKE_SIZE = 15f; + private static final int[] COLOR_VALUES = new int[]{0xFF3775E6, 0xffe51c23, 0xffff9800, 0xff259b24, 0xff9c27b0, + 0xff0099c6, 0xffdd4477, 0xff66aa00, 0xffb82e2e, 0xff316395, + 0xff994499, 0xff22aa99, 0xffaaaa11, 0xff6633cc, 0xff0073e6}; + private float[] dataValues; + private float valueSum; + private final Paint paint; + + private PieChartDrawable() { + paint = new Paint(); + paint.setFlags(Paint.ANTI_ALIAS_FLAG); + paint.setStyle(Paint.Style.STROKE); + paint.setStrokeJoin(Paint.Join.ROUND); + paint.setStrokeCap(Paint.Cap.ROUND); + paint.setStrokeWidth(STROKE_SIZE); + } + + @Override + public void draw(@NonNull Canvas canvas) { + if (valueSum == 0) { + return; + } + float radius = getBounds().height() - STROKE_SIZE; + float center = getBounds().width() / 2.f; + RectF arcBounds = new RectF(center - radius, STROKE_SIZE, center + radius, STROKE_SIZE + radius * 2); + + float startAngle = 180; + for (int i = 0; i < dataValues.length; i++) { + float datum = dataValues[i]; + float sweepAngle = 180 * datum / valueSum; + if (sweepAngle < MIN_DEGREES) { + break; + } + paint.setColor(COLOR_VALUES[i % COLOR_VALUES.length]); + float padding = i == 0 ? PADDING_DEGREES / 2 : PADDING_DEGREES; + canvas.drawArc(arcBounds, startAngle + padding, sweepAngle - padding, false, paint); + startAngle = startAngle + sweepAngle; + } + + paint.setColor(Color.GRAY); + float sweepAngle = 360 - startAngle - PADDING_DEGREES / 2; + if (sweepAngle > PADDING_DEGREES) { + canvas.drawArc(arcBounds, startAngle + PADDING_DEGREES, sweepAngle - PADDING_DEGREES, false, paint); + } + } + + @Override + public int getOpacity() { + return PixelFormat.TRANSLUCENT; + } + + @Override + public void setAlpha(int alpha) { + } + + @Override + public void setColorFilter(ColorFilter cf) { + } + } +} diff --git a/app/src/main/java/de/danoeh/antennapod/view/SimpleAdapterDataObserver.java b/app/src/main/java/de/danoeh/antennapod/view/SimpleAdapterDataObserver.java index 45c3a35bd..5bd335532 100644 --- a/app/src/main/java/de/danoeh/antennapod/view/SimpleAdapterDataObserver.java +++ b/app/src/main/java/de/danoeh/antennapod/view/SimpleAdapterDataObserver.java @@ -1,7 +1,7 @@ package de.danoeh.antennapod.view; -import android.support.annotation.Nullable; -import android.support.v7.widget.RecyclerView; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.RecyclerView; /** * AdapterDataObserver that relays all events to the method anythingChanged(). diff --git a/app/src/main/java/de/danoeh/antennapod/view/SquareImageView.java b/app/src/main/java/de/danoeh/antennapod/view/SquareImageView.java index 7ce33e11f..f82309c4a 100644 --- a/app/src/main/java/de/danoeh/antennapod/view/SquareImageView.java +++ b/app/src/main/java/de/danoeh/antennapod/view/SquareImageView.java @@ -1,7 +1,7 @@ package de.danoeh.antennapod.view; import android.content.Context; -import android.support.v7.widget.AppCompatImageView; +import androidx.appcompat.widget.AppCompatImageView; import android.util.AttributeSet; /** diff --git a/app/src/main/java/de/danoeh/antennapod/viewmodel/FeedSettingsViewModel.java b/app/src/main/java/de/danoeh/antennapod/viewmodel/FeedSettingsViewModel.java deleted file mode 100644 index fe11a645c..000000000 --- a/app/src/main/java/de/danoeh/antennapod/viewmodel/FeedSettingsViewModel.java +++ /dev/null @@ -1,30 +0,0 @@ -package de.danoeh.antennapod.viewmodel; - -import android.arch.lifecycle.ViewModel; -import de.danoeh.antennapod.core.feed.Feed; -import de.danoeh.antennapod.core.storage.DBReader; -import io.reactivex.Maybe; - -public class FeedSettingsViewModel extends ViewModel { - private Feed feed; - - public Maybe<Feed> getFeed(long feedId) { - if (feed == null) { - return loadFeed(feedId); - } else { - return Maybe.just(feed); - } - } - - private Maybe<Feed> loadFeed(long feedId) { - return Maybe.create(emitter -> { - Feed feed = DBReader.getFeed(feedId); - if (feed != null) { - this.feed = feed; - emitter.onSuccess(feed); - } else { - emitter.onComplete(); - } - }); - } -} diff --git a/app/src/main/res/anim/card_flip_left_in.xml b/app/src/main/res/anim/card_flip_left_in.xml new file mode 100644 index 000000000..0ffc85aec --- /dev/null +++ b/app/src/main/res/anim/card_flip_left_in.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<set xmlns:android="http://schemas.android.com/apk/res/android"> + <!-- Before rotating, immediately set the alpha to 0. --> + <objectAnimator + android:valueFrom="1.0" + android:valueTo="0.0" + android:propertyName="alpha" + android:duration="0" /> + + <!-- Rotate. --> + <objectAnimator + android:valueFrom="-180" + android:valueTo="0" + android:propertyName="rotationY" + android:interpolator="@android:interpolator/accelerate_decelerate" + android:duration="@integer/card_flip_time_full" /> + + <!-- Half-way through the rotation (see startOffset), set the alpha to 1. --> + <objectAnimator + android:valueFrom="0.0" + android:valueTo="1.0" + android:propertyName="alpha" + android:startOffset="@integer/card_flip_time_half" + android:duration="1" /> +</set>
\ No newline at end of file diff --git a/app/src/main/res/anim/card_flip_left_out.xml b/app/src/main/res/anim/card_flip_left_out.xml new file mode 100644 index 000000000..817f0d3fc --- /dev/null +++ b/app/src/main/res/anim/card_flip_left_out.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="utf-8"?> +<set xmlns:android="http://schemas.android.com/apk/res/android"> + <!-- Rotate. --> + <objectAnimator + android:valueFrom="0" + android:valueTo="180" + android:propertyName="rotationY" + android:interpolator="@android:interpolator/accelerate_decelerate" + android:duration="@integer/card_flip_time_full" /> + + <!-- Half-way through the rotation (see startOffset), set the alpha to 0. --> + <objectAnimator + android:valueFrom="1.0" + android:valueTo="0.0" + android:propertyName="alpha" + android:startOffset="@integer/card_flip_time_half" + android:duration="1" /> +</set>
\ No newline at end of file diff --git a/app/src/main/res/anim/card_flip_right_in.xml b/app/src/main/res/anim/card_flip_right_in.xml new file mode 100644 index 000000000..31ff1dde5 --- /dev/null +++ b/app/src/main/res/anim/card_flip_right_in.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<set xmlns:android="http://schemas.android.com/apk/res/android"> + <!-- Before rotating, immediately set the alpha to 0. --> + <objectAnimator + android:valueFrom="1.0" + android:valueTo="0.0" + android:propertyName="alpha" + android:duration="0" /> + + <!-- Rotate. --> + <objectAnimator + android:valueFrom="180" + android:valueTo="0" + android:propertyName="rotationY" + android:interpolator="@android:interpolator/accelerate_decelerate" + android:duration="@integer/card_flip_time_full" /> + + <!-- Half-way through the rotation (see startOffset), set the alpha to 1. --> + <objectAnimator + android:valueFrom="0.0" + android:valueTo="1.0" + android:propertyName="alpha" + android:startOffset="@integer/card_flip_time_half" + android:duration="1" /> +</set>
\ No newline at end of file diff --git a/app/src/main/res/anim/card_flip_right_out.xml b/app/src/main/res/anim/card_flip_right_out.xml new file mode 100644 index 000000000..b57113fea --- /dev/null +++ b/app/src/main/res/anim/card_flip_right_out.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="utf-8"?> +<set xmlns:android="http://schemas.android.com/apk/res/android"> + <!-- Rotate. --> + <objectAnimator + android:valueFrom="0" + android:valueTo="-180" + android:propertyName="rotationY" + android:interpolator="@android:interpolator/accelerate_decelerate" + android:duration="@integer/card_flip_time_full" /> + + <!-- Half-way through the rotation (see startOffset), set the alpha to 0. --> + <objectAnimator + android:valueFrom="1.0" + android:valueTo="0.0" + android:propertyName="alpha" + android:startOffset="@integer/card_flip_time_half" + android:duration="1" /> +</set>
\ No newline at end of file diff --git a/app/src/main/res/layout/addfeed.xml b/app/src/main/res/layout/addfeed.xml index a7f7d9f12..99fa1c3f9 100644 --- a/app/src/main/res/layout/addfeed.xml +++ b/app/src/main/res/layout/addfeed.xml @@ -13,7 +13,7 @@ android:focusableInTouchMode="true" android:padding="8dp"> - <android.support.v7.widget.CardView + <androidx.cardview.widget.CardView android:layout_width="match_parent" android:layout_height="wrap_content" app:cardCornerRadius="4dp" @@ -53,7 +53,7 @@ </LinearLayout> - </android.support.v7.widget.CardView> + </androidx.cardview.widget.CardView> <fragment android:id="@+id/quickFeedDiscovery" @@ -62,7 +62,7 @@ android:layout_height="wrap_content" android:layout_margin="8dp"/> - <android.support.v7.widget.CardView + <androidx.cardview.widget.CardView android:layout_width="match_parent" android:layout_height="wrap_content" app:cardCornerRadius="4dp" @@ -102,9 +102,9 @@ </LinearLayout> - </android.support.v7.widget.CardView> + </androidx.cardview.widget.CardView> - <android.support.v7.widget.CardView + <androidx.cardview.widget.CardView android:layout_width="match_parent" android:layout_height="wrap_content" app:cardCornerRadius="4dp" @@ -170,7 +170,7 @@ </LinearLayout> - </android.support.v7.widget.CardView> + </androidx.cardview.widget.CardView> </LinearLayout> diff --git a/app/src/main/res/layout/all_episodes_fragment.xml b/app/src/main/res/layout/all_episodes_fragment.xml index 53636c2b6..9160998ac 100644 --- a/app/src/main/res/layout/all_episodes_fragment.xml +++ b/app/src/main/res/layout/all_episodes_fragment.xml @@ -17,7 +17,7 @@ android:visibility="gone" tools:text="(i) Information" /> - <android.support.v7.widget.RecyclerView + <androidx.recyclerview.widget.RecyclerView android:id="@android:id/list" android:layout_width="match_parent" android:layout_height="match_parent" diff --git a/app/src/main/res/layout/choose_data_folder_dialog_entry.xml b/app/src/main/res/layout/choose_data_folder_dialog_entry.xml index 9a216b36b..f4a2ff703 100644 --- a/app/src/main/res/layout/choose_data_folder_dialog_entry.xml +++ b/app/src/main/res/layout/choose_data_folder_dialog_entry.xml @@ -5,7 +5,7 @@ android:id="@+id/root" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_margin="@dimen/diag_content_side_padding" + android:layout_margin="16dp" android:background="?attr/selectableItemBackground"> <RadioButton diff --git a/app/src/main/res/layout/feedinfo.xml b/app/src/main/res/layout/feedinfo.xml index 50061c4d8..416fc3aec 100644 --- a/app/src/main/res/layout/feedinfo.xml +++ b/app/src/main/res/layout/feedinfo.xml @@ -24,7 +24,7 @@ android:layout_height="wrap_content" android:orientation="vertical"> - <android.support.v7.widget.GridLayout + <androidx.gridlayout.widget.GridLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="8dp" @@ -107,7 +107,7 @@ tools:text="http://www.example.com/feed" tools:background="@android:color/holo_green_dark"/> - </android.support.v7.widget.GridLayout> + </androidx.gridlayout.widget.GridLayout> <TextView style="@style/AntennaPod.TextView.Heading" diff --git a/app/src/main/res/layout/fragment_subscriptions.xml b/app/src/main/res/layout/fragment_subscriptions.xml index a716cecb6..69eee04ce 100644 --- a/app/src/main/res/layout/fragment_subscriptions.xml +++ b/app/src/main/res/layout/fragment_subscriptions.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> @@ -11,6 +11,18 @@ android:horizontalSpacing="2dp" android:verticalSpacing="2dp" android:layout_height="match_parent" - android:layout_gravity="center_horizontal"> + android:layout_gravity="center_horizontal" + android:paddingBottom="88dp" + android:clipToPadding="false"> </GridView> -</LinearLayout> + + <com.google.android.material.floatingactionbutton.FloatingActionButton + android:id="@+id/subscriptions_add" + android:layout_width="56dp" + android:layout_height="56dp" + android:layout_margin="16dp" + android:layout_gravity="bottom|end" + android:contentDescription="@string/add_feed_label" + android:src="@drawable/ic_add_white_24dp" + /> +</FrameLayout> diff --git a/app/src/main/res/layout/main.xml b/app/src/main/res/layout/main.xml index 6cabcdff2..a226e482f 100644 --- a/app/src/main/res/layout/main.xml +++ b/app/src/main/res/layout/main.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> -<android.support.v4.widget.DrawerLayout +<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/drawer_layout" @@ -19,7 +19,7 @@ tools:layout_height="64dp" tools:background="@android:color/holo_green_light" /> - <android.support.v7.widget.Toolbar + <androidx.appcompat.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="wrap_content" @@ -48,4 +48,4 @@ <include layout="@layout/nav_list" /> -</android.support.v4.widget.DrawerLayout>
\ No newline at end of file +</androidx.drawerlayout.widget.DrawerLayout>
\ No newline at end of file diff --git a/app/src/main/res/layout/mediaplayerinfo_activity.xml b/app/src/main/res/layout/mediaplayerinfo_activity.xml index c4217db54..b759b0092 100644 --- a/app/src/main/res/layout/mediaplayerinfo_activity.xml +++ b/app/src/main/res/layout/mediaplayerinfo_activity.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> -<android.support.v4.widget.DrawerLayout +<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto" @@ -12,12 +12,12 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - <android.support.design.widget.AppBarLayout + <com.google.android.material.appbar.AppBarLayout android:id="@+id/appBar" android:layout_width="match_parent" android:layout_height="wrap_content"> - <android.support.v7.widget.Toolbar + <androidx.appcompat.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="wrap_content" @@ -37,7 +37,7 @@ app:strokeColor="?android:attr/textColorSecondary" app:radius="4dp" /> - </android.support.design.widget.AppBarLayout> + </com.google.android.material.appbar.AppBarLayout> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" @@ -251,7 +251,7 @@ </LinearLayout> - <android.support.v4.view.ViewPager + <androidx.viewpager.widget.ViewPager xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/pager" android:layout_width="match_parent" @@ -272,4 +272,4 @@ <include layout="@layout/nav_list" /> -</android.support.v4.widget.DrawerLayout>
\ No newline at end of file +</androidx.drawerlayout.widget.DrawerLayout>
\ No newline at end of file diff --git a/app/src/main/res/layout/pager_fragment.xml b/app/src/main/res/layout/pager_fragment.xml index 54b711b1c..492743239 100644 --- a/app/src/main/res/layout/pager_fragment.xml +++ b/app/src/main/res/layout/pager_fragment.xml @@ -7,14 +7,14 @@ android:orientation="vertical"> - <android.support.design.widget.TabLayout + <com.google.android.material.tabs.TabLayout android:id="@+id/sliding_tabs" android:layout_width="match_parent" android:layout_height="wrap_content" app:tabGravity="fill" app:tabMode="fixed" /> - <android.support.v4.view.ViewPager + <androidx.viewpager.widget.ViewPager android:id="@+id/viewpager" android:layout_width="match_parent" android:layout_height="0px" diff --git a/app/src/main/res/layout/queue_fragment.xml b/app/src/main/res/layout/queue_fragment.xml index 85b0df58c..63da6a315 100644 --- a/app/src/main/res/layout/queue_fragment.xml +++ b/app/src/main/res/layout/queue_fragment.xml @@ -20,7 +20,7 @@ android:layout_below="@id/info_bar" android:background="?android:attr/listDivider"/> - <android.support.v7.widget.RecyclerView + <androidx.recyclerview.widget.RecyclerView android:id="@+id/recyclerView" android:layout_width="match_parent" android:layout_height="match_parent" diff --git a/app/src/main/res/layout/quick_feed_discovery.xml b/app/src/main/res/layout/quick_feed_discovery.xml index ce5cfa65b..e791d19d7 100644 --- a/app/src/main/res/layout/quick_feed_discovery.xml +++ b/app/src/main/res/layout/quick_feed_discovery.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> -<android.support.v7.widget.CardView +<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" @@ -79,5 +79,5 @@ </LinearLayout> -</android.support.v7.widget.CardView> +</androidx.cardview.widget.CardView> diff --git a/app/src/main/res/layout/statistics_activity.xml b/app/src/main/res/layout/statistics_activity.xml index 4a72dc7de..9d9cad438 100644 --- a/app/src/main/res/layout/statistics_activity.xml +++ b/app/src/main/res/layout/statistics_activity.xml @@ -1,41 +1,24 @@ <?xml version="1.0" encoding="utf-8"?> -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:orientation="vertical" - android:paddingTop="8dp" - android:paddingBottom="8dp"> - - <TextView - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="@string/total_time_listened_to_podcasts" - android:gravity="center_horizontal"/> +<FrameLayout 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"> <ProgressBar - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:id="@+id/progressBar" - android:layout_gravity="center_horizontal" - style="?android:attr/progressBarStyleLarge"/> - - <TextView - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:id="@+id/total_time" - android:gravity="center_horizontal" - android:textSize="45sp"/> + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:id="@+id/progressBar" + android:layout_gravity="center"/> - <ListView - android:id="@+id/statistics_list" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:choiceMode="singleChoice" - android:clipToPadding="false" - android:divider="@android:color/transparent" - android:dividerHeight="0dp" - android:paddingBottom="@dimen/list_vertical_padding" - android:paddingTop="@dimen/list_vertical_padding" - android:scrollbarStyle="outsideOverlay" /> + <androidx.recyclerview.widget.RecyclerView + android:id="@+id/statistics_list" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:clipToPadding="false" + android:paddingBottom="@dimen/list_vertical_padding" + android:paddingTop="@dimen/list_vertical_padding" + android:scrollbarStyle="outsideOverlay" + tools:listitem="@layout/statistics_listitem"/> -</LinearLayout> +</FrameLayout> diff --git a/app/src/main/res/layout/statistics_listitem.xml b/app/src/main/res/layout/statistics_listitem.xml index f52aa73e0..6bd2a907e 100644 --- a/app/src/main/res/layout/statistics_listitem.xml +++ b/app/src/main/res/layout/statistics_listitem.xml @@ -3,63 +3,55 @@ xmlns:tools="http://schemas.android.com/tools" android:orientation="vertical" android:layout_width="match_parent" - android:layout_height="@dimen/listitem_iconwithtext_height" - android:paddingLeft="@dimen/listitem_threeline_verticalpadding" - android:paddingStart="@dimen/listitem_threeline_verticalpadding" - android:paddingRight="@dimen/listitem_threeline_verticalpadding" - android:paddingEnd="@dimen/listitem_threeline_verticalpadding" - tools:background="@android:color/darker_gray"> + android:layout_height="wrap_content" + android:paddingLeft="16dp" + android:paddingRight="16dp" + android:paddingTop="8dp" + android:paddingBottom="8dp" + android:background="?android:attr/selectableItemBackground"> <ImageView - android:id="@+id/imgvCover" - android:contentDescription="@string/cover_label" - android:layout_width="@dimen/thumbnail_length_navlist" - android:layout_height="@dimen/thumbnail_length_navlist" - android:layout_alignParentLeft="true" - android:layout_alignParentStart="true" - android:layout_centerVertical="true" - android:adjustViewBounds="true" - android:cropToPadding="true" - android:scaleType="centerCrop" - android:layout_marginTop="4dp" - android:layout_marginBottom="4dp" - tools:src="@drawable/ic_antenna" - tools:background="@android:color/holo_green_dark"/> + android:id="@+id/imgvCover" + android:contentDescription="@string/cover_label" + android:layout_width="40dp" + android:layout_height="40dp" + android:layout_alignParentLeft="true" + android:layout_alignParentStart="true" + android:layout_centerVertical="true" + android:adjustViewBounds="true" + android:cropToPadding="true" + android:scaleType="centerCrop" + tools:src="@drawable/ic_antenna" + tools:background="@android:color/holo_green_dark"/> <TextView - android:id="@+id/txtvTime" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginLeft="@dimen/list_vertical_padding" - android:layout_marginStart="@dimen/list_vertical_padding" - android:lines="1" - android:textColor="?android:attr/textColorTertiary" - android:textSize="@dimen/text_size_navdrawer" - android:layout_alignParentRight="true" - android:layout_alignParentEnd="true" - android:layout_centerVertical="true" - tools:text="23" - tools:background="@android:color/holo_green_dark"/> + android:id="@+id/txtvTitle" + android:lines="1" + android:ellipsize="end" + android:singleLine="true" + android:textColor="?android:attr/textColorPrimary" + android:textSize="16sp" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginLeft="16dp" + android:layout_marginStart="16dp" + android:layout_toRightOf="@id/imgvCover" + android:layout_alignTop="@id/imgvCover" + android:layout_alignWithParentIfMissing="true" + tools:text="Feed title"/> <TextView - android:id="@+id/txtvTitle" - android:lines="1" - android:ellipsize="end" - android:singleLine="true" - android:layout_centerVertical="true" - android:textColor="?android:attr/textColorPrimary" - android:textSize="@dimen/text_size_navdrawer" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginLeft="@dimen/listitem_iconwithtext_textleftpadding" - android:layout_marginStart="@dimen/listitem_iconwithtext_textleftpadding" - android:layout_toRightOf="@id/imgvCover" - android:layout_toEndOf="@id/imgvCover" - android:layout_toLeftOf="@id/txtvTime" - android:layout_toStartOf="@id/txtvTime" - android:layout_alignWithParentIfMissing="true" - tools:text="Navigation feed item title" - tools:background="@android:color/holo_green_dark"/> - + android:id="@+id/txtvTime" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:lines="1" + android:textColor="?android:attr/textColorTertiary" + android:textSize="14sp" + android:layout_toEndOf="@+id/imgvCover" + android:layout_toRightOf="@+id/imgvCover" + android:layout_marginLeft="16dp" + android:layout_marginStart="16dp" + android:layout_below="@+id/txtvTitle" + tools:text="23 hours"/> </RelativeLayout> diff --git a/app/src/main/res/layout/statistics_listitem_total_time.xml b/app/src/main/res/layout/statistics_listitem_total_time.xml new file mode 100644 index 000000000..2e0ae54d6 --- /dev/null +++ b/app/src/main/res/layout/statistics_listitem_total_time.xml @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="utf-8"?> +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:padding="16dp"> + + <de.danoeh.antennapod.view.PieChartView + android:id="@+id/pie_chart" + android:layout_marginLeft="8dp" + android:layout_marginRight="8dp" + android:layout_width="match_parent" + android:layout_height="wrap_content"/> + + <TextView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:id="@+id/total_time_description" + android:textSize="14sp" + android:text="@string/total_time_listened_to_podcasts" + android:gravity="center_horizontal" + android:layout_above="@+id/total_time"/> + + <TextView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:id="@+id/total_time" + android:textColor="?android:attr/textColorPrimary" + android:gravity="center_horizontal" + android:textSize="28sp" + android:layout_marginBottom="16dp" + android:layout_alignBottom="@id/pie_chart" + tools:text="10.0 hours"/> + + <View + android:layout_width="match_parent" + android:layout_height="1dp" + android:layout_marginTop="16dp" + android:background="?android:attr/dividerVertical" + android:layout_below="@+id/pie_chart"/> + +</RelativeLayout>
\ No newline at end of file diff --git a/app/src/main/res/menu/episodes.xml b/app/src/main/res/menu/episodes.xml index 1e1aa8f56..7398754e5 100644 --- a/app/src/main/res/menu/episodes.xml +++ b/app/src/main/res/menu/episodes.xml @@ -7,7 +7,7 @@ android:id="@+id/action_search" android:icon="?attr/action_search" custom:showAsAction="collapseActionView|ifRoom" - custom:actionViewClass="android.support.v7.widget.SearchView" + custom:actionViewClass="androidx.appcompat.widget.SearchView" android:title="@string/search_label"/> <item diff --git a/app/src/main/res/menu/feedlist.xml b/app/src/main/res/menu/feedlist.xml index 4144c392f..fdd0e01bc 100644 --- a/app/src/main/res/menu/feedlist.xml +++ b/app/src/main/res/menu/feedlist.xml @@ -34,7 +34,7 @@ android:id="@+id/action_search" android:icon="?attr/action_search" custom:showAsAction="always|collapseActionView" - custom:actionViewClass="android.support.v7.widget.SearchView" + custom:actionViewClass="androidx.appcompat.widget.SearchView" android:title="@string/search_label"/> <item diff --git a/app/src/main/res/menu/gpodder_podcasts.xml b/app/src/main/res/menu/gpodder_podcasts.xml index 88fa36a4a..93d93157a 100644 --- a/app/src/main/res/menu/gpodder_podcasts.xml +++ b/app/src/main/res/menu/gpodder_podcasts.xml @@ -7,7 +7,7 @@ android:id="@+id/action_search" android:icon="?attr/action_search" custom:showAsAction="collapseActionView|ifRoom" - custom:actionViewClass="android.support.v7.widget.SearchView" + custom:actionViewClass="androidx.appcompat.widget.SearchView" android:title="@string/search_label"/> </menu> diff --git a/app/src/main/res/menu/itunes_search.xml b/app/src/main/res/menu/itunes_search.xml index 88fa36a4a..93d93157a 100644 --- a/app/src/main/res/menu/itunes_search.xml +++ b/app/src/main/res/menu/itunes_search.xml @@ -7,7 +7,7 @@ android:id="@+id/action_search" android:icon="?attr/action_search" custom:showAsAction="collapseActionView|ifRoom" - custom:actionViewClass="android.support.v7.widget.SearchView" + custom:actionViewClass="androidx.appcompat.widget.SearchView" android:title="@string/search_label"/> </menu> diff --git a/app/src/main/res/menu/queue.xml b/app/src/main/res/menu/queue.xml index a4e511eb8..b86ad5d63 100644 --- a/app/src/main/res/menu/queue.xml +++ b/app/src/main/res/menu/queue.xml @@ -20,7 +20,7 @@ android:id="@+id/action_search" android:icon="?attr/action_search" custom:showAsAction="collapseActionView|ifRoom" - custom:actionViewClass="android.support.v7.widget.SearchView" + custom:actionViewClass="androidx.appcompat.widget.SearchView" android:title="@string/search_label"/> <item diff --git a/app/src/main/res/values/integers.xml b/app/src/main/res/values/integers.xml new file mode 100644 index 000000000..8c444ee8b --- /dev/null +++ b/app/src/main/res/values/integers.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <integer name="card_flip_time_full">400</integer> + <integer name="card_flip_time_half">200</integer> +</resources>
\ No newline at end of file diff --git a/app/src/main/res/xml/feed_settings.xml b/app/src/main/res/xml/feed_settings.xml index 5fd6b2038..505248198 100644 --- a/app/src/main/res/xml/feed_settings.xml +++ b/app/src/main/res/xml/feed_settings.xml @@ -13,6 +13,11 @@ android:summary="@string/authentication_descr"/> <ListPreference + android:key="feedPlaybackSpeed" + android:title="@string/playback_speed" + android:summary="@string/pref_feed_playback_speed_sum"/> + + <ListPreference android:entries="@array/spnAutoDeleteItems" android:entryValues="@array/spnAutoDeleteValues" android:title="@string/auto_delete_label" diff --git a/app/src/play/java/de/danoeh/antennapod/activity/CastEnabledActivity.java b/app/src/play/java/de/danoeh/antennapod/activity/CastEnabledActivity.java index 87304b3d6..912571a7e 100644 --- a/app/src/play/java/de/danoeh/antennapod/activity/CastEnabledActivity.java +++ b/app/src/play/java/de/danoeh/antennapod/activity/CastEnabledActivity.java @@ -4,9 +4,9 @@ import android.content.SharedPreferences; import android.media.AudioManager; import android.os.Bundle; import android.preference.PreferenceManager; -import android.support.annotation.CallSuper; -import android.support.v4.view.MenuItemCompat; -import android.support.v7.app.AppCompatActivity; +import androidx.annotation.CallSuper; +import androidx.core.view.MenuItemCompat; +import androidx.appcompat.app.AppCompatActivity; import android.util.Log; import android.view.Menu; import android.view.MenuItem; @@ -29,17 +29,34 @@ public abstract class CastEnabledActivity extends AppCompatActivity implements SharedPreferences.OnSharedPreferenceChangeListener { public static final String TAG = "CastEnabledActivity"; - protected CastManager castManager; - protected SwitchableMediaRouteActionProvider mediaRouteActionProvider; + private CastConsumer castConsumer; + private CastManager castManager; + + private SwitchableMediaRouteActionProvider mediaRouteActionProvider; private final CastButtonVisibilityManager castButtonVisibilityManager = new CastButtonVisibilityManager(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + if (!CastManager.isInitialized()) { + return; + } + PreferenceManager.getDefaultSharedPreferences(getApplicationContext()). registerOnSharedPreferenceChangeListener(this); + castConsumer = new DefaultCastConsumer() { + @Override + public void onApplicationConnected(ApplicationMetadata appMetadata, String sessionId, boolean wasLaunched) { + onCastConnectionChanged(true); + } + + @Override + public void onDisconnected() { + onCastConnectionChanged(false); + } + }; castManager = CastManager.getInstance(); castManager.addCastConsumer(castConsumer); castButtonVisibilityManager.setPrefEnabled(UserPreferences.isCastEnabled()); @@ -48,6 +65,10 @@ public abstract class CastEnabledActivity extends AppCompatActivity @Override protected void onDestroy() { + if (!CastManager.isInitialized()) { + super.onDestroy(); + return; + } PreferenceManager.getDefaultSharedPreferences(getApplicationContext()) .unregisterOnSharedPreferenceChangeListener(this); castManager.removeCastConsumer(castConsumer); @@ -58,6 +79,9 @@ public abstract class CastEnabledActivity extends AppCompatActivity @CallSuper public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); + if (!CastManager.isInitialized()) { + return true; + } getMenuInflater().inflate(R.menu.cast_enabled, menu); castButtonVisibilityManager.setMenu(menu); return true; @@ -67,6 +91,10 @@ public abstract class CastEnabledActivity extends AppCompatActivity @CallSuper public boolean onPrepareOptionsMenu(Menu menu) { super.onPrepareOptionsMenu(menu); + if (!CastManager.isInitialized()) { + return true; + } + MenuItem mediaRouteButton = menu.findItem(R.id.media_route_menu_item); if (mediaRouteButton == null) { Log.wtf(TAG, "MediaRoute item could not be found on the menu!", new Exception()); @@ -83,15 +111,22 @@ public abstract class CastEnabledActivity extends AppCompatActivity @Override protected void onResume() { super.onResume(); + if (!CastManager.isInitialized()) { + return; + } castButtonVisibilityManager.setResumed(true); } @Override protected void onPause() { super.onPause(); + if (!CastManager.isInitialized()) { + return; + } castButtonVisibilityManager.setResumed(false); } + @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { if (UserPreferences.PREF_CAST_ENABLED.equals(key)) { @@ -105,18 +140,6 @@ public abstract class CastEnabledActivity extends AppCompatActivity } } - CastConsumer castConsumer = new DefaultCastConsumer() { - @Override - public void onApplicationConnected(ApplicationMetadata appMetadata, String sessionId, boolean wasLaunched) { - onCastConnectionChanged(true); - } - - @Override - public void onDisconnected() { - onCastConnectionChanged(false); - } - }; - private void onCastConnectionChanged(boolean connected) { if (connected) { castButtonVisibilityManager.onConnected(); @@ -133,6 +156,9 @@ public abstract class CastEnabledActivity extends AppCompatActivity * @param showAsAction refer to {@link MenuItem#setShowAsAction(int)} */ public final void requestCastButton(int showAsAction) { + if (!CastManager.isInitialized()) { + return; + } castButtonVisibilityManager.requestCastButton(showAsAction); } diff --git a/app/src/play/java/de/danoeh/antennapod/config/CastCallbackImpl.java b/app/src/play/java/de/danoeh/antennapod/config/CastCallbackImpl.java index 916b13a38..2a879c62d 100644 --- a/app/src/play/java/de/danoeh/antennapod/config/CastCallbackImpl.java +++ b/app/src/play/java/de/danoeh/antennapod/config/CastCallbackImpl.java @@ -1,8 +1,8 @@ package de.danoeh.antennapod.config; -import android.support.annotation.NonNull; -import android.support.v7.app.MediaRouteControllerDialogFragment; -import android.support.v7.app.MediaRouteDialogFactory; +import androidx.annotation.NonNull; +import androidx.mediarouter.app.MediaRouteControllerDialogFragment; +import androidx.mediarouter.app.MediaRouteDialogFactory; import de.danoeh.antennapod.core.CastCallbacks; import de.danoeh.antennapod.fragment.CustomMRControllerDialogFragment; diff --git a/app/src/play/java/de/danoeh/antennapod/dialog/CustomMRControllerDialog.java b/app/src/play/java/de/danoeh/antennapod/dialog/CustomMRControllerDialog.java index ae8e20575..bf5b85c82 100644 --- a/app/src/play/java/de/danoeh/antennapod/dialog/CustomMRControllerDialog.java +++ b/app/src/play/java/de/danoeh/antennapod/dialog/CustomMRControllerDialog.java @@ -8,19 +8,19 @@ import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Bundle; import android.os.RemoteException; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import android.support.v4.media.MediaDescriptionCompat; import android.support.v4.media.MediaMetadataCompat; import android.support.v4.media.session.MediaControllerCompat; import android.support.v4.media.session.MediaSessionCompat; import android.support.v4.media.session.PlaybackStateCompat; -import android.support.v4.util.Pair; -import android.support.v4.view.MarginLayoutParamsCompat; -import android.support.v4.view.accessibility.AccessibilityEventCompat; -import android.support.v7.app.MediaRouteControllerDialog; -import android.support.v7.graphics.Palette; -import android.support.v7.media.MediaRouter; -import android.support.v7.widget.AppCompatImageView; +import androidx.core.util.Pair; +import androidx.core.view.MarginLayoutParamsCompat; +import androidx.core.view.accessibility.AccessibilityEventCompat; +import androidx.mediarouter.app.MediaRouteControllerDialog; +import androidx.palette.graphics.Palette; +import androidx.mediarouter.media.MediaRouter; +import androidx.appcompat.widget.AppCompatImageView; import android.text.TextUtils; import android.util.Log; import android.util.TypedValue; @@ -311,9 +311,7 @@ public class CustomMRControllerDialog extends MediaRouteControllerDialog { AccessibilityEventCompat.TYPE_ANNOUNCEMENT); event.setPackageName(getContext().getPackageName()); event.setClassName(getClass().getName()); - int resId = isPlaying ? - android.support.v7.mediarouter.R.string.mr_controller_pause : - android.support.v7.mediarouter.R.string.mr_controller_play; + int resId = isPlaying ? R.string.mr_controller_pause : R.string.mr_controller_play; event.getText().add(getContext().getString(resId)); accessibilityManager.sendAccessibilityEvent(event); } @@ -359,17 +357,17 @@ public class CustomMRControllerDialog extends MediaRouteControllerDialog { if (route.getPresentationDisplay() != null && route.getPresentationDisplay().getDisplayId() != MediaRouter.RouteInfo.PRESENTATION_DISPLAY_ID_NONE) { // The user is currently casting screen. - titleView.setText(android.support.v7.mediarouter.R.string.mr_controller_casting_screen); + titleView.setText(R.string.mr_controller_casting_screen); showTitle = true; } else if (state == null || state.getState() == PlaybackStateCompat.STATE_NONE) { // Show "No media selected" as we don't yet know the playback state. // (Only exception is bluetooth where we don't show anything.) if (!route.isBluetooth()) { - titleView.setText(android.support.v7.mediarouter.R.string.mr_controller_no_media_selected); + titleView.setText(R.string.mr_controller_no_media_selected); showTitle = true; } } else if (!hasTitle && !hasSubtitle) { - titleView.setText(android.support.v7.mediarouter.R.string.mr_controller_no_info_available); + titleView.setText(R.string.mr_controller_no_info_available); showTitle = true; } else { if (hasTitle) { @@ -435,16 +433,12 @@ public class CustomMRControllerDialog extends MediaRouteControllerDialog { | PlaybackStateCompat.ACTION_PLAY_PAUSE)) != 0; if (isPlaying && supportsPause) { playPauseButton.setVisibility(View.VISIBLE); - playPauseButton.setImageResource(getThemeResource(getContext(), - android.support.v7.mediarouter.R.attr.mediaRoutePauseDrawable)); - playPauseButton.setContentDescription(getContext().getResources() - .getText(android.support.v7.mediarouter.R.string.mr_controller_pause)); + playPauseButton.setImageResource(getThemeResource(getContext(), R.attr.mediaRoutePauseDrawable)); + playPauseButton.setContentDescription(getContext().getResources().getText(R.string.mr_controller_pause)); } else if (!isPlaying && supportsPlay) { playPauseButton.setVisibility(View.VISIBLE); - playPauseButton.setImageResource(getThemeResource(getContext(), - android.support.v7.mediarouter.R.attr.mediaRoutePlayDrawable)); - playPauseButton.setContentDescription(getContext().getResources() - .getText(android.support.v7.mediarouter.R.string.mr_controller_play)); + playPauseButton.setImageResource(getThemeResource(getContext(), R.attr.mediaRoutePlayDrawable)); + playPauseButton.setContentDescription(getContext().getResources().getText(R.string.mr_controller_play)); } else { playPauseButton.setVisibility(View.GONE); } diff --git a/app/src/play/java/de/danoeh/antennapod/fragment/CustomMRControllerDialogFragment.java b/app/src/play/java/de/danoeh/antennapod/fragment/CustomMRControllerDialogFragment.java index a960ec998..dad7b0bfd 100644 --- a/app/src/play/java/de/danoeh/antennapod/fragment/CustomMRControllerDialogFragment.java +++ b/app/src/play/java/de/danoeh/antennapod/fragment/CustomMRControllerDialogFragment.java @@ -2,8 +2,8 @@ package de.danoeh.antennapod.fragment; import android.content.Context; import android.os.Bundle; -import android.support.v7.app.MediaRouteControllerDialog; -import android.support.v7.app.MediaRouteControllerDialogFragment; +import androidx.mediarouter.app.MediaRouteControllerDialog; +import androidx.mediarouter.app.MediaRouteControllerDialogFragment; import de.danoeh.antennapod.dialog.CustomMRControllerDialog; diff --git a/app/src/play/java/de/danoeh/antennapod/preferences/PreferenceControllerFlavorHelper.java b/app/src/play/java/de/danoeh/antennapod/preferences/PreferenceControllerFlavorHelper.java index c9d52df0c..810074bbe 100644 --- a/app/src/play/java/de/danoeh/antennapod/preferences/PreferenceControllerFlavorHelper.java +++ b/app/src/play/java/de/danoeh/antennapod/preferences/PreferenceControllerFlavorHelper.java @@ -1,8 +1,13 @@ package de.danoeh.antennapod.preferences; +import android.content.Context; +import androidx.annotation.NonNull; +import androidx.appcompat.app.AlertDialog; + import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.GoogleApiAvailability; +import de.danoeh.antennapod.R; import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.fragment.preferences.PlaybackPreferencesFragment; @@ -18,6 +23,7 @@ public class PreferenceControllerFlavorHelper { final int googlePlayServicesCheck = GoogleApiAvailability.getInstance() .isGooglePlayServicesAvailable(ui.getActivity()); if (googlePlayServicesCheck == ConnectionResult.SUCCESS) { + displayRestartRequiredDialog(ui.requireContext()); return true; } else { GoogleApiAvailability.getInstance() @@ -29,4 +35,13 @@ public class PreferenceControllerFlavorHelper { return true; }); } + + private static void displayRestartRequiredDialog(@NonNull Context context) { + AlertDialog.Builder dialog = new AlertDialog.Builder(context); + dialog.setTitle(android.R.string.dialog_alert_title); + dialog.setMessage(R.string.pref_restart_required); + dialog.setPositiveButton(android.R.string.ok, null); + dialog.setCancelable(false); + dialog.show(); + } } |