Converted lists to RecyclerView
Also, cleaned up list adapters
This commit is contained in:
parent
4e0e4baa05
commit
4f0de071ec
|
@ -34,6 +34,8 @@ import static androidx.test.espresso.action.ViewActions.scrollTo;
|
|||
import static androidx.test.espresso.action.ViewActions.swipeUp;
|
||||
import static androidx.test.espresso.intent.Intents.intended;
|
||||
import static androidx.test.espresso.intent.matcher.IntentMatchers.hasComponent;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isDescendantOfA;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.isRoot;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withId;
|
||||
import static androidx.test.espresso.matcher.ViewMatchers.withText;
|
||||
|
@ -80,52 +82,51 @@ public class NavigationDrawerTest {
|
|||
uiTestUtils.addLocalFeedData(false);
|
||||
UserPreferences.setHiddenDrawerItems(new ArrayList<>());
|
||||
activityRule.launchActivity(new Intent());
|
||||
MainActivity activity = activityRule.getActivity();
|
||||
|
||||
// queue
|
||||
openNavDrawer();
|
||||
onDrawerItem(withText(R.string.queue_label)).perform(click());
|
||||
onView(isRoot()).perform(waitForView(withId(R.id.recyclerView), 1000));
|
||||
assertEquals(activity.getString(R.string.queue_label), activity.getSupportActionBar().getTitle());
|
||||
onView(isRoot()).perform(waitForView(allOf(isDescendantOfA(withId(R.id.toolbar)),
|
||||
withText(R.string.queue_label)), 1000));
|
||||
|
||||
// episodes
|
||||
openNavDrawer();
|
||||
onDrawerItem(withText(R.string.episodes_label)).perform(click());
|
||||
onView(isRoot()).perform(waitForView(withId(android.R.id.list), 1000));
|
||||
assertEquals(activity.getString(R.string.episodes_label), activity.getSupportActionBar().getTitle());
|
||||
onView(isRoot()).perform(waitForView(allOf(isDescendantOfA(withId(R.id.toolbar)),
|
||||
withText(R.string.episodes_label), isDisplayed()), 1000));
|
||||
|
||||
// Subscriptions
|
||||
openNavDrawer();
|
||||
onDrawerItem(withText(R.string.subscriptions_label)).perform(click());
|
||||
onView(isRoot()).perform(waitForView(withId(R.id.subscriptions_grid), 1000));
|
||||
assertEquals(activity.getString(R.string.subscriptions_label), activity.getSupportActionBar().getTitle());
|
||||
onView(isRoot()).perform(waitForView(allOf(isDescendantOfA(withId(R.id.toolbar)),
|
||||
withText(R.string.subscriptions_label), isDisplayed()), 1000));
|
||||
|
||||
// downloads
|
||||
openNavDrawer();
|
||||
onDrawerItem(withText(R.string.downloads_label)).perform(click());
|
||||
onView(isRoot()).perform(waitForView(withId(android.R.id.list), 1000));
|
||||
assertEquals(activity.getString(R.string.downloads_label), activity.getSupportActionBar().getTitle());
|
||||
onView(isRoot()).perform(waitForView(allOf(isDescendantOfA(withId(R.id.toolbar)),
|
||||
withText(R.string.downloads_label), isDisplayed()), 1000));
|
||||
|
||||
// playback history
|
||||
openNavDrawer();
|
||||
onDrawerItem(withText(R.string.playback_history_label)).perform(click());
|
||||
onView(isRoot()).perform(waitForView(withId(android.R.id.list), 1000));
|
||||
assertEquals(activity.getString(R.string.playback_history_label), activity.getSupportActionBar().getTitle());
|
||||
onView(isRoot()).perform(waitForView(allOf(isDescendantOfA(withId(R.id.toolbar)),
|
||||
withText(R.string.playback_history_label), isDisplayed()), 1000));
|
||||
|
||||
// add podcast
|
||||
openNavDrawer();
|
||||
onView(withId(R.id.nav_list)).perform(swipeUp());
|
||||
onDrawerItem(withText(R.string.add_feed_label)).perform(click());
|
||||
onView(isRoot()).perform(waitForView(withId(R.id.btn_add_via_url), 1000));
|
||||
assertEquals(activity.getString(R.string.add_feed_label), activity.getSupportActionBar().getTitle());
|
||||
onView(isRoot()).perform(waitForView(allOf(isDescendantOfA(withId(R.id.toolbar)),
|
||||
withText(R.string.add_feed_label), isDisplayed()), 1000));
|
||||
|
||||
// podcasts
|
||||
for (int i = 0; i < uiTestUtils.hostedFeeds.size(); i++) {
|
||||
Feed f = uiTestUtils.hostedFeeds.get(i);
|
||||
openNavDrawer();
|
||||
onDrawerItem(withText(f.getTitle())).perform(scrollTo(), click());
|
||||
onView(isRoot()).perform(waitForView(withId(android.R.id.list), 1000));
|
||||
assertEquals("", activity.getSupportActionBar().getTitle());
|
||||
onView(isRoot()).perform(waitForView(allOf(isDescendantOfA(withId(R.id.appBar)),
|
||||
withText(f.getTitle()), isDisplayed()), 1000));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,6 @@ import de.danoeh.antennapod.core.storage.DownloadRequestException;
|
|||
import de.danoeh.antennapod.core.storage.DownloadRequester;
|
||||
import de.danoeh.antennapod.core.util.ThemeUtils;
|
||||
import de.danoeh.antennapod.view.viewholder.DownloadItemViewHolder;
|
||||
import de.danoeh.antennapod.view.viewholder.FeedViewHolder;
|
||||
|
||||
/**
|
||||
* Displays a list of DownloadStatus entries.
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
package de.danoeh.antennapod.adapter;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.activity.MainActivity;
|
||||
|
@ -24,15 +24,14 @@ import java.util.List;
|
|||
/**
|
||||
* List adapter for the list of new episodes.
|
||||
*/
|
||||
public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<EpisodeItemViewHolder>
|
||||
public class EpisodeItemListAdapter extends RecyclerView.Adapter<EpisodeItemViewHolder>
|
||||
implements View.OnCreateContextMenuListener {
|
||||
|
||||
private final WeakReference<MainActivity> mainActivityRef;
|
||||
private List<FeedItem> episodes = new ArrayList<>();
|
||||
|
||||
private FeedItem selectedItem;
|
||||
|
||||
public AllEpisodesRecycleAdapter(MainActivity mainActivity) {
|
||||
public EpisodeItemListAdapter(MainActivity mainActivity) {
|
||||
super();
|
||||
this.mainActivityRef = new WeakReference<>(mainActivity);
|
||||
}
|
||||
|
@ -45,9 +44,7 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<EpisodeItemV
|
|||
@NonNull
|
||||
@Override
|
||||
public EpisodeItemViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
EpisodeItemViewHolder viewHolder = new EpisodeItemViewHolder(mainActivityRef.get(), parent);
|
||||
viewHolder.dragHandle.setVisibility(View.GONE);
|
||||
return viewHolder;
|
||||
return new EpisodeItemViewHolder(mainActivityRef.get(), parent);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -86,6 +83,14 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<EpisodeItemV
|
|||
return episodes.size();
|
||||
}
|
||||
|
||||
protected FeedItem getItem(int index) {
|
||||
return episodes.get(index);
|
||||
}
|
||||
|
||||
protected Activity getActivity() {
|
||||
return mainActivityRef.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateContextMenu(final ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
|
||||
MenuInflater inflater = mainActivityRef.get().getMenuInflater();
|
||||
|
@ -93,26 +98,4 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<EpisodeItemV
|
|||
menu.setHeaderTitle(selectedItem.getTitle());
|
||||
FeedItemMenuHandler.onPrepareMenu(menu, selectedItem, R.id.skip_episode_item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies a View Holder of relevant callbacks from
|
||||
* {@link ItemTouchHelper.Callback}.
|
||||
*/
|
||||
public interface ItemTouchHelperViewHolder {
|
||||
|
||||
/**
|
||||
* Called when the {@link ItemTouchHelper} first registers an
|
||||
* item as being moved or swiped.
|
||||
* Implementations should update the item view to indicate
|
||||
* it's active state.
|
||||
*/
|
||||
void onItemSelected();
|
||||
|
||||
|
||||
/**
|
||||
* Called when the {@link ItemTouchHelper} has completed the
|
||||
* move or swipe, and the active item state should be cleared.
|
||||
*/
|
||||
void onItemClear();
|
||||
}
|
||||
}
|
|
@ -1,119 +0,0 @@
|
|||
package de.danoeh.antennapod.adapter;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.ListView;
|
||||
import de.danoeh.antennapod.activity.MainActivity;
|
||||
import de.danoeh.antennapod.core.event.PlaybackPositionEvent;
|
||||
import de.danoeh.antennapod.core.feed.Feed;
|
||||
import de.danoeh.antennapod.core.feed.FeedComponent;
|
||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||
import de.danoeh.antennapod.view.viewholder.EpisodeItemViewHolder;
|
||||
import de.danoeh.antennapod.view.viewholder.FeedComponentViewHolder;
|
||||
import de.danoeh.antennapod.view.viewholder.FeedViewHolder;
|
||||
|
||||
/**
|
||||
* List adapter for items of feeds that the user has already subscribed to.
|
||||
*/
|
||||
public class FeedItemlistAdapter extends BaseAdapter {
|
||||
|
||||
private final ItemAccess itemAccess;
|
||||
private final MainActivity activity;
|
||||
private final boolean makePlayedItemsTransparent;
|
||||
private final boolean showIcons;
|
||||
|
||||
private int currentlyPlayingItem = -1;
|
||||
|
||||
public FeedItemlistAdapter(MainActivity activity, ItemAccess itemAccess,
|
||||
boolean showIcons, boolean makePlayedItemsTransparent) {
|
||||
super();
|
||||
this.activity = activity;
|
||||
this.itemAccess = itemAccess;
|
||||
this.showIcons = showIcons;
|
||||
this.makePlayedItemsTransparent = makePlayedItemsTransparent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return itemAccess.getCount();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FeedComponent getItem(int position) {
|
||||
return itemAccess.getItem(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(final int position, View convertView, ViewGroup parent) {
|
||||
final FeedComponent item = getItem(position);
|
||||
if (item instanceof Feed) {
|
||||
return getView((Feed) item, convertView, parent);
|
||||
} else {
|
||||
final FeedItem feeditem = (FeedItem) item;
|
||||
if (feeditem.getMedia() != null && feeditem.getMedia().isCurrentlyPlaying()) {
|
||||
currentlyPlayingItem = position;
|
||||
}
|
||||
return getView(feeditem, convertView, parent);
|
||||
}
|
||||
}
|
||||
|
||||
private View getView(Feed item, View convertView, ViewGroup parent) {
|
||||
FeedViewHolder holder;
|
||||
if (convertView == null || !(convertView.getTag() instanceof FeedViewHolder)) {
|
||||
holder = new FeedViewHolder(activity, parent);
|
||||
} else {
|
||||
holder = (FeedViewHolder) convertView.getTag();
|
||||
}
|
||||
holder.bind(item);
|
||||
return holder.itemView;
|
||||
}
|
||||
|
||||
private View getView(final FeedItem item, View convertView, ViewGroup parent) {
|
||||
EpisodeItemViewHolder holder;
|
||||
if (convertView == null || !(convertView.getTag() instanceof EpisodeItemViewHolder)) {
|
||||
holder = new EpisodeItemViewHolder(activity, parent);
|
||||
} else {
|
||||
holder = (EpisodeItemViewHolder) convertView.getTag();
|
||||
}
|
||||
|
||||
if (!showIcons) {
|
||||
holder.coverHolder.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
holder.bind(item);
|
||||
holder.dragHandle.setVisibility(View.GONE);
|
||||
|
||||
if (!makePlayedItemsTransparent) {
|
||||
holder.itemView.setAlpha(1.0f);
|
||||
}
|
||||
|
||||
holder.hideSeparatorIfNecessary();
|
||||
return holder.itemView;
|
||||
}
|
||||
|
||||
public void notifyCurrentlyPlayingItemChanged(PlaybackPositionEvent event, ListView listView) {
|
||||
if (currentlyPlayingItem != -1 && currentlyPlayingItem < getCount()) {
|
||||
View view = listView.getChildAt(currentlyPlayingItem
|
||||
- listView.getFirstVisiblePosition() + listView.getHeaderViewsCount());
|
||||
if (view == null) {
|
||||
return;
|
||||
}
|
||||
EpisodeItemViewHolder holder = (EpisodeItemViewHolder) view.getTag();
|
||||
holder.notifyPlaybackPositionUpdated(event);
|
||||
}
|
||||
}
|
||||
|
||||
public interface ItemAccess {
|
||||
int getCount();
|
||||
|
||||
FeedComponent getItem(int position);
|
||||
}
|
||||
|
||||
}
|
|
@ -6,44 +6,24 @@ import android.view.ContextMenu;
|
|||
import android.view.MenuInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.view.MotionEventCompat;
|
||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.activity.MainActivity;
|
||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.util.LongList;
|
||||
import de.danoeh.antennapod.fragment.ItemPagerFragment;
|
||||
import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
|
||||
import de.danoeh.antennapod.view.viewholder.EpisodeItemViewHolder;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
/**
|
||||
* List adapter for the queue.
|
||||
*/
|
||||
public class QueueRecyclerAdapter extends RecyclerView.Adapter<EpisodeItemViewHolder> implements View.OnCreateContextMenuListener {
|
||||
public class QueueRecyclerAdapter extends EpisodeItemListAdapter {
|
||||
private static final String TAG = "QueueRecyclerAdapter";
|
||||
|
||||
private final WeakReference<MainActivity> mainActivity;
|
||||
private final ItemAccess itemAccess;
|
||||
private final ItemTouchHelper itemTouchHelper;
|
||||
|
||||
private boolean locked;
|
||||
|
||||
private FeedItem selectedItem;
|
||||
|
||||
public QueueRecyclerAdapter(MainActivity mainActivity,
|
||||
ItemAccess itemAccess,
|
||||
ItemTouchHelper itemTouchHelper) {
|
||||
super();
|
||||
this.mainActivity = new WeakReference<>(mainActivity);
|
||||
this.itemAccess = itemAccess;
|
||||
public QueueRecyclerAdapter(MainActivity mainActivity, ItemTouchHelper itemTouchHelper) {
|
||||
super(mainActivity);
|
||||
this.itemTouchHelper = itemTouchHelper;
|
||||
locked = UserPreferences.isQueueLocked();
|
||||
}
|
||||
|
@ -53,31 +33,10 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<EpisodeItemViewHo
|
|||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public EpisodeItemViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
return new EpisodeItemViewHolder(mainActivity.get(), parent);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
public void onBindViewHolder(EpisodeItemViewHolder holder, int pos) {
|
||||
FeedItem item = itemAccess.getItem(pos);
|
||||
holder.bind(item);
|
||||
holder.dragHandle.setVisibility(locked ? View.GONE : View.VISIBLE);
|
||||
holder.itemView.setOnLongClickListener(v -> {
|
||||
selectedItem = item;
|
||||
return false;
|
||||
});
|
||||
holder.itemView.setOnClickListener(v -> {
|
||||
MainActivity activity = mainActivity.get();
|
||||
if (activity != null) {
|
||||
long[] ids = itemAccess.getQueueIds().toArray();
|
||||
int position = ArrayUtils.indexOf(ids, item.getId());
|
||||
activity.loadChildFragment(ItemPagerFragment.newInstance(ids, position));
|
||||
}
|
||||
});
|
||||
|
||||
super.onBindViewHolder(holder, pos);
|
||||
View.OnTouchListener startDragTouchListener = (v1, event) -> {
|
||||
if (MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN) {
|
||||
Log.d(TAG, "startDrag()");
|
||||
|
@ -85,80 +44,33 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<EpisodeItemViewHo
|
|||
}
|
||||
return false;
|
||||
};
|
||||
if (!locked) {
|
||||
holder.dragHandle.setOnTouchListener(startDragTouchListener);
|
||||
holder.coverHolder.setOnTouchListener(startDragTouchListener);
|
||||
} else {
|
||||
|
||||
if (locked) {
|
||||
holder.dragHandle.setVisibility(View.GONE);
|
||||
holder.dragHandle.setOnTouchListener(null);
|
||||
holder.coverHolder.setOnTouchListener(null);
|
||||
} else {
|
||||
holder.dragHandle.setVisibility(View.VISIBLE);
|
||||
holder.dragHandle.setOnTouchListener(startDragTouchListener);
|
||||
holder.coverHolder.setOnTouchListener(startDragTouchListener);
|
||||
}
|
||||
|
||||
holder.itemView.setOnCreateContextMenuListener(this);
|
||||
holder.isInQueue.setVisibility(View.GONE);
|
||||
holder.hideSeparatorIfNecessary();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public FeedItem getSelectedItem() {
|
||||
return selectedItem;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
FeedItem item = itemAccess.getItem(position);
|
||||
return item != null ? item.getId() : RecyclerView.NO_POSITION;
|
||||
}
|
||||
|
||||
public int getItemCount() {
|
||||
return itemAccess.getCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateContextMenu(final ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
|
||||
MenuInflater inflater = mainActivity.get().getMenuInflater();
|
||||
inflater.inflate(R.menu.queue_context, menu); // queue-specific menu items
|
||||
inflater.inflate(R.menu.feeditemlist_context, menu); // generic menu items for item feeds
|
||||
MenuInflater inflater = getActivity().getMenuInflater();
|
||||
inflater.inflate(R.menu.queue_context, menu);
|
||||
super.onCreateContextMenu(menu, v, menuInfo);
|
||||
|
||||
menu.setHeaderTitle(selectedItem.getTitle());
|
||||
FeedItemMenuHandler.onPrepareMenu(menu, selectedItem, R.id.skip_episode_item);
|
||||
// Queue-specific menu preparation
|
||||
final boolean keepSorted = UserPreferences.isQueueKeepSorted();
|
||||
final LongList queueAccess = itemAccess.getQueueIds();
|
||||
if (queueAccess.size() == 0 || queueAccess.get(0) == selectedItem.getId() || keepSorted) {
|
||||
if (getItem(0).getId() == getSelectedItem().getId() || keepSorted) {
|
||||
menu.findItem(R.id.move_to_top_item).setVisible(false);
|
||||
}
|
||||
if (queueAccess.size() == 0 || queueAccess.get(queueAccess.size() - 1) == selectedItem.getId() || keepSorted) {
|
||||
if (getItem(getItemCount() - 1).getId() == getSelectedItem().getId() || keepSorted) {
|
||||
menu.findItem(R.id.move_to_bottom_item).setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
public interface ItemAccess {
|
||||
FeedItem getItem(int position);
|
||||
|
||||
int getCount();
|
||||
|
||||
LongList getQueueIds();
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies a View Holder of relevant callbacks from
|
||||
* {@link ItemTouchHelper.Callback}.
|
||||
*/
|
||||
public interface ItemTouchHelperViewHolder {
|
||||
|
||||
/**
|
||||
* Called when the {@link ItemTouchHelper} first registers an
|
||||
* item as being moved or swiped.
|
||||
* Implementations should update the item view to indicate
|
||||
* it's active state.
|
||||
*/
|
||||
void onItemSelected();
|
||||
|
||||
|
||||
/**
|
||||
* Called when the {@link ItemTouchHelper} has completed the
|
||||
* move or swipe, and the active item state should be cleared.
|
||||
*/
|
||||
void onItemClear();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,10 +6,8 @@ import android.content.SharedPreferences;
|
|||
import android.os.Bundle;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.core.view.MenuItemCompat;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.appcompat.widget.SearchView;
|
||||
import androidx.recyclerview.widget.SimpleItemAnimator;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
|
@ -24,6 +22,7 @@ import android.widget.Toast;
|
|||
|
||||
import com.yqritc.recyclerviewflexibledivider.HorizontalDividerItemDecoration;
|
||||
|
||||
import de.danoeh.antennapod.adapter.EpisodeItemListAdapter;
|
||||
import de.danoeh.antennapod.core.event.FeedListUpdateEvent;
|
||||
import de.danoeh.antennapod.core.event.PlaybackPositionEvent;
|
||||
import de.danoeh.antennapod.core.event.PlayerStatusEvent;
|
||||
|
@ -38,14 +37,12 @@ import java.util.List;
|
|||
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.activity.MainActivity;
|
||||
import de.danoeh.antennapod.adapter.AllEpisodesRecycleAdapter;
|
||||
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.feed.FeedItem;
|
||||
import de.danoeh.antennapod.core.service.download.DownloadService;
|
||||
import de.danoeh.antennapod.core.service.download.Downloader;
|
||||
import de.danoeh.antennapod.core.storage.DBWriter;
|
||||
import de.danoeh.antennapod.core.storage.DownloadRequester;
|
||||
import de.danoeh.antennapod.core.util.FeedItemUtil;
|
||||
|
@ -73,7 +70,7 @@ public abstract class EpisodesListFragment extends Fragment {
|
|||
protected int page = 1;
|
||||
|
||||
RecyclerView recyclerView;
|
||||
AllEpisodesRecycleAdapter listAdapter;
|
||||
EpisodeItemListAdapter listAdapter;
|
||||
ProgressBar progLoading;
|
||||
View loadingMore;
|
||||
EmptyViewHandler emptyView;
|
||||
|
@ -346,7 +343,7 @@ public abstract class EpisodesListFragment extends Fragment {
|
|||
*/
|
||||
private void createRecycleAdapter(RecyclerView recyclerView, EmptyViewHandler emptyViewHandler) {
|
||||
MainActivity mainActivity = (MainActivity) getActivity();
|
||||
listAdapter = new AllEpisodesRecycleAdapter(mainActivity);
|
||||
listAdapter = new EpisodeItemListAdapter(mainActivity);
|
||||
listAdapter.setHasStableIds(true);
|
||||
listAdapter.updateItems(episodes);
|
||||
recyclerView.setAdapter(listAdapter);
|
||||
|
|
|
@ -5,7 +5,6 @@ import android.content.DialogInterface;
|
|||
import android.graphics.LightingColorFilter;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
|
@ -15,7 +14,6 @@ import android.view.ViewGroup;
|
|||
import android.widget.AdapterView;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ListView;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
@ -23,19 +21,20 @@ import android.widget.Toast;
|
|||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.SearchView;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.core.view.MenuItemCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import com.google.android.material.appbar.AppBarLayout;
|
||||
import com.google.android.material.appbar.CollapsingToolbarLayout;
|
||||
import com.joanzapata.iconify.Iconify;
|
||||
import com.joanzapata.iconify.widget.IconTextView;
|
||||
import com.yqritc.recyclerviewflexibledivider.HorizontalDividerItemDecoration;
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.activity.MainActivity;
|
||||
import de.danoeh.antennapod.adapter.FeedItemlistAdapter;
|
||||
import de.danoeh.antennapod.adapter.EpisodeItemListAdapter;
|
||||
import de.danoeh.antennapod.core.asynctask.FeedRemover;
|
||||
import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
|
||||
import de.danoeh.antennapod.core.dialog.DownloadRequestErrorDialogCreator;
|
||||
|
@ -68,6 +67,7 @@ import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
|
|||
import de.danoeh.antennapod.menuhandler.FeedMenuHandler;
|
||||
import de.danoeh.antennapod.menuhandler.MenuItemUtils;
|
||||
import de.danoeh.antennapod.view.ToolbarIconTintManager;
|
||||
import de.danoeh.antennapod.view.viewholder.EpisodeItemViewHolder;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
|
@ -86,12 +86,11 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
|
|||
private static final String TAG = "ItemlistFragment";
|
||||
private static final String ARGUMENT_FEED_ID = "argument.de.danoeh.antennapod.feed_id";
|
||||
|
||||
private FeedItemlistAdapter adapter;
|
||||
private AdapterView.AdapterContextMenuInfo lastMenuInfo = null;
|
||||
private FeedItemListAdapter adapter;
|
||||
private MoreContentListFooterUtil listFooter;
|
||||
|
||||
private ProgressBar progressBar;
|
||||
private ListView listView;
|
||||
private RecyclerView recyclerView;
|
||||
private TextView txtvTitle;
|
||||
private IconTextView txtvFailure;
|
||||
private ImageView imgvBackground;
|
||||
|
@ -144,9 +143,13 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
|
|||
toolbar.setTitle("");
|
||||
((AppCompatActivity) getActivity()).setSupportActionBar(toolbar);
|
||||
|
||||
listView = root.findViewById(android.R.id.list);
|
||||
listView.setOnItemClickListener(this);
|
||||
registerForContextMenu(listView);
|
||||
recyclerView = root.findViewById(R.id.recyclerView);
|
||||
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
|
||||
recyclerView.setLayoutManager(layoutManager);
|
||||
recyclerView.setHasFixedSize(true);
|
||||
recyclerView.addItemDecoration(new HorizontalDividerItemDecoration.Builder(getActivity()).build());
|
||||
recyclerView.setVisibility(View.GONE);
|
||||
|
||||
progressBar = root.findViewById(R.id.progLoading);
|
||||
txtvTitle = root.findViewById(R.id.txtvTitle);
|
||||
txtvAuthor = root.findViewById(R.id.txtvAuthor);
|
||||
|
@ -283,35 +286,12 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
|
||||
super.onCreateContextMenu(menu, v, menuInfo);
|
||||
AdapterView.AdapterContextMenuInfo adapterInfo = (AdapterView.AdapterContextMenuInfo) menuInfo;
|
||||
|
||||
FeedItem item = (FeedItem) itemAccess.getItem(adapterInfo.position);
|
||||
MenuInflater inflater = getActivity().getMenuInflater();
|
||||
inflater.inflate(R.menu.feeditemlist_context, menu);
|
||||
|
||||
if (item != null) {
|
||||
menu.setHeaderTitle(item.getTitle());
|
||||
}
|
||||
|
||||
lastMenuInfo = (AdapterView.AdapterContextMenuInfo) menuInfo;
|
||||
FeedItemMenuHandler.onPrepareMenu(menu, item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onContextItemSelected(MenuItem item) {
|
||||
AdapterView.AdapterContextMenuInfo menuInfo = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
|
||||
if (menuInfo == null) {
|
||||
menuInfo = lastMenuInfo;
|
||||
}
|
||||
FeedItem selectedItem = feed.getItemAtIndex(menuInfo.position);
|
||||
|
||||
public boolean onContextItemSelected(@NonNull MenuItem item) {
|
||||
FeedItem selectedItem = adapter.getSelectedItem();
|
||||
if (selectedItem == null) {
|
||||
Log.i(TAG, "Selected item at position " + menuInfo.position + " was null, ignoring selection");
|
||||
Log.i(TAG, "Selected item at current position was null, ignoring selection");
|
||||
return super.onContextItemSelected(item);
|
||||
}
|
||||
|
||||
return FeedItemMenuHandler.onMenuItemClicked(this, item.getItemId(), selectedItem);
|
||||
}
|
||||
|
||||
|
@ -336,14 +316,19 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
|
|||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
public void onEventMainThread(FeedItemEvent event) {
|
||||
Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
|
||||
if (feed == null || feed.getItems() == null || adapter == null) {
|
||||
if (feed == null || feed.getItems() == null) {
|
||||
return;
|
||||
} else if (adapter == null) {
|
||||
loadItems();
|
||||
return;
|
||||
}
|
||||
for (FeedItem item : event.items) {
|
||||
for (int i = 0, size = event.items.size(); i < size; i++) {
|
||||
FeedItem item = event.items.get(i);
|
||||
int pos = FeedItemUtil.indexOfItemWithId(feed.getItems(), item.getId());
|
||||
if (pos >= 0) {
|
||||
loadItems();
|
||||
return;
|
||||
feed.getItems().remove(pos);
|
||||
feed.getItems().add(pos, item);
|
||||
adapter.notifyItemChanged(pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -356,14 +341,25 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
|
|||
updateProgressBarVisibility();
|
||||
}
|
||||
if (adapter != null && update.mediaIds.length > 0) {
|
||||
adapter.notifyDataSetChanged();
|
||||
for (long mediaId : update.mediaIds) {
|
||||
int pos = FeedItemUtil.indexOfItemWithMediaId(feed.getItems(), mediaId);
|
||||
if (pos >= 0) {
|
||||
adapter.notifyItemChanged(pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
public void onEventMainThread(PlaybackPositionEvent event) {
|
||||
if (adapter != null) {
|
||||
adapter.notifyCurrentlyPlayingItemChanged(event, listView);
|
||||
for (int i = 0; i < adapter.getItemCount(); i++) {
|
||||
EpisodeItemViewHolder holder = (EpisodeItemViewHolder) recyclerView.findViewHolderForAdapterPosition(i);
|
||||
if (holder != null && holder.isCurrentlyPlayingItem()) {
|
||||
holder.notifyPlaybackPositionUpdated(event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -405,24 +401,24 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
|
|||
return;
|
||||
}
|
||||
if (adapter == null) {
|
||||
listView.setAdapter(null);
|
||||
recyclerView.setAdapter(null);
|
||||
setupFooterView();
|
||||
adapter = new FeedItemlistAdapter((MainActivity) getActivity(), itemAccess, false, true);
|
||||
listView.setAdapter(adapter);
|
||||
adapter = new FeedItemListAdapter((MainActivity) getActivity());
|
||||
recyclerView.setAdapter(adapter);
|
||||
}
|
||||
listView.setVisibility(View.VISIBLE);
|
||||
recyclerView.setVisibility(View.VISIBLE);
|
||||
progressBar.setVisibility(View.GONE);
|
||||
adapter.notifyDataSetChanged();
|
||||
adapter.updateItems(feed.getItems());
|
||||
|
||||
getActivity().supportInvalidateOptionsMenu();
|
||||
|
||||
if (feed != null && feed.getNextPageLink() == null && listFooter != null) {
|
||||
/*if (feed != null && feed.getNextPageLink() == null && listFooter != null) {
|
||||
listView.removeFooterView(listFooter.getRoot());
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
private void refreshHeaderView() {
|
||||
if (listView == null || feed == null || !headerCreated) {
|
||||
if (recyclerView == null || feed == null || !headerCreated) {
|
||||
Log.e(TAG, "Unable to refresh header view");
|
||||
return;
|
||||
}
|
||||
|
@ -453,11 +449,7 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
|
|||
}
|
||||
|
||||
private void setupHeaderView() {
|
||||
if (listView == null || feed == null) {
|
||||
Log.e(TAG, "Unable to setup listview: recyclerView = null or feed = null");
|
||||
return;
|
||||
}
|
||||
if (headerCreated) {
|
||||
if (feed == null || headerCreated) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -506,16 +498,16 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
|
|||
|
||||
|
||||
private void setupFooterView() {
|
||||
if (listView == null || feed == null) {
|
||||
if (recyclerView == null || feed == null) {
|
||||
Log.e(TAG, "Unable to setup listview: recyclerView = null or feed = null");
|
||||
return;
|
||||
}
|
||||
if (feed.isPaged() && feed.getNextPageLink() != null) {
|
||||
LayoutInflater inflater = (LayoutInflater)
|
||||
getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
View header = inflater.inflate(R.layout.more_content_list_footer, listView, false);
|
||||
listView.addFooterView(header);
|
||||
listFooter = new MoreContentListFooterUtil(header);
|
||||
View footer = inflater.inflate(R.layout.more_content_list_footer, null, false);
|
||||
//adapter.setFooterView(footer);
|
||||
listFooter = new MoreContentListFooterUtil(footer);
|
||||
listFooter.setClickListener(() -> {
|
||||
if (feed != null) {
|
||||
try {
|
||||
|
@ -529,24 +521,6 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
|
|||
}
|
||||
}
|
||||
|
||||
private final FeedItemlistAdapter.ItemAccess itemAccess = new FeedItemlistAdapter.ItemAccess() {
|
||||
|
||||
@Override
|
||||
public FeedItem getItem(int position) {
|
||||
if (feed != null && 0 <= position && position < feed.getNumOfItems()) {
|
||||
return feed.getItemAtIndex(position);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return (feed != null) ? feed.getNumOfItems() : 0;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
private void loadItems() {
|
||||
if (disposable != null) {
|
||||
disposable.dispose();
|
||||
|
@ -576,4 +550,18 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
|
|||
}
|
||||
return Optional.ofNullable(feed);
|
||||
}
|
||||
|
||||
private static class FeedItemListAdapter extends EpisodeItemListAdapter {
|
||||
public FeedItemListAdapter(MainActivity mainActivity) {
|
||||
super(mainActivity);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public EpisodeItemViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
EpisodeItemViewHolder viewHolder = super.onCreateViewHolder(parent, viewType);
|
||||
viewHolder.coverHolder.setVisibility(View.GONE);
|
||||
return viewHolder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@ import android.view.ViewGroup;
|
|||
import java.util.List;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.adapter.AllEpisodesRecycleAdapter;
|
||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||
import de.danoeh.antennapod.core.storage.DBReader;
|
||||
import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
|
||||
|
@ -53,7 +52,8 @@ public class NewEpisodesFragment extends EpisodesListFragment {
|
|||
ItemTouchHelper.SimpleCallback simpleItemTouchCallback = new ItemTouchHelper.SimpleCallback(0,
|
||||
ItemTouchHelper.RIGHT) {
|
||||
@Override
|
||||
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
|
||||
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,
|
||||
RecyclerView.ViewHolder target) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -62,33 +62,6 @@ public class NewEpisodesFragment extends EpisodesListFragment {
|
|||
EpisodeItemViewHolder holder = (EpisodeItemViewHolder) viewHolder;
|
||||
FeedItemMenuHandler.removeNewFlagWithUndo(NewEpisodesFragment.this, holder.getFeedItem());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder,
|
||||
int actionState) {
|
||||
// We only want the active item
|
||||
if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
|
||||
if (viewHolder instanceof AllEpisodesRecycleAdapter.ItemTouchHelperViewHolder) {
|
||||
AllEpisodesRecycleAdapter.ItemTouchHelperViewHolder itemViewHolder =
|
||||
(AllEpisodesRecycleAdapter.ItemTouchHelperViewHolder) viewHolder;
|
||||
itemViewHolder.onItemSelected();
|
||||
}
|
||||
}
|
||||
|
||||
super.onSelectedChanged(viewHolder, actionState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearView(RecyclerView recyclerView,
|
||||
RecyclerView.ViewHolder viewHolder) {
|
||||
super.clearView(recyclerView, viewHolder);
|
||||
|
||||
if (viewHolder instanceof AllEpisodesRecycleAdapter.ItemTouchHelperViewHolder) {
|
||||
AllEpisodesRecycleAdapter.ItemTouchHelperViewHolder itemViewHolder =
|
||||
(AllEpisodesRecycleAdapter.ItemTouchHelperViewHolder) viewHolder;
|
||||
itemViewHolder.onItemClear();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(simpleItemTouchCallback);
|
||||
|
|
|
@ -9,26 +9,31 @@ import android.view.MenuInflater;
|
|||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ListView;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.core.view.MenuItemCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import com.yqritc.recyclerviewflexibledivider.HorizontalDividerItemDecoration;
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.activity.MainActivity;
|
||||
import de.danoeh.antennapod.adapter.FeedItemlistAdapter;
|
||||
import de.danoeh.antennapod.adapter.EpisodeItemListAdapter;
|
||||
import de.danoeh.antennapod.core.event.DownloadEvent;
|
||||
import de.danoeh.antennapod.core.event.DownloaderUpdate;
|
||||
import de.danoeh.antennapod.core.event.FeedItemEvent;
|
||||
import de.danoeh.antennapod.core.event.PlaybackHistoryEvent;
|
||||
import de.danoeh.antennapod.core.event.PlaybackPositionEvent;
|
||||
import de.danoeh.antennapod.core.event.PlayerStatusEvent;
|
||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||
import de.danoeh.antennapod.core.storage.DBReader;
|
||||
import de.danoeh.antennapod.core.storage.DBWriter;
|
||||
import de.danoeh.antennapod.core.util.FeedItemUtil;
|
||||
import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
|
||||
import de.danoeh.antennapod.view.EmptyViewHandler;
|
||||
import de.danoeh.antennapod.view.viewholder.EpisodeItemViewHolder;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
|
@ -39,13 +44,13 @@ import org.greenrobot.eventbus.ThreadMode;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
public class PlaybackHistoryFragment extends Fragment implements AdapterView.OnItemClickListener {
|
||||
public class PlaybackHistoryFragment extends Fragment {
|
||||
public static final String TAG = "PlaybackHistoryFragment";
|
||||
|
||||
private List<FeedItem> playbackHistory;
|
||||
private FeedItemlistAdapter adapter;
|
||||
private PlaybackHistoryListAdapter adapter;
|
||||
private Disposable disposable;
|
||||
private ListView listView;
|
||||
private RecyclerView recyclerView;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
|
@ -62,18 +67,20 @@ public class PlaybackHistoryFragment extends Fragment implements AdapterView.OnI
|
|||
toolbar.setTitle(R.string.playback_history_label);
|
||||
((AppCompatActivity) getActivity()).setSupportActionBar(toolbar);
|
||||
|
||||
listView = root.findViewById(android.R.id.list);
|
||||
recyclerView = root.findViewById(R.id.recyclerView);
|
||||
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
|
||||
recyclerView.setLayoutManager(layoutManager);
|
||||
recyclerView.setHasFixedSize(true);
|
||||
recyclerView.addItemDecoration(new HorizontalDividerItemDecoration.Builder(getActivity()).build());
|
||||
recyclerView.setVisibility(View.GONE);
|
||||
adapter = new PlaybackHistoryListAdapter((MainActivity) getActivity());
|
||||
recyclerView.setAdapter(adapter);
|
||||
|
||||
EmptyViewHandler emptyView = new EmptyViewHandler(getActivity());
|
||||
emptyView.setIcon(R.attr.ic_history);
|
||||
emptyView.setTitle(R.string.no_history_head_label);
|
||||
emptyView.setMessage(R.string.no_history_label);
|
||||
emptyView.attachToListView(listView);
|
||||
|
||||
// played items shoudln't be transparent for this fragment since, *all* items
|
||||
// in this fragment will, by definition, be played. So it serves no purpose and can make
|
||||
// it harder to read.
|
||||
adapter = new FeedItemlistAdapter((MainActivity) getActivity(), itemAccess, true, false);
|
||||
listView.setAdapter(adapter);
|
||||
emptyView.attachToRecyclerView(recyclerView);
|
||||
return root;
|
||||
}
|
||||
|
||||
|
@ -93,17 +100,51 @@ public class PlaybackHistoryFragment extends Fragment implements AdapterView.OnI
|
|||
}
|
||||
}
|
||||
|
||||
@Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
|
||||
public void onEvent(DownloadEvent event) {
|
||||
Log.d(TAG, "onEvent() called with: " + "event = [" + event + "]");
|
||||
adapter.notifyDataSetChanged();
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
public void onEventMainThread(FeedItemEvent event) {
|
||||
Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
|
||||
if (playbackHistory == null) {
|
||||
return;
|
||||
} else if (adapter == null) {
|
||||
loadItems();
|
||||
return;
|
||||
}
|
||||
for (int i = 0, size = event.items.size(); i < size; i++) {
|
||||
FeedItem item = event.items.get(i);
|
||||
int pos = FeedItemUtil.indexOfItemWithId(playbackHistory, item.getId());
|
||||
if (pos >= 0) {
|
||||
playbackHistory.remove(pos);
|
||||
playbackHistory.add(pos, item);
|
||||
adapter.notifyItemChanged(pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
position -= listView.getHeaderViewsCount();
|
||||
long[] ids = FeedItemUtil.getIds(playbackHistory);
|
||||
((MainActivity) getActivity()).loadChildFragment(ItemPagerFragment.newInstance(ids, position));
|
||||
@Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
|
||||
public void onEventMainThread(DownloadEvent event) {
|
||||
Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
|
||||
DownloaderUpdate update = event.update;
|
||||
if (adapter != null && update.mediaIds.length > 0) {
|
||||
for (long mediaId : update.mediaIds) {
|
||||
int pos = FeedItemUtil.indexOfItemWithMediaId(playbackHistory, mediaId);
|
||||
if (pos >= 0) {
|
||||
adapter.notifyItemChanged(pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
public void onEventMainThread(PlaybackPositionEvent event) {
|
||||
if (adapter != null) {
|
||||
for (int i = 0; i < adapter.getItemCount(); i++) {
|
||||
EpisodeItemViewHolder holder = (EpisodeItemViewHolder) recyclerView.findViewHolderForAdapterPosition(i);
|
||||
if (holder != null && holder.isCurrentlyPlayingItem()) {
|
||||
holder.notifyPlaybackPositionUpdated(event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -143,19 +184,14 @@ public class PlaybackHistoryFragment extends Fragment implements AdapterView.OnI
|
|||
}
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
public void onEventMainThread(FeedItemEvent event) {
|
||||
Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
|
||||
if (playbackHistory == null) {
|
||||
return;
|
||||
}
|
||||
for (FeedItem item : event.items) {
|
||||
int pos = FeedItemUtil.indexOfItemWithId(playbackHistory, item.getId());
|
||||
if (pos >= 0) {
|
||||
loadItems();
|
||||
return;
|
||||
}
|
||||
@Override
|
||||
public boolean onContextItemSelected(@NonNull MenuItem item) {
|
||||
FeedItem selectedItem = adapter.getSelectedItem();
|
||||
if (selectedItem == null) {
|
||||
Log.i(TAG, "Selected item at current position was null, ignoring selection");
|
||||
return super.onContextItemSelected(item);
|
||||
}
|
||||
return FeedItemMenuHandler.onMenuItemClicked(this, item.getItemId(), selectedItem);
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
|
@ -175,23 +211,6 @@ public class PlaybackHistoryFragment extends Fragment implements AdapterView.OnI
|
|||
getActivity().supportInvalidateOptionsMenu();
|
||||
}
|
||||
|
||||
private final FeedItemlistAdapter.ItemAccess itemAccess = new FeedItemlistAdapter.ItemAccess() {
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return (playbackHistory != null) ? playbackHistory.size() : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FeedItem getItem(int position) {
|
||||
if (playbackHistory != null && 0 <= position && position < playbackHistory.size()) {
|
||||
return playbackHistory.get(position);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private void loadItems() {
|
||||
if (disposable != null) {
|
||||
disposable.dispose();
|
||||
|
@ -202,6 +221,7 @@ public class PlaybackHistoryFragment extends Fragment implements AdapterView.OnI
|
|||
.subscribe(result -> {
|
||||
if (result != null) {
|
||||
playbackHistory = result;
|
||||
adapter.updateItems(playbackHistory);
|
||||
onFragmentLoaded();
|
||||
}
|
||||
}, error -> Log.e(TAG, Log.getStackTraceString(error)));
|
||||
|
@ -213,4 +233,20 @@ public class PlaybackHistoryFragment extends Fragment implements AdapterView.OnI
|
|||
DBReader.loadAdditionalFeedItemListData(history);
|
||||
return history;
|
||||
}
|
||||
|
||||
private static class PlaybackHistoryListAdapter extends EpisodeItemListAdapter {
|
||||
|
||||
public PlaybackHistoryListAdapter(MainActivity mainActivity) {
|
||||
super(mainActivity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(EpisodeItemViewHolder holder, int pos) {
|
||||
super.onBindViewHolder(holder, pos);
|
||||
// played items shouldn't be transparent for this fragment since, *all* items
|
||||
// in this fragment will, by definition, be played. So it serves no purpose and can make
|
||||
// it harder to read.
|
||||
holder.itemView.setAlpha(1.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,27 +14,15 @@ import android.view.ViewGroup;
|
|||
import android.widget.CheckBox;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
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.view.viewholder.EpisodeItemViewHolder;
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
import org.greenrobot.eventbus.ThreadMode;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.activity.MainActivity;
|
||||
import de.danoeh.antennapod.adapter.QueueRecyclerAdapter;
|
||||
|
@ -44,8 +32,8 @@ 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.PlayerStatusEvent;
|
||||
import de.danoeh.antennapod.core.event.UnreadItemsUpdateEvent;
|
||||
import de.danoeh.antennapod.core.event.QueueEvent;
|
||||
import de.danoeh.antennapod.core.event.UnreadItemsUpdateEvent;
|
||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||
import de.danoeh.antennapod.core.feed.util.PlaybackSpeedUtils;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
|
@ -55,24 +43,29 @@ import de.danoeh.antennapod.core.storage.DBWriter;
|
|||
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.SortOrder;
|
||||
import de.danoeh.antennapod.core.util.download.AutoUpdateManager;
|
||||
import de.danoeh.antennapod.dialog.EpisodesApplyActionFragment;
|
||||
import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
|
||||
import de.danoeh.antennapod.menuhandler.MenuItemUtils;
|
||||
import de.danoeh.antennapod.view.EmptyViewHandler;
|
||||
import de.danoeh.antennapod.view.viewholder.EpisodeItemViewHolder;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
import org.greenrobot.eventbus.ThreadMode;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static de.danoeh.antennapod.dialog.EpisodesApplyActionFragment.ACTION_DELETE;
|
||||
import static de.danoeh.antennapod.dialog.EpisodesApplyActionFragment.ACTION_REMOVE_FROM_QUEUE;
|
||||
import static de.danoeh.antennapod.dialog.EpisodesApplyActionFragment.ACTION_DOWNLOAD;
|
||||
import static de.danoeh.antennapod.dialog.EpisodesApplyActionFragment.ACTION_REMOVE_FROM_QUEUE;
|
||||
|
||||
/**
|
||||
* Shows all items in the queue
|
||||
* Shows all items in the queue.
|
||||
*/
|
||||
public class QueueFragment extends Fragment {
|
||||
public static final String TAG = "QueueFragment";
|
||||
|
@ -179,10 +172,10 @@ public class QueueFragment extends Fragment {
|
|||
loadItems(true);
|
||||
return;
|
||||
}
|
||||
for(int i=0, size = event.items.size(); i < size; i++) {
|
||||
for (int i = 0, size = event.items.size(); i < size; i++) {
|
||||
FeedItem item = event.items.get(i);
|
||||
int pos = FeedItemUtil.indexOfItemWithId(queue, item.getId());
|
||||
if(pos >= 0) {
|
||||
if (pos >= 0) {
|
||||
queue.remove(pos);
|
||||
queue.add(pos, item);
|
||||
recyclerAdapter.notifyItemChanged(pos);
|
||||
|
@ -501,12 +494,13 @@ public class QueueFragment extends Fragment {
|
|||
int dragTo = -1;
|
||||
|
||||
@Override
|
||||
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
|
||||
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,
|
||||
RecyclerView.ViewHolder target) {
|
||||
int fromPosition = viewHolder.getAdapterPosition();
|
||||
int toPosition = target.getAdapterPosition();
|
||||
|
||||
// Update tracked position
|
||||
if(dragFrom == -1) {
|
||||
if (dragFrom == -1) {
|
||||
dragFrom = fromPosition;
|
||||
}
|
||||
dragTo = toPosition;
|
||||
|
@ -514,7 +508,7 @@ public class QueueFragment extends Fragment {
|
|||
int from = viewHolder.getAdapterPosition();
|
||||
int to = target.getAdapterPosition();
|
||||
Log.d(TAG, "move(" + from + ", " + to + ") in memory");
|
||||
if(from >= queue.size() || to >= queue.size()) {
|
||||
if (from >= queue.size() || to >= queue.size()) {
|
||||
return false;
|
||||
}
|
||||
queue.add(to, queue.remove(from));
|
||||
|
@ -524,7 +518,7 @@ public class QueueFragment extends Fragment {
|
|||
|
||||
@Override
|
||||
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
|
||||
if(disposable != null) {
|
||||
if (disposable != null) {
|
||||
disposable.dispose();
|
||||
}
|
||||
final int position = viewHolder.getAdapterPosition();
|
||||
|
@ -556,36 +550,14 @@ public class QueueFragment extends Fragment {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder,
|
||||
int actionState) {
|
||||
// We only want the active item
|
||||
if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
|
||||
if (viewHolder instanceof QueueRecyclerAdapter.ItemTouchHelperViewHolder) {
|
||||
QueueRecyclerAdapter.ItemTouchHelperViewHolder itemViewHolder =
|
||||
(QueueRecyclerAdapter.ItemTouchHelperViewHolder) viewHolder;
|
||||
itemViewHolder.onItemSelected();
|
||||
}
|
||||
}
|
||||
|
||||
super.onSelectedChanged(viewHolder, actionState);
|
||||
}
|
||||
@Override
|
||||
public void clearView(RecyclerView recyclerView,
|
||||
RecyclerView.ViewHolder viewHolder) {
|
||||
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
|
||||
super.clearView(recyclerView, viewHolder);
|
||||
|
||||
// Check if drag finished
|
||||
if(dragFrom != -1 && dragTo != -1 && dragFrom != dragTo) {
|
||||
if (dragFrom != -1 && dragTo != -1 && dragFrom != dragTo) {
|
||||
reallyMoved(dragFrom, dragTo);
|
||||
}
|
||||
|
||||
dragFrom = dragTo = -1;
|
||||
|
||||
if (viewHolder instanceof QueueRecyclerAdapter.ItemTouchHelperViewHolder) {
|
||||
QueueRecyclerAdapter.ItemTouchHelperViewHolder itemViewHolder =
|
||||
(QueueRecyclerAdapter.ItemTouchHelperViewHolder) viewHolder;
|
||||
itemViewHolder.onItemClear();
|
||||
}
|
||||
}
|
||||
|
||||
private void reallyMoved(int from, int to) {
|
||||
|
@ -613,11 +585,12 @@ public class QueueFragment extends Fragment {
|
|||
if (queue != null && queue.size() > 0) {
|
||||
if (recyclerAdapter == null) {
|
||||
MainActivity activity = (MainActivity) getActivity();
|
||||
recyclerAdapter = new QueueRecyclerAdapter(activity, itemAccess, itemTouchHelper);
|
||||
recyclerAdapter = new QueueRecyclerAdapter(activity, itemTouchHelper);
|
||||
recyclerAdapter.setHasStableIds(true);
|
||||
recyclerView.setAdapter(recyclerAdapter);
|
||||
emptyView.updateAdapter(recyclerAdapter);
|
||||
}
|
||||
recyclerAdapter.updateItems(queue);
|
||||
recyclerView.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
recyclerAdapter = null;
|
||||
|
@ -657,29 +630,9 @@ public class QueueFragment extends Fragment {
|
|||
infoBar.setText(info);
|
||||
}
|
||||
|
||||
private final QueueRecyclerAdapter.ItemAccess itemAccess = new QueueRecyclerAdapter.ItemAccess() {
|
||||
@Override
|
||||
public int getCount() {
|
||||
return queue != null ? queue.size() : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FeedItem getItem(int position) {
|
||||
if (queue != null && 0 <= position && position < queue.size()) {
|
||||
return queue.get(position);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LongList getQueueIds() {
|
||||
return queue != null ? LongList.of(FeedItemUtil.getIds(queue)) : new LongList(0);
|
||||
}
|
||||
};
|
||||
|
||||
private void loadItems(final boolean restoreScrollPosition) {
|
||||
Log.d(TAG, "loadItems()");
|
||||
if(disposable != null) {
|
||||
if (disposable != null) {
|
||||
disposable.dispose();
|
||||
}
|
||||
if (queue == null) {
|
||||
|
@ -694,7 +647,7 @@ public class QueueFragment extends Fragment {
|
|||
progLoading.setVisibility(View.GONE);
|
||||
queue = items;
|
||||
onFragmentLoaded(restoreScrollPosition);
|
||||
if(recyclerAdapter != null) {
|
||||
if (recyclerAdapter != null) {
|
||||
recyclerAdapter.notifyDataSetChanged();
|
||||
}
|
||||
}, error -> Log.e(TAG, Log.getStackTraceString(error)));
|
||||
|
|
|
@ -9,49 +9,54 @@ import android.view.MenuInflater;
|
|||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ListView;
|
||||
import android.widget.ProgressBar;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.SearchView;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import com.yqritc.recyclerviewflexibledivider.HorizontalDividerItemDecoration;
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.activity.MainActivity;
|
||||
import de.danoeh.antennapod.adapter.FeedItemlistAdapter;
|
||||
import de.danoeh.antennapod.adapter.EpisodeItemListAdapter;
|
||||
import de.danoeh.antennapod.core.event.DownloadEvent;
|
||||
import de.danoeh.antennapod.core.event.DownloaderUpdate;
|
||||
import de.danoeh.antennapod.core.event.FeedItemEvent;
|
||||
import de.danoeh.antennapod.core.event.PlaybackPositionEvent;
|
||||
import de.danoeh.antennapod.core.event.PlayerStatusEvent;
|
||||
import de.danoeh.antennapod.core.event.UnreadItemsUpdateEvent;
|
||||
import de.danoeh.antennapod.core.feed.Feed;
|
||||
import de.danoeh.antennapod.core.feed.FeedComponent;
|
||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||
import de.danoeh.antennapod.core.storage.FeedSearcher;
|
||||
import de.danoeh.antennapod.core.util.FeedItemUtil;
|
||||
import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
|
||||
import de.danoeh.antennapod.view.EmptyViewHandler;
|
||||
import de.danoeh.antennapod.view.viewholder.EpisodeItemViewHolder;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
import org.greenrobot.eventbus.ThreadMode;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Performs a search operation on all feeds or one specific feed and displays the search result.
|
||||
*/
|
||||
public class SearchFragment extends Fragment implements AdapterView.OnItemClickListener {
|
||||
public class SearchFragment extends Fragment {
|
||||
private static final String TAG = "SearchFragment";
|
||||
|
||||
private static final String ARG_QUERY = "query";
|
||||
private static final String ARG_FEED = "feed";
|
||||
|
||||
private FeedItemlistAdapter searchAdapter;
|
||||
private List<FeedComponent> searchResults = new ArrayList<>();
|
||||
private EpisodeItemListAdapter adapter;
|
||||
private Disposable disposable;
|
||||
private ProgressBar progressBar;
|
||||
private EmptyViewHandler emptyViewHandler;
|
||||
private RecyclerView recyclerView;
|
||||
private List<FeedItem> results;
|
||||
|
||||
/**
|
||||
* Create a new SearchFragment that searches all feeds.
|
||||
|
@ -104,14 +109,18 @@ public class SearchFragment extends Fragment implements AdapterView.OnItemClickL
|
|||
@Nullable Bundle savedInstanceState) {
|
||||
View layout = inflater.inflate(R.layout.search_fragment, container, false);
|
||||
((AppCompatActivity) getActivity()).setSupportActionBar(layout.findViewById(R.id.toolbar));
|
||||
ListView listView = layout.findViewById(R.id.listview);
|
||||
progressBar = layout.findViewById(R.id.progressBar);
|
||||
searchAdapter = new FeedItemlistAdapter((MainActivity) getActivity(), itemAccess, true, true);
|
||||
listView.setAdapter(searchAdapter);
|
||||
listView.setOnItemClickListener(this);
|
||||
recyclerView = layout.findViewById(R.id.recyclerView);
|
||||
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
|
||||
recyclerView.setLayoutManager(layoutManager);
|
||||
recyclerView.setHasFixedSize(true);
|
||||
recyclerView.addItemDecoration(new HorizontalDividerItemDecoration.Builder(getActivity()).build());
|
||||
recyclerView.setVisibility(View.GONE);
|
||||
adapter = new EpisodeItemListAdapter((MainActivity) getActivity());
|
||||
recyclerView.setAdapter(adapter);
|
||||
|
||||
emptyViewHandler = new EmptyViewHandler(getContext());
|
||||
emptyViewHandler.attachToListView(listView);
|
||||
emptyViewHandler.attachToRecyclerView(recyclerView);
|
||||
emptyViewHandler.setIcon(R.attr.action_search);
|
||||
emptyViewHandler.setTitle(R.string.search_status_no_results);
|
||||
EventBus.getDefault().register(this);
|
||||
|
@ -124,17 +133,6 @@ public class SearchFragment extends Fragment implements AdapterView.OnItemClickL
|
|||
EventBus.getDefault().unregister(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
FeedComponent comp = searchAdapter.getItem(position);
|
||||
if (comp.getClass() == Feed.class) {
|
||||
((MainActivity) getActivity()).loadFeedFragmentById(comp.getId(), null);
|
||||
} else if (comp.getClass() == FeedItem.class) {
|
||||
FeedItem item = (FeedItem) comp;
|
||||
((MainActivity) getActivity()).loadChildFragment(ItemPagerFragment.newInstance(item.getId()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
|
||||
super.onCreateOptionsMenu(menu, inflater);
|
||||
|
@ -173,42 +171,72 @@ public class SearchFragment extends Fragment implements AdapterView.OnItemClickL
|
|||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onContextItemSelected(@NonNull MenuItem item) {
|
||||
FeedItem selectedItem = adapter.getSelectedItem();
|
||||
if (selectedItem == null) {
|
||||
Log.i(TAG, "Selected item at current position was null, ignoring selection");
|
||||
return super.onContextItemSelected(item);
|
||||
}
|
||||
return FeedItemMenuHandler.onMenuItemClicked(this, item.getItemId(), selectedItem);
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onUnreadItemsChanged(UnreadItemsUpdateEvent event) {
|
||||
search();
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
public void onEventMainThread(FeedItemEvent event) {
|
||||
Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
|
||||
if (results == null) {
|
||||
return;
|
||||
} else if (adapter == null) {
|
||||
search();
|
||||
return;
|
||||
}
|
||||
for (int i = 0, size = event.items.size(); i < size; i++) {
|
||||
FeedItem item = event.items.get(i);
|
||||
int pos = FeedItemUtil.indexOfItemWithId(results, item.getId());
|
||||
if (pos >= 0) {
|
||||
results.remove(pos);
|
||||
results.add(pos, item);
|
||||
adapter.notifyItemChanged(pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
|
||||
public void onEventMainThread(DownloadEvent event) {
|
||||
Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
|
||||
if (searchAdapter != null) {
|
||||
searchAdapter.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private void onSearchResults(List<FeedComponent> results) {
|
||||
progressBar.setVisibility(View.GONE);
|
||||
searchResults = results;
|
||||
searchAdapter.notifyDataSetChanged();
|
||||
String query = getArguments().getString(ARG_QUERY);
|
||||
emptyViewHandler.setMessage(getString(R.string.no_results_for_query, query));
|
||||
}
|
||||
|
||||
private final FeedItemlistAdapter.ItemAccess itemAccess = new FeedItemlistAdapter.ItemAccess() {
|
||||
@Override
|
||||
public int getCount() {
|
||||
return searchResults.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FeedComponent getItem(int position) {
|
||||
if (0 <= position && position < searchResults.size()) {
|
||||
return searchResults.get(position);
|
||||
} else {
|
||||
return null;
|
||||
DownloaderUpdate update = event.update;
|
||||
if (adapter != null && update.mediaIds.length > 0) {
|
||||
for (long mediaId : update.mediaIds) {
|
||||
int pos = FeedItemUtil.indexOfItemWithMediaId(results, mediaId);
|
||||
if (pos >= 0) {
|
||||
adapter.notifyItemChanged(pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
public void onEventMainThread(PlaybackPositionEvent event) {
|
||||
if (adapter != null) {
|
||||
for (int i = 0; i < adapter.getItemCount(); i++) {
|
||||
EpisodeItemViewHolder holder = (EpisodeItemViewHolder) recyclerView.findViewHolderForAdapterPosition(i);
|
||||
if (holder != null && holder.isCurrentlyPlayingItem()) {
|
||||
holder.notifyPlaybackPositionUpdated(event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
public void onPlayerStatusChanged(PlayerStatusEvent event) {
|
||||
search();
|
||||
}
|
||||
|
||||
private void search() {
|
||||
if (disposable != null) {
|
||||
|
@ -219,15 +247,21 @@ public class SearchFragment extends Fragment implements AdapterView.OnItemClickL
|
|||
disposable = Observable.fromCallable(this::performSearch)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(this::onSearchResults, error -> Log.e(TAG, Log.getStackTraceString(error)));
|
||||
.subscribe(results -> {
|
||||
progressBar.setVisibility(View.GONE);
|
||||
this.results = results;
|
||||
adapter.updateItems(results);
|
||||
String query = getArguments().getString(ARG_QUERY);
|
||||
emptyViewHandler.setMessage(getString(R.string.no_results_for_query, query));
|
||||
}, error -> Log.e(TAG, Log.getStackTraceString(error)));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private List<FeedComponent> performSearch() {
|
||||
private List<FeedItem> performSearch() {
|
||||
Bundle args = getArguments();
|
||||
String query = args.getString(ARG_QUERY);
|
||||
long feed = args.getLong(ARG_FEED);
|
||||
Context context = getActivity();
|
||||
return FeedSearcher.performSearch(context, query, feed);
|
||||
return FeedSearcher.searchFeedItems(context, query, feed);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -78,8 +78,13 @@ public class CircularProgressBar extends View {
|
|||
}
|
||||
|
||||
if (Math.abs(percentage - targetPercentage) > EPSILON) {
|
||||
float delta = Math.min(0.02f, Math.abs(targetPercentage - percentage));
|
||||
percentage += delta * ((targetPercentage - percentage) > 0 ? 1f : -1f);
|
||||
float speed = 0.02f;
|
||||
if (Math.abs(targetPercentage - percentage) < 0.1 && targetPercentage > percentage) {
|
||||
speed = 0.006f;
|
||||
}
|
||||
float delta = Math.min(speed, Math.abs(targetPercentage - percentage));
|
||||
float direction = ((targetPercentage - percentage) > 0 ? 1f : -1f);
|
||||
percentage += delta * direction;
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,74 +0,0 @@
|
|||
package de.danoeh.antennapod.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.ListView;
|
||||
import androidx.core.view.NestedScrollingChild;
|
||||
import androidx.core.view.NestedScrollingChildHelper;
|
||||
|
||||
/**
|
||||
* ListView that can be wrapped in NestedScrollView
|
||||
* Based on https://stackoverflow.com/a/34920961.
|
||||
*/
|
||||
public class NestedScrollingListView extends ListView implements NestedScrollingChild {
|
||||
private final NestedScrollingChildHelper nestedScrollingChildHelper;
|
||||
|
||||
public NestedScrollingListView(Context context) {
|
||||
super(context);
|
||||
nestedScrollingChildHelper = new NestedScrollingChildHelper(this);
|
||||
setNestedScrollingEnabled(true);
|
||||
}
|
||||
|
||||
public NestedScrollingListView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
nestedScrollingChildHelper = new NestedScrollingChildHelper(this);
|
||||
setNestedScrollingEnabled(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNestedScrollingEnabled(boolean enabled) {
|
||||
nestedScrollingChildHelper.setNestedScrollingEnabled(enabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNestedScrollingEnabled() {
|
||||
return nestedScrollingChildHelper.isNestedScrollingEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean startNestedScroll(int axes) {
|
||||
return nestedScrollingChildHelper.startNestedScroll(axes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopNestedScroll() {
|
||||
nestedScrollingChildHelper.stopNestedScroll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNestedScrollingParent() {
|
||||
return nestedScrollingChildHelper.hasNestedScrollingParent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed,
|
||||
int dyUnconsumed, int[] offsetInWindow) {
|
||||
return nestedScrollingChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed,
|
||||
dxUnconsumed, dyUnconsumed, offsetInWindow);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) {
|
||||
return nestedScrollingChildHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
|
||||
return nestedScrollingChildHelper.dispatchNestedFling(velocityX, velocityY, consumed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchNestedPreFling(float velocityX, float velocityY) {
|
||||
return nestedScrollingChildHelper.dispatchNestedPreFling(velocityX, velocityY);
|
||||
}
|
||||
}
|
|
@ -1,16 +1,13 @@
|
|||
package de.danoeh.antennapod.view.viewholder;
|
||||
|
||||
import android.graphics.Color;
|
||||
import android.os.Build;
|
||||
import android.text.Layout;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
import androidx.cardview.widget.CardView;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
@ -36,8 +33,7 @@ import de.danoeh.antennapod.view.CircularProgressBar;
|
|||
/**
|
||||
* Holds the view which shows FeedItems.
|
||||
*/
|
||||
public class EpisodeItemViewHolder extends FeedComponentViewHolder
|
||||
implements QueueRecyclerAdapter.ItemTouchHelperViewHolder {
|
||||
public class EpisodeItemViewHolder extends RecyclerView.ViewHolder {
|
||||
private static final String TAG = "EpisodeItemViewHolder";
|
||||
|
||||
private final View container;
|
||||
|
@ -91,16 +87,6 @@ public class EpisodeItemViewHolder extends FeedComponentViewHolder
|
|||
itemView.setTag(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemSelected() {
|
||||
itemView.setAlpha(0.5f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClear() {
|
||||
itemView.setAlpha(1.0f);
|
||||
}
|
||||
|
||||
public void bind(FeedItem item) {
|
||||
this.item = item;
|
||||
placeholder.setText(item.getFeed().getTitle());
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
package de.danoeh.antennapod.view.viewholder;
|
||||
|
||||
import android.view.View;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
/**
|
||||
* Holds the view which shows FeedComponents.
|
||||
*/
|
||||
public class FeedComponentViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
public FeedComponentViewHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
}
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
package de.danoeh.antennapod.view.viewholder;
|
||||
|
||||
import android.os.Build;
|
||||
import android.text.Layout;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import androidx.cardview.widget.CardView;
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.activity.MainActivity;
|
||||
import de.danoeh.antennapod.adapter.CoverLoader;
|
||||
import de.danoeh.antennapod.core.feed.Feed;
|
||||
|
||||
/**
|
||||
* Holds the view which shows feeds.
|
||||
*/
|
||||
public class FeedViewHolder extends FeedComponentViewHolder {
|
||||
private static final String TAG = "FeedViewHolder";
|
||||
|
||||
private final TextView placeholder;
|
||||
private final ImageView cover;
|
||||
private final TextView title;
|
||||
public final CardView coverHolder;
|
||||
|
||||
private final MainActivity activity;
|
||||
private Feed feed;
|
||||
|
||||
public FeedViewHolder(MainActivity activity, ViewGroup parent) {
|
||||
super(LayoutInflater.from(activity).inflate(R.layout.feeditemlist_item, parent, false));
|
||||
this.activity = activity;
|
||||
placeholder = itemView.findViewById(R.id.txtvPlaceholder);
|
||||
cover = itemView.findViewById(R.id.imgvCover);
|
||||
coverHolder = itemView.findViewById(R.id.coverHolder);
|
||||
title = itemView.findViewById(R.id.txtvTitle);
|
||||
if (Build.VERSION.SDK_INT >= 23) {
|
||||
title.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_FULL);
|
||||
}
|
||||
|
||||
itemView.findViewById(R.id.secondaryActionButton).setVisibility(View.GONE);
|
||||
itemView.findViewById(R.id.status).setVisibility(View.GONE);
|
||||
itemView.findViewById(R.id.progress).setVisibility(View.GONE);
|
||||
itemView.findViewById(R.id.drag_handle).setVisibility(View.GONE);
|
||||
itemView.setTag(this);
|
||||
}
|
||||
|
||||
public void bind(Feed feed) {
|
||||
this.feed = feed;
|
||||
placeholder.setText(feed.getTitle());
|
||||
title.setText(feed.getTitle());
|
||||
|
||||
if (coverHolder.getVisibility() == View.VISIBLE) {
|
||||
new CoverLoader(activity)
|
||||
.withUri(feed.getImageLocation())
|
||||
.withPlaceholderView(placeholder)
|
||||
.withCoverView(cover)
|
||||
.load();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -2,7 +2,8 @@
|
|||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_height="match_parent" android:layout_width="match_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
|
@ -11,6 +12,7 @@
|
|||
android:minHeight="?attr/actionBarSize"
|
||||
android:theme="?attr/actionBarTheme"
|
||||
app:title="@string/add_feed_label"
|
||||
app:navigationIcon="?homeAsUpIndicator"
|
||||
android:id="@+id/toolbar"/>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
|
@ -19,8 +21,7 @@
|
|||
app:cardCornerRadius="4dp"
|
||||
app:cardElevation="4dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginTop="16dp">
|
||||
android:layout_marginRight="16dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
@ -39,17 +39,17 @@
|
|||
android:theme="?attr/actionBarTheme"
|
||||
android:layout_alignParentTop="true"
|
||||
android:id="@+id/toolbar"
|
||||
app:navigationIcon="?homeAsUpIndicator"
|
||||
app:layout_collapseMode="pin"/>
|
||||
|
||||
</com.google.android.material.appbar.CollapsingToolbarLayout>
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<de.danoeh.antennapod.view.NestedScrollingListView
|
||||
android:clipToPadding="false"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recyclerView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@android:id/list" />
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progLoading"
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
android:src="?attr/dragview_background"
|
||||
android:paddingEnd="8dp"
|
||||
android:paddingRight="8dp"
|
||||
android:visibility="gone"
|
||||
tools:src="@drawable/ic_drag_vertical_grey600_48dp"
|
||||
tools:background="@android:color/holo_green_dark"/>
|
||||
|
||||
|
|
|
@ -22,9 +22,9 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"/>
|
||||
|
||||
<ListView
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:layout_below="@id/toolbar"
|
||||
android:id="@+id/listview"
|
||||
android:id="@+id/recyclerView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
</RelativeLayout>
|
||||
|
|
|
@ -11,11 +11,12 @@
|
|||
android:layout_alignParentTop="true"
|
||||
android:id="@+id/toolbar"/>
|
||||
|
||||
<ListView android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_below="@id/toolbar"
|
||||
android:id="@android:id/list"
|
||||
android:clipToPadding="false"/>
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_below="@id/toolbar"
|
||||
android:id="@+id/recyclerView"
|
||||
android:clipToPadding="false"/>
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progLoading"
|
||||
|
|
|
@ -54,7 +54,6 @@ import de.danoeh.antennapod.core.event.settings.SpeedPresetChangedEvent;
|
|||
import de.danoeh.antennapod.core.event.settings.VolumeAdaptionChangedEvent;
|
||||
import de.danoeh.antennapod.core.feed.Chapter;
|
||||
import de.danoeh.antennapod.core.feed.Feed;
|
||||
import de.danoeh.antennapod.core.feed.FeedComponent;
|
||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||
import de.danoeh.antennapod.core.feed.FeedMedia;
|
||||
import de.danoeh.antennapod.core.feed.MediaType;
|
||||
|
@ -1649,18 +1648,11 @@ public class PlaybackService extends MediaBrowserServiceCompat {
|
|||
public void onPlayFromSearch(String query, Bundle extras) {
|
||||
Log.d(TAG, "onPlayFromSearch query=" + query + " extras=" + extras.toString());
|
||||
|
||||
List<FeedComponent> results = FeedSearcher.performSearch(getBaseContext(), query, 0);
|
||||
for (FeedComponent result : results) {
|
||||
if (result instanceof FeedItem) {
|
||||
try {
|
||||
FeedMedia media = ((FeedItem) result).getMedia();
|
||||
mediaPlayer.playMediaObject(media, !media.localFileAvailable(), true, true);
|
||||
return;
|
||||
} catch (Exception e) {
|
||||
Log.d(TAG, e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
List<FeedItem> results = FeedSearcher.searchFeedItems(getBaseContext(), query, 0);
|
||||
if (results.size() > 0 && results.get(0).getMedia() != null) {
|
||||
FeedMedia media = results.get(0).getMedia();
|
||||
mediaPlayer.playMediaObject(media, !media.localFileAvailable(), true, true);
|
||||
return;
|
||||
}
|
||||
onPlay();
|
||||
}
|
||||
|
|
|
@ -126,8 +126,6 @@ public class DBWriter {
|
|||
}
|
||||
}
|
||||
EventBus.getDefault().post(FeedItemEvent.deletedMedia(Collections.singletonList(media.getItem())));
|
||||
EventBus.getDefault().post(new UnreadItemsUpdateEvent());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ import de.danoeh.antennapod.core.feed.FeedComponent;
|
|||
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.FutureTask;
|
||||
|
@ -19,32 +20,25 @@ public class FeedSearcher {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Search through a feed, or all feeds, for episodes that match the query in either the title,
|
||||
* chapter, or show notes. The search is first performed on titles, then chapters, and finally
|
||||
* show notes. The list of resulting episodes also describes where the first match occurred
|
||||
* (title, chapters, or show notes).
|
||||
*
|
||||
* @param context Used for database access
|
||||
* @param query search query
|
||||
* @param selectedFeed feed to search, 0 to search through all feeds
|
||||
* @return list of episodes containing the query
|
||||
*/
|
||||
@NonNull
|
||||
public static List<FeedComponent> performSearch(final Context context, final String query, final long selectedFeed) {
|
||||
final List<FeedComponent> result = new ArrayList<>();
|
||||
public static List<FeedItem> searchFeedItems(final Context context, final String query, final long selectedFeed) {
|
||||
try {
|
||||
FutureTask<List<FeedItem>> itemSearchTask = DBTasks.searchFeedItems(context, selectedFeed, query);
|
||||
itemSearchTask.run();
|
||||
if (selectedFeed == 0) {
|
||||
FutureTask<List<Feed>> feedSearchTask = DBTasks.searchFeeds(context, query);
|
||||
feedSearchTask.run();
|
||||
result.addAll(feedSearchTask.get());
|
||||
}
|
||||
result.addAll(itemSearchTask.get());
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
e.printStackTrace();
|
||||
return itemSearchTask.get();
|
||||
} catch (ExecutionException | InterruptedException e) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static List<Feed> searchFeeds(final Context context, final String query) {
|
||||
try {
|
||||
FutureTask<List<Feed>> feedSearchTask = DBTasks.searchFeeds(context, query);
|
||||
feedSearchTask.run();
|
||||
return feedSearchTask.get();
|
||||
} catch (ExecutionException | InterruptedException e) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue