Move common code of list fragments to EpisodesListFragment

This commit is contained in:
ByteHamster 2022-08-06 11:30:58 +02:00
parent 5887a86cec
commit 0f5f4d9e35
8 changed files with 201 additions and 403 deletions

View File

@ -7,80 +7,47 @@ import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.Toolbar;
import com.joanzapata.iconify.Iconify;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.core.event.DownloadEvent;
import de.danoeh.antennapod.core.menuhandler.MenuItemUtils;
import de.danoeh.antennapod.core.service.download.DownloadService;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.dialog.AllEpisodesFilterDialog;
import de.danoeh.antennapod.fragment.swipeactions.SwipeActions;
import de.danoeh.antennapod.model.feed.FeedItem;
import de.danoeh.antennapod.model.feed.FeedItemFilter;
import org.apache.commons.lang3.StringUtils;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import java.util.Collections;
import java.util.List;
/**
* Shows all episodes (possibly filtered by user).
*/
public class AllEpisodesFragment extends EpisodesListFragment implements Toolbar.OnMenuItemClickListener {
public class AllEpisodesFragment extends EpisodesListFragment {
public static final String TAG = "EpisodesFragment";
private static final String PREF_NAME = "PrefAllEpisodesFragment";
private static final String PREF_FILTER = "filter";
private static final String KEY_UP_ARROW = "up_arrow";
private Toolbar toolbar;
private boolean displayUpArrow;
private volatile boolean isUpdatingFeeds;
private SwipeActions swipeActions;
private FeedItemFilter feedItemFilter = new FeedItemFilter("");
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SharedPreferences prefs = getActivity().getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
feedItemFilter = new FeedItemFilter(prefs.getString(PREF_FILTER, ""));
}
@NonNull
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View appEpisodesContainer = View.inflate(getContext(), R.layout.list_container_fragment, null);
View root = super.onCreateView(inflater, container, savedInstanceState);
((FrameLayout) appEpisodesContainer.findViewById(R.id.listContent)).addView(root);
toolbar = appEpisodesContainer.findViewById(R.id.toolbar);
toolbar.setOnMenuItemClickListener(this);
final View root = super.onCreateView(inflater, container, savedInstanceState);
toolbar.inflateMenu(R.menu.episodes);
toolbar.setTitle(R.string.episodes_label);
toolbar.setOnLongClickListener(v -> {
recyclerView.scrollToPosition(5);
recyclerView.post(() -> recyclerView.smoothScrollToPosition(0));
return false;
});
updateToolbar();
displayUpArrow = getParentFragmentManager().getBackStackEntryCount() != 0;
if (savedInstanceState != null) {
displayUpArrow = savedInstanceState.getBoolean(KEY_UP_ARROW);
}
((MainActivity) getActivity()).setupToolbarToggle(toolbar, displayUpArrow);
swipeActions = new SwipeActions(this, TAG).attachTo(recyclerView);
swipeActions.setFilter(feedItemFilter);
updateFilterUi();
speedDialView.removeActionItemById(R.id.mark_unread_batch);
speedDialView.removeActionItemById(R.id.remove_from_queue_batch);
speedDialView.removeActionItemById(R.id.delete_batch);
return appEpisodesContainer;
return root;
}
@Override
protected FeedItemFilter getFilter() {
SharedPreferences prefs = getActivity().getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
return new FeedItemFilter(prefs.getString(PREF_FILTER, ""));
}
@Override
protected String getFragmentTag() {
return TAG;
}
@Override
@ -94,10 +61,10 @@ public class AllEpisodesFragment extends EpisodesListFragment implements Toolbar
return true;
}
if (item.getItemId() == R.id.filter_items) {
AllEpisodesFilterDialog.newInstance(feedItemFilter).show(getChildFragmentManager(), null);
AllEpisodesFilterDialog.newInstance(getFilter()).show(getChildFragmentManager(), null);
return true;
} else if (item.getItemId() == R.id.action_favorites) {
onFilterChanged(new AllEpisodesFilterDialog.AllEpisodesFilterChangedEvent(feedItemFilter.showIsFavorite
onFilterChanged(new AllEpisodesFilterDialog.AllEpisodesFilterChangedEvent(getFilter().showIsFavorite
? Collections.emptySet() : Collections.singleton(FeedItemFilter.IS_FAVORITE)));
return true;
}
@ -106,19 +73,16 @@ public class AllEpisodesFragment extends EpisodesListFragment implements Toolbar
@Subscribe
public void onFilterChanged(AllEpisodesFilterDialog.AllEpisodesFilterChangedEvent event) {
feedItemFilter = new FeedItemFilter(event.filterValues.toArray(new String[0]));
SharedPreferences prefs = getActivity().getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
prefs.edit().putString(PREF_FILTER, StringUtils.join(event.filterValues, ",")).apply();
updateFilterUi();
page = 1;
swipeActions.setFilter(feedItemFilter);
loadItems();
}
@Override
protected void onFragmentLoaded(List<FeedItem> episodes) {
super.onFragmentLoaded(episodes);
if (feedItemFilter.getValues().length > 0) {
private void updateFilterUi() {
swipeActions.setFilter(getFilter());
if (getFilter().getValues().length > 0) {
txtvInformation.setText("{md-info-outline} " + this.getString(R.string.filtered_label));
Iconify.addIcons(txtvInformation);
txtvInformation.setVisibility(View.VISIBLE);
@ -126,57 +90,4 @@ public class AllEpisodesFragment extends EpisodesListFragment implements Toolbar
txtvInformation.setVisibility(View.GONE);
}
}
private final MenuItemUtils.UpdateRefreshMenuItemChecker updateRefreshMenuItemChecker =
() -> DownloadService.isRunning && DownloadService.isDownloadingFeeds();
private void updateToolbar() {
isUpdatingFeeds = MenuItemUtils.updateRefreshMenuItem(toolbar.getMenu(),
R.id.refresh_item, updateRefreshMenuItemChecker);
toolbar.getMenu().findItem(R.id.filter_items).setVisible(true);
}
@Override
public void onStart() {
super.onStart();
if (isUpdatingFeeds != updateRefreshMenuItemChecker.isRefreshing()) {
updateToolbar();
}
}
@Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
public void onEventMainThread(DownloadEvent event) {
super.onEventMainThread(event);
if (event.hasChangedFeedUpdateStatus(isUpdatingFeeds)) {
updateToolbar();
}
}
@Override
protected boolean shouldUpdatedItemRemainInList(FeedItem item) {
return feedItemFilter.matches(item);
}
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
outState.putBoolean(KEY_UP_ARROW, displayUpArrow);
super.onSaveInstanceState(outState);
}
@NonNull
@Override
protected List<FeedItem> loadData() {
return DBReader.getRecentlyPublishedEpisodes(0, page * EPISODES_PER_PAGE, feedItemFilter);
}
@NonNull
@Override
protected List<FeedItem> loadMoreData(int page) {
return DBReader.getRecentlyPublishedEpisodes((page - 1) * EPISODES_PER_PAGE, EPISODES_PER_PAGE, feedItemFilter);
}
@Override
protected int loadTotalItemCount() {
return DBReader.getTotalEpisodeCount(feedItemFilter);
}
}

View File

@ -2,18 +2,11 @@ package de.danoeh.antennapod.fragment;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.ContextMenu;
import android.view.KeyEvent;
import androidx.annotation.NonNull;
import androidx.core.util.Pair;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.SimpleItemAnimator;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.view.ContextMenu;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
@ -21,22 +14,44 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.Toolbar;
import androidx.core.util.Pair;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.SimpleItemAnimator;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import com.google.android.material.snackbar.Snackbar;
import com.leinardi.android.speeddial.SpeedDialView;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.adapter.EpisodeItemListAdapter;
import de.danoeh.antennapod.adapter.SelectableAdapter;
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.menuhandler.MenuItemUtils;
import de.danoeh.antennapod.core.service.download.DownloadService;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.util.FeedItemUtil;
import de.danoeh.antennapod.core.util.download.AutoUpdateManager;
import de.danoeh.antennapod.event.FeedItemEvent;
import de.danoeh.antennapod.event.FeedListUpdateEvent;
import de.danoeh.antennapod.event.playback.PlaybackPositionEvent;
import de.danoeh.antennapod.event.PlayerStatusEvent;
import de.danoeh.antennapod.event.UnreadItemsUpdateEvent;
import de.danoeh.antennapod.core.menuhandler.MenuItemUtils;
import de.danoeh.antennapod.event.playback.PlaybackPositionEvent;
import de.danoeh.antennapod.fragment.actions.EpisodeMultiSelectActionHandler;
import de.danoeh.antennapod.ui.common.PagedToolbarFragment;
import de.danoeh.antennapod.fragment.swipeactions.SwipeActions;
import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
import de.danoeh.antennapod.model.feed.FeedItem;
import de.danoeh.antennapod.model.feed.FeedItemFilter;
import de.danoeh.antennapod.view.EmptyViewHandler;
import de.danoeh.antennapod.view.EpisodeItemListRecyclerView;
import de.danoeh.antennapod.view.viewholder.EpisodeItemViewHolder;
import io.reactivex.Completable;
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;
@ -44,34 +59,18 @@ import org.greenrobot.eventbus.ThreadMode;
import java.util.ArrayList;
import java.util.List;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
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.event.FeedItemEvent;
import de.danoeh.antennapod.model.feed.FeedItem;
import de.danoeh.antennapod.core.service.download.DownloadService;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.util.FeedItemUtil;
import de.danoeh.antennapod.core.util.download.AutoUpdateManager;
import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
import de.danoeh.antennapod.view.EmptyViewHandler;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
/**
* Shows unread or recently published episodes
*/
public abstract class EpisodesListFragment extends Fragment implements EpisodeItemListAdapter.OnSelectModeListener {
public abstract class EpisodesListFragment extends Fragment
implements EpisodeItemListAdapter.OnSelectModeListener, Toolbar.OnMenuItemClickListener {
public static final String TAG = "EpisodesListFragment";
private static final String KEY_UP_ARROW = "up_arrow";
protected static final int EPISODES_PER_PAGE = 150;
protected int page = 1;
protected boolean isLoadingMore = false;
protected boolean hasMoreItems = true;
private boolean displayUpArrow;
EpisodeItemListRecyclerView recyclerView;
EpisodeItemListAdapter listAdapter;
@ -79,6 +78,8 @@ public abstract class EpisodesListFragment extends Fragment implements EpisodeIt
View loadingMoreView;
EmptyViewHandler emptyView;
SpeedDialView speedDialView;
Toolbar toolbar;
SwipeActions swipeActions;
@NonNull
List<FeedItem> episodes = new ArrayList<>();
@ -87,9 +88,6 @@ public abstract class EpisodesListFragment extends Fragment implements EpisodeIt
protected Disposable disposable;
protected TextView txtvInformation;
String getPrefName() {
return TAG;
}
@Override
public void onStart() {
@ -137,21 +135,6 @@ public abstract class EpisodesListFragment extends Fragment implements EpisodeIt
if (itemId == R.id.refresh_item) {
AutoUpdateManager.runImmediate(requireContext());
return true;
} else if (itemId == R.id.remove_all_inbox_item) {
ConfirmationDialog removeAllNewFlagsConfirmationDialog = new ConfirmationDialog(getActivity(),
R.string.remove_all_inbox_label,
R.string.remove_all_inbox_confirmation_msg) {
@Override
public void onConfirmButtonPressed(DialogInterface dialog) {
dialog.dismiss();
DBWriter.removeAllNewFlags();
((MainActivity) getActivity()).showSnackbarAbovePlayer(
R.string.removed_all_inbox_msg, Toast.LENGTH_SHORT);
}
};
removeAllNewFlagsConfirmationDialog.createNewDialog().show();
return true;
} else if (itemId == R.id.action_search) {
((MainActivity) getActivity()).loadChildFragment(SearchFragment.newInstance());
return true;
@ -180,13 +163,28 @@ public abstract class EpisodesListFragment extends Fragment implements EpisodeIt
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View root = inflater.inflate(R.layout.all_episodes_fragment, container, false);
View root = inflater.inflate(R.layout.episodes_list_fragment, container, false);
txtvInformation = root.findViewById(R.id.txtvInformation);
toolbar = root.findViewById(R.id.toolbar);
toolbar.setOnMenuItemClickListener(this);
toolbar.setOnLongClickListener(v -> {
recyclerView.scrollToPosition(5);
recyclerView.post(() -> recyclerView.smoothScrollToPosition(0));
return false;
});
displayUpArrow = getParentFragmentManager().getBackStackEntryCount() != 0;
if (savedInstanceState != null) {
displayUpArrow = savedInstanceState.getBoolean(KEY_UP_ARROW);
}
((MainActivity) getActivity()).setupToolbarToggle(toolbar, displayUpArrow);
recyclerView = root.findViewById(android.R.id.list);
recyclerView.setRecycledViewPool(((MainActivity) getActivity()).getRecycledViewPool());
setupLoadMoreScrollListener();
swipeActions = new SwipeActions(this, getFragmentTag()).attachTo(recyclerView);
swipeActions.setFilter(getFilter());
RecyclerView.ItemAnimator animator = recyclerView.getItemAnimator();
if (animator instanceof SimpleItemAnimator) {
((SimpleItemAnimator) animator).setSupportsChangeAnimations(false);
@ -308,7 +306,7 @@ public abstract class EpisodesListFragment extends Fragment implements EpisodeIt
hasMoreItems = false;
}
episodes.addAll(data);
onFragmentLoaded(episodes);
updateAdapterWithNewItems();
if (listAdapter.shouldSelectLazyLoadedItems()) {
listAdapter.setSelected(episodes.size() - data.size(), episodes.size(), true);
}
@ -320,7 +318,7 @@ public abstract class EpisodesListFragment extends Fragment implements EpisodeIt
});
}
protected void onFragmentLoaded(List<FeedItem> episodes) {
protected void updateAdapterWithNewItems() {
boolean restoreScrollPosition = listAdapter.getItemCount() == 0;
if (episodes.size() == 0) {
createRecycleAdapter(recyclerView, emptyView);
@ -330,10 +328,6 @@ public abstract class EpisodesListFragment extends Fragment implements EpisodeIt
if (restoreScrollPosition) {
recyclerView.restoreScrollPosition(getPrefName());
}
if (isUpdatingFeeds != updateRefreshMenuItemChecker.isRefreshing()
&& getParentFragment() instanceof PagedToolbarFragment) {
((PagedToolbarFragment) getParentFragment()).invalidateOptionsMenuIfActive(this);
}
}
/**
@ -385,7 +379,7 @@ public abstract class EpisodesListFragment extends Fragment implements EpisodeIt
int pos = FeedItemUtil.indexOfItemWithId(episodes, item.getId());
if (pos >= 0) {
episodes.remove(pos);
if (shouldUpdatedItemRemainInList(item)) {
if (getFilter().matches(item)) {
episodes.add(pos, item);
listAdapter.notifyItemChangedCompat(pos);
} else {
@ -425,16 +419,12 @@ public abstract class EpisodesListFragment extends Fragment implements EpisodeIt
}
}
protected boolean shouldUpdatedItemRemainInList(FeedItem item) {
return true;
}
@Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
public void onEventMainThread(DownloadEvent event) {
Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
DownloaderUpdate update = event.update;
if (event.hasChangedFeedUpdateStatus(isUpdatingFeeds) && getParentFragment() instanceof PagedToolbarFragment) {
((PagedToolbarFragment) getParentFragment()).invalidateOptionsMenuIfActive(this);
if (event.hasChangedFeedUpdateStatus(isUpdatingFeeds)) {
updateToolbar();
}
if (update.mediaIds.length > 0) {
for (long mediaId : update.mediaIds) {
@ -448,9 +438,8 @@ public abstract class EpisodesListFragment extends Fragment implements EpisodeIt
private void updateUi() {
loadItems();
if (isUpdatingFeeds != updateRefreshMenuItemChecker.isRefreshing()
&& getParentFragment() instanceof PagedToolbarFragment) {
((PagedToolbarFragment) getParentFragment()).invalidateOptionsMenuIfActive(this);
if (isUpdatingFeeds != updateRefreshMenuItemChecker.isRefreshing()) {
updateToolbar();
}
}
@ -481,32 +470,41 @@ public abstract class EpisodesListFragment extends Fragment implements EpisodeIt
loadingMoreView.setVisibility(View.GONE);
hasMoreItems = true;
episodes = data.first;
listAdapter.notifyDataSetChanged();
listAdapter.setTotalNumberOfItems(data.second);
onFragmentLoaded(episodes);
if (getParentFragment() instanceof PagedToolbarFragment) {
((PagedToolbarFragment) getParentFragment()).invalidateOptionsMenuIfActive(this);
}
updateAdapterWithNewItems();
updateToolbar();
}, error -> Log.e(TAG, Log.getStackTraceString(error)));
}
@NonNull
protected abstract List<FeedItem> loadData();
protected List<FeedItem> loadData() {
return DBReader.getRecentlyPublishedEpisodes(0, page * EPISODES_PER_PAGE, getFilter());
}
/**
* Load a new page of data as defined by {@link #page} and {@link #EPISODES_PER_PAGE}.
* If the number of items returned is less than {@link #EPISODES_PER_PAGE},
* it will be assumed that the underlying data is exhausted
* and this method will not be called again.
*
* @return The items from the next page of data
*/
@NonNull
protected abstract List<FeedItem> loadMoreData(int page);
protected List<FeedItem> loadMoreData(int page) {
return DBReader.getRecentlyPublishedEpisodes((page - 1) * EPISODES_PER_PAGE, EPISODES_PER_PAGE, getFilter());
}
/**
* Returns the total number of items that would be returned if {@link #loadMoreData} was called often enough.
*/
protected int loadTotalItemCount() {
return SelectableAdapter.COUNT_AUTOMATICALLY;
return DBReader.getTotalEpisodeCount(getFilter());
}
protected abstract FeedItemFilter getFilter();
protected abstract String getFragmentTag();
protected abstract String getPrefName();
protected void updateToolbar() {
isUpdatingFeeds = MenuItemUtils.updateRefreshMenuItem(toolbar.getMenu(),
R.id.refresh_item, updateRefreshMenuItemChecker);
}
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
outState.putBoolean(KEY_UP_ARROW, displayUpArrow);
super.onSaveInstanceState(outState);
}
}

View File

@ -1,116 +1,84 @@
package de.danoeh.antennapod.fragment;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.MenuItem;
import android.widget.FrameLayout;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.Toolbar;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import java.util.List;
import android.widget.Toast;
import androidx.annotation.NonNull;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.core.event.DownloadEvent;
import de.danoeh.antennapod.core.menuhandler.MenuItemUtils;
import de.danoeh.antennapod.core.service.download.DownloadService;
import de.danoeh.antennapod.fragment.swipeactions.SwipeActions;
import de.danoeh.antennapod.model.feed.FeedItem;
import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.model.feed.FeedItem;
import de.danoeh.antennapod.model.feed.FeedItemFilter;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import java.util.List;
/**
* Like 'EpisodesFragment' except that it only shows new episodes and
* supports swiping to mark as read.
*/
public class InboxFragment extends EpisodesListFragment implements Toolbar.OnMenuItemClickListener {
public class InboxFragment extends EpisodesListFragment {
public static final String TAG = "NewEpisodesFragment";
private static final String PREF_NAME = "PrefNewEpisodesFragment";
private static final String KEY_UP_ARROW = "up_arrow";
private Toolbar toolbar;
private boolean displayUpArrow;
private volatile boolean isUpdatingFeeds;
@NonNull
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View root = super.onCreateView(inflater, container, savedInstanceState);
toolbar.inflateMenu(R.menu.inbox);
toolbar.setTitle(R.string.inbox_label);
updateToolbar();
emptyView.setIcon(R.drawable.ic_inbox);
emptyView.setTitle(R.string.no_inbox_head_label);
emptyView.setMessage(R.string.no_inbox_label);
speedDialView.removeActionItemById(R.id.mark_unread_batch);
speedDialView.removeActionItemById(R.id.remove_from_queue_batch);
speedDialView.removeActionItemById(R.id.delete_batch);
return root;
}
@Override
protected FeedItemFilter getFilter() {
return new FeedItemFilter(FeedItemFilter.NEW);
}
@Override
protected String getFragmentTag() {
return TAG;
}
@Override
protected String getPrefName() {
return PREF_NAME;
}
@Override
protected boolean shouldUpdatedItemRemainInList(FeedItem item) {
return item.isNew();
}
@NonNull
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View inboxContainer = View.inflate(getContext(), R.layout.list_container_fragment, null);
View root = super.onCreateView(inflater, container, savedInstanceState);
((FrameLayout) inboxContainer.findViewById(R.id.listContent)).addView(root);
emptyView.setTitle(R.string.no_inbox_head_label);
emptyView.setMessage(R.string.no_inbox_label);
toolbar = inboxContainer.findViewById(R.id.toolbar);
toolbar.setOnMenuItemClickListener(this);
toolbar.inflateMenu(R.menu.inbox);
toolbar.setOnLongClickListener(v -> {
recyclerView.scrollToPosition(5);
recyclerView.post(() -> recyclerView.smoothScrollToPosition(0));
return false;
});
displayUpArrow = getParentFragmentManager().getBackStackEntryCount() != 0;
if (savedInstanceState != null) {
displayUpArrow = savedInstanceState.getBoolean(KEY_UP_ARROW);
}
((MainActivity) getActivity()).setupToolbarToggle(toolbar, displayUpArrow);
SwipeActions swipeActions = new SwipeActions(this, TAG).attachTo(recyclerView);
swipeActions.setFilter(new FeedItemFilter(FeedItemFilter.NEW));
speedDialView.removeActionItemById(R.id.mark_unread_batch);
speedDialView.removeActionItemById(R.id.remove_from_queue_batch);
speedDialView.removeActionItemById(R.id.delete_batch);
return inboxContainer;
}
private final MenuItemUtils.UpdateRefreshMenuItemChecker updateRefreshMenuItemChecker =
() -> DownloadService.isRunning && DownloadService.isDownloadingFeeds();
private void updateToolbar() {
isUpdatingFeeds = MenuItemUtils.updateRefreshMenuItem(toolbar.getMenu(),
R.id.refresh_item, updateRefreshMenuItemChecker);
}
@Override
public void onStart() {
super.onStart();
if (isUpdatingFeeds != updateRefreshMenuItemChecker.isRefreshing()) {
updateToolbar();
}
}
@Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
public void onEventMainThread(DownloadEvent event) {
super.onEventMainThread(event);
if (event.hasChangedFeedUpdateStatus(isUpdatingFeeds)) {
updateToolbar();
}
}
@Override
public boolean onMenuItemClick(MenuItem item) {
return super.onOptionsItemSelected(item);
if (super.onOptionsItemSelected(item)) {
return true;
}
if (item.getItemId() == R.id.remove_all_inbox_item) {
ConfirmationDialog removeAllNewFlagsConfirmationDialog = new ConfirmationDialog(getActivity(),
R.string.remove_all_inbox_label,
R.string.remove_all_inbox_confirmation_msg) {
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
outState.putBoolean(KEY_UP_ARROW, displayUpArrow);
super.onSaveInstanceState(outState);
public void onConfirmButtonPressed(DialogInterface dialog) {
dialog.dismiss();
DBWriter.removeAllNewFlags();
((MainActivity) getActivity()).showSnackbarAbovePlayer(
R.string.removed_all_inbox_msg, Toast.LENGTH_SHORT);
}
};
removeAllNewFlagsConfirmationDialog.createNewDialog().show();
return true;
}
return false;
}
@NonNull

View File

@ -1,92 +1,59 @@
package de.danoeh.antennapod.fragment;
import android.os.Bundle;
import android.view.ContextMenu;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.Toolbar;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.adapter.EpisodeItemListAdapter;
import de.danoeh.antennapod.core.menuhandler.MenuItemUtils;
import de.danoeh.antennapod.event.playback.PlaybackHistoryEvent;
import de.danoeh.antennapod.event.PlayerStatusEvent;
import de.danoeh.antennapod.event.UnreadItemsUpdateEvent;
import de.danoeh.antennapod.model.feed.FeedItem;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.event.playback.PlaybackHistoryEvent;
import de.danoeh.antennapod.model.feed.FeedItem;
import de.danoeh.antennapod.model.feed.FeedItemFilter;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import java.util.List;
public class PlaybackHistoryFragment extends EpisodesListFragment implements Toolbar.OnMenuItemClickListener {
public class PlaybackHistoryFragment extends EpisodesListFragment {
public static final String TAG = "PlaybackHistoryFragment";
private static final String KEY_UP_ARROW = "up_arrow";
private Toolbar toolbar;
private boolean displayUpArrow;
@NonNull
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
View historyContainer = View.inflate(getContext(), R.layout.list_container_fragment, null);
View root = super.onCreateView(inflater, container, savedInstanceState);
((FrameLayout) historyContainer.findViewById(R.id.listContent)).addView(root);
toolbar = historyContainer.findViewById(R.id.toolbar);
toolbar.setTitle(R.string.playback_history_label);
toolbar.setOnMenuItemClickListener(this);
toolbar.setOnLongClickListener(v -> {
recyclerView.scrollToPosition(5);
recyclerView.post(() -> recyclerView.smoothScrollToPosition(0));
return false;
});
displayUpArrow = getParentFragmentManager().getBackStackEntryCount() != 0;
if (savedInstanceState != null) {
displayUpArrow = savedInstanceState.getBoolean(KEY_UP_ARROW);
}
((MainActivity) getActivity()).setupToolbarToggle(toolbar, displayUpArrow);
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View root = super.onCreateView(inflater, container, savedInstanceState);
toolbar.inflateMenu(R.menu.playback_history);
refreshToolbarState();
listAdapter = new PlaybackHistoryListAdapter((MainActivity) getActivity());
recyclerView.setAdapter(listAdapter);
toolbar.setTitle(R.string.playback_history_label);
updateToolbar();
emptyView.setIcon(R.drawable.ic_history);
emptyView.setTitle(R.string.no_history_head_label);
emptyView.setMessage(R.string.no_history_label);
return historyContainer;
swipeActions.detach();
return root;
}
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
outState.putBoolean(KEY_UP_ARROW, displayUpArrow);
super.onSaveInstanceState(outState);
protected FeedItemFilter getFilter() {
return FeedItemFilter.unfiltered();
}
public void refreshToolbarState() {
boolean hasHistory = episodes != null && !episodes.isEmpty();
toolbar.getMenu().findItem(R.id.clear_history_item).setVisible(hasHistory);
@Override
protected String getFragmentTag() {
return TAG;
}
@Override
protected String getPrefName() {
return TAG;
}
@Override
public boolean onMenuItemClick(MenuItem item) {
if (super.onOptionsItemSelected(item)) {
return true;
}
if (item.getItemId() == R.id.clear_history_item) {
DBWriter.clearPlaybackHistory();
return true;
@ -94,43 +61,16 @@ public class PlaybackHistoryFragment extends EpisodesListFragment implements Too
return false;
}
@Override
protected void updateToolbar() {
// Not calling super, as we do not have a refresh button that could be updated
toolbar.getMenu().findItem(R.id.clear_history_item).setVisible(!episodes.isEmpty());
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onHistoryUpdated(PlaybackHistoryEvent event) {
loadItems();
refreshToolbarState();
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onPlayerStatusChanged(PlayerStatusEvent event) {
loadItems();
refreshToolbarState();
}
@Override
@Subscribe(threadMode = ThreadMode.MAIN)
public void onUnreadItemsChanged(UnreadItemsUpdateEvent event) {
loadItems();
refreshToolbarState();
}
@Override
protected void onFragmentLoaded(List<FeedItem> episodes) {
super.onFragmentLoaded(episodes);
listAdapter.notifyDataSetChanged();
refreshToolbarState();
}
private class PlaybackHistoryListAdapter extends EpisodeItemListAdapter {
public PlaybackHistoryListAdapter(MainActivity mainActivity) {
super(mainActivity);
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
MenuItemUtils.setOnClickListeners(menu, PlaybackHistoryFragment.this::onContextItemSelected);
}
updateToolbar();
}
@NonNull

View File

@ -6,11 +6,20 @@
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:minHeight="?attr/actionBarSize"
android:theme="?attr/actionBarTheme" />
<TextView
android:id="@+id/txtvInformation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_below="@id/toolbar"
android:paddingTop="2dp"
android:paddingBottom="2dp"
android:visibility="gone"

View File

@ -1,23 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:minHeight="?attr/actionBarSize"
android:theme="?attr/actionBarTheme"
app:title="@string/inbox_label" />
<FrameLayout
android:id="@+id/listContent"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/toolbar" />
</RelativeLayout>

View File

@ -21,7 +21,6 @@
android:icon="@drawable/ic_filter"
android:menuCategory="container"
android:title="@string/filter"
android:visible="false"
custom:showAsAction="always"/>
<item

View File

@ -72,10 +72,6 @@ public class FeedItemFilter implements Serializable {
return properties.clone();
}
public boolean isShowDownloaded() {
return showDownloaded;
}
public boolean matches(FeedItem item) {
if (showNew && !item.isNew()) {
return false;