summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Hennen <TomHennen@users.noreply.github.com>2015-12-10 21:08:49 -0500
committerTom Hennen <TomHennen@users.noreply.github.com>2015-12-10 21:08:49 -0500
commite021e78c81c3f162b9a60ed2f3ce4c43a2e0613a (patch)
tree9e7bed559c8d83eedd09d8e1cb4df707ef892121
parent212bef11414cda7af816cbb6753710c9561841a1 (diff)
parentc0f15653d4d986e83167402807db27e0b8a121ed (diff)
downloadAntennaPod-e021e78c81c3f162b9a60ed2f3ce4c43a2e0613a.zip
Merge pull request #1457 from AntennaPod/develop1.4.1.4
1.4.1 now in production
-rw-r--r--CHANGELOG.md8
-rw-r--r--CONTRIBUTING.md25
-rw-r--r--app/build.gradle3
-rw-r--r--app/src/androidTest/java/de/test/antennapod/storage/DBWriterTest.java14
-rw-r--r--app/src/androidTest/java/de/test/antennapod/ui/MainActivityTest.java3
-rw-r--r--app/src/main/AndroidManifest.xml4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/CrashReportWriter.java49
-rw-r--r--app/src/main/java/de/danoeh/antennapod/PodcastApp.java19
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java6
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java14
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java23
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/StorageErrorActivity.java5
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/ActionButtonUtils.java9
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java45
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java8
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java21
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java25
-rw-r--r--app/src/main/java/de/danoeh/antennapod/asynctask/OpmlExportWorker.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java14
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/RatingDialog.java136
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java82
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java15
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java61
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java82
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java16
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java89
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java130
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/RunningDownloadsFragment.java58
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java5
-rw-r--r--app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java40
-rw-r--r--app/src/main/java/de/danoeh/antennapod/receiver/ConnectivityActionReceiver.java5
-rw-r--r--app/src/main/java/de/danoeh/antennapod/receiver/PlayerWidget.java95
-rw-r--r--app/src/main/java/de/danoeh/antennapod/receiver/SPAReceiver.java5
-rw-r--r--app/src/main/java/de/danoeh/antennapod/service/PlayerWidgetService.java342
-rw-r--r--app/src/main/res/layout/all_episodes_fragment.xml1
-rw-r--r--app/src/main/res/layout/downloadlog_item.xml3
-rw-r--r--app/src/main/res/layout/feeditemlist_item.xml9
-rw-r--r--app/src/main/res/layout/new_episodes_listitem.xml14
-rw-r--r--app/src/main/res/layout/queue_listitem.xml13
-rw-r--r--app/src/main/res/xml/player_widget_info.xml9
-rw-r--r--app/src/main/res/xml/preferences.xml10
-rw-r--r--build.gradle2
-rw-r--r--changelog/ar.md4
-rw-r--r--changelog/az.md4
-rw-r--r--changelog/ca.md4
-rw-r--r--changelog/cs_CZ.md4
-rw-r--r--changelog/da.md4
-rw-r--r--changelog/de.md4
-rw-r--r--changelog/el.md4
-rw-r--r--changelog/es.md4
-rw-r--r--changelog/es_ES.md4
-rw-r--r--changelog/fi.md4
-rw-r--r--changelog/fr.md4
-rw-r--r--changelog/he_IL.md4
-rw-r--r--changelog/hi_IN.md4
-rw-r--r--changelog/hu.md4
-rw-r--r--changelog/id.md4
-rw-r--r--changelog/it.md4
-rw-r--r--changelog/it_IT.md4
-rw-r--r--changelog/ja.md4
-rw-r--r--changelog/kn_IN.md4
-rw-r--r--changelog/ko.md4
-rw-r--r--changelog/ko_KR.md4
-rw-r--r--changelog/nb_NO.md4
-rw-r--r--changelog/nl.md109
-rw-r--r--changelog/no.md4
-rw-r--r--changelog/pl.md4
-rw-r--r--changelog/pl_PL.md4
-rw-r--r--changelog/pt.md4
-rw-r--r--changelog/pt_BR.md4
-rw-r--r--changelog/ro_RO.md4
-rw-r--r--changelog/ru_RU.md4
-rw-r--r--changelog/sv_SE.md4
-rw-r--r--changelog/tr.md4
-rw-r--r--changelog/uk_UA.md4
-rw-r--r--changelog/vi.md4
-rw-r--r--changelog/vi_VN.md4
-rw-r--r--changelog/zh_CN.md4
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/asynctask/DownloadObserver.java191
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/asynctask/FlattrClickWorker.java5
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/event/DownloadEvent.java28
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/event/DownloaderUpdate.java53
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/event/FeedItemEvent.java5
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/feed/EventDistributor.java12
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/feed/Feed.java8
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/feed/FeedItemFilter.java6
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/feed/FeedPreferences.java7
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/gpoddernet/GpodnetService.java105
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetDevice.java8
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetEpisodeAction.java69
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetEpisodeActionGetResponse.java14
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetPodcast.java15
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetSubscriptionChange.java8
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetTag.java8
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/preferences/GpodnetPreferences.java5
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java30
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/receiver/AlarmUpdateReceiver.java7
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/download/AntennapodHttpClient.java34
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadRequest.java22
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java143
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadStatus.java13
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/download/HttpDownloader.java17
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java15
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java202
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceTaskManager.java19
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java181
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java7
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java20
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/DownloadRequester.java17
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java127
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/LongList.java22
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/StorageUtils.java4
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/URLChecker.java10
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/flattr/FlattrUtils.java6
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java10
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/playback/Timeline.java5
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/syndication/FeedDiscoverer.java7
-rw-r--r--core/src/main/res/drawable-hdpi/ic_widget_preview.pngbin0 -> 18320 bytes
-rw-r--r--core/src/main/res/values-az/strings.xml1
-rw-r--r--core/src/main/res/values-ca/strings.xml1
-rw-r--r--core/src/main/res/values-cs-rCZ/strings.xml16
-rw-r--r--core/src/main/res/values-da/strings.xml1
-rw-r--r--core/src/main/res/values-de/strings.xml18
-rw-r--r--core/src/main/res/values-es-rES/strings.xml1
-rw-r--r--core/src/main/res/values-es/strings.xml1
-rw-r--r--core/src/main/res/values-fr/strings.xml20
-rw-r--r--core/src/main/res/values-hi-rIN/strings.xml1
-rw-r--r--core/src/main/res/values-it-rIT/strings.xml1
-rw-r--r--core/src/main/res/values-iw-rIL/strings.xml1
-rw-r--r--core/src/main/res/values-ja/strings.xml1
-rw-r--r--core/src/main/res/values-ko/strings.xml1
-rw-r--r--core/src/main/res/values-nb/strings.xml1
-rw-r--r--core/src/main/res/values-nl/strings.xml11
-rw-r--r--core/src/main/res/values-pl-rPL/strings.xml1
-rw-r--r--core/src/main/res/values-pt-rBR/strings.xml1
-rw-r--r--core/src/main/res/values-pt/strings.xml16
-rw-r--r--core/src/main/res/values-ro-rRO/strings.xml1
-rw-r--r--core/src/main/res/values-ru/strings.xml114
-rw-r--r--core/src/main/res/values-sv-rSE/strings.xml66
-rw-r--r--core/src/main/res/values-tr/strings.xml1
-rw-r--r--core/src/main/res/values-uk-rUA/strings.xml1
-rw-r--r--core/src/main/res/values-zh-rCN/strings.xml1
-rw-r--r--core/src/main/res/values/colors.xml2
-rw-r--r--core/src/main/res/values/strings.xml15
-rw-r--r--description/ar.txt6
-rw-r--r--description/az.txt6
-rw-r--r--description/ca.txt6
-rw-r--r--description/cs_CZ.txt6
-rw-r--r--description/da.txt6
-rw-r--r--description/de.txt72
-rw-r--r--description/el.txt6
-rwxr-xr-xdescription/en.txt6
-rw-r--r--description/es.txt6
-rw-r--r--description/es_ES.txt6
-rw-r--r--description/fi.txt6
-rw-r--r--description/fr.txt6
-rw-r--r--description/he_IL.txt6
-rw-r--r--description/hi_IN.txt6
-rw-r--r--description/hu.txt6
-rw-r--r--description/id.txt6
-rw-r--r--description/it.txt6
-rw-r--r--description/it_IT.txt6
-rw-r--r--description/ja.txt6
-rw-r--r--description/kn_IN.txt6
-rw-r--r--description/ko.txt6
-rw-r--r--description/ko_KR.txt6
-rw-r--r--description/nb_NO.txt6
-rw-r--r--description/nl.txt8
-rw-r--r--description/no.txt6
-rw-r--r--description/pl.txt6
-rw-r--r--description/pl_PL.txt6
-rw-r--r--description/pt.txt8
-rw-r--r--description/pt_BR.txt6
-rw-r--r--description/ro_RO.txt6
-rw-r--r--description/ru_RU.txt6
-rw-r--r--description/sv_SE.txt8
-rw-r--r--description/tr.txt6
-rw-r--r--description/uk_UA.txt6
-rw-r--r--description/vi.txt6
-rw-r--r--description/vi_VN.txt6
-rw-r--r--description/zh_CN.txt6
-rw-r--r--gradlew.bat180
-rwxr-xr-xmakeRelease.sh11
-rw-r--r--project.properties1
187 files changed, 2355 insertions, 1665 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f07b7f7e7..2e3a210a9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,13 @@
Change Log
==========
+Version 1.4.1
+-------------
+* Performance improvements
+* Hardware buttons now ff and rewind instead of skipping
+* Option to have forward button skip
+* Option to send crash reports directly to developers
+* Highlight currently playing episode
+* Widget improvements
Version 1.4.0.12
----------------
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 9dfd9ecfe..5e6f1dbff 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -7,6 +7,31 @@ How to report a bug
- If the bug only seems to occur with a certain podcast, make sure to include the URL of that podcast.
- If possible, add instructions on how to reproduce the bug.
- If possible, add a logfile to your post. This is especially useful if the bug makes the application crash. You can create logfiles with an app like `aLogcat`. Just launch `alogcat`, then start AntennaPod and reproduce the bug. aLogcat should now display information about the bug when you start it.
+- Usually, you can make a screenshot of your smartphone by pressing [Power] + [Volume down] for a few seconds
+- Please use the following **template**:
+
+**Android version**: 5.x [Especially mention custom roms!]
+
+**Devide model**:
+
+**Expected behaviour**:
+
+**Current behaviour**:
+
+**First occured**: Version 1.x / about x days/weeks ago
+
+**Steps to reproduce**:
+
+1. Do this
+1. Do that
+
+**Environment**: Settings you have changed, e.g. Auto Download. "Unusual" devices you use, e.g. Bluetooth headphones. Do you still use Prestissimo?
+
+**Stacktrace/Logcat**: [if available]
+```
+...
+```
+
How to submit a feature request
-------------------------------
diff --git a/app/build.gradle b/app/build.gradle
index 5a391b45e..3f1584081 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -28,6 +28,9 @@ dependencies {
compile "com.squareup.okio:okio:$okioVersion"
compile "de.greenrobot:eventbus:$eventbusVersion"
compile "io.reactivex:rxandroid:$rxAndroidVersion"
+ compile "io.reactivex:rxjava:$rxJavaVersion"
+ // And ProGuard rules for RxJava!
+ compile "com.artemzin.rxjava:proguard-rules:$rxJavaRulesVersion"
compile "com.joanzapata.iconify:android-iconify-fontawesome:2.1.0"
compile "com.afollestad:material-dialogs:0.7.8.1"
compile "com.yqritc:recyclerview-flexibledivider:1.2.6"
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 f5240b873..d61d4ab52 100644
--- a/app/src/androidTest/java/de/test/antennapod/storage/DBWriterTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/storage/DBWriterTest.java
@@ -177,7 +177,7 @@ public class DBWriterTest extends InstrumentationTestCase {
Cursor c = adapter.getFeedCursor(feed.getId());
assertEquals(0, c.getCount());
c.close();
- c = adapter.getImageCursor(image.getId());
+ c = adapter.getImageCursor(String.valueOf(image.getId()));
assertEquals(0, c.getCount());
c.close();
for (FeedItem item : feed.getItems()) {
@@ -280,7 +280,7 @@ public class DBWriterTest extends InstrumentationTestCase {
Cursor c = adapter.getFeedCursor(feed.getId());
assertTrue(c.getCount() == 0);
c.close();
- c = adapter.getImageCursor(image.getId());
+ c = adapter.getImageCursor(String.valueOf(image.getId()));
assertTrue(c.getCount() == 0);
c.close();
}
@@ -327,7 +327,7 @@ public class DBWriterTest extends InstrumentationTestCase {
Cursor c = adapter.getFeedCursor(feed.getId());
assertTrue(c.getCount() == 0);
c.close();
- c = adapter.getImageCursor(image.getId());
+ c = adapter.getImageCursor(String.valueOf(image.getId()));
assertTrue(c.getCount() == 0);
c.close();
for (FeedItem item : feed.getItems()) {
@@ -382,14 +382,14 @@ public class DBWriterTest extends InstrumentationTestCase {
Cursor c = adapter.getFeedCursor(feed.getId());
assertTrue(c.getCount() == 0);
c.close();
- c = adapter.getImageCursor(image.getId());
+ c = adapter.getImageCursor(String.valueOf(image.getId()));
assertTrue(c.getCount() == 0);
c.close();
for (FeedItem item : feed.getItems()) {
c = adapter.getFeedItemCursor(String.valueOf(item.getId()));
assertTrue(c.getCount() == 0);
c.close();
- c = adapter.getImageCursor(item.getImage().getId());
+ c = adapter.getImageCursor(String.valueOf(item.getImage().getId()));
assertEquals(0, c.getCount());
c.close();
}
@@ -450,7 +450,7 @@ public class DBWriterTest extends InstrumentationTestCase {
Cursor c = adapter.getFeedCursor(feed.getId());
assertTrue(c.getCount() == 0);
c.close();
- c = adapter.getImageCursor(image.getId());
+ c = adapter.getImageCursor(String.valueOf(image.getId()));
assertTrue(c.getCount() == 0);
c.close();
for (FeedItem item : feed.getItems()) {
@@ -512,7 +512,7 @@ public class DBWriterTest extends InstrumentationTestCase {
Cursor c = adapter.getFeedCursor(feed.getId());
assertTrue(c.getCount() == 0);
c.close();
- c = adapter.getImageCursor(image.getId());
+ c = adapter.getImageCursor(String.valueOf(image.getId()));
assertTrue(c.getCount() == 0);
c.close();
for (FeedItem item : feed.getItems()) {
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 c09f40b17..4dae53a15 100644
--- a/app/src/androidTest/java/de/test/antennapod/ui/MainActivityTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/ui/MainActivityTest.java
@@ -41,7 +41,6 @@ public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActiv
@Override
protected void setUp() throws Exception {
super.setUp();
- solo = new Solo(getInstrumentation(), getActivity());
uiTestUtils = new UITestUtils(getInstrumentation().getTargetContext());
uiTestUtils.setup();
@@ -54,6 +53,8 @@ public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActiv
// override first launch preference
prefs = getInstrumentation().getTargetContext().getSharedPreferences(MainActivity.PREF_NAME, Context.MODE_PRIVATE);
prefs.edit().putBoolean(MainActivity.PREF_IS_FIRST_LAUNCH, false).commit();
+
+ solo = new Solo(getInstrumentation(), getActivity());
}
@Override
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 4efd5f5b6..ae2e69b5c 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="de.danoeh.antennapod"
- android:versionCode="1040012"
- android:versionName="1.4.0.12">
+ android:versionCode="1040104"
+ android:versionName="1.4.1.4">
<!--
Version code schema:
"1.2.3-SNAPSHOT" -> 1020300
diff --git a/app/src/main/java/de/danoeh/antennapod/CrashReportWriter.java b/app/src/main/java/de/danoeh/antennapod/CrashReportWriter.java
new file mode 100644
index 000000000..17942a93c
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/CrashReportWriter.java
@@ -0,0 +1,49 @@
+package de.danoeh.antennapod;
+
+import android.os.Build;
+import android.util.Log;
+
+import org.apache.commons.io.IOUtils;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import de.danoeh.antennapod.core.preferences.UserPreferences;
+
+public class CrashReportWriter implements Thread.UncaughtExceptionHandler {
+
+ private static final String TAG = "CrashReportWriter";
+
+ private final Thread.UncaughtExceptionHandler defaultHandler;
+
+ public CrashReportWriter() {
+ defaultHandler = Thread.getDefaultUncaughtExceptionHandler();
+ }
+
+ public static File getFile() {
+ return new File(UserPreferences.getDataFolder(null), "crash-report.log");
+ }
+
+ @Override
+ public void uncaughtException(Thread thread, Throwable ex) {
+ File path = getFile();
+ PrintWriter out = null;
+ try {
+ out = new PrintWriter(new FileWriter(path));
+ out.println("[ Environment ]");
+ out.println("Android version: " + Build.VERSION.RELEASE);
+ out.println("AntennaPod version: " + BuildConfig.VERSION_NAME);
+ out.println("Phone model: " + Build.MODEL);
+ out.println();
+ out.println("[ StackTrace ]");
+ ex.printStackTrace(out);
+ } catch (IOException e) {
+ Log.e(TAG, Log.getStackTraceString(e));
+ } finally {
+ IOUtils.closeQuietly(out);
+ }
+ defaultHandler.uncaughtException(thread, ex);
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/PodcastApp.java b/app/src/main/java/de/danoeh/antennapod/PodcastApp.java
index 83bc9afb2..835f43f40 100644
--- a/app/src/main/java/de/danoeh/antennapod/PodcastApp.java
+++ b/app/src/main/java/de/danoeh/antennapod/PodcastApp.java
@@ -1,7 +1,6 @@
package de.danoeh.antennapod;
import android.app.Application;
-import android.content.res.Configuration;
import android.os.Build;
import android.os.StrictMode;
@@ -27,10 +26,6 @@ public class PodcastApp extends Application {
}
}
- private static final String TAG = "PodcastApp";
-
- private static float LOGICAL_DENSITY;
-
private static PodcastApp singleton;
public static PodcastApp getInstance() {
@@ -41,6 +36,8 @@ public class PodcastApp extends Application {
public void onCreate() {
super.onCreate();
+ Thread.setDefaultUncaughtExceptionHandler(new CrashReportWriter());
+
if(BuildConfig.DEBUG) {
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder()
.detectLeakedSqlLiteObjects()
@@ -57,7 +54,6 @@ public class PodcastApp extends Application {
}
singleton = this;
- LOGICAL_DENSITY = getResources().getDisplayMetrics().density;
PodDBAdapter.init(this);
UpdateManager.init(this);
@@ -68,15 +64,6 @@ public class PodcastApp extends Application {
Iconify.with(new FontAwesomeModule());
SPAUtil.sendSPAppsQueryFeedsIntent(this);
- }
-
- public static float getLogicalDensity() {
- return LOGICAL_DENSITY;
- }
-
- public boolean isLargeScreen() {
- return (getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_LARGE
- || (getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_XLARGE;
+ }
- }
}
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 b87870c69..220724af4 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java
@@ -13,6 +13,7 @@ import android.support.v4.app.ListFragment;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.widget.Toolbar;
+import android.text.TextUtils;
import android.util.Log;
import android.view.ContextMenu;
import android.view.Gravity;
@@ -35,7 +36,6 @@ import android.widget.TextView;
import com.bumptech.glide.Glide;
import org.apache.commons.lang3.ArrayUtils;
-import org.apache.commons.lang3.StringUtils;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.adapter.ChapterListAdapter;
@@ -246,7 +246,7 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc
@Override
protected void onResume() {
super.onResume();
- if (StringUtils.equals(getIntent().getAction(), Intent.ACTION_VIEW)) {
+ if (TextUtils.equals(getIntent().getAction(), Intent.ACTION_VIEW)) {
Intent intent = getIntent();
Log.d(TAG, "Received VIEW intent: " + intent.getData().getPath());
ExternalMedia media = new ExternalMedia(intent.getData().getPath(),
@@ -772,7 +772,7 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc
private DBReader.NavDrawerData navDrawerData;
private void loadData() {
- subscription = Observable.defer(() -> Observable.just(DBReader.getNavDrawerData()))
+ subscription = Observable.fromCallable(() -> DBReader.getNavDrawerData())
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
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 6915c817b..211b895d0 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java
@@ -8,6 +8,7 @@ import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.database.DataSetObserver;
import android.media.AudioManager;
+import android.media.Rating;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
@@ -41,10 +42,9 @@ import de.danoeh.antennapod.adapter.NavListAdapter;
import de.danoeh.antennapod.core.asynctask.FeedRemover;
import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
import de.danoeh.antennapod.core.event.ProgressEvent;
+import de.danoeh.antennapod.core.event.QueueEvent;
import de.danoeh.antennapod.core.feed.EventDistributor;
import de.danoeh.antennapod.core.feed.Feed;
-import de.danoeh.antennapod.core.event.QueueEvent;
-import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.service.playback.PlaybackService;
@@ -54,6 +54,7 @@ import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.util.StorageUtils;
import de.danoeh.antennapod.core.util.playback.Playable;
import de.danoeh.antennapod.core.util.playback.PlaybackController;
+import de.danoeh.antennapod.dialog.RatingDialog;
import de.danoeh.antennapod.fragment.AddFeedFragment;
import de.danoeh.antennapod.fragment.DownloadsFragment;
import de.danoeh.antennapod.fragment.EpisodesFragment;
@@ -76,9 +77,7 @@ public class MainActivity extends ActionBarActivity implements NavDrawerActivity
private static final String TAG = "MainActivity";
- private static final int EVENTS = EventDistributor.DOWNLOAD_HANDLED
- | EventDistributor.DOWNLOAD_QUEUED
- | EventDistributor.FEED_LIST_UPDATE
+ private static final int EVENTS = EventDistributor.FEED_LIST_UPDATE
| EventDistributor.UNREAD_ITEMS_UPDATE;
public static final String PREF_NAME = "MainActivityPrefs";
@@ -452,6 +451,7 @@ public class MainActivity extends ActionBarActivity implements NavDrawerActivity
super.onStart();
EventDistributor.getInstance().register(contentUpdate);
EventBus.getDefault().register(this);
+ RatingDialog.init(this);
}
@Override
@@ -469,8 +469,8 @@ public class MainActivity extends ActionBarActivity implements NavDrawerActivity
(intent.hasExtra(EXTRA_NAV_INDEX) || intent.hasExtra(EXTRA_FRAGMENT_TAG))) {
handleNavIntent();
}
-
loadData();
+ RatingDialog.check();
}
@Override
@@ -639,7 +639,7 @@ public class MainActivity extends ActionBarActivity implements NavDrawerActivity
};
private void loadData() {
- subscription = Observable.defer(() -> Observable.just(DBReader.getNavDrawerData()))
+ subscription = Observable.fromCallable(() -> DBReader.getNavDrawerData())
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
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 c67d65a9d..8c2b7f838 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java
@@ -9,6 +9,7 @@ import android.os.Looper;
import android.support.v4.app.NavUtils;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.AlertDialog;
+import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MenuItem;
@@ -41,6 +42,7 @@ import java.util.Map;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.adapter.FeedItemlistDescriptionAdapter;
import de.danoeh.antennapod.core.dialog.DownloadRequestErrorDialogCreator;
+import de.danoeh.antennapod.core.event.DownloadEvent;
import de.danoeh.antennapod.core.feed.EventDistributor;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedItem;
@@ -63,6 +65,7 @@ import de.danoeh.antennapod.core.util.StorageUtils;
import de.danoeh.antennapod.core.util.URLChecker;
import de.danoeh.antennapod.core.util.syndication.FeedDiscoverer;
import de.danoeh.antennapod.dialog.AuthenticationDialog;
+import de.greenrobot.event.EventBus;
import rx.Observable;
import rx.Subscriber;
import rx.Subscription;
@@ -86,7 +89,7 @@ public class OnlineFeedViewActivity extends ActionBarActivity {
// Optional argument: specify a title for the actionbar.
public static final String ARG_TITLE = "title";
- private static final int EVENTS = EventDistributor.DOWNLOAD_HANDLED | EventDistributor.DOWNLOAD_QUEUED | EventDistributor.FEED_LIST_UPDATE;
+ private static final int EVENTS = EventDistributor.FEED_LIST_UPDATE;
public static final int RESULT_ERROR = 2;
@@ -105,11 +108,16 @@ public class OnlineFeedViewActivity extends ActionBarActivity {
private Subscription parser;
private Subscription updater;
+ public void onEventMainThread(DownloadEvent event) {
+ Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
+ setSubscribeButtonState(feed);
+ }
+
private EventDistributor.EventListener listener = new EventDistributor.EventListener() {
@Override
public void update(EventDistributor eventDistributor, Integer arg) {
if ((arg & EventDistributor.FEED_LIST_UPDATE) != 0) {
- updater = Observable.defer(() -> Observable.just(DBReader.getFeedList()))
+ updater = Observable.fromCallable(() -> DBReader.getFeedList())
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(feeds -> {
@@ -138,9 +146,9 @@ public class OnlineFeedViewActivity extends ActionBarActivity {
final String feedUrl;
if (getIntent().hasExtra(ARG_FEEDURL)) {
feedUrl = getIntent().getStringExtra(ARG_FEEDURL);
- } else if (StringUtils.equals(getIntent().getAction(), Intent.ACTION_SEND)
- || StringUtils.equals(getIntent().getAction(), Intent.ACTION_VIEW)) {
- feedUrl = (StringUtils.equals(getIntent().getAction(), Intent.ACTION_SEND))
+ } else if (TextUtils.equals(getIntent().getAction(), Intent.ACTION_SEND)
+ || TextUtils.equals(getIntent().getAction(), Intent.ACTION_VIEW)) {
+ feedUrl = (TextUtils.equals(getIntent().getAction(), Intent.ACTION_SEND))
? getIntent().getStringExtra(Intent.EXTRA_TEXT) : getIntent().getDataString();
getSupportActionBar().setTitle(R.string.add_new_feed_label);
} else {
@@ -180,7 +188,7 @@ public class OnlineFeedViewActivity extends ActionBarActivity {
super.onResume();
isPaused = false;
EventDistributor.getInstance().register(listener);
-
+ EventBus.getDefault().register(this);
}
@Override
@@ -188,6 +196,7 @@ public class OnlineFeedViewActivity extends ActionBarActivity {
super.onPause();
isPaused = true;
EventDistributor.getInstance().unregister(listener);
+ EventBus.getDefault().unregister(this);
}
@Override
@@ -314,7 +323,7 @@ public class OnlineFeedViewActivity extends ActionBarActivity {
subscriber.onNext(result);
} catch (UnsupportedFeedtypeException e) {
Log.d(TAG, "Unsupported feed type detected");
- if (StringUtils.equalsIgnoreCase("html", e.getRootElement())) {
+ if (TextUtils.equals("html", e.getRootElement().toLowerCase())) {
showFeedDiscoveryDialog(new File(feed.getFile_url()), feed.getDownload_url());
} else {
subscriber.onError(e);
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 173bec6b2..7f975b3c8 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/StorageErrorActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/StorageErrorActivity.java
@@ -6,10 +6,9 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
+import android.text.TextUtils;
import android.util.Log;
-import org.apache.commons.lang3.StringUtils;
-
import de.danoeh.antennapod.BuildConfig;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.preferences.UserPreferences;
@@ -57,7 +56,7 @@ public class StorageErrorActivity extends ActionBarActivity {
@Override
public void onReceive(Context context, Intent intent) {
- if (StringUtils.equals(intent.getAction(), Intent.ACTION_MEDIA_MOUNTED)) {
+ if (TextUtils.equals(intent.getAction(), Intent.ACTION_MEDIA_MOUNTED)) {
if (intent.getBooleanExtra("read-only", true)) {
if (BuildConfig.DEBUG)
Log.d(TAG, "Media was mounted; Finishing activity");
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/ActionButtonUtils.java b/app/src/main/java/de/danoeh/antennapod/adapter/ActionButtonUtils.java
index 74cf6af60..1a8f0a67a 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/ActionButtonUtils.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/ActionButtonUtils.java
@@ -7,14 +7,10 @@ import android.widget.ImageButton;
import org.apache.commons.lang3.Validate;
-import java.lang.ref.WeakReference;
-
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
-import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DownloadRequester;
-import de.danoeh.antennapod.core.util.LongList;
/**
* Utility methods for the action button that is displayed on the right hand side
@@ -51,7 +47,7 @@ public class ActionButtonUtils {
* Sets the displayed bitmap and content description of the given
* action button so that it matches the state of the FeedItem.
*/
- public void configureActionButton(ImageButton butSecondary, FeedItem item) {
+ public void configureActionButton(ImageButton butSecondary, FeedItem item, boolean isInQueue) {
Validate.isTrue(butSecondary != null && item != null, "butSecondary or item was null");
final FeedMedia media = item.getMedia();
@@ -66,9 +62,8 @@ public class ActionButtonUtils {
butSecondary.setContentDescription(context.getString(labels[1]));
} else {
// item is not downloaded and not being downloaded
- LongList queueIds = DBReader.getQueueIDList();
if(DefaultActionButtonCallback.userAllowedMobileDownloads() ||
- !DefaultActionButtonCallback.userChoseAddToQueue() || queueIds.contains(item.getId())) {
+ !DefaultActionButtonCallback.userChoseAddToQueue() || isInQueue) {
butSecondary.setVisibility(View.VISIBLE);
butSecondary.setImageDrawable(drawables.getDrawable(2));
butSecondary.setContentDescription(context.getString(labels[2]));
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 b35ff0aa9..f120aa1d5 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java
@@ -1,22 +1,21 @@
package de.danoeh.antennapod.adapter;
-import android.content.Context;
import android.graphics.drawable.Drawable;
import android.net.Uri;
-import android.support.v7.widget.PopupMenu;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;
import android.text.format.DateUtils;
import android.util.Log;
import android.view.ContextMenu;
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.FrameLayout;
import android.widget.ImageButton;
import android.widget.ImageView;
+import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
@@ -34,7 +33,7 @@ import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.glide.ApGlideSettings;
-import de.danoeh.antennapod.core.storage.DownloadRequestException;
+import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.storage.DownloadRequester;
import de.danoeh.antennapod.core.util.Converter;
import de.danoeh.antennapod.core.util.NetworkUtils;
@@ -48,27 +47,34 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
private static final String TAG = AllEpisodesRecycleAdapter.class.getSimpleName();
- private final Context context;
+ private final WeakReference<MainActivity> mainActivityRef;
private final ItemAccess itemAccess;
private final ActionButtonCallback actionButtonCallback;
private final ActionButtonUtils actionButtonUtils;
private final boolean showOnlyNewEpisodes;
- private final WeakReference<MainActivity> mainActivityRef;
private int position = -1;
- public AllEpisodesRecycleAdapter(Context context,
- MainActivity mainActivity,
+ private final int playingBackGroundColor;
+ private final int normalBackGroundColor;
+
+ public AllEpisodesRecycleAdapter(MainActivity mainActivity,
ItemAccess itemAccess,
ActionButtonCallback actionButtonCallback,
boolean showOnlyNewEpisodes) {
super();
this.mainActivityRef = new WeakReference<>(mainActivity);
- this.context = context;
this.itemAccess = itemAccess;
- this.actionButtonUtils = new ActionButtonUtils(context);
+ this.actionButtonUtils = new ActionButtonUtils(mainActivity);
this.actionButtonCallback = actionButtonCallback;
this.showOnlyNewEpisodes = showOnlyNewEpisodes;
+
+ if(UserPreferences.getTheme() == R.style.Theme_AntennaPod_Dark) {
+ playingBackGroundColor = mainActivity.getResources().getColor(R.color.highlight_dark);
+ } else {
+ playingBackGroundColor = mainActivity.getResources().getColor(R.color.highlight_light);
+ }
+ normalBackGroundColor = mainActivity.getResources().getColor(android.R.color.transparent);
}
@Override
@@ -76,6 +82,7 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.new_episodes_listitem, parent, false);
Holder holder = new Holder(view);
+ holder.container = (FrameLayout) view.findViewById(R.id.container);
holder.placeholder = (TextView) view.findViewById(R.id.txtvPlaceholder);
holder.title = (TextView) view.findViewById(R.id.txtvTitle);
holder.pubDate = (TextView) view
@@ -111,7 +118,8 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
holder.placeholder.setVisibility(View.VISIBLE);
holder.placeholder.setText(item.getFeed().getTitle());
holder.title.setText(item.getTitle());
- holder.pubDate.setText(DateUtils.formatDateTime(context, item.getPubDate().getTime(), DateUtils.FORMAT_ABBREV_ALL));
+ holder.pubDate.setText(DateUtils.formatDateTime(mainActivityRef.get(),
+ item.getPubDate().getTime(), DateUtils.FORMAT_ABBREV_ALL));
if (showOnlyNewEpisodes || false == item.isNew()) {
holder.statusUnread.setVisibility(View.INVISIBLE);
} else {
@@ -161,23 +169,29 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
holder.progress.setVisibility(View.GONE);
}
+ if(media.isCurrentlyPlaying()) {
+ holder.container.setBackgroundColor(playingBackGroundColor);
+ } else {
+ holder.container.setBackgroundColor(normalBackGroundColor);
+ }
} else {
holder.progress.setVisibility(View.GONE);
holder.txtvDuration.setVisibility(View.GONE);
}
- if (itemAccess.isInQueue(item)) {
+ boolean isInQueue = itemAccess.isInQueue(item);
+ if (isInQueue) {
holder.queueStatus.setVisibility(View.VISIBLE);
} else {
holder.queueStatus.setVisibility(View.INVISIBLE);
}
- actionButtonUtils.configureActionButton(holder.butSecondary, item);
+ actionButtonUtils.configureActionButton(holder.butSecondary, item, isInQueue);
holder.butSecondary.setFocusable(false);
holder.butSecondary.setTag(item);
holder.butSecondary.setOnClickListener(secondaryActionListener);
- Glide.with(context)
+ Glide.with(mainActivityRef.get())
.load(item.getImageUri())
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
.fitCenter()
@@ -224,7 +238,7 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
TextView txtvPlaceholder = placeholder.get();
ImageView imgvCover = cover.get();
if(fallbackUri != null && txtvPlaceholder != null && imgvCover != null) {
- Glide.with(context)
+ Glide.with(mainActivityRef.get())
.load(fallbackUri)
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
.fitCenter()
@@ -255,6 +269,7 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
implements View.OnClickListener,
View.OnCreateContextMenuListener,
ItemTouchHelperViewHolder {
+ FrameLayout container;
TextView placeholder;
TextView title;
TextView pubDate;
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 4ccff39af..9d7a509cf 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java
@@ -7,11 +7,11 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
-import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import com.joanzapata.iconify.Iconify;
+import com.joanzapata.iconify.widget.IconButton;
import java.util.Date;
@@ -50,7 +50,7 @@ public class DownloadLogAdapter extends BaseAdapter {
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.downloadlog_item, parent, false);
holder.icon = (TextView) convertView.findViewById(R.id.txtvIcon);
- holder.retry = (Button) convertView.findViewById(R.id.btnRetry);
+ holder.retry = (IconButton) convertView.findViewById(R.id.btnRetry);
holder.date = (TextView) convertView.findViewById(R.id.txtvDate);
holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
holder.type = (TextView) convertView.findViewById(R.id.txtvType);
@@ -96,8 +96,6 @@ public class DownloadLogAdapter extends BaseAdapter {
if(status.getFeedfileType() != FeedImage.FEEDFILETYPE_FEEDIMAGE &&
!newerWasSuccessful(position, status.getFeedfileType(), status.getFeedfileId())) {
holder.retry.setVisibility(View.VISIBLE);
- holder.retry.setText("{fa-repeat}");
- Iconify.addIcons(holder.retry);
holder.retry.setOnClickListener(clickListener);
ButtonHolder btnHolder;
if(holder.retry.getTag() != null) {
@@ -161,7 +159,7 @@ public class DownloadLogAdapter extends BaseAdapter {
static class Holder {
TextView icon;
- Button retry;
+ IconButton retry;
TextView title;
TextView type;
TextView date;
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 507d1adbc..1972e675e 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java
@@ -11,6 +11,7 @@ import android.widget.Adapter;
import android.widget.BaseAdapter;
import android.widget.ImageButton;
import android.widget.ImageView;
+import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
@@ -39,6 +40,9 @@ public class FeedItemlistAdapter extends BaseAdapter {
public static final int SELECTION_NONE = -1;
+ private final int playingBackGroundColor;
+ private final int normalBackGroundColor;
+
public FeedItemlistAdapter(Context context,
ItemAccess itemAccess,
ActionButtonCallback callback,
@@ -52,6 +56,9 @@ public class FeedItemlistAdapter extends BaseAdapter {
this.selectedItemIndex = SELECTION_NONE;
this.actionButtonUtils = new ActionButtonUtils(context);
this.makePlayedItemsTransparent = makePlayedItemsTransparent;
+
+ playingBackGroundColor = context.getResources().getColor(R.color.highlight_light);
+ normalBackGroundColor = context.getResources().getColor(android.R.color.transparent);
}
@Override
@@ -80,6 +87,8 @@ public class FeedItemlistAdapter extends BaseAdapter {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.feeditemlist_item, parent, false);
+ holder.container = (LinearLayout) convertView
+ .findViewById(R.id.container);
holder.title = (TextView) convertView
.findViewById(R.id.txtvItemname);
holder.lenSize = (TextView) convertView
@@ -174,9 +183,18 @@ public class FeedItemlistAdapter extends BaseAdapter {
holder.type.setImageBitmap(null);
holder.type.setVisibility(View.GONE);
}
+
+ if(media.isCurrentlyPlaying()) {
+ if(media.isCurrentlyPlaying()) {
+ holder.container.setBackgroundColor(playingBackGroundColor);
+ } else {
+ holder.container.setBackgroundColor(normalBackGroundColor);
+ }
+ }
}
- actionButtonUtils.configureActionButton(holder.butAction, item);
+ boolean isInQueue = itemAccess.isInQueue(item);
+ actionButtonUtils.configureActionButton(holder.butAction, item, isInQueue);
holder.butAction.setFocusable(false);
holder.butAction.setTag(item);
holder.butAction.setOnClickListener(butActionListener);
@@ -196,6 +214,7 @@ public class FeedItemlistAdapter extends BaseAdapter {
};
static class Holder {
+ LinearLayout container;
TextView title;
TextView published;
TextView lenSize;
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 8593e0dde..3e4dd4deb 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java
@@ -4,19 +4,18 @@ import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.support.annotation.Nullable;
import android.support.v4.view.MotionEventCompat;
-import android.support.v7.widget.PopupMenu;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;
import android.text.format.DateUtils;
import android.util.Log;
import android.view.ContextMenu;
import android.view.LayoutInflater;
-import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.ProgressBar;
@@ -37,7 +36,6 @@ import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.glide.ApGlideSettings;
import de.danoeh.antennapod.core.preferences.UserPreferences;
-import de.danoeh.antennapod.core.storage.DownloadRequestException;
import de.danoeh.antennapod.core.storage.DownloadRequester;
import de.danoeh.antennapod.core.util.Converter;
import de.danoeh.antennapod.core.util.LongList;
@@ -62,6 +60,9 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap
private FeedItem selectedItem;
+ private final int playingBackGroundColor;
+ private final int normalBackGroundColor;
+
public QueueRecyclerAdapter(MainActivity mainActivity,
ItemAccess itemAccess,
ActionButtonCallback actionButtonCallback,
@@ -73,6 +74,13 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap
this.actionButtonCallback = actionButtonCallback;
this.itemTouchHelper = itemTouchHelper;
locked = UserPreferences.isQueueLocked();
+
+ if(UserPreferences.getTheme() == R.style.Theme_AntennaPod_Dark) {
+ playingBackGroundColor = mainActivity.getResources().getColor(R.color.highlight_dark);
+ } else {
+ playingBackGroundColor = mainActivity.getResources().getColor(R.color.highlight_light);
+ }
+ normalBackGroundColor = mainActivity.getResources().getColor(android.R.color.transparent);
}
public void setLocked(boolean locked) {
@@ -108,6 +116,7 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap
View.OnCreateContextMenuListener,
ItemTouchHelperViewHolder {
+ private final FrameLayout container;
private final ImageView dragHandle;
private final TextView placeholder;
private final ImageView cover;
@@ -122,6 +131,7 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap
public ViewHolder(View v) {
super(v);
+ container = (FrameLayout) v.findViewById(R.id.container);
dragHandle = (ImageView) v.findViewById(R.id.drag_handle);
placeholder = (TextView) v.findViewById(R.id.txtvPlaceholder);
cover = (ImageView) v.findViewById(R.id.imgvCover);
@@ -249,9 +259,15 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap
progressRight.setText(Converter.getDurationStringLong(media.getDuration()));
progressBar.setVisibility(View.GONE);
}
+
+ if(media.isCurrentlyPlaying()) {
+ container.setBackgroundColor(playingBackGroundColor);
+ } else {
+ container.setBackgroundColor(normalBackGroundColor);
+ }
}
- actionButtonUtils.configureActionButton(butSecondary, item);
+ actionButtonUtils.configureActionButton(butSecondary, item, true);
butSecondary.setFocusable(false);
butSecondary.setTag(item);
butSecondary.setOnClickListener(secondaryActionListener);
@@ -264,7 +280,6 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap
.into(new CoverTarget(item.getFeed().getImageUri(), placeholder, cover));
}
-
}
diff --git a/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlExportWorker.java b/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlExportWorker.java
index 3940eb8b6..5c24c2822 100644
--- a/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlExportWorker.java
+++ b/app/src/main/java/de/danoeh/antennapod/asynctask/OpmlExportWorker.java
@@ -49,7 +49,7 @@ public class OpmlExportWorker extends AsyncTask<Void, Void, Void> {
OpmlWriter opmlWriter = new OpmlWriter();
if (output == null) {
output = new File(
- UserPreferences.getDataFolder(context, EXPORT_DIR),
+ UserPreferences.getDataFolder(EXPORT_DIR),
DEFAULT_OUTPUT_NAME);
if (output.exists()) {
Log.w(TAG, "Overwriting previously exported file.");
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 c5b6ddb65..e867540e4 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java
@@ -11,7 +11,6 @@ import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
@@ -23,7 +22,6 @@ import com.joanzapata.iconify.fonts.FontAwesomeIcons;
import java.util.ArrayList;
import java.util.Collections;
-import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -58,9 +56,15 @@ public class EpisodesApplyActionFragment extends Fragment {
private int textColor;
- public EpisodesApplyActionFragment(List<FeedItem> episodes) {
- this.episodes = episodes;
- this.idMap = new HashMap<>(episodes.size());
+ public EpisodesApplyActionFragment() {
+ this.episodes = new ArrayList<>();
+ this.idMap = new HashMap<>();
+ }
+
+ public void setEpisodes(List<FeedItem> episodes) {
+ this.episodes.clear();
+ this.episodes.addAll(episodes);
+ this.idMap.clear();
for(FeedItem episode : episodes) {
this.idMap.put(episode.getId(), episode);
}
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/RatingDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/RatingDialog.java
new file mode 100644
index 000000000..ed0db92a4
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/RatingDialog.java
@@ -0,0 +1,136 @@
+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.util.Log;
+
+import com.afollestad.materialdialogs.MaterialDialog;
+
+import java.lang.ref.WeakReference;
+import java.util.concurrent.TimeUnit;
+
+import de.danoeh.antennapod.R;
+
+public class RatingDialog {
+
+ private static final String TAG = RatingDialog.class.getSimpleName();
+ private static final int AFTER_DAYS = 7;
+
+ private static WeakReference<Context> mContext;
+ private static SharedPreferences mPreferences;
+ private static Dialog mDialog;
+
+ private static final String PREFS_NAME = "RatingPrefs";
+ private static final String KEY_RATED = "KEY_WAS_RATED";
+ private static final String KEY_FIRST_START_DATE = "KEY_FIRST_HIT_DATE";
+
+ public static void init(Context context) {
+ mContext = new WeakReference<>(context);
+ mPreferences = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
+
+ long firstDate = mPreferences.getLong(KEY_FIRST_START_DATE, 0);
+ if (firstDate == 0) {
+ resetStartDate();
+ }
+ }
+
+ public static void check() {
+ if (mDialog != null && mDialog.isShowing()) {
+ return;
+ }
+ if (shouldShow()) {
+ try {
+ mDialog = createDialog();
+ if (mDialog != null) {
+ mDialog.show();
+ }
+ } catch (Exception e) {
+ Log.e(TAG, Log.getStackTraceString(e));
+ }
+ }
+ }
+
+ public static void rateNow() {
+ Context context = mContext.get();
+ if(context == null) {
+ return;
+ }
+ final String appPackage = "de.danoeh.antennapod";
+ final Uri uri = Uri.parse("https://play.google.com/store/apps/details?id=" + appPackage);
+ Intent intent = new Intent(Intent.ACTION_VIEW, uri);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ context.startActivity(intent);
+ saveRated();
+ }
+
+ public static boolean rated() {
+ return mPreferences.getBoolean(KEY_RATED, false);
+ }
+
+ public static void saveRated() {
+ mPreferences
+ .edit()
+ .putBoolean(KEY_RATED, true)
+ .apply();
+ }
+
+ private static void resetStartDate() {
+ mPreferences
+ .edit()
+ .putLong(KEY_FIRST_START_DATE, System.currentTimeMillis())
+ .apply();
+ }
+
+ private static boolean shouldShow() {
+ if (rated()) {
+ return false;
+ }
+
+ long now = System.currentTimeMillis();
+ long firstDate = mPreferences.getLong(KEY_FIRST_START_DATE, now);
+ long diff = now - firstDate;
+ long diffDays = TimeUnit.DAYS.convert(diff, TimeUnit.MILLISECONDS);
+ if (diffDays >= AFTER_DAYS) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ @Nullable
+ private static MaterialDialog createDialog() {
+ Context context = mContext.get();
+ if(context == null) {
+ return null;
+ }
+ MaterialDialog dialog = new MaterialDialog.Builder(context)
+ .title(R.string.rating_title)
+ .content(R.string.rating_message)
+ .positiveText(R.string.rating_now_label)
+ .negativeText(R.string.rating_never_label)
+ .neutralText(R.string.rating_later_label)
+ .callback(new MaterialDialog.ButtonCallback() {
+ @Override
+ public void onPositive(MaterialDialog dialog) {
+ rateNow();
+ }
+
+ @Override
+ public void onNegative(MaterialDialog dialog) {
+ saveRated();
+ }
+
+ @Override
+ public void onNeutral(MaterialDialog dialog) {
+ resetStartDate();
+ }
+ })
+ .cancelListener(dialog1 -> resetStartDate())
+ .build();
+ return dialog;
+ }
+}
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 cdd6bc265..37be8f020 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java
@@ -5,7 +5,6 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.os.Bundle;
-import android.os.Handler;
import android.support.v4.app.Fragment;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.widget.LinearLayoutManager;
@@ -30,8 +29,10 @@ import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.adapter.AllEpisodesRecycleAdapter;
import de.danoeh.antennapod.adapter.DefaultActionButtonCallback;
-import de.danoeh.antennapod.core.asynctask.DownloadObserver;
import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
+import de.danoeh.antennapod.core.event.DownloadEvent;
+import de.danoeh.antennapod.core.event.DownloaderUpdate;
+import de.danoeh.antennapod.core.event.FeedItemEvent;
import de.danoeh.antennapod.core.feed.EventDistributor;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedItem;
@@ -43,8 +44,10 @@ import de.danoeh.antennapod.core.storage.DBTasks;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.storage.DownloadRequestException;
import de.danoeh.antennapod.core.storage.DownloadRequester;
+import de.danoeh.antennapod.core.util.FeedItemUtil;
import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
import de.danoeh.antennapod.menuhandler.MenuItemUtils;
+import de.greenrobot.event.EventBus;
import rx.Observable;
import rx.Subscription;
import rx.android.schedulers.AndroidSchedulers;
@@ -57,9 +60,7 @@ public class AllEpisodesFragment extends Fragment {
public static final String TAG = "AllEpisodesFragment";
- private static final int EVENTS = EventDistributor.DOWNLOAD_HANDLED |
- EventDistributor.FEED_LIST_UPDATE |
- EventDistributor.DOWNLOAD_QUEUED |
+ private static final int EVENTS = EventDistributor.FEED_LIST_UPDATE |
EventDistributor.UNREAD_ITEMS_UPDATE |
EventDistributor.PLAYER_STATUS_UPDATE;
@@ -80,8 +81,6 @@ public class AllEpisodesFragment extends Fragment {
private AtomicReference<MainActivity> activity = new AtomicReference<MainActivity>();
- private DownloadObserver downloadObserver = null;
-
private boolean isUpdatingFeeds;
protected Subscription subscription;
@@ -101,10 +100,6 @@ public class AllEpisodesFragment extends Fragment {
super.onStart();
EventDistributor.getInstance().register(contentUpdate);
this.activity.set((MainActivity) getActivity());
- if (downloadObserver != null) {
- downloadObserver.setActivity(getActivity());
- downloadObserver.onResume();
- }
if (viewsCreated && itemsLoaded) {
onFragmentLoaded();
}
@@ -113,6 +108,7 @@ public class AllEpisodesFragment extends Fragment {
@Override
public void onResume() {
super.onResume();
+ EventBus.getDefault().registerSticky(this);
loadItems();
registerForContextMenu(recyclerView);
}
@@ -120,6 +116,7 @@ public class AllEpisodesFragment extends Fragment {
@Override
public void onPause() {
super.onPause();
+ EventBus.getDefault().unregister(this);
saveScrollPosition();
unregisterForContextMenu(recyclerView);
}
@@ -180,9 +177,6 @@ public class AllEpisodesFragment extends Fragment {
listAdapter = null;
activity.set(null);
viewsCreated = false;
- if (downloadObserver != null) {
- downloadObserver.onPause();
- }
}
@@ -267,9 +261,13 @@ public class AllEpisodesFragment extends Fragment {
@Override
public boolean onContextItemSelected(MenuItem item) {
+ Log.d(TAG, "onContextItemSelected() called with: " + "item = [" + item + "]");
if(!isVisible()) {
return false;
}
+ if(item.getItemId() == R.id.share_item) {
+ return true; // avoids that the position is reset when we need it in the submenu
+ }
int pos = listAdapter.getPosition();
if(pos < 0) {
return false;
@@ -327,11 +325,10 @@ public class AllEpisodesFragment extends Fragment {
private void onFragmentLoaded() {
if (listAdapter == null) {
- listAdapter = new AllEpisodesRecycleAdapter(activity.get(), activity.get(), itemAccess,
- new DefaultActionButtonCallback(activity.get()), showOnlyNewEpisodes());
+ MainActivity mainActivity = activity.get();
+ listAdapter = new AllEpisodesRecycleAdapter(mainActivity, itemAccess,
+ new DefaultActionButtonCallback(mainActivity), showOnlyNewEpisodes());
recyclerView.setAdapter(listAdapter);
- downloadObserver = new DownloadObserver(activity.get(), new Handler(), downloadObserverCallback);
- downloadObserver.onResume();
}
listAdapter.notifyDataSetChanged();
restoreScrollPosition();
@@ -339,21 +336,11 @@ public class AllEpisodesFragment extends Fragment {
updateShowOnlyEpisodesListViewState();
}
- private DownloadObserver.Callback downloadObserverCallback = new DownloadObserver.Callback() {
- @Override
- public void onContentChanged(List<Downloader> downloaderList) {
- AllEpisodesFragment.this.downloaderList = downloaderList;
- if (listAdapter != null) {
- listAdapter.notifyDataSetChanged();
- }
- }
- };
-
protected AllEpisodesRecycleAdapter.ItemAccess itemAccess = new AllEpisodesRecycleAdapter.ItemAccess() {
@Override
public int getCount() {
- if (itemsLoaded) {
+ if (episodes != null) {
return episodes.size();
}
return 0;
@@ -361,7 +348,7 @@ public class AllEpisodesFragment extends Fragment {
@Override
public FeedItem getItem(int position) {
- if (itemsLoaded) {
+ if (episodes != null && position < episodes.size()) {
return episodes.get(position);
}
return null;
@@ -389,6 +376,39 @@ public class AllEpisodesFragment extends Fragment {
}
};
+ public void onEventMainThread(FeedItemEvent event) {
+ Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
+ if(episodes == null || listAdapter == null) {
+ return;
+ }
+ for(int i=0, size = event.items.size(); i < size; i++) {
+ FeedItem item = event.items.get(i);
+ int pos = FeedItemUtil.indexOfItemWithId(episodes, item.getId());
+ if(pos >= 0) {
+ episodes.remove(pos);
+ episodes.add(pos, item);
+ listAdapter.notifyItemChanged(pos);
+ }
+ }
+ }
+
+
+ public void onEventMainThread(DownloadEvent event) {
+ Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
+ DownloaderUpdate update = event.update;
+ downloaderList = update.downloaders;
+ if(update.feedIds.length > 0) {
+ if (isUpdatingFeeds != updateRefreshMenuItemChecker.isRefreshing()) {
+ getActivity().supportInvalidateOptionsMenu();
+ }
+ }
+ if(update.mediaIds.length > 0) {
+ if(listAdapter != null) {
+ listAdapter.notifyDataSetChanged();
+ }
+ }
+ }
+
private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
@Override
public void update(EventDistributor eventDistributor, Integer arg) {
@@ -412,7 +432,7 @@ public class AllEpisodesFragment extends Fragment {
recyclerView.setVisibility(View.GONE);
progLoading.setVisibility(View.VISIBLE);
}
- subscription = Observable.defer(() -> Observable.just(loadData()))
+ subscription = Observable.fromCallable(() -> loadData())
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(data -> {
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 c5b582d3a..a5568b16e 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java
@@ -156,7 +156,7 @@ public class CompletedDownloadsFragment extends ListFragment {
if (!itemsLoaded && viewCreated) {
setListShown(false);
}
- subscription = Observable.defer(() -> Observable.just(DBReader.getDownloadedItems()))
+ subscription = Observable.fromCallable(() -> DBReader.getDownloadedItems())
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
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 669c6ac49..90cacd2e4 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/DownloadLogFragment.java
@@ -147,7 +147,7 @@ public class DownloadLogFragment extends ListFragment {
if(subscription != null) {
subscription.unsubscribe();
}
- subscription = Observable.defer(() -> Observable.just(DBReader.getDownloadLog()))
+ subscription = Observable.fromCallable(() -> DBReader.getDownloadLog())
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
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 532516dda..65305df3d 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java
@@ -17,7 +17,6 @@ import de.danoeh.antennapod.core.event.FavoritesEvent;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBWriter;
-import de.greenrobot.event.EventBus;
/**
@@ -38,23 +37,11 @@ public class FavoriteEpisodesFragment extends AllEpisodesFragment {
protected String getPrefName() { return PREF_NAME; }
public void onEvent(FavoritesEvent event) {
- Log.d(TAG, "onEvent(" + event + ")");
+ Log.d(TAG, "onEvent() called with: " + "event = [" + event + "]");
loadItems();
}
@Override
- public void onStart() {
- super.onStart();
- EventBus.getDefault().register(this);
- }
-
- @Override
- public void onStop() {
- super.onStop();
- EventBus.getDefault().unregister(this);
- }
-
- @Override
protected void resetViewState() {
super.resetViewState();
}
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 dc9f9740d..10d56d5cf 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java
@@ -8,7 +8,6 @@ import android.content.res.TypedArray;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
-import android.os.Handler;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.util.Pair;
@@ -35,12 +34,16 @@ import android.widget.Toast;
import com.bumptech.glide.Glide;
+import org.apache.commons.lang3.ArrayUtils;
+
import java.util.List;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.adapter.DefaultActionButtonCallback;
-import de.danoeh.antennapod.core.asynctask.DownloadObserver;
+import de.danoeh.antennapod.core.event.DownloadEvent;
+import de.danoeh.antennapod.core.event.DownloaderUpdate;
+import de.danoeh.antennapod.core.event.FeedItemEvent;
import de.danoeh.antennapod.core.event.QueueEvent;
import de.danoeh.antennapod.core.feed.EventDistributor;
import de.danoeh.antennapod.core.feed.FeedItem;
@@ -72,9 +75,7 @@ public class ItemFragment extends Fragment {
private static final String TAG = "ItemFragment";
- private static final int EVENTS = EventDistributor.DOWNLOAD_HANDLED |
- EventDistributor.DOWNLOAD_QUEUED |
- EventDistributor.UNREAD_ITEMS_UPDATE;
+ private static final int EVENTS = EventDistributor.UNREAD_ITEMS_UPDATE;
private static final String ARG_FEEDITEM = "feeditem";
@@ -97,7 +98,6 @@ public class ItemFragment extends Fragment {
private FeedItem item;
private LongList queue;
private String webviewData;
- private DownloadObserver downloadObserver;
private List<Downloader> downloaderList;
private ViewGroup root;
@@ -263,11 +263,7 @@ public class ItemFragment extends Fragment {
public void onResume() {
super.onResume();
EventDistributor.getInstance().register(contentUpdate);
- EventBus.getDefault().register(this);
- if (downloadObserver != null) {
- downloadObserver.setActivity(getActivity());
- downloadObserver.onResume();
- }
+ EventBus.getDefault().registerSticky(this);
if(itemsLoaded) {
updateAppearance();
}
@@ -294,9 +290,6 @@ public class ItemFragment extends Fragment {
}
private void resetViewState() {
- if (downloadObserver != null) {
- downloadObserver.onPause();
- }
Toolbar toolbar = ((MainActivity) getActivity()).getToolbar();
toolbar.removeView(header);
}
@@ -319,8 +312,6 @@ public class ItemFragment extends Fragment {
"utf-8", "about:blank");
}
updateAppearance();
- downloadObserver = new DownloadObserver(getActivity(), new Handler(), downloadObserverCallback);
- downloadObserver.onResume();
}
private void updateAppearance() {
@@ -486,27 +477,41 @@ public class ItemFragment extends Fragment {
public void onEventMainThread(QueueEvent event) {
if(event.contains(itemID)) {
- updateAppearance();
+ load();
}
}
+ public void onEventMainThread(FeedItemEvent event) {
+ Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
+ for(FeedItem item : event.items) {
+ if(itemID == item.getId()) {
+ load();
+ return;
+ }
+ }
+ }
- private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
- @Override
- public void update(EventDistributor eventDistributor, Integer arg) {
- if ((arg & EVENTS) != 0) {
+ public void onEventMainThread(DownloadEvent event) {
+ Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
+ DownloaderUpdate update = event.update;
+ downloaderList = update.downloaders;
+ if(item == null || item.getMedia() == null) {
+ return;
+ }
+ long mediaId = item.getMedia().getId();
+ if(ArrayUtils.contains(update.mediaIds, mediaId)) {
+ if (itemsLoaded && getActivity() != null) {
updateAppearance();
}
}
- };
+ }
- private final DownloadObserver.Callback downloadObserverCallback = new DownloadObserver.Callback() {
+ private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
@Override
- public void onContentChanged(List<Downloader> downloaderList) {
- ItemFragment.this.downloaderList = downloaderList;
- if (itemsLoaded && getActivity() != null) {
- updateAppearance();
+ public void update(EventDistributor eventDistributor, Integer arg) {
+ if ((arg & EVENTS) != 0) {
+ load();
}
}
};
@@ -515,7 +520,7 @@ public class ItemFragment extends Fragment {
if(subscription != null) {
subscription.unsubscribe();
}
- subscription = Observable.defer(() -> Observable.just(loadInBackground()))
+ subscription = Observable.fromCallable(() -> loadInBackground())
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java
index ba3dfc2af..09d2f5676 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java
@@ -9,7 +9,6 @@ import android.graphics.Color;
import android.graphics.LightingColorFilter;
import android.os.Build;
import android.os.Bundle;
-import android.os.Handler;
import android.support.v4.app.Fragment;
import android.support.v4.app.ListFragment;
import android.support.v4.util.Pair;
@@ -46,17 +45,19 @@ import de.danoeh.antennapod.activity.FeedInfoActivity;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.adapter.DefaultActionButtonCallback;
import de.danoeh.antennapod.adapter.FeedItemlistAdapter;
-import de.danoeh.antennapod.core.asynctask.DownloadObserver;
import de.danoeh.antennapod.core.asynctask.FeedRemover;
import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
import de.danoeh.antennapod.core.dialog.DownloadRequestErrorDialogCreator;
+import de.danoeh.antennapod.core.event.DownloadEvent;
+import de.danoeh.antennapod.core.event.DownloaderUpdate;
+import de.danoeh.antennapod.core.event.FeedItemEvent;
+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.FeedEvent;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedItemFilter;
import de.danoeh.antennapod.core.feed.FeedMedia;
-import de.danoeh.antennapod.core.event.QueueEvent;
import de.danoeh.antennapod.core.glide.ApGlideSettings;
import de.danoeh.antennapod.core.glide.FastBlurTransformation;
import de.danoeh.antennapod.core.preferences.UserPreferences;
@@ -66,6 +67,7 @@ import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBTasks;
import de.danoeh.antennapod.core.storage.DownloadRequestException;
import de.danoeh.antennapod.core.storage.DownloadRequester;
+import de.danoeh.antennapod.core.util.FeedItemUtil;
import de.danoeh.antennapod.core.util.LongList;
import de.danoeh.antennapod.core.util.gui.MoreContentListFooterUtil;
import de.danoeh.antennapod.dialog.EpisodesApplyActionFragment;
@@ -85,9 +87,7 @@ import rx.schedulers.Schedulers;
public class ItemlistFragment extends ListFragment {
private static final String TAG = "ItemlistFragment";
- private static final int EVENTS = EventDistributor.DOWNLOAD_HANDLED
- | EventDistributor.DOWNLOAD_QUEUED
- | EventDistributor.UNREAD_ITEMS_UPDATE
+ private static final int EVENTS = EventDistributor.UNREAD_ITEMS_UPDATE
| EventDistributor.PLAYER_STATUS_UPDATE;
public static final String EXTRA_SELECTED_FEEDITEM = "extra.de.danoeh.antennapod.activity.selected_feeditem";
@@ -104,7 +104,6 @@ public class ItemlistFragment extends ListFragment {
private boolean itemsLoaded = false;
private boolean viewsCreated = false;
- private DownloadObserver downloadObserver;
private List<Downloader> downloaderList;
private MoreContentListFooterUtil listFooter;
@@ -147,11 +146,7 @@ public class ItemlistFragment extends ListFragment {
public void onStart() {
super.onStart();
EventDistributor.getInstance().register(contentUpdate);
- EventBus.getDefault().register(this);
- if (downloadObserver != null) {
- downloadObserver.setActivity(getActivity());
- downloadObserver.onResume();
- }
+ EventBus.getDefault().registerSticky(this);
if (viewsCreated && itemsLoaded) {
onFragmentLoaded();
}
@@ -193,9 +188,6 @@ public class ItemlistFragment extends ListFragment {
adapter = null;
viewsCreated = false;
listFooter = null;
- if (downloadObserver != null) {
- downloadObserver.onPause();
- }
}
private final MenuItemUtils.UpdateRefreshMenuItemChecker updateRefreshMenuItemChecker = new MenuItemUtils.UpdateRefreshMenuItemChecker() {
@@ -265,7 +257,8 @@ public class ItemlistFragment extends ListFragment {
if (!FeedMenuHandler.onOptionsItemClicked(getActivity(), item, feed)) {
switch (item.getItemId()) {
case R.id.episode_actions:
- Fragment fragment = new EpisodesApplyActionFragment(feed.getItems());
+ EpisodesApplyActionFragment fragment = new EpisodesApplyActionFragment();
+ fragment.setEpisodes(feed.getItems());
((MainActivity)getActivity()).loadChildFragment(fragment);
return true;
case R.id.remove_item:
@@ -394,29 +387,54 @@ public class ItemlistFragment extends ListFragment {
}
public void onEvent(QueueEvent event) {
- Log.d(TAG, "onEvent(" + event + ")");
+ Log.d(TAG, "onEvent() called with: " + "event = [" + event + "]");
loadItems();
}
public void onEvent(FeedEvent event) {
- Log.d(TAG, "onEvent(" + event + ")");
+ Log.d(TAG, "onEvent() called with: " + "event = [" + event + "]");
if(event.feedId == feedID) {
loadItems();
}
}
+ public void onEventMainThread(FeedItemEvent event) {
+ Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
+ boolean queueChanged = false;
+ if(feed == null || feed.getItems() == null || adapter == null) {
+ return;
+ }
+ for(FeedItem item : event.items) {
+ int pos = FeedItemUtil.indexOfItemWithId(feed.getItems(), item.getId());
+ if(pos >= 0) {
+ loadItems();
+ return;
+ }
+ }
+ }
+
+ public void onEventMainThread(DownloadEvent event) {
+ Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
+ DownloaderUpdate update = event.update;
+ downloaderList = update.downloaders;
+ if(update.feedIds.length > 0) {
+ updateProgressBarVisibility();
+ }
+ if(update.mediaIds.length > 0) {
+ if (adapter != null) {
+ adapter.notifyDataSetChanged();
+ }
+ }
+ }
+
private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
@Override
public void update(EventDistributor eventDistributor, Integer arg) {
if ((EVENTS & arg) != 0) {
Log.d(TAG, "Received contentUpdate Intent. arg " + arg);
- if ((EventDistributor.DOWNLOAD_QUEUED & arg) != 0) {
- updateProgressBarVisibility();
- } else {
- loadItems();
- updateProgressBarVisibility();
- }
+ loadItems();
+ updateProgressBarVisibility();
}
}
};
@@ -444,8 +462,6 @@ public class ItemlistFragment extends ListFragment {
setupFooterView();
adapter = new FeedItemlistAdapter(getActivity(), itemAccess, new DefaultActionButtonCallback(getActivity()), false, true);
setListAdapter(adapter);
- downloadObserver = new DownloadObserver(getActivity(), new Handler(), downloadObserverCallback);
- downloadObserver.onResume();
}
refreshHeaderView();
setListShown(true);
@@ -485,22 +501,10 @@ public class ItemlistFragment extends ListFragment {
txtvInformation.setVisibility(View.GONE);
}
} else {
-
txtvInformation.setVisibility(View.GONE);
}
}
-
- private DownloadObserver.Callback downloadObserverCallback = new DownloadObserver.Callback() {
- @Override
- public void onContentChanged(List<Downloader> downloaderList) {
- ItemlistFragment.this.downloaderList = downloaderList;
- if (adapter != null) {
- adapter.notifyDataSetChanged();
- }
- }
- };
-
private void setupHeaderView() {
if (getListView() == null || feed == null) {
Log.e(TAG, "Unable to setup listview: recyclerView = null or feed = null");
@@ -624,7 +628,7 @@ public class ItemlistFragment extends ListFragment {
subscription.unsubscribe();
}
- subscription = Observable.defer(() -> Observable.just(loadData()))
+ subscription = Observable.fromCallable(() -> loadData())
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
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 d684c064c..b996e1cb3 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java
@@ -14,14 +14,12 @@ import java.util.List;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.adapter.AllEpisodesRecycleAdapter;
-import de.danoeh.antennapod.adapter.QueueRecyclerAdapter;
import de.danoeh.antennapod.core.event.QueueEvent;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBWriter;
-import de.greenrobot.event.EventBus;
/**
@@ -42,23 +40,11 @@ public class NewEpisodesFragment extends AllEpisodesFragment {
protected String getPrefName() { return PREF_NAME; }
public void onEvent(QueueEvent event) {
- Log.d(TAG, "onEvent(" + event + ")");
+ Log.d(TAG, "onEvent() called with: " + "event = [" + event + "]");
loadItems();
}
@Override
- public void onStart() {
- super.onStart();
- EventBus.getDefault().register(this);
- }
-
- @Override
- public void onStop() {
- super.onStop();
- EventBus.getDefault().unregister(this);
- }
-
- @Override
protected void resetViewState() {
super.resetViewState();
}
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 d7ffa3e23..b47a197c3 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java
@@ -3,7 +3,6 @@ package de.danoeh.antennapod.fragment;
import android.app.Activity;
import android.content.res.TypedArray;
import android.os.Bundle;
-import android.os.Handler;
import android.support.v4.app.ListFragment;
import android.support.v4.util.Pair;
import android.support.v4.view.MenuItemCompat;
@@ -21,7 +20,8 @@ import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.adapter.DefaultActionButtonCallback;
import de.danoeh.antennapod.adapter.FeedItemlistAdapter;
-import de.danoeh.antennapod.core.asynctask.DownloadObserver;
+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.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
@@ -52,12 +52,20 @@ public class PlaybackHistoryFragment extends ListFragment {
private AtomicReference<Activity> activity = new AtomicReference<Activity>();
- private DownloadObserver downloadObserver;
private List<Downloader> downloaderList;
private Subscription subscription;
@Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ this.activity.set(activity);
+ if (viewsCreated && itemsLoaded) {
+ onFragmentLoaded();
+ }
+ }
+
+ @Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
@@ -65,8 +73,26 @@ public class PlaybackHistoryFragment extends ListFragment {
}
@Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+
+ // add padding
+ final ListView lv = getListView();
+ lv.setClipToPadding(false);
+ final int vertPadding = getResources().getDimensionPixelSize(R.dimen.list_vertical_padding);
+ lv.setPadding(0, vertPadding, 0, vertPadding);
+
+ viewsCreated = true;
+ if (itemsLoaded) {
+ onFragmentLoaded();
+ }
+ }
+
+
+ @Override
public void onResume() {
super.onResume();
+ EventBus.getDefault().registerSticky(this);
loadItems();
}
@@ -74,14 +100,18 @@ public class PlaybackHistoryFragment extends ListFragment {
public void onStart() {
super.onStart();
EventDistributor.getInstance().register(contentUpdate);
- EventBus.getDefault().register(this);
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ EventBus.getDefault().unregister(this);
}
@Override
public void onStop() {
super.onStop();
EventDistributor.getInstance().unregister(contentUpdate);
- EventBus.getDefault().unregister(this);
if(subscription != null) {
subscription.unsubscribe();
}
@@ -97,41 +127,18 @@ public class PlaybackHistoryFragment extends ListFragment {
}
@Override
- public void onAttach(Activity activity) {
- super.onAttach(activity);
- this.activity.set(activity);
- if (downloadObserver != null) {
- downloadObserver.setActivity(activity);
- downloadObserver.onResume();
- }
- if (viewsCreated && itemsLoaded) {
- onFragmentLoaded();
- }
- }
-
- @Override
public void onDestroyView() {
super.onDestroyView();
adapter = null;
viewsCreated = false;
- if (downloadObserver != null) {
- downloadObserver.onPause();
- }
}
- @Override
- public void onViewCreated(View view, Bundle savedInstanceState) {
- super.onViewCreated(view, savedInstanceState);
-
- // add padding
- final ListView lv = getListView();
- lv.setClipToPadding(false);
- final int vertPadding = getResources().getDimensionPixelSize(R.dimen.list_vertical_padding);
- lv.setPadding(0, vertPadding, 0, vertPadding);
-
- viewsCreated = true;
- if (itemsLoaded) {
- onFragmentLoaded();
+ public void onEvent(DownloadEvent event) {
+ Log.d(TAG, "onEvent() called with: " + "event = [" + event + "]");
+ DownloaderUpdate update = event.update;
+ downloaderList = update.downloaders;
+ if (adapter != null) {
+ adapter.notifyDataSetChanged();
}
}
@@ -205,24 +212,12 @@ public class PlaybackHistoryFragment extends ListFragment {
// it harder to read.
adapter = new FeedItemlistAdapter(getActivity(), itemAccess, new DefaultActionButtonCallback(activity.get()), true, false);
setListAdapter(adapter);
- downloadObserver = new DownloadObserver(activity.get(), new Handler(), downloadObserverCallback);
- downloadObserver.onResume();
}
setListShown(true);
adapter.notifyDataSetChanged();
getActivity().supportInvalidateOptionsMenu();
}
- private DownloadObserver.Callback downloadObserverCallback = new DownloadObserver.Callback() {
- @Override
- public void onContentChanged(List<Downloader> downloaderList) {
- PlaybackHistoryFragment.this.downloaderList = downloaderList;
- if (adapter != null) {
- adapter.notifyDataSetChanged();
- }
- }
- };
-
private FeedItemlistAdapter.ItemAccess itemAccess = new FeedItemlistAdapter.ItemAccess() {
@Override
public boolean isInQueue(FeedItem item) {
@@ -257,7 +252,7 @@ public class PlaybackHistoryFragment extends ListFragment {
if(subscription != null) {
subscription.unsubscribe();
}
- subscription = Observable.defer(() -> Observable.just(loadData()))
+ subscription = Observable.fromCallable(() -> loadData())
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
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 bfac7a347..46bbfd13c 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java
@@ -4,7 +4,6 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.os.Bundle;
-import android.os.Handler;
import android.support.design.widget.Snackbar;
import android.support.v4.app.Fragment;
import android.support.v4.view.MenuItemCompat;
@@ -31,8 +30,9 @@ import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.adapter.DefaultActionButtonCallback;
import de.danoeh.antennapod.adapter.QueueRecyclerAdapter;
-import de.danoeh.antennapod.core.asynctask.DownloadObserver;
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.event.FeedItemEvent;
import de.danoeh.antennapod.core.event.QueueEvent;
import de.danoeh.antennapod.core.feed.EventDistributor;
@@ -67,7 +67,6 @@ public class QueueFragment extends Fragment {
public static final String TAG = "QueueFragment";
private static final int EVENTS = EventDistributor.DOWNLOAD_HANDLED |
- EventDistributor.DOWNLOAD_QUEUED |
EventDistributor.PLAYER_STATUS_UPDATE;
private TextView infoBar;
@@ -85,13 +84,6 @@ public class QueueFragment extends Fragment {
private static final String PREF_SCROLL_POSITION = "scroll_position";
private static final String PREF_SCROLL_OFFSET = "scroll_offset";
- private DownloadObserver downloadObserver = null;
-
- /**
- * Download observer updates won't result in an upate of the list adapter if this is true.
- */
- private boolean blockDownloadObserverUpdate = false;
-
private Subscription subscription;
private LinearLayoutManager layoutManager;
private ItemTouchHelper itemTouchHelper;
@@ -107,12 +99,8 @@ public class QueueFragment extends Fragment {
@Override
public void onStart() {
super.onStart();
- if (downloadObserver != null) {
- downloadObserver.setActivity(getActivity());
- downloadObserver.onResume();
- }
if (queue != null) {
- onFragmentLoaded();
+ onFragmentLoaded(true);
}
}
@@ -120,9 +108,9 @@ public class QueueFragment extends Fragment {
public void onResume() {
super.onResume();
recyclerView.setAdapter(recyclerAdapter);
- loadItems();
+ loadItems(true);
EventDistributor.getInstance().register(contentUpdate);
- EventBus.getDefault().register(this);
+ EventBus.getDefault().registerSticky(this);
}
@Override
@@ -137,7 +125,10 @@ public class QueueFragment extends Fragment {
}
public void onEventMainThread(QueueEvent event) {
- Log.d(TAG, "onEvent(" + event + ")");
+ Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
+ if(queue == null || recyclerAdapter == null) {
+ return;
+ }
switch(event.action) {
case ADDED:
queue.add(event.position, event.item);
@@ -162,21 +153,17 @@ public class QueueFragment extends Fragment {
recyclerAdapter.notifyDataSetChanged();
break;
case MOVED:
- int from = FeedItemUtil.indexOfItemWithId(queue, event.item.getId());
- int to = event.position;
- if(from != to) {
- queue.add(to, queue.remove(from));
- recyclerAdapter.notifyItemMoved(from, to);
- } else {
- // QueueFragment itself sent the event and already moved the item
- }
- break;
+ return;
}
- onFragmentLoaded();
+ saveScrollPosition();
+ onFragmentLoaded(false);
}
public void onEventMainThread(FeedItemEvent event) {
- Log.d(TAG, "onEvent(" + event + ")");
+ Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
+ if(queue == null || recyclerAdapter == null) {
+ return;
+ }
for(int i=0, size = event.items.size(); i < size; i++) {
FeedItem item = event.items.get(i);
int pos = FeedItemUtil.indexOfItemWithId(queue, item.getId());
@@ -188,6 +175,21 @@ public class QueueFragment extends Fragment {
}
}
+ public void onEventMainThread(DownloadEvent event) {
+ Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
+ DownloaderUpdate update = event.update;
+ downloaderList = update.downloaders;
+ if (update.feedIds.length > 0) {
+ if (isUpdatingFeeds != updateRefreshMenuItemChecker.isRefreshing()) {
+ getActivity().supportInvalidateOptionsMenu();
+ }
+ } else if (update.mediaIds.length > 0) {
+ if (recyclerAdapter != null) {
+ recyclerAdapter.notifyDataSetChanged();
+ }
+ }
+ }
+
private void saveScrollPosition() {
int firstItem = layoutManager.findFirstVisibleItemPosition();
View firstItemView = layoutManager.findViewByPosition(firstItem);
@@ -211,20 +213,11 @@ public class QueueFragment extends Fragment {
float offset = prefs.getFloat(PREF_SCROLL_OFFSET, 0.0f);
if (position > 0 || offset > 0) {
layoutManager.scrollToPositionWithOffset(position, (int) offset);
- // restore once, then forget
- SharedPreferences.Editor editor = prefs.edit();
- editor.putInt(PREF_SCROLL_POSITION, 0);
- editor.putFloat(PREF_SCROLL_OFFSET, 0.0f);
- editor.commit();
}
}
private void resetViewState() {
recyclerAdapter = null;
- blockDownloadObserverUpdate = false;
- if (downloadObserver != null) {
- downloadObserver.onPause();
- }
}
@Override
@@ -327,6 +320,7 @@ public class QueueFragment extends Fragment {
@Override
public boolean onContextItemSelected(MenuItem item) {
+ Log.d(TAG, "onContextItemSelected() called with: " + "item = [" + item + "]");
if(!isVisible()) {
return false;
}
@@ -336,12 +330,27 @@ public class QueueFragment extends Fragment {
return super.onContextItemSelected(item);
}
- try {
- return FeedItemMenuHandler.onMenuItemClicked(getActivity(), item.getItemId(), selectedItem);
- } catch (DownloadRequestException e) {
- e.printStackTrace();
- Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_LONG).show();
- return true;
+ switch(item.getItemId()) {
+ case R.id.move_to_top_item:
+ int position = FeedItemUtil.indexOfItemWithId(queue, selectedItem.getId());
+ queue.add(0, queue.remove(position));
+ recyclerAdapter.notifyItemMoved(position, 0);
+ DBWriter.moveQueueItemToTop(selectedItem.getId(), true);
+ return true;
+ case R.id.move_to_bottom_item:
+ position = FeedItemUtil.indexOfItemWithId(queue, selectedItem.getId());
+ queue.add(queue.size()-1, queue.remove(position));
+ recyclerAdapter.notifyItemMoved(position, queue.size()-1);
+ DBWriter.moveQueueItemToBottom(selectedItem.getId(), true);
+ return true;
+ default:
+ try {
+ return FeedItemMenuHandler.onMenuItemClicked(getActivity(), item.getItemId(), selectedItem);
+ } catch (DownloadRequestException e) {
+ e.printStackTrace();
+ Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_LONG).show();
+ return true;
+ }
}
}
@@ -442,14 +451,12 @@ public class QueueFragment extends Fragment {
return root;
}
- private void onFragmentLoaded() {
+ private void onFragmentLoaded(final boolean restoreScrollPosition) {
if (recyclerAdapter == null) {
MainActivity activity = (MainActivity) getActivity();
recyclerAdapter = new QueueRecyclerAdapter(activity, itemAccess,
new DefaultActionButtonCallback(activity), itemTouchHelper);
recyclerView.setAdapter(recyclerAdapter);
- downloadObserver = new DownloadObserver(activity, new Handler(), downloadObserverCallback);
- downloadObserver.onResume();
}
if(queue == null || queue.size() == 0) {
recyclerView.setVisibility(View.GONE);
@@ -459,7 +466,9 @@ public class QueueFragment extends Fragment {
recyclerView.setVisibility(View.VISIBLE);
}
- restoreScrollPosition();
+ if (restoreScrollPosition) {
+ restoreScrollPosition();
+ }
// we need to refresh the options menu because it sometimes
// needs data that may have just been loaded.
@@ -483,16 +492,6 @@ public class QueueFragment extends Fragment {
infoBar.setText(info);
}
- private DownloadObserver.Callback downloadObserverCallback = new DownloadObserver.Callback() {
- @Override
- public void onContentChanged(List<Downloader> downloaderList) {
- QueueFragment.this.downloaderList = downloaderList;
- if (recyclerAdapter != null && !blockDownloadObserverUpdate) {
- recyclerAdapter.notifyDataSetChanged();
- }
- }
- };
-
private QueueRecyclerAdapter.ItemAccess itemAccess = new QueueRecyclerAdapter.ItemAccess() {
@Override
public int getCount() {
@@ -501,7 +500,10 @@ public class QueueFragment extends Fragment {
@Override
public FeedItem getItem(int position) {
- return queue != null ? queue.get(position) : null;
+ if(queue != null && position < queue.size()) {
+ return queue.get(position);
+ }
+ return null;
}
@Override
@@ -554,7 +556,8 @@ public class QueueFragment extends Fragment {
@Override
public void update(EventDistributor eventDistributor, Integer arg) {
if ((arg & EVENTS) != 0) {
- loadItems();
+ Log.d(TAG, "arg: " + arg);
+ loadItems(false);
if (isUpdatingFeeds != updateRefreshMenuItemChecker.isRefreshing()) {
getActivity().supportInvalidateOptionsMenu();
}
@@ -562,7 +565,8 @@ public class QueueFragment extends Fragment {
}
};
- private void loadItems() {
+ private void loadItems(final boolean restoreScrollPosition) {
+ Log.d(TAG, "loadItems()");
if(subscription != null) {
subscription.unsubscribe();
}
@@ -571,14 +575,14 @@ public class QueueFragment extends Fragment {
txtvEmpty.setVisibility(View.GONE);
progLoading.setVisibility(View.VISIBLE);
}
- subscription = Observable.defer(() -> Observable.just(DBReader.getQueue()))
+ subscription = Observable.fromCallable(() -> DBReader.getQueue())
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(items -> {
if(items != null) {
progLoading.setVisibility(View.GONE);
queue = items;
- onFragmentLoaded();
+ onFragmentLoaded(restoreScrollPosition);
if(recyclerAdapter != null) {
recyclerAdapter.notifyDataSetChanged();
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/RunningDownloadsFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/RunningDownloadsFragment.java
index 544bdfc43..d81d18640 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,6 @@
package de.danoeh.antennapod.fragment;
import android.os.Bundle;
-import android.os.Handler;
import android.support.v4.app.ListFragment;
import android.util.Log;
import android.view.View;
@@ -12,7 +11,8 @@ import java.util.List;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.adapter.DownloadlistAdapter;
-import de.danoeh.antennapod.core.asynctask.DownloadObserver;
+import de.danoeh.antennapod.core.event.DownloadEvent;
+import de.danoeh.antennapod.core.event.DownloaderUpdate;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.service.download.DownloadRequest;
@@ -20,25 +20,18 @@ import de.danoeh.antennapod.core.service.download.Downloader;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.storage.DownloadRequester;
+import de.greenrobot.event.EventBus;
/**
* Displays all running downloads and provides actions to cancel them
*/
public class RunningDownloadsFragment extends ListFragment {
+
private static final String TAG = "RunningDownloadsFrag";
- private DownloadObserver downloadObserver;
+ private DownloadlistAdapter adapter;
private List<Downloader> downloaderList;
-
- @Override
- public void onDetach() {
- super.onDetach();
- if (downloadObserver != null) {
- downloadObserver.onPause();
- }
- }
-
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
@@ -49,20 +42,39 @@ public class RunningDownloadsFragment extends ListFragment {
final int vertPadding = getResources().getDimensionPixelSize(R.dimen.list_vertical_padding);
lv.setPadding(0, vertPadding, 0, vertPadding);
- final DownloadlistAdapter downloadlistAdapter = new DownloadlistAdapter(getActivity(), itemAccess);
- setListAdapter(downloadlistAdapter);
+ adapter = new DownloadlistAdapter(getActivity(), itemAccess);
+ setListAdapter(adapter);
+ }
- downloadObserver = new DownloadObserver(getActivity(), new Handler(), new DownloadObserver.Callback() {
- @Override
- public void onContentChanged(List<Downloader> downloaderList) {
- Log.d(TAG, "onContentChanged: downloaderList.size() == " + downloaderList.size());
- RunningDownloadsFragment.this.downloaderList = downloaderList;
- downloadlistAdapter.notifyDataSetChanged();
- }
- });
- downloadObserver.onResume();
+ @Override
+ public void onResume() {
+ super.onResume();
+ EventBus.getDefault().registerSticky(this);
}
+ @Override
+ public void onPause() {
+ super.onPause();
+ EventBus.getDefault().unregister(this);
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ setListAdapter(null);
+ adapter = null;
+ }
+
+ public void onEvent(DownloadEvent event) {
+ Log.d(TAG, "onEvent() called with: " + "event = [" + event + "]");
+ DownloaderUpdate update = event.update;
+ downloaderList = update.downloaders;
+ if (adapter != null) {
+ adapter.notifyDataSetChanged();
+ }
+ }
+
+
private DownloadlistAdapter.ItemAccess itemAccess = new DownloadlistAdapter.ItemAccess() {
@Override
public int getCount() {
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 edd8cdd1a..43354ad28 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java
@@ -204,7 +204,7 @@ public class SearchFragment extends ListFragment {
if (viewCreated && !itemsLoaded) {
setListShown(false);
}
- subscription = Observable.defer(() -> Observable.just(performSearch()))
+ subscription = Observable.fromCallable(() -> performSearch())
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
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 3fa1048c0..0197cc88c 100644
--- a/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java
+++ b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java
@@ -186,11 +186,6 @@ public class FeedItemMenuHandler {
GpodnetPreferences.enqueueEpisodeAction(actionNew);
}
break;
- case R.id.move_to_top_item:
- DBWriter.moveQueueItemToTop(selectedItem.getId(), true);
- return true;
- case R.id.move_to_bottom_item:
- DBWriter.moveQueueItemToBottom(selectedItem.getId(), true);
case R.id.add_to_queue_item:
DBWriter.addQueueItem(context, selectedItem);
break;
diff --git a/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java b/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java
index 73d7da0f2..94f5d822e 100644
--- a/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java
+++ b/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java
@@ -8,6 +8,7 @@ import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Resources;
+import android.net.Uri;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.os.Build;
@@ -34,6 +35,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import de.danoeh.antennapod.CrashReportWriter;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.AboutActivity;
import de.danoeh.antennapod.activity.DirectoryChooserActivity;
@@ -169,7 +171,7 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
- if(Build.VERSION.SDK_INT >= 19) {
+ if (Build.VERSION.SDK_INT >= 19) {
showChooseDataFolderDialog();
} else {
Intent intent = new Intent(activity, DirectoryChooserActivity.class);
@@ -254,7 +256,7 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
setParallelDownloadsText(value);
return true;
}
- } catch(NumberFormatException e) {
+ } catch (NumberFormatException e) {
return false;
}
}
@@ -263,17 +265,19 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
}
);
// validate and set correct value: number of downloads between 1 and 50 (inclusive)
- final EditText ev = ((EditTextPreference)ui.findPreference(UserPreferences.PREF_PARALLEL_DOWNLOADS)).getEditText();
+ final EditText ev = ((EditTextPreference) ui.findPreference(UserPreferences.PREF_PARALLEL_DOWNLOADS)).getEditText();
ev.addTextChangedListener(new TextWatcher() {
@Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ }
@Override
- public void onTextChanged(CharSequence s, int start, int before, int count) {}
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ }
@Override
public void afterTextChanged(Editable s) {
- if(s.length() > 0) {
+ if (s.length() > 0) {
try {
int value = Integer.valueOf(s.toString());
if (value <= 0) {
@@ -281,7 +285,7 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
} else if (value > 50) {
ev.setText("50");
}
- } catch(NumberFormatException e) {
+ } catch (NumberFormatException e) {
ev.setText("6");
}
ev.setSelection(ev.getText().length());
@@ -386,11 +390,23 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
}
}
);
+ ui.findPreference("prefSendCrashReport").setOnPreferenceClickListener(preference -> {
+ Intent emailIntent = new Intent(Intent.ACTION_SEND);
+ emailIntent.setType("text/plain");
+ String to[] = { "Martin.Fietz@gmail.com" };
+ emailIntent .putExtra(Intent.EXTRA_EMAIL, to);
+ // the attachment
+ emailIntent .putExtra(Intent.EXTRA_STREAM, Uri.fromFile(CrashReportWriter.getFile()));
+ // the mail subject
+ emailIntent .putExtra(Intent.EXTRA_SUBJECT, "AntennaPod Crash Report");
+ String intentTitle = ui.getActivity().getString(R.string.send_email);
+ ui.getActivity().startActivity(Intent.createChooser(emailIntent, intentTitle));
+ return true;
+ });
buildEpisodeCleanupPreference();
buildSmartMarkAsPlayedPreference();
buildAutodownloadSelectedNetworsPreference();
- setSelectedNetworksEnabled(UserPreferences
- .isEnableAutodownloadWifiFilter());
+ setSelectedNetworksEnabled(UserPreferences.isEnableAutodownloadWifiFilter());
}
public void onResume() {
@@ -527,6 +543,8 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
ui.findPreference(UserPreferences.PREF_ENABLE_AUTODL_ON_BATTERY)
.setEnabled(UserPreferences.isEnableAutodownload());
+ ui.findPreference("prefSendCrashReport").setEnabled(CrashReportWriter.getFile().exists());
+
if (Build.VERSION.SDK_INT >= 16) {
ui.findPreference(UserPreferences.PREF_SONIC).setEnabled(true);
} else {
@@ -558,7 +576,7 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
}
private void setDataFolderText() {
- File f = UserPreferences.getDataFolder(ui.getActivity(), null);
+ File f = UserPreferences.getDataFolder(null);
if (f != null) {
ui.findPreference(PreferenceController.PREF_CHOOSE_DATA_DIR)
.setSummary(f.getAbsolutePath());
@@ -677,7 +695,7 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
private void showChooseDataFolderDialog() {
Context context = ui.getActivity();
- String dataFolder = UserPreferences.getDataFolder(context, null).getAbsolutePath();
+ String dataFolder = UserPreferences.getDataFolder(null).getAbsolutePath();
int selectedIndex = -1;
File[] mediaDirs = ContextCompat.getExternalFilesDirs(context, null);
String[] folders = new String[mediaDirs.length];
diff --git a/app/src/main/java/de/danoeh/antennapod/receiver/ConnectivityActionReceiver.java b/app/src/main/java/de/danoeh/antennapod/receiver/ConnectivityActionReceiver.java
index 2615ec5c8..665ddc3b5 100644
--- a/app/src/main/java/de/danoeh/antennapod/receiver/ConnectivityActionReceiver.java
+++ b/app/src/main/java/de/danoeh/antennapod/receiver/ConnectivityActionReceiver.java
@@ -5,10 +5,9 @@ import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
+import android.text.TextUtils;
import android.util.Log;
-import org.apache.commons.lang3.StringUtils;
-
import de.danoeh.antennapod.core.storage.DBTasks;
import de.danoeh.antennapod.core.storage.DownloadRequester;
import de.danoeh.antennapod.core.util.NetworkUtils;
@@ -18,7 +17,7 @@ public class ConnectivityActionReceiver extends BroadcastReceiver {
@Override
public void onReceive(final Context context, Intent intent) {
- if (StringUtils.equals(intent.getAction(), ConnectivityManager.CONNECTIVITY_ACTION)) {
+ if (TextUtils.equals(intent.getAction(), ConnectivityManager.CONNECTIVITY_ACTION)) {
Log.d(TAG, "Received intent");
if (NetworkUtils.autodownloadNetworkAvailable()) {
diff --git a/app/src/main/java/de/danoeh/antennapod/receiver/PlayerWidget.java b/app/src/main/java/de/danoeh/antennapod/receiver/PlayerWidget.java
index 7ab386edf..7000827c6 100644
--- a/app/src/main/java/de/danoeh/antennapod/receiver/PlayerWidget.java
+++ b/app/src/main/java/de/danoeh/antennapod/receiver/PlayerWidget.java
@@ -4,46 +4,75 @@ import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.content.Intent;
+import android.content.SharedPreferences;
+import android.text.TextUtils;
import android.util.Log;
-import org.apache.commons.lang3.StringUtils;
-
-import de.danoeh.antennapod.core.BuildConfig;
import de.danoeh.antennapod.core.service.playback.PlaybackService;
import de.danoeh.antennapod.service.PlayerWidgetService;
public class PlayerWidget extends AppWidgetProvider {
- private static final String TAG = "PlayerWidget";
+ private static final String TAG = "PlayerWidget";
+ private static final String PREFS_NAME = "PlayerWidgetPrefs";
+ private static final String KEY_ENABLED = "WidgetEnabled";
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Log.d(TAG, "onReceive");
+ super.onReceive(context, intent);
+ // don't do anything if we're not enabled
+ if (!isEnabled(context)) {
+ return;
+ }
+
+ // these come from the PlaybackService when things should get updated
+ if (TextUtils.equals(intent.getAction(), PlaybackService.FORCE_WIDGET_UPDATE)) {
+ startUpdate(context);
+ } else if (TextUtils.equals(intent.getAction(), PlaybackService.STOP_WIDGET_UPDATE)) {
+ stopUpdate(context);
+ }
+ }
+
+ @Override
+ public void onEnabled(Context context) {
+ super.onEnabled(context);
+ Log.d(TAG, "Widget enabled");
+ setEnabled(context, true);
+ startUpdate(context);
+ }
@Override
- public void onReceive(Context context, Intent intent) {
- if (StringUtils.equals(intent.getAction(), PlaybackService.FORCE_WIDGET_UPDATE)) {
- startUpdate(context);
- } else if (StringUtils.equals(intent.getAction(), PlaybackService.STOP_WIDGET_UPDATE)) {
- stopUpdate(context);
- }
-
- }
-
- @Override
- public void onEnabled(Context context) {
- super.onEnabled(context);
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Widget enabled");
- }
-
- @Override
- public void onUpdate(Context context, AppWidgetManager appWidgetManager,
- int[] appWidgetIds) {
- startUpdate(context);
- }
-
- private void startUpdate(Context context) {
- context.startService(new Intent(context, PlayerWidgetService.class));
- }
-
- private void stopUpdate(Context context) {
- context.stopService(new Intent(context, PlayerWidgetService.class));
- }
+ public void onUpdate(Context context, AppWidgetManager appWidgetManager,
+ int[] appWidgetIds) {
+ Log.d(TAG, "onUpdate() called with: " + "context = [" + context + "], appWidgetManager = [" + appWidgetManager + "], appWidgetIds = [" + appWidgetIds + "]");
+ startUpdate(context);
+ }
+
+ @Override
+ public void onDisabled(Context context) {
+ super.onDisabled(context);
+ Log.d(TAG, "Widet disabled");
+ setEnabled(context, false);
+ stopUpdate(context);
+ }
+
+ private void startUpdate(Context context) {
+ Log.d(TAG, "startUpdate() called with: " + "context = [" + context + "]");
+ context.startService(new Intent(context, PlayerWidgetService.class));
+ }
+
+ private void stopUpdate(Context context) {
+ Log.d(TAG, "stopUpdate() called with: " + "context = [" + context + "]");
+ context.stopService(new Intent(context, PlayerWidgetService.class));
+ }
+
+ private boolean isEnabled(Context context) {
+ SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
+ return prefs.getBoolean(KEY_ENABLED, false);
+ }
+ private void setEnabled(Context context, boolean enabled) {
+ SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
+ prefs.edit().putBoolean(KEY_ENABLED, enabled).apply();
+ }
}
diff --git a/app/src/main/java/de/danoeh/antennapod/receiver/SPAReceiver.java b/app/src/main/java/de/danoeh/antennapod/receiver/SPAReceiver.java
index d15108bfe..ef6330f82 100644
--- a/app/src/main/java/de/danoeh/antennapod/receiver/SPAReceiver.java
+++ b/app/src/main/java/de/danoeh/antennapod/receiver/SPAReceiver.java
@@ -3,11 +3,10 @@ package de.danoeh.antennapod.receiver;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
+import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;
-import org.apache.commons.lang3.StringUtils;
-
import java.util.Arrays;
import java.util.Date;
@@ -29,7 +28,7 @@ public class SPAReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
- if (StringUtils.equals(intent.getAction(), ACTION_SP_APPS_QUERY_FEEDS_REPSONSE)) {
+ if (TextUtils.equals(intent.getAction(), ACTION_SP_APPS_QUERY_FEEDS_REPSONSE)) {
if (BuildConfig.DEBUG) Log.d(TAG, "Received SP_APPS_QUERY_RESPONSE");
if (intent.hasExtra(ACTION_SP_APPS_QUERY_FEEDS_REPSONSE_FEEDS_EXTRA)) {
String[] feedUrls = intent.getStringArrayExtra(ACTION_SP_APPS_QUERY_FEEDS_REPSONSE_FEEDS_EXTRA);
diff --git a/app/src/main/java/de/danoeh/antennapod/service/PlayerWidgetService.java b/app/src/main/java/de/danoeh/antennapod/service/PlayerWidgetService.java
index d7a049a32..d61a189c2 100644
--- a/app/src/main/java/de/danoeh/antennapod/service/PlayerWidgetService.java
+++ b/app/src/main/java/de/danoeh/antennapod/service/PlayerWidgetService.java
@@ -14,6 +14,7 @@ import android.view.View;
import android.widget.RemoteViews;
import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.receiver.MediaButtonReceiver;
@@ -22,197 +23,220 @@ import de.danoeh.antennapod.core.service.playback.PlayerStatus;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.util.Converter;
import de.danoeh.antennapod.core.util.playback.Playable;
+import de.danoeh.antennapod.fragment.QueueFragment;
import de.danoeh.antennapod.receiver.PlayerWidget;
-/** Updates the state of the player widget */
+/**
+ * Updates the state of the player widget
+ */
public class PlayerWidgetService extends Service {
- private static final String TAG = "PlayerWidgetService";
+ private static final String TAG = "PlayerWidgetService";
- private PlaybackService playbackService;
+ private PlaybackService playbackService;
- /** Controls write access to playbackservice reference */
+ /**
+ * Controls write access to playbackservice reference
+ */
private Object psLock;
- /** True while service is updating the widget */
- private volatile boolean isUpdating;
+ /**
+ * True while service is updating the widget
+ */
+ private volatile boolean isUpdating;
- public PlayerWidgetService() {
- }
+ public PlayerWidgetService() {
+ }
- @Override
- public void onCreate() {
- super.onCreate();
- Log.d(TAG, "Service created");
- isUpdating = false;
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ Log.d(TAG, "Service created");
+ isUpdating = false;
psLock = new Object();
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- Log.d(TAG, "Service is about to be destroyed");
- if (playbackService != null) {
- Playable playable = playbackService.getPlayable();
- if (playable != null && playable instanceof FeedMedia) {
- FeedMedia media = (FeedMedia) playable;
- if (media.hasAlmostEnded()) {
- Log.d(TAG, "smart mark as read");
- FeedItem item = media.getItem();
- DBWriter.markItemPlayed(item, FeedItem.PLAYED, false);
- DBWriter.removeQueueItem(this, item, false);
- DBWriter.addItemToPlaybackHistory(media);
- if (item.getFeed().getPreferences().getCurrentAutoDelete()) {
- Log.d(TAG, "Delete " + media.toString());
- DBWriter.deleteFeedMediaOfItem(this, media.getId());
- }
- }
- }
- }
-
- try {
- unbindService(mConnection);
- } catch (IllegalArgumentException e) {
- Log.w(TAG, "IllegalArgumentException when trying to unbind service");
- }
- }
-
- @Override
- public IBinder onBind(Intent intent) {
- return null;
- }
-
- @Override
- public int onStartCommand(Intent intent, int flags, int startId) {
- if (!isUpdating) {
- if (playbackService == null && PlaybackService.isRunning) {
- bindService(new Intent(this, PlaybackService.class),
- mConnection, 0);
- } else {
- startViewUpdaterIfNotRunning();
- }
- } else {
- Log.d(TAG, "Service was called while updating. Ignoring update request");
- }
- return Service.START_NOT_STICKY;
- }
-
- private void updateViews() {
- if (playbackService == null) {
- return;
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ Log.d(TAG, "Service is about to be destroyed");
+ if (playbackService != null) {
+ Playable playable = playbackService.getPlayable();
+ if (playable != null && playable instanceof FeedMedia) {
+ FeedMedia media = (FeedMedia) playable;
+ if (media.hasAlmostEnded()) {
+ Log.d(TAG, "smart mark as read");
+ FeedItem item = media.getItem();
+ DBWriter.markItemPlayed(item, FeedItem.PLAYED, false);
+ DBWriter.removeQueueItem(this, item, false);
+ DBWriter.addItemToPlaybackHistory(media);
+ if (item.getFeed().getPreferences().getCurrentAutoDelete()) {
+ Log.d(TAG, "Delete " + media.toString());
+ DBWriter.deleteFeedMediaOfItem(this, media.getId());
+ }
+ }
+ }
+ }
+
+ try {
+ unbindService(mConnection);
+ } catch (IllegalArgumentException e) {
+ Log.w(TAG, "IllegalArgumentException when trying to unbind service");
+ }
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ if (!isUpdating) {
+ if (playbackService == null && PlaybackService.isRunning) {
+ bindService(new Intent(this, PlaybackService.class),
+ mConnection, 0);
+ } else {
+ startViewUpdaterIfNotRunning();
+ }
+ } else {
+ Log.d(TAG, "Service was called while updating. Ignoring update request");
}
- isUpdating = true;
-
- ComponentName playerWidget = new ComponentName(this, PlayerWidget.class);
- AppWidgetManager manager = AppWidgetManager.getInstance(this);
- RemoteViews views = new RemoteViews(getPackageName(),
- R.layout.player_widget);
- PendingIntent startMediaplayer = PendingIntent.getActivity(this, 0,
- PlaybackService.getPlayerActivityIntent(this), 0);
-
- views.setOnClickPendingIntent(R.id.layout_left, startMediaplayer);
- final Playable media = playbackService.getPlayable();
- if (playbackService != null && media != null) {
- PlayerStatus status = playbackService.getStatus();
-
- views.setTextViewText(R.id.txtvTitle, media.getEpisodeTitle());
-
- String progressString = getProgressString(media);
- if (progressString != null) {
- views.setTextViewText(R.id.txtvProgress, progressString);
- }
-
- if (status == PlayerStatus.PLAYING) {
- views.setImageViewResource(R.id.butPlay, R.drawable.ic_pause_white_24dp);
- if (Build.VERSION.SDK_INT >= 15) {
- views.setContentDescription(R.id.butPlay, getString(R.string.pause_label));
+ return Service.START_NOT_STICKY;
+ }
+
+ private void updateViews() {
+ isUpdating = true;
+
+ ComponentName playerWidget = new ComponentName(this, PlayerWidget.class);
+ AppWidgetManager manager = AppWidgetManager.getInstance(this);
+ RemoteViews views = new RemoteViews(getPackageName(),
+ R.layout.player_widget);
+ PendingIntent startMediaplayer = PendingIntent.getActivity(this, 0,
+ PlaybackService.getPlayerActivityIntent(this), 0);
+
+ Intent startApp = new Intent(getBaseContext(), MainActivity.class);
+ startApp.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ startApp.putExtra(MainActivity.EXTRA_FRAGMENT_TAG, QueueFragment.TAG);
+ PendingIntent startAppPending = PendingIntent.getActivity(getBaseContext(), 0, startApp, PendingIntent.FLAG_UPDATE_CURRENT);
+
+ boolean nothingPlaying = false;
+ if (playbackService != null) {
+ final Playable media = playbackService.getPlayable();
+ if (media != null) {
+ PlayerStatus status = playbackService.getStatus();
+ views.setOnClickPendingIntent(R.id.layout_left, startMediaplayer);
+
+ views.setTextViewText(R.id.txtvTitle, media.getEpisodeTitle());
+
+ String progressString = getProgressString(media);
+ if (progressString != null) {
+ views.setViewVisibility(R.id.txtvProgress, View.VISIBLE);
+ views.setTextViewText(R.id.txtvProgress, progressString);
}
- } else {
- views.setImageViewResource(R.id.butPlay, R.drawable.ic_play_arrow_white_24dp);
- if (Build.VERSION.SDK_INT >= 15) {
- views.setContentDescription(R.id.butPlay, getString(R.string.play_label));
+
+ if (status == PlayerStatus.PLAYING) {
+ views.setImageViewResource(R.id.butPlay, R.drawable.ic_pause_white_24dp);
+ if (Build.VERSION.SDK_INT >= 15) {
+ views.setContentDescription(R.id.butPlay, getString(R.string.pause_label));
+ }
+ } else {
+ views.setImageViewResource(R.id.butPlay, R.drawable.ic_play_arrow_white_24dp);
+ if (Build.VERSION.SDK_INT >= 15) {
+ views.setContentDescription(R.id.butPlay, getString(R.string.play_label));
+ }
}
- }
- views.setOnClickPendingIntent(R.id.butPlay,
- createMediaButtonIntent());
- } else {
- views.setViewVisibility(R.id.txtvProgress, View.INVISIBLE);
- views.setTextViewText(R.id.txtvTitle,
- this.getString(R.string.no_media_playing_label));
- views.setImageViewResource(R.id.butPlay, R.drawable.ic_play_arrow_white_24dp);
-
- }
-
- manager.updateAppWidget(playerWidget, views);
- isUpdating = false;
- }
-
- /** Creates an intent which fakes a mediabutton press */
- private PendingIntent createMediaButtonIntent() {
- KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN,
- KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
- Intent startingIntent = new Intent(
- MediaButtonReceiver.NOTIFY_BUTTON_RECEIVER);
- startingIntent.putExtra(Intent.EXTRA_KEY_EVENT, event);
-
- return PendingIntent.getBroadcast(this, 0, startingIntent, 0);
- }
-
- private String getProgressString(Playable media) {
- int position = media.getPosition();
- int duration = media.getDuration();
- if (position > 0 && duration > 0) {
- return Converter.getDurationStringLong(position) + " / "
- + Converter.getDurationStringLong(duration);
- } else {
- return null;
- }
- }
-
- private ServiceConnection mConnection = new ServiceConnection() {
- public void onServiceConnected(ComponentName className, IBinder service) {
- Log.d(TAG, "Connection to service established");
+ views.setOnClickPendingIntent(R.id.butPlay,
+ createMediaButtonIntent());
+ } else {
+ nothingPlaying = true;
+ }
+ } else {
+ nothingPlaying = true;
+ }
+
+ if (nothingPlaying) {
+ // start the app if they click anything
+ views.setOnClickPendingIntent(R.id.layout_left, startAppPending);
+ views.setOnClickPendingIntent(R.id.butPlay, startAppPending);
+ views.setViewVisibility(R.id.txtvProgress, View.INVISIBLE);
+ views.setTextViewText(R.id.txtvTitle,
+ this.getString(R.string.no_media_playing_label));
+ views.setImageViewResource(R.id.butPlay, R.drawable.ic_play_arrow_white_24dp);
+ }
+
+ manager.updateAppWidget(playerWidget, views);
+ isUpdating = false;
+ }
+
+ /**
+ * Creates an intent which fakes a mediabutton press
+ */
+ private PendingIntent createMediaButtonIntent() {
+ KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN,
+ KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
+ Intent startingIntent = new Intent(
+ MediaButtonReceiver.NOTIFY_BUTTON_RECEIVER);
+ startingIntent.putExtra(Intent.EXTRA_KEY_EVENT, event);
+
+ return PendingIntent.getBroadcast(this, 0, startingIntent, 0);
+ }
+
+ private String getProgressString(Playable media) {
+ int position = media.getPosition();
+ int duration = media.getDuration();
+ if (position > 0 && duration > 0) {
+ return Converter.getDurationStringLong(position) + " / "
+ + Converter.getDurationStringLong(duration);
+ } else {
+ return null;
+ }
+ }
+
+ private ServiceConnection mConnection = new ServiceConnection() {
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ Log.d(TAG, "Connection to service established");
synchronized (psLock) {
playbackService = ((PlaybackService.LocalBinder) service)
.getService();
startViewUpdaterIfNotRunning();
}
- }
+ }
- @Override
- public void onServiceDisconnected(ComponentName name) {
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
synchronized (psLock) {
playbackService = null;
Log.d(TAG, "Disconnected from service");
}
- }
+ }
- };
+ };
- private void startViewUpdaterIfNotRunning() {
- if (!isUpdating) {
- ViewUpdater updateThread = new ViewUpdater(this);
- updateThread.start();
- }
- }
+ private void startViewUpdaterIfNotRunning() {
+ if (!isUpdating) {
+ ViewUpdater updateThread = new ViewUpdater(this);
+ updateThread.start();
+ }
+ }
- class ViewUpdater extends Thread {
- private static final String THREAD_NAME = "ViewUpdater";
- private PlayerWidgetService service;
+ class ViewUpdater extends Thread {
+ private static final String THREAD_NAME = "ViewUpdater";
+ private PlayerWidgetService service;
- public ViewUpdater(PlayerWidgetService service) {
- super();
- setName(THREAD_NAME);
- this.service = service;
+ public ViewUpdater(PlayerWidgetService service) {
+ super();
+ setName(THREAD_NAME);
+ this.service = service;
- }
+ }
- @Override
- public void run() {
+ @Override
+ public void run() {
synchronized (psLock) {
service.updateViews();
}
- }
+ }
- }
+ }
}
diff --git a/app/src/main/res/layout/all_episodes_fragment.xml b/app/src/main/res/layout/all_episodes_fragment.xml
index 81562b560..5336fb8ce 100644
--- a/app/src/main/res/layout/all_episodes_fragment.xml
+++ b/app/src/main/res/layout/all_episodes_fragment.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:dslv="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
diff --git a/app/src/main/res/layout/downloadlog_item.xml b/app/src/main/res/layout/downloadlog_item.xml
index c6a34a517..20d879933 100644
--- a/app/src/main/res/layout/downloadlog_item.xml
+++ b/app/src/main/res/layout/downloadlog_item.xml
@@ -20,7 +20,7 @@
tools:text="[Icon]"
android:gravity="center" />
- <Button
+ <com.joanzapata.iconify.widget.IconButton
android:id="@+id/btnRetry"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -28,6 +28,7 @@
android:layout_alignLeft="@id/txtvIcon"
android:layout_alignRight="@id/txtvIcon"
android:layout_marginTop="8dp"
+ android:text="{fa-repeat}"
tools:text="↻" />
<TextView
diff --git a/app/src/main/res/layout/feeditemlist_item.xml b/app/src/main/res/layout/feeditemlist_item.xml
index 6b7c45978..d2b85e7df 100644
--- a/app/src/main/res/layout/feeditemlist_item.xml
+++ b/app/src/main/res/layout/feeditemlist_item.xml
@@ -1,14 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="@dimen/listitem_threeline_height"
android:orientation="horizontal"
tools:background="@android:color/darker_gray">
<RelativeLayout
-
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginLeft="@dimen/listitem_threeline_horizontalpadding"
@@ -103,12 +104,10 @@
android:indeterminate="false"
/>
-
-
</RelativeLayout>
<include layout="@layout/vertical_list_divider"/>
<include layout="@layout/secondary_action"/>
-</LinearLayout> \ No newline at end of file
+</LinearLayout>
diff --git a/app/src/main/res/layout/new_episodes_listitem.xml b/app/src/main/res/layout/new_episodes_listitem.xml
index 7a5652c45..cde1b4aa6 100644
--- a/app/src/main/res/layout/new_episodes_listitem.xml
+++ b/app/src/main/res/layout/new_episodes_listitem.xml
@@ -1,11 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<FrameLayout
+ android:id="@+id/container"
+ 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">
+
+<LinearLayout
+ android:layout_width="match_parent"
android:layout_height="@dimen/listitem_threeline_height"
- android:orientation="horizontal"
android:background="?attr/selectableItemBackground"
+ android:orientation="horizontal"
tools:background="@android:color/darker_gray">
<RelativeLayout
@@ -127,4 +133,6 @@
<include layout="@layout/secondary_action" />
-</LinearLayout> \ No newline at end of file
+</LinearLayout>
+
+</FrameLayout>
diff --git a/app/src/main/res/layout/queue_listitem.xml b/app/src/main/res/layout/queue_listitem.xml
index 8572f5e05..d950f11d2 100644
--- a/app/src/main/res/layout/queue_listitem.xml
+++ b/app/src/main/res/layout/queue_listitem.xml
@@ -1,14 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout
+<FrameLayout
+ android:id="@+id/container"
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">
+
+<LinearLayout
+ android:layout_width="match_parent"
android:layout_height="@dimen/listitem_threeline_height"
+ android:background="?attr/selectableItemBackground"
android:orientation="horizontal"
android:paddingLeft="8dp"
android:gravity="center_vertical"
- android:background="?attr/selectableItemBackground"
tools:background="@android:color/darker_gray" >
<ImageView
@@ -135,4 +140,6 @@
<include layout="@layout/secondary_action"/>
-</LinearLayout> \ No newline at end of file
+</LinearLayout>
+
+</FrameLayout>
diff --git a/app/src/main/res/xml/player_widget_info.xml b/app/src/main/res/xml/player_widget_info.xml
index 831f6daf0..1dbfabcd6 100644
--- a/app/src/main/res/xml/player_widget_info.xml
+++ b/app/src/main/res/xml/player_widget_info.xml
@@ -1,4 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
-<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" android:resizeMode="none" android:initialLayout="@layout/player_widget" android:minHeight="40dp" android:minWidth="250dp">
+<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
+ android:resizeMode="horizontal"
+ android:initialLayout="@layout/player_widget"
+ android:updatePeriodMillis="86400000"
+ android:previewImage="@drawable/ic_widget_preview"
+ android:minHeight="40dp"
+ android:minWidth="250dp"
+ android:minResizeWidth="40dp">
</appwidget-provider> \ No newline at end of file
diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml
index 38350155a..e9e9d48f7 100644
--- a/app/src/main/res/xml/preferences.xml
+++ b/app/src/main/res/xml/preferences.xml
@@ -90,6 +90,12 @@
android:summary="@string/pref_unpauseOnBluetoothReconnect_sum"
android:title="@string/pref_unpauseOnBluetoothReconnect_title"/>
<CheckBoxPreference
+ android:defaultValue="false"
+ android:enabled="true"
+ android:key="prefHardwareForwardButtonSkips"
+ android:summary="@string/pref_hardwareForwardButtonSkips_sum"
+ android:title="@string/pref_hardwareForwardButtonSkips_title"/>
+ <CheckBoxPreference
android:defaultValue="true"
android:enabled="true"
android:key="prefFollowQueue"
@@ -245,6 +251,10 @@
<Preference
android:key="prefAbout"
android:title="@string/about_pref"/>
+ <Preference
+ android:key="prefSendCrashReport"
+ android:title="@string/crash_report_title"
+ android:summary="@string/crash_report_sum"/>
</PreferenceCategory>
<PreferenceCategory android:title="@string/experimental_pref">
diff --git a/build.gradle b/build.gradle
index ab6884c76..2a0fb0aa3 100644
--- a/build.gradle
+++ b/build.gradle
@@ -49,6 +49,8 @@ project.ext {
glideVersion = "3.6.1"
jsoupVersion = "1.7.3"
rxAndroidVersion = "1.0.1"
+ rxJavaVersion = "1.0.16"
+ rxJavaRulesVersion = "1.0.16.1"
okhttpVersion = "2.5.0"
okioVersion = "1.6.0"
}
diff --git a/changelog/ar.md b/changelog/ar.md
index 6776f0a7a..06111059e 100644
--- a/changelog/ar.md
+++ b/changelog/ar.md
@@ -1,6 +1,10 @@
Change Log
==========
+Version 1.4.0.12
+----------------
+* Fix for crash on Huawei devices (media buttons may not work)
+
Version 1.4
-----------
* BLUETOOTH PERMISSION: Needed to be able to resume playback when a Bluetooth device reconnects with your phone
diff --git a/changelog/az.md b/changelog/az.md
index 6776f0a7a..06111059e 100644
--- a/changelog/az.md
+++ b/changelog/az.md
@@ -1,6 +1,10 @@
Change Log
==========
+Version 1.4.0.12
+----------------
+* Fix for crash on Huawei devices (media buttons may not work)
+
Version 1.4
-----------
* BLUETOOTH PERMISSION: Needed to be able to resume playback when a Bluetooth device reconnects with your phone
diff --git a/changelog/ca.md b/changelog/ca.md
index f808a0b4f..c1d5920d6 100644
--- a/changelog/ca.md
+++ b/changelog/ca.md
@@ -1,6 +1,10 @@
Registre de canvis
====================
+Version 1.4.0.12
+----------------
+* Fix for crash on Huawei devices (media buttons may not work)
+
Versió 1.4
-----------
* BLUETOOTH PERMISSION: Needed to be able to resume playback when a Bluetooth device reconnects with your phone
diff --git a/changelog/cs_CZ.md b/changelog/cs_CZ.md
index 11a6a44f6..3523ac125 100644
--- a/changelog/cs_CZ.md
+++ b/changelog/cs_CZ.md
@@ -1,6 +1,10 @@
Seznam změn
==========
+Version 1.4.0.12
+----------------
+* Fix for crash on Huawei devices (media buttons may not work)
+
Verze 1.4
-----------
* BLUETOOTH PERMISSION: Needed to be able to resume playback when a Bluetooth device reconnects with your phone
diff --git a/changelog/da.md b/changelog/da.md
index 6b3dab193..72858a0b0 100644
--- a/changelog/da.md
+++ b/changelog/da.md
@@ -1,6 +1,10 @@
Change Log
==========
+Version 1.4.0.12
+----------------
+* Fix for crash on Huawei devices (media buttons may not work)
+
Version 1.4
-----------
* BLUETOOTH PERMISSION: Needed to be able to resume playback when a Bluetooth device reconnects with your phone
diff --git a/changelog/de.md b/changelog/de.md
index 71fe5936c..db3fcef98 100644
--- a/changelog/de.md
+++ b/changelog/de.md
@@ -1,6 +1,10 @@
Änderungen
==========
+Version 1.4.0.12
+----------------
+* Behebt Abstürze von Huawei-Geräten (Abspieltasten funktionieren möglicherweise nicht)
+
Version 1.4
-----------
* BLUETOOTH-Berechtigung: Wird benötigt, um bei Wiederverbindung eines Bluetooth-Gerät mit deinem Smartphone mit dem Abspielen fortzufahren
diff --git a/changelog/el.md b/changelog/el.md
index 7b7d58fbf..57be32b28 100644
--- a/changelog/el.md
+++ b/changelog/el.md
@@ -1,6 +1,10 @@
Καταγραφή Αλλαγών
==========
+Version 1.4.0.12
+----------------
+* Fix for crash on Huawei devices (media buttons may not work)
+
Version 1.4
-----------
* BLUETOOTH PERMISSION: Needed to be able to resume playback when a Bluetooth device reconnects with your phone
diff --git a/changelog/es.md b/changelog/es.md
index e6f0173bc..023cc4eae 100644
--- a/changelog/es.md
+++ b/changelog/es.md
@@ -1,6 +1,10 @@
Registro de cambios
==========
+Version 1.4.0.12
+----------------
+* Fix for crash on Huawei devices (media buttons may not work)
+
Versión 1.4
-----------
* PERMISO BLUETOOTH: Necesario para poder iniciar la reproducción cuando un dispositivo Bluetooth se conecta al teléfono
diff --git a/changelog/es_ES.md b/changelog/es_ES.md
index 6776f0a7a..06111059e 100644
--- a/changelog/es_ES.md
+++ b/changelog/es_ES.md
@@ -1,6 +1,10 @@
Change Log
==========
+Version 1.4.0.12
+----------------
+* Fix for crash on Huawei devices (media buttons may not work)
+
Version 1.4
-----------
* BLUETOOTH PERMISSION: Needed to be able to resume playback when a Bluetooth device reconnects with your phone
diff --git a/changelog/fi.md b/changelog/fi.md
index 6776f0a7a..06111059e 100644
--- a/changelog/fi.md
+++ b/changelog/fi.md
@@ -1,6 +1,10 @@
Change Log
==========
+Version 1.4.0.12
+----------------
+* Fix for crash on Huawei devices (media buttons may not work)
+
Version 1.4
-----------
* BLUETOOTH PERMISSION: Needed to be able to resume playback when a Bluetooth device reconnects with your phone
diff --git a/changelog/fr.md b/changelog/fr.md
index 58e384f99..130774662 100644
--- a/changelog/fr.md
+++ b/changelog/fr.md
@@ -1,6 +1,10 @@
Nouveautés
==========
+Version 1.4.0.12
+----------------
+* Correction d'un plantage sur les appareils Huawei (les boutons de lecture peuvent ne pas fonctionner)
+
Version 1.4
-----------
* PERMISSION BLUETOOTH: Nécessaire afin de pouvoir reprendre la lecture quand la connexion Bluetooth est rétablie avec l'appareil
diff --git a/changelog/he_IL.md b/changelog/he_IL.md
index 6776f0a7a..06111059e 100644
--- a/changelog/he_IL.md
+++ b/changelog/he_IL.md
@@ -1,6 +1,10 @@
Change Log
==========
+Version 1.4.0.12
+----------------
+* Fix for crash on Huawei devices (media buttons may not work)
+
Version 1.4
-----------
* BLUETOOTH PERMISSION: Needed to be able to resume playback when a Bluetooth device reconnects with your phone
diff --git a/changelog/hi_IN.md b/changelog/hi_IN.md
index 42dea95e8..47e7d4cf6 100644
--- a/changelog/hi_IN.md
+++ b/changelog/hi_IN.md
@@ -1,6 +1,10 @@
प्रवेश बदलें
==========
+Version 1.4.0.12
+----------------
+* Fix for crash on Huawei devices (media buttons may not work)
+
Version 1.4
-----------
* BLUETOOTH PERMISSION: Needed to be able to resume playback when a Bluetooth device reconnects with your phone
diff --git a/changelog/hu.md b/changelog/hu.md
index 6776f0a7a..06111059e 100644
--- a/changelog/hu.md
+++ b/changelog/hu.md
@@ -1,6 +1,10 @@
Change Log
==========
+Version 1.4.0.12
+----------------
+* Fix for crash on Huawei devices (media buttons may not work)
+
Version 1.4
-----------
* BLUETOOTH PERMISSION: Needed to be able to resume playback when a Bluetooth device reconnects with your phone
diff --git a/changelog/id.md b/changelog/id.md
index 6776f0a7a..06111059e 100644
--- a/changelog/id.md
+++ b/changelog/id.md
@@ -1,6 +1,10 @@
Change Log
==========
+Version 1.4.0.12
+----------------
+* Fix for crash on Huawei devices (media buttons may not work)
+
Version 1.4
-----------
* BLUETOOTH PERMISSION: Needed to be able to resume playback when a Bluetooth device reconnects with your phone
diff --git a/changelog/it.md b/changelog/it.md
index cf0c8e499..f40778afd 100644
--- a/changelog/it.md
+++ b/changelog/it.md
@@ -1,6 +1,10 @@
Registro dei cambiamenti
==========
+Version 1.4.0.12
+----------------
+* Fix for crash on Huawei devices (media buttons may not work)
+
Version 1.4
-----------
* BLUETOOTH PERMISSION: Needed to be able to resume playback when a Bluetooth device reconnects with your phone
diff --git a/changelog/it_IT.md b/changelog/it_IT.md
index 6cde1c5f0..7fcf20302 100644
--- a/changelog/it_IT.md
+++ b/changelog/it_IT.md
@@ -1,6 +1,10 @@
Registro dei cambiamenti
==========
+Version 1.4.0.12
+----------------
+* Fix for crash on Huawei devices (media buttons may not work)
+
Versione 1.4
-----------
* BLUETOOTH PERMISSION: Needed to be able to resume playback when a Bluetooth device reconnects with your phone
diff --git a/changelog/ja.md b/changelog/ja.md
index 0158028dc..64fb28c66 100644
--- a/changelog/ja.md
+++ b/changelog/ja.md
@@ -1,6 +1,10 @@
変更ログ
==========
+Version 1.4.0.12
+----------------
+* Fix for crash on Huawei devices (media buttons may not work)
+
バージョン 1.4
-----------
* BLUETOOTH アクセス許可: お使いの携帯電話に Bluetooth デバイスが再接続する際、再生を再開するために必要です
diff --git a/changelog/kn_IN.md b/changelog/kn_IN.md
index 6776f0a7a..06111059e 100644
--- a/changelog/kn_IN.md
+++ b/changelog/kn_IN.md
@@ -1,6 +1,10 @@
Change Log
==========
+Version 1.4.0.12
+----------------
+* Fix for crash on Huawei devices (media buttons may not work)
+
Version 1.4
-----------
* BLUETOOTH PERMISSION: Needed to be able to resume playback when a Bluetooth device reconnects with your phone
diff --git a/changelog/ko.md b/changelog/ko.md
index 47a08d6d3..fea036846 100644
--- a/changelog/ko.md
+++ b/changelog/ko.md
@@ -1,6 +1,10 @@
변경 로그
==========
+Version 1.4.0.12
+----------------
+* Fix for crash on Huawei devices (media buttons may not work)
+
Version 1.4
-----------
* BLUETOOTH PERMISSION: Needed to be able to resume playback when a Bluetooth device reconnects with your phone
diff --git a/changelog/ko_KR.md b/changelog/ko_KR.md
index 6776f0a7a..06111059e 100644
--- a/changelog/ko_KR.md
+++ b/changelog/ko_KR.md
@@ -1,6 +1,10 @@
Change Log
==========
+Version 1.4.0.12
+----------------
+* Fix for crash on Huawei devices (media buttons may not work)
+
Version 1.4
-----------
* BLUETOOTH PERMISSION: Needed to be able to resume playback when a Bluetooth device reconnects with your phone
diff --git a/changelog/nb_NO.md b/changelog/nb_NO.md
index e884b6cfc..1c8007023 100644
--- a/changelog/nb_NO.md
+++ b/changelog/nb_NO.md
@@ -1,6 +1,10 @@
Endringslogg
==========
+Version 1.4.0.12
+----------------
+* Fix for crash on Huawei devices (media buttons may not work)
+
Versjon 1.4
-----------
* BLUETOOTH-TILGANG: Kreves for å kunne gjenoppta avspilling når en Bluetooth-enhet kobles til telefonen igjen
diff --git a/changelog/nl.md b/changelog/nl.md
index faf416198..ba26825d6 100644
--- a/changelog/nl.md
+++ b/changelog/nl.md
@@ -1,5 +1,16 @@
Changelog
==========
+Version 1.4.1
+-------------
+* Performance improvements
+* Hardware buttons now ff and rewind instead of skipping
+* Option to have forward button skip
+* Option to send crash reports directly to developers
+* Highlight currently playing episode
+
+Version 1.4.0.12
+----------------
+* Fix for crash on Huawei devices (media buttons may not work)
Versie 1.4
-----------
@@ -26,81 +37,81 @@ Versie 1.3
* Automatisch downloaden verbeterd
* Veel bugfixes en verbeterde gebruiksvriendelijkheid
-Version 1.2
+Versie 1.2
-----------
-* Optionally disable swiping and dragging in the queue
-* Resume playback after phone call
-* Filter episodes in the Podcast feed
-* Hide items in the Nav drawer
-* Customize times for fast forward and rewind
-* Resolved issues with opening some OPML files
-* Various bug fixes and usability improvements
-
-Version 1.1
+* Deactiveer vegen en slepen in de wachtrij eventueel
+* Afspelen hervatten na telefoon gesprek
+* Afleveringen filteren in podcast feed
+* Onderdelen verbergen in menu
+* Personaliseer tijden voor vooruit- en achteruitspoelen
+* Opgelostte problemen bij het open van enkele OPML-bestanden
+* Verscheidene problemen opgelost en gebruikersvriendelijkheid verbeterd
+
+Versie 1.1
-----------
-* iTunes podcast integration
-* Swipe to remove items from the queue
-* Set the number of parallel downloads
-* Fix for gpodder.net on old devices
-* Fixed date problems for some feeds
-* Display improvements
+* iTunes podcast integratie
+* Veeg om afleveringen te verwijderen uit de wachtrij
+* Stel het aantal tegelijktijdige downloads in
+* Oplossing voor gpodder.net op oudere apparaten
+* Oplossing voor datum problemen in sommige feeds
+* Weergave verbeteringen
* Verbeterd gebruiksgemak
-* Several other bugfixes
+* Verscheidene andere oplossingen
-Version 1.0
+Versie 1.0
-----------
-* The queue can now be sorted
-* Added option to delete episode after playback
-* Fixed a bug that caused chapters to be displayed multiple times
-* Several other improvements and bugfixes
+* De wachtrij kan nu gesorteerd worden
+* Mogelijkheid toegevoegd om aflevering te verwijderen na afspelen
+* Oplossing voor probleem waarbij hoofdstukken meerdere malen getoon werden
+* Verscheidene andere verbeteringen en probleem oplossingen
-Version 0.9.9.6
+Versie 0.9.9.6
---------------
-* Fixed problems related to variable playback speed plugins
-* Fixed automatic feed update problems
-* Several other bugfixes and improvements
+* Oplossing gerelateerd aan variabele afspeel snelheid plugins
+* Oplossing voor automatische feed update problemen
+* Diverse andere bugfixes en usability verbeteringen
-Version 0.9.9.5
+Versie 0.9.9.5
---------------
-* Added support for paged feeds
+* Ondersteuning voor feeds bladeren toegevoegd
* Verbeterde gebruikersinterface
-* Added Japanese and Turkish translations
-* Fixed more image loading problems
+* Japanse en Turkse vertalingen toegevoegd
+* Meer afbeeldingen laden problemen opgelost
* Andere bugfixes en verbeteringen
-Version 0.9.9.4
+Versie 0.9.9.4
---------------
-* Added option to keep notification and lockscreen controls when playback is paused
-* Fixed a bug where episode images were not loaded correctly
-* Fixed battery usage problems
+* Optie toegevoegd om notificatie en vergrendelingsscherm bedieningsknoppen te behouden tijdens pauzering
+* Probleem opgelost waarbij afleveringafbeeldingen niet goed geladen werden
+* Batterij gebruik probleem opgelost
-Version 0.9.9.3
+Versie 0.9.9.3
---------------
-* Fixed video playback problems
-* Improved image loading
+* Video afspeel problemen opgelost
+* Laden van afbeeldingen verbeterd
* Andere bugfixes en verbeteringen
-Version 0.9.9.2
+Versie 0.9.9.2
---------------
-* Added support for feed discovery if a website URL is entered
-* Added support for 'next'/'previous' media keys
+* Ondersteuning toegevoegd voor het vinden van feed als er een website URL ingevoerd is
+* Ondersteunin voor 'next' en 'previous' media toetsen
* Verbeterde slaap timer
-* Timestamps in shownotes can now be used to jump to a specific position
-* Automatic Flattring is now configurable
+* Tijdsaanduiding in shownotes kan nu gebruikt worden om naar een specifieke positie te springen
+* Automatisch gebruik van Flattring is nu instelbaar
* Diverse bugfixes en verbeteringen
-Version 0.9.9.1
+Versie 0.9.9.1
---------------
* Diverse bugfixes en verbeteringen
-Version 0.9.9.0
+Versie 0.9.9.0
---------------
-* New user interface
-* Failed downloads are now resumed when restarted
-* Added support for Podlove Alternate Feeds
-* Added support for "pcast"-protocol
-* Added backup & restore functionality. This feature has to be enabled in the Android settings in order to work
+* Nieuw gebruikersinterface
+* Mislukte downloads worden nu hervat na herstarten
+* Ondersteuning voor Podlove Alternate Feeds
+* Ondersteuning voor "pcast" protocol
+* Backup & restore functie toegevoegd. Deze functie moet aangezet worden in de Android instellingen om te functioneren
* Diverse bugfixes en verbeteringen
Version 0.9.8.3
diff --git a/changelog/no.md b/changelog/no.md
index 6776f0a7a..06111059e 100644
--- a/changelog/no.md
+++ b/changelog/no.md
@@ -1,6 +1,10 @@
Change Log
==========
+Version 1.4.0.12
+----------------
+* Fix for crash on Huawei devices (media buttons may not work)
+
Version 1.4
-----------
* BLUETOOTH PERMISSION: Needed to be able to resume playback when a Bluetooth device reconnects with your phone
diff --git a/changelog/pl.md b/changelog/pl.md
index 6776f0a7a..06111059e 100644
--- a/changelog/pl.md
+++ b/changelog/pl.md
@@ -1,6 +1,10 @@
Change Log
==========
+Version 1.4.0.12
+----------------
+* Fix for crash on Huawei devices (media buttons may not work)
+
Version 1.4
-----------
* BLUETOOTH PERMISSION: Needed to be able to resume playback when a Bluetooth device reconnects with your phone
diff --git a/changelog/pl_PL.md b/changelog/pl_PL.md
index d0c12ee9b..0d06d21b6 100644
--- a/changelog/pl_PL.md
+++ b/changelog/pl_PL.md
@@ -1,6 +1,10 @@
Dziennik zmian
==========
+Version 1.4.0.12
+----------------
+* Fix for crash on Huawei devices (media buttons may not work)
+
Version 1.4
-----------
* BLUETOOTH PERMISSION: Needed to be able to resume playback when a Bluetooth device reconnects with your phone
diff --git a/changelog/pt.md b/changelog/pt.md
index b676fd80d..6c1071d85 100644
--- a/changelog/pt.md
+++ b/changelog/pt.md
@@ -1,6 +1,10 @@
Registo de alterações
==========
+Versão 1.4.0.12
+----------------
+* Correções para dispositivos Huawei (botões multimédia não funcionavam)
+
Versão 1.4
-----------
* Permissão Bluetooth: para poder continuar a reprodução ao ligar um dispositivo Bluetooth com o seu dispositivo
diff --git a/changelog/pt_BR.md b/changelog/pt_BR.md
index 8fc2e9f5f..4e68fe0e4 100644
--- a/changelog/pt_BR.md
+++ b/changelog/pt_BR.md
@@ -1,6 +1,10 @@
Últimas modificações
==========
+Version 1.4.0.12
+----------------
+* Fix for crash on Huawei devices (media buttons may not work)
+
Version 1.4
-----------
* BLUETOOTH PERMISSION: Needed to be able to resume playback when a Bluetooth device reconnects with your phone
diff --git a/changelog/ro_RO.md b/changelog/ro_RO.md
index 6a67fc57c..d88c6a736 100644
--- a/changelog/ro_RO.md
+++ b/changelog/ro_RO.md
@@ -1,6 +1,10 @@
Change Log
==========
+Version 1.4.0.12
+----------------
+* Fix for crash on Huawei devices (media buttons may not work)
+
Version 1.4
-----------
* BLUETOOTH PERMISSION: Needed to be able to resume playback when a Bluetooth device reconnects with your phone
diff --git a/changelog/ru_RU.md b/changelog/ru_RU.md
index 60f512495..10f120e4e 100644
--- a/changelog/ru_RU.md
+++ b/changelog/ru_RU.md
@@ -1,6 +1,10 @@
Список изменений
==========
+Version 1.4.0.12
+----------------
+* Fix for crash on Huawei devices (media buttons may not work)
+
Версия 1.4
-----------
* ДОСТУП К BLUETOOTH: Используется для продолжения воспроизведения, когда Bluetooth-устройство переподключается к вашему телефону
diff --git a/changelog/sv_SE.md b/changelog/sv_SE.md
index 53b7d3375..75a35c36f 100644
--- a/changelog/sv_SE.md
+++ b/changelog/sv_SE.md
@@ -1,6 +1,10 @@
Ändringslogg
==========
+Version 1.4.0.12
+----------------
+* Fixade krash på Huawei enheter (mediaknappar kanske inte fungerar)
+
Version 1.4
-----------
* BLUETOOTH PERMISSION: Behövs för att kunna fortsätta uppspelningen när en blåtandsenhet kopplas tillbaka till telefonen
diff --git a/changelog/tr.md b/changelog/tr.md
index 9629e0cf0..f05d8b80e 100644
--- a/changelog/tr.md
+++ b/changelog/tr.md
@@ -1,6 +1,10 @@
Yenilikler
==========
+Version 1.4.0.12
+----------------
+* Fix for crash on Huawei devices (media buttons may not work)
+
Version 1.4
-----------
* BLUETOOTH PERMISSION: Needed to be able to resume playback when a Bluetooth device reconnects with your phone
diff --git a/changelog/uk_UA.md b/changelog/uk_UA.md
index 28a7ed02e..6d8cc7871 100644
--- a/changelog/uk_UA.md
+++ b/changelog/uk_UA.md
@@ -1,6 +1,10 @@
Зміни
==========
+Version 1.4.0.12
+----------------
+* Fix for crash on Huawei devices (media buttons may not work)
+
Версія 1.4
-----------
* Дозвіл на використання bluetooth: Потрібен для поновлення програвання в разі повторного підключення пристроя Bluetooth
diff --git a/changelog/vi.md b/changelog/vi.md
index 6776f0a7a..06111059e 100644
--- a/changelog/vi.md
+++ b/changelog/vi.md
@@ -1,6 +1,10 @@
Change Log
==========
+Version 1.4.0.12
+----------------
+* Fix for crash on Huawei devices (media buttons may not work)
+
Version 1.4
-----------
* BLUETOOTH PERMISSION: Needed to be able to resume playback when a Bluetooth device reconnects with your phone
diff --git a/changelog/vi_VN.md b/changelog/vi_VN.md
index 6776f0a7a..06111059e 100644
--- a/changelog/vi_VN.md
+++ b/changelog/vi_VN.md
@@ -1,6 +1,10 @@
Change Log
==========
+Version 1.4.0.12
+----------------
+* Fix for crash on Huawei devices (media buttons may not work)
+
Version 1.4
-----------
* BLUETOOTH PERMISSION: Needed to be able to resume playback when a Bluetooth device reconnects with your phone
diff --git a/changelog/zh_CN.md b/changelog/zh_CN.md
index 01a1c80c8..7c0f7228b 100644
--- a/changelog/zh_CN.md
+++ b/changelog/zh_CN.md
@@ -1,6 +1,10 @@
更新日志
==========
+Version 1.4.0.12
+----------------
+* Fix for crash on Huawei devices (media buttons may not work)
+
Version 1.4
-----------
* BLUETOOTH PERMISSION: Needed to be able to resume playback when a Bluetooth device reconnects with your phone
diff --git a/core/src/main/java/de/danoeh/antennapod/core/asynctask/DownloadObserver.java b/core/src/main/java/de/danoeh/antennapod/core/asynctask/DownloadObserver.java
deleted file mode 100644
index 2ce506c22..000000000
--- a/core/src/main/java/de/danoeh/antennapod/core/asynctask/DownloadObserver.java
+++ /dev/null
@@ -1,191 +0,0 @@
-package de.danoeh.antennapod.core.asynctask;
-
-import android.app.Activity;
-import android.content.*;
-import android.os.Handler;
-import android.os.IBinder;
-import android.util.Log;
-
-import org.apache.commons.lang3.Validate;
-
-import de.danoeh.antennapod.core.BuildConfig;
-import de.danoeh.antennapod.core.service.download.DownloadService;
-import de.danoeh.antennapod.core.service.download.Downloader;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-
-/**
- * Provides access to the DownloadService's list of items that are currently being downloaded.
- * The DownloadObserver object should be created in the activity's onCreate() method. resume() and pause()
- * should be called in the activity's onResume() and onPause() methods
- */
-public class DownloadObserver {
- private static final String TAG = "DownloadObserver";
-
- /**
- * Time period between update notifications.
- */
- public static final int WAITING_INTERVAL_MS = 3000;
-
- private volatile Activity activity;
- private final Handler handler;
- private final Callback callback;
-
- private DownloadService downloadService = null;
- private AtomicBoolean mIsBound = new AtomicBoolean(false);
-
- private Thread refresherThread;
- private AtomicBoolean refresherThreadRunning = new AtomicBoolean(false);
-
- private AtomicInteger users = new AtomicInteger(0);
-
-
- /**
- * Creates a new download observer.
- *
- * @param activity Used for registering receivers
- * @param handler All callback methods are executed on this handler. The handler MUST run on the GUI thread.
- * @param callback Callback methods for posting content updates
- * @throws java.lang.IllegalArgumentException if one of the arguments is null.
- */
- public DownloadObserver(Activity activity, Handler handler, Callback callback) {
- Validate.notNull(activity);
- Validate.notNull(handler);
- Validate.notNull(callback);
-
- this.activity = activity;
- this.handler = handler;
- this.callback = callback;
- }
-
- public void onResume() {
- Log.d(TAG, "DownloadObserver resumed");
- if(users.getAndIncrement() == 0) {
- activity.registerReceiver(contentChangedReceiver, new IntentFilter(DownloadService.ACTION_DOWNLOADS_CONTENT_CHANGED));
- connectToDownloadService();
- }
- }
-
- public void onPause() {
- Log.d(TAG, "DownloadObserver paused");
- if(users.decrementAndGet() > 0) {
- return;
- }
- try {
- activity.unregisterReceiver(contentChangedReceiver);
- } catch (IllegalArgumentException e) {
- e.printStackTrace();
- }
- try {
- activity.unbindService(mConnection);
- } catch (IllegalArgumentException e) {
- e.printStackTrace();
- }
- stopRefresher();
- }
-
- private BroadcastReceiver contentChangedReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- // reconnect to DownloadService if connection has been closed
- if (downloadService == null) {
- connectToDownloadService();
- }
- if (downloadService != null) {
- callback.onContentChanged(downloadService.getDownloads());
- } else {
- // the service is gone, there are no more downloads.
- callback.onContentChanged(new ArrayList<Downloader>());
- }
- startRefresher();
- }
- };
-
- public interface Callback {
- void onContentChanged(List<Downloader> downloaderList);
- }
-
- private void connectToDownloadService() {
- activity.bindService(new Intent(activity, DownloadService.class), mConnection, 0);
- }
-
- private ServiceConnection mConnection = new ServiceConnection() {
- public void onServiceDisconnected(ComponentName className) {
- downloadService = null;
- mIsBound.set(false);
- stopRefresher();
- Log.i(TAG, "Closed connection with DownloadService.");
- }
-
- public void onServiceConnected(ComponentName name, IBinder service) {
- downloadService = ((DownloadService.LocalBinder) service)
- .getService();
- mIsBound.set(true);
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Connection to service established");
- List<Downloader> downloaderList = downloadService.getDownloads();
- if (downloaderList != null && !downloaderList.isEmpty()) {
- callback.onContentChanged(downloaderList);
- startRefresher();
- }
- }
- };
-
- private void stopRefresher() {
- if (refresherThread != null) {
- refresherThread.interrupt();
- }
- }
-
- private void startRefresher() {
- if (refresherThread == null || refresherThread.isInterrupted()) {
- refresherThread = new Thread(new RefresherThread());
- refresherThread.start();
- }
- }
-
- private class RefresherThread implements Runnable {
-
- public void run() {
- refresherThreadRunning.set(true);
- while (!Thread.interrupted()) {
- try {
- Thread.sleep(WAITING_INTERVAL_MS);
- } catch (InterruptedException e) {
- Log.d(TAG, "Refresher thread was interrupted");
- }
- if (mIsBound.get()) {
- postUpdate();
- }
- }
- refresherThreadRunning.set(false);
- }
-
- private void postUpdate() {
- handler.post(new Runnable() {
- @Override
- public void run() {
- if (downloadService != null) {
- List<Downloader> downloaderList = downloadService.getDownloads();
- callback.onContentChanged(downloaderList);
- if (downloaderList == null || downloaderList.isEmpty()) {
- Thread.currentThread().interrupt();
- }
- } else {
- callback.onContentChanged(new ArrayList<Downloader>());
- }
- }
- });
- }
- }
-
- public void setActivity(Activity activity) {
- Validate.notNull(activity);
- this.activity = activity;
- }
-
-}
-
diff --git a/core/src/main/java/de/danoeh/antennapod/core/asynctask/FlattrClickWorker.java b/core/src/main/java/de/danoeh/antennapod/core/asynctask/FlattrClickWorker.java
index 93b584677..ac032fcc0 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/asynctask/FlattrClickWorker.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/asynctask/FlattrClickWorker.java
@@ -6,11 +6,11 @@ import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.os.AsyncTask;
+import android.support.annotation.NonNull;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import android.widget.Toast;
-import org.apache.commons.lang3.Validate;
import org.shredzone.flattr4j.exception.FlattrException;
import java.util.LinkedList;
@@ -63,8 +63,7 @@ public class FlattrClickWorker extends AsyncTask<Void, Integer, FlattrClickWorke
*
* @param context A context for accessing the database and posting notifications. Must not be null.
*/
- public FlattrClickWorker(Context context) {
- Validate.notNull(context);
+ public FlattrClickWorker(@NonNull Context context) {
this.context = context.getApplicationContext();
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/event/DownloadEvent.java b/core/src/main/java/de/danoeh/antennapod/core/event/DownloadEvent.java
new file mode 100644
index 000000000..124fd3e64
--- /dev/null
+++ b/core/src/main/java/de/danoeh/antennapod/core/event/DownloadEvent.java
@@ -0,0 +1,28 @@
+package de.danoeh.antennapod.core.event;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import de.danoeh.antennapod.core.service.download.Downloader;
+
+public class DownloadEvent {
+
+ public final DownloaderUpdate update;
+
+ private DownloadEvent(DownloaderUpdate downloader) {
+ this.update = downloader;
+ }
+
+ public static DownloadEvent refresh(List<Downloader> list) {
+ list = new ArrayList<>(list);
+ DownloaderUpdate update = new DownloaderUpdate(list);
+ return new DownloadEvent(update);
+ }
+
+ @Override
+ public String toString() {
+ return "DownloadEvent{" +
+ "update=" + update +
+ '}';
+ }
+}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/event/DownloaderUpdate.java b/core/src/main/java/de/danoeh/antennapod/core/event/DownloaderUpdate.java
new file mode 100644
index 000000000..dcb033267
--- /dev/null
+++ b/core/src/main/java/de/danoeh/antennapod/core/event/DownloaderUpdate.java
@@ -0,0 +1,53 @@
+package de.danoeh.antennapod.core.event;
+
+import java.util.Arrays;
+import java.util.List;
+
+import de.danoeh.antennapod.core.feed.Feed;
+import de.danoeh.antennapod.core.feed.FeedMedia;
+import de.danoeh.antennapod.core.service.download.Downloader;
+import de.danoeh.antennapod.core.util.LongList;
+
+public class DownloaderUpdate {
+
+ /* Downloaders that are currently running */
+ public final List<Downloader> downloaders;
+
+ /**
+ * IDs of feeds that are currently being downloaded
+ * Often used to show some progress wheel in the action bar
+ */
+ public final long[] feedIds;
+
+ /**
+ * IDs of feed media that are currently being downloaded
+ * Can be used to show and update download progress bars
+ */
+ public final long[] mediaIds;
+
+ public DownloaderUpdate(List<Downloader> downloaders) {
+ this.downloaders = downloaders;
+ LongList feedIds1 = new LongList(), mediaIds1 = new LongList();
+ for(Downloader d1 : downloaders) {
+ int type = d1.getDownloadRequest().getFeedfileType();
+ long id = d1.getDownloadRequest().getFeedfileId();
+ if(type == Feed.FEEDFILETYPE_FEED) {
+ feedIds1.add(id);
+ } else if(type == FeedMedia.FEEDFILETYPE_FEEDMEDIA) {
+ mediaIds1.add(id);
+ }
+ }
+
+ this.feedIds = feedIds1.toArray();
+ this.mediaIds = mediaIds1.toArray();
+ }
+
+ @Override
+ public String toString() {
+ return "DownloaderUpdate{" +
+ "downloaders=" + downloaders +
+ ", feedIds=" + Arrays.toString(feedIds) +
+ ", mediaIds=" + Arrays.toString(mediaIds) +
+ '}';
+ }
+}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/event/FeedItemEvent.java b/core/src/main/java/de/danoeh/antennapod/core/event/FeedItemEvent.java
index a4a79187e..7ff241456 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/event/FeedItemEvent.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/event/FeedItemEvent.java
@@ -6,6 +6,7 @@ import android.support.annotation.NonNull;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
+import java.util.Arrays;
import java.util.List;
import de.danoeh.antennapod.core.feed.FeedItem;
@@ -32,6 +33,10 @@ public class FeedItemEvent {
return new FeedItemEvent(Action.UPDATE, items);
}
+ public static FeedItemEvent updated(FeedItem... items) {
+ return new FeedItemEvent(Action.UPDATE, Arrays.asList(items));
+ }
+
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/EventDistributor.java b/core/src/main/java/de/danoeh/antennapod/core/feed/EventDistributor.java
index 2667a2e12..7ccb742fb 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/feed/EventDistributor.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/feed/EventDistributor.java
@@ -3,8 +3,6 @@ package de.danoeh.antennapod.core.feed;
import android.os.Handler;
import android.util.Log;
-import org.apache.commons.lang3.Validate;
-
import java.util.AbstractQueue;
import java.util.Observable;
import java.util.Observer;
@@ -26,7 +24,6 @@ public class EventDistributor extends Observable {
public static final int UNREAD_ITEMS_UPDATE = 2;
public static final int DOWNLOADLOG_UPDATE = 8;
public static final int PLAYBACK_HISTORY_UPDATE = 16;
- public static final int DOWNLOAD_QUEUED = 32;
public static final int DOWNLOAD_HANDLED = 64;
public static final int PLAYER_STATUS_UPDATE = 128;
@@ -85,11 +82,6 @@ public class EventDistributor extends Observable {
@Override
public void addObserver(Observer observer) {
super.addObserver(observer);
- Validate.isInstanceOf(EventListener.class, observer);
- }
-
- public void sendDownloadQueuedBroadcast() {
- addEvent(DOWNLOAD_QUEUED);
}
public void sendUnreadItemsUpdateBroadcast() {
@@ -108,10 +100,6 @@ public class EventDistributor extends Observable {
addEvent(DOWNLOADLOG_UPDATE);
}
- public void sendDownloadHandledBroadcast() {
- addEvent(DOWNLOAD_HANDLED);
- }
-
public void sendPlayerStatusUpdateBroadcast() { addEvent(PLAYER_STATUS_UPDATE); }
public static abstract class EventListener implements Observer {
diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/Feed.java b/core/src/main/java/de/danoeh/antennapod/core/feed/Feed.java
index 6b93723a0..0de046fe5 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/feed/Feed.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/feed/Feed.java
@@ -4,8 +4,7 @@ import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.support.annotation.Nullable;
-
-import org.apache.commons.lang3.StringUtils;
+import android.text.TextUtils;
import java.util.ArrayList;
import java.util.Date;
@@ -292,7 +291,8 @@ public class Feed extends FeedFile implements FlattrThing, ImageResource {
}
public void updateFromOther(Feed other) {
- super.updateFromOther(other);
+ // don't update feed's download_url, we do that manually if redirected
+ // see AntennapodHttpClient
if (other.title != null) {
title = other.title;
}
@@ -366,7 +366,7 @@ public class Feed extends FeedFile implements FlattrThing, ImageResource {
if (other.isPaged() && !this.isPaged()) {
return true;
}
- if (!StringUtils.equals(other.getNextPageLink(), this.getNextPageLink())) {
+ if (!TextUtils.equals(other.getNextPageLink(), this.getNextPageLink())) {
return true;
}
return false;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItemFilter.java b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItemFilter.java
index c1d21552e..d3d5dd0a1 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItemFilter.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItemFilter.java
@@ -1,8 +1,6 @@
package de.danoeh.antennapod.core.feed;
-import android.content.Context;
-
-import org.apache.commons.lang3.StringUtils;
+import android.text.TextUtils;
import java.util.ArrayList;
import java.util.List;
@@ -22,7 +20,7 @@ public class FeedItemFilter {
private boolean hideNotDownloaded = false;
public FeedItemFilter(String properties) {
- this(StringUtils.split(properties, ','));
+ this(TextUtils.split(",", properties));
}
public FeedItemFilter(String[] properties) {
diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedPreferences.java b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedPreferences.java
index eb28a3185..ed568a6e5 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedPreferences.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedPreferences.java
@@ -2,8 +2,7 @@ package de.danoeh.antennapod.core.feed;
import android.content.Context;
import android.database.Cursor;
-
-import org.apache.commons.lang3.StringUtils;
+import android.text.TextUtils;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.storage.DBWriter;
@@ -60,10 +59,10 @@ public class FeedPreferences {
public boolean compareWithOther(FeedPreferences other) {
if (other == null)
return true;
- if (!StringUtils.equals(username, other.username)) {
+ if (!TextUtils.equals(username, other.username)) {
return true;
}
- if (!StringUtils.equals(password, other.password)) {
+ if (!TextUtils.equals(password, other.password)) {
return true;
}
return false;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/GpodnetService.java b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/GpodnetService.java
index d8e07085d..d2a13f768 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/GpodnetService.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/GpodnetService.java
@@ -1,5 +1,7 @@
package de.danoeh.antennapod.core.gpoddernet;
+import android.support.annotation.NonNull;
+
import com.squareup.okhttp.Credentials;
import com.squareup.okhttp.MediaType;
import com.squareup.okhttp.OkHttpClient;
@@ -8,7 +10,6 @@ import com.squareup.okhttp.RequestBody;
import com.squareup.okhttp.Response;
import com.squareup.okhttp.ResponseBody;
-import org.apache.commons.lang3.Validate;
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.json.JSONArray;
@@ -101,10 +102,9 @@ public class GpodnetService {
*
* @throws IllegalArgumentException if tag is null
*/
- public List<GpodnetPodcast> getPodcastsForTag(GpodnetTag tag, int count)
+ public List<GpodnetPodcast> getPodcastsForTag(@NonNull GpodnetTag tag,
+ int count)
throws GpodnetServiceException {
- Validate.notNull(tag);
-
try {
URL url = new URI(BASE_SCHEME, BASE_HOST, String.format(
"/api/2/tag/%s/%d.json", tag.getTag(), count), null).toURL();
@@ -128,7 +128,9 @@ public class GpodnetService {
*/
public List<GpodnetPodcast> getPodcastToplist(int count)
throws GpodnetServiceException {
- Validate.isTrue(count >= 1 && count <= 100, "Count must be in range 1..100");
+ if(count < 1 || count > 100) {
+ throw new IllegalArgumentException("Count must be in range 1..100");
+ }
try {
URL url = new URI(BASE_SCHEME, BASE_HOST, String.format(
@@ -158,7 +160,9 @@ public class GpodnetService {
* @throws GpodnetServiceAuthenticationException If there is an authentication error.
*/
public List<GpodnetPodcast> getSuggestions(int count) throws GpodnetServiceException {
- Validate.isTrue(count >= 1 && count <= 100, "Count must be in range 1..100");
+ if(count < 1 || count > 100) {
+ throw new IllegalArgumentException("Count must be in range 1..100");
+ }
try {
URL url = new URI(BASE_SCHEME, BASE_HOST, String.format(
@@ -215,10 +219,8 @@ public class GpodnetService {
* @throws IllegalArgumentException If username is null.
* @throws GpodnetServiceAuthenticationException If there is an authentication error.
*/
- public List<GpodnetDevice> getDevices(String username)
+ public List<GpodnetDevice> getDevices(@NonNull String username)
throws GpodnetServiceException {
- Validate.notNull(username);
-
try {
URL url = new URI(BASE_SCHEME, BASE_HOST, String.format(
"/api/2/devices/%s.json", username), null).toURL();
@@ -243,12 +245,11 @@ public class GpodnetService {
* @throws IllegalArgumentException If username or deviceId is null.
* @throws GpodnetServiceAuthenticationException If there is an authentication error.
*/
- public void configureDevice(String username, String deviceId,
- String caption, GpodnetDevice.DeviceType type)
+ public void configureDevice(@NonNull String username,
+ @NonNull String deviceId,
+ String caption,
+ GpodnetDevice.DeviceType type)
throws GpodnetServiceException {
- Validate.notNull(username);
- Validate.notNull(deviceId);
-
try {
URL url = new URI(BASE_SCHEME, BASE_HOST, String.format(
"/api/2/devices/%s/%s.json", username, deviceId), null).toURL();
@@ -286,11 +287,9 @@ public class GpodnetService {
* @throws IllegalArgumentException If username or deviceId is null.
* @throws GpodnetServiceAuthenticationException If there is an authentication error.
*/
- public String getSubscriptionsOfDevice(String username, String deviceId)
+ public String getSubscriptionsOfDevice(@NonNull String username,
+ @NonNull String deviceId)
throws GpodnetServiceException {
- Validate.notNull(username);
- Validate.notNull(deviceId);
-
try {
URL url = new URI(BASE_SCHEME, BASE_HOST, String.format(
"/subscriptions/%s/%s.opml", username, deviceId), null).toURL();
@@ -313,9 +312,8 @@ public class GpodnetService {
* @throws IllegalArgumentException If username is null.
* @throws GpodnetServiceAuthenticationException If there is an authentication error.
*/
- public String getSubscriptionsOfUser(String username)
+ public String getSubscriptionsOfUser(@NonNull String username)
throws GpodnetServiceException {
- Validate.notNull(username);
try {
URL url = new URI(BASE_SCHEME, BASE_HOST, String.format(
@@ -342,12 +340,11 @@ public class GpodnetService {
* @throws IllegalArgumentException If username, deviceId or subscriptions is null.
* @throws GpodnetServiceAuthenticationException If there is an authentication error.
*/
- public void uploadSubscriptions(String username, String deviceId,
- List<String> subscriptions) throws GpodnetServiceException {
- if (username == null || deviceId == null || subscriptions == null) {
- throw new IllegalArgumentException(
- "Username, device ID and subscriptions must not be null");
- }
+ public void uploadSubscriptions(@NonNull String username,
+ @NonNull String deviceId,
+ @NonNull List<String> subscriptions)
+ throws GpodnetServiceException {
+
try {
URL url = new URI(BASE_SCHEME, BASE_HOST, String.format(
"/subscriptions/%s/%s.txt", username, deviceId), null).toURL();
@@ -363,6 +360,7 @@ public class GpodnetService {
e.printStackTrace();
throw new GpodnetServiceException(e);
}
+
}
/**
@@ -381,12 +379,11 @@ public class GpodnetService {
* @throws de.danoeh.antennapod.core.gpoddernet.GpodnetServiceException if added or removed contain duplicates or if there
* is an authentication error.
*/
- public GpodnetUploadChangesResponse uploadChanges(String username, String deviceId, Collection<String> added,
- Collection<String> removed) throws GpodnetServiceException {
- Validate.notNull(username);
- Validate.notNull(deviceId);
- Validate.notNull(added);
- Validate.notNull(removed);
+ public GpodnetUploadChangesResponse uploadChanges(@NonNull String username,
+ @NonNull String deviceId,
+ @NonNull Collection<String> added,
+ @NonNull Collection<String> removed)
+ throws GpodnetServiceException {
try {
URL url = new URI(BASE_SCHEME, BASE_HOST, String.format(
@@ -422,10 +419,9 @@ public class GpodnetService {
* @throws IllegalArgumentException If username or deviceId is null.
* @throws GpodnetServiceAuthenticationException If there is an authentication error.
*/
- public GpodnetSubscriptionChange getSubscriptionChanges(String username,
- String deviceId, long timestamp) throws GpodnetServiceException {
- Validate.notNull(username);
- Validate.notNull(deviceId);
+ public GpodnetSubscriptionChange getSubscriptionChanges(@NonNull String username,
+ @NonNull String deviceId,
+ long timestamp) throws GpodnetServiceException {
String params = String.format("since=%d", timestamp);
String path = String.format("/api/2/subscriptions/%s/%s.json",
@@ -460,11 +456,9 @@ public class GpodnetService {
* @throws de.danoeh.antennapod.core.gpoddernet.GpodnetServiceException if added or removed contain duplicates or if there
* is an authentication error.
*/
- public GpodnetEpisodeActionPostResponse uploadEpisodeActions(Collection<GpodnetEpisodeAction> episodeActions)
+ public GpodnetEpisodeActionPostResponse uploadEpisodeActions(@NonNull Collection<GpodnetEpisodeAction> episodeActions)
throws GpodnetServiceException {
- Validate.notNull(episodeActions);
-
String username = GpodnetPreferences.getUsername();
try {
@@ -533,11 +527,9 @@ public class GpodnetService {
*
* @throws IllegalArgumentException If username or password is null.
*/
- public void authenticate(String username, String password)
+ public void authenticate(@NonNull String username,
+ @NonNull String password)
throws GpodnetServiceException {
- Validate.notNull(username);
- Validate.notNull(password);
-
URL url;
try {
url = new URI(BASE_SCHEME, BASE_HOST, String.format(
@@ -564,10 +556,8 @@ public class GpodnetService {
}.start();
}
- private String executeRequest(Request.Builder requestB)
+ private String executeRequest(@NonNull Request.Builder requestB)
throws GpodnetServiceException {
- Validate.notNull(requestB);
-
Request request = requestB.header("User-Agent", ClientConfig.USER_AGENT).build();
String responseString = null;
Response response = null;
@@ -631,10 +621,8 @@ public class GpodnetService {
return result;
}
- private String getStringFromResponseBody(ResponseBody body)
+ private String getStringFromResponseBody(@NonNull ResponseBody body)
throws GpodnetServiceException {
- Validate.notNull(body);
-
ByteArrayOutputStream outputStream;
int contentLength = 0;
try {
@@ -661,9 +649,8 @@ public class GpodnetService {
return outputStream.toString();
}
- private void checkStatusCode(Response response)
+ private void checkStatusCode(@NonNull Response response)
throws GpodnetServiceException {
- Validate.notNull(response);
int responseCode = response.code();
if (responseCode != HttpStatus.SC_OK) {
if (responseCode == HttpStatus.SC_UNAUTHORIZED) {
@@ -675,17 +662,14 @@ public class GpodnetService {
}
}
- private List<GpodnetPodcast> readPodcastListFromJSONArray(JSONArray array)
+ private List<GpodnetPodcast> readPodcastListFromJSONArray(@NonNull JSONArray array)
throws JSONException {
- Validate.notNull(array);
-
List<GpodnetPodcast> result = new ArrayList<GpodnetPodcast>(
array.length());
for (int i = 0; i < array.length(); i++) {
result.add(readPodcastFromJSONObject(array.getJSONObject(i)));
}
return result;
-
}
private GpodnetPodcast readPodcastFromJSONObject(JSONObject object)
@@ -730,10 +714,8 @@ public class GpodnetService {
logoUrl, website, mygpoLink);
}
- private List<GpodnetDevice> readDeviceListFromJSONArray(JSONArray array)
+ private List<GpodnetDevice> readDeviceListFromJSONArray(@NonNull JSONArray array)
throws JSONException {
- Validate.notNull(array);
-
List<GpodnetDevice> result = new ArrayList<GpodnetDevice>(
array.length());
for (int i = 0; i < array.length(); i++) {
@@ -752,8 +734,7 @@ public class GpodnetService {
}
private GpodnetSubscriptionChange readSubscriptionChangesFromJSONObject(
- JSONObject object) throws JSONException {
- Validate.notNull(object);
+ @NonNull JSONObject object) throws JSONException {
List<String> added = new LinkedList<String>();
JSONArray jsonAdded = object.getJSONArray("add");
@@ -772,8 +753,7 @@ public class GpodnetService {
}
private GpodnetEpisodeActionGetResponse readEpisodeActionsFromJSONObject(
- JSONObject object) throws JSONException {
- Validate.notNull(object);
+ @NonNull JSONObject object) throws JSONException {
List<GpodnetEpisodeAction> episodeActions = new ArrayList<GpodnetEpisodeAction>();
@@ -789,5 +769,4 @@ public class GpodnetService {
return new GpodnetEpisodeActionGetResponse(episodeActions, timestamp);
}
-
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetDevice.java b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetDevice.java
index 4885a243a..2d49c170a 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetDevice.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetDevice.java
@@ -1,6 +1,6 @@
package de.danoeh.antennapod.core.gpoddernet.model;
-import org.apache.commons.lang3.Validate;
+import android.support.annotation.NonNull;
public class GpodnetDevice {
@@ -9,10 +9,10 @@ public class GpodnetDevice {
private DeviceType type;
private int subscriptions;
- public GpodnetDevice(String id, String caption, String type,
+ public GpodnetDevice(@NonNull String id,
+ String caption,
+ String type,
int subscriptions) {
- Validate.notNull(id);
-
this.id = id;
this.caption = caption;
this.type = DeviceType.fromString(type);
diff --git a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetEpisodeAction.java b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetEpisodeAction.java
index efe39485e..2d174a6bc 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetEpisodeAction.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetEpisodeAction.java
@@ -1,13 +1,9 @@
package de.danoeh.antennapod.core.gpoddernet.model;
+import android.text.TextUtils;
import android.util.Log;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.builder.EqualsBuilder;
-import org.apache.commons.lang3.builder.HashCodeBuilder;
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
import org.json.JSONException;
import org.json.JSONObject;
@@ -90,7 +86,7 @@ public class GpodnetEpisodeAction {
String podcast = object.optString("podcast", null);
String episode = object.optString("episode", null);
String actionString = object.optString("action", null);
- if(StringUtils.isEmpty(podcast) || StringUtils.isEmpty(episode) || StringUtils.isEmpty(actionString)) {
+ if(TextUtils.isEmpty(podcast) || TextUtils.isEmpty(episode) || TextUtils.isEmpty(actionString)) {
return null;
}
GpodnetEpisodeAction.Action action;
@@ -103,7 +99,7 @@ public class GpodnetEpisodeAction {
GpodnetEpisodeAction.Builder builder = new GpodnetEpisodeAction.Builder(podcast, episode, action)
.deviceId(deviceId);
String utcTimestamp = object.optString("timestamp", null);
- if(StringUtils.isNotEmpty(utcTimestamp)) {
+ if(!TextUtils.isEmpty(utcTimestamp)) {
builder.timestamp(DateUtils.parse(utcTimestamp));
}
if(action == GpodnetEpisodeAction.Action.PLAY) {
@@ -173,34 +169,34 @@ public class GpodnetEpisodeAction {
@Override
public boolean equals(Object o) {
- if(o == null) return false;
- if(this == o) return true;
- if(this.getClass() != o.getClass()) return false;
- GpodnetEpisodeAction that = (GpodnetEpisodeAction)o;
- return new EqualsBuilder()
- .append(this.podcast, that.podcast)
- .append(this.episode, that.episode)
- .append(this.deviceId, that.deviceId)
- .append(this.action, that.action)
- .append(this.timestamp, that.timestamp)
- .append(this.started, that.started)
- .append(this.position, that.position)
- .append(this.total, that.total)
- .isEquals();
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ GpodnetEpisodeAction that = (GpodnetEpisodeAction) o;
+
+ if (started != that.started) return false;
+ if (position != that.position) return false;
+ if (total != that.total) return false;
+ if (podcast != null ? !podcast.equals(that.podcast) : that.podcast != null) return false;
+ if (episode != null ? !episode.equals(that.episode) : that.episode != null) return false;
+ if (deviceId != null ? !deviceId.equals(that.deviceId) : that.deviceId != null)
+ return false;
+ if (action != that.action) return false;
+ return !(timestamp != null ? !timestamp.equals(that.timestamp) : that.timestamp != null);
+
}
@Override
public int hashCode() {
- return new HashCodeBuilder()
- .append(this.podcast)
- .append(this.episode)
- .append(this.deviceId)
- .append(this.action)
- .append(this.timestamp)
- .append(this.started)
- .append(this.position)
- .append(this.total)
- .toHashCode();
+ int result = podcast != null ? podcast.hashCode() : 0;
+ result = 31 * result + (episode != null ? episode.hashCode() : 0);
+ result = 31 * result + (deviceId != null ? deviceId.hashCode() : 0);
+ result = 31 * result + (action != null ? action.hashCode() : 0);
+ result = 31 * result + (timestamp != null ? timestamp.hashCode() : 0);
+ result = 31 * result + started;
+ result = 31 * result + position;
+ result = 31 * result + total;
+ return result;
}
public String writeToString() {
@@ -245,7 +241,16 @@ public class GpodnetEpisodeAction {
@Override
public String toString() {
- return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
+ return "GpodnetEpisodeAction{" +
+ "podcast='" + podcast + '\'' +
+ ", episode='" + episode + '\'' +
+ ", deviceId='" + deviceId + '\'' +
+ ", action=" + action +
+ ", timestamp=" + timestamp +
+ ", started=" + started +
+ ", position=" + position +
+ ", total=" + total +
+ '}';
}
public static class Builder {
diff --git a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetEpisodeActionGetResponse.java b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetEpisodeActionGetResponse.java
index 50420f0a3..1e21efcda 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetEpisodeActionGetResponse.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetEpisodeActionGetResponse.java
@@ -1,9 +1,7 @@
package de.danoeh.antennapod.core.gpoddernet.model;
-import org.apache.commons.lang3.Validate;
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
+import android.support.annotation.NonNull;
import java.util.List;
@@ -12,8 +10,8 @@ public class GpodnetEpisodeActionGetResponse {
private final List<GpodnetEpisodeAction> episodeActions;
private final long timestamp;
- public GpodnetEpisodeActionGetResponse(List<GpodnetEpisodeAction> episodeActions, long timestamp) {
- Validate.notNull(episodeActions);
+ public GpodnetEpisodeActionGetResponse(@NonNull List<GpodnetEpisodeAction> episodeActions,
+ long timestamp) {
this.episodeActions = episodeActions;
this.timestamp = timestamp;
}
@@ -28,7 +26,9 @@ public class GpodnetEpisodeActionGetResponse {
@Override
public String toString() {
- return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
+ return "GpodnetEpisodeActionGetResponse{" +
+ "episodeActions=" + episodeActions +
+ ", timestamp=" + timestamp +
+ '}';
}
-
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetPodcast.java b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetPodcast.java
index afebf66ac..191c0fa39 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetPodcast.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetPodcast.java
@@ -1,6 +1,6 @@
package de.danoeh.antennapod.core.gpoddernet.model;
-import org.apache.commons.lang3.Validate;
+import android.support.annotation.NonNull;
public class GpodnetPodcast {
private String url;
@@ -11,12 +11,13 @@ public class GpodnetPodcast {
private String website;
private String mygpoLink;
- public GpodnetPodcast(String url, String title, String description,
- int subscribers, String logoUrl, String website, String mygpoLink) {
- Validate.notNull(url);
- Validate.notNull(title);
- Validate.notNull(description);
-
+ public GpodnetPodcast(@NonNull String url,
+ @NonNull String title,
+ @NonNull String description,
+ int subscribers,
+ String logoUrl,
+ String website,
+ String mygpoLink) {
this.url = url;
this.title = title;
this.description = description;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetSubscriptionChange.java b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetSubscriptionChange.java
index a5cb8c0f0..6cc9b79a3 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetSubscriptionChange.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetSubscriptionChange.java
@@ -1,6 +1,6 @@
package de.danoeh.antennapod.core.gpoddernet.model;
-import org.apache.commons.lang3.Validate;
+import android.support.annotation.NonNull;
import java.util.List;
@@ -9,11 +9,9 @@ public class GpodnetSubscriptionChange {
private List<String> removed;
private long timestamp;
- public GpodnetSubscriptionChange(List<String> added, List<String> removed,
+ public GpodnetSubscriptionChange(@NonNull List<String> added,
+ @NonNull List<String> removed,
long timestamp) {
- Validate.notNull(added);
- Validate.notNull(removed);
-
this.added = added;
this.removed = removed;
this.timestamp = timestamp;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetTag.java b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetTag.java
index ee13bef25..42a31afc5 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetTag.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetTag.java
@@ -2,8 +2,7 @@ package de.danoeh.antennapod.core.gpoddernet.model;
import android.os.Parcel;
import android.os.Parcelable;
-
-import org.apache.commons.lang3.Validate;
+import android.support.annotation.NonNull;
public class GpodnetTag implements Parcelable {
@@ -11,10 +10,7 @@ public class GpodnetTag implements Parcelable {
private final String tag;
private final int usage;
- public GpodnetTag(String title, String tag, int usage) {
- Validate.notNull(title);
- Validate.notNull(tag);
-
+ public GpodnetTag(@NonNull String title, @NonNull String tag, int usage) {
this.title = title;
this.tag = tag;
this.usage = usage;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/preferences/GpodnetPreferences.java b/core/src/main/java/de/danoeh/antennapod/core/preferences/GpodnetPreferences.java
index 1401d5f39..edd7b807a 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/preferences/GpodnetPreferences.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/preferences/GpodnetPreferences.java
@@ -2,10 +2,9 @@ package de.danoeh.antennapod.core.preferences;
import android.content.Context;
import android.content.SharedPreferences;
+import android.text.TextUtils;
import android.util.Log;
-import org.apache.commons.lang3.StringUtils;
-
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
@@ -293,7 +292,7 @@ public class GpodnetPreferences {
String[] lines = s.split("\n");
List<GpodnetEpisodeAction> result = new ArrayList<GpodnetEpisodeAction>(lines.length);
for(String line : lines) {
- if(StringUtils.isNotBlank(line)) {
+ if(TextUtils.isEmpty(line)) {
GpodnetEpisodeAction action = GpodnetEpisodeAction.readFromString(line);
if(action != null) {
result.add(GpodnetEpisodeAction.readFromString(line));
diff --git a/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java b/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java
index 6de546d3b..d6ac8496b 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java
@@ -7,11 +7,11 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.os.SystemClock;
import android.preference.PreferenceManager;
+import android.support.annotation.NonNull;
import android.support.v4.app.NotificationCompat;
+import android.text.TextUtils;
import android.util.Log;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.Validate;
import org.json.JSONArray;
import org.json.JSONException;
@@ -60,6 +60,7 @@ public class UserPreferences {
public static final String PREF_PAUSE_ON_HEADSET_DISCONNECT = "prefPauseOnHeadsetDisconnect";
public static final String PREF_UNPAUSE_ON_HEADSET_RECONNECT = "prefUnpauseOnHeadsetReconnect";
public static final String PREF_UNPAUSE_ON_BLUETOOTH_RECONNECT = "prefUnpauseOnBluetoothReconnect";
+ public static final String PREF_HARDWARE_FOWARD_BUTTON_SKIPS = "prefHardwareForwardButtonSkips";
public static final String PREF_FOLLOW_QUEUE = "prefFollowQueue";
public static final String PREF_SKIP_KEEPS_EPISODE = "prefSkipKeepsEpisode";
public static final String PREF_AUTO_DELETE = "prefAutoDelete";
@@ -120,9 +121,8 @@ public class UserPreferences {
*
* @throws IllegalArgumentException if context is null
*/
- public static void init(Context context) {
+ public static void init(@NonNull Context context) {
Log.d(TAG, "Creating new instance of UserPreferences");
- Validate.notNull(context);
UserPreferences.context = context.getApplicationContext();
UserPreferences.prefs = PreferenceManager.getDefaultSharedPreferences(context);
@@ -151,7 +151,7 @@ public class UserPreferences {
public static List<String> getHiddenDrawerItems() {
String hiddenItems = prefs.getString(PREF_HIDDEN_DRAWER_ITEMS, "");
- return new ArrayList<String>(Arrays.asList(StringUtils.split(hiddenItems, ',')));
+ return new ArrayList<>(Arrays.asList(TextUtils.split(hiddenItems, ",")));
}
public static int getFeedOrder() {
@@ -225,6 +225,10 @@ public class UserPreferences {
return prefs.getBoolean(PREF_UNPAUSE_ON_BLUETOOTH_RECONNECT, false);
}
+ public static boolean shouldHardwareButtonSkip() {
+ return prefs.getBoolean(PREF_HARDWARE_FOWARD_BUTTON_SKIPS, false);
+ }
+
public static boolean isFollowQueue() {
return prefs.getBoolean(PREF_FOLLOW_QUEUE, true);
@@ -342,7 +346,7 @@ public class UserPreferences {
public static String[] getAutodownloadSelectedNetworks() {
String selectedNetWorks = prefs.getString(PREF_AUTODL_SELECTED_NETWORKS, "");
- return StringUtils.split(selectedNetWorks, ',');
+ return TextUtils.split(selectedNetWorks, ",");
}
public static boolean shouldResumeAfterCall() {
@@ -383,7 +387,7 @@ public class UserPreferences {
public static void setAutodownloadSelectedNetworks(String[] value) {
prefs.edit()
- .putString(PREF_AUTODL_SELECTED_NETWORKS, StringUtils.join(value, ','))
+ .putString(PREF_AUTODL_SELECTED_NETWORKS, TextUtils.join(",", value))
.apply();
}
@@ -417,7 +421,9 @@ public class UserPreferences {
* flattrd. Must be a value between 0 and 1 (inclusive)
* */
public static void setAutoFlattrSettings( boolean enabled, float autoFlattrThreshold) {
- Validate.inclusiveBetween(0.0, 1.0, autoFlattrThreshold);
+ if(autoFlattrThreshold < 0.0 || autoFlattrThreshold > 1.0) {
+ throw new IllegalArgumentException("Flattr threshold must be in range [0.0, 1.0]");
+ }
prefs.edit()
.putBoolean(PREF_AUTO_FLATTR, enabled)
.putFloat(PREF_AUTO_FLATTR_PLAYED_DURATION_THRESHOLD, autoFlattrThreshold)
@@ -425,7 +431,7 @@ public class UserPreferences {
}
public static void setHiddenDrawerItems(List<String> items) {
- String str = StringUtils.join(items, ',');
+ String str = TextUtils.join(",", items);
prefs.edit()
.putString(PREF_HIDDEN_DRAWER_ITEMS, str)
.apply();
@@ -520,7 +526,7 @@ public class UserPreferences {
* @return The data folder that has been requested or null if the folder
* could not be created.
*/
- public static File getDataFolder(Context context, String type) {
+ public static File getDataFolder(String type) {
String strDir = prefs.getString(PREF_DATA_FOLDER, null);
if (strDir == null) {
Log.d(TAG, "Using default data folder");
@@ -542,7 +548,7 @@ public class UserPreferences {
for (int i = 0; i < dirs.length; i++) {
if (dirs.length > 0) {
if (i < dirs.length - 1) {
- dataDir = getDataFolder(context, dirs[i]);
+ dataDir = getDataFolder(dirs[i]);
if (dataDir == null) {
return null;
}
@@ -593,7 +599,7 @@ public class UserPreferences {
* available
*/
private static void createImportDirectory() {
- File importDir = getDataFolder(context, IMPORT_DIR);
+ File importDir = getDataFolder(IMPORT_DIR);
if (importDir != null) {
if (importDir.exists()) {
Log.d(TAG, "Import directory already exists");
diff --git a/core/src/main/java/de/danoeh/antennapod/core/receiver/AlarmUpdateReceiver.java b/core/src/main/java/de/danoeh/antennapod/core/receiver/AlarmUpdateReceiver.java
index 7fa92f30c..ce5004a98 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/receiver/AlarmUpdateReceiver.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/receiver/AlarmUpdateReceiver.java
@@ -3,10 +3,9 @@ package de.danoeh.antennapod.core.receiver;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
+import android.text.TextUtils;
import android.util.Log;
-import org.apache.commons.lang3.StringUtils;
-
import de.danoeh.antennapod.core.preferences.PlaybackPreferences;
import de.danoeh.antennapod.core.preferences.UserPreferences;
@@ -18,9 +17,9 @@ public class AlarmUpdateReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "Received intent");
- if (StringUtils.equals(intent.getAction(), Intent.ACTION_BOOT_COMPLETED)) {
+ if (TextUtils.equals(intent.getAction(), Intent.ACTION_BOOT_COMPLETED)) {
Log.d(TAG, "Resetting update alarm after reboot");
- } else if (StringUtils.equals(intent.getAction(), Intent.ACTION_PACKAGE_REPLACED)) {
+ } else if (TextUtils.equals(intent.getAction(), Intent.ACTION_PACKAGE_REPLACED)) {
Log.d(TAG, "Resetting update alarm after app upgrade");
}
PlaybackPreferences.init(context);
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/AntennapodHttpClient.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/AntennapodHttpClient.java
index 5deb5e501..ed74e0fb6 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/download/AntennapodHttpClient.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/AntennapodHttpClient.java
@@ -5,12 +5,17 @@ import android.support.annotation.NonNull;
import android.util.Log;
import com.squareup.okhttp.OkHttpClient;
+import com.squareup.okhttp.Request;
+import com.squareup.okhttp.Response;
+import com.squareup.okhttp.internal.http.StatusLine;
import java.io.IOException;
import java.net.CookieManager;
import java.net.CookiePolicy;
+import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.Socket;
+import java.net.URL;
import java.security.GeneralSecurityException;
import java.util.concurrent.TimeUnit;
@@ -18,6 +23,8 @@ import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
+import de.danoeh.antennapod.core.storage.DBWriter;
+
/**
* Provides access to a HttpClient singleton.
*/
@@ -58,6 +65,33 @@ public class AntennapodHttpClient {
OkHttpClient client = new OkHttpClient();
+ // detect 301 Moved permanently and 308 Permanent Redirect
+ client.networkInterceptors().add(chain -> {
+ Request request = chain.request();
+ Response response = chain.proceed(request);
+ if(response.code() == HttpURLConnection.HTTP_MOVED_PERM ||
+ response.code() == StatusLine.HTTP_PERM_REDIRECT) {
+ String location = response.header("Location");
+ if(location.startsWith("/")) { // URL is not absolute, but relative
+ URL url = request.url();
+ location = url.getProtocol() + "://" + url.getHost() + location;
+ } else if(!location.startsWith("http://") && !location.startsWith("https://")) {
+ // Reference is relative to current path
+ URL url = request.url();
+ String path = url.getPath();
+ String newPath = path.substring(0, path.lastIndexOf("/") + 1) + location;
+ location = url.getProtocol() + "://" + url.getHost() + newPath;
+ }
+ Log.d(TAG, "New location: " + location);
+ try {
+ DBWriter.updateFeedDownloadURL(request.urlString(), location).get();
+ } catch (Exception e) {
+ Log.e(TAG, Log.getStackTraceString(e));
+ }
+ }
+ return response;
+ });
+
// set cookie handler
CookieManager cm = new CookieManager();
cm.setCookiePolicy(CookiePolicy.ACCEPT_ORIGINAL_SERVER);
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadRequest.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadRequest.java
index 41bbd5ba6..bc3006eea 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadRequest.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadRequest.java
@@ -3,8 +3,7 @@ package de.danoeh.antennapod.core.service.download;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
-
-import org.apache.commons.lang3.Validate;
+import android.support.annotation.NonNull;
import de.danoeh.antennapod.core.feed.FeedFile;
import de.danoeh.antennapod.core.util.URLChecker;
@@ -27,11 +26,15 @@ public class DownloadRequest implements Parcelable {
protected long size;
protected int statusMsg;
- public DownloadRequest(String destination, String source, String title,
- long feedfileId, int feedfileType, String username, String password, boolean deleteOnFailure, Bundle arguments) {
- Validate.notNull(destination);
- Validate.notNull(source);
- Validate.notNull(title);
+ public DownloadRequest(@NonNull String destination,
+ @NonNull String source,
+ @NonNull String title,
+ long feedfileId,
+ int feedfileType,
+ String username,
+ String password,
+ boolean deleteOnFailure,
+ Bundle arguments) {
this.destination = destination;
this.source = source;
@@ -260,7 +263,7 @@ public class DownloadRequest implements Parcelable {
private int feedfileType;
private Bundle arguments;
- public Builder(String destination, FeedFile item) {
+ public Builder(@NonNull String destination, @NonNull FeedFile item) {
this.destination = destination;
this.source = URLChecker.prepareURL(item.getDownload_url());
this.title = item.getHumanReadableIdentifier();
@@ -285,9 +288,6 @@ public class DownloadRequest implements Parcelable {
}
public DownloadRequest build() {
- Validate.notNull(destination);
- Validate.notNull(source);
- Validate.notNull(title);
return new DownloadRequest(this);
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java
index 0698107a7..f7e084e20 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java
@@ -14,14 +14,14 @@ import android.media.MediaMetadataRetriever;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
+import android.support.annotation.NonNull;
import android.support.v4.app.NotificationCompat;
import android.support.v4.util.Pair;
+import android.text.TextUtils;
import android.util.Log;
import android.webkit.URLUtil;
import org.apache.commons.io.FileUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.Validate;
import org.apache.http.HttpStatus;
import org.xml.sax.SAXException;
@@ -53,7 +53,8 @@ import javax.xml.parsers.ParserConfigurationException;
import de.danoeh.antennapod.core.ClientConfig;
import de.danoeh.antennapod.core.R;
-import de.danoeh.antennapod.core.feed.EventDistributor;
+import de.danoeh.antennapod.core.event.DownloadEvent;
+import de.danoeh.antennapod.core.event.FeedItemEvent;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedImage;
import de.danoeh.antennapod.core.feed.FeedItem;
@@ -74,6 +75,7 @@ import de.danoeh.antennapod.core.syndication.handler.UnsupportedFeedtypeExceptio
import de.danoeh.antennapod.core.util.ChapterUtils;
import de.danoeh.antennapod.core.util.DownloadError;
import de.danoeh.antennapod.core.util.InvalidFeedException;
+import de.greenrobot.event.EventBus;
/**
* Manages the download of feedfiles in the app. Downloads can be enqueued viathe startService intent.
@@ -102,12 +104,6 @@ public class DownloadService extends Service {
public static final String EXTRA_DOWNLOAD_URL = "downloadUrl";
/**
- * Sent by the DownloadService when the content of the downloads list
- * changes.
- */
- public static final String ACTION_DOWNLOADS_CONTENT_CHANGED = "action.de.danoeh.antennapod.core.service.downloadsContentChanged";
-
- /**
* Extra for ACTION_ENQUEUE_DOWNLOAD intent.
*/
public static final String EXTRA_REQUEST = "request";
@@ -155,6 +151,8 @@ public class DownloadService extends Service {
private static final int SCHED_EX_POOL_SIZE = 1;
private ScheduledThreadPoolExecutor schedExecutor;
+ private Handler postHandler = new Handler();
+
private final IBinder mBinder = new LocalBinder();
public class LocalBinder extends Binder {
@@ -180,10 +178,7 @@ public class DownloadService extends Service {
final int type = status.getFeedfileType();
if (successful) {
if (type == Feed.FEEDFILETYPE_FEED) {
- handleCompletedFeedDownload(downloader
- .getDownloadRequest());
- } else if (type == FeedImage.FEEDFILETYPE_FEEDIMAGE) {
- handleCompletedImageDownload(status, downloader.getDownloadRequest());
+ handleCompletedFeedDownload(downloader.getDownloadRequest());
} else if (type == FeedMedia.FEEDFILETYPE_FEEDMEDIA) {
handleCompletedFeedMediaDownload(status, downloader.getDownloadRequest());
}
@@ -202,9 +197,22 @@ public class DownloadService extends Service {
Log.e(TAG, "Download failed");
saveDownloadStatus(status);
handleFailedDownload(status, downloader.getDownloadRequest());
+
+ // to make lists reload the failed item, we fake an item update
+ if(type == FeedMedia.FEEDFILETYPE_FEEDMEDIA) {
+ long id = status.getFeedfileId();
+ FeedMedia media = DBReader.getFeedMedia(id);
+ EventBus.getDefault().post(FeedItemEvent.updated(media.getItem()));
+ }
+ }
+ } else {
+ // if FeedMedia download has been canceled, fake FeedItem update
+ // so that lists reload that it
+ if(status.getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA) {
+ FeedMedia media = DBReader.getFeedMedia(status.getFeedfileId());
+ EventBus.getDefault().post(FeedItemEvent.updated(media.getItem()));
}
}
- sendDownloadHandledIntent();
queryDownloadsAsync();
}
} catch (InterruptedException e) {
@@ -306,6 +314,9 @@ public class DownloadService extends Service {
updateReport();
}
+ postHandler.removeCallbacks(postDownloaderTask);
+ EventBus.getDefault().postSticky(DownloadEvent.refresh(Collections.emptyList()));
+
stopForeground(true);
NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
nm.cancel(NOTIFICATION_ID);
@@ -396,9 +407,11 @@ public class DownloadService extends Service {
@Override
public void onReceive(Context context, Intent intent) {
- if (StringUtils.equals(intent.getAction(), ACTION_CANCEL_DOWNLOAD)) {
+ if (TextUtils.equals(intent.getAction(), ACTION_CANCEL_DOWNLOAD)) {
String url = intent.getStringExtra(EXTRA_DOWNLOAD_URL);
- Validate.notNull(url, "ACTION_CANCEL_DOWNLOAD intent needs download url extra");
+ if(url == null) {
+ throw new IllegalArgumentException("ACTION_CANCEL_DOWNLOAD intent needs download url extra");
+ }
Log.d(TAG, "Cancelling download with url " + url);
Downloader d = getDownloader(url);
@@ -407,15 +420,14 @@ public class DownloadService extends Service {
} else {
Log.e(TAG, "Could not cancel download with url " + url);
}
- sendBroadcast(new Intent(ACTION_DOWNLOADS_CONTENT_CHANGED));
+ postDownloaders();
- } else if (StringUtils.equals(intent.getAction(), ACTION_CANCEL_ALL_DOWNLOADS)) {
+ } else if (TextUtils.equals(intent.getAction(), ACTION_CANCEL_ALL_DOWNLOADS)) {
for (Downloader d : downloads) {
d.cancel();
Log.d(TAG, "Cancelled all downloads");
}
- sendBroadcast(new Intent(ACTION_DOWNLOADS_CONTENT_CHANGED));
-
+ postDownloaders();
}
queryDownloads();
}
@@ -434,13 +446,14 @@ public class DownloadService extends Service {
if (downloader != null) {
numberOfDownloads.incrementAndGet();
// smaller rss feeds before bigger media files
- if(request.getFeedfileId() == Feed.FEEDFILETYPE_FEED) {
+ if(request.getFeedfileType() == Feed.FEEDFILETYPE_FEED) {
downloads.add(0, downloader);
} else {
downloads.add(downloader);
}
downloadExecutor.submit(downloader);
- sendBroadcast(new Intent(ACTION_DOWNLOADS_CONTENT_CHANGED));
+
+ postDownloaders();
}
queryDownloads();
@@ -471,7 +484,7 @@ public class DownloadService extends Service {
boolean rc = downloads.remove(d);
Log.d(TAG, "Result of downloads.remove: " + rc);
DownloadRequester.getInstance().removeDownload(d.getDownloadRequest());
- sendBroadcast(new Intent(ACTION_DOWNLOADS_CONTENT_CHANGED));
+ postDownloaders();
}
});
}
@@ -487,10 +500,6 @@ public class DownloadService extends Service {
DBWriter.addDownloadStatus(status);
}
- private void sendDownloadHandledIntent() {
- EventDistributor.getInstance().sendDownloadHandledBroadcast();
- }
-
/**
* Creates a notification at the end of the service lifecycle to notify the
* user about the number of completed downloads. A report will only be
@@ -607,14 +616,6 @@ public class DownloadService extends Service {
}
/**
- * Is called whenever a Feed-Image is downloaded
- */
- private void handleCompletedImageDownload(DownloadStatus status, DownloadRequest request) {
- Log.d(TAG, "Handling completed Image Download");
- syncExecutor.execute(new ImageHandlerThread(status, request));
- }
-
- /**
* Is called whenever a FeedMedia is downloaded.
*/
private void handleCompletedFeedMediaDownload(DownloadStatus status, DownloadRequest request) {
@@ -767,8 +768,6 @@ public class DownloadService extends Service {
numberOfDownloads.decrementAndGet();
}
- sendDownloadHandledIntent();
-
queryDownloadsAsync();
}
});
@@ -912,7 +911,7 @@ public class DownloadService extends Service {
FeedItem item1 = feed.getItems().get(x);
FeedItem item2 = feed.getItems().get(y);
if (item1.hasItemImage() && item2.hasItemImage()) {
- if (StringUtils.equals(item1.getImage().getDownload_url(), item2.getImage().getDownload_url())) {
+ if (TextUtils.equals(item1.getImage().getDownload_url(), item2.getImage().getDownload_url())) {
item2.setImage(null);
}
}
@@ -1013,40 +1012,6 @@ public class DownloadService extends Service {
}
/**
- * Handles a completed image download.
- */
- class ImageHandlerThread implements Runnable {
-
- private DownloadRequest request;
- private DownloadStatus status;
-
- public ImageHandlerThread(DownloadStatus status, DownloadRequest request) {
- Validate.notNull(status);
- Validate.notNull(request);
-
- this.status = status;
- this.request = request;
- }
-
- @Override
- public void run() {
- FeedImage image = DBReader.getFeedImage(request.getFeedfileId());
- if (image == null) {
- throw new IllegalStateException("Could not find downloaded image in database");
- }
-
- image.setFile_url(request.getDestination());
- image.setDownloaded(true);
-
- saveDownloadStatus(status);
- sendDownloadHandledIntent();
- DBWriter.setFeedImage(image);
- numberOfDownloads.decrementAndGet();
- queryDownloadsAsync();
- }
- }
-
- /**
* Handles a completed media download.
*/
class MediaHandlerThread implements Runnable {
@@ -1054,18 +1019,15 @@ public class DownloadService extends Service {
private DownloadRequest request;
private DownloadStatus status;
- public MediaHandlerThread(DownloadStatus status, DownloadRequest request) {
- Validate.notNull(status);
- Validate.notNull(request);
-
+ public MediaHandlerThread(@NonNull DownloadStatus status,
+ @NonNull DownloadRequest request) {
this.status = status;
this.request = request;
}
@Override
public void run() {
- FeedMedia media = DBReader.getFeedMedia(
- request.getFeedfileId());
+ FeedMedia media = DBReader.getFeedMedia(request.getFeedfileId());
if (media == null) {
throw new IllegalStateException(
"Could not find downloaded media object in database");
@@ -1121,7 +1083,6 @@ public class DownloadService extends Service {
}
saveDownloadStatus(status);
- sendDownloadHandledIntent();
if(GpodnetPreferences.loggedIn()) {
FeedItem item = media.getItem();
@@ -1174,16 +1135,24 @@ public class DownloadService extends Service {
}
}
- public List<Downloader> getDownloads() {
- if (downloads == null) {
- // this is unusual, but it should be OK, we'll return
- // an empty list to make it easy for people
- return new ArrayList<Downloader>();
+
+ private long lastPost = 0;
+
+ final Runnable postDownloaderTask = new Runnable() {
+ @Override
+ public void run() {
+ List<Downloader> list = Collections.unmodifiableList(downloads);
+ EventBus.getDefault().postSticky(DownloadEvent.refresh(list));
+ postHandler.postDelayed(postDownloaderTask, 1500);
}
+ };
- // return a copy of downloads, but the copy doesn't need to be synchronized.
- synchronized (downloads) {
- return new ArrayList<Downloader>(downloads);
+ private void postDownloaders() {
+ long now = System.currentTimeMillis();
+ if(now - lastPost >= 250) {
+ postHandler.removeCallbacks(postDownloaderTask);
+ postDownloaderTask.run();
+ lastPost = now;
}
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadStatus.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadStatus.java
index 21928c94f..ed2b00dfe 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadStatus.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadStatus.java
@@ -1,8 +1,7 @@
package de.danoeh.antennapod.core.service.download;
import android.database.Cursor;
-
-import org.apache.commons.lang3.Validate;
+import android.support.annotation.NonNull;
import java.util.Date;
@@ -62,10 +61,8 @@ public class DownloadStatus {
this.feedfileType = feedfileType;
}
- public DownloadStatus(DownloadRequest request, DownloadError reason,
+ public DownloadStatus(@NonNull DownloadRequest request, DownloadError reason,
boolean successful, boolean cancelled, String reasonDetailed) {
- Validate.notNull(request);
-
this.title = request.getTitle();
this.feedfileId = request.getFeedfileId();
this.feedfileType = request.getFeedfileType();
@@ -77,10 +74,8 @@ public class DownloadStatus {
}
/** Constructor for creating new completed downloads. */
- public DownloadStatus(FeedFile feedfile, String title, DownloadError reason,
- boolean successful, String reasonDetailed) {
- Validate.notNull(feedfile);
-
+ public DownloadStatus(@NonNull FeedFile feedfile, String title, DownloadError reason,
+ boolean successful, String reasonDetailed) {
this.title = title;
this.done = true;
this.feedfileId = feedfile.getId();
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/HttpDownloader.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/HttpDownloader.java
index eda857bd5..9f54db477 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/download/HttpDownloader.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/HttpDownloader.java
@@ -1,5 +1,6 @@
package de.danoeh.antennapod.core.service.download;
+import android.text.TextUtils;
import android.util.Log;
import com.squareup.okhttp.OkHttpClient;
@@ -10,7 +11,6 @@ import com.squareup.okhttp.ResponseBody;
import com.squareup.okhttp.internal.http.HttpDate;
import org.apache.commons.io.IOUtils;
-import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpStatus;
import java.io.BufferedInputStream;
@@ -86,7 +86,7 @@ public class HttpDownloader extends Downloader {
String credentials = encodeCredentials(parts[0], parts[1], "ISO-8859-1");
httpReq.header("Authorization", credentials);
}
- } else if (!StringUtils.isEmpty(request.getUsername()) && request.getPassword() != null) {
+ } else if (!TextUtils.isEmpty(request.getUsername()) && request.getPassword() != null) {
String credentials = encodeCredentials(request.getUsername(), request.getPassword(),
"ISO-8859-1");
httpReq.header("Authorization", credentials);
@@ -114,7 +114,10 @@ public class HttpDownloader extends Downloader {
}
responseBody = response.body();
String contentEncodingHeader = response.header("Content-Encoding");
- boolean isGzip = StringUtils.equalsIgnoreCase(contentEncodingHeader, "gzip");
+ boolean isGzip = false;
+ if(!TextUtils.isEmpty(contentEncodingHeader)) {
+ isGzip = TextUtils.equals(contentEncodingHeader.toLowerCase(), "gzip");
+ }
Log.d(TAG, "Response code is " + response.code());
@@ -126,7 +129,7 @@ public class HttpDownloader extends Downloader {
String credentials = encodeCredentials(parts[0], parts[1], "UTF-8");
httpReq.header("Authorization", credentials);
}
- } else if (!StringUtils.isEmpty(request.getUsername()) && request.getPassword() != null) {
+ } else if (!TextUtils.isEmpty(request.getUsername()) && request.getPassword() != null) {
String credentials = encodeCredentials(request.getUsername(), request.getPassword(),
"UTF-8");
httpReq.header("Authorization", credentials);
@@ -134,7 +137,9 @@ public class HttpDownloader extends Downloader {
response = httpClient.newCall(httpReq.build()).execute();
responseBody = response.body();
contentEncodingHeader = response.header("Content-Encoding");
- isGzip = StringUtils.equalsIgnoreCase(contentEncodingHeader, "gzip");
+ if(!TextUtils.isEmpty(contentEncodingHeader)) {
+ isGzip = TextUtils.equals(contentEncodingHeader.toLowerCase(), "gzip");
+ }
}
if(!response.isSuccessful() && response.code() == HttpURLConnection.HTTP_NOT_MODIFIED) {
@@ -167,7 +172,7 @@ public class HttpDownloader extends Downloader {
String contentRangeHeader = (fileExists) ? response.header("Content-Range") : null;
if (fileExists && response.code() == HttpStatus.SC_PARTIAL_CONTENT
- && !StringUtils.isEmpty(contentRangeHeader)) {
+ && !TextUtils.isEmpty(contentRangeHeader)) {
String start = contentRangeHeader.substring("bytes ".length(),
contentRangeHeader.indexOf("-"));
request.setSoFar(Long.valueOf(start));
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java
index 5e0738cb8..1313d9607 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java
@@ -20,6 +20,7 @@ import android.os.IBinder;
import android.os.Vibrator;
import android.preference.PreferenceManager;
import android.support.v4.app.NotificationCompat;
+import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
import android.view.KeyEvent;
@@ -28,8 +29,6 @@ import android.widget.Toast;
import com.bumptech.glide.Glide;
-import org.apache.commons.lang3.StringUtils;
-
import java.util.List;
import java.util.concurrent.ExecutionException;
@@ -1019,7 +1018,7 @@ public class PlaybackService extends Service {
@Override
public void onReceive(Context context, Intent intent) {
- if (StringUtils.equals(intent.getAction(), Intent.ACTION_HEADSET_PLUG)) {
+ if (TextUtils.equals(intent.getAction(), Intent.ACTION_HEADSET_PLUG)) {
int state = intent.getIntExtra("state", -1);
if (state != -1) {
Log.d(TAG, "Headset plug event. State is " + state);
@@ -1041,7 +1040,7 @@ public class PlaybackService extends Service {
@Override
public void onReceive(Context context, Intent intent) {
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
- if (StringUtils.equals(intent.getAction(), BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED)) {
+ if (TextUtils.equals(intent.getAction(), BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED)) {
int state = intent.getIntExtra(BluetoothA2dp.EXTRA_STATE, -1);
if (state == BluetoothA2dp.STATE_CONNECTED) {
Log.d(TAG, "Received bluetooth connection intent");
@@ -1102,7 +1101,7 @@ public class PlaybackService extends Service {
@Override
public void onReceive(Context context, Intent intent) {
- if (StringUtils.equals(intent.getAction(), ACTION_SHUTDOWN_PLAYBACK_SERVICE)) {
+ if (TextUtils.equals(intent.getAction(), ACTION_SHUTDOWN_PLAYBACK_SERVICE)) {
stopSelf();
}
}
@@ -1112,7 +1111,7 @@ public class PlaybackService extends Service {
private final BroadcastReceiver skipCurrentEpisodeReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- if (StringUtils.equals(intent.getAction(), ACTION_SKIP_CURRENT_EPISODE)) {
+ if (TextUtils.equals(intent.getAction(), ACTION_SKIP_CURRENT_EPISODE)) {
Log.d(TAG, "Received SKIP_CURRENT_EPISODE intent");
mediaPlayer.endPlayback(true);
}
@@ -1122,7 +1121,7 @@ public class PlaybackService extends Service {
private final BroadcastReceiver pauseResumeCurrentEpisodeReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- if (StringUtils.equals(intent.getAction(), ACTION_RESUME_PLAY_CURRENT_EPISODE)) {
+ if (TextUtils.equals(intent.getAction(), ACTION_RESUME_PLAY_CURRENT_EPISODE)) {
Log.d(TAG, "Received RESUME_PLAY_CURRENT_EPISODE intent");
mediaPlayer.resume();
}
@@ -1132,7 +1131,7 @@ public class PlaybackService extends Service {
private final BroadcastReceiver pausePlayCurrentEpisodeReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- if (StringUtils.equals(intent.getAction(), ACTION_PAUSE_PLAY_CURRENT_EPISODE)) {
+ if (TextUtils.equals(intent.getAction(), ACTION_PAUSE_PLAY_CURRENT_EPISODE)) {
Log.d(TAG, "Received PAUSE_PLAY_CURRENT_EPISODE intent");
mediaPlayer.pause(false, false);
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java
index df3dbfa69..6ad376bf0 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java
@@ -10,20 +10,20 @@ import android.media.AudioManager;
import android.net.wifi.WifiManager;
import android.os.PowerManager;
import android.preference.PreferenceManager;
+import android.support.annotation.NonNull;
import android.support.v4.media.MediaMetadataCompat;
import android.support.v4.media.session.MediaSessionCompat;
import android.support.v4.media.session.PlaybackStateCompat;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.util.Pair;
+import android.view.InputDevice;
import android.view.KeyEvent;
import android.view.SurfaceHolder;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.target.Target;
-import org.apache.commons.lang3.Validate;
-
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingDeque;
@@ -91,10 +91,8 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre
*/
private WifiManager.WifiLock wifiLock;
- public PlaybackServiceMediaPlayer(Context context, PSMPCallback callback) {
- Validate.notNull(context);
- Validate.notNull(callback);
-
+ public PlaybackServiceMediaPlayer(@NonNull Context context,
+ @NonNull PSMPCallback callback) {
this.context = context;
this.callback = callback;
this.audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
@@ -174,9 +172,7 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre
* for playback immediately (see 'prepareImmediately' parameter for more details)
* @param prepareImmediately Set to true if the method should also prepare the episode for playback.
*/
- public void playMediaObject(final Playable playable, final boolean stream, final boolean startWhenPrepared, final boolean prepareImmediately) {
- Validate.notNull(playable);
-
+ public void playMediaObject(@NonNull final Playable playable, final boolean stream, final boolean startWhenPrepared, final boolean prepareImmediately) {
Log.d(TAG, "playMediaObject(...)");
executor.submit(new Runnable() {
@Override
@@ -202,8 +198,7 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre
*
* @see #playMediaObject(de.danoeh.antennapod.core.util.playback.Playable, boolean, boolean, boolean)
*/
- private void playMediaObject(final Playable playable, final boolean forceReset, final boolean stream, final boolean startWhenPrepared, final boolean prepareImmediately) {
- Validate.notNull(playable);
+ private void playMediaObject(@NonNull final Playable playable, final boolean forceReset, final boolean stream, final boolean startWhenPrepared, final boolean prepareImmediately) {
if (!playerLock.isHeldByCurrentThread()) {
throw new IllegalStateException("method requires playerLock");
}
@@ -572,9 +567,7 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre
/**
* Seek to the start of the specified chapter.
*/
- public void seekToChapter(Chapter c) {
- Validate.notNull(c);
-
+ public void seekToChapter(@NonNull Chapter c) {
seekTo((int) c.getStart());
}
@@ -839,9 +832,7 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre
* @param newStatus The new PlayerStatus. This must not be null.
* @param newMedia The new playable object of the PSMP object. This can be null.
*/
- private synchronized void setPlayerStatus(PlayerStatus newStatus, Playable newMedia) {
- Validate.notNull(newStatus);
-
+ private synchronized void setPlayerStatus(@NonNull PlayerStatus newStatus, Playable newMedia) {
Log.d(TAG, "Setting player status to " + newStatus);
this.playerStatus = newStatus;
@@ -1182,129 +1173,100 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre
private final MediaSessionCompat.Callback sessionCallback = new MediaSessionCompat.Callback() {
- @Override
- public void onPlay() {
- if (playerStatus == PlayerStatus.PAUSED || playerStatus == PlayerStatus.PREPARED) {
- resume();
- } else if (playerStatus == PlayerStatus.INITIALIZED) {
- setStartWhenPrepared(true);
- prepare();
- }
- }
-
- @Override
- public void onPause() {
- super.onPause();
- if (playerStatus == PlayerStatus.PLAYING) {
- pause(false, true);
- }
- if (UserPreferences.isPersistNotify()) {
- pause(false, true);
- } else {
- pause(true, true);
- }
- }
-
- @Override
- public void onSkipToNext() {
- super.onSkipToNext();
- endPlayback(true);
- }
-
- @Override
- public void onFastForward() {
- super.onFastForward();
- seekDelta(UserPreferences.getFastFowardSecs() * 1000);
- }
-
- @Override
- public void onRewind() {
- super.onRewind();
- seekDelta(-UserPreferences.getRewindSecs() * 1000);
- }
-
- @Override
- public void onSeekTo(long pos) {
- super.onSeekTo(pos);
- seekTo((int) pos);
- }
+ private static final String TAG = "MediaSessionCompat";
@Override
public boolean onMediaButtonEvent(final Intent mediaButton) {
- Log.d(TAG, "GOT MediaButton EVENT");
+ Log.d(TAG, "onMediaButtonEvent(" + mediaButton + ")");
if (mediaButton != null) {
KeyEvent keyEvent = (KeyEvent) mediaButton.getExtras().get(Intent.EXTRA_KEY_EVENT);
handleMediaKey(keyEvent);
}
- return super.onMediaButtonEvent(mediaButton);
+ return false;
}
};
- public boolean handleMediaKey(KeyEvent event) {
- if (event != null
- && event.getAction() == KeyEvent.ACTION_DOWN
- && event.getRepeatCount() == 0) {
- switch (event.getKeyCode()) {
- case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
- case KeyEvent.KEYCODE_HEADSETHOOK:
- {
- Log.d(TAG, "Received Play/Pause event from RemoteControlClient");
- if (playerStatus == PlayerStatus.PAUSED || playerStatus == PlayerStatus.PREPARED) {
- resume();
- } else if (playerStatus == PlayerStatus.INITIALIZED) {
- setStartWhenPrepared(true);
- prepare();
- } else if (playerStatus == PlayerStatus.PLAYING) {
- pause(false, true);
- if (UserPreferences.isPersistNotify()) {
- pause(false, true);
- } else {
- pause(true, true);
- }
- }
- return true;
- }
- case KeyEvent.KEYCODE_MEDIA_PLAY:
- {
- Log.d(TAG, "Received Play event from RemoteControlClient");
- if (playerStatus == PlayerStatus.PAUSED || playerStatus == PlayerStatus.PREPARED) {
- resume();
- } else if (playerStatus == PlayerStatus.INITIALIZED) {
- setStartWhenPrepared(true);
- prepare();
- }
- return true;
- }
- case KeyEvent.KEYCODE_MEDIA_PAUSE:
- {
- Log.d(TAG, "Received Pause event from RemoteControlClient");
- if (playerStatus == PlayerStatus.PLAYING) {
- pause(false, true);
- }
+ public boolean handleMediaKey(KeyEvent event) {
+ Log.d(TAG, "handleMediaKey(" + event +")");
+ if (event != null
+ && event.getAction() == KeyEvent.ACTION_DOWN
+ && event.getRepeatCount() == 0) {
+ switch (event.getKeyCode()) {
+ case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
+ case KeyEvent.KEYCODE_HEADSETHOOK: {
+ Log.d(TAG, "Received Play/Pause event from RemoteControlClient");
+ if (playerStatus == PlayerStatus.PAUSED || playerStatus == PlayerStatus.PREPARED) {
+ resume();
+ } else if (playerStatus == PlayerStatus.INITIALIZED) {
+ setStartWhenPrepared(true);
+ prepare();
+ } else if (playerStatus == PlayerStatus.PLAYING) {
+ pause(false, true);
if (UserPreferences.isPersistNotify()) {
pause(false, true);
} else {
pause(true, true);
}
- return true;
}
- case KeyEvent.KEYCODE_MEDIA_STOP:
- {
- Log.d(TAG, "Received Stop event from RemoteControlClient");
- stop();
- return true;
+ return true;
+ }
+ case KeyEvent.KEYCODE_MEDIA_PLAY: {
+ Log.d(TAG, "Received Play event from RemoteControlClient");
+ if (playerStatus == PlayerStatus.PAUSED || playerStatus == PlayerStatus.PREPARED) {
+ resume();
+ } else if (playerStatus == PlayerStatus.INITIALIZED) {
+ setStartWhenPrepared(true);
+ prepare();
+ }
+ return true;
+ }
+ case KeyEvent.KEYCODE_MEDIA_PAUSE: {
+ Log.d(TAG, "Received Pause event from RemoteControlClient");
+ if (playerStatus == PlayerStatus.PLAYING) {
+ pause(false, true);
+ }
+ if (UserPreferences.isPersistNotify()) {
+ pause(false, true);
+ } else {
+ pause(true, true);
}
- case KeyEvent.KEYCODE_MEDIA_NEXT:
- {
- Log.d(TAG, "Received next event from RemoteControlClient");
+ return true;
+ }
+ case KeyEvent.KEYCODE_MEDIA_STOP: {
+ Log.d(TAG, "Received Stop event from RemoteControlClient");
+ stop();
+ return true;
+ }
+ case KeyEvent.KEYCODE_MEDIA_PREVIOUS: {
+ seekDelta(-UserPreferences.getRewindSecs() * 1000);
+ return true;
+ }
+ case KeyEvent.KEYCODE_MEDIA_REWIND: {
+ seekDelta(-UserPreferences.getRewindSecs() * 1000);
+ return true;
+ }
+ case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
+ seekDelta(UserPreferences.getFastFowardSecs() * 1000);
+ return true;
+ }
+ case KeyEvent.KEYCODE_MEDIA_NEXT: {
+ if(event.getSource() == InputDevice.SOURCE_CLASS_NONE ||
+ UserPreferences.shouldHardwareButtonSkip()) {
+ // assume the skip command comes from a notification or the lockscreen
+ // a >| skip button should actually skip
endPlayback(true);
- return true;
+ } else {
+ // assume skip command comes from a (bluetooth) media button
+ // user actually wants to fast-forward
+ seekDelta(UserPreferences.getFastFowardSecs() * 1000);
}
- default:
- Log.d(TAG, "Unhandled key code: " + event.getKeyCode());
- break;
+ return true;
}
+ default:
+ Log.d(TAG, "Unhandled key code: " + event.getKeyCode());
+ break;
}
- return false;
}
+ return false;
+ }
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceTaskManager.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceTaskManager.java
index 961f923e9..4e0c8a109 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceTaskManager.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceTaskManager.java
@@ -2,10 +2,9 @@ package de.danoeh.antennapod.core.service.playback;
import android.content.Context;
import android.os.Vibrator;
+import android.support.annotation.NonNull;
import android.util.Log;
-import org.apache.commons.lang3.Validate;
-
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
@@ -15,8 +14,8 @@ import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
-import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.event.QueueEvent;
+import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.util.playback.Playable;
import de.greenrobot.event.EventBus;
@@ -62,10 +61,8 @@ public class PlaybackServiceTaskManager {
* @param context
* @param callback A PSTMCallback object for notifying the user about updates. Must not be null.
*/
- public PlaybackServiceTaskManager(Context context, PSTMCallback callback) {
- Validate.notNull(context);
- Validate.notNull(callback);
-
+ public PlaybackServiceTaskManager(@NonNull Context context,
+ @NonNull PSTMCallback callback) {
this.context = context;
this.callback = callback;
schedExecutor = new ScheduledThreadPoolExecutor(SCHED_EX_POOL_SIZE, new ThreadFactory() {
@@ -200,7 +197,9 @@ public class PlaybackServiceTaskManager {
* @throws java.lang.IllegalArgumentException if waitingTime <= 0
*/
public synchronized void setSleepTimer(long waitingTime, boolean shakeToReset, boolean vibrate) {
- Validate.isTrue(waitingTime > 0, "Waiting time <= 0");
+ if(waitingTime <= 0) {
+ throw new IllegalArgumentException("Waiting time <= 0");
+ }
Log.d(TAG, "Setting sleep timer to " + Long.toString(waitingTime) + " milliseconds");
if (isSleepTimerActive()) {
@@ -275,9 +274,7 @@ public class PlaybackServiceTaskManager {
* it will be cancelled first.
* On completion, the callback's onChapterLoaded method will be called.
*/
- public synchronized void startChapterLoader(final Playable media) {
- Validate.notNull(media);
-
+ public synchronized void startChapterLoader(@NonNull final Playable media) {
if (isChapterLoaderActive()) {
cancelChapterLoader();
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java
index a422a3b0c..c34515118 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java
@@ -3,13 +3,13 @@ package de.danoeh.antennapod.core.storage;
import android.database.Cursor;
import android.util.Log;
-import org.apache.commons.lang3.StringUtils;
-
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import de.danoeh.antennapod.core.feed.Chapter;
import de.danoeh.antennapod.core.feed.Feed;
@@ -160,7 +160,7 @@ public final class DBReader {
* The method does NOT change the items-attribute of the feed.
*/
public static List<FeedItem> getFeedItemList(final Feed feed) {
- Log.d(TAG, "Extracting Feeditems of feed " + feed.getTitle());
+ Log.d(TAG, "getFeedItemList() called with: " + "feed = [" + feed + "]");
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
@@ -169,11 +169,10 @@ public final class DBReader {
List<FeedItem> items = extractItemlistFromCursor(adapter,
itemlistCursor);
itemlistCursor.close();
+ adapter.close();
Collections.sort(items, new FeedItemPubdateComparator());
- adapter.close();
-
for (FeedItem item : items) {
item.setFeed(feed);
}
@@ -182,6 +181,7 @@ public final class DBReader {
}
public static List<FeedItem> extractItemlistFromCursor(Cursor itemlistCursor) {
+ Log.d(TAG, "extractItemlistFromCursor() called with: " + "itemlistCursor = [" + itemlistCursor + "]");
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
List<FeedItem> result = extractItemlistFromCursor(adapter, itemlistCursor);
@@ -189,53 +189,61 @@ public final class DBReader {
return result;
}
- private static List<FeedItem> extractItemlistFromCursor(
- PodDBAdapter adapter, Cursor itemlistCursor) {
- ArrayList<String> itemIds = new ArrayList<>();
- List<FeedItem> items = new ArrayList<>(itemlistCursor.getCount());
+ private static List<FeedItem> extractItemlistFromCursor(PodDBAdapter adapter,
+ Cursor cursor) {
+ List<FeedItem> result = new ArrayList<>(cursor.getCount());
- if (itemlistCursor.moveToFirst()) {
+ LongList imageIds = new LongList(cursor.getCount());
+ LongList itemIds = new LongList(cursor.getCount());
+ if (cursor.moveToFirst()) {
do {
- int indexImage = itemlistCursor.getColumnIndex(PodDBAdapter.KEY_IMAGE);
- long imageId = itemlistCursor.getLong(indexImage);
- FeedImage image = null;
- if (imageId != 0) {
- image = getFeedImage(adapter, imageId);
- }
+ int indexImage = cursor.getColumnIndex(PodDBAdapter.KEY_IMAGE);
+ long imageId = cursor.getLong(indexImage);
+ imageIds.add(imageId);
- FeedItem item = FeedItem.fromCursor(itemlistCursor);
+ FeedItem item = FeedItem.fromCursor(cursor);
+ result.add(item);
+ itemIds.add(item.getId());
+ } while (cursor.moveToNext());
+ Map<Long,FeedImage> images = getFeedImages(adapter, imageIds.toArray());
+ Map<Long,FeedMedia> medias = getFeedMedia(adapter, itemIds.toArray());
+ for(int i=0; i < result.size(); i++) {
+ FeedItem item = result.get(i);
+ long imageId = imageIds.get(i);
+ FeedImage image = images.get(imageId);
item.setImage(image);
-
- itemIds.add(String.valueOf(item.getId()));
-
- items.add(item);
- } while (itemlistCursor.moveToNext());
+ FeedMedia media = medias.get(item.getId());
+ item.setMedia(media);
+ if(media != null) {
+ media.setItem(item);
+ }
+ }
}
-
- extractMediafromItemlist(adapter, items, itemIds);
- return items;
+ return result;
}
- private static void extractMediafromItemlist(PodDBAdapter adapter,
- List<FeedItem> items, ArrayList<String> itemIds) {
+ private static Map<Long,FeedMedia> getFeedMedia(PodDBAdapter adapter,
+ long... itemIds) {
- List<FeedItem> itemsCopy = new ArrayList<>(items);
- Cursor cursor = adapter.getFeedMediaCursorByItemID(itemIds
- .toArray(new String[itemIds.size()]));
- if (cursor.moveToFirst()) {
- do {
- int index = cursor.getColumnIndex(PodDBAdapter.KEY_FEEDITEM);
- long itemId = cursor.getLong(index);
- // find matching feed item
- FeedItem item = getMatchingItemForMedia(itemId, itemsCopy);
- if (item != null) {
+ String[] ids = new String[itemIds.length];
+ for(int i=0, len=itemIds.length; i < len; i++) {
+ ids[i] = String.valueOf(itemIds[i]);
+ }
+ Map<Long,FeedMedia> result = new HashMap<>(itemIds.length);
+ Cursor cursor = adapter.getFeedMediaCursor(ids);
+ try {
+ if (cursor.moveToFirst()) {
+ do {
+ int index = cursor.getColumnIndex(PodDBAdapter.KEY_FEEDITEM);
+ long itemId = cursor.getLong(index);
FeedMedia media = FeedMedia.fromCursor(cursor);
- item.setMedia(media);
- item.getMedia().setItem(item);
- }
- } while (cursor.moveToNext());
+ result.put(itemId, media);
+ } while (cursor.moveToNext());
+ }
+ } finally {
+ cursor.close();
}
- cursor.close();
+ return result;
}
private static Feed extractFeedFromCursorRow(PodDBAdapter adapter,
@@ -261,16 +269,6 @@ public final class DBReader {
return feed;
}
- private static FeedItem getMatchingItemForMedia(long itemId,
- List<FeedItem> items) {
- for (FeedItem item : items) {
- if (item.getId() == itemId) {
- return item;
- }
- }
- return null;
- }
-
static List<FeedItem> getQueue(PodDBAdapter adapter) {
Log.d(TAG, "getQueue()");
Cursor itemlistCursor = adapter.getQueueCursor();
@@ -288,6 +286,7 @@ public final class DBReader {
* list in a {@link de.danoeh.antennapod.core.util.QueueAccess} object for easier access to the queue's properties.
*/
public static LongList getQueueIDList() {
+ Log.d(TAG, "getQueueIDList() called");
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
LongList result = getQueueIDList(adapter);
@@ -296,7 +295,6 @@ public final class DBReader {
}
static LongList getQueueIDList(PodDBAdapter adapter) {
- adapter.open();
Cursor queueCursor = adapter.getQueueIDCursor();
LongList queueIds = new LongList(queueCursor.getCount());
@@ -317,7 +315,7 @@ public final class DBReader {
* list in a {@link de.danoeh.antennapod.core.util.QueueAccess} object for easier access to the queue's properties.
*/
public static List<FeedItem> getQueue() {
- Log.d(TAG, "getQueue()");
+ Log.d(TAG, "getQueue() called with: " + "");
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
@@ -332,7 +330,7 @@ public final class DBReader {
* @return A list of FeedItems whose episdoe has been downloaded.
*/
public static List<FeedItem> getDownloadedItems() {
- Log.d(TAG, "Extracting downloaded items");
+ Log.d(TAG, "getDownloadedItems() called with: " + "");
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
@@ -342,9 +340,10 @@ public final class DBReader {
itemlistCursor);
itemlistCursor.close();
loadAdditionalFeedItemListData(items);
+ adapter.close();
+
Collections.sort(items, new FeedItemPubdateComparator());
- adapter.close();
return items;
}
@@ -355,7 +354,7 @@ public final class DBReader {
* @return A list of FeedItems whose 'read'-attribute it set to false.
*/
public static List<FeedItem> getUnreadItemsList() {
- Log.d(TAG, "Extracting unread items list");
+ Log.d(TAG, "getUnreadItemsList() called");
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
@@ -376,7 +375,7 @@ public final class DBReader {
* @return A list of FeedItems that are considered new.
*/
public static List<FeedItem> getNewItemsList() {
- Log.d(TAG, "getNewItemsList()");
+ Log.d(TAG, "getNewItemsList() called");
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
@@ -393,7 +392,7 @@ public final class DBReader {
}
public static List<FeedItem> getFavoriteItemsList() {
- Log.d(TAG, "getFavoriteItemsList()");
+ Log.d(TAG, "getFavoriteItemsList() called");
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
@@ -410,7 +409,9 @@ public final class DBReader {
}
static LongList getFavoriteIDList() {
- PodDBAdapter adapter = PodDBAdapter.getInstance().open();
+ Log.d(TAG, "getFavoriteIDList() called");
+ PodDBAdapter adapter = PodDBAdapter.getInstance();
+ adapter.open();
Cursor favoritesCursor = adapter.getFavoritesCursor();
LongList favoriteIDs = new LongList(favoritesCursor.getCount());
@@ -420,6 +421,7 @@ public final class DBReader {
} while (favoritesCursor.moveToNext());
}
favoritesCursor.close();
+ adapter.close();
return favoriteIDs;
}
@@ -429,7 +431,7 @@ public final class DBReader {
* @param limit The maximum number of episodes that should be loaded.
*/
public static List<FeedItem> getRecentlyPublishedEpisodes(int limit) {
- Log.d(TAG, "Extracting recently published items list");
+ Log.d(TAG, "getRecentlyPublishedEpisodes() called with: " + "limit = [" + limit + "]");
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
@@ -453,7 +455,7 @@ public final class DBReader {
* The size of the returned list is limited by {@link #PLAYBACK_HISTORY_SIZE}.
*/
public static List<FeedItem> getPlaybackHistory() {
- Log.d(TAG, "Loading playback history");
+ Log.d(TAG, "getPlaybackHistory() called");
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
@@ -482,7 +484,7 @@ public final class DBReader {
* The size of the returned list is limited by {@link #DOWNLOAD_LOG_SIZE}.
*/
public static List<DownloadStatus> getDownloadLog() {
- Log.d(TAG, "Extracting DownloadLog");
+ Log.d(TAG, "getDownloadLog() called");
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
@@ -496,6 +498,7 @@ public final class DBReader {
} while (logCursor.moveToNext());
}
logCursor.close();
+ adapter.close();
Collections.sort(downloadLog, new DownloadStatusComparator());
return downloadLog;
}
@@ -508,7 +511,7 @@ public final class DBReader {
* newest events first.
*/
public static List<DownloadStatus> getFeedDownloadLog(Feed feed) {
- Log.d(TAG, "getFeedDownloadLog(" + feed.toString() + ")");
+ Log.d(TAG, "getFeedDownloadLog() called with: " + "feed = [" + feed + "]");
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
@@ -522,6 +525,7 @@ public final class DBReader {
} while (cursor.moveToNext());
}
cursor.close();
+ adapter.close();
Collections.sort(downloadLog, new DownloadStatusComparator());
return downloadLog;
}
@@ -534,6 +538,7 @@ public final class DBReader {
* @return A list of FeedItemStatistics objects sorted alphabetically by their Feed's title.
*/
public static List<FeedItemStatistics> getFeedStatisticsList() {
+ Log.d(TAG, "getFeedStatisticsList() called");
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
List<FeedItemStatistics> result = new ArrayList<>();
@@ -558,6 +563,7 @@ public final class DBReader {
* database and the items-attribute will be set correctly.
*/
public static Feed getFeed(final long feedId) {
+ Log.d(TAG, "getFeed() called with: " + "feedId = [" + feedId + "]");
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
Feed result = getFeed(feedId, adapter);
@@ -566,7 +572,6 @@ public final class DBReader {
}
static Feed getFeed(final long feedId, PodDBAdapter adapter) {
- Log.d(TAG, "Loading feed with id " + feedId);
Feed feed = null;
Cursor feedCursor = adapter.getFeedCursor(feedId);
@@ -635,7 +640,7 @@ public final class DBReader {
* as well as chapter marks of the FeedItem will also be loaded from the database.
*/
public static FeedItem getFeedItem(final long itemId) {
- Log.d(TAG, "Loading feeditem with id " + itemId);
+ Log.d(TAG, "getFeedItem() called with: " + "itemId = [" + itemId + "]");
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
@@ -671,8 +676,7 @@ public final class DBReader {
* as well as chapter marks of the FeedItems will also be loaded from the database.
*/
public static List<FeedItem> getFeedItems(final long... itemIds) {
- Log.d(TAG, "Loading feeditem with ids: " + StringUtils.join(itemIds, ","));
-
+ Log.d(TAG, "getFeedItems() called with: " + "itemIds = [" + itemIds + "]");
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
List<FeedItem> items = getFeedItems(adapter, itemIds);
@@ -688,7 +692,7 @@ public final class DBReader {
* @return Credentials in format "<Username>:<Password>", empty String if no authorization given
*/
public static String getImageAuthentication(final String imageUrl) {
- Log.d(TAG, "Loading credentials for image with URL " + imageUrl);
+ Log.d(TAG, "getImageAuthentication() called with: " + "imageUrl = [" + imageUrl + "]");
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
@@ -728,7 +732,7 @@ public final class DBReader {
* as well as chapter marks of the FeedItem will also be loaded from the database.
*/
public static FeedItem getFeedItem(final String podcastUrl, final String episodeUrl) {
- Log.d(TAG, "Loading feeditem with podcast url " + podcastUrl + " and episode url " + episodeUrl);
+ Log.d(TAG, "getFeedItem() called with: " + "podcastUrl = [" + podcastUrl + "], episodeUrl = [" + episodeUrl + "]");
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
@@ -743,6 +747,7 @@ public final class DBReader {
* @param item The FeedItem
*/
public static void loadExtraInformationOfFeedItem(final FeedItem item) {
+ Log.d(TAG, "loadExtraInformationOfFeedItem() called with: " + "item = [" + item + "]");
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
Cursor extraCursor = adapter.getExtraInformationOfItem(item);
@@ -766,6 +771,7 @@ public final class DBReader {
* @param item The FeedItem
*/
public static void loadChaptersOfFeedItem(final FeedItem item) {
+ Log.d(TAG, "loadChaptersOfFeedItem() called with: " + "item = [" + item + "]");
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
loadChaptersOfFeedItem(adapter, item);
@@ -820,6 +826,7 @@ public final class DBReader {
* @return The number of downloaded episodes.
*/
public static int getNumberOfDownloadedEpisodes() {
+ Log.d(TAG, "getNumberOfDownloadedEpisodes() called with: " + "");
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
final int result = adapter.getNumberOfDownloadedEpisodes();
@@ -834,6 +841,7 @@ public final class DBReader {
* @return The found object
*/
public static FeedImage getFeedImage(final long imageId) {
+ Log.d(TAG, "getFeedImage() called with: " + "imageId = [" + imageId + "]");
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
FeedImage result = getFeedImage(adapter, imageId);
@@ -844,21 +852,38 @@ public final class DBReader {
/**
* Searches the DB for a FeedImage of the given id.
*
- * @param id The id of the object
+ * @param imageId The id of the object
* @return The found object
*/
- static FeedImage getFeedImage(PodDBAdapter adapter, final long id) {
- Cursor cursor = adapter.getImageCursor(id);
+ private static FeedImage getFeedImage(PodDBAdapter adapter, final long imageId) {
+ return getFeedImages(adapter, imageId).get(imageId);
+ }
+
+ /**
+ * Searches the DB for a FeedImage of the given id.
+ *
+ * @param imageIds The ids of the images
+ * @return Map that associates the id of an image with the image itself
+ */
+ private static Map<Long,FeedImage> getFeedImages(PodDBAdapter adapter, final long... imageIds) {
+ String[] ids = new String[imageIds.length];
+ for(int i=0, len=imageIds.length; i < len; i++) {
+ ids[i] = String.valueOf(imageIds[i]);
+ }
+ Cursor cursor = adapter.getImageCursor(ids);
+ Map<Long, FeedImage> result = new HashMap<>(cursor.getCount());
try {
if ((cursor.getCount() == 0) || !cursor.moveToFirst()) {
- return null;
+ return Collections.emptyMap();
}
- FeedImage image = FeedImage.fromCursor(cursor);
- image.setId(id);
- return image;
+ do {
+ FeedImage image = FeedImage.fromCursor(cursor);
+ result.put(image.getId(), image);
+ } while(cursor.moveToNext());
} finally {
cursor.close();
}
+ return result;
}
/**
@@ -897,6 +922,7 @@ public final class DBReader {
* @return The flattr queue as a List.
*/
public static List<FlattrThing> getFlattrQueue() {
+ Log.d(TAG, "getFlattrQueue() called with: " + "");
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
List<FlattrThing> result = new ArrayList<>();
@@ -927,6 +953,7 @@ public final class DBReader {
*
*/
public static NavDrawerData getNavDrawerData() {
+ Log.d(TAG, "getNavDrawerData() called with: " + "");
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
List<Feed> feeds = getFeedList(adapter);
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java
index a8aee1961..157e6d28c 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java
@@ -6,7 +6,6 @@ import android.database.Cursor;
import android.util.Log;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
@@ -258,7 +257,7 @@ public final class DBTasks {
*/
public static void refreshFeed(Context context, Feed feed)
throws DownloadRequestException {
- Log.d(TAG, "id " + feed.getId());
+ Log.d(TAG, "refreshFeed(feed.id: " + feed.getId() +")");
refreshFeed(context, feed, false);
}
@@ -431,7 +430,7 @@ public final class DBTasks {
return queue.contains(feedItemId);
}
- private static Feed searchFeedByIdentifyingValueOrID(Context context, PodDBAdapter adapter,
+ private static Feed searchFeedByIdentifyingValueOrID(PodDBAdapter adapter,
Feed feed) {
if (feed.getId() != 0) {
return DBReader.getFeed(feed.getId(), adapter);
@@ -486,7 +485,7 @@ public final class DBTasks {
final Feed newFeed = newFeeds[feedIdx];
// Look up feed in the feedslist
- final Feed savedFeed = searchFeedByIdentifyingValueOrID(context, adapter,
+ final Feed savedFeed = searchFeedByIdentifyingValueOrID(adapter,
newFeed);
if (savedFeed == null) {
Log.d(TAG, "Found no existing Feed with title "
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java
index 14683506e..efc0c882a 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java
@@ -19,12 +19,10 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
-import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
-import de.danoeh.antennapod.core.BuildConfig;
import de.danoeh.antennapod.core.ClientConfig;
import de.danoeh.antennapod.core.asynctask.FlattrClickWorker;
import de.danoeh.antennapod.core.event.FavoritesEvent;
@@ -382,7 +380,7 @@ public class DBWriter {
events.add(QueueEvent.added(item, 0 + i));
} else {
queue.add(item);
- events.add(QueueEvent.added(item, queue.size()-1));
+ events.add(QueueEvent.added(item, queue.size() - 1));
}
queueModified = true;
if (item.isNew()) {
@@ -393,7 +391,7 @@ public class DBWriter {
}
if (queueModified) {
adapter.setQueue(queue);
- for(QueueEvent event : events) {
+ for (QueueEvent event : events) {
EventBus.getDefault().post(event);
}
if (markAsUnplayedIds.size() > 0) {
@@ -766,6 +764,7 @@ public class DBWriter {
adapter.open();
adapter.setSingleFeedItem(item);
adapter.close();
+ EventBus.getDefault().post(FeedItemEvent.updated(item));
});
}
@@ -785,19 +784,14 @@ public class DBWriter {
}
/**
- * Updates download URLs of feeds from a given Map. The key of the Map is the original URL of the feed
- * and the value is the updated URL
+ * Updates download URL of a feed
*/
- public static Future<?> updateFeedDownloadURLs(final Map<String, String> urls) {
+ public static Future<?> updateFeedDownloadURL(final String original, final String updated) {
+ Log.d(TAG, "updateFeedDownloadURL(original: " + original + ", updated: " + updated +")");
return dbExec.submit(() -> {
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
- for (String key : urls.keySet()) {
- if (BuildConfig.DEBUG)
- Log.d(TAG, "Replacing URL " + key + " with url " + urls.get(key));
-
- adapter.setFeedDownloadUrl(key, urls.get(key));
- }
+ adapter.setFeedDownloadUrl(original, updated);
adapter.close();
});
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DownloadRequester.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DownloadRequester.java
index b13f7a0cb..0dc1dadeb 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/DownloadRequester.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DownloadRequester.java
@@ -3,19 +3,18 @@ package de.danoeh.antennapod.core.storage;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.text.TextUtils;
import android.util.Log;
import android.webkit.URLUtil;
import org.apache.commons.io.FilenameUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.Validate;
import java.io.File;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import de.danoeh.antennapod.core.BuildConfig;
-import de.danoeh.antennapod.core.feed.EventDistributor;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedFile;
import de.danoeh.antennapod.core.feed.FeedMedia;
@@ -72,10 +71,8 @@ public class DownloadRequester {
* call will return false.
* @return True if the download request was accepted, false otherwise.
*/
- public synchronized boolean download(Context context, DownloadRequest request) {
- Validate.notNull(context);
- Validate.notNull(request);
-
+ public synchronized boolean download(@NonNull Context context,
+ @NonNull DownloadRequest request) {
if (downloads.containsKey(request.getSource())) {
if (BuildConfig.DEBUG) Log.i(TAG, "DownloadRequest is already stored.");
return false;
@@ -85,7 +82,7 @@ public class DownloadRequester {
Intent launchIntent = new Intent(context, DownloadService.class);
launchIntent.putExtra(DownloadService.EXTRA_REQUEST, request);
context.startService(launchIntent);
- EventDistributor.getInstance().sendDownloadQueuedBroadcast();
+
return true;
}
@@ -146,7 +143,7 @@ public class DownloadRequester {
private boolean isFilenameAvailable(String path) {
for (String key : downloads.keySet()) {
DownloadRequest r = downloads.get(key);
- if (StringUtils.equals(r.getDestination(), path)) {
+ if (TextUtils.equals(r.getDestination(), path)) {
if (BuildConfig.DEBUG)
Log.d(TAG, path
+ " is already used by another requested download");
@@ -335,7 +332,7 @@ public class DownloadRequester {
private File getExternalFilesDirOrThrowException(Context context,
String type) throws DownloadRequestException {
- File result = UserPreferences.getDataFolder(context, type);
+ File result = UserPreferences.getDataFolder(type);
if (result == null) {
throw new DownloadRequestException(
"Failed to access external storage");
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java b/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java
index 6ccb1d226..97d91ccd3 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java
@@ -10,14 +10,12 @@ import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;
import android.media.MediaMetadataRetriever;
+import android.os.Build;
import android.text.TextUtils;
import android.util.Log;
-import org.apache.commons.lang3.Validate;
-
import java.util.Arrays;
import java.util.List;
-import java.util.concurrent.atomic.AtomicInteger;
import de.danoeh.antennapod.core.R;
import de.danoeh.antennapod.core.event.ProgressEvent;
@@ -188,6 +186,15 @@ public class PodDBAdapter {
+ TABLE_NAME_FEED_ITEMS + "_" + KEY_IMAGE + " ON " + TABLE_NAME_FEED_ITEMS + " ("
+ KEY_IMAGE + ")";
+ public static final String CREATE_INDEX_FEEDITEMS_PUBDATE = "CREATE INDEX IF NOT EXISTS "
+ + TABLE_NAME_FEED_ITEMS + "_" + KEY_PUBDATE + " ON " + TABLE_NAME_FEED_ITEMS + " ("
+ + KEY_PUBDATE + ")";
+
+ public static final String CREATE_INDEX_FEEDITEMS_READ = "CREATE INDEX IF NOT EXISTS "
+ + TABLE_NAME_FEED_ITEMS + "_" + KEY_READ + " ON " + TABLE_NAME_FEED_ITEMS + " ("
+ + KEY_READ + ")";
+
+
public static final String CREATE_INDEX_QUEUE_FEEDITEM = "CREATE INDEX "
+ TABLE_NAME_QUEUE + "_" + KEY_FEEDITEM + " ON " + TABLE_NAME_QUEUE + " ("
+ KEY_FEEDITEM + ")";
@@ -254,6 +261,20 @@ public class PodDBAdapter {
};
/**
+ * All the tables in the database
+ */
+ private static final String[] ALL_TABLES = {
+ TABLE_NAME_FEEDS,
+ TABLE_NAME_FEED_ITEMS,
+ TABLE_NAME_FEED_IMAGES,
+ TABLE_NAME_FEED_MEDIA,
+ TABLE_NAME_DOWNLOAD_LOG,
+ TABLE_NAME_QUEUE,
+ TABLE_NAME_SIMPLECHAPTERS,
+ TABLE_NAME_FAVORITES
+ };
+
+ /**
* Contains FEEDITEM_SEL_FI_SMALL as comma-separated list. Useful for raw queries.
*/
private static final String SEL_FI_SMALL_STR;
@@ -270,10 +291,10 @@ public class PodDBAdapter {
KEY_CONTENT_ENCODED, KEY_FEED};
- private SQLiteDatabase db;
+ private static SQLiteDatabase db;
private static Context context;
private static PodDBHelper dbHelper;
- private static AtomicInteger counter = new AtomicInteger(0);
+ private static int counter = 0;
public static void init(Context context) {
PodDBAdapter.context = context.getApplicationContext();
@@ -288,12 +309,15 @@ public class PodDBAdapter {
private PodDBAdapter() {}
- public PodDBAdapter open() {
- counter.incrementAndGet();
+ public synchronized PodDBAdapter open() {
+ counter++;
if (db == null || !db.isOpen() || db.isReadOnly()) {
Log.v(TAG, "Opening DB");
try {
db = dbHelper.getWritableDatabase();
+ if(Build.VERSION.SDK_INT >= 11) {
+ db.enableWriteAheadLogging();
+ }
} catch (SQLException ex) {
Log.e(TAG, Log.getStackTraceString(ex));
db = dbHelper.getReadableDatabase();
@@ -302,24 +326,23 @@ public class PodDBAdapter {
return this;
}
- public void close() {
- if(counter.decrementAndGet() == 0) {
+ public synchronized void close() {
+ counter--;
+ if(counter == 0) {
Log.v(TAG, "Closing DB");
db.close();
+ db = null;
}
- db = null;
}
public static boolean deleteDatabase() {
- if(dbHelper != null) {
- dbHelper.close();
- dbHelper = null;
- }
- if(context != null) { // may not have been initialized
- return context.deleteDatabase(PodDBAdapter.DATABASE_NAME);
- } else {
- return false;
+ PodDBAdapter adapter = getInstance();
+ adapter.open();
+ for (String tableName : ALL_TABLES) {
+ db.delete(tableName, "1", null);
}
+ adapter.close();
+ return true;
}
/**
@@ -990,15 +1013,44 @@ public class PodDBAdapter {
}
/**
- * Returns a cursor for a DB query in the FeedImages table for a given ID.
+ * Returns a cursor for a DB query in the FeedImages table for given IDs.
*
- * @param id ID of the FeedImage
+ * @param imageIds IDs of the images
* @return The cursor of the query
*/
- public final Cursor getImageCursor(final long id) {
- Cursor c = db.query(TABLE_NAME_FEED_IMAGES, null, KEY_ID + "=?",
- new String[]{String.valueOf(id)}, null, null, null);
- return c;
+ public final Cursor getImageCursor(String... imageIds) {
+ int length = imageIds.length;
+ if (length > IN_OPERATOR_MAXIMUM) {
+ Log.w(TAG, "Length of id array is larger than "
+ + IN_OPERATOR_MAXIMUM + ". Creating multiple cursors");
+ int numCursors = (int) (((double) length) / (IN_OPERATOR_MAXIMUM)) + 1;
+ Cursor[] cursors = new Cursor[numCursors];
+ for (int i = 0; i < numCursors; i++) {
+ int neededLength;
+ String[] parts;
+ final int elementsLeft = length - i * IN_OPERATOR_MAXIMUM;
+
+ if (elementsLeft >= IN_OPERATOR_MAXIMUM) {
+ neededLength = IN_OPERATOR_MAXIMUM;
+ parts = Arrays.copyOfRange(imageIds, i
+ * IN_OPERATOR_MAXIMUM, (i + 1)
+ * IN_OPERATOR_MAXIMUM);
+ } else {
+ neededLength = elementsLeft;
+ parts = Arrays.copyOfRange(imageIds, i
+ * IN_OPERATOR_MAXIMUM, (i * IN_OPERATOR_MAXIMUM)
+ + neededLength);
+ }
+
+ cursors[i] = db.rawQuery("SELECT * FROM "
+ + TABLE_NAME_FEED_IMAGES + " WHERE " + KEY_ID + " IN "
+ + buildInOperator(neededLength), parts);
+ }
+ return new MergeCursor(cursors);
+ } else {
+ return db.query(TABLE_NAME_FEED_IMAGES, null, KEY_ID + " IN "
+ + buildInOperator(length), imageIds, null, null, null);
+ }
}
public final Cursor getSimpleChaptersOfFeedItemCursor(final FeedItem item) {
@@ -1126,7 +1178,9 @@ public class PodDBAdapter {
* @throws IllegalArgumentException if limit < 0
*/
public final Cursor getCompletedMediaCursor(int limit) {
- Validate.isTrue(limit >= 0, "Limit must be >= 0");
+ if(limit < 0) {
+ throw new IllegalArgumentException("Limit must be >= 0");
+ }
Cursor c = db.query(TABLE_NAME_FEED_MEDIA, null,
KEY_PLAYBACK_COMPLETION_DATE + " > 0", null, null,
@@ -1138,26 +1192,26 @@ public class PodDBAdapter {
return db.query(TABLE_NAME_FEED_MEDIA, null, KEY_ID + "=?", new String[]{String.valueOf(id)}, null, null, null);
}
- public final Cursor getFeedMediaCursorByItemID(String... mediaIds) {
- int length = mediaIds.length;
+ public final Cursor getFeedMediaCursor(String... itemIds) {
+ int length = itemIds.length;
if (length > IN_OPERATOR_MAXIMUM) {
Log.w(TAG, "Length of id array is larger than "
+ IN_OPERATOR_MAXIMUM + ". Creating multiple cursors");
int numCursors = (int) (((double) length) / (IN_OPERATOR_MAXIMUM)) + 1;
Cursor[] cursors = new Cursor[numCursors];
for (int i = 0; i < numCursors; i++) {
- int neededLength = 0;
- String[] parts = null;
+ int neededLength;
+ String[] parts;
final int elementsLeft = length - i * IN_OPERATOR_MAXIMUM;
if (elementsLeft >= IN_OPERATOR_MAXIMUM) {
neededLength = IN_OPERATOR_MAXIMUM;
- parts = Arrays.copyOfRange(mediaIds, i
+ parts = Arrays.copyOfRange(itemIds, i
* IN_OPERATOR_MAXIMUM, (i + 1)
* IN_OPERATOR_MAXIMUM);
} else {
neededLength = elementsLeft;
- parts = Arrays.copyOfRange(mediaIds, i
+ parts = Arrays.copyOfRange(itemIds, i
* IN_OPERATOR_MAXIMUM, (i * IN_OPERATOR_MAXIMUM)
+ neededLength);
}
@@ -1169,7 +1223,7 @@ public class PodDBAdapter {
return new MergeCursor(cursors);
} else {
return db.query(TABLE_NAME_FEED_MEDIA, null, KEY_FEEDITEM + " IN "
- + buildInOperator(length), mediaIds, null, null, null);
+ + buildInOperator(length), itemIds, null, null, null);
}
}
@@ -1442,7 +1496,7 @@ public class PodDBAdapter {
*/
private static class PodDBHelper extends SQLiteOpenHelper {
- private final static int VERSION = 1040002;
+ private final static int VERSION = 1040013;
private Context context;
@@ -1472,6 +1526,8 @@ public class PodDBAdapter {
db.execSQL(CREATE_INDEX_FEEDITEMS_FEED);
db.execSQL(CREATE_INDEX_FEEDITEMS_IMAGE);
+ db.execSQL(CREATE_INDEX_FEEDITEMS_PUBDATE);
+ db.execSQL(CREATE_INDEX_FEEDITEMS_READ);
db.execSQL(CREATE_INDEX_FEEDMEDIA_FEEDITEM);
db.execSQL(CREATE_INDEX_QUEUE_FEEDITEM);
db.execSQL(CREATE_INDEX_SIMPLECHAPTERS_FEEDITEM);
@@ -1680,6 +1736,11 @@ public class PodDBAdapter {
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_MEDIA
+ " ADD COLUMN " + PodDBAdapter.KEY_LAST_PLAYED_TIME + " INTEGER DEFAULT 0");
}
+ if(oldVersion < 1040013) {
+ db.execSQL(PodDBAdapter.CREATE_INDEX_FEEDITEMS_PUBDATE);
+ db.execSQL(PodDBAdapter.CREATE_INDEX_FEEDITEMS_READ);
+ }
+
EventBus.getDefault().post(ProgressEvent.end());
}
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/LongList.java b/core/src/main/java/de/danoeh/antennapod/core/util/LongList.java
index 10ffd4bec..6ed8b820e 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/LongList.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/LongList.java
@@ -177,6 +177,28 @@ public final class LongList {
}
/**
+ * Removes values from this list.
+ *
+ * @param values values to remove
+ */
+ public void removeAll(long[] values) {
+ for(long value : values) {
+ remove(value);
+ }
+ }
+
+ /**
+ * Removes values from this list.
+ *
+ * @param list List with values to remove
+ */
+ public void removeAll(LongList list) {
+ for(long value : list.values) {
+ remove(value);
+ }
+ }
+
+ /**
* Removes an element at a given index, shifting elements at greater
* indicies down one.
*
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/StorageUtils.java b/core/src/main/java/de/danoeh/antennapod/core/util/StorageUtils.java
index dea380937..248f2bf32 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/StorageUtils.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/StorageUtils.java
@@ -19,7 +19,7 @@ public class StorageUtils {
private static final String TAG = "StorageUtils";
public static boolean storageAvailable(Context context) {
- File dir = UserPreferences.getDataFolder(context, null);
+ File dir = UserPreferences.getDataFolder(null);
if (dir != null) {
return dir.exists() && dir.canRead() && dir.canWrite();
} else {
@@ -52,7 +52,7 @@ public class StorageUtils {
*/
public static long getFreeSpaceAvailable() {
StatFs stat = new StatFs(UserPreferences.getDataFolder(
- ClientConfig.applicationCallbacks.getApplicationInstance(), null).getAbsolutePath());
+ null).getAbsolutePath());
long availableBlocks;
long blockSize;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/URLChecker.java b/core/src/main/java/de/danoeh/antennapod/core/util/URLChecker.java
index 4300556d2..415a1d3a2 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/URLChecker.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/URLChecker.java
@@ -3,8 +3,6 @@ package de.danoeh.antennapod.core.util;
import android.net.Uri;
import android.util.Log;
-import org.apache.commons.lang3.StringUtils;
-
import de.danoeh.antennapod.core.BuildConfig;
/**
@@ -32,19 +30,19 @@ public final class URLChecker {
* @return The prepared url
*/
public static String prepareURL(String url) {
- url = StringUtils.trim(url);
+ url = url.trim();
if (url.startsWith("feed://")) {
if (BuildConfig.DEBUG) Log.d(TAG, "Replacing feed:// with http://");
return url.replaceFirst("feed://", "http://");
} else if (url.startsWith("pcast://")) {
if (BuildConfig.DEBUG) Log.d(TAG, "Removing pcast://");
- return prepareURL(StringUtils.removeStart(url, "pcast://"));
+ return prepareURL(url.substring("pcast://".length()));
} else if (url.startsWith("itpc")) {
if (BuildConfig.DEBUG) Log.d(TAG, "Replacing itpc:// with http://");
return url.replaceFirst("itpc://", "http://");
} else if (url.startsWith(AP_SUBSCRIBE)) {
if (BuildConfig.DEBUG) Log.d(TAG, "Removing antennapod-subscribe://");
- return prepareURL(StringUtils.removeStart(url, AP_SUBSCRIBE));
+ return prepareURL(url.substring(AP_SUBSCRIBE.length()));
} else if (!(url.startsWith("http://") || url.startsWith("https://"))) {
if (BuildConfig.DEBUG) Log.d(TAG, "Adding http:// at the beginning of the URL");
return "http://" + url;
@@ -66,7 +64,7 @@ public final class URLChecker {
if (base == null) {
return prepareURL(url);
}
- url = StringUtils.trim(url);
+ url = url.trim();
base = prepareURL(base);
Uri urlUri = Uri.parse(url);
Uri baseUri = Uri.parse(base);
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/flattr/FlattrUtils.java b/core/src/main/java/de/danoeh/antennapod/core/util/flattr/FlattrUtils.java
index 318839e1d..6ddfb0366 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/flattr/FlattrUtils.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/flattr/FlattrUtils.java
@@ -8,9 +8,9 @@ import android.content.SharedPreferences;
import android.net.Uri;
import android.preference.PreferenceManager;
import android.support.v7.app.AlertDialog;
+import android.text.TextUtils;
import android.util.Log;
-import org.apache.commons.lang3.StringUtils;
import org.shredzone.flattr4j.FlattrService;
import org.shredzone.flattr4j.exception.FlattrException;
import org.shredzone.flattr4j.model.Flattr;
@@ -78,8 +78,8 @@ public class FlattrUtils {
* Returns true if FLATTR_APP_KEY and FLATTR_APP_SECRET in BuildConfig are not null and not empty
*/
public static boolean hasAPICredentials() {
- return StringUtils.isNotEmpty(ClientConfig.flattrCallbacks.getFlattrAppKey())
- && StringUtils.isNotEmpty(ClientConfig.flattrCallbacks.getFlattrAppSecret());
+ return !TextUtils.isEmpty(ClientConfig.flattrCallbacks.getFlattrAppKey())
+ && !TextUtils.isEmpty(ClientConfig.flattrCallbacks.getFlattrAppSecret());
}
public static boolean hasToken() {
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java b/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java
index 4eb955913..a519fb555 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java
@@ -13,6 +13,8 @@ import android.media.MediaPlayer;
import android.os.AsyncTask;
import android.os.IBinder;
import android.preference.PreferenceManager;
+import android.support.annotation.NonNull;
+import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
import android.view.SurfaceHolder;
@@ -22,9 +24,6 @@ import android.widget.ImageButton;
import android.widget.SeekBar;
import android.widget.TextView;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.Validate;
-
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
@@ -74,8 +73,7 @@ public abstract class PlaybackController {
*/
private boolean reinitOnPause;
- public PlaybackController(Activity activity, boolean reinitOnPause) {
- Validate.notNull(activity);
+ public PlaybackController(@NonNull Activity activity, boolean reinitOnPause) {
this.activity = activity;
this.reinitOnPause = reinitOnPause;
@@ -360,7 +358,7 @@ public abstract class PlaybackController {
@Override
public void onReceive(Context context, Intent intent) {
if (isConnectedToPlaybackService()) {
- if (StringUtils.equals(intent.getAction(),
+ if (TextUtils.equals(intent.getAction(),
PlaybackService.ACTION_SHUTDOWN_PLAYBACK_SERVICE)) {
release();
onShutdownNotification();
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/playback/Timeline.java b/core/src/main/java/de/danoeh/antennapod/core/util/playback/Timeline.java
index 0de9863e7..00f2e6f57 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/playback/Timeline.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/playback/Timeline.java
@@ -2,10 +2,10 @@ package de.danoeh.antennapod.core.util.playback;
import android.content.Context;
import android.content.res.TypedArray;
+import android.support.annotation.NonNull;
import android.util.Log;
import android.util.TypedValue;
-import org.apache.commons.lang3.Validate;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
@@ -158,8 +158,7 @@ public class Timeline {
}
- public void setShownotesProvider(ShownotesProvider shownotesProvider) {
- Validate.notNull(shownotesProvider);
+ public void setShownotesProvider(@NonNull ShownotesProvider shownotesProvider) {
this.shownotesProvider = shownotesProvider;
}
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/syndication/FeedDiscoverer.java b/core/src/main/java/de/danoeh/antennapod/core/util/syndication/FeedDiscoverer.java
index 9588265b8..d148419fd 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/syndication/FeedDiscoverer.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/syndication/FeedDiscoverer.java
@@ -1,7 +1,8 @@
package de.danoeh.antennapod.core.util.syndication;
import android.net.Uri;
-import org.apache.commons.lang3.StringUtils;
+import android.text.TextUtils;
+
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
@@ -50,7 +51,7 @@ public class FeedDiscoverer {
for (Element link : links) {
String rel = link.attr("rel");
String href = link.attr("href");
- if (!StringUtils.isEmpty(href) &&
+ if (!TextUtils.isEmpty(href) &&
(rel.equals("alternate") || rel.equals("feed"))) {
String type = link.attr("type");
if (type.equals(MIME_RSS) || type.equals(MIME_ATOM)) {
@@ -58,7 +59,7 @@ public class FeedDiscoverer {
String processedUrl = processURL(baseUrl, href);
if (processedUrl != null) {
res.put(processedUrl,
- (StringUtils.isEmpty(title)) ? href : title);
+ (TextUtils.isEmpty(title)) ? href : title);
}
}
}
diff --git a/core/src/main/res/drawable-hdpi/ic_widget_preview.png b/core/src/main/res/drawable-hdpi/ic_widget_preview.png
new file mode 100644
index 000000000..8b583b285
--- /dev/null
+++ b/core/src/main/res/drawable-hdpi/ic_widget_preview.png
Binary files differ
diff --git a/core/src/main/res/values-az/strings.xml b/core/src/main/res/values-az/strings.xml
index a88776ea3..a2fbdd825 100644
--- a/core/src/main/res/values-az/strings.xml
+++ b/core/src/main/res/values-az/strings.xml
@@ -207,4 +207,5 @@
<!--Feed information screen-->
<!--Progress information-->
<!--AntennaPodSP-->
+ <!--Rating dialog-->
</resources>
diff --git a/core/src/main/res/values-ca/strings.xml b/core/src/main/res/values-ca/strings.xml
index 6dbc4d68f..772742753 100644
--- a/core/src/main/res/values-ca/strings.xml
+++ b/core/src/main/res/values-ca/strings.xml
@@ -497,4 +497,5 @@
<string name="sort_date_old_new">Data (Antic \u2192 Nou)</string>
<string name="sort_duration_short_long">Duració (Curt \u2192 Llarg)</string>
<string name="sort_duration_long_short">Duration (Llarg \u2192 Curt)</string>
+ <!--Rating dialog-->
</resources>
diff --git a/core/src/main/res/values-cs-rCZ/strings.xml b/core/src/main/res/values-cs-rCZ/strings.xml
index 143ecd1ef..e220432b9 100644
--- a/core/src/main/res/values-cs-rCZ/strings.xml
+++ b/core/src/main/res/values-cs-rCZ/strings.xml
@@ -22,6 +22,7 @@
<string name="playback_history_label">Historie přehrávání</string>
<string name="gpodnet_main_label">gpodder.net</string>
<string name="gpodnet_auth_label">Login pro gpodder.net</string>
+ <string name="free_space_label">%1$s volných</string>
<!--New episodes fragment-->
<string name="recently_published_episodes_label">Nedávno zveřejněné</string>
<string name="episode_filter_label">Zobrazit pouze nové epizody</string>
@@ -262,6 +263,8 @@
<string name="pref_pauseOnDisconnect_sum">Při odpojení sluchátek nebo bluetooth připojení pozastavit přehrávání.</string>
<string name="pref_unpauseOnHeadsetReconnect_sum">Pokračovat v přehrávání po připojení sluchátek</string>
<string name="pref_unpauseOnBluetoothReconnect_sum">Pokračovat v přehrávání po připojení bluetooth</string>
+ <string name="pref_hardwareForwardButtonSkips_title">Přeskočit tlačítkem vpřed</string>
+ <string name="pref_hardwareForwardButtonSkips_sum">Po stlačení hardwarového tlačítka pro posun vpřed přeskočit na další skladbu</string>
<string name="pref_followQueue_sum">Po přehrání položky z fronty přejít automaticky na další</string>
<string name="pref_auto_delete_sum">Smazat díl po jeho přehrání</string>
<string name="pref_auto_delete_title">Automatické mazání</string>
@@ -346,6 +349,9 @@
<string name="pref_smart_mark_as_played_disabled">Vypnuto</string>
<string name="pref_image_cache_size_title">Velikost odkládací paměti obrázků</string>
<string name="pref_image_cache_size_sum">Velikost diskové paměti pro obrázky.</string>
+ <string name="crash_report_title">Hlášení pádů</string>
+ <string name="crash_report_sum">Odesílat hlášení o posledním pádu aplikace emailem</string>
+ <string name="send_email">Poslat email</string>
<string name="experimental_pref">Experimentální</string>
<string name="pref_sonic_title">Přehrávač médií Sonic</string>
<string name="pref_sonic_message">Použít vestavěný přehrávač médií Sonic, jako náhradu za Prestissimo</string>
@@ -443,11 +449,15 @@
<string name="selected_folder_label">Vybraný adresář:</string>
<string name="create_folder_label">Vytvořit adresář</string>
<string name="choose_data_directory">Vybrat umístění dat</string>
+ <string name="choose_data_directory_message">Vyberte prosím váš výchozí datový adresář. AntennaPod vytvoří všechny potřebné podadresáře.</string>
<string name="create_folder_msg">Vytvořit adresář \"%1$s\"?</string>
<string name="create_folder_success">Nový adresář vytvořen</string>
<string name="create_folder_error_no_write_access">Nelze zapisovat do adresáře</string>
<string name="create_folder_error_already_exists">Adresář již existuje</string>
<string name="create_folder_error">Nelze vytvořit adresář</string>
+ <string name="folder_does_not_exist_error">\"%1$s\" neexistuje</string>
+ <string name="folder_not_readable_error">\"%1$s\" nelze číst</string>
+ <string name="folder_not_writable_error">\"%1$s\" nelze zapisovat</string>
<string name="folder_not_empty_dialog_title">Adresář není prázdný</string>
<string name="folder_not_empty_dialog_msg">Vybraný adresář není prázdný. Stažená media a ostatní soubory budou umístěny přímo do tohoto adresáře. Přesto pokračovat?</string>
<string name="set_to_default_folder">Vybrat hlavní adresář</string>
@@ -507,4 +517,10 @@
<string name="sort_date_old_new">Data (Staré \u2192 Nové)</string>
<string name="sort_duration_short_long">Délka (Krátké \u2192 Dlouhé)</string>
<string name="sort_duration_long_short">Délka (Dlouhé \u2192 Krátké)</string>
+ <!--Rating dialog-->
+ <string name="rating_title">Líbí se vám AntennaPod?</string>
+ <string name="rating_message">Oceníme, pokud věnujete chvíli času ohodnocení AntennaPod.</string>
+ <string name="rating_never_label">Neobtěžuj mě</string>
+ <string name="rating_later_label">Upozornit později</string>
+ <string name="rating_now_label">Jasně, s radostí!</string>
</resources>
diff --git a/core/src/main/res/values-da/strings.xml b/core/src/main/res/values-da/strings.xml
index a43b6661b..2c32ad5de 100644
--- a/core/src/main/res/values-da/strings.xml
+++ b/core/src/main/res/values-da/strings.xml
@@ -346,4 +346,5 @@
<!--Progress information-->
<!--AntennaPodSP-->
<string name="sp_apps_importing_feeds_msg">Importerer abonnementer fra single-purpose apps…</string>
+ <!--Rating dialog-->
</resources>
diff --git a/core/src/main/res/values-de/strings.xml b/core/src/main/res/values-de/strings.xml
index fbe8dec53..7cdd15146 100644
--- a/core/src/main/res/values-de/strings.xml
+++ b/core/src/main/res/values-de/strings.xml
@@ -22,6 +22,7 @@
<string name="playback_history_label">Zuletzt gespielt</string>
<string name="gpodnet_main_label">gpodder.net</string>
<string name="gpodnet_auth_label">gpodder.net Anmeldung</string>
+ <string name="free_space_label">%1$s frei</string>
<!--New episodes fragment-->
<string name="recently_published_episodes_label">Zuletzt veröffentlicht</string>
<string name="episode_filter_label">Nur neue Episoden anzeigen</string>
@@ -260,6 +261,8 @@
<string name="pref_pauseOnDisconnect_sum">Wiedergabe pausieren, wenn Kopfhörer ausgesteckt oder Bluetooth getrennt wird</string>
<string name="pref_unpauseOnHeadsetReconnect_sum">Wiedergabe fortsetzen, wenn Kopfhörer wieder eingesteckt werden</string>
<string name="pref_unpauseOnBluetoothReconnect_sum">Wiedergabe fortsetzen, wenn Bluetooth wieder verbunden ist</string>
+ <string name="pref_hardwareForwardButtonSkips_title">Nächster-Taste überspringt</string>
+ <string name="pref_hardwareForwardButtonSkips_sum">Springe zur nächsten Episode (statt Vorspulen), wenn die \"Nächster\"-Taste gedrückt wird</string>
<string name="pref_followQueue_sum">Springe zur nächsten Episode, wenn die vorherige Episode endet</string>
<string name="pref_auto_delete_sum">Episode löschen, wenn die Wiedergabe endet</string>
<string name="pref_auto_delete_title">Automatisches Löschen</string>
@@ -344,6 +347,9 @@
<string name="pref_smart_mark_as_played_disabled">Deaktiviert</string>
<string name="pref_image_cache_size_title">Größe des Bilder-Zwischenspeichers</string>
<string name="pref_image_cache_size_sum">Größe des Zwischenspeichers für Bilder</string>
+ <string name="crash_report_title">Absturzbericht</string>
+ <string name="crash_report_sum">Sende den aktuellen Absturzbericht per E-Mail</string>
+ <string name="send_email">E-Mail senden</string>
<string name="experimental_pref">Experimentell</string>
<string name="pref_sonic_title">Sonic Media Player</string>
<string name="pref_sonic_message">Benutze den eingebauten Sonic Media Player als Ersatz für Prestissimo</string>
@@ -364,7 +370,7 @@
<string name="opml_import_option">Option %1$d</string>
<string name="opml_import_explanation_1">Wähle einen bestimmten Dateipfad aus dem lokalen Dateisystem.</string>
<string name="opml_import_explanation_2">Verwende externe Anwendungen wie Dropbox, Google Drive oder deinen Lieblingsdateimanager, um eine OPML-Datei zu öffnen.</string>
- <string name="opml_import_explanation_3">Viele Anwendungen wie Google Mail, Dropbox, Google Drive und die meisten Dateimanager können OPML-Dateien &lt;i&gt;mit&lt;/ i&gt; AntennaPod &lt;i&gt;öffnen&lt;/i&gt;.</string>
+ <string name="opml_import_explanation_3">Viele Anwendungen wie Google Mail, Dropbox, Google Drive und die meisten Dateimanager können OPML-Dateien <i>mit</i> AntennaPod <i>öffnen</i>.</string>
<string name="start_import_label">Import starten</string>
<string name="opml_import_label">OPML Import</string>
<string name="opml_directory_error">FEHLER!</string>
@@ -438,11 +444,15 @@
<string name="selected_folder_label">Ausgewählter Ordner</string>
<string name="create_folder_label">Neuer Ordner</string>
<string name="choose_data_directory">Datenordner auswählen</string>
+ <string name="choose_data_directory_message">Bitte wähle eine Basis für deinen Datenordner. AntennaPod erstellt automatisch die richtigen Unterverzeichnisse.</string>
<string name="create_folder_msg">Neuen Ordner mit Namen \"%1$s\" erstellen?</string>
<string name="create_folder_success">Neuer Ordner angelegt</string>
<string name="create_folder_error_no_write_access">Kann in diesem Ordner nicht schreiben</string>
<string name="create_folder_error_already_exists">Ordner existiert bereits</string>
<string name="create_folder_error">Konnte Datenordner nicht erstellen</string>
+ <string name="folder_does_not_exist_error">\"%1$s\" existiert nicht</string>
+ <string name="folder_not_readable_error">\"%1$s\" ist nicht lesbar</string>
+ <string name="folder_not_writable_error">\"%1$s\" ist nicht beschreibbar</string>
<string name="folder_not_empty_dialog_title">Ordner ist nicht leer</string>
<string name="folder_not_empty_dialog_msg">Der ausgewählte Ordner ist nicht leer. Medien-Downloads und andere Daten werden direkt in diesem Ordner gespeichert. Trotzdem fortfahren?</string>
<string name="set_to_default_folder">Standardordner auswählen</string>
@@ -502,4 +512,10 @@
<string name="sort_date_old_new">Datum (alt \u2192 neu)</string>
<string name="sort_duration_short_long">Dauer (kurz \u2192 lang)</string>
<string name="sort_duration_long_short">Dauer (lang \u2192 kurz)</string>
+ <!--Rating dialog-->
+ <string name="rating_title">Magst du AntennaPod?</string>
+ <string name="rating_message">Wir würden uns freuen, wenn du dir kurz die Zeit nimmst, AntennaPod zu bewerten.</string>
+ <string name="rating_never_label">Lass mich in Ruhe</string>
+ <string name="rating_later_label">Erinnere mich später</string>
+ <string name="rating_now_label">Sicher, los geht\'s!</string>
</resources>
diff --git a/core/src/main/res/values-es-rES/strings.xml b/core/src/main/res/values-es-rES/strings.xml
index 2757d7eac..3cff046d0 100644
--- a/core/src/main/res/values-es-rES/strings.xml
+++ b/core/src/main/res/values-es-rES/strings.xml
@@ -190,4 +190,5 @@
<!--Feed information screen-->
<!--Progress information-->
<!--AntennaPodSP-->
+ <!--Rating dialog-->
</resources>
diff --git a/core/src/main/res/values-es/strings.xml b/core/src/main/res/values-es/strings.xml
index e8a885817..0bed13e34 100644
--- a/core/src/main/res/values-es/strings.xml
+++ b/core/src/main/res/values-es/strings.xml
@@ -502,4 +502,5 @@
<string name="sort_date_old_new">Fecha (Antiguo \u2192 Nuevo)</string>
<string name="sort_duration_short_long">Duración (Corto \u2192 Largo)</string>
<string name="sort_duration_long_short">Duración (Largo \u2192 Corto)</string>
+ <!--Rating dialog-->
</resources>
diff --git a/core/src/main/res/values-fr/strings.xml b/core/src/main/res/values-fr/strings.xml
index 5aa1b3697..bd3d1406f 100644
--- a/core/src/main/res/values-fr/strings.xml
+++ b/core/src/main/res/values-fr/strings.xml
@@ -22,6 +22,7 @@
<string name="playback_history_label">Journal des lectures</string>
<string name="gpodnet_main_label">gpodder.net</string>
<string name="gpodnet_auth_label">Identifiants gpodder.net</string>
+ <string name="free_space_label">\"%1$s libre</string>
<!--New episodes fragment-->
<string name="recently_published_episodes_label">Publié récemment</string>
<string name="episode_filter_label">N\'afficher que les nouveaux épisodes</string>
@@ -183,7 +184,7 @@
<string name="authentication_notification_msg">La ressource que vous avez demandé nécessite un nom d\'utilisateur et un mot de passe</string>
<string name="confirm_mobile_download_dialog_title">Confirmer le téléchargement mobile</string>
<string name="confirm_mobile_download_dialog_message_not_in_queue">Le téléchargement sur la connexion mobile est désactivé dans les options.\n\nVous pouvez choisir d\'ajouter seulement l\'épisode à la liste ou vous pouvez autoriser temporairement le téléchargement.\n\n<small>Votre choix sera retenu pour les 10 prochaines minutes.</small></string>
- <string name="confirm_mobile_download_dialog_message">Le téléchargement sur la connexion mobile est désactivé dans les options.\n\nVoulez-vous autoriser temporairement le téléchargement?\n\n&lt;small&gt;Votre choix sera retenu pour les 10 prochaines minutes.&lt;small&gt;</string>
+ <string name="confirm_mobile_download_dialog_message">Le téléchargement sur la connexion mobile est désactivé dans les options.\n\nVoulez-vous autoriser temporairement le téléchargement?\n\n<small>Votre choix sera retenu pour les 10 prochaines minutes.</small></string>
<string name="confirm_mobile_download_dialog_only_add_to_queue">Rajouter à la liste</string>
<string name="confirm_mobile_download_dialog_enable_temporarily">Autoriser temporairement</string>
<!--Mediaplayer messages-->
@@ -259,7 +260,9 @@
<string name="pref_episode_cleanup_summary">Les épisodes qui ne sont ni dans la liste ni dans les favoris peuvent être supprimés si l\'espace disque devient faible</string>
<string name="pref_pauseOnDisconnect_sum">Interrompre la lecture lorsque le casque ou le bluetooth sont déconnectés</string>
<string name="pref_unpauseOnHeadsetReconnect_sum">Reprendre la lecture quand les écouteurs sont reconnectés</string>
- <string name="pref_unpauseOnBluetoothReconnect_sum">Reprendre la lecture quand le bluetooth se connecte</string>
+ <string name="pref_unpauseOnBluetoothReconnect_sum">Reprendre la lecture quand le bluetooth se reconnecte</string>
+ <string name="pref_hardwareForwardButtonSkips_title">Le bouton piste suivante saute l\'épisode</string>
+ <string name="pref_hardwareForwardButtonSkips_sum">Au lieu de faire un saut avant passer à l\'épisode suivant quand un bouton physique pour passer à la piste suivante est pressé</string>
<string name="pref_followQueue_sum">Après la fin d\'un épisode, passer au suivant</string>
<string name="pref_auto_delete_sum">Supprimer l\'épisode quand la lecture est finie</string>
<string name="pref_auto_delete_title">Suppression automatique</string>
@@ -344,6 +347,9 @@
<string name="pref_smart_mark_as_played_disabled">Désactivé</string>
<string name="pref_image_cache_size_title">Taille du cache de l\'image</string>
<string name="pref_image_cache_size_sum">Taille de l’espace de stockage temporaire des images.</string>
+ <string name="crash_report_title">Rapport de crash</string>
+ <string name="crash_report_sum">Envoyer le dernier rapport de crash par e-mail</string>
+ <string name="send_email">Envoyer e-mail</string>
<string name="experimental_pref">Expérimental</string>
<string name="pref_sonic_title">Lecteur multimédia Sonic</string>
<string name="pref_sonic_message">Utiliser le lecteur multimédia interne Sonic au lieu de Prestissimo</string>
@@ -438,11 +444,15 @@
<string name="selected_folder_label">Répertoire choisi :</string>
<string name="create_folder_label">Créer répertoire</string>
<string name="choose_data_directory">Choisir le répertoire</string>
+ <string name="choose_data_directory_message">Choisissez le répertoire où enregistrer les données. AntennaPod créera automatiquement les sous-répertoires nécessaires.</string>
<string name="create_folder_msg">Créer un répertoire nommé \"%1$s\" ?</string>
<string name="create_folder_success">Répertoire créé</string>
<string name="create_folder_error_no_write_access">Impossible d\'écrire dans ce répertoire</string>
<string name="create_folder_error_already_exists">Le répertoire existe déjà</string>
<string name="create_folder_error">Impossible de créer le répertoire</string>
+ <string name="folder_does_not_exist_error">\"%1$s\" n\'existe pas</string>
+ <string name="folder_not_readable_error">\"%1$s\" n\'est pas lisible</string>
+ <string name="folder_not_writable_error">\"%1$s\" est en lecture seul</string>
<string name="folder_not_empty_dialog_title">Le répertoire n\'est pas vide</string>
<string name="folder_not_empty_dialog_msg">Le répertoire que vous avez choisi n\'est pas vide. Les fichiers téléchargés seront ajoutés à ce répertoire. Continuer malgré tout ?</string>
<string name="set_to_default_folder">Choisir le répertoire par défaut</string>
@@ -502,4 +512,10 @@
<string name="sort_date_old_new">Date (Ancien \u2192 Nouveau)</string>
<string name="sort_duration_short_long">Durée (Courte \u2192 Longue)</string>
<string name="sort_duration_long_short">Durée (Longue \u2192 Courte)</string>
+ <!--Rating dialog-->
+ <string name="rating_title">Vous aimez AntennaPod ?</string>
+ <string name="rating_message">Nous vous serions reconnaissant de prendre un peu de temps pour noter AntennaPod.</string>
+ <string name="rating_never_label">Laissez moi tranquille</string>
+ <string name="rating_later_label">Rappelez le moi plus tard</string>
+ <string name="rating_now_label">Okay, faisons ça !</string>
</resources>
diff --git a/core/src/main/res/values-hi-rIN/strings.xml b/core/src/main/res/values-hi-rIN/strings.xml
index 1ac70679a..9fa3d716f 100644
--- a/core/src/main/res/values-hi-rIN/strings.xml
+++ b/core/src/main/res/values-hi-rIN/strings.xml
@@ -271,4 +271,5 @@
<!--Feed information screen-->
<!--Progress information-->
<!--AntennaPodSP-->
+ <!--Rating dialog-->
</resources>
diff --git a/core/src/main/res/values-it-rIT/strings.xml b/core/src/main/res/values-it-rIT/strings.xml
index 4e052037c..adf4bd748 100644
--- a/core/src/main/res/values-it-rIT/strings.xml
+++ b/core/src/main/res/values-it-rIT/strings.xml
@@ -435,4 +435,5 @@
<string name="sort_date_old_new">Data (Old \u2192 New)</string>
<string name="sort_duration_short_long">Durata (Short \u2192 Long)</string>
<string name="sort_duration_long_short">Durata (Long \u2192 Short)</string>
+ <!--Rating dialog-->
</resources>
diff --git a/core/src/main/res/values-iw-rIL/strings.xml b/core/src/main/res/values-iw-rIL/strings.xml
index a84de71d4..52a6a170a 100644
--- a/core/src/main/res/values-iw-rIL/strings.xml
+++ b/core/src/main/res/values-iw-rIL/strings.xml
@@ -372,4 +372,5 @@
<!--AntennaPodSP-->
<string name="sp_apps_importing_feeds_msg">מייבא רישום מאפליקציות יעודיות...</string>
<string name="search_itunes_label">חפש בiTunes</string>
+ <!--Rating dialog-->
</resources>
diff --git a/core/src/main/res/values-ja/strings.xml b/core/src/main/res/values-ja/strings.xml
index 46556cabe..f58e90597 100644
--- a/core/src/main/res/values-ja/strings.xml
+++ b/core/src/main/res/values-ja/strings.xml
@@ -498,4 +498,5 @@
<string name="sort_date_old_new">日付 (旧 \u2192 新)</string>
<string name="sort_duration_short_long">期間 (短 \u2192 長)</string>
<string name="sort_duration_long_short">期間 (長 \u2192 短)</string>
+ <!--Rating dialog-->
</resources>
diff --git a/core/src/main/res/values-ko/strings.xml b/core/src/main/res/values-ko/strings.xml
index 606c849fc..250bd445d 100644
--- a/core/src/main/res/values-ko/strings.xml
+++ b/core/src/main/res/values-ko/strings.xml
@@ -465,4 +465,5 @@
<string name="sort_date_old_new">시각 (과거 \u2192 최근)</string>
<string name="sort_duration_short_long">길이 (짧은 \u2192 긴)</string>
<string name="sort_duration_long_short">길이 (긴 \u2192 짧은)</string>
+ <!--Rating dialog-->
</resources>
diff --git a/core/src/main/res/values-nb/strings.xml b/core/src/main/res/values-nb/strings.xml
index 59c04afb0..435d0cc7c 100644
--- a/core/src/main/res/values-nb/strings.xml
+++ b/core/src/main/res/values-nb/strings.xml
@@ -499,4 +499,5 @@
<string name="sort_date_old_new">Dato (Gammel \u2192 Ny)</string>
<string name="sort_duration_short_long">Lengde (Kort \u2192 Lang)</string>
<string name="sort_duration_long_short">Lengde (Lang \u2192 Kort)</string>
+ <!--Rating dialog-->
</resources>
diff --git a/core/src/main/res/values-nl/strings.xml b/core/src/main/res/values-nl/strings.xml
index b2da5ac89..b8b3d7c51 100644
--- a/core/src/main/res/values-nl/strings.xml
+++ b/core/src/main/res/values-nl/strings.xml
@@ -22,6 +22,7 @@
<string name="playback_history_label">Afspeelgeschiedenis</string>
<string name="gpodnet_main_label">gpodder.net</string>
<string name="gpodnet_auth_label">gpodder.net login</string>
+ <string name="free_space_label">%1$s beschikbaar</string>
<!--New episodes fragment-->
<string name="recently_published_episodes_label">Recent gepubliceerd</string>
<string name="episode_filter_label">Alleen nieuwe afleveringen weergeven</string>
@@ -257,7 +258,9 @@
<string name="flattr_label">Flattr</string>
<string name="pref_episode_cleanup_title">Automatisch opschonen</string>
<string name="pref_episode_cleanup_summary">Afleveringen die niet in de wachtrij staan en niet zijn gemarkeerd zijn als favoriet, komen in aanmerking voor verwijdering bij automatisch opschonen.</string>
+ <string name="pref_pauseOnDisconnect_sum">Afspelen pauzeren wanneer de koptelefoon wordt losgekoppeld of de bluetooth verbinding wordt verbroken</string>
<string name="pref_unpauseOnHeadsetReconnect_sum">Afspelen hervatten wanneer de koptelefoon opnieuw wordt aangesloten</string>
+ <string name="pref_unpauseOnBluetoothReconnect_sum">Afspelen hervatten wanneer de bluetooth verbinding hervat wordt</string>
<string name="pref_followQueue_sum">Volgende item in de wachtrij afspelen als de aflevering voltooid is</string>
<string name="pref_auto_delete_sum">Afleveringen verwijderen als ze zijn afgespeeld</string>
<string name="pref_auto_delete_title">Automatisch verwijderen</string>
@@ -278,6 +281,7 @@
<string name="pref_downloadMediaOnWifiOnly_title">WiFi download van media</string>
<string name="pref_pauseOnHeadsetDisconnect_title">Loskoppeling koptelefoon</string>
<string name="pref_unpauseOnHeadsetReconnect_title">Aansluiten koptelefoon</string>
+ <string name="pref_unpauseOnBluetoothReconnect_title">Verbinden met bluetooth</string>
<string name="pref_mobileUpdate_title">Mobiele updates</string>
<string name="pref_mobileUpdate_sum">Updates toestaan ​​via de mobiele dataverbinding</string>
<string name="refreshing_label">Aan het verversen</string>
@@ -341,6 +345,7 @@
<string name="pref_smart_mark_as_played_disabled">Uitgeschakeld</string>
<string name="pref_image_cache_size_title">Grootte cachegeheugen</string>
<string name="pref_image_cache_size_sum">De groote van het cachegeheugen voor afbeeldingen aanpassen.</string>
+ <string name="send_email">Verstuur email</string>
<string name="experimental_pref">Experimentele functie</string>
<string name="pref_sonic_title">Sonic mediaspeler</string>
<string name="pref_sonic_message">Sonic, de standaard mediaspeler van Android, gebruiken als alternatief voor Prestissimo</string>
@@ -499,4 +504,10 @@
<string name="sort_date_old_new">Datum (oud \u2192 nieuw)</string>
<string name="sort_duration_short_long">Lengte (kort \u2192 lang)</string>
<string name="sort_duration_long_short">Lengte (lang \u2192 kort)</string>
+ <!--Rating dialog-->
+ <string name="rating_title">Wat vind u van AntennaPod?</string>
+ <string name="rating_message">We zouden het op prijs stellen als u even de tijd kunt nemen om AntennaPod te beoordelen.</string>
+ <string name="rating_never_label">Nee, bedankt.</string>
+ <string name="rating_later_label">Herinner me later</string>
+ <string name="rating_now_label">Ja, doen we!</string>
</resources>
diff --git a/core/src/main/res/values-pl-rPL/strings.xml b/core/src/main/res/values-pl-rPL/strings.xml
index d94845fce..c43a5647a 100644
--- a/core/src/main/res/values-pl-rPL/strings.xml
+++ b/core/src/main/res/values-pl-rPL/strings.xml
@@ -345,4 +345,5 @@ https://gpodder.net/register/</string>
<!--Progress information-->
<!--AntennaPodSP-->
<string name="sp_apps_importing_feeds_msg">Importowanie subskrybcji z jednozadaniowych aplikacji</string>
+ <!--Rating dialog-->
</resources>
diff --git a/core/src/main/res/values-pt-rBR/strings.xml b/core/src/main/res/values-pt-rBR/strings.xml
index 1a9c0e6d0..c57f20177 100644
--- a/core/src/main/res/values-pt-rBR/strings.xml
+++ b/core/src/main/res/values-pt-rBR/strings.xml
@@ -316,4 +316,5 @@
<!--Feed information screen-->
<!--Progress information-->
<!--AntennaPodSP-->
+ <!--Rating dialog-->
</resources>
diff --git a/core/src/main/res/values-pt/strings.xml b/core/src/main/res/values-pt/strings.xml
index 731c92e1a..16c909d78 100644
--- a/core/src/main/res/values-pt/strings.xml
+++ b/core/src/main/res/values-pt/strings.xml
@@ -22,6 +22,7 @@
<string name="playback_history_label">Histórico de reprodução</string>
<string name="gpodnet_main_label">gpodder.net</string>
<string name="gpodnet_auth_label">Dados gpodder.net</string>
+ <string name="free_space_label">%1$s livre</string>
<!--New episodes fragment-->
<string name="recently_published_episodes_label">Publicados recentemente</string>
<string name="episode_filter_label">Mostrar apenas novos episódios</string>
@@ -260,6 +261,8 @@
<string name="pref_pauseOnDisconnect_sum">Pausa na reprodução ao desligar os auscultadores ou o bluetooth</string>
<string name="pref_unpauseOnHeadsetReconnect_sum">Continuar reprodução ao ligar os auscultadores</string>
<string name="pref_unpauseOnBluetoothReconnect_sum">Continuar reprodução ao estabelecer a ligação bluetooth</string>
+ <string name="pref_hardwareForwardButtonSkips_title">Botão de avançar ignora</string>
+ <string name="pref_hardwareForwardButtonSkips_sum">Ao premir o botão Avançar, avança para o episódio seguinte em vez de avançar</string>
<string name="pref_followQueue_sum">Ir para a faixa seguinte ao terminar a reprodução</string>
<string name="pref_auto_delete_sum">Apagar episódio ao terminar a reprodução</string>
<string name="pref_auto_delete_title">Eliminação automática</string>
@@ -344,6 +347,9 @@
<string name="pref_smart_mark_as_played_disabled">Desativada</string>
<string name="pref_image_cache_size_title">Cache de imagens</string>
<string name="pref_image_cache_size_sum">O tamanho da cache de imagens</string>
+ <string name="crash_report_title">Relatório de erro</string>
+ <string name="crash_report_sum">Enviar o relatório de erros por e-mail</string>
+ <string name="send_email">Enviar e-mail</string>
<string name="experimental_pref">Experimental</string>
<string name="pref_sonic_title">Reprodutor Sonic</string>
<string name="pref_sonic_message">Utilizar reprodutor multimédia Sonic como substituto de Prestissimo</string>
@@ -438,11 +444,15 @@
<string name="selected_folder_label">Diretório escolhido:</string>
<string name="create_folder_label">Criar pasta</string>
<string name="choose_data_directory">Escolha a pasta de dados</string>
+ <string name="choose_data_directory_message">Escolha a base da pasta de dados. O AntennaPod irá criar as subpastas apropriadas.</string>
<string name="create_folder_msg">Criar uma pasta com o nome \"%1$s\"?</string>
<string name="create_folder_success">Nova pasta criada</string>
<string name="create_folder_error_no_write_access">Não é possível guardar nesta pasta</string>
<string name="create_folder_error_already_exists">A pasta já existe</string>
<string name="create_folder_error">Não é possível criar a pasta</string>
+ <string name="folder_does_not_exist_error">\"%1$s\" não existe</string>
+ <string name="folder_not_readable_error">\"%1$s\" não permite leitura</string>
+ <string name="folder_not_writable_error">\"%1$s\" não permite escrita</string>
<string name="folder_not_empty_dialog_title">A pasta não está vazia</string>
<string name="folder_not_empty_dialog_msg">A pasta escolhida não está vazia. As transferências multimédia e os ficheiros serão colocados nesta pasta. Continuar?</string>
<string name="set_to_default_folder">Escolha a pasta pré-definida</string>
@@ -502,4 +512,10 @@
<string name="sort_date_old_new">Data (Antiga \u2192 Recente)</string>
<string name="sort_duration_short_long">Duração (Curta \u2192 Longa)</string>
<string name="sort_duration_long_short">Duração (Longa \u2192 Curta)</string>
+ <!--Rating dialog-->
+ <string name="rating_title">Gosta do AntennaPod?</string>
+ <string name="rating_message">Gostaríamos que dispensasse algum tempo para avaliar o AntennaPod.</string>
+ <string name="rating_never_label">Não avaliar</string>
+ <string name="rating_later_label">Lembrar mais tarde</string>
+ <string name="rating_now_label">Claro, vamos a isso!</string>
</resources>
diff --git a/core/src/main/res/values-ro-rRO/strings.xml b/core/src/main/res/values-ro-rRO/strings.xml
index 973a737d2..0512a989b 100644
--- a/core/src/main/res/values-ro-rRO/strings.xml
+++ b/core/src/main/res/values-ro-rRO/strings.xml
@@ -234,4 +234,5 @@
<!--Feed information screen-->
<!--Progress information-->
<!--AntennaPodSP-->
+ <!--Rating dialog-->
</resources>
diff --git a/core/src/main/res/values-ru/strings.xml b/core/src/main/res/values-ru/strings.xml
index cf7129b18..4ad4d3561 100644
--- a/core/src/main/res/values-ru/strings.xml
+++ b/core/src/main/res/values-ru/strings.xml
@@ -5,8 +5,11 @@
<string name="feeds_label">Каналы</string>
<string name="add_feed_label">Добавить подкаст</string>
<string name="podcasts_label">Подкасты</string>
+ <string name="episodes_label">Выпуски</string>
<string name="new_episodes_label">Новые выпуски</string>
<string name="all_episodes_label">Все выпуски</string>
+ <string name="all_episodes_short_label">Все</string>
+ <string name="favorite_episodes_label">Избранное</string>
<string name="new_label">Новые</string>
<string name="waiting_list_label">В ожидании</string>
<string name="settings_label">Настройки</string>
@@ -25,8 +28,10 @@
<!--Main activity-->
<string name="drawer_open">Открыть меню</string>
<string name="drawer_close">Закрыть меню</string>
+ <string name="drawer_preferences">Настройка бокового меню</string>
<string name="drawer_feed_order_unplayed_episodes">Сортировать по количеству</string>
<string name="drawer_feed_order_alphabetical">Сортировать по алфавиту</string>
+ <string name="drawer_feed_order_last_update">Сортировать по дате</string>
<string name="drawer_feed_counter_new_unplayed">Количество новых и непрослушанных выпусков</string>
<string name="drawer_feed_counter_new">Количество новых выпусков</string>
<string name="drawer_feed_counter_unplayed">Количество непрослушанных выпусков</string>
@@ -67,7 +72,16 @@
<string name="retry_label">Повторить</string>
<string name="auto_download_label">Добавить в автозагрузки</string>
<string name="auto_download_apply_to_items_title">Применить к предыдущим выпускам</string>
+ <string name="auto_download_apply_to_items_message">Новые настройки <i>Автозагрузки</i> будут автоматически применены к новым выпускам. \nХотите ли вы применить их к ранее опубликованным выпускам?</string>
+ <string name="auto_delete_label">Автоматическое удаление выпусков\n(игнорирует общие настройки)</string>
<string name="parallel_downloads_suffix">\u0020одновременных загрузок</string>
+ <string name="feed_auto_download_global">Общие</string>
+ <string name="feed_auto_download_always">Всегда</string>
+ <string name="feed_auto_download_never">Никогда</string>
+ <string name="send_label">Отправить...</string>
+ <string name="episode_cleanup_never">Никогда</string>
+ <string name="episode_cleanup_queue_removal">Когда не в очереди</string>
+ <string name="episode_cleanup_after_listening">После прослушивания</string>
<!--'Add Feed' Activity labels-->
<string name="feedurl_label">URL канала</string>
<string name="etxtFeedurlHint">www.example.com/feed</string>
@@ -80,13 +94,28 @@
<string name="mark_all_read_msg">Отметить все выпуски как прослушанные</string>
<string name="mark_all_read_confirmation_msg">Подтвердите, что хотите пометить все эпизоды как прослушанные.</string>
<string name="mark_all_read_feed_confirmation_msg">Подтвердите, что хотите пометить все эпизоды в этом канале как прослушанные.</string>
+ <string name="mark_all_seen_label">Отметить все как про</string>
<string name="show_info_label">Показать информацию</string>
<string name="remove_feed_label">Удалить подкаст</string>
<string name="share_label">Поделиться...</string>
<string name="share_link_label">Поделиться ссылкой</string>
+ <string name="share_link_with_position_label">Поделиться ссылкой с отметкой времени</string>
+ <string name="share_feed_url_label">Поделиться ссылкой на канал</string>
+ <string name="share_item_url_label">Поделиться ссылкой на выпуск</string>
+ <string name="share_item_url_with_position_label">Поделиться ссылкой с отметкой времени</string>
<string name="feed_delete_confirmation_msg">Подтвердите удаление канала и всех выпусков, загруженных с этого канала.</string>
<string name="feed_remover_msg">Удаление канала</string>
<string name="load_complete_feed">Обновить весь канал</string>
+ <string name="hide_episodes_title">Скрыть выпуск</string>
+ <string name="episode_actions">Применить действия</string>
+ <string name="hide_unplayed_episodes_label">Непрослушанное</string>
+ <string name="hide_paused_episodes_label">Приостановленное</string>
+ <string name="hide_played_episodes_label">Прослушанное</string>
+ <string name="hide_queued_episodes_label">В очереди</string>
+ <string name="hide_not_queued_episodes_label">Не в очереди</string>
+ <string name="hide_downloaded_episodes_label">Загружено</string>
+ <string name="hide_not_downloaded_episodes_label">Не загружено</string>
+ <string name="refresh_failed_msg">{fa-exclamation-circle} Последнее обновление не удалось</string>
<!--actions on feeditems-->
<string name="download_label">Загрузить</string>
<string name="play_label">Воспроизвести</string>
@@ -101,11 +130,17 @@
<string name="add_to_queue_label">Добавить в очередь</string>
<string name="added_to_queue_label">Добавлено в очередь</string>
<string name="remove_from_queue_label">Удалить из очереди</string>
+ <string name="add_to_favorite_label">Добавить в избранное</string>
+ <string name="remove_from_favorite_label">Удалить из избранного</string>
<string name="visit_website_label">Посетить сайт</string>
<string name="support_label">Поддержать через Flattr</string>
<string name="enqueue_all_new">Добавить всё в очередь</string>
<string name="download_all">Загрузить всё</string>
<string name="skip_episode_label">Пропустить выпуск</string>
+ <string name="activate_auto_download">Включить автоматическую загрузку</string>
+ <string name="deactivate_auto_download">Выключить автоматическую загрузку</string>
+ <string name="reset_position">Сбросить время воспроизведения</string>
+ <string name="removed_item">Удалено</string>
<!--Download messages and labels-->
<string name="download_successful">успешно</string>
<string name="download_failed">не удалось</string>
@@ -123,7 +158,9 @@
<string name="download_error_unauthorized">Ошибка авторизации</string>
<string name="cancel_all_downloads_label">Отменить все загрузки</string>
<string name="download_canceled_msg">Загрузка отменена</string>
+ <string name="download_canceled_autodownload_enabled_msg">Загрузка отменена\nОтключена <i>Автоматическая загрузка</i> для этого эпизода</string>
<string name="download_report_title">Загрузки завершены</string>
+ <string name="download_report_content_title">Отчет о загрузках</string>
<string name="download_error_malformed_url">Неправильный адрес</string>
<string name="download_error_io_error">Ошибка ввода-вывода</string>
<string name="download_error_request_error">Ошибка запроса</string>
@@ -139,6 +176,11 @@
<string name="download_request_error_dialog_message_prefix">Ошибка при загрузки файла:\u0020</string>
<string name="authentication_notification_title">Необходима авторизация</string>
<string name="authentication_notification_msg">Для доступа к ресурсу необходимо ввести имя пользователя и пароль</string>
+ <string name="confirm_mobile_download_dialog_title">Подтвердите загрузку через мобильное соединение</string>
+ <string name="confirm_mobile_download_dialog_message_not_in_queue">Загрузка через мобильное соединение отключена в настройках.\n\nВы можете добавить выпуск в очередь или временно разрешить загрузку.\n\n<small>Настройка сохранится на 10 минут.</small></string>
+ <string name="confirm_mobile_download_dialog_message">Загрузка через мобильное соединение отключена в настройках.\n\nВы желаете временно разрешить загрузку?\n\n<small>Настройка сохранится на 10 минут.</small></string>
+ <string name="confirm_mobile_download_dialog_only_add_to_queue">Добавить в очередь</string>
+ <string name="confirm_mobile_download_dialog_enable_temporarily">Разрешить временно</string>
<!--Mediaplayer messages-->
<string name="player_error_msg">Ошибка</string>
<string name="player_stopped_msg">Ничего не воспроизводится</string>
@@ -153,6 +195,8 @@
<string name="playbackservice_notification_title">Воспроизведение подкаста</string>
<string name="unknown_media_key">AntennaPod - неизвестный ключ носителя: %1$d</string>
<!--Queue operations-->
+ <string name="lock_queue">Заблокировать очередь</string>
+ <string name="unlock_queue">Разблокировать очередь</string>
<string name="clear_queue_label">Очистить очередь</string>
<string name="undo">Отмена</string>
<string name="removed_from_queue">Удалено</string>
@@ -194,7 +238,9 @@
<!--Variable Speed-->
<string name="download_plugin_label">Загрузить плагин</string>
<string name="no_playback_plugin_title">Плагин не установлен</string>
+ <string name="no_playback_plugin_or_sonic_msg">Для изменения скорости воспроизведения нужно установить библиотеку стороннего разработчика или включить экспериментальный Sonic player [Android 4.1+].\n\nНажмите \"Загрузить плагин\", чтобы скачать бесплатный плагин из Play Store\n\nЛюбые вопросы по работе плагина находятся вне ответственности AntennaPod и должны быть направлены владельцу плагина.</string>
<string name="set_playback_speed_label">Скорость воспроизведения</string>
+ <string name="enable_sonic">Включить Sonic</string>
<!--Empty list labels-->
<string name="no_items_label">Список пуст</string>
<string name="no_feeds_label">Вы еще не подписаны ни на один канал</string>
@@ -204,17 +250,32 @@
<string name="queue_label">Очередь</string>
<string name="services_label">Сервисы</string>
<string name="flattr_label">Flattr</string>
+ <string name="pref_episode_cleanup_title">Удаление выпусков</string>
+ <string name="pref_episode_cleanup_summary">Выпуски, которые не стоят в очереди и не отмечены как избранные могут быть удалены для освобождения места.</string>
+ <string name="pref_pauseOnDisconnect_sum">Приостановить воспроизведение, когда наушники или bluetooth отключены</string>
<string name="pref_unpauseOnHeadsetReconnect_sum">Продолжать воспроизведение после подключения наушников</string>
+ <string name="pref_unpauseOnBluetoothReconnect_sum">Продолжать воспроизведение после подключения наушников или восстановления bluetooth-соединения</string>
<string name="pref_followQueue_sum">После завершения воспроизведения перейти к следующему в очереди</string>
<string name="pref_auto_delete_sum">Удалять эпизод после завершения воспроизведения</string>
<string name="pref_auto_delete_title">Автоматическое удаление</string>
+ <string name="pref_smart_mark_as_played_sum">Отмечать выпуск как прослушанный, даже если до завершения остается некоторое время</string>
+ <string name="pref_smart_mark_as_played_title">Предварительная отметка \"прослушано\"</string>
+ <string name="pref_skip_keeps_episodes_sum">Сохранять выпуски, помеченные как пропущенные</string>
+ <string name="pref_skip_keeps_episodes_title">Сохранять пропущенные выпуски</string>
<string name="playback_pref">Воспроизведение</string>
<string name="network_pref">Сеть</string>
+ <string name="pref_autoUpdateIntervallOrTime_title">Время для обновлений</string>
+ <string name="pref_autoUpdateIntervallOrTime_sum">Выбрать часы или время суток для автоматического обновления каналов</string>
+ <string name="pref_autoUpdateIntervallOrTime_message">Вы можете задать <i>интервал</i>, например \"каждые 2 часа\", выбрать <i>время</i>, например \"7:00\" или <i>отключить</i> автоматическое обновление. \n\n<small>Обратите внимание: время для обновлений приблизительное. Вы можете заметить небольшие задержки.</small></string>
+ <string name="pref_autoUpdateIntervallOrTime_Disable">Отключить</string>
+ <string name="pref_autoUpdateIntervallOrTime_Interval">Задать интервал</string>
+ <string name="pref_autoUpdateIntervallOrTime_TimeOfDay">Задать время</string>
<string name="pref_downloadMediaOnWifiOnly_sum">Загружать файлы только через Wi-Fi</string>
<string name="pref_followQueue_title">Непрерывное воспроизведение</string>
<string name="pref_downloadMediaOnWifiOnly_title">Загрузка по Wi-Fi</string>
<string name="pref_pauseOnHeadsetDisconnect_title">Наушники отсоединены</string>
<string name="pref_unpauseOnHeadsetReconnect_title">Наушники отсоединены</string>
+ <string name="pref_unpauseOnBluetoothReconnect_title">Bluetooth-соединение восстановлено</string>
<string name="pref_mobileUpdate_title">Мобильные обновления</string>
<string name="pref_mobileUpdate_sum">Позволить обновления через мобильное интернет-подключение</string>
<string name="refreshing_label">Обновление</string>
@@ -229,6 +290,14 @@
<string name="pref_auto_flattr_sum">Настройка автоматической поддержки через Flattr</string>
<string name="user_interface_label">Интерфейс</string>
<string name="pref_set_theme_title">Выбор темы</string>
+ <string name="pref_nav_drawer_title">Настроить боковую панель</string>
+ <string name="pref_nav_drawer_sum">Настроить вид боковой панели</string>
+ <string name="pref_nav_drawer_items_title">Выбрать пункты боковой панели</string>
+ <string name="pref_nav_drawer_items_sum">Изменение отображения пунктов в меню боковой панели</string>
+ <string name="pref_nav_drawer_feed_order_title">Порядок подписок</string>
+ <string name="pref_nav_drawer_feed_order_sum">Выбрать порядок отображения подписок</string>
+ <string name="pref_nav_drawer_feed_counter_title">Счетчик подписок</string>
+ <string name="pref_nav_drawer_feed_counter_sum">Выбрать какую информацию показывать в счетчике подписок</string>
<string name="pref_set_theme_sum">Изменить тему оформления AntennaPod</string>
<string name="pref_automatic_download_title">Автоматическая загрузка</string>
<string name="pref_automatic_download_sum">Настроить автоматическую загрузку выпусков.</string>
@@ -252,15 +321,27 @@
<string name="pref_gpodnet_setlogin_information_sum">Изменить информацию авторизации для аккаунта gpodder.net</string>
<string name="pref_playback_speed_title">Скорость воспроизведения</string>
<string name="pref_playback_speed_sum">Настроить скорости воспроизведения</string>
+ <string name="pref_fast_forward">Интервал быстрой перемотки вперед</string>
+ <string name="pref_rewind">Интервал быстрой перемотки назад</string>
<string name="pref_gpodnet_sethostname_title">Задать имя узла</string>
<string name="pref_gpodnet_sethostname_use_default_host">Использовать узел по умолчанию</string>
<string name="pref_expandNotify_title">Расширенное уведомление</string>
<string name="pref_expandNotify_sum">Всегда показывать в уведомлении кнопки управления вопспроизведением</string>
<string name="pref_persistNotify_title">Постоянный контрооль воспроизведения</string>
<string name="pref_persistNotify_sum">Сохранять уведомление и кнопки воспроизведения на экране блокировки во время паузы.</string>
+ <string name="pref_lockscreen_background_title">Выбрать фон экрана блокировки</string>
+ <string name="pref_lockscreen_background_sum">Изменяет фон экрана блокировки на обложку выпуска. Кроме того показывает обложку в сторонних приложениях.</string>
+ <string name="pref_showDownloadReport_title">Показывать отчет о загрузках</string>
+ <string name="pref_showDownloadReport_sum">Если загрузка не удается, показывать отчет с подробностями об ошибке.</string>
<string name="pref_expand_notify_unsupport_toast">Версии Android ниже 4.1 не поддерживают расширенные уведомления.</string>
<string name="pref_queueAddToFront_sum">Добавлять новые выпуски в начало очереди.</string>
<string name="pref_queueAddToFront_title">В начало очереди.</string>
+ <string name="pref_smart_mark_as_played_disabled">Отключено</string>
+ <string name="pref_image_cache_size_title">Размер кэша для изображений</string>
+ <string name="pref_image_cache_size_sum">Размер дискового кэша для изображений</string>
+ <string name="experimental_pref">Экспериментальные настройки</string>
+ <string name="pref_sonic_title">Проигрыватель Sonic</string>
+ <string name="pref_sonic_message">Использовать встроенный проигрыватель Sonic вместо Prestissimo.</string>
<!--Auto-Flattr dialog-->
<string name="auto_flattr_enable">Включить автоматическую поддержку через Flattr</string>
<string name="auto_flattr_after_percent">Поддерживать через Flattr эпизоды, прослушанные на %d процентов</string>
@@ -275,6 +356,7 @@
<string name="found_in_title_label">Найдено в заголовке</string>
<!--OPML import and export-->
<string name="opml_import_txtv_button_lable">OPML файлы позволяют перемещать ваши подкасты из одного менеджера подкастов в другой.</string>
+ <string name="opml_import_option">Настройка %1$d</string>
<string name="opml_import_explanation_1">Укажите путь к файлу на устройстве</string>
<string name="opml_import_explanation_2">Откройте OPML-файл с помощью внешних приложений: Dropbox, Google Drive или любого файлового менеджера.</string>
<string name="opml_import_explanation_3">Множество приложений умеют <i>открывать</i> OPML-файлы <i>в</i> AntennaPod, например: Google Mail, Dropbox, Google Drive и большинство файловых менеджеров.</string>
@@ -286,6 +368,7 @@
<string name="opml_import_error_dir_empty">Каталог для импорта пуст.</string>
<string name="select_all_label">Отметить все</string>
<string name="deselect_all_label">Снять все отметки</string>
+ <string name="select_options_label">Выбрать...</string>
<string name="choose_file_from_filesystem">Из файловой системы</string>
<string name="choose_file_from_external_application">С помощью внешнего приложения</string>
<string name="opml_export_label">Экспорт в OPML</string>
@@ -300,6 +383,12 @@
<string name="sleep_timer_label">Таймер сна</string>
<string name="time_left_label">Осталось времени:\u0020</string>
<string name="time_dialog_invalid_input">Неправильный ввод, время должно быть в виде числа</string>
+ <string name="timer_about_to_expire_label"><b>Когда истекает таймер:</b></string>
+ <string name="shake_to_reset_label">Потрясти для сброса таймера</string>
+ <string name="timer_vibration_label">Вибрация</string>
+ <string name="time_seconds">с</string>
+ <string name="time_minutes">м</string>
+ <string name="time_hours">ч</string>
<!--gpodder.net-->
<string name="gpodnet_taglist_header">Категории</string>
<string name="gpodnet_toplist_header">Лучшее</string>
@@ -342,6 +431,9 @@
<string name="set_to_default_folder">Выберите папку по умолчанию</string>
<string name="pref_pausePlaybackForFocusLoss_sum">Пауза вместо уменьшения громкости, когда другое приложение проигрывает звуки</string>
<string name="pref_pausePlaybackForFocusLoss_title">Пауза при прерывании</string>
+ <string name="pref_resumeAfterCall_sum">Продолжение воспроизведения после завершения звонка</string>
+ <string name="pref_resumeAfterCall_title">Включать после звонка</string>
+ <string name="pref_restart_required">AntennaPod нужно перезапустить для применения настроек.</string>
<!--Online feed view-->
<string name="subscribe_label">Подписаться</string>
<string name="subscribed_label">Подписка оформлена</string>
@@ -369,7 +461,29 @@
<string name="authentication_label">Авторизация</string>
<string name="authentication_descr">Изменить имя пользователя и пароль для этого подкаста и его выпусков.</string>
<!--Progress information-->
+ <string name="progress_upgrading_database">Обновление базы данных</string>
<!--AntennaPodSP-->
<string name="sp_apps_importing_feeds_msg">Импорт подписок из одноцелевых приложений…</string>
<string name="search_itunes_label">Поиск в iTunes</string>
+ <string name="select_label"><b>Выбрать ...</b></string>
+ <string name="all_label">Все</string>
+ <string name="selected_all_label">Отмечены все выпуски</string>
+ <string name="none_label">Нет</string>
+ <string name="deselected_all_label">Отметки сняты со всех выпусков</string>
+ <string name="played_label">Прослушанное</string>
+ <string name="selected_played_label">Выбраны прослушанные выпуски</string>
+ <string name="unplayed_label">Непрослушанное</string>
+ <string name="selected_unplayed_label">Выбраны непрослушанные выпуски</string>
+ <string name="downloaded_label">Загружено</string>
+ <string name="selected_downloaded_label">Выбраны загруженные выпуски</string>
+ <string name="not_downloaded_label">Не загружено</string>
+ <string name="selected_not_downloaded_label">Выбраны незагруженные выпуски</string>
+ <string name="sort_title"><b>Сортировать по ...</b></string>
+ <string name="sort_title_a_z">Заголовку (А \u2192 Я)</string>
+ <string name="sort_title_z_a">Заголовку (Я \u2192 А)</string>
+ <string name="sort_date_new_old">Дате (Новое \u2192 Старое)</string>
+ <string name="sort_date_old_new">Дате (Старое \u2192 Новое)</string>
+ <string name="sort_duration_short_long">Продолжительности (Короткие \u2192 Длинные)</string>
+ <string name="sort_duration_long_short">Продолжительности (Длинные \u2192 Короткие)</string>
+ <!--Rating dialog-->
</resources>
diff --git a/core/src/main/res/values-sv-rSE/strings.xml b/core/src/main/res/values-sv-rSE/strings.xml
index b88a473c0..a618e257f 100644
--- a/core/src/main/res/values-sv-rSE/strings.xml
+++ b/core/src/main/res/values-sv-rSE/strings.xml
@@ -10,25 +10,26 @@
<string name="all_episodes_label">Alla Episoder</string>
<string name="all_episodes_short_label">Alla</string>
<string name="favorite_episodes_label">Favoriter</string>
- <string name="new_label">Ny</string>
+ <string name="new_label">Nya</string>
<string name="waiting_list_label">Väntelista</string>
<string name="settings_label">Inställningar</string>
<string name="add_new_feed_label">Lägg till Podcast</string>
<string name="downloads_label">Nedladdningar</string>
- <string name="downloads_running_label">Körs</string>
+ <string name="downloads_running_label">Pågående</string>
<string name="downloads_completed_label">Färdiga</string>
<string name="downloads_log_label">Logg</string>
<string name="cancel_download_label">Avbryt\nNedladdning</string>
<string name="playback_history_label">Uppspelningshistorik</string>
<string name="gpodnet_main_label">gpodder.net</string>
<string name="gpodnet_auth_label">Inloggning till gpodder.net</string>
+ <string name="free_space_label">\"%1$s oanvänt</string>
<!--New episodes fragment-->
<string name="recently_published_episodes_label">Nyligen publicerade</string>
<string name="episode_filter_label">Visa bara nya Episoder</string>
<!--Main activity-->
<string name="drawer_open">Öppna meny</string>
<string name="drawer_close">Stäng meny</string>
- <string name="drawer_preferences">Lådinställningar</string>
+ <string name="drawer_preferences">Menyinställningar</string>
<string name="drawer_feed_order_unplayed_episodes">Sortera efter räknare</string>
<string name="drawer_feed_order_alphabetical">Sortera alfabetiskt</string>
<string name="drawer_feed_order_last_update">Sortera efter publiceringsdatum</string>
@@ -81,7 +82,7 @@
<string name="send_label">Skicka...</string>
<string name="episode_cleanup_never">Aldrig</string>
<string name="episode_cleanup_queue_removal">Om inte köad</string>
- <string name="episode_cleanup_after_listening">Efter avslutad</string>
+ <string name="episode_cleanup_after_listening">Efter färdigspelad</string>
<plurals name="episode_cleanup_days_after_listening">
<item quantity="one">1 dag efter färdigspelad</item>
<item quantity="other">%d dagar efter färdigspelad</item>
@@ -113,12 +114,12 @@
<string name="hide_episodes_title">Dölj Episoder</string>
<string name="episode_actions">Applicera åtgärder</string>
<string name="hide_unplayed_episodes_label">Ospelade</string>
- <string name="hide_paused_episodes_label">Pausad</string>
+ <string name="hide_paused_episodes_label">Pausade</string>
<string name="hide_played_episodes_label">Spelad</string>
- <string name="hide_queued_episodes_label">Köad</string>
- <string name="hide_not_queued_episodes_label">Inte köad</string>
- <string name="hide_downloaded_episodes_label">Nedladdad</string>
- <string name="hide_not_downloaded_episodes_label">Inte nedladdad</string>
+ <string name="hide_queued_episodes_label">Köade</string>
+ <string name="hide_not_queued_episodes_label">Inte köade</string>
+ <string name="hide_downloaded_episodes_label">Nedladdade</string>
+ <string name="hide_not_downloaded_episodes_label">Ej nedladdade</string>
<string name="filtered_label">Filtrerad</string>
<string name="refresh_failed_msg">{fa-exclamation-circle} Senaste uppdateringen misslyckades</string>
<!--actions on feeditems-->
@@ -141,7 +142,7 @@
<string name="support_label">Flattra det här</string>
<string name="enqueue_all_new">Lägg till alla i kön</string>
<string name="download_all">Ladda ner alla</string>
- <string name="skip_episode_label">Hoppa över episod</string>
+ <string name="skip_episode_label">Hoppa över episoden</string>
<string name="activate_auto_download">Aktivera Automatisk Nedladdning</string>
<string name="deactivate_auto_download">Avaktivera Automatisk Nedladdning</string>
<string name="reset_position">Nollställ Uppspelningspositionen</string>
@@ -256,13 +257,15 @@
<string name="services_label">Tjänster</string>
<string name="flattr_label">Flattr</string>
<string name="pref_episode_cleanup_title">Episodupprensning</string>
- <string name="pref_episode_cleanup_summary">Episoder som inte ligger i kön och inte är favoriter bör kunna tas bort om det behövs utrymme</string>
+ <string name="pref_episode_cleanup_summary">Episoder som inte ligger i kön och inte är favoriter ska kunna tas bort om det behövs utrymme</string>
<string name="pref_pauseOnDisconnect_sum">Pausa uppspelningen när hörlurar eller bluetooth kopplas ifrån.</string>
<string name="pref_unpauseOnHeadsetReconnect_sum">Fortsätt uppspelningen när hörlurarna återansluts</string>
<string name="pref_unpauseOnBluetoothReconnect_sum">Fortsätt uppspelningen när bluetooth återansluts</string>
+ <string name="pref_hardwareForwardButtonSkips_title">Framåt-knappen hoppar</string>
+ <string name="pref_hardwareForwardButtonSkips_sum">När den fysiska framåt-knappen trycks in, hoppa till nästa episod istället för att spola framåt</string>
<string name="pref_followQueue_sum">Hoppa till nästa i kön när uppspelningen är klar</string>
<string name="pref_auto_delete_sum">Ta bort episoden när uppspelningen är klar</string>
- <string name="pref_auto_delete_title">Automatisk borttagning</string>
+ <string name="pref_auto_delete_title">Automatisk Borttagning</string>
<string name="pref_smart_mark_as_played_sum">Markera episoder som spelade även om mindre än ett visst antal sekunder är kvar</string>
<string name="pref_smart_mark_as_played_title">Smart markering av uppspelat innehåll</string>
<string name="pref_skip_keeps_episodes_sum">Ta inte bort episoder när de hoppas över</string>
@@ -278,9 +281,9 @@
<string name="pref_downloadMediaOnWifiOnly_sum">Hämta mediefiler endast över WiFi</string>
<string name="pref_followQueue_title">Kontinuerlig Uppspelning</string>
<string name="pref_downloadMediaOnWifiOnly_title">WiFi nedladdning</string>
- <string name="pref_pauseOnHeadsetDisconnect_title">Hörlurar Bortkopplade</string>
+ <string name="pref_pauseOnHeadsetDisconnect_title">Hörlurar Bortkopplas</string>
<string name="pref_unpauseOnHeadsetReconnect_title">Hörlurar Återanslutna</string>
- <string name="pref_unpauseOnBluetoothReconnect_title">Bluetooth återansluts</string>
+ <string name="pref_unpauseOnBluetoothReconnect_title">Blutetooth Återansluts</string>
<string name="pref_mobileUpdate_title">Mobila Uppdateringar</string>
<string name="pref_mobileUpdate_sum">Tillåt uppdateringar via mobil dataanslutning</string>
<string name="refreshing_label">Uppdaterar</string>
@@ -295,13 +298,13 @@
<string name="pref_auto_flattr_sum">Konfigurerar automatisk Flattring</string>
<string name="user_interface_label">Användargränssnitt</string>
<string name="pref_set_theme_title">Välj Tema</string>
- <string name="pref_nav_drawer_title">Anpassa Navigeringsrutan</string>
- <string name="pref_nav_drawer_sum">Anpassa utseendet på navigeringsrutan.</string>
- <string name="pref_nav_drawer_items_title">Välj saker i Navigeringsrutan</string>
- <string name="pref_nav_drawer_items_sum">Ändra vilka saker som visas i navigationslådan.</string>
+ <string name="pref_nav_drawer_title">Anpassa Navigeringsmenyn</string>
+ <string name="pref_nav_drawer_sum">Anpassa utseendet på navigeringmenyn.</string>
+ <string name="pref_nav_drawer_items_title">Välj Objekt i Navigeringsmenyn</string>
+ <string name="pref_nav_drawer_items_sum">Ändra vilka saker som visas på navigationsmenyn.</string>
<string name="pref_nav_drawer_feed_order_title">Välj Prenumerationsordning</string>
<string name="pref_nav_drawer_feed_order_sum">Ändra ordningen på dina prenumerationer</string>
- <string name="pref_nav_drawer_feed_counter_title">Välj Prenumerationsräknaren</string>
+ <string name="pref_nav_drawer_feed_counter_title">Val För Prenumerationsräknaren</string>
<string name="pref_nav_drawer_feed_counter_sum">Ändra informationen som visas av prenumerationsräknaren</string>
<string name="pref_set_theme_sum">Ändra utseendet på AntennaPod.</string>
<string name="pref_automatic_download_title">Automatisk Nedladdning</string>
@@ -330,21 +333,24 @@
<string name="pref_rewind">Spola bakåt</string>
<string name="pref_gpodnet_sethostname_title">Sätt värdnamn</string>
<string name="pref_gpodnet_sethostname_use_default_host">Använd standardvärden</string>
- <string name="pref_expandNotify_title">Expandera notifieringar</string>
- <string name="pref_expandNotify_sum">Expandera alltid notifieringen för att visa uppspelningskontrollerna.</string>
+ <string name="pref_expandNotify_title">Expandera aviseringen</string>
+ <string name="pref_expandNotify_sum">Expandera alltid aviseringen för att visa uppspelningskontrollerna.</string>
<string name="pref_persistNotify_title">Bestående Uppspelningskontroller</string>
- <string name="pref_persistNotify_sum">Behåll notifiering och kontroller på låsskärmen när uppspelningen pausas.</string>
+ <string name="pref_persistNotify_sum">Behåll avisering och kontroller på låsskärmen när uppspelningen pausas.</string>
<string name="pref_lockscreen_background_title">Sätt Låsskärmens Bakgrund</string>
<string name="pref_lockscreen_background_sum">Sätt låsskärmens bakgrund till den spelade episodens bild. En bieffekt är att även tredjepartsappar kan visa bilden.</string>
<string name="pref_showDownloadReport_title">Visa Nedladdningsrapport</string>
<string name="pref_showDownloadReport_sum">Visa en rapport med detaljer om felet när nedladdningar misslyckas.</string>
- <string name="pref_expand_notify_unsupport_toast">Androidversioner före 4.1 har inte stöd för expanderade notifieringar.</string>
+ <string name="pref_expand_notify_unsupport_toast">Androidversioner före 4.1 har inte stöd för expanderade aviseringar.</string>
<string name="pref_queueAddToFront_sum">Lägg till episoder först i kön.</string>
<string name="pref_queueAddToFront_title">Köa Först</string>
<string name="pref_smart_mark_as_played_disabled">Avaktiverad</string>
<string name="pref_image_cache_size_title">Bildcachestorlek</string>
<string name="pref_image_cache_size_sum">Storleken på bildcachen på disken.</string>
- <string name="experimental_pref">Experimentell</string>
+ <string name="crash_report_title">Krashrapport</string>
+ <string name="crash_report_sum">Sänd den senaste krashrapporten via e-post</string>
+ <string name="send_email">Sänd e-post</string>
+ <string name="experimental_pref">Experimentellt</string>
<string name="pref_sonic_title">Sonic mediaspelare</string>
<string name="pref_sonic_message">Använd inbyggda mediaspelaren Sonic som en ersättning för Prestissimo</string>
<!--Auto-Flattr dialog-->
@@ -438,16 +444,20 @@
<string name="selected_folder_label">Vald mapp:</string>
<string name="create_folder_label">Skapa mapp</string>
<string name="choose_data_directory">Välj Datakatalog</string>
+ <string name="choose_data_directory_message">Välj rotkatalogen för din data. AntennaPod skapar de underkataloger som behövs.</string>
<string name="create_folder_msg">Skapa ny mapp med namnet \"%1$s\"?</string>
<string name="create_folder_success">Skapade ny mapp</string>
<string name="create_folder_error_no_write_access">Kan inte skriva till den här mappen</string>
<string name="create_folder_error_already_exists">Mappen finns redan</string>
<string name="create_folder_error">Kunde inte skapa mapp</string>
+ <string name="folder_does_not_exist_error">\"%1$s\" existerar inte</string>
+ <string name="folder_not_readable_error">\"%1$s\" är inte läsbar</string>
+ <string name="folder_not_writable_error">\"%1$s\" är inte skrivbar</string>
<string name="folder_not_empty_dialog_title">Mappen är inte tom</string>
<string name="folder_not_empty_dialog_msg">Den mapp du har valt är inte tom. Filer kommer att placeras direkt i denna mapp. Fortsätt ändå?</string>
<string name="set_to_default_folder">Välj standardmapp</string>
<string name="pref_pausePlaybackForFocusLoss_sum">Pausa uppspelning istället för att sänka volymen när en annan app vill spela ljud</string>
- <string name="pref_pausePlaybackForFocusLoss_title">Pausa för Avbrott</string>
+ <string name="pref_pausePlaybackForFocusLoss_title">Pausa vid Avbrott</string>
<string name="pref_resumeAfterCall_sum">Återuppta uppspelning när ett telefonsamtal avslutas</string>
<string name="pref_resumeAfterCall_title">Fortsätt efter Samtal</string>
<string name="pref_restart_required">AntennaPod behöver startas om för att denna inställning ska gälla.</string>
@@ -502,4 +512,10 @@
<string name="sort_date_old_new">Datum (Gammal \u2192 Ny)</string>
<string name="sort_duration_short_long">Längd (Kort \u2192 Lång)</string>
<string name="sort_duration_long_short">Längd (Lång \u2192 Kort)</string>
+ <!--Rating dialog-->
+ <string name="rating_title">Gillar du AntennaPod?</string>
+ <string name="rating_message">Vi skulle uppskatta om du tog dig tid att betygsätta AntennaPod.</string>
+ <string name="rating_never_label">Lämna mig ifred</string>
+ <string name="rating_later_label">Påminn mig senare</string>
+ <string name="rating_now_label">Okej, gör det nu!</string>
</resources>
diff --git a/core/src/main/res/values-tr/strings.xml b/core/src/main/res/values-tr/strings.xml
index 86ee24107..6a59248f6 100644
--- a/core/src/main/res/values-tr/strings.xml
+++ b/core/src/main/res/values-tr/strings.xml
@@ -483,4 +483,5 @@
<string name="sort_date_old_new">Tarih (Eski \u2192 Yeni)</string>
<string name="sort_duration_short_long">Süre (Kısa \u2192 Uzun)</string>
<string name="sort_duration_long_short">Süre (Uzun \u2192 Kısa)</string>
+ <!--Rating dialog-->
</resources>
diff --git a/core/src/main/res/values-uk-rUA/strings.xml b/core/src/main/res/values-uk-rUA/strings.xml
index c1d56a29a..4fcd811b0 100644
--- a/core/src/main/res/values-uk-rUA/strings.xml
+++ b/core/src/main/res/values-uk-rUA/strings.xml
@@ -506,4 +506,5 @@
<string name="sort_date_old_new">Дата (Старі \u2192 Нові)</string>
<string name="sort_duration_short_long">Тривалість (Короткі \u2192 Довгі)</string>
<string name="sort_duration_long_short">Тривалість (Довгі \u2192 Короткі)</string>
+ <!--Rating dialog-->
</resources>
diff --git a/core/src/main/res/values-zh-rCN/strings.xml b/core/src/main/res/values-zh-rCN/strings.xml
index 8ef0eaec7..310b93aec 100644
--- a/core/src/main/res/values-zh-rCN/strings.xml
+++ b/core/src/main/res/values-zh-rCN/strings.xml
@@ -455,4 +455,5 @@
<string name="sort_date_old_new">日期 (旧 \u2192 新)</string>
<string name="sort_duration_short_long">时长 (短 \u2192 长)</string>
<string name="sort_duration_long_short">时长 (长 \u2192 短)</string>
+ <!--Rating dialog-->
</resources>
diff --git a/core/src/main/res/values/colors.xml b/core/src/main/res/values/colors.xml
index 72897ed07..ff061be4c 100644
--- a/core/src/main/res/values/colors.xml
+++ b/core/src/main/res/values/colors.xml
@@ -28,5 +28,7 @@
<!-- Theme colors -->
<color name="primary_light">#FFFFFF</color>
+ <color name="highlight_light">#DDDDDD</color>
+ <color name="highlight_dark">#414141</color>
</resources>
diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml
index 6cbc5579d..443a1a8a8 100644
--- a/core/src/main/res/values/strings.xml
+++ b/core/src/main/res/values/strings.xml
@@ -25,7 +25,7 @@
<string name="playback_history_label">Playback History</string>
<string name="gpodnet_main_label">gpodder.net</string>
<string name="gpodnet_auth_label">gpodder.net Login</string>
- <string name="free_space_label">"%1$s free</string>
+ <string name="free_space_label">%1$s free</string>
<!-- New episodes fragment -->
<string name="recently_published_episodes_label">Recently published</string>
@@ -280,6 +280,8 @@
<string name="pref_pauseOnDisconnect_sum">Pause playback when headphones or bluetooth are disconnected</string>
<string name="pref_unpauseOnHeadsetReconnect_sum">Resume playback when the headphones are reconnected</string>
<string name="pref_unpauseOnBluetoothReconnect_sum">Resume playback when bluetooth reconnects</string>
+ <string name="pref_hardwareForwardButtonSkips_title">Forward button skips</string>
+ <string name="pref_hardwareForwardButtonSkips_sum">When pressing a hardware forward button skip to the next episode instead of fast-forwarding</string>
<string name="pref_followQueue_sum">Jump to next queue item when playback completes</string>
<string name="pref_auto_delete_sum">Delete episode when playback completes</string>
<string name="pref_auto_delete_title">Auto Delete</string>
@@ -364,6 +366,9 @@
<string name="pref_smart_mark_as_played_disabled">Disabled</string>
<string name="pref_image_cache_size_title">Image Cache Size</string>
<string name="pref_image_cache_size_sum">Size of the disk cache for images.</string>
+ <string name="crash_report_title">Crash Report</string>
+ <string name="crash_report_sum">Send the latest crash report via e-mail</string>
+ <string name="send_email">Send e-mail</string>
<string name="experimental_pref">Experimental</string>
<string name="pref_sonic_title">Sonic media player</string>
<string name="pref_sonic_message">Use built-in sonic media player as a replacement for Prestissimo</string>
@@ -542,4 +547,12 @@
<string name="sort_date_old_new">Date (Old \u2192 New)</string>
<string name="sort_duration_short_long">Duration (Short \u2192 Long)</string>
<string name="sort_duration_long_short">Duration (Long \u2192 Short)</string>
+
+ <!-- Rating dialog -->
+ <string name="rating_title">Like AntennaPod?</string>
+ <string name="rating_message">We would appreciate it if you take the time to rate AntennaPod.</string>
+ <string name="rating_never_label">Leave me alone</string>
+ <string name="rating_later_label">Remind me later</string>
+ <string name="rating_now_label">Sure, let\'s do this!</string>
+
</resources>
diff --git a/description/ar.txt b/description/ar.txt
index 14e6a83c8..b4955d18a 100644
--- a/description/ar.txt
+++ b/description/ar.txt
@@ -30,13 +30,13 @@ CONTROL THE SYSTEM<br>
AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-www.github.com/AntennaPod/AntennaPod
+https://www.github.com/AntennaPod/AntennaPod
Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
https://groups.google.com/forum/#!forum/antennapod
Transifex is the place to help with translations:<br>
-www.transifex.com/antennapod/antennapod
+https://www.transifex.com/antennapod/antennapod
Check out our Beta Testing programme to get the latest features first:<br>
-www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
+https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/description/az.txt b/description/az.txt
index 14e6a83c8..b4955d18a 100644
--- a/description/az.txt
+++ b/description/az.txt
@@ -30,13 +30,13 @@ CONTROL THE SYSTEM<br>
AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-www.github.com/AntennaPod/AntennaPod
+https://www.github.com/AntennaPod/AntennaPod
Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
https://groups.google.com/forum/#!forum/antennapod
Transifex is the place to help with translations:<br>
-www.transifex.com/antennapod/antennapod
+https://www.transifex.com/antennapod/antennapod
Check out our Beta Testing programme to get the latest features first:<br>
-www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
+https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/description/ca.txt b/description/ca.txt
index 14e6a83c8..b4955d18a 100644
--- a/description/ca.txt
+++ b/description/ca.txt
@@ -30,13 +30,13 @@ CONTROL THE SYSTEM<br>
AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-www.github.com/AntennaPod/AntennaPod
+https://www.github.com/AntennaPod/AntennaPod
Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
https://groups.google.com/forum/#!forum/antennapod
Transifex is the place to help with translations:<br>
-www.transifex.com/antennapod/antennapod
+https://www.transifex.com/antennapod/antennapod
Check out our Beta Testing programme to get the latest features first:<br>
-www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
+https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/description/cs_CZ.txt b/description/cs_CZ.txt
index 14e6a83c8..b4955d18a 100644
--- a/description/cs_CZ.txt
+++ b/description/cs_CZ.txt
@@ -30,13 +30,13 @@ CONTROL THE SYSTEM<br>
AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-www.github.com/AntennaPod/AntennaPod
+https://www.github.com/AntennaPod/AntennaPod
Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
https://groups.google.com/forum/#!forum/antennapod
Transifex is the place to help with translations:<br>
-www.transifex.com/antennapod/antennapod
+https://www.transifex.com/antennapod/antennapod
Check out our Beta Testing programme to get the latest features first:<br>
-www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
+https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/description/da.txt b/description/da.txt
index 14e6a83c8..b4955d18a 100644
--- a/description/da.txt
+++ b/description/da.txt
@@ -30,13 +30,13 @@ CONTROL THE SYSTEM<br>
AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-www.github.com/AntennaPod/AntennaPod
+https://www.github.com/AntennaPod/AntennaPod
Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
https://groups.google.com/forum/#!forum/antennapod
Transifex is the place to help with translations:<br>
-www.transifex.com/antennapod/antennapod
+https://www.transifex.com/antennapod/antennapod
Check out our Beta Testing programme to get the latest features first:<br>
-www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
+https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/description/de.txt b/description/de.txt
index 6e2db081a..e14c619f2 100644
--- a/description/de.txt
+++ b/description/de.txt
@@ -1,42 +1,42 @@
Einfach zu benutzender und anpassbarer Open-Source Podcast-Manager
-AntennaPod is a podcast manager and player that gives you instant access to millions of free and paid podcasts, from independent podcasters to large publishing houses such as the BBC, NPR and CNN. Add, import and export their feeds hassle-free using the iTunes podcast database, OPML files or simple RSS URLs. Save effort, battery power and mobile data usage with powerful automation controls for downloading episodes (specify times, intervals and WiFi networks) and deleting episodes (based your favourites and delay settings).<br>
-But most importantly: Download, stream or queue episodes and enjoy them the way you like with adjustable playback speeds, chapter support and a sleep timer. You can even show your love to the content creators with our Flattr integration.
+AntennaPod ist ein Podcast-Manager und -Player, der dir unmittelbar Zugriff auf Millionen von freien und bezahlten Podcasts ermöglicht, angefangen von unabhängigen Podcastern zu großen Rundfunkanstalten oder Hörfunksendern wie BBC, NPR und CNN. Abonniere, importiere und exportiere deine Feeds mühelos mit Hilfe des iTunes-Verzeichnisses, OPML-Dateien oder einfachen RSS-URLs. Reduziere Aufwand, Stromverbrauch und Datenverbrauch durch die Kontrolle der Downloads (bestimmte Uhrzeiten, Intervalle, WiFi-Netze) und des Löschens (basierend auf deinen Favoriten und weiteren Einstellungen).
+Aber am wichtigsten: Downloade, streame oder füge Episoden zur Abspielliste hinzu und genieße sie mit einstellbarer Abspielgeschwindigkeit, Unterstützung von Kapiteln und Schlummerfunktion. Mit Flattr kannst du den Podcastern sogar deine Wertschätzung zeigen.
-Made by podcast-enthousiast, AntennaPod is free in all senses of the word: open source, no costs, no ads.
+AntennaPod ist, von Podcast-Enthusiasten gemacht, frei im Sinne des Wortes: Open Source, keine Kosten, keine Werbung.
<b>Alle Funktionen:</b><br>
IMPORTIERE, ORGANISIERE UND HÖRE<br>
-&#8226; Add and import feeds via the iTunes and gPodder.net directories, OPML files and RSS or Atom links<br>
-&#8226; Manage playback from anywhere: homescreen widget, system notification and earplug and bluetooth controls<br>
-&#8226; Enjoy listening your way with adjustable playback speed, chapter support (MP3, VorbisComment and Podlove), remembered playback position and an advanced sleep timer (shake to reset, lower volume and slow down playback)<br>
-&#8226; Access password-protected feeds and episodes<br>
-&#8226; Take advantage of paged feeds (www.podlove.org/paged-feeds)
-
-KEEP TRACK, SHARE & APPRECIATE<br>
-&#8226; Keep track of the best of the best by marking episodes as favourites<br>
-&#8226; Find that one episode through the playback history or by searching (titles and shownotes)<br>
-&#8226; Share episodes and feeds through advanced social media and email options, the gPodder.net services and via OPML export<br>
-&#8226; Support content creators with Flattr integration including automatic flattring
-
-CONTROL THE SYSTEM<br>
-&#8226; Take control over automated downloading: choose feeds, exclude mobile networks, select specific WiFi networks, require the phone to be charging and set times or intervals<br>
-&#8226; Manage storage by setting the amount of cached episodes, smart deletion (based on your favourites and play status) and selecting your preferred location<br>
-&#8226; Use AntennaPod in your language (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
-&#8226; Adapt to your environment using the light and dark theme<br>
-&#8226; Back-up your subscriptions with the gPodder.net integration and OPML export
-
-<b>Join the AntennaPod community!</b><br>
-AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
-
-GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-www.github.com/AntennaPod/AntennaPod
-
-Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
-https://groups.google.com/forum/#!forum/antennapod
-
-Transifex is the place to help with translations:<br>
-www.transifex.com/antennapod/antennapod
-
-Check out our Beta Testing programme to get the latest features first:<br>
-www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
+&#8226; Importiere oder füge Feeds über das iTunes und gPodder.net Verzeichnis, OMPL Dateien und RSS oder Atom Links hinzu.
+&#8226; Bediene die Wiedergabe von überall: Homescreen-Widget, Benachrichtigung und Koopfhörer- und Bluetooth-Bedienelementen<br>
+&#8226; Genieße das Zuhören auf deine Art mit einstellbarer Abspielgeschwindigkeit, der Unterstützung von Kapiteln (MP3, OGG, Podlove) und ausgereifter Schlummerfunktion (durch Schütteln zurücksetzen, Lautstärke verringern und Geschwindigkeit verlangsamen)
+&#8226; Greife auf Passwort-geschützte Feeds und Episoden zu<br>
+&#8226; Nutze den Vorteil von Paged Feeds (http://www.podlove.org/paged-feeds)
+
+ORDNE, TEILE & GENIEßE
+&#8226; Behalten den Überblück über die Besten der Besten, indem du Episoden als Favoriten markierst
+&#8226; Finde Episoden durch die Liste zuletzt gespielter Episoden oder durch Suche in Titel und Shownotes
+&#8226; Teile Episoden and Feeds über soziale Medien, E-Mail, den gPodder.net-Dienst oder als OPML-Export
+&#8226; Unterstütze die Autoren von Inhalten mit Flattr (inklusive automatischem Flattren)
+
+STEUER DAS SYSTEM<br>
+&#8226; Kontrolliere automatisches Herunterladen: Wähle Feeds aus, schließe mobile Netze aus, suche bestimmte WiFi-Netze aus, setze voraus, dass das Smartphone geladen wird und lege Zeitpunkt oder Intervalle fest<br>
+&#8226; Verwalte deinen Speicherplatz durch das Festlegen der Anzahl gespeicherter Episoden, schlaues Löschen und durch Auswahl des Speicherortes<br>
+&#8226; Benutze AntennaPod in deiner Sprache (EN, DE, CS, NL, NB, JA, PT, ES, SV, CA, UK, FR, KO, TR, ZH)<br>
+&#8226; Passe das Aussehen mit dem hellen oder dunklen Theme an<br>
+&#8226; Sichere deine Abonnements mit gPodder.net oder über den OPML-Export
+
+<b>Trete der AntennaPod-Gemeinschaft bei!</b><br>
+AntennaPod wird aktiv von Freiwilligen weiterentwickelt. Auch du kannst bei der Entwicklung mit Quellcode oder Kommentaren mitwirken!
+
+Wir verwenden GitHub für Funktionswünsche (Feature Requests), Fehlerberichte und zur Beteiligung an der Entwicklung.
+https://www.github.com/AntennaPod/AntennaPod (Englisch)
+
+In unserer Google-Gruppe können Ideen und Lieblingspodcastmomente geteilt werden.
+https://groups.google.com/forum/#!forum/antennapod (Englisch)
+
+Mit Transifex kannst du uns beim Übersetzen helfen:<br>
+https://www.transifex.com/antennapod/antennapod (Englisch)
+
+Probiere unser Beta-Testing-Programm aus, um die neusten Funktionen als Erster zu erhalten:<br>
+https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod (Englisch) \ No newline at end of file
diff --git a/description/el.txt b/description/el.txt
index 14e6a83c8..b4955d18a 100644
--- a/description/el.txt
+++ b/description/el.txt
@@ -30,13 +30,13 @@ CONTROL THE SYSTEM<br>
AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-www.github.com/AntennaPod/AntennaPod
+https://www.github.com/AntennaPod/AntennaPod
Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
https://groups.google.com/forum/#!forum/antennapod
Transifex is the place to help with translations:<br>
-www.transifex.com/antennapod/antennapod
+https://www.transifex.com/antennapod/antennapod
Check out our Beta Testing programme to get the latest features first:<br>
-www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
+https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/description/en.txt b/description/en.txt
index c217b5944..233410c3c 100755
--- a/description/en.txt
+++ b/description/en.txt
@@ -30,13 +30,13 @@ CONTROL THE SYSTEM<br>
AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-www.github.com/AntennaPod/AntennaPod
+https://www.github.com/AntennaPod/AntennaPod
Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
https://groups.google.com/forum/#!forum/antennapod
Transifex is the place to help with translations:<br>
-www.transifex.com/antennapod/antennapod
+https://www.transifex.com/antennapod/antennapod
Check out our Beta Testing programme to get the latest features first:<br>
-www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod
+https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod
diff --git a/description/es.txt b/description/es.txt
index 69edd4905..444819625 100644
--- a/description/es.txt
+++ b/description/es.txt
@@ -30,13 +30,13 @@ CONTROLA EL SISTEMA<br>
AntennaPod está en continuo desarrollo por voluntarios. ¡Tú también puedes contribuir, con tu código o con tus comentarios!
GitHub es el sitio que debes visitar para solicitar características nuevas, reportar fallos y contribuir con código<br>
-www.github.com/AntennaPod/AntennaPod
+https://www.github.com/AntennaPod/AntennaPod
Nuestro Grupo de Google es el sitio para compartir tus ideas, tus momentos favoritos de podcasting y tu gratitud a los voluntarios:<br>
https://groups.google.com/forum/#!forum/antennapod
Transifex es el sitio para ayudar con las traducciones:<br>
-www.transifex.com/antennapod/antennapod
+https://www.transifex.com/antennapod/antennapod
Echa un vistazo a nuestro programa de Beta Testing para ser el primero en usar las nuevas características:<br>
-www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
+https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/description/es_ES.txt b/description/es_ES.txt
index 14e6a83c8..b4955d18a 100644
--- a/description/es_ES.txt
+++ b/description/es_ES.txt
@@ -30,13 +30,13 @@ CONTROL THE SYSTEM<br>
AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-www.github.com/AntennaPod/AntennaPod
+https://www.github.com/AntennaPod/AntennaPod
Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
https://groups.google.com/forum/#!forum/antennapod
Transifex is the place to help with translations:<br>
-www.transifex.com/antennapod/antennapod
+https://www.transifex.com/antennapod/antennapod
Check out our Beta Testing programme to get the latest features first:<br>
-www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
+https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/description/fi.txt b/description/fi.txt
index 14e6a83c8..b4955d18a 100644
--- a/description/fi.txt
+++ b/description/fi.txt
@@ -30,13 +30,13 @@ CONTROL THE SYSTEM<br>
AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-www.github.com/AntennaPod/AntennaPod
+https://www.github.com/AntennaPod/AntennaPod
Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
https://groups.google.com/forum/#!forum/antennapod
Transifex is the place to help with translations:<br>
-www.transifex.com/antennapod/antennapod
+https://www.transifex.com/antennapod/antennapod
Check out our Beta Testing programme to get the latest features first:<br>
-www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
+https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/description/fr.txt b/description/fr.txt
index 3eee69744..4d05a9ca7 100644
--- a/description/fr.txt
+++ b/description/fr.txt
@@ -30,13 +30,13 @@ CONTRÔLER LE SYSTÈME<br>
AntennaPod est développé activement par des volontaires. Vous pouvez aussi contribuer avec du code ou des commentaires !
GitHub est l'endroit où aller pour demander de nouvelles options, faire part de bug ou pour contribuer au code :<br>
-www.github.com/AntennaPod/AntennaPod
+https://www.github.com/AntennaPod/AntennaPod
Notre groupe Google est l'endroit où aller pour partager vos idées, moments préférés de podcast et vos remerciements aux volontaires :<br>
https://groups.google.com/forum/#!forum/antennapod
Transifex est le lieu où vous pouvez aider à la traduction :<br>
-www.transifex.com/antennapod/antennapod
+https://www.transifex.com/antennapod/antennapod
Jetez un coup d’œil à notre programme de version Beta pour bénéficier des dernières options :<br>
-www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
+https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/description/he_IL.txt b/description/he_IL.txt
index 14e6a83c8..b4955d18a 100644
--- a/description/he_IL.txt
+++ b/description/he_IL.txt
@@ -30,13 +30,13 @@ CONTROL THE SYSTEM<br>
AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-www.github.com/AntennaPod/AntennaPod
+https://www.github.com/AntennaPod/AntennaPod
Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
https://groups.google.com/forum/#!forum/antennapod
Transifex is the place to help with translations:<br>
-www.transifex.com/antennapod/antennapod
+https://www.transifex.com/antennapod/antennapod
Check out our Beta Testing programme to get the latest features first:<br>
-www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
+https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/description/hi_IN.txt b/description/hi_IN.txt
index 14e6a83c8..b4955d18a 100644
--- a/description/hi_IN.txt
+++ b/description/hi_IN.txt
@@ -30,13 +30,13 @@ CONTROL THE SYSTEM<br>
AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-www.github.com/AntennaPod/AntennaPod
+https://www.github.com/AntennaPod/AntennaPod
Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
https://groups.google.com/forum/#!forum/antennapod
Transifex is the place to help with translations:<br>
-www.transifex.com/antennapod/antennapod
+https://www.transifex.com/antennapod/antennapod
Check out our Beta Testing programme to get the latest features first:<br>
-www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
+https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/description/hu.txt b/description/hu.txt
index 14e6a83c8..b4955d18a 100644
--- a/description/hu.txt
+++ b/description/hu.txt
@@ -30,13 +30,13 @@ CONTROL THE SYSTEM<br>
AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-www.github.com/AntennaPod/AntennaPod
+https://www.github.com/AntennaPod/AntennaPod
Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
https://groups.google.com/forum/#!forum/antennapod
Transifex is the place to help with translations:<br>
-www.transifex.com/antennapod/antennapod
+https://www.transifex.com/antennapod/antennapod
Check out our Beta Testing programme to get the latest features first:<br>
-www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
+https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/description/id.txt b/description/id.txt
index 14e6a83c8..b4955d18a 100644
--- a/description/id.txt
+++ b/description/id.txt
@@ -30,13 +30,13 @@ CONTROL THE SYSTEM<br>
AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-www.github.com/AntennaPod/AntennaPod
+https://www.github.com/AntennaPod/AntennaPod
Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
https://groups.google.com/forum/#!forum/antennapod
Transifex is the place to help with translations:<br>
-www.transifex.com/antennapod/antennapod
+https://www.transifex.com/antennapod/antennapod
Check out our Beta Testing programme to get the latest features first:<br>
-www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
+https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/description/it.txt b/description/it.txt
index 14e6a83c8..b4955d18a 100644
--- a/description/it.txt
+++ b/description/it.txt
@@ -30,13 +30,13 @@ CONTROL THE SYSTEM<br>
AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-www.github.com/AntennaPod/AntennaPod
+https://www.github.com/AntennaPod/AntennaPod
Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
https://groups.google.com/forum/#!forum/antennapod
Transifex is the place to help with translations:<br>
-www.transifex.com/antennapod/antennapod
+https://www.transifex.com/antennapod/antennapod
Check out our Beta Testing programme to get the latest features first:<br>
-www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
+https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/description/it_IT.txt b/description/it_IT.txt
index 59854c7d0..dcf36da21 100644
--- a/description/it_IT.txt
+++ b/description/it_IT.txt
@@ -30,13 +30,13 @@ CONTROLLA IL SISTEMA<br>
AntennaPod è sviluppato da volontari. Anche tu puoi contribuire, con il codice o con dei commenti!
GitHub è il posto nel quale fare richieste, segnalare bug e contribuire allo sviluppo:<br>
-www.github.com/AntennaPod/AntennaPod
+https://www.github.com/AntennaPod/AntennaPod
Il nostro Gruppo Google è il posto dove condividere le tue idee, podcast preferiti e gratitudine a tutti i nostri volontari:<br>
https://groups.google.com/forum/#!forum/antennapod
Transifex è il posto dove puoi aiutare a tradurre AntennaPod:<br>
-www.transifex.com/antennapod/antennapod
+https://www.transifex.com/antennapod/antennapod
Check out our Beta Testing programme to get the latest features first:<br>
-www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
+https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/description/ja.txt b/description/ja.txt
index 64ebaf21c..c7b518201 100644
--- a/description/ja.txt
+++ b/description/ja.txt
@@ -30,13 +30,13 @@ AntennaPodは、独自のポッドキャスターから、BBC、NPR、CNNなど
AntennaPod はボランティアによって活発に開発中です。コードやコメントで、あなたもも貢献することができます!
GitHubは、機能のリクエスト、バグの報告、コードの貢献のための場所です:<br>
-www.github.com/AntennaPod/AntennaPod
+https://www.github.com/AntennaPod/AntennaPod
私たちのGoogleグループは、あなたのアイデア、お気に入りのポッドキャスティングモーメント、感謝を、すべてのボランティアと共有するための場所で:<br>
https://groups.google.com/forum/#!forum/antennapod
Transifexは翻訳を支援するための場所です:<br>
-www.transifex.com/antennapod/antennapod
+https://www.transifex.com/antennapod/antennapod
私たちのベータテストプログラムをチェックして、最新機能を最初に入手してください:<br>
-www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
+https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/description/kn_IN.txt b/description/kn_IN.txt
index 14e6a83c8..b4955d18a 100644
--- a/description/kn_IN.txt
+++ b/description/kn_IN.txt
@@ -30,13 +30,13 @@ CONTROL THE SYSTEM<br>
AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-www.github.com/AntennaPod/AntennaPod
+https://www.github.com/AntennaPod/AntennaPod
Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
https://groups.google.com/forum/#!forum/antennapod
Transifex is the place to help with translations:<br>
-www.transifex.com/antennapod/antennapod
+https://www.transifex.com/antennapod/antennapod
Check out our Beta Testing programme to get the latest features first:<br>
-www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
+https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/description/ko.txt b/description/ko.txt
index 14e6a83c8..b4955d18a 100644
--- a/description/ko.txt
+++ b/description/ko.txt
@@ -30,13 +30,13 @@ CONTROL THE SYSTEM<br>
AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-www.github.com/AntennaPod/AntennaPod
+https://www.github.com/AntennaPod/AntennaPod
Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
https://groups.google.com/forum/#!forum/antennapod
Transifex is the place to help with translations:<br>
-www.transifex.com/antennapod/antennapod
+https://www.transifex.com/antennapod/antennapod
Check out our Beta Testing programme to get the latest features first:<br>
-www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
+https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/description/ko_KR.txt b/description/ko_KR.txt
index 14e6a83c8..b4955d18a 100644
--- a/description/ko_KR.txt
+++ b/description/ko_KR.txt
@@ -30,13 +30,13 @@ CONTROL THE SYSTEM<br>
AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-www.github.com/AntennaPod/AntennaPod
+https://www.github.com/AntennaPod/AntennaPod
Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
https://groups.google.com/forum/#!forum/antennapod
Transifex is the place to help with translations:<br>
-www.transifex.com/antennapod/antennapod
+https://www.transifex.com/antennapod/antennapod
Check out our Beta Testing programme to get the latest features first:<br>
-www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
+https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/description/nb_NO.txt b/description/nb_NO.txt
index 14e6a83c8..b4955d18a 100644
--- a/description/nb_NO.txt
+++ b/description/nb_NO.txt
@@ -30,13 +30,13 @@ CONTROL THE SYSTEM<br>
AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-www.github.com/AntennaPod/AntennaPod
+https://www.github.com/AntennaPod/AntennaPod
Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
https://groups.google.com/forum/#!forum/antennapod
Transifex is the place to help with translations:<br>
-www.transifex.com/antennapod/antennapod
+https://www.transifex.com/antennapod/antennapod
Check out our Beta Testing programme to get the latest features first:<br>
-www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
+https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/description/nl.txt b/description/nl.txt
index 14e6a83c8..926a7a70f 100644
--- a/description/nl.txt
+++ b/description/nl.txt
@@ -1,4 +1,4 @@
-Easy-to-use, flexible and open-source podcast manager and player
+Gemakkelijk te gebruiken, flexibele en open-source podcast manager en speler
AntennaPod is a podcast manager and player that gives you instant access to millions of free and paid podcasts, from independent podcasters to large publishing houses such as the BBC, NPR and CNN. Add, import and export their feeds hassle-free using the iTunes podcast database, OPML files or simple RSS URLs. Save effort, battery power and mobile data usage with powerful automation controls for downloading episodes (specify times, intervals and WiFi networks) and deleting episodes (based your favourites and delay settings).<br>
But most importantly: Download, stream or queue episodes and enjoy them the way you like with adjustable playback speeds, chapter support and a sleep timer. You can even show your love to the content creators with our Flattr integration.
@@ -30,13 +30,13 @@ CONTROL THE SYSTEM<br>
AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-www.github.com/AntennaPod/AntennaPod
+https://www.github.com/AntennaPod/AntennaPod
Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
https://groups.google.com/forum/#!forum/antennapod
Transifex is the place to help with translations:<br>
-www.transifex.com/antennapod/antennapod
+https://www.transifex.com/antennapod/antennapod
Check out our Beta Testing programme to get the latest features first:<br>
-www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
+https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/description/no.txt b/description/no.txt
index 14e6a83c8..b4955d18a 100644
--- a/description/no.txt
+++ b/description/no.txt
@@ -30,13 +30,13 @@ CONTROL THE SYSTEM<br>
AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-www.github.com/AntennaPod/AntennaPod
+https://www.github.com/AntennaPod/AntennaPod
Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
https://groups.google.com/forum/#!forum/antennapod
Transifex is the place to help with translations:<br>
-www.transifex.com/antennapod/antennapod
+https://www.transifex.com/antennapod/antennapod
Check out our Beta Testing programme to get the latest features first:<br>
-www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
+https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/description/pl.txt b/description/pl.txt
index 14e6a83c8..b4955d18a 100644
--- a/description/pl.txt
+++ b/description/pl.txt
@@ -30,13 +30,13 @@ CONTROL THE SYSTEM<br>
AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-www.github.com/AntennaPod/AntennaPod
+https://www.github.com/AntennaPod/AntennaPod
Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
https://groups.google.com/forum/#!forum/antennapod
Transifex is the place to help with translations:<br>
-www.transifex.com/antennapod/antennapod
+https://www.transifex.com/antennapod/antennapod
Check out our Beta Testing programme to get the latest features first:<br>
-www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
+https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/description/pl_PL.txt b/description/pl_PL.txt
index 14e6a83c8..b4955d18a 100644
--- a/description/pl_PL.txt
+++ b/description/pl_PL.txt
@@ -30,13 +30,13 @@ CONTROL THE SYSTEM<br>
AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-www.github.com/AntennaPod/AntennaPod
+https://www.github.com/AntennaPod/AntennaPod
Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
https://groups.google.com/forum/#!forum/antennapod
Transifex is the place to help with translations:<br>
-www.transifex.com/antennapod/antennapod
+https://www.transifex.com/antennapod/antennapod
Check out our Beta Testing programme to get the latest features first:<br>
-www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
+https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/description/pt.txt b/description/pt.txt
index 1829d3341..45a3f03d9 100644
--- a/description/pt.txt
+++ b/description/pt.txt
@@ -1,4 +1,4 @@
-Gestor e reprodutor de podcasts simples, flexível e Open Souce
+Gestor e reprodutor de podcasts simples, flexível e open souce
O AntennaPod é um gestor de podcasts que lhe permite aceder a milhões de podcasts (gratuitos ou pagos), a partir de diversas fontes tais como as estações BBC, NPR e CNN. A adição de fontes é muito fácil através das base de dados iTunes ou gPodder, ficheiros OPML ou fontes RSS. Poupe tempo, economize energia e dados móveis através dos mecanismos de controlo de transferência de episódios (possibilidade de especificar intervalos ou horas para as transferências e redes WiFi) e de eliminação de episódios (de acordo com as suas preferências).<br>
Mas ainda mais importante: pode transferir, emitir ou colocar episódios na lista de reprodução ao seu gosto, pode utilizar velocidades variáveis de reprodução, tem suporte a capítulos e um temporizador. Pode também mostrar o seu apreço aos disponibilizadores dos episódios através do serviço Flattr.
@@ -30,13 +30,13 @@ Controlar o sistema<br>
O AntennaPod é desenvolvido por voluntários. Você também pode contribuir na programação ou reportando os erros encontrados!
O GitHub é o local certo para os pedidos de funcionalidades, relatórios de erros e contribuições:<br>
-www.github.com/AntennaPod/AntennaPod
+https://www.github.com/AntennaPod/AntennaPod
O nosso grupo Google é o local certo para partilhar ideias e agradecer aos nossos voluntários:<br>
https://groups.google.com/forum/#!forum/antennapod
O Transifex é o local no qual pode ajudar a traduzir a aplicação:<br>
-www.transifex.com/antennapod/antennapod
+https://www.transifex.com/antennapod/antennapod
Junte-se ao nosso programa de testes para obter as funcionalidades mais recentes:<br>
-www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
+https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/description/pt_BR.txt b/description/pt_BR.txt
index 14e6a83c8..b4955d18a 100644
--- a/description/pt_BR.txt
+++ b/description/pt_BR.txt
@@ -30,13 +30,13 @@ CONTROL THE SYSTEM<br>
AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-www.github.com/AntennaPod/AntennaPod
+https://www.github.com/AntennaPod/AntennaPod
Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
https://groups.google.com/forum/#!forum/antennapod
Transifex is the place to help with translations:<br>
-www.transifex.com/antennapod/antennapod
+https://www.transifex.com/antennapod/antennapod
Check out our Beta Testing programme to get the latest features first:<br>
-www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
+https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/description/ro_RO.txt b/description/ro_RO.txt
index 14e6a83c8..b4955d18a 100644
--- a/description/ro_RO.txt
+++ b/description/ro_RO.txt
@@ -30,13 +30,13 @@ CONTROL THE SYSTEM<br>
AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-www.github.com/AntennaPod/AntennaPod
+https://www.github.com/AntennaPod/AntennaPod
Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
https://groups.google.com/forum/#!forum/antennapod
Transifex is the place to help with translations:<br>
-www.transifex.com/antennapod/antennapod
+https://www.transifex.com/antennapod/antennapod
Check out our Beta Testing programme to get the latest features first:<br>
-www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
+https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/description/ru_RU.txt b/description/ru_RU.txt
index 14e6a83c8..b4955d18a 100644
--- a/description/ru_RU.txt
+++ b/description/ru_RU.txt
@@ -30,13 +30,13 @@ CONTROL THE SYSTEM<br>
AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-www.github.com/AntennaPod/AntennaPod
+https://www.github.com/AntennaPod/AntennaPod
Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
https://groups.google.com/forum/#!forum/antennapod
Transifex is the place to help with translations:<br>
-www.transifex.com/antennapod/antennapod
+https://www.transifex.com/antennapod/antennapod
Check out our Beta Testing programme to get the latest features first:<br>
-www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
+https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/description/sv_SE.txt b/description/sv_SE.txt
index 3c1b98bfa..5455c7d78 100644
--- a/description/sv_SE.txt
+++ b/description/sv_SE.txt
@@ -1,4 +1,4 @@
-Användarvänlig, flexibel podcasthanterare och spelare med öppen källkod
+Användarvänlig och flexibel podcasthanterare och spelare med öppen källkod
AntennaPod är en podcasthanterare och spelare som ger dig omedelbar tillgång till millioner av gratis och betalda podcasts, allt ifrån oberoende podcasters till publiceringsjättar som BBC, NPR och CNN. Lägg till, importera och exportera enkelt deras flöden med hjälp av iTunes podcastdatabas, OPML filer eller enkla RSS URL:er. Spara tid, batterikraft och mobildata med kraftfull automatisering för nedladdning (specifiera tider, intervall och WiFi-nätverk) och borttagning av episoder (baserat på dina favoriter och fördröjningsinställningar).<br>
Men viktigast: Ladda ner, strömma eller köa episoder och avnjut dem på ditt sätt med justerbar uppspelningshastighet, kapitelstöd och en sovtimer. Du kan till och med visa din uppskattning av innehållsskaparna med vår integrering av Flattr.
@@ -30,13 +30,13 @@ KONTROLLERA SYSTEMET<br>
AntennaPod är under aktiv utveckling av volontärer. Du kan också bidra, med kod eller kommentarer!
GitHub är platsen att gå till för att be om funktioner, skapa buggrapporter eller bidra med kod:<br>
-www.github.com/AntennaPod/AntennaPod
+https://www.github.com/AntennaPod/AntennaPod
Vår Google Group är platsen för att dela idéer, dina favoritögonblick med podcasting och din uppskattning till volontärerna:<br>
https://groups.google.com/forum/#!forum/antennapod
Transifex är platsen att gå till för att hjälpa till med översättningen:<br>
-www.transifex.com/antennapod/antennapod
+https://www.transifex.com/antennapod/antennapod
Kolla in vårat Beta Testing program för att få de senaste funktionerna först:<br>
-www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
+https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/description/tr.txt b/description/tr.txt
index 14e6a83c8..b4955d18a 100644
--- a/description/tr.txt
+++ b/description/tr.txt
@@ -30,13 +30,13 @@ CONTROL THE SYSTEM<br>
AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-www.github.com/AntennaPod/AntennaPod
+https://www.github.com/AntennaPod/AntennaPod
Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
https://groups.google.com/forum/#!forum/antennapod
Transifex is the place to help with translations:<br>
-www.transifex.com/antennapod/antennapod
+https://www.transifex.com/antennapod/antennapod
Check out our Beta Testing programme to get the latest features first:<br>
-www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
+https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/description/uk_UA.txt b/description/uk_UA.txt
index a123f3854..b4c604a4f 100644
--- a/description/uk_UA.txt
+++ b/description/uk_UA.txt
@@ -30,13 +30,13 @@ AntennaPod це менеджер подкастів та плейер що да
AntennaPod швидко розвивається волонтерами. Ви також маєте змогу допомогти, кодом або зауваженнями!
Долучитись до проекта, повідомити про ваші побажання та про помилки можна на GitHub:<br>
-www.github.com/AntennaPod/AntennaPod
+https://www.github.com/AntennaPod/AntennaPod
В нашій групі на Google можна поділитись ідеями, улюбленими моментами з подкастінга та добрими побажаннями волонтерам:<br>
https://groups.google.com/forum/#!forum/antennapod
Допомагайте з перекладом на Transifex:<br>
-www.transifex.com/antennapod/antennapod
+https://www.transifex.com/antennapod/antennapod
Зверніть увагу на нашу програму для бета тестування якщо бажаєте получати найновіші версії в першу чергу:<br>
-www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
+https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/description/vi.txt b/description/vi.txt
index 14e6a83c8..b4955d18a 100644
--- a/description/vi.txt
+++ b/description/vi.txt
@@ -30,13 +30,13 @@ CONTROL THE SYSTEM<br>
AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-www.github.com/AntennaPod/AntennaPod
+https://www.github.com/AntennaPod/AntennaPod
Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
https://groups.google.com/forum/#!forum/antennapod
Transifex is the place to help with translations:<br>
-www.transifex.com/antennapod/antennapod
+https://www.transifex.com/antennapod/antennapod
Check out our Beta Testing programme to get the latest features first:<br>
-www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
+https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/description/vi_VN.txt b/description/vi_VN.txt
index 14e6a83c8..b4955d18a 100644
--- a/description/vi_VN.txt
+++ b/description/vi_VN.txt
@@ -30,13 +30,13 @@ CONTROL THE SYSTEM<br>
AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-www.github.com/AntennaPod/AntennaPod
+https://www.github.com/AntennaPod/AntennaPod
Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
https://groups.google.com/forum/#!forum/antennapod
Transifex is the place to help with translations:<br>
-www.transifex.com/antennapod/antennapod
+https://www.transifex.com/antennapod/antennapod
Check out our Beta Testing programme to get the latest features first:<br>
-www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
+https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/description/zh_CN.txt b/description/zh_CN.txt
index 14e6a83c8..b4955d18a 100644
--- a/description/zh_CN.txt
+++ b/description/zh_CN.txt
@@ -30,13 +30,13 @@ CONTROL THE SYSTEM<br>
AntennaPod is under active development by volunteers. You can contribute too, with code or with comment!
GitHub is the place to go for feature requests, bug reports and code contributions:<br>
-www.github.com/AntennaPod/AntennaPod
+https://www.github.com/AntennaPod/AntennaPod
Our Google Group is the place to share your ideas, favourite podcasting moments and gratitude to all the volunteers:<br>
https://groups.google.com/forum/#!forum/antennapod
Transifex is the place to help with translations:<br>
-www.transifex.com/antennapod/antennapod
+https://www.transifex.com/antennapod/antennapod
Check out our Beta Testing programme to get the latest features first:<br>
-www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
+https://www.github.com/AntennaPod/AntennaPod/wiki/Help-test-AntennaPod \ No newline at end of file
diff --git a/gradlew.bat b/gradlew.bat
index aec99730b..8a0b282aa 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -1,90 +1,90 @@
-@if "%DEBUG%" == "" @echo off
-@rem ##########################################################################
-@rem
-@rem Gradle startup script for Windows
-@rem
-@rem ##########################################################################
-
-@rem Set local scope for the variables with windows NT shell
-if "%OS%"=="Windows_NT" setlocal
-
-@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS=
-
-set DIRNAME=%~dp0
-if "%DIRNAME%" == "" set DIRNAME=.
-set APP_BASE_NAME=%~n0
-set APP_HOME=%DIRNAME%
-
-@rem Find java.exe
-if defined JAVA_HOME goto findJavaFromJavaHome
-
-set JAVA_EXE=java.exe
-%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto init
-
-echo.
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:findJavaFromJavaHome
-set JAVA_HOME=%JAVA_HOME:"=%
-set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-
-if exist "%JAVA_EXE%" goto init
-
-echo.
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:init
-@rem Get command-line arguments, handling Windowz variants
-
-if not "%OS%" == "Windows_NT" goto win9xME_args
-if "%@eval[2+2]" == "4" goto 4NT_args
-
-:win9xME_args
-@rem Slurp the command line arguments.
-set CMD_LINE_ARGS=
-set _SKIP=2
-
-:win9xME_args_slurp
-if "x%~1" == "x" goto execute
-
-set CMD_LINE_ARGS=%*
-goto execute
-
-:4NT_args
-@rem Get arguments from the 4NT Shell from JP Software
-set CMD_LINE_ARGS=%$
-
-:execute
-@rem Setup the command line
-
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
-
-@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
-
-:end
-@rem End local scope for the variables with windows NT shell
-if "%ERRORLEVEL%"=="0" goto mainEnd
-
-:fail
-rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
-rem the _cmd.exe /c_ return code!
-if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
-exit /b 1
-
-:mainEnd
-if "%OS%"=="Windows_NT" endlocal
-
-:omega
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/makeRelease.sh b/makeRelease.sh
new file mode 100755
index 000000000..cca75f7c2
--- /dev/null
+++ b/makeRelease.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+set -e
+DEST=$2
+VERSION_NAME=$1
+
+# need to get rid of this so that it gets regenerated
+# probably a way to solve this in Gradle too...
+rm -f app/src/main/assets/about.html
+./gradlew clean assembleDebug assembleRelease
+cp app/build/outputs/apk/app-debug.apk $DEST/AntennaPod_${VERSION_NAME}_debug.apk
+cp app/build/outputs/apk/app-release.apk $DEST/AntennaPod_${VERSION_NAME}_release.apk
diff --git a/project.properties b/project.properties
index 57e7d75fe..a8561fa99 100644
--- a/project.properties
+++ b/project.properties
@@ -10,5 +10,4 @@
# Project target.
proguard.config=proguard.cfg
target=android-19
-android.library.reference.1=submodules/dslv/library