Add lazy loading to feed item list (#7091)
This commit is contained in:
parent
04fab47072
commit
f3bca9d9e4
|
@ -98,7 +98,7 @@ public class DownloadLogAdapter extends BaseAdapter {
|
||||||
if (status.getFeedfileType() == Feed.FEEDFILETYPE_FEED) {
|
if (status.getFeedfileType() == Feed.FEEDFILETYPE_FEED) {
|
||||||
holder.secondaryActionButton.setOnClickListener(v -> {
|
holder.secondaryActionButton.setOnClickListener(v -> {
|
||||||
holder.secondaryActionButton.setVisibility(View.INVISIBLE);
|
holder.secondaryActionButton.setVisibility(View.INVISIBLE);
|
||||||
Feed feed = DBReader.getFeed(status.getFeedfileId());
|
Feed feed = DBReader.getFeed(status.getFeedfileId(), false, 0, 0);
|
||||||
if (feed == null) {
|
if (feed == null) {
|
||||||
Log.e(TAG, "Could not find feed for feed id: " + status.getFeedfileId());
|
Log.e(TAG, "Could not find feed for feed id: " + status.getFeedfileId());
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -28,7 +28,7 @@ public class DownloadLogDetailsDialog extends MaterialAlertDialogBuilder {
|
||||||
url = media.getDownloadUrl();
|
url = media.getDownloadUrl();
|
||||||
}
|
}
|
||||||
} else if (status.getFeedfileType() == Feed.FEEDFILETYPE_FEED) {
|
} else if (status.getFeedfileType() == Feed.FEEDFILETYPE_FEED) {
|
||||||
Feed feed = DBReader.getFeed(status.getFeedfileId());
|
Feed feed = DBReader.getFeed(status.getFeedfileId(), false, 0, 0);
|
||||||
if (feed != null) {
|
if (feed != null) {
|
||||||
url = feed.getDownloadUrl();
|
url = feed.getDownloadUrl();
|
||||||
}
|
}
|
||||||
|
|
|
@ -168,7 +168,7 @@ public class FeedInfoFragment extends Fragment implements MaterialToolbar.OnMenu
|
||||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||||
long feedId = getArguments().getLong(EXTRA_FEED_ID);
|
long feedId = getArguments().getLong(EXTRA_FEED_ID);
|
||||||
disposable = Maybe.create((MaybeOnSubscribe<Feed>) emitter -> {
|
disposable = Maybe.create((MaybeOnSubscribe<Feed>) emitter -> {
|
||||||
Feed feed = DBReader.getFeed(feedId);
|
Feed feed = DBReader.getFeed(feedId, false, 0, 0);
|
||||||
if (feed != null) {
|
if (feed != null) {
|
||||||
emitter.onSuccess(feed);
|
emitter.onSuccess(feed);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -17,6 +17,7 @@ import android.widget.Toast;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.content.res.AppCompatResources;
|
import androidx.appcompat.content.res.AppCompatResources;
|
||||||
|
import androidx.core.util.Pair;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
@ -49,7 +50,6 @@ import de.danoeh.antennapod.event.FeedEvent;
|
||||||
import de.danoeh.antennapod.ui.MenuItemUtils;
|
import de.danoeh.antennapod.ui.MenuItemUtils;
|
||||||
import de.danoeh.antennapod.storage.database.DBReader;
|
import de.danoeh.antennapod.storage.database.DBReader;
|
||||||
import de.danoeh.antennapod.storage.database.DBWriter;
|
import de.danoeh.antennapod.storage.database.DBWriter;
|
||||||
import de.danoeh.antennapod.storage.database.FeedItemPermutors;
|
|
||||||
import de.danoeh.antennapod.ui.common.IntentUtils;
|
import de.danoeh.antennapod.ui.common.IntentUtils;
|
||||||
import de.danoeh.antennapod.ui.share.ShareUtils;
|
import de.danoeh.antennapod.ui.share.ShareUtils;
|
||||||
import de.danoeh.antennapod.ui.episodeslist.MoreContentListFooterUtil;
|
import de.danoeh.antennapod.ui.episodeslist.MoreContentListFooterUtil;
|
||||||
|
@ -73,7 +73,6 @@ import de.danoeh.antennapod.model.download.DownloadResult;
|
||||||
import de.danoeh.antennapod.model.feed.Feed;
|
import de.danoeh.antennapod.model.feed.Feed;
|
||||||
import de.danoeh.antennapod.model.feed.FeedItem;
|
import de.danoeh.antennapod.model.feed.FeedItem;
|
||||||
import de.danoeh.antennapod.model.feed.FeedItemFilter;
|
import de.danoeh.antennapod.model.feed.FeedItemFilter;
|
||||||
import de.danoeh.antennapod.model.feed.SortOrder;
|
|
||||||
import de.danoeh.antennapod.storage.preferences.UserPreferences;
|
import de.danoeh.antennapod.storage.preferences.UserPreferences;
|
||||||
import de.danoeh.antennapod.ui.glide.FastBlurTransformation;
|
import de.danoeh.antennapod.ui.glide.FastBlurTransformation;
|
||||||
import de.danoeh.antennapod.ui.episodeslist.EpisodeItemViewHolder;
|
import de.danoeh.antennapod.ui.episodeslist.EpisodeItemViewHolder;
|
||||||
|
@ -91,6 +90,10 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
|
||||||
public static final String TAG = "ItemlistFragment";
|
public static final String TAG = "ItemlistFragment";
|
||||||
private static final String ARGUMENT_FEED_ID = "argument.de.danoeh.antennapod.feed_id";
|
private static final String ARGUMENT_FEED_ID = "argument.de.danoeh.antennapod.feed_id";
|
||||||
private static final String KEY_UP_ARROW = "up_arrow";
|
private static final String KEY_UP_ARROW = "up_arrow";
|
||||||
|
protected static final int EPISODES_PER_PAGE = 150;
|
||||||
|
protected int page = 1;
|
||||||
|
protected boolean isLoadingMore = false;
|
||||||
|
protected boolean hasMoreItems = false;
|
||||||
|
|
||||||
private FeedItemListAdapter adapter;
|
private FeedItemListAdapter adapter;
|
||||||
private SwipeActions swipeActions;
|
private SwipeActions swipeActions;
|
||||||
|
@ -147,6 +150,7 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
|
||||||
}
|
}
|
||||||
((MainActivity) getActivity()).setupToolbarToggle(viewBinding.toolbar, displayUpArrow);
|
((MainActivity) getActivity()).setupToolbarToggle(viewBinding.toolbar, displayUpArrow);
|
||||||
updateToolbar();
|
updateToolbar();
|
||||||
|
setupLoadMoreScrollListener();
|
||||||
|
|
||||||
viewBinding.recyclerView.setRecycledViewPool(((MainActivity) getActivity()).getRecycledViewPool());
|
viewBinding.recyclerView.setRecycledViewPool(((MainActivity) getActivity()).getRecycledViewPool());
|
||||||
adapter = new FeedItemListAdapter((MainActivity) getActivity());
|
adapter = new FeedItemListAdapter((MainActivity) getActivity());
|
||||||
|
@ -317,6 +321,21 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
|
||||||
return FeedItemMenuHandler.onMenuItemClicked(this, item.getItemId(), selectedItem);
|
return FeedItemMenuHandler.onMenuItemClicked(this, item.getItemId(), selectedItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setupLoadMoreScrollListener() {
|
||||||
|
viewBinding.recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
|
||||||
|
@Override
|
||||||
|
public void onScrolled(@NonNull RecyclerView view, int deltaX, int deltaY) {
|
||||||
|
super.onScrolled(view, deltaX, deltaY);
|
||||||
|
if (!isLoadingMore && hasMoreItems && viewBinding.recyclerView.isScrolledToBottom()) {
|
||||||
|
/* The end of the list has been reached. Load more data. */
|
||||||
|
page++;
|
||||||
|
loadMoreItems();
|
||||||
|
isLoadingMore = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||||
MainActivity activity = (MainActivity) getActivity();
|
MainActivity activity = (MainActivity) getActivity();
|
||||||
|
@ -535,17 +554,23 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
|
||||||
if (disposable != null) {
|
if (disposable != null) {
|
||||||
disposable.dispose();
|
disposable.dispose();
|
||||||
}
|
}
|
||||||
disposable = Observable.fromCallable(this::loadData)
|
disposable = Observable.fromCallable(
|
||||||
|
() -> {
|
||||||
|
feed = DBReader.getFeed(feedID, true, 0, page * EPISODES_PER_PAGE);
|
||||||
|
int count = DBReader.getFeedEpisodeCount(feed.getId(), feed.getItemFilter());
|
||||||
|
return new Pair<>(feed, count);
|
||||||
|
})
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe(
|
.subscribe(
|
||||||
result -> {
|
result -> {
|
||||||
feed = result;
|
hasMoreItems = !(page == 1 && feed.getItems().size() < EPISODES_PER_PAGE);
|
||||||
swipeActions.setFilter(feed.getItemFilter());
|
swipeActions.setFilter(feed.getItemFilter());
|
||||||
refreshHeaderView();
|
refreshHeaderView();
|
||||||
viewBinding.progressBar.setVisibility(View.GONE);
|
viewBinding.progressBar.setVisibility(View.GONE);
|
||||||
adapter.setDummyViews(0);
|
adapter.setDummyViews(0);
|
||||||
adapter.updateItems(feed.getItems());
|
adapter.updateItems(feed.getItems());
|
||||||
|
adapter.setTotalNumberOfItems(result.second);
|
||||||
updateToolbar();
|
updateToolbar();
|
||||||
}, error -> {
|
}, error -> {
|
||||||
feed = null;
|
feed = null;
|
||||||
|
@ -557,19 +582,37 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
private void loadMoreItems() {
|
||||||
private Feed loadData() {
|
if (disposable != null) {
|
||||||
Feed feed = DBReader.getFeed(feedID, true);
|
disposable.dispose();
|
||||||
if (feed == null) {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
DBReader.loadAdditionalFeedItemListData(feed.getItems());
|
isLoadingMore = true;
|
||||||
if (feed.getSortOrder() != null) {
|
adapter.setDummyViews(1);
|
||||||
List<FeedItem> feedItems = feed.getItems();
|
adapter.notifyItemInserted(adapter.getItemCount() - 1);
|
||||||
FeedItemPermutors.getPermutor(feed.getSortOrder()).reorder(feedItems);
|
disposable = Observable.fromCallable(() -> DBReader.getFeed(feedID, true,
|
||||||
feed.setItems(feedItems);
|
(page - 1) * EPISODES_PER_PAGE, EPISODES_PER_PAGE))
|
||||||
}
|
.subscribeOn(Schedulers.io())
|
||||||
return feed;
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe(
|
||||||
|
data -> {
|
||||||
|
if (data.getItems().size() < EPISODES_PER_PAGE) {
|
||||||
|
hasMoreItems = false;
|
||||||
|
}
|
||||||
|
feed.getItems().addAll(data.getItems());
|
||||||
|
adapter.setDummyViews(0);
|
||||||
|
adapter.updateItems(feed.getItems());
|
||||||
|
if (adapter.shouldSelectLazyLoadedItems()) {
|
||||||
|
adapter.setSelected(feed.getItems().size() - data.getItems().size(),
|
||||||
|
feed.getItems().size(), true);
|
||||||
|
}
|
||||||
|
}, error -> {
|
||||||
|
adapter.setDummyViews(0);
|
||||||
|
adapter.updateItems(Collections.emptyList());
|
||||||
|
Log.e(TAG, Log.getStackTraceString(error));
|
||||||
|
}, () -> {
|
||||||
|
// Make sure to not always load 2 pages at once
|
||||||
|
viewBinding.recyclerView.post(() -> isLoadingMore = false);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||||
|
@ -608,45 +651,4 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
|
||||||
MenuItemUtils.setOnClickListeners(menu, FeedItemlistFragment.this::onContextItemSelected);
|
MenuItemUtils.setOnClickListeners(menu, FeedItemlistFragment.this::onContextItemSelected);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class SingleFeedSortDialog extends ItemSortDialog {
|
|
||||||
private static final String ARG_FEED_ID = "feedId";
|
|
||||||
private static final String ARG_FEED_IS_LOCAL = "isLocal";
|
|
||||||
private static final String ARG_SORT_ORDER = "sortOrder";
|
|
||||||
|
|
||||||
private static SingleFeedSortDialog newInstance(Feed feed) {
|
|
||||||
Bundle bundle = new Bundle();
|
|
||||||
bundle.putLong(ARG_FEED_ID, feed.getId());
|
|
||||||
bundle.putBoolean(ARG_FEED_IS_LOCAL, feed.isLocalFeed());
|
|
||||||
if (feed.getSortOrder() == null) {
|
|
||||||
bundle.putString(ARG_SORT_ORDER, String.valueOf(SortOrder.DATE_NEW_OLD.code));
|
|
||||||
} else {
|
|
||||||
bundle.putString(ARG_SORT_ORDER, String.valueOf(feed.getSortOrder().code));
|
|
||||||
}
|
|
||||||
SingleFeedSortDialog dialog = new SingleFeedSortDialog();
|
|
||||||
dialog.setArguments(bundle);
|
|
||||||
return dialog;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
sortOrder = SortOrder.fromCodeString(getArguments().getString(ARG_SORT_ORDER));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onAddItem(int title, SortOrder ascending, SortOrder descending, boolean ascendingIsDefault) {
|
|
||||||
if (ascending == SortOrder.DATE_OLD_NEW || ascending == SortOrder.DURATION_SHORT_LONG
|
|
||||||
|| ascending == SortOrder.EPISODE_TITLE_A_Z
|
|
||||||
|| (getArguments().getBoolean(ARG_FEED_IS_LOCAL) && ascending == SortOrder.EPISODE_FILENAME_A_Z)) {
|
|
||||||
super.onAddItem(title, ascending, descending, ascendingIsDefault);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onSelectionChanged() {
|
|
||||||
super.onSelectionChanged();
|
|
||||||
DBWriter.setFeedItemSortOrder(getArguments().getLong(ARG_FEED_ID), sortOrder);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
package de.danoeh.antennapod.ui.screen.feed;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import de.danoeh.antennapod.model.feed.Feed;
|
||||||
|
import de.danoeh.antennapod.model.feed.SortOrder;
|
||||||
|
import de.danoeh.antennapod.storage.database.DBWriter;
|
||||||
|
|
||||||
|
public class SingleFeedSortDialog extends ItemSortDialog {
|
||||||
|
private static final String ARG_FEED_ID = "feedId";
|
||||||
|
private static final String ARG_FEED_IS_LOCAL = "isLocal";
|
||||||
|
private static final String ARG_SORT_ORDER = "sortOrder";
|
||||||
|
|
||||||
|
public static SingleFeedSortDialog newInstance(Feed feed) {
|
||||||
|
Bundle bundle = new Bundle();
|
||||||
|
bundle.putLong(ARG_FEED_ID, feed.getId());
|
||||||
|
bundle.putBoolean(ARG_FEED_IS_LOCAL, feed.isLocalFeed());
|
||||||
|
if (feed.getSortOrder() == null) {
|
||||||
|
bundle.putString(ARG_SORT_ORDER, String.valueOf(SortOrder.DATE_NEW_OLD.code));
|
||||||
|
} else {
|
||||||
|
bundle.putString(ARG_SORT_ORDER, String.valueOf(feed.getSortOrder().code));
|
||||||
|
}
|
||||||
|
SingleFeedSortDialog dialog = new SingleFeedSortDialog();
|
||||||
|
dialog.setArguments(bundle);
|
||||||
|
return dialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
sortOrder = SortOrder.fromCodeString(getArguments().getString(ARG_SORT_ORDER));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onAddItem(int title, SortOrder ascending, SortOrder descending, boolean ascendingIsDefault) {
|
||||||
|
if (ascending == SortOrder.DATE_OLD_NEW || ascending == SortOrder.DURATION_SHORT_LONG
|
||||||
|
|| ascending == SortOrder.EPISODE_TITLE_A_Z
|
||||||
|
|| (getArguments().getBoolean(ARG_FEED_IS_LOCAL) && ascending == SortOrder.EPISODE_FILENAME_A_Z)) {
|
||||||
|
super.onAddItem(title, ascending, descending, ascendingIsDefault);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onSelectionChanged() {
|
||||||
|
super.onSelectionChanged();
|
||||||
|
DBWriter.setFeedItemSortOrder(getArguments().getLong(ARG_FEED_ID), sortOrder);
|
||||||
|
}
|
||||||
|
}
|
|
@ -81,7 +81,7 @@ public class FeedSettingsFragment extends Fragment {
|
||||||
.commitAllowingStateLoss();
|
.commitAllowingStateLoss();
|
||||||
|
|
||||||
disposable = Maybe.create((MaybeOnSubscribe<Feed>) emitter -> {
|
disposable = Maybe.create((MaybeOnSubscribe<Feed>) emitter -> {
|
||||||
Feed feed = DBReader.getFeed(feedId);
|
Feed feed = DBReader.getFeed(feedId, false, 0, 0);
|
||||||
if (feed != null) {
|
if (feed != null) {
|
||||||
emitter.onSuccess(feed);
|
emitter.onSuccess(feed);
|
||||||
} else {
|
} else {
|
||||||
|
@ -163,7 +163,7 @@ public class FeedSettingsFragment extends Fragment {
|
||||||
|
|
||||||
long feedId = getArguments().getLong(EXTRA_FEED_ID);
|
long feedId = getArguments().getLong(EXTRA_FEED_ID);
|
||||||
disposable = Maybe.create((MaybeOnSubscribe<Feed>) emitter -> {
|
disposable = Maybe.create((MaybeOnSubscribe<Feed>) emitter -> {
|
||||||
Feed feed = DBReader.getFeed(feedId);
|
Feed feed = DBReader.getFeed(feedId, false, 0, 0);
|
||||||
if (feed != null) {
|
if (feed != null) {
|
||||||
emitter.onSuccess(feed);
|
emitter.onSuccess(feed);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -526,7 +526,7 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
|
||||||
if (didPressSubscribe) {
|
if (didPressSubscribe) {
|
||||||
didPressSubscribe = false;
|
didPressSubscribe = false;
|
||||||
|
|
||||||
Feed feed1 = DBReader.getFeed(getFeedId());
|
Feed feed1 = DBReader.getFeed(getFeedId(), false, 0, 0);
|
||||||
FeedPreferences feedPreferences = feed1.getPreferences();
|
FeedPreferences feedPreferences = feed1.getPreferences();
|
||||||
if (UserPreferences.isEnableAutodownload()) {
|
if (UserPreferences.isEnableAutodownload()) {
|
||||||
boolean autoDownload = viewBinding.autoDownloadCheckBox.isChecked();
|
boolean autoDownload = viewBinding.autoDownloadCheckBox.isChecked();
|
||||||
|
|
|
@ -76,7 +76,7 @@ public class FeedUpdateWorker extends Worker {
|
||||||
}
|
}
|
||||||
Collections.shuffle(toUpdate); // If the worker gets cancelled early, every feed has a chance to be updated
|
Collections.shuffle(toUpdate); // If the worker gets cancelled early, every feed has a chance to be updated
|
||||||
} else {
|
} else {
|
||||||
Feed feed = DBReader.getFeed(feedId);
|
Feed feed = DBReader.getFeed(feedId, false, 0, Integer.MAX_VALUE);
|
||||||
if (feed == null) {
|
if (feed == null) {
|
||||||
return Result.success();
|
return Result.success();
|
||||||
}
|
}
|
||||||
|
|
|
@ -154,7 +154,7 @@ public class DbReaderTest {
|
||||||
List<FeedItem> items = feed.getItems();
|
List<FeedItem> items = feed.getItems();
|
||||||
feed.setItems(null);
|
feed.setItems(null);
|
||||||
List<FeedItem> savedItems = DBReader.getFeedItemList(feed,
|
List<FeedItem> savedItems = DBReader.getFeedItemList(feed,
|
||||||
FeedItemFilter.unfiltered(), SortOrder.DATE_NEW_OLD);
|
FeedItemFilter.unfiltered(), SortOrder.DATE_NEW_OLD, 0, Integer.MAX_VALUE);
|
||||||
assertNotNull(savedItems);
|
assertNotNull(savedItems);
|
||||||
assertEquals(items.size(), savedItems.size());
|
assertEquals(items.size(), savedItems.size());
|
||||||
for (int i = 0; i < savedItems.size(); i++) {
|
for (int i = 0; i < savedItems.size(); i++) {
|
||||||
|
|
|
@ -133,7 +133,7 @@ public class DbTasksTest {
|
||||||
|
|
||||||
updatedFeedTest(newFeed, feedID, itemIDs, numItemsOld, numItemsNew);
|
updatedFeedTest(newFeed, feedID, itemIDs, numItemsOld, numItemsNew);
|
||||||
|
|
||||||
final Feed feedFromDB = DBReader.getFeed(newFeed.getId());
|
final Feed feedFromDB = DBReader.getFeed(newFeed.getId(), false, 0, Integer.MAX_VALUE);
|
||||||
assertNotNull(feedFromDB);
|
assertNotNull(feedFromDB);
|
||||||
assertEquals(newFeed.getId(), feedFromDB.getId());
|
assertEquals(newFeed.getId(), feedFromDB.getId());
|
||||||
updatedFeedTest(feedFromDB, feedID, itemIDs, numItemsOld, numItemsNew);
|
updatedFeedTest(feedFromDB, feedID, itemIDs, numItemsOld, numItemsNew);
|
||||||
|
@ -163,7 +163,7 @@ public class DbTasksTest {
|
||||||
final Feed newFeed = FeedDatabaseWriter.updateFeed(context, feed, false);
|
final Feed newFeed = FeedDatabaseWriter.updateFeed(context, feed, false);
|
||||||
assertNotSame(newFeed, feed);
|
assertNotSame(newFeed, feed);
|
||||||
|
|
||||||
final Feed feedFromDB = DBReader.getFeed(newFeed.getId());
|
final Feed feedFromDB = DBReader.getFeed(newFeed.getId(), false, 0, Integer.MAX_VALUE);
|
||||||
final FeedItem feedItemFromDB = feedFromDB.getItems().get(0);
|
final FeedItem feedItemFromDB = feedFromDB.getItems().get(0);
|
||||||
assertTrue(feedItemFromDB.isNew());
|
assertTrue(feedItemFromDB.isNew());
|
||||||
}
|
}
|
||||||
|
@ -186,7 +186,7 @@ public class DbTasksTest {
|
||||||
Feed newFeed = FeedDatabaseWriter.updateFeed(context, feed, true);
|
Feed newFeed = FeedDatabaseWriter.updateFeed(context, feed, true);
|
||||||
assertEquals(8, newFeed.getItems().size()); // 10 - 2 = 8 items
|
assertEquals(8, newFeed.getItems().size()); // 10 - 2 = 8 items
|
||||||
|
|
||||||
Feed feedFromDB = DBReader.getFeed(newFeed.getId());
|
Feed feedFromDB = DBReader.getFeed(newFeed.getId(), false, 0, Integer.MAX_VALUE);
|
||||||
assertEquals(8, feedFromDB.getItems().size()); // 10 - 2 = 8 items
|
assertEquals(8, feedFromDB.getItems().size()); // 10 - 2 = 8 items
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,7 +213,7 @@ public class DbTasksTest {
|
||||||
Feed newFeed = FeedDatabaseWriter.updateFeed(context, feed, false);
|
Feed newFeed = FeedDatabaseWriter.updateFeed(context, feed, false);
|
||||||
assertEquals(10, newFeed.getItems().size()); // id 1-duplicate replaces because the stream url is the same
|
assertEquals(10, newFeed.getItems().size()); // id 1-duplicate replaces because the stream url is the same
|
||||||
|
|
||||||
Feed feedFromDB = DBReader.getFeed(newFeed.getId());
|
Feed feedFromDB = DBReader.getFeed(newFeed.getId(), false, 0, Integer.MAX_VALUE);
|
||||||
assertEquals(10, feedFromDB.getItems().size()); // id1-duplicate should override id 1
|
assertEquals(10, feedFromDB.getItems().size()); // id1-duplicate should override id 1
|
||||||
|
|
||||||
FeedItem updatedItem = feedFromDB.getItemAtIndex(9);
|
FeedItem updatedItem = feedFromDB.getItemAtIndex(9);
|
||||||
|
|
|
@ -771,7 +771,7 @@ public class DbWriterTest {
|
||||||
|
|
||||||
DBWriter.removeAllNewFlags().get();
|
DBWriter.removeAllNewFlags().get();
|
||||||
List<FeedItem> loadedItems = DBReader.getFeedItemList(feed,
|
List<FeedItem> loadedItems = DBReader.getFeedItemList(feed,
|
||||||
FeedItemFilter.unfiltered(), SortOrder.DATE_NEW_OLD);
|
FeedItemFilter.unfiltered(), SortOrder.DATE_NEW_OLD, 0, Integer.MAX_VALUE);
|
||||||
for (FeedItem item : loadedItems) {
|
for (FeedItem item : loadedItems) {
|
||||||
assertFalse(item.isNew());
|
assertFalse(item.isNew());
|
||||||
}
|
}
|
||||||
|
|
|
@ -169,7 +169,8 @@ public class LocalFeedUpdaterTest {
|
||||||
callUpdateFeed(LOCAL_FEED_DIR1);
|
callUpdateFeed(LOCAL_FEED_DIR1);
|
||||||
|
|
||||||
Feed feed = verifySingleFeedInDatabase();
|
Feed feed = verifySingleFeedInDatabase();
|
||||||
List<FeedItem> feedItems = DBReader.getFeedItemList(feed, FeedItemFilter.unfiltered(), SortOrder.DATE_NEW_OLD);
|
List<FeedItem> feedItems = DBReader.getFeedItemList(feed, FeedItemFilter.unfiltered(),
|
||||||
|
SortOrder.DATE_NEW_OLD, 0, Integer.MAX_VALUE);
|
||||||
assertEquals("track1.mp3", feedItems.get(0).getTitle());
|
assertEquals("track1.mp3", feedItems.get(0).getTitle());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -283,7 +284,8 @@ public class LocalFeedUpdaterTest {
|
||||||
*/
|
*/
|
||||||
private static void verifySingleFeedInDatabaseAndItemCount(int expectedItemCount) {
|
private static void verifySingleFeedInDatabaseAndItemCount(int expectedItemCount) {
|
||||||
Feed feed = verifySingleFeedInDatabase();
|
Feed feed = verifySingleFeedInDatabase();
|
||||||
List<FeedItem> feedItems = DBReader.getFeedItemList(feed, FeedItemFilter.unfiltered(), SortOrder.DATE_NEW_OLD);
|
List<FeedItem> feedItems = DBReader.getFeedItemList(feed, FeedItemFilter.unfiltered(),
|
||||||
|
SortOrder.DATE_NEW_OLD, 0, Integer.MAX_VALUE);
|
||||||
assertEquals(expectedItemCount, feedItems.size());
|
assertEquals(expectedItemCount, feedItems.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -94,7 +94,6 @@ import de.danoeh.antennapod.model.feed.FeedItem;
|
||||||
import de.danoeh.antennapod.model.feed.FeedItemFilter;
|
import de.danoeh.antennapod.model.feed.FeedItemFilter;
|
||||||
import de.danoeh.antennapod.model.feed.FeedMedia;
|
import de.danoeh.antennapod.model.feed.FeedMedia;
|
||||||
import de.danoeh.antennapod.model.feed.FeedPreferences;
|
import de.danoeh.antennapod.model.feed.FeedPreferences;
|
||||||
import de.danoeh.antennapod.model.feed.SortOrder;
|
|
||||||
import de.danoeh.antennapod.model.playback.MediaType;
|
import de.danoeh.antennapod.model.playback.MediaType;
|
||||||
import de.danoeh.antennapod.model.playback.Playable;
|
import de.danoeh.antennapod.model.playback.Playable;
|
||||||
import de.danoeh.antennapod.playback.base.PlaybackServiceMediaPlayer;
|
import de.danoeh.antennapod.playback.base.PlaybackServiceMediaPlayer;
|
||||||
|
@ -452,12 +451,7 @@ public class PlaybackService extends MediaBrowserServiceCompat {
|
||||||
new FeedItemFilter(FeedItemFilter.UNPLAYED), UserPreferences.getAllEpisodesSortOrder());
|
new FeedItemFilter(FeedItemFilter.UNPLAYED), UserPreferences.getAllEpisodesSortOrder());
|
||||||
} else if (parentId.startsWith("FeedId:")) {
|
} else if (parentId.startsWith("FeedId:")) {
|
||||||
long feedId = Long.parseLong(parentId.split(":")[1]);
|
long feedId = Long.parseLong(parentId.split(":")[1]);
|
||||||
Feed feed = DBReader.getFeed(feedId);
|
feedItems = DBReader.getFeed(feedId, true, 0, MAX_ANDROID_AUTO_EPISODES_PER_FEED).getItems();
|
||||||
SortOrder sortOrder = feed.getSortOrder();
|
|
||||||
if (sortOrder == null) {
|
|
||||||
sortOrder = SortOrder.DATE_NEW_OLD;
|
|
||||||
}
|
|
||||||
feedItems = DBReader.getFeedItemList(feed, FeedItemFilter.unfiltered(), sortOrder);
|
|
||||||
} else if (parentId.equals(getString(R.string.current_playing_episode))) {
|
} else if (parentId.equals(getString(R.string.current_playing_episode))) {
|
||||||
FeedMedia playable = DBReader.getFeedMedia(PlaybackPreferences.getCurrentlyPlayingFeedMediaId());
|
FeedMedia playable = DBReader.getFeedMedia(PlaybackPreferences.getCurrentlyPlayingFeedMediaId());
|
||||||
if (playable != null) {
|
if (playable != null) {
|
||||||
|
|
|
@ -149,12 +149,14 @@ public final class DBReader {
|
||||||
* @param feed The Feed whose items should be loaded
|
* @param feed The Feed whose items should be loaded
|
||||||
* @return A list with the FeedItems of the Feed. The Feed-attribute of the FeedItems will already be set correctly.
|
* @return A list with the FeedItems of the Feed. The Feed-attribute of the FeedItems will already be set correctly.
|
||||||
*/
|
*/
|
||||||
public static List<FeedItem> getFeedItemList(final Feed feed, final FeedItemFilter filter, SortOrder sortOrder) {
|
public static List<FeedItem> getFeedItemList(final Feed feed, final FeedItemFilter filter, SortOrder sortOrder,
|
||||||
|
int offset, int limit) {
|
||||||
Log.d(TAG, "getFeedItemList() called with: " + "feed = [" + feed + "]");
|
Log.d(TAG, "getFeedItemList() called with: " + "feed = [" + feed + "]");
|
||||||
|
|
||||||
PodDBAdapter adapter = PodDBAdapter.getInstance();
|
PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||||
adapter.open();
|
adapter.open();
|
||||||
try (FeedItemCursor cursor = new FeedItemCursor(adapter.getItemsOfFeedCursor(feed, filter, sortOrder))) {
|
try (FeedItemCursor cursor = new FeedItemCursor(adapter.getItemsOfFeedCursor(
|
||||||
|
feed, filter, sortOrder, offset, limit))) {
|
||||||
List<FeedItem> items = extractItemlistFromCursor(cursor);
|
List<FeedItem> items = extractItemlistFromCursor(cursor);
|
||||||
feed.setItems(items);
|
feed.setItems(items);
|
||||||
for (FeedItem item : items) {
|
for (FeedItem item : items) {
|
||||||
|
@ -266,6 +268,19 @@ public final class DBReader {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int getFeedEpisodeCount(long feedId, FeedItemFilter filter) {
|
||||||
|
PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||||
|
adapter.open();
|
||||||
|
try (Cursor cursor = adapter.getFeedEpisodeCountCursor(feedId, filter)) {
|
||||||
|
if (cursor.moveToFirst()) {
|
||||||
|
return cursor.getInt(0);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
} finally {
|
||||||
|
adapter.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static List<FeedItem> getRandomEpisodes(int limit, int seed) {
|
public static List<FeedItem> getRandomEpisodes(int limit, int seed) {
|
||||||
PodDBAdapter adapter = PodDBAdapter.getInstance();
|
PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||||
adapter.open();
|
adapter.open();
|
||||||
|
@ -324,18 +339,6 @@ public final class DBReader {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads a specific Feed from the database.
|
|
||||||
*
|
|
||||||
* @param feedId The ID of the Feed
|
|
||||||
* @return The Feed or null if the Feed could not be found. The Feeds FeedItems will also be loaded from the
|
|
||||||
* database and the items-attribute will be set correctly.
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
public static Feed getFeed(final long feedId) {
|
|
||||||
return getFeed(feedId, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads a specific Feed from the database.
|
* Loads a specific Feed from the database.
|
||||||
*
|
*
|
||||||
|
@ -345,7 +348,7 @@ public final class DBReader {
|
||||||
* database and the items-attribute will be set correctly.
|
* database and the items-attribute will be set correctly.
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
public static Feed getFeed(final long feedId, boolean filtered) {
|
public static Feed getFeed(final long feedId, boolean filtered, int offset, int limit) {
|
||||||
Log.d(TAG, "getFeed() called with: " + "feedId = [" + feedId + "]");
|
Log.d(TAG, "getFeed() called with: " + "feedId = [" + feedId + "]");
|
||||||
PodDBAdapter adapter = PodDBAdapter.getInstance();
|
PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||||
adapter.open();
|
adapter.open();
|
||||||
|
@ -354,7 +357,12 @@ public final class DBReader {
|
||||||
if (cursor.moveToNext()) {
|
if (cursor.moveToNext()) {
|
||||||
feed = cursor.getFeed();
|
feed = cursor.getFeed();
|
||||||
FeedItemFilter filter = filtered ? feed.getItemFilter() : FeedItemFilter.unfiltered();
|
FeedItemFilter filter = filtered ? feed.getItemFilter() : FeedItemFilter.unfiltered();
|
||||||
feed.setItems(getFeedItemList(feed, filter, feed.getSortOrder()));
|
List<FeedItem> items = getFeedItemList(feed, filter, feed.getSortOrder(), offset, limit);
|
||||||
|
for (FeedItem item : items) {
|
||||||
|
item.setFeed(feed);
|
||||||
|
}
|
||||||
|
loadTagsOfFeedItemList(items);
|
||||||
|
feed.setItems(items);
|
||||||
} else {
|
} else {
|
||||||
Log.e(TAG, "getFeed could not find feed with id " + feedId);
|
Log.e(TAG, "getFeed could not find feed with id " + feedId);
|
||||||
}
|
}
|
||||||
|
|
|
@ -161,7 +161,7 @@ public class DBWriter {
|
||||||
*/
|
*/
|
||||||
public static Future<?> deleteFeed(final Context context, final long feedId) {
|
public static Future<?> deleteFeed(final Context context, final long feedId) {
|
||||||
return runOnDbThread(() -> {
|
return runOnDbThread(() -> {
|
||||||
final Feed feed = DBReader.getFeed(feedId, false);
|
final Feed feed = DBReader.getFeed(feedId, false, 0, Integer.MAX_VALUE);
|
||||||
if (feed == null) {
|
if (feed == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,12 +31,13 @@ public abstract class FeedDatabaseWriter {
|
||||||
|
|
||||||
private static Feed searchFeedByIdentifyingValueOrID(Feed feed) {
|
private static Feed searchFeedByIdentifyingValueOrID(Feed feed) {
|
||||||
if (feed.getId() != 0) {
|
if (feed.getId() != 0) {
|
||||||
return DBReader.getFeed(feed.getId());
|
return DBReader.getFeed(feed.getId(), false, 0, Integer.MAX_VALUE);
|
||||||
} else {
|
} else {
|
||||||
List<Feed> feeds = DBReader.getFeedList();
|
List<Feed> feeds = DBReader.getFeedList();
|
||||||
for (Feed f : feeds) {
|
for (Feed f : feeds) {
|
||||||
if (f.getIdentifyingValue().equals(feed.getIdentifyingValue())) {
|
if (f.getIdentifyingValue().equals(feed.getIdentifyingValue())) {
|
||||||
f.setItems(DBReader.getFeedItemList(f, FeedItemFilter.unfiltered(), SortOrder.DATE_NEW_OLD));
|
f.setItems(DBReader.getFeedItemList(f, FeedItemFilter.unfiltered(),
|
||||||
|
SortOrder.DATE_NEW_OLD, 0, Integer.MAX_VALUE));
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -954,14 +954,16 @@ public class PodDBAdapter {
|
||||||
* @param feed The feed you want to get the FeedItems from.
|
* @param feed The feed you want to get the FeedItems from.
|
||||||
* @return The cursor of the query
|
* @return The cursor of the query
|
||||||
*/
|
*/
|
||||||
public final Cursor getItemsOfFeedCursor(final Feed feed, FeedItemFilter filter, SortOrder sortOrder) {
|
public final Cursor getItemsOfFeedCursor(final Feed feed, FeedItemFilter filter, SortOrder sortOrder,
|
||||||
|
int offset, int limit) {
|
||||||
String orderByQuery = FeedItemSortQuery.generateFrom(sortOrder);
|
String orderByQuery = FeedItemSortQuery.generateFrom(sortOrder);
|
||||||
String filterQuery = FeedItemFilterQuery.generateFrom(filter);
|
String filterQuery = FeedItemFilterQuery.generateFrom(filter);
|
||||||
String whereClauseAnd = "".equals(filterQuery) ? "" : " AND " + filterQuery;
|
String whereClauseAnd = "".equals(filterQuery) ? "" : " AND " + filterQuery;
|
||||||
final String query = SELECT_FEED_ITEMS_AND_MEDIA
|
final String query = SELECT_FEED_ITEMS_AND_MEDIA
|
||||||
+ " WHERE " + TABLE_NAME_FEED_ITEMS + "." + KEY_FEED + "=" + feed.getId()
|
+ " WHERE " + TABLE_NAME_FEED_ITEMS + "." + KEY_FEED + "=" + feed.getId()
|
||||||
+ whereClauseAnd
|
+ whereClauseAnd
|
||||||
+ " ORDER BY " + orderByQuery;
|
+ " ORDER BY " + orderByQuery
|
||||||
|
+ " LIMIT " + offset + ", " + limit;
|
||||||
return db.rawQuery(query, null);
|
return db.rawQuery(query, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1082,6 +1084,15 @@ public class PodDBAdapter {
|
||||||
return db.rawQuery(query, null);
|
return db.rawQuery(query, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final Cursor getFeedEpisodeCountCursor(long feedId, FeedItemFilter filter) {
|
||||||
|
String filterQuery = FeedItemFilterQuery.generateFrom(filter);
|
||||||
|
String whereAndClause = "".equals(filterQuery) ? "" : " AND " + filterQuery;
|
||||||
|
final String query = "SELECT count(" + TABLE_NAME_FEED_ITEMS + "." + KEY_ID + ") FROM " + TABLE_NAME_FEED_ITEMS
|
||||||
|
+ JOIN_FEED_ITEM_AND_MEDIA
|
||||||
|
+ " WHERE " + TABLE_NAME_FEED_ITEMS + "." + KEY_FEED + "=" + feedId + whereAndClause;
|
||||||
|
return db.rawQuery(query, null);
|
||||||
|
}
|
||||||
|
|
||||||
public Cursor getRandomEpisodesCursor(int limit, int seed) {
|
public Cursor getRandomEpisodesCursor(int limit, int seed) {
|
||||||
final String allItemsRandomOrder = SELECT_FEED_ITEMS_AND_MEDIA
|
final String allItemsRandomOrder = SELECT_FEED_ITEMS_AND_MEDIA
|
||||||
+ " WHERE (" + KEY_READ + " = " + FeedItem.NEW + " OR " + KEY_READ + " = " + FeedItem.UNPLAYED + ") "
|
+ " WHERE (" + KEY_READ + " = " + FeedItem.NEW + " OR " + KEY_READ + " = " + FeedItem.UNPLAYED + ") "
|
||||||
|
|
|
@ -78,7 +78,7 @@ public class FeedStatisticsFragment extends Fragment {
|
||||||
for (StatisticsItem statisticsItem : statisticsData.feedTime) {
|
for (StatisticsItem statisticsItem : statisticsData.feedTime) {
|
||||||
if (statisticsItem.feed.getId() == feedId) {
|
if (statisticsItem.feed.getId() == feedId) {
|
||||||
List<FeedItem> items = DBReader.getFeedItemList(statisticsItem.feed,
|
List<FeedItem> items = DBReader.getFeedItemList(statisticsItem.feed,
|
||||||
FeedItemFilter.unfiltered(), SortOrder.DATE_OLD_NEW);
|
FeedItemFilter.unfiltered(), SortOrder.DATE_OLD_NEW, 0, Integer.MAX_VALUE);
|
||||||
List<Date> dates = new ArrayList<>();
|
List<Date> dates = new ArrayList<>();
|
||||||
for (FeedItem item : items) {
|
for (FeedItem item : items) {
|
||||||
dates.add(item.getPubDate());
|
dates.add(item.getPubDate());
|
||||||
|
|
Loading…
Reference in New Issue