summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/EpisodeFilterDialog.java21
-rw-r--r--app/src/main/res/layout/episode_filter_dialog.xml17
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/DBUpgrader.java4
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java6
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/mapper/FeedPreferencesCursorMapper.java4
-rw-r--r--core/src/main/res/values/strings.xml1
-rw-r--r--core/src/test/java/de/danoeh/antennapod/core/feed/FeedFilterTest.java31
-rw-r--r--model/src/main/java/de/danoeh/antennapod/model/feed/FeedFilter.java35
8 files changed, 111 insertions, 8 deletions
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/EpisodeFilterDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/EpisodeFilterDialog.java
index ee19a0339..595f37e40 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/EpisodeFilterDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/EpisodeFilterDialog.java
@@ -2,6 +2,7 @@ package de.danoeh.antennapod.dialog;
import android.content.Context;
import android.view.View;
+import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.RadioButton;
@@ -14,7 +15,6 @@ import de.danoeh.antennapod.model.feed.FeedFilter;
* Displays a dialog with a text box for filtering episodes and two radio buttons for exclusion/inclusion
*/
public abstract class EpisodeFilterDialog extends AlertDialog.Builder {
-
private final FeedFilter initialFilter;
public EpisodeFilterDialog(Context context, FeedFilter filter) {
@@ -26,8 +26,10 @@ public abstract class EpisodeFilterDialog extends AlertDialog.Builder {
setView(rootView);
final EditText etxtEpisodeFilterText = rootView.findViewById(R.id.etxtEpisodeFilterText);
+ final EditText etxtEpisodeFilterDurationText = rootView.findViewById(R.id.etxtEpisodeFilterDurationText);
final RadioButton radioInclude = rootView.findViewById(R.id.radio_filter_include);
final RadioButton radioExclude = rootView.findViewById(R.id.radio_filter_exclude);
+ final CheckBox checkboxDuration = rootView.findViewById(R.id.checkbox_filter_duration);
if (initialFilter.includeOnly()) {
radioInclude.setChecked(true);
@@ -40,18 +42,31 @@ public abstract class EpisodeFilterDialog extends AlertDialog.Builder {
radioInclude.setChecked(false);
etxtEpisodeFilterText.setText("");
}
+ if (initialFilter.hasMinimalDurationFilter()) {
+ checkboxDuration.setChecked(true);
+ // Store minimal duration in seconds, show in minutes
+ etxtEpisodeFilterDurationText.setText(String.valueOf(initialFilter.getMinimalDurationFilter() / 60));
+ }
setNegativeButton(R.string.cancel_label, null);
setPositiveButton(R.string.confirm_label, (dialog, which) -> {
String includeString = "";
String excludeString = "";
+ int minimalDuration = -1;
if (radioInclude.isChecked()) {
includeString = etxtEpisodeFilterText.getText().toString();
} else {
excludeString = etxtEpisodeFilterText.getText().toString();
}
-
- onConfirmed(new FeedFilter(includeString, excludeString));
+ if (checkboxDuration.isChecked()) {
+ try {
+ // Store minimal duration in seconds
+ minimalDuration = Integer.parseInt(etxtEpisodeFilterDurationText.getText().toString()) * 60;
+ } catch (NumberFormatException e) {
+ // Do not change anything on error
+ }
+ }
+ onConfirmed(new FeedFilter(includeString, excludeString, minimalDuration));
}
);
}
diff --git a/app/src/main/res/layout/episode_filter_dialog.xml b/app/src/main/res/layout/episode_filter_dialog.xml
index 9661a8e72..e8672c2f3 100644
--- a/app/src/main/res/layout/episode_filter_dialog.xml
+++ b/app/src/main/res/layout/episode_filter_dialog.xml
@@ -40,4 +40,21 @@
android:minLines="1"
android:scrollbars="vertical" />
+ <CheckBox
+ android:id="@+id/checkbox_filter_duration"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/episode_filters_duration" />
+
+ <EditText
+ android:id="@+id/etxtEpisodeFilterDurationText"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:cursorVisible="true"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ android:inputType="numberSigned"
+ android:lines="1" />
+
</LinearLayout>
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBUpgrader.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBUpgrader.java
index 46ab7502b..b3eec8c1d 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBUpgrader.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBUpgrader.java
@@ -322,6 +322,10 @@ class DBUpgrader {
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
+ " ADD COLUMN " + PodDBAdapter.KEY_FEED_TAGS + " TEXT;");
}
+ if (oldVersion < 2050000) {
+ db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
+ + " ADD COLUMN " + PodDBAdapter.KEY_MINIMAL_DURATION_FILTER + " INTEGER DEFAULT -1");
+ }
}
}
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 55cfafbbb..f1364255d 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
@@ -53,7 +53,7 @@ public class PodDBAdapter {
private static final String TAG = "PodDBAdapter";
public static final String DATABASE_NAME = "Antennapod.db";
- public static final int VERSION = 2030000;
+ public static final int VERSION = 2050000;
/**
* Maximum number of arguments for IN-operator.
@@ -113,6 +113,7 @@ public class PodDBAdapter {
public static final String KEY_LAST_PLAYED_TIME = "last_played_time";
public static final String KEY_INCLUDE_FILTER = "include_filter";
public static final String KEY_EXCLUDE_FILTER = "exclude_filter";
+ public static final String KEY_MINIMAL_DURATION_FILTER = "minimal_duration_filter";
public static final String KEY_FEED_PLAYBACK_SPEED = "feed_playback_speed";
public static final String KEY_FEED_SKIP_INTRO = "feed_skip_intro";
public static final String KEY_FEED_SKIP_ENDING = "feed_skip_ending";
@@ -145,6 +146,7 @@ public class PodDBAdapter {
+ KEY_PASSWORD + " TEXT,"
+ KEY_INCLUDE_FILTER + " TEXT DEFAULT '',"
+ KEY_EXCLUDE_FILTER + " TEXT DEFAULT '',"
+ + KEY_MINIMAL_DURATION_FILTER + " INTEGER DEFAULT -1,"
+ KEY_KEEP_UPDATED + " INTEGER DEFAULT 1,"
+ KEY_IS_PAGED + " INTEGER DEFAULT 0,"
+ KEY_NEXT_PAGE_LINK + " TEXT,"
@@ -257,6 +259,7 @@ public class PodDBAdapter {
TABLE_NAME_FEEDS + "." + KEY_FEED_VOLUME_ADAPTION,
TABLE_NAME_FEEDS + "." + KEY_INCLUDE_FILTER,
TABLE_NAME_FEEDS + "." + KEY_EXCLUDE_FILTER,
+ TABLE_NAME_FEEDS + "." + KEY_MINIMAL_DURATION_FILTER,
TABLE_NAME_FEEDS + "." + KEY_FEED_PLAYBACK_SPEED,
TABLE_NAME_FEEDS + "." + KEY_FEED_TAGS,
TABLE_NAME_FEEDS + "." + KEY_FEED_SKIP_INTRO,
@@ -450,6 +453,7 @@ public class PodDBAdapter {
values.put(KEY_PASSWORD, prefs.getPassword());
values.put(KEY_INCLUDE_FILTER, prefs.getFilter().getIncludeFilter());
values.put(KEY_EXCLUDE_FILTER, prefs.getFilter().getExcludeFilter());
+ values.put(KEY_MINIMAL_DURATION_FILTER, prefs.getFilter().getMinimalDurationFilter());
values.put(KEY_FEED_PLAYBACK_SPEED, prefs.getFeedPlaybackSpeed());
values.put(KEY_FEED_TAGS, prefs.getTagsAsString());
values.put(KEY_FEED_SKIP_INTRO, prefs.getFeedSkipIntro());
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/mapper/FeedPreferencesCursorMapper.java b/core/src/main/java/de/danoeh/antennapod/core/storage/mapper/FeedPreferencesCursorMapper.java
index cab6ea618..cd46bcf94 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/mapper/FeedPreferencesCursorMapper.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/mapper/FeedPreferencesCursorMapper.java
@@ -29,6 +29,7 @@ public abstract class FeedPreferencesCursorMapper {
int indexPassword = cursor.getColumnIndex(PodDBAdapter.KEY_PASSWORD);
int indexIncludeFilter = cursor.getColumnIndex(PodDBAdapter.KEY_INCLUDE_FILTER);
int indexExcludeFilter = cursor.getColumnIndex(PodDBAdapter.KEY_EXCLUDE_FILTER);
+ int indexMinimalDurationFilter = cursor.getColumnIndex(PodDBAdapter.KEY_MINIMAL_DURATION_FILTER);
int indexFeedPlaybackSpeed = cursor.getColumnIndex(PodDBAdapter.KEY_FEED_PLAYBACK_SPEED);
int indexAutoSkipIntro = cursor.getColumnIndex(PodDBAdapter.KEY_FEED_SKIP_INTRO);
int indexAutoSkipEnding = cursor.getColumnIndex(PodDBAdapter.KEY_FEED_SKIP_ENDING);
@@ -47,6 +48,7 @@ public abstract class FeedPreferencesCursorMapper {
String password = cursor.getString(indexPassword);
String includeFilter = cursor.getString(indexIncludeFilter);
String excludeFilter = cursor.getString(indexExcludeFilter);
+ int minimalDurationFilter = cursor.getInt(indexMinimalDurationFilter);
float feedPlaybackSpeed = cursor.getFloat(indexFeedPlaybackSpeed);
int feedAutoSkipIntro = cursor.getInt(indexAutoSkipIntro);
int feedAutoSkipEnding = cursor.getInt(indexAutoSkipEnding);
@@ -62,7 +64,7 @@ public abstract class FeedPreferencesCursorMapper {
volumeAdaptionSetting,
username,
password,
- new FeedFilter(includeFilter, excludeFilter),
+ new FeedFilter(includeFilter, excludeFilter, minimalDurationFilter),
feedPlaybackSpeed,
feedAutoSkipIntro,
feedAutoSkipEnding,
diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml
index 390fe7d95..780de55ac 100644
--- a/core/src/main/res/values/strings.xml
+++ b/core/src/main/res/values/strings.xml
@@ -702,6 +702,7 @@
<string name="episode_filters_description">List of terms used to decide if an episode should be included or excluded when auto downloading</string>
<string name="episode_filters_include">Include</string>
<string name="episode_filters_exclude">Exclude</string>
+ <string name="episode_filters_duration">Minimal Duration (in minutes)</string>
<string name="episode_filters_hint">Single words \n\"Multiple Words\"</string>
<string name="keep_updated">Keep Updated</string>
<string name="keep_updated_summary">Include this podcast when (auto-)refreshing all podcasts</string>
diff --git a/core/src/test/java/de/danoeh/antennapod/core/feed/FeedFilterTest.java b/core/src/test/java/de/danoeh/antennapod/core/feed/FeedFilterTest.java
index 4ad578727..3840f6387 100644
--- a/core/src/test/java/de/danoeh/antennapod/core/feed/FeedFilterTest.java
+++ b/core/src/test/java/de/danoeh/antennapod/core/feed/FeedFilterTest.java
@@ -1,7 +1,10 @@
package de.danoeh.antennapod.core.feed;
+import de.danoeh.antennapod.core.util.Converter;
import de.danoeh.antennapod.model.feed.FeedFilter;
import de.danoeh.antennapod.model.feed.FeedItem;
+import de.danoeh.antennapod.model.feed.FeedMedia;
+
import org.junit.Test;
import static org.junit.Assert.assertEquals;
@@ -125,4 +128,32 @@ public class FeedFilterTest {
assertFalse(filter.shouldAutoDownload(doNotDownload2));
}
+ @Test
+ public void testMinimalDurationFilter() {
+ FeedItem download = new FeedItem();
+ download.setTitle("Hello friend!");
+ FeedMedia downloadMedia = FeedMediaMother.anyFeedMedia();
+ downloadMedia.setDuration(Converter.durationStringShortToMs("05:00", false));
+ download.setMedia(downloadMedia);
+ // because duration of the media in unknown
+ FeedItem download2 = new FeedItem();
+ download2.setTitle("Hello friend!");
+ FeedMedia unknownDurationMedia = FeedMediaMother.anyFeedMedia();
+ download2.setMedia(unknownDurationMedia);
+ // because it is not long enough
+ FeedItem doNotDownload = new FeedItem();
+ doNotDownload.setTitle("Hello friend!");
+ FeedMedia doNotDownloadMedia = FeedMediaMother.anyFeedMedia();
+ doNotDownloadMedia.setDuration(Converter.durationStringShortToMs("02:00", false));
+ doNotDownload.setMedia(doNotDownloadMedia);
+
+ int minimalDurationFilter = 3 * 60;
+ FeedFilter filter = new FeedFilter("", "", minimalDurationFilter);
+
+ assertTrue(filter.hasMinimalDurationFilter());
+ assertTrue(filter.shouldAutoDownload(download));
+ assertFalse(filter.shouldAutoDownload(doNotDownload));
+ assertTrue(filter.shouldAutoDownload(download2));
+ }
+
}
diff --git a/model/src/main/java/de/danoeh/antennapod/model/feed/FeedFilter.java b/model/src/main/java/de/danoeh/antennapod/model/feed/FeedFilter.java
index 31d263b24..3b35fe5bd 100644
--- a/model/src/main/java/de/danoeh/antennapod/model/feed/FeedFilter.java
+++ b/model/src/main/java/de/danoeh/antennapod/model/feed/FeedFilter.java
@@ -10,18 +10,24 @@ import java.util.regex.Pattern;
public class FeedFilter implements Serializable {
private final String includeFilter;
private final String excludeFilter;
+ private final int minimalDuration;
public FeedFilter() {
- this("", "");
+ this("", "", -1);
}
- public FeedFilter(String includeFilter, String excludeFilter) {
+ public FeedFilter(String includeFilter, String excludeFilter, int minimalDuration) {
// We're storing the strings and not the parsed terms because
// 1. It's easier to show the user exactly what they typed in this way
// (we don't have to recreate it)
// 2. We don't know if we'll actually be asked to parse anything anyways.
this.includeFilter = includeFilter;
this.excludeFilter = excludeFilter;
+ this.minimalDuration = minimalDuration;
+ }
+
+ public FeedFilter(String includeFilter, String excludeFilter) {
+ this(includeFilter, excludeFilter, -1);
}
/**
@@ -49,11 +55,20 @@ public class FeedFilter implements Serializable {
List<String> includeTerms = parseTerms(includeFilter);
List<String> excludeTerms = parseTerms(excludeFilter);
- if (includeTerms.size() == 0 && excludeTerms.size() == 0) {
+ if (includeTerms.size() == 0 && excludeTerms.size() == 0 && minimalDuration <= -1) {
// nothing has been specified, so include everything
return true;
}
+ // Check if the episode is long enough if minimal duration filter is on
+ if (hasMinimalDurationFilter() && item.getMedia() != null) {
+ int durationInMs = item.getMedia().getDuration();
+ // Minimal Duration is stored in seconds
+ if (durationInMs > 0 && durationInMs / 1000 < minimalDuration) {
+ return false;
+ }
+ }
+
// check using lowercase so the users don't have to worry about case.
String title = item.getTitle().toLowerCase(Locale.getDefault());
@@ -78,6 +93,12 @@ public class FeedFilter implements Serializable {
return true;
}
+ // if they only set minimal duration filter and arrived here, autodownload
+ // should happen
+ if (hasMinimalDurationFilter()) {
+ return true;
+ }
+
return false;
}
@@ -89,6 +110,10 @@ public class FeedFilter implements Serializable {
return excludeFilter;
}
+ public int getMinimalDurationFilter() {
+ return minimalDuration;
+ }
+
/**
* @return true if only include is set
*/
@@ -110,4 +135,8 @@ public class FeedFilter implements Serializable {
public boolean hasExcludeFilter() {
return excludeFilter.length() > 0;
}
+
+ public boolean hasMinimalDurationFilter() {
+ return minimalDuration > -1;
+ }
}