Convert playback history fragment to lazy loading (#5886)
This commit is contained in:
parent
fd066a648b
commit
df53c5bfe5
|
@ -49,9 +49,9 @@ public class InboxFragment extends EpisodesListFragment implements Toolbar.OnMen
|
|||
@NonNull
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
View inboxContainer = View.inflate(getContext(), R.layout.inbox_fragment, null);
|
||||
View inboxContainer = View.inflate(getContext(), R.layout.list_container_fragment, null);
|
||||
View root = super.onCreateView(inflater, container, savedInstanceState);
|
||||
((FrameLayout) inboxContainer.findViewById(R.id.inboxContent)).addView(root);
|
||||
((FrameLayout) inboxContainer.findViewById(R.id.listContent)).addView(root);
|
||||
emptyView.setTitle(R.string.no_inbox_head_label);
|
||||
emptyView.setMessage(R.string.no_inbox_label);
|
||||
|
||||
|
|
|
@ -1,57 +1,36 @@
|
|||
package de.danoeh.antennapod.fragment;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.activity.MainActivity;
|
||||
import de.danoeh.antennapod.adapter.EpisodeItemListAdapter;
|
||||
import de.danoeh.antennapod.core.event.DownloadEvent;
|
||||
import de.danoeh.antennapod.core.event.DownloaderUpdate;
|
||||
import de.danoeh.antennapod.core.menuhandler.MenuItemUtils;
|
||||
import de.danoeh.antennapod.event.FeedItemEvent;
|
||||
import de.danoeh.antennapod.event.playback.PlaybackHistoryEvent;
|
||||
import de.danoeh.antennapod.event.playback.PlaybackPositionEvent;
|
||||
import de.danoeh.antennapod.event.PlayerStatusEvent;
|
||||
import de.danoeh.antennapod.event.UnreadItemsUpdateEvent;
|
||||
import de.danoeh.antennapod.model.feed.FeedItem;
|
||||
import de.danoeh.antennapod.core.storage.DBReader;
|
||||
import de.danoeh.antennapod.core.storage.DBWriter;
|
||||
import de.danoeh.antennapod.core.util.FeedItemUtil;
|
||||
import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
|
||||
import de.danoeh.antennapod.view.EmptyViewHandler;
|
||||
import de.danoeh.antennapod.view.EpisodeItemListRecyclerView;
|
||||
import de.danoeh.antennapod.view.viewholder.EpisodeItemViewHolder;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
import org.greenrobot.eventbus.ThreadMode;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class PlaybackHistoryFragment extends Fragment implements Toolbar.OnMenuItemClickListener {
|
||||
public class PlaybackHistoryFragment extends EpisodesListFragment implements Toolbar.OnMenuItemClickListener {
|
||||
public static final String TAG = "PlaybackHistoryFragment";
|
||||
private static final String KEY_UP_ARROW = "up_arrow";
|
||||
|
||||
private List<FeedItem> playbackHistory;
|
||||
private PlaybackHistoryListAdapter adapter;
|
||||
private Disposable disposable;
|
||||
private EpisodeItemListRecyclerView recyclerView;
|
||||
private EmptyViewHandler emptyView;
|
||||
private ProgressBar progressBar;
|
||||
private Toolbar toolbar;
|
||||
private boolean displayUpArrow;
|
||||
|
||||
|
@ -64,8 +43,12 @@ public class PlaybackHistoryFragment extends Fragment implements Toolbar.OnMenuI
|
|||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
View root = inflater.inflate(R.layout.simple_list_fragment, container, false);
|
||||
toolbar = root.findViewById(R.id.toolbar);
|
||||
View historyContainer = View.inflate(getContext(), R.layout.list_container_fragment, null);
|
||||
View root = super.onCreateView(inflater, container, savedInstanceState);
|
||||
|
||||
((FrameLayout) historyContainer.findViewById(R.id.listContent)).addView(root);
|
||||
|
||||
toolbar = historyContainer.findViewById(R.id.toolbar);
|
||||
toolbar.setTitle(R.string.playback_history_label);
|
||||
toolbar.setOnMenuItemClickListener(this);
|
||||
displayUpArrow = getParentFragmentManager().getBackStackEntryCount() != 0;
|
||||
|
@ -76,34 +59,14 @@ public class PlaybackHistoryFragment extends Fragment implements Toolbar.OnMenuI
|
|||
toolbar.inflateMenu(R.menu.playback_history);
|
||||
refreshToolbarState();
|
||||
|
||||
recyclerView = root.findViewById(R.id.recyclerView);
|
||||
recyclerView.setRecycledViewPool(((MainActivity) getActivity()).getRecycledViewPool());
|
||||
adapter = new PlaybackHistoryListAdapter((MainActivity) getActivity());
|
||||
recyclerView.setAdapter(adapter);
|
||||
progressBar = root.findViewById(R.id.progLoading);
|
||||
listAdapter = new PlaybackHistoryListAdapter((MainActivity) getActivity());
|
||||
recyclerView.setAdapter(listAdapter);
|
||||
|
||||
emptyView = new EmptyViewHandler(getActivity());
|
||||
emptyView.setIcon(R.drawable.ic_history);
|
||||
emptyView.setTitle(R.string.no_history_head_label);
|
||||
emptyView.setMessage(R.string.no_history_label);
|
||||
emptyView.attachToRecyclerView(recyclerView);
|
||||
return root;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
EventBus.getDefault().register(this);
|
||||
loadItems();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
super.onStop();
|
||||
EventBus.getDefault().unregister(this);
|
||||
if (disposable != null) {
|
||||
disposable.dispose();
|
||||
}
|
||||
return historyContainer;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -112,55 +75,8 @@ public class PlaybackHistoryFragment extends Fragment implements Toolbar.OnMenuI
|
|||
super.onSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
public void onEventMainThread(FeedItemEvent event) {
|
||||
Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
|
||||
if (playbackHistory == null) {
|
||||
return;
|
||||
} else if (adapter == null) {
|
||||
loadItems();
|
||||
return;
|
||||
}
|
||||
for (int i = 0, size = event.items.size(); i < size; i++) {
|
||||
FeedItem item = event.items.get(i);
|
||||
int pos = FeedItemUtil.indexOfItemWithId(playbackHistory, item.getId());
|
||||
if (pos >= 0) {
|
||||
playbackHistory.remove(pos);
|
||||
playbackHistory.add(pos, item);
|
||||
adapter.notifyItemChangedCompat(pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
|
||||
public void onEventMainThread(DownloadEvent event) {
|
||||
Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
|
||||
DownloaderUpdate update = event.update;
|
||||
if (adapter != null && update.mediaIds.length > 0) {
|
||||
for (long mediaId : update.mediaIds) {
|
||||
int pos = FeedItemUtil.indexOfItemWithMediaId(playbackHistory, mediaId);
|
||||
if (pos >= 0) {
|
||||
adapter.notifyItemChangedCompat(pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
public void onEventMainThread(PlaybackPositionEvent event) {
|
||||
if (adapter != null) {
|
||||
for (int i = 0; i < adapter.getItemCount(); i++) {
|
||||
EpisodeItemViewHolder holder = (EpisodeItemViewHolder) recyclerView.findViewHolderForAdapterPosition(i);
|
||||
if (holder != null && holder.isCurrentlyPlayingItem()) {
|
||||
holder.notifyPlaybackPositionUpdated(event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void refreshToolbarState() {
|
||||
boolean hasHistory = playbackHistory != null && !playbackHistory.isEmpty();
|
||||
boolean hasHistory = episodes != null && !episodes.isEmpty();
|
||||
toolbar.getMenu().findItem(R.id.clear_history_item).setVisible(hasHistory);
|
||||
}
|
||||
|
||||
|
@ -173,33 +89,6 @@ public class PlaybackHistoryFragment extends Fragment implements Toolbar.OnMenuI
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onContextItemSelected(@NonNull MenuItem item) {
|
||||
FeedItem selectedItem = adapter.getLongPressedItem();
|
||||
if (selectedItem == null) {
|
||||
Log.i(TAG, "Selected item at current position was null, ignoring selection");
|
||||
return super.onContextItemSelected(item);
|
||||
}
|
||||
return FeedItemMenuHandler.onMenuItemClicked(this, item.getItemId(), selectedItem);
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
public void onKeyUp(KeyEvent event) {
|
||||
if (!isAdded() || !isVisible() || !isMenuVisible()) {
|
||||
return;
|
||||
}
|
||||
switch (event.getKeyCode()) {
|
||||
case KeyEvent.KEYCODE_T:
|
||||
recyclerView.smoothScrollToPosition(0);
|
||||
break;
|
||||
case KeyEvent.KEYCODE_B:
|
||||
recyclerView.smoothScrollToPosition(adapter.getItemCount() - 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
public void onHistoryUpdated(PlaybackHistoryEvent event) {
|
||||
loadItems();
|
||||
|
@ -212,59 +101,47 @@ public class PlaybackHistoryFragment extends Fragment implements Toolbar.OnMenuI
|
|||
refreshToolbarState();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
public void onUnreadItemsChanged(UnreadItemsUpdateEvent event) {
|
||||
loadItems();
|
||||
refreshToolbarState();
|
||||
}
|
||||
|
||||
private void onFragmentLoaded() {
|
||||
adapter.notifyDataSetChanged();
|
||||
@Override
|
||||
protected void onFragmentLoaded(List<FeedItem> episodes) {
|
||||
super.onFragmentLoaded(episodes);
|
||||
listAdapter.notifyDataSetChanged();
|
||||
refreshToolbarState();
|
||||
}
|
||||
|
||||
private void loadItems() {
|
||||
if (disposable != null) {
|
||||
disposable.dispose();
|
||||
}
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
emptyView.hide();
|
||||
disposable = Observable.fromCallable(this::loadData)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(result -> {
|
||||
progressBar.setVisibility(View.GONE);
|
||||
playbackHistory = result;
|
||||
adapter.updateItems(playbackHistory);
|
||||
onFragmentLoaded();
|
||||
}, error -> Log.e(TAG, Log.getStackTraceString(error)));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private List<FeedItem> loadData() {
|
||||
List<FeedItem> history = DBReader.getPlaybackHistory();
|
||||
DBReader.loadAdditionalFeedItemListData(history);
|
||||
return history;
|
||||
}
|
||||
|
||||
private class PlaybackHistoryListAdapter extends EpisodeItemListAdapter {
|
||||
|
||||
public PlaybackHistoryListAdapter(MainActivity mainActivity) {
|
||||
super(mainActivity);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void afterBindViewHolder(EpisodeItemViewHolder holder, int pos) {
|
||||
// played items shouldn't be transparent for this fragment since, *all* items
|
||||
// in this fragment will, by definition, be played. So it serves no purpose and can make
|
||||
// it harder to read.
|
||||
holder.itemView.setAlpha(1.0f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
|
||||
super.onCreateContextMenu(menu, v, menuInfo);
|
||||
MenuItemUtils.setOnClickListeners(menu, PlaybackHistoryFragment.this::onContextItemSelected);
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected List<FeedItem> loadData() {
|
||||
return DBReader.getPlaybackHistory(0, page * EPISODES_PER_PAGE);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected List<FeedItem> loadMoreData(int page) {
|
||||
return DBReader.getPlaybackHistory((page - 1) * EPISODES_PER_PAGE, EPISODES_PER_PAGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int loadTotalItemCount() {
|
||||
return (int) DBReader.getPlaybackHistoryLength();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,13 +9,13 @@
|
|||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true"
|
||||
android:minHeight="?attr/actionBarSize"
|
||||
android:theme="?attr/actionBarTheme"
|
||||
android:layout_alignParentTop="true"
|
||||
app:title="@string/inbox_label" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/inboxContent"
|
||||
android:id="@+id/listContent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_below="@+id/toolbar" />
|
|
@ -45,11 +45,6 @@ public final class DBReader {
|
|||
|
||||
private static final String TAG = "DBReader";
|
||||
|
||||
/**
|
||||
* Maximum size of the list returned by {@link #getPlaybackHistory()}.
|
||||
*/
|
||||
public static final int PLAYBACK_HISTORY_SIZE = 50;
|
||||
|
||||
/**
|
||||
* Maximum size of the list returned by {@link #getDownloadLog()}.
|
||||
*/
|
||||
|
@ -419,11 +414,12 @@ public final class DBReader {
|
|||
* Loads the playback history from the database. A FeedItem is in the playback history if playback of the correpsonding episode
|
||||
* has been completed at least once.
|
||||
*
|
||||
* @param limit The maximum number of items to return.
|
||||
*
|
||||
* @return The playback history. The FeedItems are sorted by their media's playbackCompletionDate in descending order.
|
||||
* The size of the returned list is limited by {@link #PLAYBACK_HISTORY_SIZE}.
|
||||
*/
|
||||
@NonNull
|
||||
public static List<FeedItem> getPlaybackHistory() {
|
||||
public static List<FeedItem> getPlaybackHistory(int offset, int limit) {
|
||||
Log.d(TAG, "getPlaybackHistory() called");
|
||||
|
||||
PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||
|
@ -432,7 +428,7 @@ public final class DBReader {
|
|||
Cursor mediaCursor = null;
|
||||
Cursor itemCursor = null;
|
||||
try {
|
||||
mediaCursor = adapter.getCompletedMediaCursor(PLAYBACK_HISTORY_SIZE);
|
||||
mediaCursor = adapter.getCompletedMediaCursor(offset, limit);
|
||||
String[] itemIds = new String[mediaCursor.getCount()];
|
||||
for (int i = 0; i < itemIds.length && mediaCursor.moveToPosition(i); i++) {
|
||||
int index = mediaCursor.getColumnIndex(PodDBAdapter.KEY_FEEDITEM);
|
||||
|
@ -454,6 +450,17 @@ public final class DBReader {
|
|||
}
|
||||
}
|
||||
|
||||
public static long getPlaybackHistoryLength() {
|
||||
PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
|
||||
try {
|
||||
return adapter.getCompletedMediaLength();
|
||||
} finally {
|
||||
adapter.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the download log from the database.
|
||||
*
|
||||
|
|
|
@ -3,6 +3,8 @@ package de.danoeh.antennapod.core.storage;
|
|||
import android.content.Context;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
@ -16,8 +18,11 @@ import de.danoeh.antennapod.core.util.LongList;
|
|||
import de.danoeh.antennapod.storage.database.PodDBAdapter;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.experimental.runners.Enclosed;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.ParameterizedRobolectricTestRunner;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
|
||||
import static de.danoeh.antennapod.core.storage.DbTestUtils.saveFeedlist;
|
||||
|
@ -31,9 +36,10 @@ import static org.junit.Assert.assertTrue;
|
|||
* Test class for DBReader.
|
||||
*/
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@RunWith(Enclosed.class)
|
||||
public class DbReaderTest {
|
||||
|
||||
@Ignore("Not a test")
|
||||
public static class TestBase {
|
||||
@Before
|
||||
public void setUp() {
|
||||
Context context = InstrumentationRegistry.getInstrumentation().getContext();
|
||||
|
@ -51,7 +57,10 @@ public class DbReaderTest {
|
|||
PodDBAdapter.tearDownTests();
|
||||
DBWriter.tearDownTests();
|
||||
}
|
||||
}
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public static class SingleTests extends TestBase {
|
||||
@Test
|
||||
public void testGetFeedList() {
|
||||
List<Feed> feeds = saveFeedlist(10, 0, false);
|
||||
|
@ -289,33 +298,26 @@ public class DbReaderTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testGetPlaybackHistory() {
|
||||
final int numItems = (DBReader.PLAYBACK_HISTORY_SIZE + 1) * 2;
|
||||
final int playedItems = DBReader.PLAYBACK_HISTORY_SIZE + 1;
|
||||
final int numReturnedItems = Math.min(playedItems, DBReader.PLAYBACK_HISTORY_SIZE);
|
||||
final int numFeeds = 1;
|
||||
public void testGetPlaybackHistoryLength() {
|
||||
final int totalItems = 100;
|
||||
|
||||
Feed feed = DbTestUtils.saveFeedlist(numFeeds, numItems, true).get(0);
|
||||
long[] ids = new long[playedItems];
|
||||
Feed feed = DbTestUtils.saveFeedlist(1, totalItems, true).get(0);
|
||||
|
||||
PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||
for (int playedItems : Arrays.asList(0, 1, 20, 100)) {
|
||||
adapter.open();
|
||||
for (int i = 0; i < playedItems; i++) {
|
||||
for (int i = 0; i < playedItems; ++i) {
|
||||
FeedMedia m = feed.getItems().get(i).getMedia();
|
||||
m.setPlaybackCompletionDate(new Date(i + 1));
|
||||
|
||||
adapter.setFeedMediaPlaybackCompletionDate(m);
|
||||
ids[ids.length - 1 - i] = m.getItem().getId();
|
||||
}
|
||||
adapter.close();
|
||||
|
||||
List<FeedItem> saved = DBReader.getPlaybackHistory();
|
||||
assertNotNull(saved);
|
||||
assertEquals("Wrong size: ", numReturnedItems, saved.size());
|
||||
for (int i = 0; i < numReturnedItems; i++) {
|
||||
FeedItem item = saved.get(i);
|
||||
assertNotNull(item.getMedia().getPlaybackCompletionDate());
|
||||
assertEquals("Wrong sort order: ", item.getId(), ids[i]);
|
||||
long len = DBReader.getPlaybackHistoryLength();
|
||||
assertEquals("Wrong size: ", (int) len, playedItems);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -437,4 +439,70 @@ public class DbReaderTest {
|
|||
item1.getMedia().getDownload_url());
|
||||
assertEquals(item1.getItemIdentifier(), feedItemByGuid.getItemIdentifier());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@RunWith(ParameterizedRobolectricTestRunner.class)
|
||||
public static class PlaybackHistoryTest extends TestBase {
|
||||
|
||||
private int paramOffset;
|
||||
private int paramLimit;
|
||||
|
||||
@ParameterizedRobolectricTestRunner.Parameters
|
||||
public static Collection<Object[]> data() {
|
||||
List<Integer> limits = Arrays.asList(1, 20, 100);
|
||||
List<Integer> offsets = Arrays.asList(0, 10, 20);
|
||||
Object[][] rv = new Object[limits.size() * offsets.size()][2];
|
||||
int i = 0;
|
||||
for (int offset : offsets) {
|
||||
for (int limit : limits) {
|
||||
rv[i][0] = offset;
|
||||
rv[i][1] = limit;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
return Arrays.asList(rv);
|
||||
}
|
||||
|
||||
public PlaybackHistoryTest(int offset, int limit) {
|
||||
this.paramOffset = offset;
|
||||
this.paramLimit = limit;
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetPlaybackHistory() {
|
||||
final int numItems = (paramLimit + 1) * 2;
|
||||
final int playedItems = paramLimit + 1;
|
||||
final int numReturnedItems = Math.min(Math.max(playedItems - paramOffset, 0), paramLimit);
|
||||
final int numFeeds = 1;
|
||||
|
||||
Feed feed = DbTestUtils.saveFeedlist(numFeeds, numItems, true).get(0);
|
||||
long[] ids = new long[playedItems];
|
||||
|
||||
PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
for (int i = 0; i < playedItems; i++) {
|
||||
FeedMedia m = feed.getItems().get(i).getMedia();
|
||||
m.setPlaybackCompletionDate(new Date(i + 1));
|
||||
adapter.setFeedMediaPlaybackCompletionDate(m);
|
||||
ids[ids.length - 1 - i] = m.getItem().getId();
|
||||
}
|
||||
adapter.close();
|
||||
|
||||
List<FeedItem> saved = DBReader.getPlaybackHistory(paramOffset, paramLimit);
|
||||
assertNotNull(saved);
|
||||
assertEquals(String.format("Wrong size with offset %d and limit %d: ",
|
||||
paramOffset, paramLimit),
|
||||
numReturnedItems, saved.size());
|
||||
for (int i = 0; i < numReturnedItems; i++) {
|
||||
FeedItem item = saved.get(i);
|
||||
assertNotNull(item.getMedia().getPlaybackCompletionDate());
|
||||
assertEquals(String.format("Wrong sort order with offset %d and limit %d: ",
|
||||
paramOffset, paramLimit),
|
||||
item.getId(), ids[paramOffset + i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1076,18 +1076,23 @@ public class PodDBAdapter {
|
|||
* Returns a cursor which contains feed media objects with a playback
|
||||
* completion date in ascending order.
|
||||
*
|
||||
* @param offset The row to start at.
|
||||
* @param limit The maximum row count of the returned cursor. Must be an
|
||||
* integer >= 0.
|
||||
* @throws IllegalArgumentException if limit < 0
|
||||
*/
|
||||
public final Cursor getCompletedMediaCursor(int limit) {
|
||||
public final Cursor getCompletedMediaCursor(int offset, int limit) {
|
||||
if (limit < 0) {
|
||||
throw new IllegalArgumentException("Limit must be >= 0");
|
||||
}
|
||||
|
||||
return db.query(TABLE_NAME_FEED_MEDIA, null,
|
||||
KEY_PLAYBACK_COMPLETION_DATE + " > 0", null, null,
|
||||
null, String.format(Locale.US, "%s DESC LIMIT %d", KEY_PLAYBACK_COMPLETION_DATE, limit));
|
||||
null, String.format(Locale.US, "%s DESC LIMIT %d, %d", KEY_PLAYBACK_COMPLETION_DATE, offset, limit));
|
||||
}
|
||||
|
||||
public final long getCompletedMediaLength() {
|
||||
return DatabaseUtils.queryNumEntries(db, TABLE_NAME_FEED_MEDIA, KEY_PLAYBACK_COMPLETION_DATE + "> 0");
|
||||
}
|
||||
|
||||
public final Cursor getSingleFeedMediaCursor(long id) {
|
||||
|
|
Loading…
Reference in New Issue