Merge pull request #3528 from orionlee/podcast_screen_sort_2524
Sort Support in Podcast screen
|
@ -44,8 +44,8 @@ class DBTestUtils {
|
|||
PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
for (int i = 0; i < numFeeds; i++) {
|
||||
Feed f = new Feed(0, null, "feed " + i, null, "link" + i, "descr", null, null,
|
||||
null, null, "id" + i, null, null, "url" + i, false, false, null, null, false);
|
||||
Feed f = new Feed(0, null, "feed " + i, "link" + i, "descr", null, null,
|
||||
null, null, "id" + i, null, null, "url" + i, false);
|
||||
f.setItems(new ArrayList<>());
|
||||
for (int j = 0; j < numItems; j++) {
|
||||
FeedItem item = new FeedItem(0, "item " + j, "id" + j, "link" + j, new Date(),
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
package de.danoeh.antennapod.dialog;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.core.util.SortOrder;
|
||||
|
||||
public abstract class IntraFeedSortDialog {
|
||||
|
||||
@Nullable
|
||||
protected SortOrder currentSortOrder;
|
||||
@NonNull
|
||||
protected Context context;
|
||||
|
||||
public IntraFeedSortDialog(@NonNull Context context, @Nullable SortOrder sortOrder) {
|
||||
this.context = context;
|
||||
this.currentSortOrder = sortOrder;
|
||||
}
|
||||
|
||||
public void openDialog() {
|
||||
final String[] items = context.getResources().getStringArray(R.array.feed_episodes_sort_options);
|
||||
final String[] valueStrs = context.getResources().getStringArray(R.array.feed_episodes_sort_values);
|
||||
final SortOrder[] values = new SortOrder[valueStrs.length];
|
||||
for (int i = 0; i < valueStrs.length; i++) {
|
||||
values[i] = SortOrder.valueOf(valueStrs[i]);
|
||||
}
|
||||
|
||||
int idxCurrentSort = -1;
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
if (currentSortOrder == values[i]) {
|
||||
idxCurrentSort = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
||||
builder.setTitle(R.string.sort);
|
||||
builder.setSingleChoiceItems(items, idxCurrentSort, (dialog, idxNewSort) -> {
|
||||
updateSort(values[idxNewSort]);
|
||||
dialog.dismiss();
|
||||
});
|
||||
builder.setNegativeButton(R.string.cancel_label, null);
|
||||
builder.create().show();
|
||||
}
|
||||
|
||||
protected abstract void updateSort(@NonNull SortOrder sortOrder);
|
||||
}
|
|
@ -5,10 +5,6 @@ import android.content.Context;
|
|||
import android.content.DialogInterface;
|
||||
import android.graphics.LightingColorFilter;
|
||||
import android.os.Bundle;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.ListFragment;
|
||||
import androidx.core.view.MenuItemCompat;
|
||||
import androidx.appcompat.widget.SearchView;
|
||||
import android.util.Log;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.LayoutInflater;
|
||||
|
@ -23,12 +19,16 @@ import android.widget.ListView;
|
|||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.widget.SearchView;
|
||||
import androidx.core.view.MenuItemCompat;
|
||||
import androidx.fragment.app.ListFragment;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import com.joanzapata.iconify.Iconify;
|
||||
import com.joanzapata.iconify.widget.IconTextView;
|
||||
|
||||
import de.danoeh.antennapod.core.event.PlaybackPositionEvent;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
|
@ -45,6 +45,7 @@ import de.danoeh.antennapod.core.dialog.DownloadRequestErrorDialogCreator;
|
|||
import de.danoeh.antennapod.core.event.DownloadEvent;
|
||||
import de.danoeh.antennapod.core.event.DownloaderUpdate;
|
||||
import de.danoeh.antennapod.core.event.FeedItemEvent;
|
||||
import de.danoeh.antennapod.core.event.PlaybackPositionEvent;
|
||||
import de.danoeh.antennapod.core.feed.EventDistributor;
|
||||
import de.danoeh.antennapod.core.feed.Feed;
|
||||
import de.danoeh.antennapod.core.feed.FeedEvent;
|
||||
|
@ -59,6 +60,7 @@ import de.danoeh.antennapod.core.storage.DBReader;
|
|||
import de.danoeh.antennapod.core.storage.DBTasks;
|
||||
import de.danoeh.antennapod.core.storage.DownloadRequestException;
|
||||
import de.danoeh.antennapod.core.storage.DownloadRequester;
|
||||
import de.danoeh.antennapod.core.util.FeedItemPermutors;
|
||||
import de.danoeh.antennapod.core.util.FeedItemUtil;
|
||||
import de.danoeh.antennapod.core.util.LongList;
|
||||
import de.danoeh.antennapod.core.util.Optional;
|
||||
|
@ -192,6 +194,7 @@ public class FeedItemlistFragment extends ListFragment {
|
|||
searchItem.setOnActionExpandListener(new MenuItem.OnActionExpandListener() {
|
||||
@Override
|
||||
public boolean onMenuItemActionExpand(MenuItem item) {
|
||||
menu.findItem(R.id.sort_items).setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
|
||||
menu.findItem(R.id.filter_items).setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
|
||||
menu.findItem(R.id.episode_actions).setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
|
||||
menu.findItem(R.id.refresh_item).setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
|
||||
|
@ -629,6 +632,11 @@ public class FeedItemlistFragment extends ListFragment {
|
|||
FeedItemFilter filter = feed.getItemFilter();
|
||||
feed.setItems(filter.filter(feed.getItems()));
|
||||
}
|
||||
if (feed != null && feed.getSortOrder() != null) {
|
||||
List<FeedItem> feedItems = feed.getItems();
|
||||
FeedItemPermutors.getPermutor(feed.getSortOrder()).reorder(feedItems);
|
||||
feed.setItems(feedItems);
|
||||
}
|
||||
return Optional.ofNullable(feed);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,15 +4,6 @@ import android.content.Context;
|
|||
import android.content.DialogInterface;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.core.view.MenuItemCompat;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.appcompat.widget.SearchView;
|
||||
import androidx.recyclerview.widget.SimpleItemAnimator;
|
||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
|
@ -24,9 +15,18 @@ import android.widget.CheckBox;
|
|||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.widget.SearchView;
|
||||
import androidx.core.view.MenuItemCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.recyclerview.widget.SimpleItemAnimator;
|
||||
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
import com.yqritc.recyclerviewflexibledivider.HorizontalDividerItemDecoration;
|
||||
|
||||
import de.danoeh.antennapod.core.event.PlaybackPositionEvent;
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
import org.greenrobot.eventbus.ThreadMode;
|
||||
|
@ -40,6 +40,7 @@ import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
|
|||
import de.danoeh.antennapod.core.event.DownloadEvent;
|
||||
import de.danoeh.antennapod.core.event.DownloaderUpdate;
|
||||
import de.danoeh.antennapod.core.event.FeedItemEvent;
|
||||
import de.danoeh.antennapod.core.event.PlaybackPositionEvent;
|
||||
import de.danoeh.antennapod.core.event.QueueEvent;
|
||||
import de.danoeh.antennapod.core.feed.EventDistributor;
|
||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||
|
@ -54,7 +55,6 @@ import de.danoeh.antennapod.core.storage.DownloadRequester;
|
|||
import de.danoeh.antennapod.core.util.Converter;
|
||||
import de.danoeh.antennapod.core.util.FeedItemUtil;
|
||||
import de.danoeh.antennapod.core.util.LongList;
|
||||
import de.danoeh.antennapod.core.util.QueueSorter;
|
||||
import de.danoeh.antennapod.core.util.SortOrder;
|
||||
import de.danoeh.antennapod.core.util.download.AutoUpdateManager;
|
||||
import de.danoeh.antennapod.dialog.EpisodesApplyActionFragment;
|
||||
|
@ -372,7 +372,7 @@ public class QueueFragment extends Fragment {
|
|||
UserPreferences.setQueueKeepSorted(keepSortedNew);
|
||||
if (keepSortedNew) {
|
||||
SortOrder sortOrder = UserPreferences.getQueueKeepSortedOrder();
|
||||
QueueSorter.sort(sortOrder, true);
|
||||
DBWriter.reorderQueue(sortOrder, true);
|
||||
if (recyclerAdapter != null) {
|
||||
recyclerAdapter.setLocked(true);
|
||||
}
|
||||
|
@ -438,7 +438,7 @@ public class QueueFragment extends Fragment {
|
|||
*/
|
||||
private void setSortOrder(SortOrder sortOrder) {
|
||||
UserPreferences.setQueueKeepSortedOrder(sortOrder);
|
||||
QueueSorter.sort(sortOrder, true);
|
||||
DBWriter.reorderQueue(sortOrder, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -7,6 +7,8 @@ import android.view.Menu;
|
|||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.Set;
|
||||
|
@ -19,7 +21,9 @@ import de.danoeh.antennapod.core.storage.DBWriter;
|
|||
import de.danoeh.antennapod.core.storage.DownloadRequestException;
|
||||
import de.danoeh.antennapod.core.util.IntentUtils;
|
||||
import de.danoeh.antennapod.core.util.ShareUtils;
|
||||
import de.danoeh.antennapod.core.util.SortOrder;
|
||||
import de.danoeh.antennapod.dialog.FilterDialog;
|
||||
import de.danoeh.antennapod.dialog.IntraFeedSortDialog;
|
||||
|
||||
/**
|
||||
* Handles interactions with the FeedItemMenu.
|
||||
|
@ -65,6 +69,9 @@ public class FeedMenuHandler {
|
|||
case R.id.refresh_complete_item:
|
||||
DBTasks.forceRefreshCompleteFeed(context, selectedFeed);
|
||||
break;
|
||||
case R.id.sort_items:
|
||||
showSortDialog(context, selectedFeed);
|
||||
break;
|
||||
case R.id.filter_items:
|
||||
showFilterDialog(context, selectedFeed);
|
||||
break;
|
||||
|
@ -108,4 +115,17 @@ public class FeedMenuHandler {
|
|||
|
||||
filterDialog.openDialog();
|
||||
}
|
||||
|
||||
|
||||
private static void showSortDialog(Context context, Feed selectedFeed) {
|
||||
IntraFeedSortDialog sortDialog = new IntraFeedSortDialog(context, selectedFeed.getSortOrder()) {
|
||||
@Override
|
||||
protected void updateSort(@NonNull SortOrder sortOrder) {
|
||||
selectedFeed.setSortOrder(sortOrder);
|
||||
DBWriter.setFeedItemSortOrder(selectedFeed.getId(), sortOrder);
|
||||
}
|
||||
};
|
||||
sortDialog.openDialog();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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/sort_items"
|
||||
android:icon="?attr/ic_sort"
|
||||
android:menuCategory="container"
|
||||
android:title="@string/sort"
|
||||
custom:showAsAction="always">
|
||||
</item>
|
||||
<item
|
||||
android:id="@+id/filter_items"
|
||||
android:icon="?attr/ic_filter"
|
||||
|
@ -9,13 +16,6 @@
|
|||
android:title="@string/filter"
|
||||
custom:showAsAction="always">
|
||||
</item>
|
||||
<item
|
||||
android:id="@+id/episode_actions"
|
||||
android:menuCategory="container"
|
||||
android:icon="?attr/checkbox_multiple"
|
||||
android:title="@string/batch_edit"
|
||||
custom:showAsAction="always">
|
||||
</item>
|
||||
<item
|
||||
android:id="@+id/refresh_item"
|
||||
android:icon="?attr/navigation_refresh"
|
||||
|
@ -37,6 +37,13 @@
|
|||
custom:actionViewClass="androidx.appcompat.widget.SearchView"
|
||||
android:title="@string/search_label"/>
|
||||
|
||||
<item
|
||||
android:id="@+id/episode_actions"
|
||||
android:menuCategory="container"
|
||||
android:icon="?attr/checkbox_multiple"
|
||||
android:title="@string/batch_edit"
|
||||
custom:showAsAction="collapseActionView">
|
||||
</item>
|
||||
<item
|
||||
android:id="@+id/visit_website_item"
|
||||
android:icon="?attr/location_web_site"
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
package de.danoeh.antennapod.core.feed;
|
||||
|
||||
import android.database.Cursor;
|
||||
import androidx.annotation.Nullable;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
@ -11,6 +12,8 @@ import java.util.List;
|
|||
import de.danoeh.antennapod.core.asynctask.ImageResource;
|
||||
import de.danoeh.antennapod.core.storage.DBWriter;
|
||||
import de.danoeh.antennapod.core.storage.PodDBAdapter;
|
||||
import de.danoeh.antennapod.core.util.SortOrder;
|
||||
|
||||
/**
|
||||
* Data Object for a whole feed
|
||||
*
|
||||
|
@ -88,13 +91,20 @@ public class Feed extends FeedFile implements ImageResource {
|
|||
*/
|
||||
private FeedItemFilter itemfilter;
|
||||
|
||||
/**
|
||||
* User-preferred sortOrder for display.
|
||||
* Only those of scope {@link SortOrder.Scope#INTRA_FEED} is allowed.
|
||||
*/
|
||||
@Nullable
|
||||
private SortOrder sortOrder;
|
||||
|
||||
/**
|
||||
* This constructor is used for restoring a feed from the database.
|
||||
*/
|
||||
public Feed(long id, String lastUpdate, String title, String customTitle, String link, String description, String paymentLink,
|
||||
String author, String language, String type, String feedIdentifier, String imageUrl, String fileUrl,
|
||||
String downloadUrl, boolean downloaded, boolean paged, String nextPageLink,
|
||||
String filter, boolean lastUpdateFailed) {
|
||||
String filter, @Nullable SortOrder sortOrder, boolean lastUpdateFailed) {
|
||||
super(fileUrl, downloadUrl, downloaded);
|
||||
this.id = id;
|
||||
this.feedTitle = title;
|
||||
|
@ -116,6 +126,7 @@ public class Feed extends FeedFile implements ImageResource {
|
|||
} else {
|
||||
this.itemfilter = new FeedItemFilter(new String[0]);
|
||||
}
|
||||
setSortOrder(sortOrder);
|
||||
this.lastUpdateFailed = lastUpdateFailed;
|
||||
}
|
||||
|
||||
|
@ -126,7 +137,7 @@ public class Feed extends FeedFile implements ImageResource {
|
|||
String author, String language, String type, String feedIdentifier, String imageUrl, String fileUrl,
|
||||
String downloadUrl, boolean downloaded) {
|
||||
this(id, lastUpdate, title, null, link, description, paymentLink, author, language, type, feedIdentifier, imageUrl,
|
||||
fileUrl, downloadUrl, downloaded, false, null, null, false);
|
||||
fileUrl, downloadUrl, downloaded, false, null, null, null, false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -181,6 +192,7 @@ public class Feed extends FeedFile implements ImageResource {
|
|||
int indexIsPaged = cursor.getColumnIndex(PodDBAdapter.KEY_IS_PAGED);
|
||||
int indexNextPageLink = cursor.getColumnIndex(PodDBAdapter.KEY_NEXT_PAGE_LINK);
|
||||
int indexHide = cursor.getColumnIndex(PodDBAdapter.KEY_HIDE);
|
||||
int indexSortOrder = cursor.getColumnIndex(PodDBAdapter.KEY_SORT_ORDER);
|
||||
int indexLastUpdateFailed = cursor.getColumnIndex(PodDBAdapter.KEY_LAST_UPDATE_FAILED);
|
||||
int indexImageUrl = cursor.getColumnIndex(PodDBAdapter.KEY_IMAGE_URL);
|
||||
|
||||
|
@ -203,6 +215,7 @@ public class Feed extends FeedFile implements ImageResource {
|
|||
cursor.getInt(indexIsPaged) > 0,
|
||||
cursor.getString(indexNextPageLink),
|
||||
cursor.getString(indexHide),
|
||||
SortOrder.fromCodeString(cursor.getString(indexSortOrder)),
|
||||
cursor.getInt(indexLastUpdateFailed) > 0
|
||||
);
|
||||
|
||||
|
@ -523,6 +536,19 @@ public class Feed extends FeedFile implements ImageResource {
|
|||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public SortOrder getSortOrder() {
|
||||
return sortOrder;
|
||||
}
|
||||
|
||||
public void setSortOrder(@Nullable SortOrder sortOrder) {
|
||||
if (sortOrder != null && sortOrder.scope != SortOrder.Scope.INTRA_FEED) {
|
||||
throw new IllegalArgumentException("The specified sortOrder " + sortOrder
|
||||
+ " is invalid. Only those with INTRA_FEED scope are allowed.");
|
||||
}
|
||||
this.sortOrder = sortOrder;
|
||||
}
|
||||
|
||||
public boolean hasLastUpdateFailed() {
|
||||
return this.lastUpdateFailed;
|
||||
}
|
||||
|
|
|
@ -6,7 +6,8 @@ import org.apache.commons.lang3.builder.ToStringStyle;
|
|||
public class FeedEvent {
|
||||
|
||||
public enum Action {
|
||||
FILTER_CHANGED
|
||||
FILTER_CHANGED,
|
||||
SORT_ORDER_CHANGED
|
||||
}
|
||||
|
||||
private final Action action;
|
||||
|
|
|
@ -294,6 +294,11 @@ class DBUpgrader {
|
|||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
|
||||
+ " ADD COLUMN " + PodDBAdapter.KEY_FEED_PLAYBACK_SPEED + " REAL DEFAULT " + SPEED_USE_GLOBAL);
|
||||
}
|
||||
|
||||
if (oldVersion < 1070401) {
|
||||
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
|
||||
+ " ADD COLUMN " + PodDBAdapter.KEY_SORT_ORDER + " TEXT");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import android.content.Context;
|
|||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import de.danoeh.antennapod.core.event.DownloadLogEvent;
|
||||
import de.danoeh.antennapod.core.event.PlaybackHistoryEvent;
|
||||
|
@ -38,10 +39,10 @@ import de.danoeh.antennapod.core.preferences.PlaybackPreferences;
|
|||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.service.download.DownloadStatus;
|
||||
import de.danoeh.antennapod.core.service.playback.PlaybackService;
|
||||
import de.danoeh.antennapod.core.util.FeedItemPermutors;
|
||||
import de.danoeh.antennapod.core.util.IntentUtils;
|
||||
import de.danoeh.antennapod.core.util.LongList;
|
||||
import de.danoeh.antennapod.core.util.Permutor;
|
||||
import de.danoeh.antennapod.core.util.QueueSorter;
|
||||
import de.danoeh.antennapod.core.util.SortOrder;
|
||||
|
||||
/**
|
||||
|
@ -387,7 +388,7 @@ public class DBWriter {
|
|||
// do not shuffle the list on every change
|
||||
return;
|
||||
}
|
||||
Permutor<FeedItem> permutor = QueueSorter.getPermutor(sortOrder);
|
||||
Permutor<FeedItem> permutor = FeedItemPermutors.getPermutor(sortOrder);
|
||||
permutor.reorder(queue);
|
||||
|
||||
// Replace ADDED events by a single SORTED event
|
||||
|
@ -847,14 +848,18 @@ public class DBWriter {
|
|||
}
|
||||
|
||||
/**
|
||||
* Sort the FeedItems in the queue with the given Permutor.
|
||||
* Sort the FeedItems in the queue with the given the named sort order.
|
||||
*
|
||||
* @param permutor Encapsulates whole-Queue reordering logic.
|
||||
* @param broadcastUpdate <code>true</code> if this operation should trigger a
|
||||
* QueueUpdateBroadcast. This option should be set to <code>false</code>
|
||||
* if the caller wants to avoid unexpected updates of the GUI.
|
||||
*/
|
||||
public static Future<?> reorderQueue(final Permutor<FeedItem> permutor, final boolean broadcastUpdate) {
|
||||
public static Future<?> reorderQueue(@Nullable SortOrder sortOrder, final boolean broadcastUpdate) {
|
||||
if (sortOrder == null) {
|
||||
Log.w(TAG, "reorderQueue() - sortOrder is null. Do nothing.");
|
||||
return dbExec.submit(() -> { });
|
||||
}
|
||||
final Permutor<FeedItem> permutor = FeedItemPermutors.getPermutor(sortOrder);
|
||||
return dbExec.submit(() -> {
|
||||
final PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
|
@ -946,6 +951,19 @@ public class DBWriter {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Set item sort order of the feed
|
||||
*
|
||||
*/
|
||||
public static Future<?> setFeedItemSortOrder(long feedId, @Nullable SortOrder sortOrder) {
|
||||
return dbExec.submit(() -> {
|
||||
PodDBAdapter adapter = PodDBAdapter.getInstance();
|
||||
adapter.open();
|
||||
adapter.setFeedItemSortOrder(feedId, sortOrder);
|
||||
adapter.close();
|
||||
EventBus.getDefault().post(new FeedEvent(FeedEvent.Action.SORT_ORDER_CHANGED, feedId));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the statistics in DB
|
||||
|
|
|
@ -13,11 +13,11 @@ import android.database.sqlite.SQLiteDatabase;
|
|||
import android.database.sqlite.SQLiteDatabase.CursorFactory;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
import android.os.Build;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
|
||||
import java.io.File;
|
||||
|
@ -35,8 +35,10 @@ import de.danoeh.antennapod.core.feed.FeedPreferences;
|
|||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.service.download.DownloadStatus;
|
||||
import de.danoeh.antennapod.core.util.LongIntMap;
|
||||
import de.danoeh.antennapod.core.util.SortOrder;
|
||||
|
||||
import static de.danoeh.antennapod.core.feed.FeedPreferences.SPEED_USE_GLOBAL;
|
||||
import static de.danoeh.antennapod.core.util.SortOrder.toCodeString;
|
||||
|
||||
// TODO Remove media column from feeditem table
|
||||
|
||||
|
@ -101,6 +103,7 @@ public class PodDBAdapter {
|
|||
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";
|
||||
public static final String KEY_SORT_ORDER = "sort_order";
|
||||
public static final String KEY_LAST_UPDATE_FAILED = "last_update_failed";
|
||||
public static final String KEY_HAS_EMBEDDED_PICTURE = "has_embedded_picture";
|
||||
public static final String KEY_LAST_PLAYED_TIME = "last_played_time";
|
||||
|
@ -138,6 +141,7 @@ public class PodDBAdapter {
|
|||
+ KEY_IS_PAGED + " INTEGER DEFAULT 0,"
|
||||
+ KEY_NEXT_PAGE_LINK + " TEXT,"
|
||||
+ KEY_HIDE + " TEXT,"
|
||||
+ KEY_SORT_ORDER + " TEXT,"
|
||||
+ KEY_LAST_UPDATE_FAILED + " INTEGER DEFAULT 0,"
|
||||
+ KEY_AUTO_DELETE_ACTION + " INTEGER DEFAULT 0,"
|
||||
+ KEY_FEED_PLAYBACK_SPEED + " REAL DEFAULT " + SPEED_USE_GLOBAL + ")";
|
||||
|
@ -234,6 +238,7 @@ public class PodDBAdapter {
|
|||
TABLE_NAME_FEEDS + "." + KEY_USERNAME,
|
||||
TABLE_NAME_FEEDS + "." + KEY_PASSWORD,
|
||||
TABLE_NAME_FEEDS + "." + KEY_HIDE,
|
||||
TABLE_NAME_FEEDS + "." + KEY_SORT_ORDER,
|
||||
TABLE_NAME_FEEDS + "." + KEY_LAST_UPDATE_FAILED,
|
||||
TABLE_NAME_FEEDS + "." + KEY_AUTO_DELETE_ACTION,
|
||||
TABLE_NAME_FEEDS + "." + KEY_INCLUDE_FILTER,
|
||||
|
@ -378,6 +383,7 @@ public class PodDBAdapter {
|
|||
} else {
|
||||
values.put(KEY_HIDE, "");
|
||||
}
|
||||
values.put(KEY_SORT_ORDER, toCodeString(feed.getSortOrder()));
|
||||
values.put(KEY_LAST_UPDATE_FAILED, feed.hasLastUpdateFailed());
|
||||
if (feed.getId() == 0) {
|
||||
// Create new entry
|
||||
|
@ -416,6 +422,12 @@ public class PodDBAdapter {
|
|||
db.update(TABLE_NAME_FEEDS, values, KEY_ID + "=?", new String[]{String.valueOf(feedId)});
|
||||
}
|
||||
|
||||
public void setFeedItemSortOrder(long feedId, @Nullable SortOrder sortOrder) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(KEY_SORT_ORDER, toCodeString(sortOrder));
|
||||
db.update(TABLE_NAME_FEEDS, values, KEY_ID + "=?", new String[]{String.valueOf(feedId)});
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts or updates a media entry
|
||||
*
|
||||
|
@ -1455,7 +1467,7 @@ public class PodDBAdapter {
|
|||
*/
|
||||
private static class PodDBHelper extends SQLiteOpenHelper {
|
||||
|
||||
private static final int VERSION = 1070400;
|
||||
private static final int VERSION = 1070401;
|
||||
|
||||
private final Context context;
|
||||
|
||||
|
|
|
@ -1,89 +1,58 @@
|
|||
package de.danoeh.antennapod.core.util;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||
import de.danoeh.antennapod.core.feed.FeedMedia;
|
||||
import de.danoeh.antennapod.core.storage.DBWriter;
|
||||
|
||||
/**
|
||||
* Provides method for sorting the queue according to rules.
|
||||
* Provides method for sorting the a list of {@link FeedItem} according to rules.
|
||||
*/
|
||||
public class QueueSorter {
|
||||
|
||||
/**
|
||||
* Sorts the queue by the given sort order and sends a broadcast update.
|
||||
*
|
||||
* @param sortOrder Sort order.
|
||||
* @param broadcastUpdate Send broadcast update?
|
||||
*/
|
||||
public static void sort(SortOrder sortOrder, boolean broadcastUpdate) {
|
||||
Permutor<FeedItem> permutor = getPermutor(sortOrder);
|
||||
if (permutor != null) {
|
||||
DBWriter.reorderQueue(permutor, broadcastUpdate);
|
||||
}
|
||||
}
|
||||
public class FeedItemPermutors {
|
||||
|
||||
/**
|
||||
* Returns a Permutor that sorts a list appropriate to the given sort order.
|
||||
*
|
||||
* @param sortOrder Sort order.
|
||||
* @return Permutor that sorts a list appropriate to the given sort order. <code>null</code> if the order is unknown or <code>null</code>.
|
||||
* @return Permutor that sorts a list appropriate to the given sort order.
|
||||
*/
|
||||
public static Permutor<FeedItem> getPermutor(SortOrder sortOrder) {
|
||||
if (sortOrder == null) {
|
||||
return null;
|
||||
}
|
||||
@NonNull
|
||||
public static Permutor<FeedItem> getPermutor(@NonNull SortOrder sortOrder) {
|
||||
|
||||
Comparator<FeedItem> comparator = null;
|
||||
Permutor<FeedItem> permutor = null;
|
||||
|
||||
switch (sortOrder) {
|
||||
case EPISODE_TITLE_A_Z:
|
||||
comparator = (f1, f2) -> f1.getTitle().compareTo(f2.getTitle());
|
||||
comparator = (f1, f2) -> itemTitle(f1).compareTo(itemTitle(f2));
|
||||
break;
|
||||
case EPISODE_TITLE_Z_A:
|
||||
comparator = (f1, f2) -> f2.getTitle().compareTo(f1.getTitle());
|
||||
comparator = (f1, f2) -> itemTitle(f2).compareTo(itemTitle(f1));
|
||||
break;
|
||||
case DATE_OLD_NEW:
|
||||
comparator = (f1, f2) -> f1.getPubDate().compareTo(f2.getPubDate());
|
||||
comparator = (f1, f2) -> pubDate(f1).compareTo(pubDate(f2));
|
||||
break;
|
||||
case DATE_NEW_OLD:
|
||||
comparator = (f1, f2) -> f2.getPubDate().compareTo(f1.getPubDate());
|
||||
comparator = (f1, f2) -> pubDate(f2).compareTo(pubDate(f1));
|
||||
break;
|
||||
case DURATION_SHORT_LONG:
|
||||
comparator = (f1, f2) -> {
|
||||
FeedMedia f1Media = f1.getMedia();
|
||||
FeedMedia f2Media = f2.getMedia();
|
||||
int duration1 = f1Media != null ? f1Media.getDuration() : -1;
|
||||
int duration2 = f2Media != null ? f2Media.getDuration() : -1;
|
||||
|
||||
if (duration1 == -1 || duration2 == -1)
|
||||
return duration2 - duration1;
|
||||
else
|
||||
return duration1 - duration2;
|
||||
};
|
||||
comparator = (f1, f2) -> Integer.compare(duration(f1), duration(f2));
|
||||
break;
|
||||
case DURATION_LONG_SHORT:
|
||||
comparator = (f1, f2) -> {
|
||||
FeedMedia f1Media = f1.getMedia();
|
||||
FeedMedia f2Media = f2.getMedia();
|
||||
int duration1 = f1Media != null ? f1Media.getDuration() : -1;
|
||||
int duration2 = f2Media != null ? f2Media.getDuration() : -1;
|
||||
|
||||
return -1 * (duration1 - duration2);
|
||||
};
|
||||
comparator = (f1, f2) -> Integer.compare(duration(f2), duration(f1));
|
||||
break;
|
||||
case FEED_TITLE_A_Z:
|
||||
comparator = (f1, f2) -> f1.getFeed().getTitle().compareTo(f2.getFeed().getTitle());
|
||||
comparator = (f1, f2) -> feedTitle(f1).compareTo(feedTitle(f2));
|
||||
break;
|
||||
case FEED_TITLE_Z_A:
|
||||
comparator = (f1, f2) -> f2.getFeed().getTitle().compareTo(f1.getFeed().getTitle());
|
||||
comparator = (f1, f2) -> feedTitle(f2).compareTo(feedTitle(f1));
|
||||
break;
|
||||
case RANDOM:
|
||||
permutor = Collections::shuffle;
|
||||
|
@ -103,6 +72,31 @@ public class QueueSorter {
|
|||
return permutor;
|
||||
}
|
||||
|
||||
// Null-safe accessors
|
||||
|
||||
@NonNull
|
||||
private static Date pubDate(@Nullable FeedItem item) {
|
||||
return (item != null && item.getPubDate() != null) ?
|
||||
item.getPubDate() : new Date(0);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static String itemTitle(@Nullable FeedItem item) {
|
||||
return (item != null && item.getTitle() != null) ?
|
||||
item.getTitle() : "";
|
||||
}
|
||||
|
||||
private static int duration(@Nullable FeedItem item) {
|
||||
return (item != null && item.getMedia() != null) ?
|
||||
item.getMedia().getDuration() : 0;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static String feedTitle(@Nullable FeedItem item) {
|
||||
return (item != null && item.getFeed() != null && item.getFeed().getTitle() != null) ?
|
||||
item.getFeed().getTitle() : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements a reordering by pubdate that avoids consecutive episodes from the same feed in
|
||||
* the queue.
|
|
@ -1,20 +1,42 @@
|
|||
package de.danoeh.antennapod.core.util;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import static de.danoeh.antennapod.core.util.SortOrder.Scope.INTER_FEED;
|
||||
import static de.danoeh.antennapod.core.util.SortOrder.Scope.INTRA_FEED;
|
||||
|
||||
/**
|
||||
* Provides sort orders to sort a list of episodes.
|
||||
*/
|
||||
public enum SortOrder {
|
||||
EPISODE_TITLE_A_Z,
|
||||
EPISODE_TITLE_Z_A,
|
||||
DATE_OLD_NEW,
|
||||
DATE_NEW_OLD,
|
||||
DURATION_SHORT_LONG,
|
||||
DURATION_LONG_SHORT,
|
||||
FEED_TITLE_A_Z,
|
||||
FEED_TITLE_Z_A,
|
||||
RANDOM,
|
||||
SMART_SHUFFLE_OLD_NEW,
|
||||
SMART_SHUFFLE_NEW_OLD;
|
||||
DATE_OLD_NEW(1, INTRA_FEED),
|
||||
DATE_NEW_OLD(2, INTRA_FEED),
|
||||
EPISODE_TITLE_A_Z(3, INTRA_FEED),
|
||||
EPISODE_TITLE_Z_A(4, INTRA_FEED),
|
||||
DURATION_SHORT_LONG(5, INTRA_FEED),
|
||||
DURATION_LONG_SHORT(6, INTRA_FEED),
|
||||
FEED_TITLE_A_Z(101, INTER_FEED),
|
||||
FEED_TITLE_Z_A(102, INTER_FEED),
|
||||
RANDOM(103, INTER_FEED),
|
||||
SMART_SHUFFLE_OLD_NEW(104, INTER_FEED),
|
||||
SMART_SHUFFLE_NEW_OLD(105, INTER_FEED);
|
||||
|
||||
public enum Scope {
|
||||
INTRA_FEED, INTER_FEED;
|
||||
}
|
||||
|
||||
public final int code;
|
||||
|
||||
@NonNull
|
||||
public final Scope scope;
|
||||
|
||||
SortOrder(int code, @NonNull Scope scope) {
|
||||
this.code = code;
|
||||
this.scope = scope;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the string representation to its enum value. If the string value is unknown,
|
||||
|
@ -27,4 +49,23 @@ public enum SortOrder {
|
|||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static SortOrder fromCodeString(@Nullable String codeStr) {
|
||||
if (TextUtils.isEmpty(codeStr)) {
|
||||
return null;
|
||||
}
|
||||
int code = Integer.parseInt(codeStr);
|
||||
for (SortOrder sortOrder : values()) {
|
||||
if (sortOrder.code == code) {
|
||||
return sortOrder;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Unsupported code: " + code);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static String toCodeString(@Nullable SortOrder sortOrder) {
|
||||
return sortOrder != null ? Integer.toString(sortOrder.code) : null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ import de.danoeh.antennapod.core.feed.FeedItem;
|
|||
/** Compares the pubDate of two FeedItems for sorting*/
|
||||
public class FeedItemPubdateComparator implements Comparator<FeedItem> {
|
||||
|
||||
/** Returns a new instance of this comparator in reverse order.
|
||||
/** Returns a new instance of this comparator in reverse order.
|
||||
public static FeedItemPubdateComparator newInstance() {
|
||||
FeedItemPubdateComparator
|
||||
}*/
|
||||
|
|
Before Width: | Height: | Size: 111 B |
Before Width: | Height: | Size: 110 B |
Before Width: | Height: | Size: 91 B |
Before Width: | Height: | Size: 90 B |
Before Width: | Height: | Size: 106 B |
Before Width: | Height: | Size: 103 B |
Before Width: | Height: | Size: 114 B |
Before Width: | Height: | Size: 107 B |
Before Width: | Height: | Size: 123 B |
Before Width: | Height: | Size: 106 B |
|
@ -0,0 +1,7 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:width="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path android:fillColor="#FF757575" android:pathData="M15,19.88C15.04,20.18 14.94,20.5 14.71,20.71C14.32,21.1 13.69,21.1 13.3,20.71L9.29,16.7C9.06,16.47 8.96,16.16 9,15.87V10.75L4.21,4.62C3.87,4.19 3.95,3.56 4.38,3.22C4.57,3.08 4.78,3 5,3V3H19V3C19.22,3 19.43,3.08 19.62,3.22C20.05,3.56 20.13,4.19 19.79,4.62L15,10.75V19.88M7.04,5L11,10.06V15.58L13,17.58V10.05L16.96,5H7.04Z" />
|
||||
</vector>
|
|
@ -0,0 +1,7 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:width="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path android:fillColor="#FFFFFFFF" android:pathData="M15,19.88C15.04,20.18 14.94,20.5 14.71,20.71C14.32,21.1 13.69,21.1 13.3,20.71L9.29,16.7C9.06,16.47 8.96,16.16 9,15.87V10.75L4.21,4.62C3.87,4.19 3.95,3.56 4.38,3.22C4.57,3.08 4.78,3 5,3V3H19V3C19.22,3 19.43,3.08 19.62,3.22C20.05,3.56 20.13,4.19 19.79,4.62L15,10.75V19.88M7.04,5L11,10.06V15.58L13,17.58V10.05L16.96,5H7.04Z" />
|
||||
</vector>
|
|
@ -254,6 +254,25 @@
|
|||
<item>is_favorite</item>
|
||||
</string-array>
|
||||
|
||||
<!-- sort for podcast screen, not for queue -->
|
||||
<string-array name="feed_episodes_sort_options">
|
||||
<item>@string/sort_date_new_old</item>
|
||||
<item>@string/sort_date_old_new</item>
|
||||
<item>@string/sort_title_a_z</item>
|
||||
<item>@string/sort_title_z_a</item>
|
||||
<item>@string/sort_duration_short_long</item>
|
||||
<item>@string/sort_duration_long_short</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="feed_episodes_sort_values">
|
||||
<item>DATE_NEW_OLD</item>
|
||||
<item>DATE_OLD_NEW</item>
|
||||
<item>EPISODE_TITLE_A_Z</item>
|
||||
<item>EPISODE_TITLE_Z_A</item>
|
||||
<item>DURATION_SHORT_LONG</item>
|
||||
<item>DURATION_LONG_SHORT</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="image_cache_size_options">
|
||||
<item>20 MiB</item>
|
||||
<item>50 MiB</item>
|
||||
|
|
|
@ -3,10 +3,13 @@ package de.danoeh.antennapod.core.feed;
|
|||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import de.danoeh.antennapod.core.util.SortOrder;
|
||||
|
||||
import static de.danoeh.antennapod.core.feed.FeedMother.anyFeed;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
public class FeedTest {
|
||||
|
||||
|
@ -59,6 +62,27 @@ public class FeedTest {
|
|||
feedImageWasUpdated();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetSortOrder_OnlyIntraFeedSortAllowed() throws Exception {
|
||||
for (SortOrder sortOrder : SortOrder.values()) {
|
||||
if (sortOrder.scope == SortOrder.Scope.INTRA_FEED) {
|
||||
original.setSortOrder(sortOrder); // should be okay
|
||||
} else {
|
||||
try {
|
||||
original.setSortOrder(sortOrder);
|
||||
fail("SortOrder " + sortOrder + " should not be allowed on a feed");
|
||||
} catch (IllegalArgumentException iae) {
|
||||
// expected exception
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetSortOrder_NullAllowed() throws Exception {
|
||||
original.setSortOrder(null); // should be okay
|
||||
}
|
||||
|
||||
private void feedHasNotChanged() {
|
||||
assertFalse(original.compareWithOther(changedFeed));
|
||||
}
|
||||
|
|
|
@ -10,22 +10,25 @@ import de.danoeh.antennapod.core.feed.Feed;
|
|||
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||
import de.danoeh.antennapod.core.feed.FeedMedia;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
/**
|
||||
* Test class for QueueSorter.
|
||||
* Test class for FeedItemPermutors.
|
||||
*/
|
||||
public class QueueSorterTest {
|
||||
public class FeedItemPermutorsTest {
|
||||
|
||||
@Test
|
||||
public void testPermutorForRule_null() {
|
||||
assertNull(QueueSorter.getPermutor(null));
|
||||
public void testEnsureNonNullPermutors() {
|
||||
for (SortOrder sortOrder : SortOrder.values()) {
|
||||
assertNotNull("The permutor for SortOrder " + sortOrder + " is unexpectedly null",
|
||||
FeedItemPermutors.getPermutor(sortOrder));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPermutorForRule_EPISODE_TITLE_ASC() {
|
||||
Permutor<FeedItem> permutor = QueueSorter.getPermutor(SortOrder.EPISODE_TITLE_A_Z);
|
||||
Permutor<FeedItem> permutor = FeedItemPermutors.getPermutor(SortOrder.EPISODE_TITLE_A_Z);
|
||||
|
||||
List<FeedItem> itemList = getTestList();
|
||||
assertTrue(checkIdOrder(itemList, 1, 3, 2)); // before sorting
|
||||
|
@ -33,9 +36,22 @@ public class QueueSorterTest {
|
|||
assertTrue(checkIdOrder(itemList, 1, 2, 3)); // after sorting
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPermutorForRule_EPISODE_TITLE_ASC_NullTitle() {
|
||||
Permutor<FeedItem> permutor = FeedItemPermutors.getPermutor(SortOrder.EPISODE_TITLE_A_Z);
|
||||
|
||||
List<FeedItem> itemList = getTestList();
|
||||
itemList.get(2) // itemId 2
|
||||
.setTitle(null);
|
||||
assertTrue(checkIdOrder(itemList, 1, 3, 2)); // before sorting
|
||||
permutor.reorder(itemList);
|
||||
assertTrue(checkIdOrder(itemList, 2, 1, 3)); // after sorting
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testPermutorForRule_EPISODE_TITLE_DESC() {
|
||||
Permutor<FeedItem> permutor = QueueSorter.getPermutor(SortOrder.EPISODE_TITLE_Z_A);
|
||||
Permutor<FeedItem> permutor = FeedItemPermutors.getPermutor(SortOrder.EPISODE_TITLE_Z_A);
|
||||
|
||||
List<FeedItem> itemList = getTestList();
|
||||
assertTrue(checkIdOrder(itemList, 1, 3, 2)); // before sorting
|
||||
|
@ -45,7 +61,7 @@ public class QueueSorterTest {
|
|||
|
||||
@Test
|
||||
public void testPermutorForRule_DATE_ASC() {
|
||||
Permutor<FeedItem> permutor = QueueSorter.getPermutor(SortOrder.DATE_OLD_NEW);
|
||||
Permutor<FeedItem> permutor = FeedItemPermutors.getPermutor(SortOrder.DATE_OLD_NEW);
|
||||
|
||||
List<FeedItem> itemList = getTestList();
|
||||
assertTrue(checkIdOrder(itemList, 1, 3, 2)); // before sorting
|
||||
|
@ -53,9 +69,21 @@ public class QueueSorterTest {
|
|||
assertTrue(checkIdOrder(itemList, 1, 2, 3)); // after sorting
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPermutorForRule_DATE_ASC_NulPubDatel() {
|
||||
Permutor<FeedItem> permutor = FeedItemPermutors.getPermutor(SortOrder.DATE_OLD_NEW);
|
||||
|
||||
List<FeedItem> itemList = getTestList();
|
||||
itemList.get(2) // itemId 2
|
||||
.setPubDate(null);
|
||||
assertTrue(checkIdOrder(itemList, 1, 3, 2)); // before sorting
|
||||
permutor.reorder(itemList);
|
||||
assertTrue(checkIdOrder(itemList, 2, 1, 3)); // after sorting
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPermutorForRule_DATE_DESC() {
|
||||
Permutor<FeedItem> permutor = QueueSorter.getPermutor(SortOrder.DATE_NEW_OLD);
|
||||
Permutor<FeedItem> permutor = FeedItemPermutors.getPermutor(SortOrder.DATE_NEW_OLD);
|
||||
|
||||
List<FeedItem> itemList = getTestList();
|
||||
assertTrue(checkIdOrder(itemList, 1, 3, 2)); // before sorting
|
||||
|
@ -65,7 +93,7 @@ public class QueueSorterTest {
|
|||
|
||||
@Test
|
||||
public void testPermutorForRule_DURATION_ASC() {
|
||||
Permutor<FeedItem> permutor = QueueSorter.getPermutor(SortOrder.DURATION_SHORT_LONG);
|
||||
Permutor<FeedItem> permutor = FeedItemPermutors.getPermutor(SortOrder.DURATION_SHORT_LONG);
|
||||
|
||||
List<FeedItem> itemList = getTestList();
|
||||
assertTrue(checkIdOrder(itemList, 1, 3, 2)); // before sorting
|
||||
|
@ -75,7 +103,7 @@ public class QueueSorterTest {
|
|||
|
||||
@Test
|
||||
public void testPermutorForRule_DURATION_DESC() {
|
||||
Permutor<FeedItem> permutor = QueueSorter.getPermutor(SortOrder.DURATION_LONG_SHORT);
|
||||
Permutor<FeedItem> permutor = FeedItemPermutors.getPermutor(SortOrder.DURATION_LONG_SHORT);
|
||||
|
||||
List<FeedItem> itemList = getTestList();
|
||||
assertTrue(checkIdOrder(itemList, 1, 3, 2)); // before sorting
|
||||
|
@ -83,9 +111,21 @@ public class QueueSorterTest {
|
|||
assertTrue(checkIdOrder(itemList, 3, 2, 1)); // after sorting
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPermutorForRule_DURATION_DESC_NullMedia() {
|
||||
Permutor<FeedItem> permutor = FeedItemPermutors.getPermutor(SortOrder.DURATION_LONG_SHORT);
|
||||
|
||||
List<FeedItem> itemList = getTestList();
|
||||
itemList.get(1) // itemId 3
|
||||
.setMedia(null);
|
||||
assertTrue(checkIdOrder(itemList, 1, 3, 2)); // before sorting
|
||||
permutor.reorder(itemList);
|
||||
assertTrue(checkIdOrder(itemList, 2, 1, 3)); // after sorting
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPermutorForRule_FEED_TITLE_ASC() {
|
||||
Permutor<FeedItem> permutor = QueueSorter.getPermutor(SortOrder.FEED_TITLE_A_Z);
|
||||
Permutor<FeedItem> permutor = FeedItemPermutors.getPermutor(SortOrder.FEED_TITLE_A_Z);
|
||||
|
||||
List<FeedItem> itemList = getTestList();
|
||||
assertTrue(checkIdOrder(itemList, 1, 3, 2)); // before sorting
|
||||
|
@ -95,7 +135,7 @@ public class QueueSorterTest {
|
|||
|
||||
@Test
|
||||
public void testPermutorForRule_FEED_TITLE_DESC() {
|
||||
Permutor<FeedItem> permutor = QueueSorter.getPermutor(SortOrder.FEED_TITLE_Z_A);
|
||||
Permutor<FeedItem> permutor = FeedItemPermutors.getPermutor(SortOrder.FEED_TITLE_Z_A);
|
||||
|
||||
List<FeedItem> itemList = getTestList();
|
||||
assertTrue(checkIdOrder(itemList, 1, 3, 2)); // before sorting
|
||||
|
@ -103,6 +143,18 @@ public class QueueSorterTest {
|
|||
assertTrue(checkIdOrder(itemList, 3, 2, 1)); // after sorting
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPermutorForRule_FEED_TITLE_DESC_NullTitle() {
|
||||
Permutor<FeedItem> permutor = FeedItemPermutors.getPermutor(SortOrder.FEED_TITLE_Z_A);
|
||||
|
||||
List<FeedItem> itemList = getTestList();
|
||||
itemList.get(1) // itemId 3
|
||||
.getFeed().setTitle(null);
|
||||
assertTrue(checkIdOrder(itemList, 1, 3, 2)); // before sorting
|
||||
permutor.reorder(itemList);
|
||||
assertTrue(checkIdOrder(itemList, 2, 1, 3)); // after sorting
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a list with test data.
|
||||
*/
|