summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Hennen <TomHennen@users.noreply.github.com>2015-06-28 16:27:41 -0400
committerTom Hennen <TomHennen@users.noreply.github.com>2015-06-28 16:27:41 -0400
commitcff363e474d5527a18a05cec0ce81fcb05be2d3c (patch)
tree2f7b8dc044e0022caf9214238d60552964c92b8e
parentacd62a799df0965df666d839e707a5b2ca81e6e7 (diff)
parentc7256d8152cf062c8e608b87e62f645ef2c72642 (diff)
downloadAntennaPod-cff363e474d5527a18a05cec0ce81fcb05be2d3c.zip
Merge pull request #974 from mfietz/feature/episodes-actions
Perform action on episodes
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java416
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java21
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java1
-rw-r--r--app/src/main/res/layout/episodes_apply_action_fragment.xml120
-rw-r--r--app/src/main/res/menu/episodes_apply_action_options.xml55
-rw-r--r--app/src/main/res/menu/feedlist.xml13
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java36
-rw-r--r--core/src/main/res/values/strings.xml25
9 files changed, 669 insertions, 22 deletions
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java b/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java
new file mode 100644
index 000000000..1ca5b831c
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java
@@ -0,0 +1,416 @@
+package de.danoeh.antennapod.dialog;
+
+import android.content.res.TypedArray;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.support.v4.app.ActivityCompat;
+import android.support.v4.app.Fragment;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.ActionBarActivity;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.ListView;
+import android.widget.Toast;
+
+import com.joanzapata.android.iconify.IconDrawable;
+import com.joanzapata.android.iconify.Iconify;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.dialog.DownloadRequestErrorDialogCreator;
+import de.danoeh.antennapod.core.feed.FeedItem;
+import de.danoeh.antennapod.core.storage.DBTasks;
+import de.danoeh.antennapod.core.storage.DBWriter;
+import de.danoeh.antennapod.core.storage.DownloadRequestException;
+import de.danoeh.antennapod.core.util.LongList;
+
+public class EpisodesApplyActionFragment extends Fragment {
+
+ public String TAG = "EpisodeActionFragment";
+
+ private ListView mListView;
+ private ArrayAdapter<String> mAdapter;
+
+ private Button btnAddToQueue;
+ private Button btnMarkAsPlayed;
+ private Button btnMarkAsUnplayed;
+ private Button btnDownload;
+ private Button btnDelete;
+
+ private final Map<Long,FeedItem> idMap;
+ private final List<FeedItem> episodes;
+ private final List<String> titles = new ArrayList();
+ private final LongList checkedIds = new LongList();
+
+ private MenuItem mSelectToggle;
+
+ private int textColor;
+
+ public EpisodesApplyActionFragment(List<FeedItem> episodes) {
+ this.episodes = episodes;
+ this.idMap = new HashMap<>(episodes.size());
+ for(FeedItem episode : episodes) {
+ this.idMap.put(episode.getId(), episode);
+ }
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setHasOptionsMenu(true);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ View view = inflater.inflate(R.layout.episodes_apply_action_fragment, container, false);
+
+ mListView = (ListView) view.findViewById(android.R.id.list);
+ mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
+ mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+ public void onItemClick(AdapterView<?> ListView, View view, int position, long rowId) {
+ long id = episodes.get(position).getId();
+ if (checkedIds.contains(id)) {
+ checkedIds.remove(id);
+ } else {
+ checkedIds.add(id);
+ }
+ refreshCheckboxes();
+ }
+ });
+
+ for(FeedItem episode : episodes) {
+ titles.add(episode.getTitle());
+ }
+
+ mAdapter = new ArrayAdapter<>(getActivity(),
+ android.R.layout.simple_list_item_multiple_choice, titles);
+ mListView.setAdapter(mAdapter);
+ checkAll();
+
+ btnAddToQueue = (Button) view.findViewById(R.id.btnAddToQueue);
+ btnAddToQueue.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ queueChecked();
+ }
+ });
+ btnMarkAsPlayed = (Button) view.findViewById(R.id.btnMarkAsPlayed);
+ btnMarkAsPlayed.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ markedCheckedPlayed();
+ }
+ });
+ btnMarkAsUnplayed = (Button) view.findViewById(R.id.btnMarkAsUnplayed);
+ btnMarkAsUnplayed.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ markedCheckedUnplayed();
+ }
+ });
+ btnDownload = (Button) view.findViewById(R.id.btnDownload);
+ btnDownload.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ downloadChecked();
+ }
+ });
+ btnDelete = (Button) view.findViewById(R.id.btnDelete);
+ btnDelete.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ deleteChecked();
+ }
+ });
+
+ return view;
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ super.onCreateOptionsMenu(menu, inflater);
+ inflater.inflate(R.menu.episodes_apply_action_options, menu);
+
+ int[] attrs = { android.R.attr.textColor };
+ TypedArray ta = getActivity().obtainStyledAttributes(attrs);
+ textColor = ta.getColor(0, Color.GRAY);
+ ta.recycle();
+
+ menu.findItem(R.id.sort).setIcon(new IconDrawable(getActivity(),
+ Iconify.IconValue.fa_sort).color(textColor).actionBarSize());
+
+ mSelectToggle = menu.findItem(R.id.select_toggle);
+ mSelectToggle.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
+ @Override
+ public boolean onMenuItemClick(MenuItem item) {
+ if (checkedIds.size() == episodes.size()) {
+ checkNone();
+ } else {
+ checkAll();
+ }
+ return true;
+ }
+ });
+
+ menu.findItem(R.id.select_options).setIcon(new IconDrawable(getActivity(),
+ Iconify.IconValue.fa_caret_down).color(textColor).actionBarSize());
+ }
+
+ @Override
+ public void onPrepareOptionsMenu (Menu menu) {
+ Iconify.IconValue iVal;
+ if(checkedIds.size() == episodes.size()) {
+ iVal = Iconify.IconValue.fa_check_square_o;
+ } else if(checkedIds.size() == 0) {
+ iVal = Iconify.IconValue.fa_square_o;
+ } else {
+ iVal = Iconify.IconValue.fa_minus_square_o;
+ }
+ mSelectToggle.setIcon(new IconDrawable(getActivity(), iVal).color(textColor).actionBarSize());
+
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ int resId = 0;
+ switch(item.getItemId()) {
+ case R.id.select_options:
+ return true;
+ case R.id.check_all:
+ checkAll();
+ resId = R.string.selected_all_label;
+ break;
+ case R.id.check_none:
+ checkNone();
+ resId = R.string.deselected_all_label;
+ break;
+ case R.id.check_played:
+ checkPlayed(true);
+ resId = R.string.selected_played_label;
+ break;
+ case R.id.check_unplayed:
+ checkPlayed(false);
+ resId = R.string.selected_unplayed_label;
+ break;
+ case R.id.check_downloaded:
+ checkDownloaded(true);
+ resId = R.string.selected_downloaded_label;
+ break;
+ case R.id.check_not_downloaded:
+ checkDownloaded(false);
+ resId = R.string.selected_not_downloaded_label;
+ break;
+ case R.id.sort_title_a_z:
+ sortByTitle(false);
+ return true;
+ case R.id.sort_title_z_a:
+ sortByTitle(true);
+ return true;
+ case R.id.sort_date_new_old:
+ sortByDate(true);
+ return true;
+ case R.id.sort_date_old_new:
+ sortByDate(false);
+ return true;
+ case R.id.sort_duration_long_short:
+ sortByDuration(true);
+ return true;
+ case R.id.sort_duration_short_long:
+ sortByDuration(false);
+ return true;
+ }
+ if(resId != 0) {
+ Toast.makeText(getActivity(), resId, Toast.LENGTH_SHORT).show();
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ private void sortByTitle(final boolean reverse) {
+ Collections.sort(episodes, new Comparator<FeedItem>() {
+ @Override
+ public int compare(FeedItem lhs, FeedItem rhs) {
+ if (reverse) {
+ return -1 * lhs.getTitle().compareTo(rhs.getTitle());
+ } else {
+ return lhs.getTitle().compareTo(rhs.getTitle());
+ }
+ }
+ });
+ refreshTitles();
+ refreshCheckboxes();
+ }
+
+ private void sortByDate(final boolean reverse) {
+ Collections.sort(episodes, new Comparator<FeedItem>() {
+ @Override
+ public int compare(FeedItem lhs, FeedItem rhs) {
+ if (lhs.getPubDate() == null) {
+ return -1;
+ } else if (rhs.getPubDate() == null) {
+ return 1;
+ }
+ int code = lhs.getPubDate().compareTo(rhs.getPubDate());
+ if (reverse) {
+ return -1 * code;
+ } else {
+ return code;
+ }
+ }
+ });
+ refreshTitles();
+ refreshCheckboxes();
+ }
+
+ private void sortByDuration(final boolean reverse) {
+ Collections.sort(episodes, new Comparator<FeedItem>() {
+ @Override
+ public int compare(FeedItem lhs, FeedItem rhs) {
+ int ordering;
+ if (false == lhs.hasMedia()) {
+ ordering = 1;
+ } else if (false == rhs.hasMedia()) {
+ ordering = -1;
+ } else {
+ ordering = lhs.getMedia().getDuration() - rhs.getMedia().getDuration();
+ }
+ if(reverse) {
+ return -1 * ordering;
+ } else {
+ return ordering;
+ }
+ }
+ });
+ refreshTitles();
+ refreshCheckboxes();
+ }
+
+ private void checkAll() {
+ for (FeedItem episode : episodes) {
+ if(false == checkedIds.contains(episode.getId())) {
+ checkedIds.add(episode.getId());
+ }
+ }
+ refreshCheckboxes();
+ }
+
+ private void checkNone() {
+ checkedIds.clear();
+ refreshCheckboxes();
+ }
+
+ private void checkPlayed(boolean isPlayed) {
+ for (FeedItem episode : episodes) {
+ if(episode.isRead() == isPlayed) {
+ if(!checkedIds.contains(episode.getId())) {
+ checkedIds.add(episode.getId());
+ }
+ } else {
+ if(checkedIds.contains(episode.getId())) {
+ checkedIds.remove(episode.getId());
+ }
+ }
+ }
+ refreshCheckboxes();
+ }
+
+ private void checkDownloaded(boolean isDownloaded) {
+ for (FeedItem episode : episodes) {
+ if(episode.hasMedia() && episode.getMedia().isDownloaded() == isDownloaded) {
+ if(!checkedIds.contains(episode.getId())) {
+ checkedIds.add(episode.getId());
+ }
+ } else {
+ if(checkedIds.contains(episode.getId())) {
+ checkedIds.remove(episode.getId());
+ }
+ }
+ }
+ refreshCheckboxes();
+ }
+
+ private void refreshTitles() {
+ titles.clear();
+ for(FeedItem episode : episodes) {
+ titles.add(episode.getTitle());
+ }
+ mAdapter.notifyDataSetChanged();
+ }
+
+ private void refreshCheckboxes() {
+ for (int i = 0; i < episodes.size(); i++) {
+ FeedItem episode = episodes.get(i);
+ boolean checked = checkedIds.contains(episode.getId());
+ mListView.setItemChecked(i, checked);
+ }
+ ActivityCompat.invalidateOptionsMenu(EpisodesApplyActionFragment.this.getActivity());
+ }
+
+ 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());
+ close();
+ }
+
+ private void markedCheckedPlayed() {
+ DBWriter.markItemRead(getActivity(), true, checkedIds.toArray());
+ close();
+ }
+
+ private void markedCheckedUnplayed() {
+ DBWriter.markItemRead(getActivity(), false, checkedIds.toArray());
+ close();
+ }
+
+ private void downloadChecked() {
+ // download the check episodes in the same order as they are currently displayed
+ List<FeedItem> toDownload = new ArrayList<FeedItem>(checkedIds.size());
+ for(FeedItem episode : episodes) {
+ if(checkedIds.contains(episode.getId())) {
+ toDownload.add(episode);
+ }
+ }
+ try {
+ DBTasks.downloadFeedItems(getActivity(), toDownload.toArray(new FeedItem[0]));
+ } catch (DownloadRequestException e) {
+ e.printStackTrace();
+ DownloadRequestErrorDialogCreator.newRequestErrorDialog(getActivity(), e.getMessage());
+ }
+ close();
+ }
+
+ private void deleteChecked() {
+ for(long id : checkedIds.toArray()) {
+ FeedItem episode = idMap.get(id);
+ if(episode.hasMedia()) {
+ DBWriter.deleteFeedMediaOfItem(getActivity(), episode.getMedia().getId());
+ }
+ }
+ close();
+ }
+
+ private void close() {
+ getActivity().getSupportFragmentManager().popBackStack();
+ }
+
+}
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 726e99621..797e5fb82 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java
@@ -4,13 +4,15 @@ import android.annotation.SuppressLint;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
+import android.content.res.TypedArray;
+import android.graphics.Color;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
+import android.support.v4.app.Fragment;
import android.support.v4.app.ListFragment;
import android.support.v4.view.MenuItemCompat;
-
import android.support.v7.app.ActionBarActivity;
import android.support.v7.widget.SearchView;
import android.util.Log;
@@ -29,6 +31,7 @@ import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.TextView;
+import com.joanzapata.android.iconify.IconDrawable;
import com.joanzapata.android.iconify.Iconify;
import com.squareup.picasso.Picasso;
@@ -61,6 +64,7 @@ import de.danoeh.antennapod.core.storage.DownloadRequestException;
import de.danoeh.antennapod.core.storage.DownloadRequester;
import de.danoeh.antennapod.core.util.LongList;
import de.danoeh.antennapod.core.util.gui.MoreContentListFooterUtil;
+import de.danoeh.antennapod.dialog.EpisodesApplyActionFragment;
import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
import de.danoeh.antennapod.menuhandler.FeedMenuHandler;
import de.danoeh.antennapod.menuhandler.MenuItemUtils;
@@ -156,6 +160,7 @@ public class ItemlistFragment extends ListFragment {
@Override
public void onResume() {
super.onResume();
+ Log.d(TAG, "onResume()");
updateProgressBarVisibility();
startItemLoader();
}
@@ -222,6 +227,13 @@ public class ItemlistFragment extends ListFragment {
menu.findItem(R.id.share_link_item).setVisible(false);
menu.findItem(R.id.visit_website_item).setVisible(false);
}
+ int[] attrs = { android.R.attr.textColor };
+ TypedArray ta = getActivity().obtainStyledAttributes(attrs);
+ int textColor = ta.getColor(0, Color.GRAY);
+ ta.recycle();
+
+ menu.findItem(R.id.episode_actions).setIcon(new IconDrawable(getActivity(),
+ Iconify.IconValue.fa_gears).color(textColor).actionBarSize());
isUpdatingFeed = MenuItemUtils.updateRefreshMenuItem(menu, R.id.refresh_item, updateRefreshMenuItemChecker);
}
@@ -240,6 +252,10 @@ public class ItemlistFragment extends ListFragment {
try {
if (!FeedMenuHandler.onOptionsItemClicked(getActivity(), item, feed)) {
switch (item.getItemId()) {
+ case R.id.episode_actions:
+ Fragment fragment = new EpisodesApplyActionFragment(feed.getItems());
+ ((MainActivity)getActivity()).loadChildFragment(fragment);
+ return true;
case R.id.remove_item:
final FeedRemover remover = new FeedRemover(
getActivity(), feed) {
@@ -406,6 +422,9 @@ public class ItemlistFragment extends ListFragment {
private boolean insideOnFragmentLoaded = false;
private void onFragmentLoaded() {
+ if(!isVisible()) {
+ return;
+ }
insideOnFragmentLoaded = true;
if (adapter == null) {
setListAdapter(null);
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 4bce3c7ba..cbf3ffdd7 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java
@@ -72,7 +72,7 @@ public class NewEpisodesFragment extends AllEpisodesFragment {
Log.d(TAG, "remove(" + which + ")");
stopItemLoader();
FeedItem item = (FeedItem) listView.getAdapter().getItem(which);
- DBWriter.markItemRead(getActivity(), item.getId(), true);
+ DBWriter.markItemRead(getActivity(), true, item.getId());
undoBarController.showUndoBar(false,
getString(R.string.marked_as_read_label), new FeedItemUndoToken(item,
which)
@@ -88,7 +88,7 @@ public class NewEpisodesFragment extends AllEpisodesFragment {
public void onUndo(FeedItemUndoToken token) {
if (token != null) {
long itemId = token.getFeedItemId();
- DBWriter.markItemRead(context, itemId, false);
+ DBWriter.markItemRead(context, false, itemId);
}
}
@Override
diff --git a/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java
index 30cc2c640..3df59724d 100644
--- a/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java
+++ b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java
@@ -41,7 +41,6 @@ public class FeedMenuHandler {
}
Log.d(TAG, "Preparing options menu");
- menu.findItem(R.id.mark_all_read_item).setVisible(selectedFeed.hasNewItems());
if (selectedFeed.getPaymentLink() != null && selectedFeed.getFlattrStatus().flattrable()) {
menu.findItem(R.id.support_item).setVisible(true);
} else {
diff --git a/app/src/main/res/layout/episodes_apply_action_fragment.xml b/app/src/main/res/layout/episodes_apply_action_fragment.xml
new file mode 100644
index 000000000..d63088662
--- /dev/null
+++ b/app/src/main/res/layout/episodes_apply_action_fragment.xml
@@ -0,0 +1,120 @@
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+
+ <LinearLayout
+ android:id="@+id/bottomBar"
+ android:layout_width="wrap_content"
+ android:layout_height="68dp"
+ android:layout_alignParentBottom="true"
+ android:orientation="horizontal"
+ android:gravity="center_vertical"
+ android:padding="4dp">
+
+ <Button
+ android:id="@+id/btnAddToQueue"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:drawableTop="?attr/content_new"
+ android:text="@string/add_to_queue_label"
+ android:textSize="10sp"
+ android:background="@android:color/transparent"/>
+
+ <View xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="1dp"
+ android:layout_height="match_parent"
+ android:layout_margin="4dp"
+ android:background="?android:attr/listDivider"
+ tools:background="@android:color/holo_red_dark" />
+
+ <Button
+ android:id="@+id/btnMarkAsPlayed"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:drawableTop="?attr/navigation_accept"
+ android:text="@string/mark_read_label"
+ android:textSize="10sp"
+ android:background="@android:color/transparent"/>
+
+ <View xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="1dp"
+ android:layout_height="match_parent"
+ android:layout_margin="4dp"
+ android:background="?android:attr/listDivider"
+ tools:background="@android:color/holo_red_dark" />
+
+ <Button
+ android:id="@+id/btnMarkAsUnplayed"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:drawableTop="?attr/navigation_cancel"
+ android:text="@string/mark_unread_label"
+ android:textSize="10sp"
+ android:background="@android:color/transparent"/>
+
+ <View xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="1dp"
+ android:layout_height="match_parent"
+ android:layout_margin="4dp"
+ android:background="?android:attr/listDivider"
+ tools:background="@android:color/holo_red_dark" />
+
+ <Button
+ android:id="@+id/btnDownload"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:drawableTop="?attr/av_download"
+ android:text="@string/download_label"
+ android:textSize="10sp"
+ android:background="@android:color/transparent"/>
+
+ <View xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="1dp"
+ android:layout_height="match_parent"
+ android:layout_margin="4dp"
+ android:background="?android:attr/listDivider"
+ tools:background="@android:color/holo_red_dark" />
+
+ <Button
+ android:id="@+id/btnDelete"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:drawableTop="?attr/content_discard"
+ android:text="@string/remove_episode_lable"
+ android:textSize="10sp"
+ android:background="@android:color/transparent"/>
+
+ </LinearLayout>
+
+ <View
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/divider"
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="?android:attr/listDivider"
+ android:paddingBottom="4dp"
+ android:layout_above="@id/bottomBar"
+ tools:background="@android:color/holo_red_dark" />
+
+ <ListView
+ android:id="@android:id/list"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_above="@id/divider">
+
+ </ListView>
+
+
+</RelativeLayout>
diff --git a/app/src/main/res/menu/episodes_apply_action_options.xml b/app/src/main/res/menu/episodes_apply_action_options.xml
new file mode 100644
index 000000000..88bef8d1f
--- /dev/null
+++ b/app/src/main/res/menu/episodes_apply_action_options.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
+
+ <item
+ android:id="@+id/sort"
+ android:title="@string/sort"
+ app:showAsAction="always">
+ <menu>
+ <item android:id="@+id/sort_title"
+ android:title="@string/sort_title"/>
+ <item android:id="@+id/sort_title_a_z"
+ android:title="@string/sort_title_a_z"/>
+ <item android:id="@+id/sort_title_z_a"
+ android:title="@string/sort_title_z_a"/>
+ <item android:id="@+id/sort_date_new_old"
+ android:title="@string/sort_date_new_old"/>
+ <item android:id="@+id/sort_date_old_new"
+ android:title="@string/sort_date_old_new"/>
+ <item android:id="@+id/sort_duration_short_long"
+ android:title="@string/sort_duration_short_long"/>
+ <item android:id="@+id/sort_duration_long_short"
+ android:title="@string/sort_duration_long_short"/>
+ </menu>
+ </item>
+
+ <item
+ android:id="@+id/select_toggle"
+ android:title="@string/select_all_label"
+ app:showAsAction="always"/>
+
+ <item
+ android:id="@+id/select_options"
+ android:title="@string/all_label"
+ app:showAsAction="always">
+
+ <menu>
+ <item android:id="@+id/select_label"
+ android:title="@string/select_label"/>
+ <item android:id="@+id/check_all"
+ android:title="@string/all_label"/>
+ <item android:id="@+id/check_none"
+ android:title="@string/none_label"/>
+ <item android:id="@+id/check_played"
+ android:title="@string/played_label"/>
+ <item android:id="@+id/check_unplayed"
+ android:title="@string/unplayed_label"/>
+ <item android:id="@+id/check_downloaded"
+ android:title="@string/downloaded_label"/>
+ <item android:id="@+id/check_not_downloaded"
+ android:title="@string/not_downloaded_label"/>
+ </menu>
+ </item>
+
+</menu>
diff --git a/app/src/main/res/menu/feedlist.xml b/app/src/main/res/menu/feedlist.xml
index e6e85093b..54b90f5c6 100644
--- a/app/src/main/res/menu/feedlist.xml
+++ b/app/src/main/res/menu/feedlist.xml
@@ -10,6 +10,12 @@
custom:showAsAction="always">
</item>
<item
+ android:id="@+id/episode_actions"
+ android:menuCategory="container"
+ android:title="@string/episode_actions"
+ custom:showAsAction="always">
+ </item>
+ <item
android:id="@+id/refresh_item"
android:icon="?attr/navigation_refresh"
android:menuCategory="container"
@@ -31,13 +37,6 @@
android:title="@string/search_label"/>
<item
- android:id="@+id/mark_all_read_item"
- android:menuCategory="container"
- android:title="@string/mark_all_read_label"
- custom:showAsAction="collapseActionView">
- </item>
-
- <item
android:id="@+id/support_item"
android:menuCategory="container"
android:title="@string/support_label"
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 feeee48c5..e103007e3 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
@@ -375,14 +375,21 @@ public class DBWriter {
}
+ public static Future<?> addQueueItem(final Context context,
+ final long... itemIds) {
+ return addQueueItem(context, false, itemIds);
+ }
+
+
/**
* Appends FeedItem objects to the end of the queue. The 'read'-attribute of all items will be set to true.
* If a FeedItem is already in the queue, the FeedItem will not change its position in the queue.
*
* @param context A context that is used for opening a database connection.
+ * @param performAutoDownload true if an auto-download process should be started after the operation.
* @param itemIds IDs of the FeedItem objects that should be added to the queue.
*/
- public static Future<?> addQueueItem(final Context context,
+ public static Future<?> addQueueItem(final Context context, final boolean performAutoDownload,
final long... itemIds) {
return dbExec.submit(new Runnable() {
@@ -408,7 +415,7 @@ public class DBWriter {
boolean addToFront = UserPreferences.enqueueAtFront();
if(addToFront){
- queue.add(0, item);
+ queue.add(0+i, item);
} else {
queue.add(item);
}
@@ -423,11 +430,12 @@ public class DBWriter {
}
}
adapter.close();
- DBTasks.autodownloadUndownloadedItems(context);
+ if (performAutoDownload) {
+ DBTasks.autodownloadUndownloadedItems(context);
+ }
}
}
});
-
}
/**
@@ -595,16 +603,24 @@ public class DBWriter {
adapter.close();
}
- /**
- * Sets the 'read'-attribute of a FeedItem to the specified value.
+ /*
+ * Sets the 'read'-attribute of all specified FeedItems
*
* @param context A context that is used for opening a database connection.
- * @param itemId ID of the FeedItem
* @param read New value of the 'read'-attribute
+ * @param itemIds IDs of the FeedItems.
*/
- public static Future<?> markItemRead(final Context context, final long itemId,
- final boolean read) {
- return markItemRead(context, itemId, read, 0, false);
+ public static Future<?> markItemRead(final Context context, final boolean read, final long... itemIds) {
+ return dbExec.submit(new Runnable() {
+ @Override
+ public void run() {
+ final PodDBAdapter adapter = new PodDBAdapter(context);
+ adapter.open();
+ adapter.setFeedItemRead(read, itemIds);
+ adapter.close();
+ EventDistributor.getInstance().sendUnreadItemsUpdateBroadcast();
+ }
+ });
}
diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml
index 0f1830202..00d7ed1bd 100644
--- a/core/src/main/res/values/strings.xml
+++ b/core/src/main/res/values/strings.xml
@@ -96,6 +96,7 @@
<string name="feed_remover_msg">Removing Feed</string>
<string name="load_complete_feed">Refresh complete Feed</string>
<string name="hide_episodes_title">Hide Episodes</string>
+ <string name="episode_actions">Apply actions</string>
<string name="hide_unplayed_episodes_label">Unplayed</string>
<string name="hide_paused_episodes_label">Paused</string>
<string name="hide_played_episodes_label">Played</string>
@@ -115,8 +116,8 @@
<string name="remove_label">Remove</string>
<string name="remove_episode_lable">Remove Episode</string>
<string name="mark_read_label">Mark as played</string>
- <string name="mark_unread_label">Mark as unplayed</string>
<string name="marked_as_read_label">Marked as played</string>
+ <string name="mark_unread_label">Mark as unplayed</string>
<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>
@@ -346,6 +347,7 @@
<string name="opml_import_error_dir_empty">The import directory is empty.</string>
<string name="select_all_label">Select all</string>
<string name="deselect_all_label">Deselect all</string>
+ <string name="select_options_label">Select ...</string>
<string name="choose_file_from_filesystem">From local filesystem</string>
<string name="choose_file_from_external_application">Use external application</string>
<string name="opml_export_label">OPML export</string>
@@ -450,4 +452,25 @@
<string name="sp_apps_importing_feeds_msg">Importing subscriptions from single-purpose apps&#8230;</string>
<string name="search_itunes_label">Search iTunes</string>
+
+ <string name="select_label"><b>Select ...</b></string>
+ <string name="all_label">All</string>
+ <string name="selected_all_label">Selected all Episodes</string>
+ <string name="none_label">None</string>
+ <string name="deselected_all_label">Deselected all Episodes</string>
+ <string name="played_label">Played</string>
+ <string name="selected_played_label">Selected played Episodes</string>
+ <string name="unplayed_label">Unplayed</string>
+ <string name="selected_unplayed_label">Selected unplayed Episodes</string>
+ <string name="downloaded_label">Downloaded</string>
+ <string name="selected_downloaded_label">Selected downloaded Episodes</string>
+ <string name="not_downloaded_label">Not downloaded</string>
+ <string name="selected_not_downloaded_label">Selected not downloaded Episodes</string>
+ <string name="sort_title"><b>Sort by ...</b></string>
+ <string name="sort_title_a_z">Title (A \u2192 Z)</string>
+ <string name="sort_title_z_a">Title (Z \u2192 A)</string>
+ <string name="sort_date_new_old">Date (New \u2192 Old)</string>
+ <string name="sort_date_old_new">Date (Old \u2192 New)</string>
+ <string name="sort_duration_short_long">Duration (Short \u2192 Long)</string>
+ <string name="sort_duration_long_short">Duration (Long \u2192 Short)</string>
</resources>