summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorByteHamster <ByteHamster@users.noreply.github.com>2024-04-03 22:21:42 +0200
committerGitHub <noreply@github.com>2024-04-03 22:21:42 +0200
commit613a9896e91200c3d4e8744173e48c445003469f (patch)
tree55f6b53eec9cfaa9ef573d390afa0e27d0360730
parenta846e417b030e1491c472d50651d58a8f2c15c0e (diff)
downloadAntennaPod-613a9896e91200c3d4e8744173e48c445003469f.zip
Remember column indices between different list items (#7051)
This is way faster than searching for the column index again for every item.
-rw-r--r--storage/database/src/main/java/de/danoeh/antennapod/storage/database/DBReader.java155
-rw-r--r--storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/ChapterCursor.java41
-rw-r--r--storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/ChapterCursorMapper.java32
-rw-r--r--storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/DownloadResultCursor.java52
-rw-r--r--storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/DownloadResultCursorMapper.java35
-rw-r--r--storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/FeedCursor.java92
-rw-r--r--storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/FeedCursorMapper.java70
-rw-r--r--storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/FeedItemCursor.java71
-rw-r--r--storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/FeedItemCursorMapper.java48
-rw-r--r--storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/FeedMediaCursor.java81
-rw-r--r--storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/FeedMediaCursorMapper.java67
-rw-r--r--storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/FeedPreferencesCursor.java85
-rw-r--r--storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/FeedPreferencesCursorMapper.java82
-rw-r--r--storage/database/src/test/java/de/danoeh/antennapod/storage/database/mapper/FeedCursorMapperTest.java5
14 files changed, 485 insertions, 431 deletions
diff --git a/storage/database/src/main/java/de/danoeh/antennapod/storage/database/DBReader.java b/storage/database/src/main/java/de/danoeh/antennapod/storage/database/DBReader.java
index f0239d8f5..41bb75b8b 100644
--- a/storage/database/src/main/java/de/danoeh/antennapod/storage/database/DBReader.java
+++ b/storage/database/src/main/java/de/danoeh/antennapod/storage/database/DBReader.java
@@ -25,12 +25,11 @@ import de.danoeh.antennapod.model.feed.FeedPreferences;
import de.danoeh.antennapod.model.feed.SortOrder;
import de.danoeh.antennapod.model.feed.SubscriptionsFilter;
import de.danoeh.antennapod.model.download.DownloadResult;
-import de.danoeh.antennapod.storage.database.mapper.ChapterCursorMapper;
-import de.danoeh.antennapod.storage.database.mapper.DownloadResultCursorMapper;
-import de.danoeh.antennapod.storage.database.mapper.FeedCursorMapper;
-import de.danoeh.antennapod.storage.database.mapper.FeedItemCursorMapper;
-import de.danoeh.antennapod.storage.database.mapper.FeedMediaCursorMapper;
-import de.danoeh.antennapod.storage.database.mapper.FeedPreferencesCursorMapper;
+import de.danoeh.antennapod.storage.database.mapper.ChapterCursor;
+import de.danoeh.antennapod.storage.database.mapper.DownloadResultCursor;
+import de.danoeh.antennapod.storage.database.mapper.FeedCursor;
+import de.danoeh.antennapod.storage.database.mapper.FeedItemCursor;
+import de.danoeh.antennapod.storage.database.mapper.FeedMediaCursor;
/**
* Provides methods for reading data from the AntennaPod database.
@@ -72,11 +71,10 @@ public final class DBReader {
@NonNull
private static List<Feed> getFeedList(PodDBAdapter adapter) {
- try (Cursor cursor = adapter.getAllFeedsCursor()) {
+ try (FeedCursor cursor = new FeedCursor(adapter.getAllFeedsCursor())) {
List<Feed> feeds = new ArrayList<>(cursor.getCount());
while (cursor.moveToNext()) {
- Feed feed = extractFeedFromCursorRow(cursor);
- feeds.add(feed);
+ feeds.add(cursor.getFeed());
}
return feeds;
}
@@ -173,8 +171,8 @@ public final class DBReader {
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
- try (Cursor cursor = adapter.getItemsOfFeedCursor(feed, filter)) {
- List<FeedItem> items = extractItemlistFromCursor(adapter, cursor);
+ try (FeedItemCursor cursor = new FeedItemCursor(adapter.getItemsOfFeedCursor(feed, filter))) {
+ List<FeedItem> items = extractItemlistFromCursor(cursor);
FeedItemPermutors.getPermutor(sortOrder).reorder(items);
feed.setItems(items);
for (FeedItem item : items) {
@@ -186,45 +184,20 @@ 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();
- try {
- return extractItemlistFromCursor(adapter, itemlistCursor);
- } finally {
- adapter.close();
- }
- }
-
@NonNull
- private static List<FeedItem> extractItemlistFromCursor(PodDBAdapter adapter, Cursor cursor) {
+ private static List<FeedItem> extractItemlistFromCursor(FeedItemCursor cursor) {
List<FeedItem> result = new ArrayList<>(cursor.getCount());
- if (cursor.moveToFirst()) {
- int indexMediaId = cursor.getColumnIndexOrThrow(PodDBAdapter.SELECT_KEY_MEDIA_ID);
- do {
- FeedItem item = FeedItemCursorMapper.convert(cursor);
- result.add(item);
- if (!cursor.isNull(indexMediaId)) {
- item.setMedia(FeedMediaCursorMapper.convert(cursor));
- }
- } while (cursor.moveToNext());
+ while (cursor.moveToNext()) {
+ result.add(cursor.getFeedItem());
}
return result;
}
- private static Feed extractFeedFromCursorRow(Cursor cursor) {
- Feed feed = FeedCursorMapper.convert(cursor);
- FeedPreferences preferences = FeedPreferencesCursorMapper.convert(cursor);
- feed.setPreferences(preferences);
- return feed;
- }
-
@NonNull
public static List<FeedItem> getQueue(PodDBAdapter adapter) {
Log.d(TAG, "getQueue()");
- try (Cursor cursor = adapter.getQueueCursor()) {
- List<FeedItem> items = extractItemlistFromCursor(adapter, cursor);
+ try (FeedItemCursor cursor = new FeedItemCursor(adapter.getQueueCursor())) {
+ List<FeedItem> items = extractItemlistFromCursor(cursor);
loadAdditionalFeedItemListData(items);
return items;
}
@@ -303,8 +276,8 @@ public final class DBReader {
Log.d(TAG, "getRecentlyPublishedEpisodes() called with: offset=" + offset + ", limit=" + limit);
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
- try (Cursor cursor = adapter.getEpisodesCursor(offset, limit, filter, sortOrder)) {
- List<FeedItem> items = extractItemlistFromCursor(adapter, cursor);
+ try (FeedItemCursor cursor = new FeedItemCursor(adapter.getEpisodesCursor(offset, limit, filter, sortOrder))) {
+ List<FeedItem> items = extractItemlistFromCursor(cursor);
loadAdditionalFeedItemListData(items);
return items;
} finally {
@@ -328,8 +301,8 @@ public final class DBReader {
public static List<FeedItem> getRandomEpisodes(int limit, int seed) {
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
- try (Cursor cursor = adapter.getRandomEpisodesCursor(limit, seed)) {
- List<FeedItem> items = extractItemlistFromCursor(adapter, cursor);
+ try (FeedItemCursor cursor = new FeedItemCursor(adapter.getRandomEpisodesCursor(limit, seed))) {
+ List<FeedItem> items = extractItemlistFromCursor(cursor);
loadAdditionalFeedItemListData(items);
return items;
} finally {
@@ -348,10 +321,10 @@ public final class DBReader {
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
- try (Cursor cursor = adapter.getDownloadLogCursor(DOWNLOAD_LOG_SIZE)) {
+ try (DownloadResultCursor cursor = new DownloadResultCursor(adapter.getDownloadLogCursor(DOWNLOAD_LOG_SIZE))) {
List<DownloadResult> downloadLog = new ArrayList<>(cursor.getCount());
while (cursor.moveToNext()) {
- downloadLog.add(DownloadResultCursorMapper.convert(cursor));
+ downloadLog.add(cursor.getDownloadResult());
}
return downloadLog;
} finally {
@@ -371,10 +344,11 @@ public final class DBReader {
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
- try (Cursor cursor = adapter.getDownloadLog(Feed.FEEDFILETYPE_FEED, feedId)) {
+ try (DownloadResultCursor cursor = new DownloadResultCursor(
+ adapter.getDownloadLog(Feed.FEEDFILETYPE_FEED, feedId))) {
List<DownloadResult> downloadLog = new ArrayList<>(cursor.getCount());
while (cursor.moveToNext()) {
- downloadLog.add(DownloadResultCursorMapper.convert(cursor));
+ downloadLog.add(cursor.getDownloadResult());
}
return downloadLog;
} finally {
@@ -408,9 +382,9 @@ public final class DBReader {
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
Feed feed = null;
- try (Cursor cursor = adapter.getFeedCursor(feedId)) {
+ try (FeedCursor cursor = new FeedCursor(adapter.getFeedCursor(feedId))) {
if (cursor.moveToNext()) {
- feed = extractFeedFromCursorRow(cursor);
+ feed = cursor.getFeed();
if (filtered) {
feed.setItems(getFeedItemList(feed, feed.getItemFilter()));
} else {
@@ -430,13 +404,11 @@ public final class DBReader {
Log.d(TAG, "Loading feeditem with id " + itemId);
FeedItem item = null;
- try (Cursor cursor = adapter.getFeedItemCursor(Long.toString(itemId))) {
- if (cursor.moveToNext()) {
- List<FeedItem> list = extractItemlistFromCursor(adapter, cursor);
- if (!list.isEmpty()) {
- item = list.get(0);
- loadAdditionalFeedItemListData(list);
- }
+ try (FeedItemCursor cursor = new FeedItemCursor(adapter.getFeedItemCursor(Long.toString(itemId)))) {
+ List<FeedItem> list = extractItemlistFromCursor(cursor);
+ if (!list.isEmpty()) {
+ item = list.get(0);
+ loadAdditionalFeedItemListData(list);
}
return item;
}
@@ -473,18 +445,16 @@ public final class DBReader {
Log.d(TAG, "getNextInQueue() called with: " + "itemId = [" + item.getId() + "]");
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
- try {
- FeedItem nextItem = null;
- try (Cursor cursor = adapter.getNextInQueue(item)) {
- List<FeedItem> list = extractItemlistFromCursor(adapter, cursor);
- if (!list.isEmpty()) {
- nextItem = list.get(0);
- loadAdditionalFeedItemListData(list);
- }
+ try (FeedItemCursor cursor = new FeedItemCursor(adapter.getNextInQueue(item))) {
+ List<FeedItem> list = extractItemlistFromCursor(cursor);
+ if (!list.isEmpty()) {
+ FeedItem nextItem = list.get(0);
+ loadAdditionalFeedItemListData(list);
return nextItem;
- } catch (Exception e) {
- return null;
}
+ return null;
+ } catch (Exception e) {
+ return null;
} finally {
adapter.close();
}
@@ -494,8 +464,8 @@ public final class DBReader {
public static List<FeedItem> getPausedQueue(int limit) {
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
- try (Cursor cursor = adapter.getPausedQueueCursor(limit)) {
- List<FeedItem> items = extractItemlistFromCursor(adapter, cursor);
+ try (FeedItemCursor cursor = new FeedItemCursor(adapter.getPausedQueueCursor(limit))) {
+ List<FeedItem> items = extractItemlistFromCursor(cursor);
loadAdditionalFeedItemListData(items);
return items;
} finally {
@@ -514,11 +484,8 @@ public final class DBReader {
@Nullable
private static FeedItem getFeedItemByGuidOrEpisodeUrl(final String guid, final String episodeUrl,
PodDBAdapter adapter) {
- try (Cursor cursor = adapter.getFeedItemCursor(guid, episodeUrl)) {
- if (!cursor.moveToNext()) {
- return null;
- }
- List<FeedItem> list = extractItemlistFromCursor(adapter, cursor);
+ try (FeedItemCursor cursor = new FeedItemCursor(adapter.getFeedItemCursor(guid, episodeUrl))) {
+ List<FeedItem> list = extractItemlistFromCursor(cursor);
if (!list.isEmpty()) {
return list.get(0);
}
@@ -584,7 +551,7 @@ public final class DBReader {
}
private static List<Chapter> loadChaptersOfFeedItem(PodDBAdapter adapter, FeedItem item) {
- try (Cursor cursor = adapter.getSimpleChaptersOfFeedItemCursor(item)) {
+ try (ChapterCursor cursor = new ChapterCursor(adapter.getSimpleChaptersOfFeedItemCursor(item))) {
int chaptersCount = cursor.getCount();
if (chaptersCount == 0) {
item.setChapters(null);
@@ -592,7 +559,7 @@ public final class DBReader {
}
ArrayList<Chapter> chapters = new ArrayList<>();
while (cursor.moveToNext()) {
- chapters.add(ChapterCursorMapper.convert(cursor));
+ chapters.add(cursor.getChapter());
}
return chapters;
}
@@ -609,14 +576,14 @@ public final class DBReader {
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
- try (Cursor mediaCursor = adapter.getSingleFeedMediaCursor(mediaId)) {
+ try (FeedMediaCursor mediaCursor = new FeedMediaCursor(adapter.getSingleFeedMediaCursor(mediaId))) {
if (!mediaCursor.moveToFirst()) {
return null;
}
int indexFeedItem = mediaCursor.getColumnIndex(PodDBAdapter.KEY_FEEDITEM);
long itemId = mediaCursor.getLong(indexFeedItem);
- FeedMedia media = FeedMediaCursorMapper.convert(mediaCursor);
+ FeedMedia media = mediaCursor.getFeedMedia();
FeedItem item = getFeedItem(itemId);
if (item != null) {
media.setItem(item);
@@ -631,8 +598,8 @@ public final class DBReader {
public static List<FeedItem> getFeedItemsWithUrl(List<String> urls) {
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
- try (Cursor itemCursor = adapter.getFeedItemCursorByUrl(urls)) {
- List<FeedItem> items = extractItemlistFromCursor(adapter, itemCursor);
+ try (FeedItemCursor itemCursor = new FeedItemCursor(adapter.getFeedItemCursorByUrl(urls))) {
+ List<FeedItem> items = extractItemlistFromCursor(itemCursor);
loadAdditionalFeedItemListData(items);
return items;
} finally {
@@ -708,7 +675,8 @@ public final class DBReader {
adapter.open();
StatisticsResult result = new StatisticsResult();
- try (Cursor cursor = adapter.getFeedStatisticsCursor(includeMarkedAsPlayed, timeFilterFrom, timeFilterTo)) {
+ try (FeedCursor cursor = new FeedCursor(adapter.getFeedStatisticsCursor(
+ includeMarkedAsPlayed, timeFilterFrom, timeFilterTo))) {
int indexOldestDate = cursor.getColumnIndexOrThrow("oldest_date");
int indexNumEpisodes = cursor.getColumnIndexOrThrow("num_episodes");
int indexEpisodesStarted = cursor.getColumnIndexOrThrow("episodes_started");
@@ -718,7 +686,7 @@ public final class DBReader {
int indexDownloadSize = cursor.getColumnIndexOrThrow("download_size");
while (cursor.moveToNext()) {
- Feed feed = extractFeedFromCursorRow(cursor);
+ Feed feed = cursor.getFeed();
long feedPlayedTime = Long.parseLong(cursor.getString(indexPlayedTime)) / 1000;
long feedTotalTime = Long.parseLong(cursor.getString(indexTotalTime)) / 1000;
@@ -860,7 +828,7 @@ public final class DBReader {
public static List<FeedItem> searchFeedItems(final long feedId, final String query) {
PodDBAdapter adapter = PodDBAdapter.getInstance().open();
- Cursor searchResult = adapter.searchItems(feedId, query);
+ FeedItemCursor searchResult = new FeedItemCursor(adapter.searchItems(feedId, query));
List<FeedItem> items = extractItemlistFromCursor(searchResult);
loadAdditionalFeedItemListData(items);
searchResult.close();
@@ -870,15 +838,14 @@ public final class DBReader {
public static List<Feed> searchFeeds(final String query) {
PodDBAdapter adapter = PodDBAdapter.getInstance();
- Cursor cursor = adapter.searchFeeds(query);
- List<Feed> items = new ArrayList<>();
- if (cursor.moveToFirst()) {
- do {
- items.add(FeedCursorMapper.convert(cursor));
- } while (cursor.moveToNext());
- }
- cursor.close();
- adapter.close();
- return items;
+ try (FeedCursor cursor = new FeedCursor(adapter.searchFeeds(query))) {
+ List<Feed> items = new ArrayList<>();
+ while (cursor.moveToNext()) {
+ items.add(cursor.getFeed());
+ }
+ return items;
+ } finally {
+ adapter.close();
+ }
}
}
diff --git a/storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/ChapterCursor.java b/storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/ChapterCursor.java
new file mode 100644
index 000000000..fbdc5a297
--- /dev/null
+++ b/storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/ChapterCursor.java
@@ -0,0 +1,41 @@
+package de.danoeh.antennapod.storage.database.mapper;
+
+import android.database.Cursor;
+import android.database.CursorWrapper;
+import androidx.annotation.NonNull;
+import de.danoeh.antennapod.model.feed.Chapter;
+import de.danoeh.antennapod.storage.database.PodDBAdapter;
+
+/**
+ * Converts a {@link Cursor} to a {@link Chapter} object.
+ */
+public class ChapterCursor extends CursorWrapper {
+ private final int indexId;
+ private final int indexTitle;
+ private final int indexStart;
+ private final int indexLink;
+ private final int indexImage;
+
+ public ChapterCursor(Cursor cursor) {
+ super(cursor);
+ indexId = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_ID);
+ indexTitle = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_TITLE);
+ indexStart = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_START);
+ indexLink = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_LINK);
+ indexImage = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_IMAGE_URL);
+ }
+
+ /**
+ * Create a {@link Chapter} instance from a database row (cursor).
+ */
+ @NonNull
+ public Chapter getChapter() {
+ Chapter chapter = new Chapter(
+ getLong(indexStart),
+ getString(indexTitle),
+ getString(indexLink),
+ getString(indexImage));
+ chapter.setId(getLong(indexId));
+ return chapter;
+ }
+}
diff --git a/storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/ChapterCursorMapper.java b/storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/ChapterCursorMapper.java
deleted file mode 100644
index b48a7f9d1..000000000
--- a/storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/ChapterCursorMapper.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package de.danoeh.antennapod.storage.database.mapper;
-
-import android.database.Cursor;
-import androidx.annotation.NonNull;
-import de.danoeh.antennapod.model.feed.Chapter;
-import de.danoeh.antennapod.storage.database.PodDBAdapter;
-
-/**
- * Converts a {@link Cursor} to a {@link Chapter} object.
- */
-public abstract class ChapterCursorMapper {
- /**
- * Create a {@link Chapter} instance from a database row (cursor).
- */
- @NonNull
- public static Chapter convert(@NonNull Cursor cursor) {
- int indexId = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_ID);
- int indexTitle = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_TITLE);
- int indexStart = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_START);
- int indexLink = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_LINK);
- int indexImage = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_IMAGE_URL);
-
- long id = cursor.getLong(indexId);
- String title = cursor.getString(indexTitle);
- long start = cursor.getLong(indexStart);
- String link = cursor.getString(indexLink);
- String imageUrl = cursor.getString(indexImage);
- Chapter chapter = new Chapter(start, title, link, imageUrl);
- chapter.setId(id);
- return chapter;
- }
-}
diff --git a/storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/DownloadResultCursor.java b/storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/DownloadResultCursor.java
new file mode 100644
index 000000000..8804ac09d
--- /dev/null
+++ b/storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/DownloadResultCursor.java
@@ -0,0 +1,52 @@
+package de.danoeh.antennapod.storage.database.mapper;
+
+import android.database.Cursor;
+import android.database.CursorWrapper;
+import androidx.annotation.NonNull;
+import de.danoeh.antennapod.model.download.DownloadResult;
+import de.danoeh.antennapod.model.download.DownloadError;
+import de.danoeh.antennapod.storage.database.PodDBAdapter;
+
+import java.util.Date;
+
+/**
+ * Converts a {@link Cursor} to a {@link DownloadResult} object.
+ */
+public class DownloadResultCursor extends CursorWrapper {
+ private final int indexId;
+ private final int indexTitle;
+ private final int indexFeedFile;
+ private final int indexFileFileType;
+ private final int indexSuccessful;
+ private final int indexReason;
+ private final int indexCompletionDate;
+ private final int indexReasonDetailed;
+
+ public DownloadResultCursor(Cursor cursor) {
+ super(cursor);
+ indexId = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_ID);
+ indexTitle = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_DOWNLOADSTATUS_TITLE);
+ indexFeedFile = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_FEEDFILE);
+ indexFileFileType = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_FEEDFILETYPE);
+ indexSuccessful = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_SUCCESSFUL);
+ indexReason = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_REASON);
+ indexCompletionDate = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_COMPLETION_DATE);
+ indexReasonDetailed = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_REASON_DETAILED);
+ }
+
+ /**
+ * Create a {@link DownloadResult} instance from a database row (cursor).
+ */
+ @NonNull
+ public DownloadResult getDownloadResult() {
+ return new DownloadResult(
+ getLong(indexId),
+ getString(indexTitle),
+ getLong(indexFeedFile),
+ getInt(indexFileFileType),
+ getInt(indexSuccessful) > 0,
+ DownloadError.fromCode(getInt(indexReason)),
+ new Date(getLong(indexCompletionDate)),
+ getString(indexReasonDetailed));
+ }
+}
diff --git a/storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/DownloadResultCursorMapper.java b/storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/DownloadResultCursorMapper.java
deleted file mode 100644
index d8f40d6a3..000000000
--- a/storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/DownloadResultCursorMapper.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package de.danoeh.antennapod.storage.database.mapper;
-
-import android.database.Cursor;
-import androidx.annotation.NonNull;
-import de.danoeh.antennapod.model.download.DownloadResult;
-import de.danoeh.antennapod.model.download.DownloadError;
-import de.danoeh.antennapod.storage.database.PodDBAdapter;
-
-import java.util.Date;
-
-/**
- * Converts a {@link Cursor} to a {@link DownloadResult} object.
- */
-public abstract class DownloadResultCursorMapper {
- /**
- * Create a {@link DownloadResult} instance from a database row (cursor).
- */
- @NonNull
- public static DownloadResult convert(@NonNull Cursor cursor) {
- int indexId = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_ID);
- int indexTitle = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_DOWNLOADSTATUS_TITLE);
- int indexFeedFile = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_FEEDFILE);
- int indexFileFileType = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_FEEDFILETYPE);
- int indexSuccessful = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_SUCCESSFUL);
- int indexReason = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_REASON);
- int indexCompletionDate = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_COMPLETION_DATE);
- int indexReasonDetailed = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_REASON_DETAILED);
-
- return new DownloadResult(cursor.getLong(indexId), cursor.getString(indexTitle), cursor.getLong(indexFeedFile),
- cursor.getInt(indexFileFileType), cursor.getInt(indexSuccessful) > 0,
- DownloadError.fromCode(cursor.getInt(indexReason)),
- new Date(cursor.getLong(indexCompletionDate)),
- cursor.getString(indexReasonDetailed));
- }
-}
diff --git a/storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/FeedCursor.java b/storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/FeedCursor.java
new file mode 100644
index 000000000..2707275ca
--- /dev/null
+++ b/storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/FeedCursor.java
@@ -0,0 +1,92 @@
+package de.danoeh.antennapod.storage.database.mapper;
+
+import android.database.Cursor;
+
+import android.database.CursorWrapper;
+import androidx.annotation.NonNull;
+
+import de.danoeh.antennapod.model.feed.Feed;
+import de.danoeh.antennapod.model.feed.SortOrder;
+import de.danoeh.antennapod.storage.database.PodDBAdapter;
+
+/**
+ * Converts a {@link Cursor} to a {@link Feed} object.
+ */
+public class FeedCursor extends CursorWrapper {
+ private final FeedPreferencesCursor preferencesCursor;
+ private final int indexId;
+ private final int indexLastUpdate;
+ private final int indexTitle;
+ private final int indexCustomTitle;
+ private final int indexLink;
+ private final int indexDescription;
+ private final int indexPaymentLink;
+ private final int indexAuthor;
+ private final int indexLanguage;
+ private final int indexType;
+ private final int indexFeedIdentifier;
+ private final int indexFileUrl;
+ private final int indexDownloadUrl;
+ private final int indexLastRefreshed;
+ private final int indexIsPaged;
+ private final int indexNextPageLink;
+ private final int indexHide;
+ private final int indexSortOrder;
+ private final int indexLastUpdateFailed;
+ private final int indexImageUrl;
+
+ public FeedCursor(Cursor cursor) {
+ super(new FeedPreferencesCursor(cursor));
+ preferencesCursor = (FeedPreferencesCursor) getWrappedCursor();
+ indexId = cursor.getColumnIndexOrThrow(PodDBAdapter.SELECT_KEY_FEED_ID);
+ indexLastUpdate = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_LASTUPDATE);
+ indexTitle = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_TITLE);
+ indexCustomTitle = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_CUSTOM_TITLE);
+ indexLink = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_LINK);
+ indexDescription = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_DESCRIPTION);
+ indexPaymentLink = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_PAYMENT_LINK);
+ indexAuthor = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_AUTHOR);
+ indexLanguage = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_LANGUAGE);
+ indexType = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_TYPE);
+ indexFeedIdentifier = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_FEED_IDENTIFIER);
+ indexFileUrl = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_FILE_URL);
+ indexDownloadUrl = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_DOWNLOAD_URL);
+ indexLastRefreshed = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_LAST_REFRESH_ATTEMPT);
+ indexIsPaged = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_IS_PAGED);
+ indexNextPageLink = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_NEXT_PAGE_LINK);
+ indexHide = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_HIDE);
+ indexSortOrder = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_SORT_ORDER);
+ indexLastUpdateFailed = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_LAST_UPDATE_FAILED);
+ indexImageUrl = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_IMAGE_URL);
+ }
+
+ /**
+ * Create a {@link Feed} instance from the current database row.
+ */
+ @NonNull
+ public Feed getFeed() {
+ Feed feed = new Feed(
+ getLong(indexId),
+ getString(indexLastUpdate),
+ getString(indexTitle),
+ getString(indexCustomTitle),
+ getString(indexLink),
+ getString(indexDescription),
+ getString(indexPaymentLink),
+ getString(indexAuthor),
+ getString(indexLanguage),
+ getString(indexType),
+ getString(indexFeedIdentifier),
+ getString(indexImageUrl),
+ getString(indexFileUrl),
+ getString(indexDownloadUrl),
+ getLong(indexLastRefreshed),
+ getInt(indexIsPaged) > 0,
+ getString(indexNextPageLink),
+ getString(indexHide),
+ SortOrder.fromCodeString(getString(indexSortOrder)),
+ getInt(indexLastUpdateFailed) > 0);
+ feed.setPreferences(preferencesCursor.getFeedPreferences());
+ return feed;
+ }
+}
diff --git a/storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/FeedCursorMapper.java b/storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/FeedCursorMapper.java
deleted file mode 100644
index f7be7009f..000000000
--- a/storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/FeedCursorMapper.java
+++ /dev/null
@@ -1,70 +0,0 @@
-package de.danoeh.antennapod.storage.database.mapper;
-
-import android.database.Cursor;
-
-import androidx.annotation.NonNull;
-
-import de.danoeh.antennapod.model.feed.Feed;
-import de.danoeh.antennapod.model.feed.FeedPreferences;
-import de.danoeh.antennapod.model.feed.SortOrder;
-import de.danoeh.antennapod.storage.database.PodDBAdapter;
-
-/**
- * Converts a {@link Cursor} to a {@link Feed} object.
- */
-public abstract class FeedCursorMapper {
-
- /**
- * Create a {@link Feed} instance from a database row (cursor).
- */
- @NonNull
- public static Feed convert(@NonNull Cursor cursor) {
- int indexId = cursor.getColumnIndexOrThrow(PodDBAdapter.SELECT_KEY_FEED_ID);
- int indexLastUpdate = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_LASTUPDATE);
- int indexTitle = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_TITLE);
- int indexCustomTitle = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_CUSTOM_TITLE);
- int indexLink = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_LINK);
- int indexDescription = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_DESCRIPTION);
- int indexPaymentLink = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_PAYMENT_LINK);
- int indexAuthor = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_AUTHOR);
- int indexLanguage = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_LANGUAGE);
- int indexType = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_TYPE);
- int indexFeedIdentifier = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_FEED_IDENTIFIER);
- int indexFileUrl = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_FILE_URL);
- int indexDownloadUrl = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_DOWNLOAD_URL);
- int indexLastRefreshed = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_LAST_REFRESH_ATTEMPT);
- int indexIsPaged = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_IS_PAGED);
- int indexNextPageLink = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_NEXT_PAGE_LINK);
- int indexHide = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_HIDE);
- int indexSortOrder = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_SORT_ORDER);
- int indexLastUpdateFailed = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_LAST_UPDATE_FAILED);
- int indexImageUrl = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_IMAGE_URL);
-
- Feed feed = new Feed(
- cursor.getLong(indexId),
- cursor.getString(indexLastUpdate),
- cursor.getString(indexTitle),
- cursor.getString(indexCustomTitle),
- cursor.getString(indexLink),
- cursor.getString(indexDescription),
- cursor.getString(indexPaymentLink),
- cursor.getString(indexAuthor),
- cursor.getString(indexLanguage),
- cursor.getString(indexType),
- cursor.getString(indexFeedIdentifier),
- cursor.getString(indexImageUrl),
- cursor.getString(indexFileUrl),
- cursor.getString(indexDownloadUrl),
- cursor.getLong(indexLastRefreshed),
- cursor.getInt(indexIsPaged) > 0,
- cursor.getString(indexNextPageLink),
- cursor.getString(indexHide),
- SortOrder.fromCodeString(cursor.getString(indexSortOrder)),
- cursor.getInt(indexLastUpdateFailed) > 0
- );
-
- FeedPreferences preferences = FeedPreferencesCursorMapper.convert(cursor);
- feed.setPreferences(preferences);
- return feed;
- }
-}
diff --git a/storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/FeedItemCursor.java b/storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/FeedItemCursor.java
new file mode 100644
index 000000000..d526299e4
--- /dev/null
+++ b/storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/FeedItemCursor.java
@@ -0,0 +1,71 @@
+package de.danoeh.antennapod.storage.database.mapper;
+
+import android.database.Cursor;
+import android.database.CursorWrapper;
+import androidx.annotation.NonNull;
+import de.danoeh.antennapod.model.feed.FeedItem;
+import de.danoeh.antennapod.storage.database.PodDBAdapter;
+
+import java.util.Date;
+
+/**
+ * Converts a {@link Cursor} to a {@link FeedItem} object.
+ */
+public class FeedItemCursor extends CursorWrapper {
+ private final FeedMediaCursor feedMediaCursor;
+ private final int indexId;
+ private final int indexTitle;
+ private final int indexLink;
+ private final int indexPubDate;
+ private final int indexPaymentLink;
+ private final int indexFeedId;
+ private final int indexHasChapters;
+ private final int indexRead;
+ private final int indexItemIdentifier;
+ private final int indexAutoDownload;
+ private final int indexImageUrl;
+ private final int indexPodcastIndexChapterUrl;
+ private final int indexMediaId;
+
+ public FeedItemCursor(Cursor cursor) {
+ super(new FeedMediaCursor(cursor));
+ feedMediaCursor = (FeedMediaCursor) getWrappedCursor();
+ indexId = cursor.getColumnIndexOrThrow(PodDBAdapter.SELECT_KEY_ITEM_ID);
+ indexTitle = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_TITLE);
+ indexLink = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_LINK);
+ indexPubDate = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_PUBDATE);
+ indexPaymentLink = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_PAYMENT_LINK);
+ indexFeedId = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_FEED);
+ indexHasChapters = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_HAS_CHAPTERS);
+ indexRead = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_READ);
+ indexItemIdentifier = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_ITEM_IDENTIFIER);
+ indexAutoDownload = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_AUTO_DOWNLOAD_ENABLED);
+ indexImageUrl = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_IMAGE_URL);
+ indexPodcastIndexChapterUrl = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_PODCASTINDEX_CHAPTER_URL);
+ indexMediaId = cursor.getColumnIndexOrThrow(PodDBAdapter.SELECT_KEY_MEDIA_ID);
+ }
+
+ /**
+ * Create a {@link FeedItem} instance from a database row (cursor).
+ */
+ @NonNull
+ public FeedItem getFeedItem() {
+ FeedItem item = new FeedItem(
+ getInt(indexId),
+ getString(indexTitle),
+ getString(indexLink),
+ new Date(getLong(indexPubDate)),
+ getString(indexPaymentLink),
+ getLong(indexFeedId),
+ getInt(indexHasChapters) > 0,
+ getString(indexImageUrl),
+ getInt(indexRead),
+ getString(indexItemIdentifier),
+ getLong(indexAutoDownload) > 0,
+ getString(indexPodcastIndexChapterUrl));
+ if (!isNull(indexMediaId)) {
+ item.setMedia(feedMediaCursor.getFeedMedia());
+ }
+ return item;
+ }
+}
diff --git a/storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/FeedItemCursorMapper.java b/storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/FeedItemCursorMapper.java
deleted file mode 100644
index c2c9b89d4..000000000
--- a/storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/FeedItemCursorMapper.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package de.danoeh.antennapod.storage.database.mapper;
-
-import android.database.Cursor;
-import androidx.annotation.NonNull;
-import de.danoeh.antennapod.model.feed.FeedItem;
-import de.danoeh.antennapod.storage.database.PodDBAdapter;
-
-import java.util.Date;
-
-/**
- * Converts a {@link Cursor} to a {@link FeedItem} object.
- */
-public abstract class FeedItemCursorMapper {
- /**
- * Create a {@link FeedItem} instance from a database row (cursor).
- */
- @NonNull
- public static FeedItem convert(@NonNull Cursor cursor) {
- int indexId = cursor.getColumnIndexOrThrow(PodDBAdapter.SELECT_KEY_ITEM_ID);
- int indexTitle = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_TITLE);
- int indexLink = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_LINK);
- int indexPubDate = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_PUBDATE);
- int indexPaymentLink = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_PAYMENT_LINK);
- int indexFeedId = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_FEED);
- int indexHasChapters = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_HAS_CHAPTERS);
- int indexRead = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_READ);
- int indexItemIdentifier = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_ITEM_IDENTIFIER);
- int indexAutoDownload = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_AUTO_DOWNLOAD_ENABLED);
- int indexImageUrl = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_IMAGE_URL);
- int indexPodcastIndexChapterUrl = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_PODCASTINDEX_CHAPTER_URL);
-
- long id = cursor.getInt(indexId);
- String title = cursor.getString(indexTitle);
- String link = cursor.getString(indexLink);
- Date pubDate = new Date(cursor.getLong(indexPubDate));
- String paymentLink = cursor.getString(indexPaymentLink);
- long feedId = cursor.getLong(indexFeedId);
- boolean hasChapters = cursor.getInt(indexHasChapters) > 0;
- int state = cursor.getInt(indexRead);
- String itemIdentifier = cursor.getString(indexItemIdentifier);
- boolean autoDownloadEnabled = cursor.getLong(indexAutoDownload) > 0;
- String imageUrl = cursor.getString(indexImageUrl);
- String podcastIndexChapterUrl = cursor.getString(indexPodcastIndexChapterUrl);
-
- return new FeedItem(id, title, link, pubDate, paymentLink, feedId,
- hasChapters, imageUrl, state, itemIdentifier, autoDownloadEnabled, podcastIndexChapterUrl);
- }
-}
diff --git a/storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/FeedMediaCursor.java b/storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/FeedMediaCursor.java
new file mode 100644
index 000000000..48e897c74
--- /dev/null
+++ b/storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/FeedMediaCursor.java
@@ -0,0 +1,81 @@
+package de.danoeh.antennapod.storage.database.mapper;
+
+import android.database.Cursor;
+import android.database.CursorWrapper;
+import androidx.annotation.NonNull;
+import de.danoeh.antennapod.model.feed.FeedMedia;
+import de.danoeh.antennapod.storage.database.PodDBAdapter;
+
+import java.util.Date;
+
+/**
+ * Converts a {@link Cursor} to a {@link FeedMedia} object.
+ */
+public class FeedMediaCursor extends CursorWrapper {
+ private final int indexId;
+ private final int indexPlaybackCompletionDate;
+ private final int indexDuration;
+ private final int indexPosition;
+ private final int indexSize;
+ private final int indexMimeType;
+ private final int indexFileUrl;
+ private final int indexDownloadUrl;
+ private final int indexDownloaded;
+ private final int indexPlayedDuration;
+ private final int indexLastPlayedTime;
+ private final int indexHasEmbeddedPicture;
+
+ public FeedMediaCursor(Cursor cursor) {
+ super(cursor);
+ indexId = cursor.getColumnIndexOrThrow(PodDBAdapter.SELECT_KEY_MEDIA_ID);
+ indexPlaybackCompletionDate = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_PLAYBACK_COMPLETION_DATE);
+ indexDuration = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_DURATION);
+ indexPosition = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_POSITION);
+ indexSize = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_SIZE);
+ indexMimeType = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_MIME_TYPE);
+ indexFileUrl = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_FILE_URL);
+ indexDownloadUrl = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_DOWNLOAD_URL);
+ indexDownloaded = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_DOWNLOADED);
+ indexPlayedDuration = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_PLAYED_DURATION);
+ indexLastPlayedTime = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_LAST_PLAYED_TIME);
+ indexHasEmbeddedPicture = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_HAS_EMBEDDED_PICTURE);
+ }
+
+ /**
+ * Create a {@link FeedMedia} instance from a database row (cursor).
+ */
+ @NonNull
+ public FeedMedia getFeedMedia() {
+ long playbackCompletionTime = getLong(indexPlaybackCompletionDate);
+ Date playbackCompletionDate = playbackCompletionTime > 0 ? new Date(playbackCompletionTime) : null;
+
+ Boolean hasEmbeddedPicture;
+ switch (getInt(indexHasEmbeddedPicture)) {
+ case 1:
+ hasEmbeddedPicture = Boolean.TRUE;
+ break;
+ case 0:
+ hasEmbeddedPicture = Boolean.FALSE;
+ break;
+ default:
+ hasEmbeddedPicture = null;
+ break;
+ }
+
+ return new FeedMedia(
+ getLong(indexId),
+ null,
+ getInt(indexDuration),
+ getInt(indexPosition),
+ getLong(indexSize),
+ getString(indexMimeType),
+ getString(indexFileUrl),
+ getString(indexDownloadUrl),
+ getInt(indexDownloaded) > 0,
+ playbackCompletionDate,
+ getInt(indexPlayedDuration),
+ hasEmbeddedPicture,
+ getLong(indexLastPlayedTime)
+ );
+ }
+}
diff --git a/storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/FeedMediaCursorMapper.java b/storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/FeedMediaCursorMapper.java
deleted file mode 100644
index f57e91b83..000000000
--- a/storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/FeedMediaCursorMapper.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package de.danoeh.antennapod.storage.database.mapper;
-
-import android.database.Cursor;
-import androidx.annotation.NonNull;
-import de.danoeh.antennapod.model.feed.FeedMedia;
-import de.danoeh.antennapod.storage.database.PodDBAdapter;
-
-import java.util.Date;
-
-/**
- * Converts a {@link Cursor} to a {@link FeedMedia} object.
- */
-public abstract class FeedMediaCursorMapper {
- /**
- * Create a {@link FeedMedia} instance from a database row (cursor).
- */
- @NonNull
- public static FeedMedia convert(@NonNull Cursor cursor) {
- int indexId = cursor.getColumnIndexOrThrow(PodDBAdapter.SELECT_KEY_MEDIA_ID);
- int indexPlaybackCompletionDate = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_PLAYBACK_COMPLETION_DATE);
- int indexDuration = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_DURATION);
- int indexPosition = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_POSITION);
- int indexSize = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_SIZE);
- int indexMimeType = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_MIME_TYPE);
- int indexFileUrl = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_FILE_URL);
- int indexDownloadUrl = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_DOWNLOAD_URL);
- int indexDownloaded = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_DOWNLOADED);
- int indexPlayedDuration = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_PLAYED_DURATION);
- int indexLastPlayedTime = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_LAST_PLAYED_TIME);
-
- long mediaId = cursor.getLong(indexId);
- Date playbackCompletionDate = null;
- long playbackCompletionTime = cursor.getLong(indexPlaybackCompletionDate);
- if (playbackCompletionTime > 0) {
- playbackCompletionDate = new Date(playbackCompletionTime);
- }
-
- Boolean hasEmbeddedPicture;
- switch (cursor.getInt(cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_HAS_EMBEDDED_PICTURE))) {
- case 1:
- hasEmbeddedPicture = Boolean.TRUE;
- break;
- case 0:
- hasEmbeddedPicture = Boolean.FALSE;
- break;
- default:
- hasEmbeddedPicture = null;
- break;
- }
-
- return new FeedMedia(
- mediaId,
- null,
- cursor.getInt(indexDuration),
- cursor.getInt(indexPosition),
- cursor.getLong(indexSize),
- cursor.getString(indexMimeType),
- cursor.getString(indexFileUrl),
- cursor.getString(indexDownloadUrl),
- cursor.getInt(indexDownloaded) > 0,
- playbackCompletionDate,
- cursor.getInt(indexPlayedDuration),
- hasEmbeddedPicture,
- cursor.getLong(indexLastPlayedTime)
- );
- }
-}
diff --git a/storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/FeedPreferencesCursor.java b/storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/FeedPreferencesCursor.java
new file mode 100644
index 000000000..147650e15
--- /dev/null
+++ b/storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/FeedPreferencesCursor.java
@@ -0,0 +1,85 @@
+package de.danoeh.antennapod.storage.database.mapper;
+
+import android.database.Cursor;
+import android.database.CursorWrapper;
+import android.text.TextUtils;
+import androidx.annotation.NonNull;
+import de.danoeh.antennapod.model.feed.FeedFilter;
+import de.danoeh.antennapod.model.feed.FeedPreferences;
+import de.danoeh.antennapod.model.feed.VolumeAdaptionSetting;
+import de.danoeh.antennapod.storage.database.PodDBAdapter;
+
+import java.util.Arrays;
+import java.util.HashSet;
+
+/**
+ * Converts a {@link Cursor} to a {@link FeedPreferences} object.
+ */
+public class FeedPreferencesCursor extends CursorWrapper {
+ private final int indexId;
+ private final int indexAutoDownload;
+ private final int indexAutoRefresh;
+ private final int indexAutoDeleteAction;
+ private final int indexVolumeAdaption;
+ private final int indexUsername;
+ private final int indexPassword;
+ private final int indexIncludeFilter;
+ private final int indexExcludeFilter;
+ private final int indexMinimalDurationFilter;
+ private final int indexFeedPlaybackSpeed;
+ private final int indexFeedSkipSilence;
+ private final int indexAutoSkipIntro;
+ private final int indexAutoSkipEnding;
+ private final int indexEpisodeNotification;
+ private final int indexNewEpisodesAction;
+ private final int indexTags;
+
+ public FeedPreferencesCursor(Cursor cursor) {
+ super(cursor);
+ indexId = cursor.getColumnIndexOrThrow(PodDBAdapter.SELECT_KEY_FEED_ID);
+ indexAutoDownload = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_AUTO_DOWNLOAD_ENABLED);
+ indexAutoRefresh = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_KEEP_UPDATED);
+ indexAutoDeleteAction = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_AUTO_DELETE_ACTION);
+ indexVolumeAdaption = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_FEED_VOLUME_ADAPTION);
+ indexUsername = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_USERNAME);
+ indexPassword = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_PASSWORD);
+ indexIncludeFilter = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_INCLUDE_FILTER);
+ indexExcludeFilter = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_EXCLUDE_FILTER);
+ indexMinimalDurationFilter = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_MINIMAL_DURATION_FILTER);
+ indexFeedPlaybackSpeed = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_FEED_PLAYBACK_SPEED);
+ indexFeedSkipSilence = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_FEED_SKIP_SILENCE);
+ indexAutoSkipIntro = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_FEED_SKIP_INTRO);
+ indexAutoSkipEnding = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_FEED_SKIP_ENDING);
+ indexEpisodeNotification = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_EPISODE_NOTIFICATION);
+ indexNewEpisodesAction = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_NEW_EPISODES_ACTION);
+ indexTags = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_FEED_TAGS);
+ }
+
+ /**
+ * Create a {@link FeedPreferences} instance from a database row (cursor).
+ */
+ @NonNull
+ public FeedPreferences getFeedPreferences() {
+ String tagsString = getString(indexTags);
+ if (TextUtils.isEmpty(tagsString)) {
+ tagsString = FeedPreferences.TAG_ROOT;
+ }
+ return new FeedPreferences(
+ getLong(indexId),
+ getInt(indexAutoDownload) > 0,
+ getInt(indexAutoRefresh) > 0,
+ FeedPreferences.AutoDeleteAction.fromCode(getInt(indexAutoDeleteAction)),
+ VolumeAdaptionSetting.fromInteger(getInt(indexVolumeAdaption)),
+ getString(indexUsername),
+ getString(indexPassword),
+ new FeedFilter(getString(indexIncludeFilter),
+ getString(indexExcludeFilter), getInt(indexMinimalDurationFilter)),
+ getFloat(indexFeedPlaybackSpeed),
+ getInt(indexAutoSkipIntro),
+ getInt(indexAutoSkipEnding),
+ FeedPreferences.SkipSilence.fromCode(getInt(indexFeedSkipSilence)),
+ getInt(indexEpisodeNotification) > 0,
+ FeedPreferences.NewEpisodesAction.fromCode(getInt(indexNewEpisodesAction)),
+ new HashSet<>(Arrays.asList(tagsString.split(FeedPreferences.TAG_SEPARATOR))));
+ }
+}
diff --git a/storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/FeedPreferencesCursorMapper.java b/storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/FeedPreferencesCursorMapper.java
deleted file mode 100644
index 83b62b8a3..000000000
--- a/storage/database/src/main/java/de/danoeh/antennapod/storage/database/mapper/FeedPreferencesCursorMapper.java
+++ /dev/null
@@ -1,82 +0,0 @@
-package de.danoeh.antennapod.storage.database.mapper;
-
-import android.database.Cursor;
-import android.text.TextUtils;
-import androidx.annotation.NonNull;
-import de.danoeh.antennapod.model.feed.FeedFilter;
-import de.danoeh.antennapod.model.feed.FeedPreferences;
-import de.danoeh.antennapod.model.feed.VolumeAdaptionSetting;
-import de.danoeh.antennapod.storage.database.PodDBAdapter;
-
-import java.util.Arrays;
-import java.util.HashSet;
-
-/**
- * Converts a {@link Cursor} to a {@link FeedPreferences} object.
- */
-public abstract class FeedPreferencesCursorMapper {
- /**
- * Create a {@link FeedPreferences} instance from a database row (cursor).
- */
- @NonNull
- public static FeedPreferences convert(@NonNull Cursor cursor) {
- int indexId = cursor.getColumnIndexOrThrow(PodDBAdapter.SELECT_KEY_FEED_ID);
- int indexAutoDownload = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_AUTO_DOWNLOAD_ENABLED);
- int indexAutoRefresh = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_KEEP_UPDATED);
- int indexAutoDeleteAction = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_AUTO_DELETE_ACTION);
- int indexVolumeAdaption = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_FEED_VOLUME_ADAPTION);
- int indexUsername = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_USERNAME);
- int indexPassword = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_PASSWORD);
- int indexIncludeFilter = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_INCLUDE_FILTER);
- int indexExcludeFilter = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_EXCLUDE_FILTER);
- int indexMinimalDurationFilter = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_MINIMAL_DURATION_FILTER);
- int indexFeedPlaybackSpeed = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_FEED_PLAYBACK_SPEED);
- int indexFeedSkipSilence = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_FEED_SKIP_SILENCE);
- int indexAutoSkipIntro = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_FEED_SKIP_INTRO);
- int indexAutoSkipEnding = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_FEED_SKIP_ENDING);
- int indexEpisodeNotification = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_EPISODE_NOTIFICATION);
- int indexNewEpisodesAction = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_NEW_EPISODES_ACTION);
- int indexTags = cursor.getColumnIndexOrThrow(PodDBAdapter.KEY_FEED_TAGS);
-
- long feedId = cursor.getLong(indexId);
- boolean autoDownload = cursor.getInt(indexAutoDownload) > 0;
- boolean autoRefresh = cursor.getInt(indexAutoRefresh) > 0;
- FeedPreferences.AutoDeleteAction autoDeleteAction =
- FeedPreferences.AutoDeleteAction.fromCode(cursor.getInt(indexAutoDeleteAction));
- int volumeAdaptionValue = cursor.getInt(indexVolumeAdaption);
- VolumeAdaptionSetting volumeAdaptionSetting = VolumeAdaptionSetting.fromInteger(volumeAdaptionValue);
- String username = cursor.getString(indexUsername);
- 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);
- FeedPreferences.SkipSilence feedSkipSilence =
- FeedPreferences.SkipSilence.fromCode(cursor.getInt(indexFeedSkipSilence));
- FeedPreferences.NewEpisodesAction feedNewEpisodesAction =
- FeedPreferences.NewEpisodesAction.fromCode(cursor.getInt(indexNewEpisodesAction));
- boolean showNotification = cursor.getInt(indexEpisodeNotification) > 0;
- String tagsString = cursor.getString(indexTags);
- if (TextUtils.isEmpty(tagsString)) {
- tagsString = FeedPreferences.TAG_ROOT;
- }
-
- return new FeedPreferences(feedId,
- autoDownload,
- autoRefresh,
- autoDeleteAction,
- volumeAdaptionSetting,
- username,
- password,
- new FeedFilter(includeFilter, excludeFilter, minimalDurationFilter),
- feedPlaybackSpeed,
- feedAutoSkipIntro,
- feedAutoSkipEnding,
- feedSkipSilence,
- showNotification,
- feedNewEpisodesAction,
- new HashSet<>(Arrays.asList(tagsString.split(FeedPreferences.TAG_SEPARATOR))));
- }
-}
diff --git a/storage/database/src/test/java/de/danoeh/antennapod/storage/database/mapper/FeedCursorMapperTest.java b/storage/database/src/test/java/de/danoeh/antennapod/storage/database/mapper/FeedCursorMapperTest.java
index 5e7a4843e..2e1697c9f 100644
--- a/storage/database/src/test/java/de/danoeh/antennapod/storage/database/mapper/FeedCursorMapperTest.java
+++ b/storage/database/src/test/java/de/danoeh/antennapod/storage/database/mapper/FeedCursorMapperTest.java
@@ -2,7 +2,6 @@ package de.danoeh.antennapod.storage.database.mapper;
import android.content.ContentValues;
import android.content.Context;
-import android.database.Cursor;
import androidx.test.platform.app.InstrumentationRegistry;
@@ -40,9 +39,9 @@ public class FeedCursorMapperTest {
@SuppressWarnings("ConstantConditions")
@Test
public void testFromCursor() {
- try (Cursor cursor = adapter.getAllFeedsCursor()) {
+ try (FeedCursor cursor = new FeedCursor(adapter.getAllFeedsCursor())) {
cursor.moveToNext();
- Feed feed = FeedCursorMapper.convert(cursor);
+ Feed feed = cursor.getFeed();
assertTrue(feed.getId() >= 0);
assertEquals("feed custom title", feed.getTitle());
assertEquals("feed custom title", feed.getCustomTitle());