Add feed item filter
@ -45,7 +45,7 @@ public class DBReaderTest extends InstrumentationTestCase {
|
||||
private void expiredFeedListTestHelper(long lastUpdate, long expirationTime, boolean shouldReturn) {
|
||||
final Context context = getInstrumentation().getTargetContext();
|
||||
Feed feed = new Feed(0, new Date(lastUpdate), "feed", "link", "descr", null,
|
||||
null, null, null, "feed", null, null, "url", false, new FlattrStatus(), false, null);
|
||||
null, null, null, "feed", null, null, "url", false, new FlattrStatus(), false, null, null);
|
||||
feed.setItems(new ArrayList<FeedItem>());
|
||||
PodDBAdapter adapter = new PodDBAdapter(context);
|
||||
adapter.open();
|
||||
|
@ -4,6 +4,14 @@ import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.test.InstrumentationTestCase;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import de.danoeh.antennapod.core.feed.Feed;
|
||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||
import de.danoeh.antennapod.core.feed.FeedMedia;
|
||||
@ -13,14 +21,7 @@ import de.danoeh.antennapod.core.storage.DBTasks;
|
||||
import de.danoeh.antennapod.core.storage.PodDBAdapter;
|
||||
import de.danoeh.antennapod.core.util.flattr.FlattrStatus;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import static de.test.antennapod.storage.DBTestUtils.*;
|
||||
import static de.test.antennapod.storage.DBTestUtils.saveFeedlist;
|
||||
|
||||
/**
|
||||
* Test class for DBTasks
|
||||
@ -296,7 +297,7 @@ public class DBTasksTest extends InstrumentationTestCase {
|
||||
final Context context = getInstrumentation().getTargetContext();
|
||||
UserPreferences.setUpdateInterval(context, expirationTime);
|
||||
Feed feed = new Feed(0, new Date(lastUpdate), "feed", "link", "descr", null,
|
||||
null, null, null, "feed", null, null, "url", false, new FlattrStatus(), false, null);
|
||||
null, null, null, "feed", null, null, "url", false, new FlattrStatus(), false, null, null);
|
||||
feed.setItems(new ArrayList<FeedItem>());
|
||||
PodDBAdapter adapter = new PodDBAdapter(context);
|
||||
adapter.open();
|
||||
|
@ -47,7 +47,7 @@ public class DBTestUtils {
|
||||
adapter.open();
|
||||
for (int i = 0; i < numFeeds; i++) {
|
||||
Feed f = new Feed(0, new Date(), "feed " + i, "link" + i, "descr", null, null,
|
||||
null, null, "id" + i, null, null, "url" + i, false, new FlattrStatus(), false, null);
|
||||
null, null, "id" + i, null, null, "url" + i, false, new FlattrStatus(), false, null, null);
|
||||
f.setItems(new ArrayList<FeedItem>());
|
||||
for (int j = 0; j < numItems; j++) {
|
||||
FeedItem item = new FeedItem(0, "item " + j, "id" + j, "link" + j, new Date(),
|
||||
|
@ -7,9 +7,14 @@ import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.*;
|
||||
import android.widget.Adapter;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
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.MediaType;
|
||||
@ -211,8 +216,8 @@ public class FeedItemlistAdapter extends BaseAdapter {
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public static interface ItemAccess {
|
||||
public boolean isInQueue(FeedItem item);
|
||||
public interface ItemAccess {
|
||||
boolean isInQueue(FeedItem item);
|
||||
|
||||
int getItemDownloadProgressPercent(FeedItem item);
|
||||
|
||||
|
@ -133,6 +133,8 @@ public class StorageCallbacksImpl implements StorageCallbacks {
|
||||
+ " FROM " + PodDBAdapter.TABLE_NAME_FEEDS
|
||||
+ " WHERE " + PodDBAdapter.TABLE_NAME_FEEDS + "." + PodDBAdapter.KEY_ID
|
||||
+ " = " + PodDBAdapter.TABLE_NAME_FEED_ITEMS + "." + PodDBAdapter.KEY_FEED + ")");
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
|
||||
+ " ADD COLUMN " + PodDBAdapter.KEY_HIDE + " TEXT");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ import android.widget.ListAdapter;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.joanzapata.android.iconify.Iconify;
|
||||
import com.squareup.picasso.Picasso;
|
||||
|
||||
import org.apache.commons.lang3.Validate;
|
||||
@ -42,7 +43,9 @@ import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
|
||||
import de.danoeh.antennapod.core.dialog.DownloadRequestErrorDialogCreator;
|
||||
import de.danoeh.antennapod.core.feed.EventDistributor;
|
||||
import de.danoeh.antennapod.core.feed.Feed;
|
||||
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.service.download.DownloadService;
|
||||
@ -55,7 +58,6 @@ import de.danoeh.antennapod.core.util.LongList;
|
||||
import de.danoeh.antennapod.core.util.gui.MoreContentListFooterUtil;
|
||||
import de.danoeh.antennapod.menuhandler.FeedMenuHandler;
|
||||
import de.danoeh.antennapod.menuhandler.MenuItemUtils;
|
||||
import de.danoeh.antennapod.menuhandler.NavDrawerActivity;
|
||||
import de.greenrobot.event.EventBus;
|
||||
|
||||
/**
|
||||
@ -89,6 +91,8 @@ public class ItemlistFragment extends ListFragment {
|
||||
|
||||
private boolean isUpdatingFeed;
|
||||
|
||||
private TextView txtvInformation;
|
||||
|
||||
/**
|
||||
* Creates new ItemlistFragment which shows the Feeditems of a specific
|
||||
* feed. Sets 'showFeedtitle' to false
|
||||
@ -291,6 +295,13 @@ public class ItemlistFragment extends ListFragment {
|
||||
startItemLoader();
|
||||
}
|
||||
|
||||
public void onEvent(FeedEvent event) {
|
||||
Log.d(TAG, "onEvent(" + event + ")");
|
||||
if(event.feedId == feedID) {
|
||||
startItemLoader();
|
||||
}
|
||||
}
|
||||
|
||||
private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
|
||||
|
||||
@Override
|
||||
@ -330,6 +341,7 @@ public class ItemlistFragment extends ListFragment {
|
||||
downloadObserver = new DownloadObserver(getActivity(), new Handler(), downloadObserverCallback);
|
||||
downloadObserver.onResume();
|
||||
}
|
||||
refreshHeaderView();
|
||||
setListShown(true);
|
||||
adapter.notifyDataSetChanged();
|
||||
|
||||
@ -343,6 +355,22 @@ public class ItemlistFragment extends ListFragment {
|
||||
|
||||
}
|
||||
|
||||
private void refreshHeaderView() {
|
||||
if(feed.getItemFilter() != null) {
|
||||
FeedItemFilter filter = feed.getItemFilter();
|
||||
if(filter.getValues().length > 0) {
|
||||
txtvInformation.setText("{fa-info-circle} " + this.getString(R.string.filtered_label));
|
||||
Iconify.addIcons(txtvInformation);
|
||||
txtvInformation.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
txtvInformation.setVisibility(View.GONE);
|
||||
}
|
||||
} else {
|
||||
txtvInformation.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private DownloadObserver.Callback downloadObserverCallback = new DownloadObserver.Callback() {
|
||||
@Override
|
||||
public void onContentChanged() {
|
||||
@ -376,6 +404,7 @@ public class ItemlistFragment extends ListFragment {
|
||||
ImageView imgvBackground = (ImageView) header.findViewById(R.id.imgvBackground);
|
||||
ImageView imgvCover = (ImageView) header.findViewById(R.id.imgvCover);
|
||||
ImageButton butShowInfo = (ImageButton) header.findViewById(R.id.butShowInfo);
|
||||
txtvInformation = (TextView) header.findViewById(R.id.txtvInformation);
|
||||
|
||||
txtvTitle.setText(feed.getTitle());
|
||||
txtvAuthor.setText(feed.getAuthor());
|
||||
@ -488,6 +517,10 @@ public class ItemlistFragment extends ListFragment {
|
||||
Context context = getActivity();
|
||||
if (context != null) {
|
||||
Feed feed = DBReader.getFeed(context, feedID);
|
||||
if(feed.getItemFilter() != null) {
|
||||
FeedItemFilter filter = feed.getItemFilter();
|
||||
feed.setItems(filter.filter(context, feed.getItems()));
|
||||
}
|
||||
LongList queue = DBReader.getQueueIDList(context);
|
||||
return Pair.create(feed, queue);
|
||||
} else {
|
||||
|
@ -23,10 +23,10 @@ import de.danoeh.antennapod.core.util.ShareUtils;
|
||||
* Handles interactions with the FeedItemMenu.
|
||||
*/
|
||||
public class FeedItemMenuHandler {
|
||||
|
||||
private static final String TAG = "FeedItemMenuHandler";
|
||||
|
||||
private FeedItemMenuHandler() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,5 +1,6 @@
|
||||
package de.danoeh.antennapod.menuhandler;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
@ -9,6 +10,10 @@ import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.core.BuildConfig;
|
||||
import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
|
||||
@ -62,6 +67,9 @@ public class FeedMenuHandler {
|
||||
case R.id.refresh_complete_item:
|
||||
DBTasks.refreshCompleteFeed(context, selectedFeed);
|
||||
break;
|
||||
case R.id.hide_items:
|
||||
showHideDialog(context, selectedFeed);
|
||||
break;
|
||||
case R.id.mark_all_read_item:
|
||||
ConfirmationDialog conDialog = new ConfirmationDialog(context,
|
||||
R.string.mark_all_read_label,
|
||||
@ -94,4 +102,43 @@ public class FeedMenuHandler {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void showHideDialog(final Context context, final Feed feed) {
|
||||
|
||||
final String[] items = context.getResources().getStringArray(R.array.episode_hide_options);
|
||||
final String[] values = context.getResources().getStringArray(R.array.episode_hide_values);
|
||||
final boolean[] checkedItems = new boolean[items.length];
|
||||
|
||||
final List<String> hidden = new ArrayList<String>(Arrays.asList(feed.getItemFilter().getValues()));
|
||||
for(int i=0; i < values.length; i++) {
|
||||
String value = values[i];
|
||||
if(hidden.contains(value)) {
|
||||
checkedItems[i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
||||
builder.setTitle(R.string.hide_episodes_title);
|
||||
builder.setMultiChoiceItems(items, checkedItems, new DialogInterface.OnMultiChoiceClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which, boolean isChecked) {
|
||||
if (isChecked) {
|
||||
hidden.add(values[which]);
|
||||
} else {
|
||||
hidden.remove(values[which]);
|
||||
}
|
||||
}
|
||||
});
|
||||
builder.setPositiveButton(R.string.confirm_label, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
feed.setFeedItemsFilter(hidden.toArray(new String[hidden.size()]));
|
||||
DBWriter.setFeedItemsFilter(context, feed.getId(), hidden);
|
||||
}
|
||||
});
|
||||
builder.setNegativeButton(R.string.cancel_label, null);
|
||||
builder.create().show();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/feeditemlist_header_height"
|
||||
android:layout_height="wrap_content"
|
||||
tools:context="de.danoeh.antennapod.activity.MainActivity"
|
||||
tools:background="@android:color/darker_gray">
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
android:id="@+id/imgvBackground"
|
||||
style="@style/BigBlurryBackground"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
android:layout_height="@dimen/feeditemlist_header_height" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/imgvCover"
|
||||
@ -78,5 +78,16 @@
|
||||
tools:text="Podcast author"
|
||||
tools:background="@android:color/holo_green_dark" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/txtvInformation"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/imgvBackground"
|
||||
android:paddingTop="2dp"
|
||||
android:paddingBottom="2dp"
|
||||
android:gravity="center"
|
||||
android:visibility="gone"
|
||||
tools:text="(i) Information"
|
||||
/>
|
||||
|
||||
</RelativeLayout>
|
@ -2,6 +2,13 @@
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:custom="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item
|
||||
android:id="@+id/hide_items"
|
||||
android:icon="?attr/ic_filter"
|
||||
android:menuCategory="container"
|
||||
android:title="@string/hide_episodes_title"
|
||||
custom:showAsAction="always">
|
||||
</item>
|
||||
<item
|
||||
android:id="@+id/refresh_item"
|
||||
android:icon="?attr/navigation_refresh"
|
||||
|
@ -10,9 +10,7 @@ import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import de.danoeh.antennapod.core.asynctask.PicassoImageResource;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.storage.DBWriter;
|
||||
import de.danoeh.antennapod.core.util.EpisodeFilter;
|
||||
import de.danoeh.antennapod.core.util.flattr.FlattrStatus;
|
||||
import de.danoeh.antennapod.core.util.flattr.FlattrThing;
|
||||
|
||||
@ -81,12 +79,18 @@ public class Feed extends FeedFile implements FlattrThing, PicassoImageResource
|
||||
*/
|
||||
private String nextPageLink;
|
||||
|
||||
/**
|
||||
* Contains property strings. If such a property applies to a feed item, it is not shown in the feed list
|
||||
*/
|
||||
private FeedItemFilter itemfilter;
|
||||
|
||||
/**
|
||||
* This constructor is used for restoring a feed from the database.
|
||||
*/
|
||||
public Feed(long id, Date lastUpdate, String title, String link, String description, String paymentLink,
|
||||
String author, String language, String type, String feedIdentifier, FeedImage image, String fileUrl,
|
||||
String downloadUrl, boolean downloaded, FlattrStatus status, boolean paged, String nextPageLink) {
|
||||
String downloadUrl, boolean downloaded, FlattrStatus status, boolean paged, String nextPageLink,
|
||||
String filter) {
|
||||
super(fileUrl, downloadUrl, downloaded);
|
||||
this.id = id;
|
||||
this.title = title;
|
||||
@ -106,6 +110,11 @@ public class Feed extends FeedFile implements FlattrThing, PicassoImageResource
|
||||
this.flattrStatus = status;
|
||||
this.paged = paged;
|
||||
this.nextPageLink = nextPageLink;
|
||||
if(filter != null) {
|
||||
this.itemfilter = new FeedItemFilter(filter);
|
||||
} else {
|
||||
this.itemfilter = new FeedItemFilter(new String[0]);
|
||||
}
|
||||
|
||||
items = new ArrayList<FeedItem>();
|
||||
}
|
||||
@ -117,7 +126,7 @@ public class Feed extends FeedFile implements FlattrThing, PicassoImageResource
|
||||
String author, String language, String type, String feedIdentifier, FeedImage image, String fileUrl,
|
||||
String downloadUrl, boolean downloaded) {
|
||||
this(id, lastUpdate, title, link, description, paymentLink, author, language, type, feedIdentifier, image,
|
||||
fileUrl, downloadUrl, downloaded, new FlattrStatus(), false, null);
|
||||
fileUrl, downloadUrl, downloaded, new FlattrStatus(), false, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -159,40 +168,6 @@ public class Feed extends FeedFile implements FlattrThing, PicassoImageResource
|
||||
preferences = new FeedPreferences(0, true, username, password);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of FeedItems where 'read' is false. If the 'display
|
||||
* only episodes' - preference is set to true, this method will only count
|
||||
* items with episodes.
|
||||
*/
|
||||
public int getNumOfNewItems() {
|
||||
int count = 0;
|
||||
for (FeedItem item : items) {
|
||||
if (item.getState() == FeedItem.State.NEW) {
|
||||
if (!UserPreferences.isDisplayOnlyEpisodes()
|
||||
|| item.getMedia() != null) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of FeedItems where the media started to play but
|
||||
* wasn't finished yet.
|
||||
*/
|
||||
public int getNumOfStartedItems() {
|
||||
int count = 0;
|
||||
|
||||
for (FeedItem item : items) {
|
||||
FeedItem.State state = item.getState();
|
||||
if (state == FeedItem.State.IN_PROGRESS
|
||||
|| state == FeedItem.State.PLAYING) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if at least one item in the itemlist is unread.
|
||||
@ -204,8 +179,7 @@ public class Feed extends FeedFile implements FlattrThing, PicassoImageResource
|
||||
public boolean hasNewItems(boolean enableEpisodeFilter) {
|
||||
for (FeedItem item : items) {
|
||||
if (item.getState() == FeedItem.State.NEW) {
|
||||
if (!(enableEpisodeFilter && UserPreferences
|
||||
.isDisplayOnlyEpisodes()) || item.getMedia() != null) {
|
||||
if (item.getMedia() != null) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -221,11 +195,7 @@ public class Feed extends FeedFile implements FlattrThing, PicassoImageResource
|
||||
* user.
|
||||
*/
|
||||
public int getNumOfItems(boolean enableEpisodeFilter) {
|
||||
if (enableEpisodeFilter && UserPreferences.isDisplayOnlyEpisodes()) {
|
||||
return EpisodeFilter.countItemsWithEpisodes(items);
|
||||
} else {
|
||||
return items.size();
|
||||
}
|
||||
return items.size();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -235,11 +205,7 @@ public class Feed extends FeedFile implements FlattrThing, PicassoImageResource
|
||||
* the episodes filter has been enabled by the user.
|
||||
*/
|
||||
public FeedItem getItemAtIndex(boolean enableEpisodeFilter, int position) {
|
||||
if (enableEpisodeFilter && UserPreferences.isDisplayOnlyEpisodes()) {
|
||||
return EpisodeFilter.accessEpisodeByIndex(items, position);
|
||||
} else {
|
||||
return items.get(position);
|
||||
}
|
||||
return items.get(position);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -516,4 +482,15 @@ public class Feed extends FeedFile implements FlattrThing, PicassoImageResource
|
||||
public void setNextPageLink(String nextPageLink) {
|
||||
this.nextPageLink = nextPageLink;
|
||||
}
|
||||
|
||||
public FeedItemFilter getItemFilter() {
|
||||
return itemfilter;
|
||||
}
|
||||
|
||||
public void setFeedItemsFilter(String[] filter) {
|
||||
if(filter != null) {
|
||||
this.itemfilter = new FeedItemFilter(filter);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,28 @@
|
||||
package de.danoeh.antennapod.core.feed;
|
||||
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
|
||||
public class FeedEvent {
|
||||
|
||||
public enum Action {
|
||||
FILTER_CHANGED
|
||||
}
|
||||
|
||||
public final Action action;
|
||||
public final long feedId;
|
||||
|
||||
public FeedEvent(Action action, long feedId) {
|
||||
this.action = action;
|
||||
this.feedId = feedId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
|
||||
.append("action", action)
|
||||
.append("feedId", feedId)
|
||||
.toString();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
package de.danoeh.antennapod.core.feed;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import de.danoeh.antennapod.core.storage.DBReader;
|
||||
|
||||
public class FeedItemFilter {
|
||||
|
||||
private final String[] filter;
|
||||
|
||||
private boolean hideUnplayed = false;
|
||||
private boolean hidePaused = false;
|
||||
private boolean hidePlayed = false;
|
||||
private boolean hideQueued = false;
|
||||
private boolean hideNotQueued = false;
|
||||
private boolean hideDownloaded = false;
|
||||
private boolean hideNotDownloaded = false;
|
||||
|
||||
public FeedItemFilter(String filter) {
|
||||
this(StringUtils.split(filter, ','));
|
||||
}
|
||||
|
||||
public FeedItemFilter(String[] filter) {
|
||||
this.filter = filter;
|
||||
for(String f : filter) {
|
||||
// see R.arrays.feed_filter_values
|
||||
switch(f) {
|
||||
case "unplayed":
|
||||
hideUnplayed = true;
|
||||
break;
|
||||
case "paused":
|
||||
hidePaused = true;
|
||||
break;
|
||||
case "played":
|
||||
hidePlayed = true;
|
||||
break;
|
||||
case "queued":
|
||||
hideQueued = true;
|
||||
break;
|
||||
case "not_queued":
|
||||
hideNotQueued = true;
|
||||
break;
|
||||
case "downloaded":
|
||||
hideDownloaded = true;
|
||||
break;
|
||||
case "not_downloaded":
|
||||
hideNotDownloaded = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<FeedItem> filter(Context context, List<FeedItem> items) {
|
||||
if(filter.length == 0) {
|
||||
return items;
|
||||
}
|
||||
List<FeedItem> result = new ArrayList<FeedItem>();
|
||||
for(FeedItem item : items) {
|
||||
if(hideUnplayed && false == item.isRead()) continue;
|
||||
if(hidePaused && item.getState() == FeedItem.State.IN_PROGRESS) continue;
|
||||
if(hidePlayed && item.isRead()) continue;
|
||||
boolean isQueued = DBReader.getQueueIDList(context).contains(item.getId());
|
||||
if(hideQueued && isQueued) continue;
|
||||
if(hideNotQueued && false == isQueued) continue;
|
||||
boolean isDownloaded = item.getMedia() != null && item.getMedia().isDownloaded();
|
||||
if(hideDownloaded && isDownloaded) continue;
|
||||
if(hideNotDownloaded && false == isDownloaded) continue;
|
||||
result.add(item);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public String[] getValues() {
|
||||
return filter.clone();
|
||||
}
|
||||
|
||||
}
|
@ -6,7 +6,6 @@ import android.media.MediaMetadataRetriever;
|
||||
import android.net.Uri;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
@ -231,7 +230,6 @@ public class FeedMedia extends FeedFile implements Playable {
|
||||
}
|
||||
|
||||
public boolean hasEmbeddedPicture() {
|
||||
Log.d(TAG, "hasEmbeddedPicture() -> " + hasEmbeddedPicture);
|
||||
return this.hasEmbeddedPicture;
|
||||
}
|
||||
|
||||
@ -433,7 +431,6 @@ public class FeedMedia extends FeedFile implements Playable {
|
||||
}
|
||||
|
||||
private void checkEmbeddedPicture() {
|
||||
Log.d(TAG, "checkEmbeddedPicture()");
|
||||
if (!localFileAvailable()) {
|
||||
hasEmbeddedPicture = false;
|
||||
return;
|
||||
|
@ -45,7 +45,6 @@ public class UserPreferences implements
|
||||
public static final String PREF_UPDATE_INTERVAL = "prefAutoUpdateIntervall";
|
||||
public static final String PREF_PARALLEL_DOWNLOADS = "prefParallelDownloads";
|
||||
public static final String PREF_MOBILE_UPDATE = "prefMobileUpdate";
|
||||
public static final String PREF_DISPLAY_ONLY_EPISODES = "prefDisplayOnlyEpisodes";
|
||||
public static final String PREF_AUTO_DELETE = "prefAutoDelete";
|
||||
public static final String PREF_SMART_MARK_AS_PLAYED_SECS = "prefSmartMarkAsPlayedSecs";
|
||||
public static final String PREF_AUTO_FLATTR = "pref_auto_flattr";
|
||||
@ -84,7 +83,6 @@ public class UserPreferences implements
|
||||
private boolean downloadMediaOnWifiOnly;
|
||||
private long updateInterval;
|
||||
private boolean allowMobileUpdate;
|
||||
private boolean displayOnlyEpisodes;
|
||||
private boolean autoDelete;
|
||||
private int smartMarkAsPlayedSecs;
|
||||
private boolean autoFlattr;
|
||||
@ -146,7 +144,6 @@ public class UserPreferences implements
|
||||
updateInterval = readUpdateInterval(sp.getString(PREF_UPDATE_INTERVAL,
|
||||
"0"));
|
||||
allowMobileUpdate = sp.getBoolean(PREF_MOBILE_UPDATE, false);
|
||||
displayOnlyEpisodes = sp.getBoolean(PREF_DISPLAY_ONLY_EPISODES, false);
|
||||
autoDelete = sp.getBoolean(PREF_AUTO_DELETE, false);
|
||||
smartMarkAsPlayedSecs = Integer.valueOf(sp.getString(PREF_SMART_MARK_AS_PLAYED_SECS, "30"));
|
||||
autoFlattr = sp.getBoolean(PREF_AUTO_FLATTR, false);
|
||||
@ -272,12 +269,6 @@ public class UserPreferences implements
|
||||
return instance.allowMobileUpdate;
|
||||
}
|
||||
|
||||
public static boolean isDisplayOnlyEpisodes() {
|
||||
instanceAvailable();
|
||||
//return instance.displayOnlyEpisodes;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isAutoDelete() {
|
||||
instanceAvailable();
|
||||
return instance.autoDelete;
|
||||
@ -435,9 +426,6 @@ public class UserPreferences implements
|
||||
smartMarkAsPlayedSecs = Integer.valueOf(sp.getString(PREF_SMART_MARK_AS_PLAYED_SECS, "30"));
|
||||
} else if (key.equals(PREF_AUTO_FLATTR)) {
|
||||
autoFlattr = sp.getBoolean(PREF_AUTO_FLATTR, false);
|
||||
} else if (key.equals(PREF_DISPLAY_ONLY_EPISODES)) {
|
||||
displayOnlyEpisodes = sp.getBoolean(PREF_DISPLAY_ONLY_EPISODES,
|
||||
false);
|
||||
} else if (key.equals(PREF_THEME)) {
|
||||
theme = readThemeValue(sp.getString(PREF_THEME, ""));
|
||||
} else if (key.equals(PREF_ENABLE_AUTODL_WIFI_FILTER)) {
|
||||
|
@ -316,7 +316,9 @@ public final class DBReader {
|
||||
cursor.getInt(PodDBAdapter.IDX_FEED_SEL_STD_DOWNLOADED) > 0,
|
||||
new FlattrStatus(cursor.getLong(PodDBAdapter.IDX_FEED_SEL_STD_FLATTR_STATUS)),
|
||||
cursor.getInt(PodDBAdapter.IDX_FEED_SEL_STD_IS_PAGED) > 0,
|
||||
cursor.getString(PodDBAdapter.IDX_FEED_SEL_STD_NEXT_PAGE_LINK));
|
||||
cursor.getString(PodDBAdapter.IDX_FEED_SEL_STD_NEXT_PAGE_LINK),
|
||||
cursor.getString(cursor.getColumnIndex(PodDBAdapter.KEY_HIDE))
|
||||
);
|
||||
|
||||
if (image != null) {
|
||||
image.setOwner(feed);
|
||||
|
@ -29,6 +29,7 @@ import de.danoeh.antennapod.core.ClientConfig;
|
||||
import de.danoeh.antennapod.core.asynctask.FlattrClickWorker;
|
||||
import de.danoeh.antennapod.core.feed.EventDistributor;
|
||||
import de.danoeh.antennapod.core.feed.Feed;
|
||||
import de.danoeh.antennapod.core.feed.FeedEvent;
|
||||
import de.danoeh.antennapod.core.feed.FeedImage;
|
||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||
import de.danoeh.antennapod.core.feed.FeedMedia;
|
||||
@ -1063,4 +1064,28 @@ public class DBWriter {
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Set filter of the feed
|
||||
*
|
||||
* @param context Used for opening a database connection.
|
||||
* @param feedId The feed's ID
|
||||
* @param filterValues Values that represent properties to filter by
|
||||
*/
|
||||
public static Future<?> setFeedItemsFilter(final Context context, final long feedId,
|
||||
final List<String> filterValues) {
|
||||
Log.d(TAG, "setFeedFilter");
|
||||
|
||||
return dbExec.submit(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
PodDBAdapter adapter = new PodDBAdapter(context);
|
||||
adapter.open();
|
||||
adapter.setFeedItemFilter(feedId, filterValues);
|
||||
adapter.close();
|
||||
EventBus.getDefault().post(new FeedEvent(FeedEvent.Action.FILTER_CHANGED, feedId));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ import android.database.sqlite.SQLiteDatabase.CursorFactory;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
import android.util.Log;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
|
||||
import java.util.Arrays;
|
||||
@ -149,6 +150,7 @@ public class PodDBAdapter {
|
||||
public static final String KEY_PASSWORD = "password";
|
||||
public static final String KEY_IS_PAGED = "is_paged";
|
||||
public static final String KEY_NEXT_PAGE_LINK = "next_page_link";
|
||||
public static final String KEY_HIDE = "hide";
|
||||
|
||||
// Table names
|
||||
public static final String TABLE_NAME_FEEDS = "Feeds";
|
||||
@ -175,7 +177,8 @@ public class PodDBAdapter {
|
||||
+ KEY_USERNAME + " TEXT,"
|
||||
+ KEY_PASSWORD + " TEXT,"
|
||||
+ KEY_IS_PAGED + " INTEGER DEFAULT 0,"
|
||||
+ KEY_NEXT_PAGE_LINK + " TEXT)";
|
||||
+ KEY_NEXT_PAGE_LINK + " TEXT,"
|
||||
+ KEY_HIDE + " TEXT)";
|
||||
|
||||
|
||||
public static final String CREATE_TABLE_FEED_ITEMS = "CREATE TABLE "
|
||||
@ -247,6 +250,7 @@ public class PodDBAdapter {
|
||||
TABLE_NAME_FEEDS + "." + KEY_NEXT_PAGE_LINK,
|
||||
TABLE_NAME_FEEDS + "." + KEY_USERNAME,
|
||||
TABLE_NAME_FEEDS + "." + KEY_PASSWORD,
|
||||
TABLE_NAME_FEEDS + "." + KEY_HIDE
|
||||
};
|
||||
|
||||
// column indices for FEED_SEL_STD
|
||||
@ -403,17 +407,15 @@ public class PodDBAdapter {
|
||||
values.put(KEY_FLATTR_STATUS, feed.getFlattrStatus().toLong());
|
||||
values.put(KEY_IS_PAGED, feed.isPaged());
|
||||
values.put(KEY_NEXT_PAGE_LINK, feed.getNextPageLink());
|
||||
values.put(KEY_HIDE, StringUtils.join(feed.getItemFilter(), ","));
|
||||
if (feed.getId() == 0) {
|
||||
// Create new entry
|
||||
if (BuildConfig.DEBUG)
|
||||
Log.d(this.toString(), "Inserting new Feed into db");
|
||||
Log.d(this.toString(), "Inserting new Feed into db");
|
||||
feed.setId(db.insert(TABLE_NAME_FEEDS, null, values));
|
||||
} else {
|
||||
if (BuildConfig.DEBUG)
|
||||
Log.d(this.toString(), "Updating existing Feed in db");
|
||||
Log.d(this.toString(), "Updating existing Feed in db");
|
||||
db.update(TABLE_NAME_FEEDS, values, KEY_ID + "=?",
|
||||
new String[]{String.valueOf(feed.getId())});
|
||||
|
||||
}
|
||||
return feed.getId();
|
||||
}
|
||||
@ -429,6 +431,13 @@ public class PodDBAdapter {
|
||||
db.update(TABLE_NAME_FEEDS, values, KEY_ID + "=?", new String[]{String.valueOf(prefs.getFeedID())});
|
||||
}
|
||||
|
||||
public void setFeedItemFilter(long feedId, List<String> filterValues) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(KEY_HIDE, StringUtils.join(filterValues, ","));
|
||||
Log.d(TAG, StringUtils.join(filterValues, ","));
|
||||
db.update(TABLE_NAME_FEEDS, values, KEY_ID + "=?", new String[]{String.valueOf(feedId)});
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts or updates an image entry
|
||||
*
|
||||
|
@ -1,11 +1,12 @@
|
||||
package de.danoeh.antennapod.core.util;
|
||||
|
||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||
|
||||
public class EpisodeFilter {
|
||||
|
||||
private EpisodeFilter() {
|
||||
|
||||
}
|
||||
|
BIN
core/src/main/res/drawable-hdpi/ic_filter_grey600_24dp.png
Normal file
After Width: | Height: | Size: 135 B |
BIN
core/src/main/res/drawable-hdpi/ic_filter_white_24dp.png
Normal file
After Width: | Height: | Size: 131 B |
BIN
core/src/main/res/drawable-mdpi/ic_filter_grey600_24dp.png
Normal file
After Width: | Height: | Size: 111 B |
BIN
core/src/main/res/drawable-mdpi/ic_filter_white_24dp.png
Normal file
After Width: | Height: | Size: 111 B |
BIN
core/src/main/res/drawable-xhdpi/ic_filter_grey600_24dp.png
Normal file
After Width: | Height: | Size: 141 B |
BIN
core/src/main/res/drawable-xhdpi/ic_filter_white_24dp.png
Normal file
After Width: | Height: | Size: 141 B |
BIN
core/src/main/res/drawable-xxhdpi/ic_filter_grey600_24dp.png
Normal file
After Width: | Height: | Size: 189 B |
BIN
core/src/main/res/drawable-xxhdpi/ic_filter_white_24dp.png
Normal file
After Width: | Height: | Size: 188 B |
BIN
core/src/main/res/drawable-xxxhdpi/ic_filter_grey600_24dp.png
Normal file
After Width: | Height: | Size: 235 B |
BIN
core/src/main/res/drawable-xxxhdpi/ic_filter_white_24dp.png
Normal file
After Width: | Height: | Size: 234 B |
@ -137,4 +137,24 @@
|
||||
<item>@string/add_feed_label</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="episode_hide_options">
|
||||
<item>@string/hide_unplayed_episodes_label</item>
|
||||
<item>@string/hide_paused_episodes_label</item>
|
||||
<item>@string/hide_played_episodes_label</item>
|
||||
<item>@string/hide_queued_episodes_label</item>
|
||||
<item>@string/hide_not_queued_episodes_label</item>
|
||||
<item>@string/hide_downloaded_episodes_label</item>
|
||||
<item>@string/hide_not_downloaded_episodes_label</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="episode_hide_values">
|
||||
<item>unplayed</item>
|
||||
<item>paused</item>
|
||||
<item>played</item>
|
||||
<item>queued</item>
|
||||
<item>not_queued</item>
|
||||
<item>downloaded</item>
|
||||
<item>not_downloaded</item>
|
||||
</string-array>
|
||||
|
||||
</resources>
|
||||
|
@ -39,6 +39,7 @@
|
||||
<attr name="ic_settings" format="reference"/>
|
||||
<attr name="ic_lock_open" format="reference"/>
|
||||
<attr name="ic_lock_closed" format="reference"/>
|
||||
<attr name="ic_filter" format="reference"/>
|
||||
|
||||
<!-- Used in itemdescription -->
|
||||
<attr name="non_transparent_background" format="reference"/>
|
||||
|
@ -91,6 +91,15 @@
|
||||
<string name="feed_delete_confirmation_msg">Please confirm that you want to delete this feed and ALL episodes of this feed that you have downloaded.</string>
|
||||
<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="hide_unplayed_episodes_label">Unplayed</string>
|
||||
<string name="hide_paused_episodes_label">Paused</string>
|
||||
<string name="hide_played_episodes_label">Played</string>
|
||||
<string name="hide_queued_episodes_label">Queued</string>
|
||||
<string name="hide_not_queued_episodes_label">Not queued</string>
|
||||
<string name="hide_downloaded_episodes_label">Downloaded</string>
|
||||
<string name="hide_not_downloaded_episodes_label">Not downloaded</string>
|
||||
<string name="filtered_label">Filtered</string>
|
||||
|
||||
<!-- actions on feeditems -->
|
||||
<string name="download_label">Download</string>
|
||||
|
@ -44,6 +44,7 @@
|
||||
<item name="attr/ic_settings">@drawable/ic_settings_grey600_24dp</item>
|
||||
<item name="attr/ic_lock_open">@drawable/ic_lock_open_grey600_24dp</item>
|
||||
<item name="attr/ic_lock_closed">@drawable/ic_lock_closed_grey600_24dp</item>
|
||||
<item name="attr/ic_filter">@drawable/ic_filter_grey600_24dp</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.AntennaPod.Dark" parent="@style/Theme.AppCompat">
|
||||
@ -88,6 +89,7 @@
|
||||
<item name="attr/ic_settings">@drawable/ic_settings_white_24dp</item>
|
||||
<item name="attr/ic_lock_open">@drawable/ic_lock_open_white_24dp</item>
|
||||
<item name="attr/ic_lock_closed">@drawable/ic_lock_closed_white_24dp</item>
|
||||
<item name="attr/ic_filter">@drawable/ic_filter_white_24dp</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.AntennaPod.Light.NoTitle" parent="@style/Theme.AppCompat.Light.NoActionBar">
|
||||
@ -135,6 +137,7 @@
|
||||
<item name="attr/ic_settings">@drawable/ic_settings_grey600_24dp</item>
|
||||
<item name="attr/ic_lock_open">@drawable/ic_lock_open_grey600_24dp</item>
|
||||
<item name="attr/ic_lock_closed">@drawable/ic_lock_closed_grey600_24dp</item>
|
||||
<item name="attr/ic_filter">@drawable/ic_filter_grey600_24dp</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.AntennaPod.Dark.NoTitle" parent="@style/Theme.AppCompat.NoActionBar">
|
||||
@ -181,6 +184,7 @@
|
||||
<item name="attr/ic_settings">@drawable/ic_settings_white_24dp</item>
|
||||
<item name="attr/ic_lock_open">@drawable/ic_lock_open_white_24dp</item>
|
||||
<item name="attr/ic_lock_closed">@drawable/ic_lock_closed_white_24dp</item>
|
||||
<item name="attr/ic_filter">@drawable/ic_filter_white_24dp</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.AntennaPod.VideoPlayer" parent="@style/Theme.AntennaPod.Dark">
|
||||
|