diff options
author | Tom Hennen <TomHennen@users.noreply.github.com> | 2015-09-25 17:33:08 -0400 |
---|---|---|
committer | Tom Hennen <TomHennen@users.noreply.github.com> | 2015-09-25 17:33:08 -0400 |
commit | f27d14f4b9b1da216aa5dc3dfef72ef47001d502 (patch) | |
tree | e0c4b9f514366dc81a1be2b6528ecec08825d6db | |
parent | 5e458ec305b4f02a68e1a26ab85a005e28abd2d8 (diff) | |
parent | c00b5f4033f6c4e74d5a30efd253482250510477 (diff) | |
download | AntennaPod-f27d14f4b9b1da216aa5dc3dfef72ef47001d502.zip |
Merge pull request #1213 from TomHennen/favorites
Favorites
31 files changed, 455 insertions, 73 deletions
diff --git a/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceTaskManagerTest.java b/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceTaskManagerTest.java index 869a13127..201ce17c0 100644 --- a/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceTaskManagerTest.java +++ b/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceTaskManagerTest.java @@ -12,7 +12,7 @@ import java.util.concurrent.TimeUnit; import de.danoeh.antennapod.core.feed.EventDistributor; import de.danoeh.antennapod.core.feed.Feed; import de.danoeh.antennapod.core.feed.FeedItem; -import de.danoeh.antennapod.core.feed.QueueEvent; +import de.danoeh.antennapod.core.event.QueueEvent; import de.danoeh.antennapod.core.service.playback.PlaybackServiceTaskManager; import de.danoeh.antennapod.core.storage.PodDBAdapter; import de.danoeh.antennapod.core.util.playback.Playable; diff --git a/app/src/androidTest/java/de/test/antennapod/storage/DBReaderTest.java b/app/src/androidTest/java/de/test/antennapod/storage/DBReaderTest.java index 6873cb9a6..3988669ce 100644 --- a/app/src/androidTest/java/de/test/antennapod/storage/DBReaderTest.java +++ b/app/src/androidTest/java/de/test/antennapod/storage/DBReaderTest.java @@ -102,7 +102,7 @@ public class DBReaderTest extends InstrumentationTestCase { items.add(item); } } - DBReader.loadFeedDataOfFeedItemlist(items); + DBReader.loadAdditionalFeedItemListData(items); for (int i = 0; i < numFeeds; i++) { for (int j = 0; j < numItems; j++) { FeedItem item = feeds.get(i).getItems().get(j); diff --git a/app/src/androidTest/java/de/test/antennapod/storage/DBWriterTest.java b/app/src/androidTest/java/de/test/antennapod/storage/DBWriterTest.java index 2a63ef4b3..585e27e0b 100644 --- a/app/src/androidTest/java/de/test/antennapod/storage/DBWriterTest.java +++ b/app/src/androidTest/java/de/test/antennapod/storage/DBWriterTest.java @@ -556,7 +556,7 @@ public class DBWriterTest extends InstrumentationTestCase { } List<Future<?>> futures = new ArrayList<Future<?>>(); for (FeedItem item : feed.getItems()) { - futures.add(DBWriter.addQueueItem(context, item.getId())); + futures.add(DBWriter.addQueueItem(context, item)); } for (Future<?> f : futures) { f.get(TIMEOUT, TimeUnit.SECONDS); @@ -577,7 +577,7 @@ public class DBWriterTest extends InstrumentationTestCase { adapter.close(); assertTrue(item.getId() != 0); - DBWriter.addQueueItem(context, item.getId()).get(TIMEOUT, TimeUnit.SECONDS); + DBWriter.addQueueItem(context, item).get(TIMEOUT, TimeUnit.SECONDS); adapter = PodDBAdapter.getInstance(); adapter.open(); @@ -601,7 +601,7 @@ public class DBWriterTest extends InstrumentationTestCase { adapter.close(); assertTrue(item.getId() != 0); - DBWriter.addQueueItem(context, item.getId()).get(TIMEOUT, TimeUnit.SECONDS); + DBWriter.addQueueItem(context, item).get(TIMEOUT, TimeUnit.SECONDS); adapter = PodDBAdapter.getInstance(); adapter.open(); @@ -611,7 +611,7 @@ public class DBWriterTest extends InstrumentationTestCase { cursor.close(); adapter.close(); - DBWriter.addQueueItem(context, item.getId()).get(TIMEOUT, TimeUnit.SECONDS); + DBWriter.addQueueItem(context, item).get(TIMEOUT, TimeUnit.SECONDS); adapter = PodDBAdapter.getInstance(); adapter.open(); cursor = adapter.getQueueIDCursor(); diff --git a/app/src/androidTest/java/de/test/antennapod/ui/UITestUtils.java b/app/src/androidTest/java/de/test/antennapod/ui/UITestUtils.java index 9859e7534..973426841 100644 --- a/app/src/androidTest/java/de/test/antennapod/ui/UITestUtils.java +++ b/app/src/androidTest/java/de/test/antennapod/ui/UITestUtils.java @@ -26,7 +26,7 @@ import de.danoeh.antennapod.core.feed.Feed; import de.danoeh.antennapod.core.feed.FeedImage; import de.danoeh.antennapod.core.feed.FeedItem; import de.danoeh.antennapod.core.feed.FeedMedia; -import de.danoeh.antennapod.core.feed.QueueEvent; +import de.danoeh.antennapod.core.event.QueueEvent; import de.danoeh.antennapod.core.storage.PodDBAdapter; import de.greenrobot.event.EventBus; import de.test.antennapod.util.service.download.HTTPBin; diff --git a/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java index 76d657585..4b3460476 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java @@ -43,7 +43,7 @@ import de.danoeh.antennapod.core.dialog.ConfirmationDialog; import de.danoeh.antennapod.core.event.ProgressEvent; import de.danoeh.antennapod.core.feed.EventDistributor; import de.danoeh.antennapod.core.feed.Feed; -import de.danoeh.antennapod.core.feed.QueueEvent; +import de.danoeh.antennapod.core.event.QueueEvent; import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.core.storage.DBReader; import de.danoeh.antennapod.core.storage.DBWriter; diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/DefaultActionButtonCallback.java b/app/src/main/java/de/danoeh/antennapod/adapter/DefaultActionButtonCallback.java index f17f0ba0f..445e4832c 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/DefaultActionButtonCallback.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/DefaultActionButtonCallback.java @@ -67,7 +67,7 @@ public class DefaultActionButtonCallback implements ActionButtonCallback { DownloadRequestErrorDialogCreator.newRequestErrorDialog(context, e.getMessage()); } } else if(userChoseAddToQueue() && !queueIds.contains(item.getId())) { - DBWriter.addQueueItem(context, item.getId()); + DBWriter.addQueueItem(context, item); Toast.makeText(context, R.string.added_to_queue_label, Toast.LENGTH_SHORT).show(); } else { confirmMobileDownload(context, item); @@ -124,7 +124,7 @@ public class DefaultActionButtonCallback implements ActionButtonCallback { @Override public void onClick(DialogInterface dialog, int which) { onlyAddToQueueTimeStamp = System.currentTimeMillis(); - DBWriter.addQueueItem(context, item.getId()); + DBWriter.addQueueItem(context, item); Toast.makeText(context, R.string.added_to_queue_label, Toast.LENGTH_SHORT).show(); } }) diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java b/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java index 37ca0ad26..8e416139e 100644 --- a/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java @@ -361,13 +361,7 @@ public class EpisodesApplyActionFragment extends Fragment { } private void queueChecked() { - LongList orderedIds = new LongList(); - for(FeedItem episode : episodes) { - if(checkedIds.contains(episode.getId())) { - orderedIds.add((episode.getId())); - } - } - DBWriter.addQueueItem(getActivity(), false, orderedIds.toArray()); + DBWriter.addQueueItem(getActivity(), episodes.toArray(new FeedItem[0])); close(); } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java index 5aed66013..31b24773f 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java @@ -338,7 +338,6 @@ public class AllEpisodesFragment extends Fragment { super.onCreateContextMenu(menu, v, menuInfo); AdapterView.AdapterContextMenuInfo adapterInfo = (AdapterView.AdapterContextMenuInfo) menuInfo; FeedItem item = itemAccess.getItem(adapterInfo.position); - MenuInflater inflater = getActivity().getMenuInflater(); inflater.inflate(R.menu.allepisodes_context, menu); @@ -353,11 +352,27 @@ public class AllEpisodesFragment extends Fragment { @Override public boolean onContextItemSelected(MenuItem item) { + if (!getUserVisibleHint()) { + // we're not visible, don't do anything. + return false; + } AdapterView.AdapterContextMenuInfo menuInfo = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo(); - if(menuInfo == null) { + if (menuInfo == null) { menuInfo = lastMenuInfo; } - FeedItem selectedItem = itemAccess.getItem(menuInfo.position); + if (menuInfo == null) { + Log.e(TAG, "menuInfo is null, not doing anything"); + return false; + } + + FeedItem selectedItem = null; + + // make sure the item still makes sense + if (menuInfo.position >= 0 && menuInfo.position < itemAccess.getCount()) { + selectedItem = itemAccess.getItem(menuInfo.position); + } else { + Log.d(TAG, "Selected item at position " + menuInfo.position + " does not exist, only " + itemAccess.getCount() + " items available"); + } if (selectedItem == null) { Log.i(TAG, "Selected item at position " + menuInfo.position + " was null, ignoring selection"); @@ -452,12 +467,7 @@ public class AllEpisodesFragment extends Fragment { }; private void updateShowOnlyEpisodesListViewState() { - if (showOnlyNewEpisodes) { - listView.setEmptyView(null); - txtvEmpty.setVisibility(View.GONE); - } else { - listView.setEmptyView(txtvEmpty); - } + listView.setEmptyView(txtvEmpty); } protected void loadItems() { @@ -488,13 +498,9 @@ public class AllEpisodesFragment extends Fragment { }); } - private Pair<List<FeedItem>,LongList> loadData() { + protected Pair<List<FeedItem>,LongList> loadData() { List<FeedItem> items; - if(showOnlyNewEpisodes) { - items = DBReader.getNewItemsList(); - } else { - items = DBReader.getRecentlyPublishedEpisodes(RECENT_EPISODES_LIMIT); - } + items = DBReader.getRecentlyPublishedEpisodes(RECENT_EPISODES_LIMIT); LongList queuedIds = DBReader.getQueueIDList(); return Pair.create(items, queuedIds); } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesFragment.java index e234d95ad..f23981935 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesFragment.java @@ -23,7 +23,8 @@ public class EpisodesFragment extends Fragment { public static final int POS_NEW_EPISODES = 0; public static final int POS_ALL_EPISODES = 1; - public static final int TOTAL_COUNT = 2; + public static final int POS_FAV_EPISODES = 2; + public static final int TOTAL_COUNT = 3; private TabLayout tabLayout; @@ -91,6 +92,8 @@ public class EpisodesFragment extends Fragment { return new AllEpisodesFragment(); case POS_NEW_EPISODES: return new NewEpisodesFragment(); + case POS_FAV_EPISODES: + return new FavoriteEpisodesFragment(); } return null; } @@ -107,6 +110,8 @@ public class EpisodesFragment extends Fragment { return resources.getString(R.string.all_episodes_short_label); case POS_NEW_EPISODES: return resources.getString(R.string.new_label); + case POS_FAV_EPISODES: + return resources.getString(R.string.favorite_episodes_label); default: return super.getPageTitle(position); } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java new file mode 100644 index 000000000..95f7cfcc1 --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java @@ -0,0 +1,111 @@ +package de.danoeh.antennapod.fragment; + +import android.content.Context; +import android.os.Bundle; +import android.support.v4.util.Pair; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import java.util.List; + +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.core.event.FavoritesEvent; +import de.danoeh.antennapod.core.feed.FeedItem; +import de.danoeh.antennapod.core.storage.DBReader; +import de.danoeh.antennapod.core.storage.DBWriter; +import de.danoeh.antennapod.core.util.LongList; +import de.danoeh.antennapod.core.util.gui.FeedItemUndoToken; +import de.danoeh.antennapod.core.util.gui.UndoBarController; +import de.greenrobot.event.EventBus; + + +/** + * Like 'EpisodesFragment' except that it only shows favorite episodes and + * supports swiping to remove from favorites. + */ + +public class FavoriteEpisodesFragment extends AllEpisodesFragment { + + public static final String TAG = "FavoriteEpisodesFrag"; + + private static final String PREF_NAME = "PrefFavoriteEpisodesFragment"; + + private UndoBarController undoBarController; + + public FavoriteEpisodesFragment() { + super(false, PREF_NAME); + } + + public void onEvent(FavoritesEvent event) { + Log.d(TAG, "onEvent(" + event + ")"); + loadItems(); + } + + @Override + public void onStart() { + super.onStart(); + EventBus.getDefault().register(this); + } + + @Override + public void onStop() { + super.onStop(); + EventBus.getDefault().unregister(this); + } + + @Override + protected void resetViewState() { + super.resetViewState(); + undoBarController = null; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View root = super.onCreateViewHelper(inflater, container, savedInstanceState, + R.layout.episodes_fragment_with_undo); + + listView.setRemoveListener(which -> { + Log.d(TAG, "remove(" + which + ")"); + if (subscription != null) { + subscription.unsubscribe(); + } + FeedItem item = (FeedItem) listView.getAdapter().getItem(which); + + DBWriter.removeFavoriteItem(item); + + undoBarController.showUndoBar(false, + getString(R.string.removed_item), new FeedItemUndoToken(item, + which) + ); + }); + + undoBarController = new UndoBarController<FeedItemUndoToken>(root.findViewById(R.id.undobar), new UndoBarController.UndoListener<FeedItemUndoToken>() { + + private final Context context = getActivity(); + + @Override + public void onUndo(FeedItemUndoToken token) { + if (token != null) { + long itemId = token.getFeedItemId(); + DBWriter.addFavoriteItemById(itemId); + } + } + + @Override + public void onHide(FeedItemUndoToken token) { + // nothing to do + } + }); + return root; + } + + @Override + protected Pair<List<FeedItem>,LongList> loadData() { + List<FeedItem> items; + items = DBReader.getFavoriteItemsList(); + LongList queuedIds = DBReader.getQueueIDList(); + return Pair.create(items, queuedIds); + } +} diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java index 353d8149c..6d28478e9 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java @@ -47,7 +47,7 @@ import de.danoeh.antennapod.core.asynctask.DownloadObserver; import de.danoeh.antennapod.core.feed.EventDistributor; import de.danoeh.antennapod.core.feed.FeedItem; import de.danoeh.antennapod.core.feed.FeedMedia; -import de.danoeh.antennapod.core.feed.QueueEvent; +import de.danoeh.antennapod.core.event.QueueEvent; import de.danoeh.antennapod.core.glide.ApGlideSettings; import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.core.service.download.Downloader; diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java index 3d0ff66f7..d17788dde 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java @@ -56,7 +56,7 @@ import de.danoeh.antennapod.core.feed.FeedEvent; import de.danoeh.antennapod.core.feed.FeedItem; import de.danoeh.antennapod.core.feed.FeedItemFilter; import de.danoeh.antennapod.core.feed.FeedMedia; -import de.danoeh.antennapod.core.feed.QueueEvent; +import de.danoeh.antennapod.core.event.QueueEvent; import de.danoeh.antennapod.core.glide.ApGlideSettings; import de.danoeh.antennapod.core.glide.FastBlurTransformation; import de.danoeh.antennapod.core.preferences.UserPreferences; diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java index d454208c1..60d0161b2 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java @@ -2,6 +2,7 @@ package de.danoeh.antennapod.fragment; import android.content.Context; import android.os.Bundle; +import android.support.v4.util.Pair; import android.util.Log; import android.view.LayoutInflater; import android.view.View; @@ -9,12 +10,15 @@ import android.view.ViewGroup; import com.mobeta.android.dslv.DragSortListView; +import java.util.List; + import de.danoeh.antennapod.R; import de.danoeh.antennapod.core.feed.FeedItem; import de.danoeh.antennapod.core.feed.FeedMedia; -import de.danoeh.antennapod.core.feed.QueueEvent; +import de.danoeh.antennapod.core.event.QueueEvent; import de.danoeh.antennapod.core.storage.DBReader; import de.danoeh.antennapod.core.storage.DBWriter; +import de.danoeh.antennapod.core.util.LongList; import de.danoeh.antennapod.core.util.gui.FeedItemUndoToken; import de.danoeh.antennapod.core.util.gui.UndoBarController; import de.greenrobot.event.EventBus; @@ -63,13 +67,13 @@ public class NewEpisodesFragment extends AllEpisodesFragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View root = super.onCreateViewHelper(inflater, container, savedInstanceState, - R.layout.new_episodes_fragment); + R.layout.episodes_fragment_with_undo); listView.setRemoveListener(new DragSortListView.RemoveListener() { @Override public void remove(int which) { Log.d(TAG, "remove(" + which + ")"); - if(subscription != null) { + if (subscription != null) { subscription.unsubscribe(); } FeedItem item = (FeedItem) listView.getAdapter().getItem(which); @@ -109,4 +113,12 @@ public class NewEpisodesFragment extends AllEpisodesFragment { return root; } + @Override + protected Pair<List<FeedItem>,LongList> loadData() { + List<FeedItem> items; + items = DBReader.getNewItemsList(); + LongList queuedIds = DBReader.getQueueIDList(); + return Pair.create(items, queuedIds); + } + } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java index e6460309b..d7ffa3e23 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java @@ -25,7 +25,7 @@ import de.danoeh.antennapod.core.asynctask.DownloadObserver; import de.danoeh.antennapod.core.feed.EventDistributor; import de.danoeh.antennapod.core.feed.FeedItem; import de.danoeh.antennapod.core.feed.FeedMedia; -import de.danoeh.antennapod.core.feed.QueueEvent; +import de.danoeh.antennapod.core.event.QueueEvent; import de.danoeh.antennapod.core.service.download.Downloader; import de.danoeh.antennapod.core.storage.DBReader; import de.danoeh.antennapod.core.storage.DBWriter; @@ -277,7 +277,7 @@ public class PlaybackHistoryFragment extends ListFragment { private Pair<List<FeedItem>, LongList> loadData() { List<FeedItem> history = DBReader.getPlaybackHistory(); LongList queue = DBReader.getQueueIDList(); - DBReader.loadFeedDataOfFeedItemlist(history); + DBReader.loadAdditionalFeedItemListData(history); return Pair.create(history, queue); } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java index 7bcd98dc8..0ac33f8fb 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java @@ -37,7 +37,7 @@ import de.danoeh.antennapod.core.feed.EventDistributor; import de.danoeh.antennapod.core.feed.Feed; import de.danoeh.antennapod.core.feed.FeedItem; import de.danoeh.antennapod.core.feed.FeedMedia; -import de.danoeh.antennapod.core.feed.QueueEvent; +import de.danoeh.antennapod.core.event.QueueEvent; import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.core.service.download.DownloadService; import de.danoeh.antennapod.core.service.download.Downloader; diff --git a/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java index 510ea2760..da87fb1b9 100644 --- a/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java +++ b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedItemMenuHandler.java @@ -72,7 +72,7 @@ public class FeedItemMenuHandler { mi.setItemVisibility(R.id.skip_episode_item, false); } - boolean isInQueue = queueAccess.contains(selectedItem.getId()); + boolean isInQueue = selectedItem.isTagged(FeedItem.TAG_QUEUE); if(queueAccess.size() == 0 || queueAccess.get(0) == selectedItem.getId()) { mi.setItemVisibility(R.id.move_to_top_item, false); } @@ -123,6 +123,11 @@ public class FeedItemMenuHandler { if (selectedItem.getPaymentLink() == null || !selectedItem.getFlattrStatus().flattrable()) { mi.setItemVisibility(R.id.support_item, false); } + + boolean isFavorite = selectedItem.isTagged(FeedItem.TAG_FAVORITE); + mi.setItemVisibility(R.id.add_to_favorites_item, !isFavorite); + mi.setItemVisibility(R.id.remove_from_favorites_item, isFavorite); + return true; } @@ -188,11 +193,17 @@ public class FeedItemMenuHandler { case R.id.move_to_bottom_item: DBWriter.moveQueueItemToBottom(selectedItem.getId(), true); case R.id.add_to_queue_item: - DBWriter.addQueueItem(context, selectedItem.getId()); + DBWriter.addQueueItem(context, selectedItem); break; case R.id.remove_from_queue_item: DBWriter.removeQueueItem(context, selectedItem, true); break; + case R.id.add_to_favorites_item: + DBWriter.addFavoriteItem(selectedItem); + break; + case R.id.remove_from_favorites_item: + DBWriter.removeFavoriteItem(selectedItem); + break; case R.id.reset_position: selectedItem.getMedia().setPosition(0); DBWriter.markItemPlayed(selectedItem, FeedItem.UNPLAYED, true); diff --git a/app/src/main/res/layout/new_episodes_fragment.xml b/app/src/main/res/layout/episodes_fragment_with_undo.xml index e90171630..e90171630 100644 --- a/app/src/main/res/layout/new_episodes_fragment.xml +++ b/app/src/main/res/layout/episodes_fragment_with_undo.xml diff --git a/app/src/main/res/menu/allepisodes_context.xml b/app/src/main/res/menu/allepisodes_context.xml index 171e509a8..c5356535c 100644 --- a/app/src/main/res/menu/allepisodes_context.xml +++ b/app/src/main/res/menu/allepisodes_context.xml @@ -24,7 +24,14 @@ android:id="@+id/remove_from_queue_item" android:menuCategory="container" android:title="@string/remove_from_queue_label" /> - + <item + android:id="@+id/add_to_favorites_item" + android:menuCategory="container" + android:title="@string/add_to_favorite_label" /> + <item + android:id="@+id/remove_from_favorites_item" + android:menuCategory="container" + android:title="@string/remove_from_favorite_label" /> <item android:id="@+id/reset_position" android:menuCategory="container" diff --git a/app/src/main/res/menu/feeditem_options.xml b/app/src/main/res/menu/feeditem_options.xml index 650912ea2..898081486 100644 --- a/app/src/main/res/menu/feeditem_options.xml +++ b/app/src/main/res/menu/feeditem_options.xml @@ -31,6 +31,16 @@ </item> <item + android:id="@+id/add_to_favorites_item" + android:menuCategory="container" + android:title="@string/add_to_favorite_label" /> + + <item + android:id="@+id/remove_from_favorites_item" + android:menuCategory="container" + android:title="@string/remove_from_favorite_label" /> + + <item android:id="@+id/reset_position" custom:showAsAction="collapseActionView" android:title="@string/reset_position"> diff --git a/app/src/main/res/menu/queue_context.xml b/app/src/main/res/menu/queue_context.xml index d09f3c84c..3eb1d9d5e 100644 --- a/app/src/main/res/menu/queue_context.xml +++ b/app/src/main/res/menu/queue_context.xml @@ -28,6 +28,14 @@ android:title="@string/remove_from_queue_label" /> <item + android:id="@+id/add_to_favorites_item" + android:menuCategory="container" + android:title="@string/add_to_favorite_label" /> + <item + android:id="@+id/remove_from_favorites_item" + android:menuCategory="container" + android:title="@string/remove_from_favorite_label" /> + <item android:id="@+id/reset_position" android:menuCategory="container" android:title="@string/reset_position" /> diff --git a/core/src/main/java/de/danoeh/antennapod/core/event/FavoritesEvent.java b/core/src/main/java/de/danoeh/antennapod/core/event/FavoritesEvent.java new file mode 100644 index 000000000..d09f6802f --- /dev/null +++ b/core/src/main/java/de/danoeh/antennapod/core/event/FavoritesEvent.java @@ -0,0 +1,38 @@ +package de.danoeh.antennapod.core.event; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import de.danoeh.antennapod.core.feed.FeedItem; + +public class FavoritesEvent { + + public enum Action { + ADDED, REMOVED + } + + public final Action action; + public final FeedItem item; + + private FavoritesEvent(Action action, FeedItem item) { + this.action = action; + this.item = item; + } + + public static FavoritesEvent added(FeedItem item) { + return new FavoritesEvent(Action.ADDED, item); + } + + public static FavoritesEvent removed(FeedItem item) { + return new FavoritesEvent(Action.REMOVED, item); + } + + @Override + public String toString() { + return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) + .append("action", action) + .append("item", item) + .toString(); + } + +} diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/QueueEvent.java b/core/src/main/java/de/danoeh/antennapod/core/event/QueueEvent.java index 97d086e5b..4d59d75eb 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/feed/QueueEvent.java +++ b/core/src/main/java/de/danoeh/antennapod/core/event/QueueEvent.java @@ -1,10 +1,12 @@ -package de.danoeh.antennapod.core.feed; +package de.danoeh.antennapod.core.event; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; import java.util.List; +import de.danoeh.antennapod.core.feed.FeedItem; + public class QueueEvent { public enum Action { diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/EventDistributor.java b/core/src/main/java/de/danoeh/antennapod/core/feed/EventDistributor.java index 20a85d43f..2667a2e12 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/feed/EventDistributor.java +++ b/core/src/main/java/de/danoeh/antennapod/core/feed/EventDistributor.java @@ -112,9 +112,7 @@ public class EventDistributor extends Observable { addEvent(DOWNLOAD_HANDLED); } - public void sendPlayerStatusUpdateBroadcast() { - addEvent(PLAYER_STATUS_UPDATE); - } + public void sendPlayerStatusUpdateBroadcast() { addEvent(PLAYER_STATUS_UPDATE); } public static abstract class EventListener implements Observer { diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java index 5c3ed303f..c54cc1d5b 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java +++ b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java @@ -7,7 +7,9 @@ import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; import java.util.Date; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.concurrent.Callable; import de.danoeh.antennapod.core.asynctask.ImageResource; @@ -24,6 +26,11 @@ import de.danoeh.antennapod.core.util.flattr.FlattrThing; */ public class FeedItem extends FeedComponent implements ShownotesProvider, FlattrThing, ImageResource { + /** tag that indicates this item is in the queue */ + public static final String TAG_QUEUE = "Queue"; + /** tag that indicates this item is in favorites */ + public static final String TAG_FAVORITE = "Favorite"; + /** * The id/guid that can be found in the rss/atom feed. Might not be set. */ @@ -70,6 +77,11 @@ public class FeedItem extends FeedComponent implements ShownotesProvider, Flattr private boolean autoDownload = true; + /** + * Any tags assigned to this item + */ + private Set<String> tags = new HashSet<>(); + public FeedItem() { this.state = UNPLAYED; this.flattrStatus = new FlattrStatus(); @@ -451,6 +463,21 @@ public class FeedItem extends FeedComponent implements ShownotesProvider, Flattr this.getAutoDownload(); } + /** + * @return true if the item has this tag + */ + public boolean isTagged(String tag) { return tags.contains(tag); } + + /** + * @param tag adds this tag to the item. NOTE: does NOT persist to the database + */ + public void addTag(String tag) { tags.add(tag); } + + /** + * @param tag the to remove + */ + public void removeTag(String tag) { tags.remove(tag); } + @Override public String toString() { return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE); diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java index 36ea1e222..cb050463e 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java @@ -1129,7 +1129,7 @@ public class DownloadService extends Service { DBWriter.setFeedMedia(media).get(); if (!DBTasks.isInQueue(DownloadService.this, item.getId())) { - DBWriter.addQueueItem(DownloadService.this, item.getId()).get(); + DBWriter.addQueueItem(DownloadService.this, item).get(); } } catch (ExecutionException e) { e.printStackTrace(); diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceTaskManager.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceTaskManager.java index dba66a36d..19ef6ef09 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceTaskManager.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceTaskManager.java @@ -16,7 +16,7 @@ import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; import de.danoeh.antennapod.core.feed.FeedItem; -import de.danoeh.antennapod.core.feed.QueueEvent; +import de.danoeh.antennapod.core.event.QueueEvent; import de.danoeh.antennapod.core.storage.DBReader; import de.danoeh.antennapod.core.util.playback.Playable; import de.greenrobot.event.EventBus; diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java index 4ef4ac067..d95e4ff02 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java @@ -104,6 +104,30 @@ public final class DBReader { return result; } + + /** + * Loads additional data in to the feed items from other database queries + * @param items the FeedItems who should have other data loaded + */ + public static void loadAdditionalFeedItemListData(List<FeedItem> items) { + loadTagsOfFeedItemList(items); + loadFeedDataOfFeedItemList(items); + } + + public static void loadTagsOfFeedItemList(List<FeedItem> items) { + LongList favoriteIds = getFavoriteIDList(); + LongList queueIds = getQueueIDList(); + + for (FeedItem item : items) { + if (favoriteIds.contains(item.getId())) { + item.addTag(FeedItem.TAG_FAVORITE); + } + if (queueIds.contains(item.getId())) { + item.addTag(FeedItem.TAG_QUEUE); + } + } + } + /** * Takes a list of FeedItems and loads their corresponding Feed-objects from the database. * The feedID-attribute of a FeedItem must be set to the ID of its feed or the method will @@ -111,7 +135,7 @@ public final class DBReader { * * @param items The FeedItems whose Feed-objects should be loaded. */ - public static void loadFeedDataOfFeedItemlist(List<FeedItem> items) { + public static void loadFeedDataOfFeedItemList(List<FeedItem> items) { List<Feed> feeds = getFeedList(); for (FeedItem item : items) { for (Feed feed : feeds) { @@ -251,7 +275,7 @@ public final class DBReader { Cursor itemlistCursor = adapter.getQueueCursor(); List<FeedItem> items = extractItemlistFromCursor(adapter, itemlistCursor); itemlistCursor.close(); - loadFeedDataOfFeedItemlist(items); + loadAdditionalFeedItemListData(items); return items; } @@ -316,7 +340,7 @@ public final class DBReader { List<FeedItem> items = extractItemlistFromCursor(adapter, itemlistCursor); itemlistCursor.close(); - loadFeedDataOfFeedItemlist(items); + loadAdditionalFeedItemListData(items); Collections.sort(items, new FeedItemPubdateComparator()); adapter.close(); @@ -338,7 +362,7 @@ public final class DBReader { List<FeedItem> items = extractItemlistFromCursor(adapter, itemlistCursor); itemlistCursor.close(); - loadFeedDataOfFeedItemlist(items); + loadAdditionalFeedItemListData(items); adapter.close(); @@ -360,13 +384,44 @@ public final class DBReader { List<FeedItem> items = extractItemlistFromCursor(adapter, itemlistCursor); itemlistCursor.close(); - loadFeedDataOfFeedItemlist(items); + loadAdditionalFeedItemListData(items); + + adapter.close(); + + return items; + } + + public static List<FeedItem> getFavoriteItemsList() { + Log.d(TAG, "getFavoriteItemsList()"); + + PodDBAdapter adapter = PodDBAdapter.getInstance(); + adapter.open(); + + Cursor itemlistCursor = adapter.getFavoritesCursor(); + List<FeedItem> items = extractItemlistFromCursor(adapter, itemlistCursor); + itemlistCursor.close(); + + loadAdditionalFeedItemListData(items); adapter.close(); return items; } + static LongList getFavoriteIDList() { + PodDBAdapter adapter = PodDBAdapter.getInstance().open(); + Cursor favoritesCursor = adapter.getFavoritesCursor(); + + LongList favoriteIDs = new LongList(favoritesCursor.getCount()); + if (favoritesCursor.moveToFirst()) { + do { + favoriteIDs.add(favoritesCursor.getLong(0)); + } while (favoritesCursor.moveToNext()); + } + favoritesCursor.close(); + return favoriteIDs; + } + /** * Loads a list of FeedItems sorted by pubDate in descending order. * @@ -382,7 +437,7 @@ public final class DBReader { List<FeedItem> items = extractItemlistFromCursor(adapter, itemlistCursor); itemlistCursor.close(); - loadFeedDataOfFeedItemlist(items); + loadAdditionalFeedItemListData(items); adapter.close(); @@ -411,7 +466,7 @@ public final class DBReader { mediaCursor.close(); Cursor itemCursor = adapter.getFeedItemCursor(itemIds); List<FeedItem> items = extractItemlistFromCursor(adapter, itemCursor); - loadFeedDataOfFeedItemlist(items); + loadAdditionalFeedItemListData(items); itemCursor.close(); adapter.close(); @@ -533,7 +588,7 @@ public final class DBReader { List<FeedItem> list = extractItemlistFromCursor(adapter, itemCursor); if (list.size() > 0) { item = list.get(0); - loadFeedDataOfFeedItemlist(list); + loadAdditionalFeedItemListData(list); if (item.hasChapters()) { loadChaptersOfFeedItem(adapter, item); } @@ -556,7 +611,7 @@ public final class DBReader { Cursor itemCursor = adapter.getFeedItemCursor(ids); if (itemCursor.moveToFirst()) { result = extractItemlistFromCursor(adapter, itemCursor); - loadFeedDataOfFeedItemlist(result); + loadAdditionalFeedItemListData(result); for(FeedItem item : result) { if (item.hasChapters()) { loadChaptersOfFeedItem(adapter, item); @@ -596,7 +651,7 @@ public final class DBReader { List<FeedItem> list = extractItemlistFromCursor(adapter, itemCursor); if (list.size() > 0) { item = list.get(0); - loadFeedDataOfFeedItemlist(list); + loadAdditionalFeedItemListData(list); if (item.hasChapters()) { loadChaptersOfFeedItem(adapter, item); } diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java index 96a632d68..3f9cece77 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java @@ -601,7 +601,7 @@ public final class DBTasks { Cursor searchResult = adapter.searchItemTitles(feedID, query); List<FeedItem> items = DBReader.extractItemlistFromCursor(searchResult); - DBReader.loadFeedDataOfFeedItemlist(items); + DBReader.loadAdditionalFeedItemListData(items); setResult(items); searchResult.close(); } @@ -625,7 +625,7 @@ public final class DBTasks { Cursor searchResult = adapter.searchItemDescriptions(feedID, query); List<FeedItem> items = DBReader.extractItemlistFromCursor(searchResult); - DBReader.loadFeedDataOfFeedItemlist(items); + DBReader.loadAdditionalFeedItemListData(items); setResult(items); searchResult.close(); } @@ -649,7 +649,7 @@ public final class DBTasks { Cursor searchResult = adapter.searchItemContentEncoded(feedID, query); List<FeedItem> items = DBReader.extractItemlistFromCursor(searchResult); - DBReader.loadFeedDataOfFeedItemlist(items); + DBReader.loadAdditionalFeedItemListData(items); setResult(items); searchResult.close(); } @@ -672,7 +672,7 @@ public final class DBTasks { Cursor searchResult = adapter.searchItemChapters(feedID, query); List<FeedItem> items = DBReader.extractItemlistFromCursor(searchResult); - DBReader.loadFeedDataOfFeedItemlist(items); + DBReader.loadAdditionalFeedItemListData(items); setResult(items); searchResult.close(); } diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java index 521f960ec..bae31b52b 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java @@ -26,6 +26,7 @@ import java.util.concurrent.Future; import de.danoeh.antennapod.core.BuildConfig; import de.danoeh.antennapod.core.ClientConfig; import de.danoeh.antennapod.core.asynctask.FlattrClickWorker; +import de.danoeh.antennapod.core.event.FavoritesEvent; import de.danoeh.antennapod.core.feed.EventDistributor; import de.danoeh.antennapod.core.feed.Feed; import de.danoeh.antennapod.core.feed.FeedEvent; @@ -33,7 +34,7 @@ import de.danoeh.antennapod.core.feed.FeedImage; import de.danoeh.antennapod.core.feed.FeedItem; import de.danoeh.antennapod.core.feed.FeedMedia; import de.danoeh.antennapod.core.feed.FeedPreferences; -import de.danoeh.antennapod.core.feed.QueueEvent; +import de.danoeh.antennapod.core.event.QueueEvent; import de.danoeh.antennapod.core.gpoddernet.model.GpodnetEpisodeAction; import de.danoeh.antennapod.core.preferences.GpodnetPreferences; import de.danoeh.antennapod.core.preferences.PlaybackPreferences; @@ -317,6 +318,7 @@ public class DBWriter { if (item != null) { queue.add(index, item); adapter.setQueue(queue); + item.addTag(FeedItem.TAG_QUEUE); EventBus.getDefault().post(new QueueEvent(QueueEvent.Action.ADDED, item, index)); if (item.isNew()) { DBWriter.markItemPlayed(FeedItem.UNPLAYED, item.getId()); @@ -335,8 +337,13 @@ public class DBWriter { } public static Future<?> addQueueItem(final Context context, - final long... itemIds) { - return addQueueItem(context, false, itemIds); + final FeedItem... items) { + LongList itemIds = new LongList(items.length); + for (FeedItem item : items) { + itemIds.add(item.getId()); + item.addTag(FeedItem.TAG_QUEUE); + } + return addQueueItem(context, false, itemIds.toArray()); } /** @@ -371,7 +378,7 @@ public class DBWriter { queue.add(item); } queueModified = true; - if(item.isNew()) { + if (item.isNew()) { markAsUnplayedIds.add(item.getId()); } } @@ -380,8 +387,8 @@ public class DBWriter { if (queueModified) { adapter.setQueue(queue); EventBus.getDefault().post(new QueueEvent(QueueEvent.Action.ADDED_ITEMS, queue)); - if(markAsUnplayedIds.size() > 0) { - DBWriter.markItemPlayed(FeedItem.UNPLAYED, markAsUnplayedIds.toArray()); + if (markAsUnplayedIds.size() > 0) { + DBWriter.markItemPlayed(FeedItem.UNPLAYED, markAsUnplayedIds.toArray()); } } } @@ -424,9 +431,10 @@ public class DBWriter { if (queue != null) { int position = queue.indexOf(item); - if(position >= 0) { + if (position >= 0) { queue.remove(position); adapter.setQueue(queue); + item.removeTag(FeedItem.TAG_QUEUE); EventBus.getDefault().post(new QueueEvent(QueueEvent.Action.REMOVED, item, position)); } else { Log.w(TAG, "Queue was not modified by call to removeQueueItem"); @@ -442,6 +450,41 @@ public class DBWriter { } + public static Future<?> addFavoriteItem(final FeedItem item) { + return dbExec.submit(() -> { + final PodDBAdapter adapter = PodDBAdapter.getInstance().open(); + adapter.addFavoriteItem(item); + adapter.close(); + item.addTag(FeedItem.TAG_FAVORITE); + EventBus.getDefault().post(FavoritesEvent.added(item)); + }); + } + + public static Future<?> addFavoriteItemById(final long itemId) { + return dbExec.submit(() -> { + final FeedItem item = DBReader.getFeedItem(itemId); + if (item == null) { + Log.d(TAG, "Can't find item for itemId " + itemId); + return; + } + final PodDBAdapter adapter = PodDBAdapter.getInstance().open(); + adapter.addFavoriteItem(item); + adapter.close(); + item.addTag(FeedItem.TAG_FAVORITE); + EventBus.getDefault().post(FavoritesEvent.added(item)); + }); + } + + public static Future<?> removeFavoriteItem(final FeedItem item) { + return dbExec.submit(() -> { + final PodDBAdapter adapter = PodDBAdapter.getInstance().open(); + adapter.removeFavoriteItem(item); + adapter.close(); + item.removeTag(FeedItem.TAG_FAVORITE); + EventBus.getDefault().post(FavoritesEvent.removed(item)); + }); + } + /** * Moves the specified item to the top of the queue. * @param itemId The item to move to the top of the queue diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java b/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java index fa4a5726a..730b02f1d 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java @@ -39,7 +39,7 @@ import de.greenrobot.event.EventBus; /** * Implements methods for accessing the database */ -public class PodDBAdapter { +public class PodDBAdapter implements AutoCloseable { private static final String TAG = "PodDBAdapter"; public static final String DATABASE_NAME = "Antennapod.db"; @@ -113,6 +113,7 @@ public class PodDBAdapter { public static final String TABLE_NAME_DOWNLOAD_LOG = "DownloadLog"; public static final String TABLE_NAME_QUEUE = "Queue"; public static final String TABLE_NAME_SIMPLECHAPTERS = "SimpleChapters"; + public static final String TABLE_NAME_FAVORITES = "Favorites"; // SQL Statements for creating new tables private static final String TABLE_PRIMARY_KEY = KEY_ID @@ -197,6 +198,10 @@ public class PodDBAdapter { public static final String CREATE_INDEX_SIMPLECHAPTERS_FEEDITEM = "CREATE INDEX " + TABLE_NAME_SIMPLECHAPTERS + "_" + KEY_FEEDITEM + " ON " + TABLE_NAME_SIMPLECHAPTERS + " (" + KEY_FEEDITEM + ")"; + + public static final String CREATE_TABLE_FAVORITES = "CREATE TABLE " + + TABLE_NAME_FAVORITES + "(" + KEY_ID + " INTEGER PRIMARY KEY," + + KEY_FEEDITEM + " INTEGER," + KEY_FEED + " INTEGER)"; /** * Select all columns from the feed-table @@ -785,6 +790,38 @@ public class PodDBAdapter { db.execSQL(sql); } + /** + * Adds the item to favorites + */ + public void addFavoriteItem(FeedItem item) { + // don't add an item that's already there... + if (isItemInFavorites(item)) { + Log.d(TAG, "item already in favorites"); + return; + } + ContentValues values = new ContentValues(); + values.put(KEY_FEEDITEM, item.getId()); + values.put(KEY_FEED, item.getFeedId()); + db.insert(TABLE_NAME_FAVORITES, null, values); + } + + public void removeFavoriteItem(FeedItem item) { + String deleteClause = String.format("DELETE FROM %s WHERE %s=%s AND %s=%s", + TABLE_NAME_FAVORITES, + KEY_FEEDITEM, item.getId(), + KEY_FEED, item.getFeedId()); + db.execSQL(deleteClause); + } + + public boolean isItemInFavorites(FeedItem item) { + String query = String.format("SELECT %s from %s WHERE %s=%d", + KEY_ID, TABLE_NAME_FAVORITES, KEY_FEEDITEM, item.getId()); + Cursor c = db.rawQuery(query, null); + int count = c.getCount(); + c.close(); + return count > 0; + } + public long getDownloadLogSize() { final String query = String.format("SELECT COUNT(%s) FROM %s", KEY_ID, TABLE_NAME_DOWNLOAD_LOG); Cursor result = db.rawQuery(query, null); @@ -990,6 +1027,19 @@ public class PodDBAdapter { return c; } + + public final Cursor getFavoritesCursor() { + Object[] args = new String[] { + SEL_FI_SMALL_STR, + TABLE_NAME_FEED_ITEMS, TABLE_NAME_FAVORITES, + TABLE_NAME_FEED_ITEMS + "." + KEY_ID, + TABLE_NAME_FAVORITES + "." + KEY_FEEDITEM, + TABLE_NAME_FAVORITES + "." + KEY_ID }; + String query = String.format("SELECT %s FROM %s INNER JOIN %s ON %s=%s ORDER BY %s", args); + Cursor c = db.rawQuery(query, null); + return c; + } + /** * Returns a cursor which contains all feed items in the unread items list. * The returned cursor uses the FEEDITEM_SEL_FI_SMALL selection. @@ -1374,7 +1424,7 @@ public class PodDBAdapter { */ private static class PodDBHelper extends SQLiteOpenHelper { - private final static int VERSION = 1030002; + private final static int VERSION = 1040000; private Context context; @@ -1400,6 +1450,7 @@ public class PodDBAdapter { db.execSQL(CREATE_TABLE_DOWNLOAD_LOG); db.execSQL(CREATE_TABLE_QUEUE); db.execSQL(CREATE_TABLE_SIMPLECHAPTERS); + db.execSQL(CREATE_TABLE_FAVORITES); db.execSQL(CREATE_INDEX_FEEDITEMS_FEED); db.execSQL(CREATE_INDEX_FEEDITEMS_IMAGE); diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml index ff9891bab..951b0b9ba 100644 --- a/core/src/main/res/values/strings.xml +++ b/core/src/main/res/values/strings.xml @@ -12,6 +12,7 @@ <string name="new_episodes_label">New Episodes</string> <string name="all_episodes_label">All Episodes</string> <string name="all_episodes_short_label">All</string> + <string name="favorite_episodes_label">Favorites</string> <string name="new_label">New</string> <string name="waiting_list_label">Waiting List</string> <string name="settings_label">Settings</string> @@ -137,6 +138,8 @@ <string name="add_to_queue_label">Add to Queue</string> <string name="added_to_queue_label">Added to Queue</string> <string name="remove_from_queue_label">Remove from Queue</string> + <string name="add_to_favorite_label">Add to Favorites</string> + <string name="remove_from_favorite_label">Remove from Favorites</string> <string name="visit_website_label">Visit Website</string> <string name="support_label">Flattr this</string> <string name="enqueue_all_new">Enqueue all</string> @@ -145,6 +148,7 @@ <string name="activate_auto_download">Activate Auto Download</string> <string name="deactivate_auto_download">Deactivate Auto Download</string> <string name="reset_position">Reset Playback Position</string> + <string name="removed_item">Item removed</string> <!-- Download messages and labels --> <string name="download_successful">successful</string> |