Merge pull request #6048 from ByteHamster/loading-dummy

Use dummy items instead of loading progress bar
This commit is contained in:
ByteHamster 2022-09-10 11:58:01 +02:00 committed by GitHub
commit a63948ec6d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 256 additions and 365 deletions

View File

@ -52,6 +52,7 @@ public class SubscriptionsRecyclerAdapter extends SelectableAdapter<Subscription
private List<NavDrawerData.DrawerItem> listItems;
private NavDrawerData.DrawerItem selectedItem = null;
int longPressedPosition = 0; // used to init actionMode
private int dummyViews = 0;
public SubscriptionsRecyclerAdapter(MainActivity mainActivity) {
super(mainActivity);
@ -95,6 +96,11 @@ public class SubscriptionsRecyclerAdapter extends SelectableAdapter<Subscription
@Override
public void onBindViewHolder(@NonNull SubscriptionViewHolder holder, int position) {
if (position >= listItems.size()) {
holder.selectView.setVisibility(View.GONE);
holder.bindDummy();
return;
}
NavDrawerData.DrawerItem drawerItem = listItems.get(position);
boolean isFeed = drawerItem.type == NavDrawerData.DrawerItem.Type.FEED;
holder.bind(drawerItem);
@ -157,11 +163,14 @@ public class SubscriptionsRecyclerAdapter extends SelectableAdapter<Subscription
@Override
public int getItemCount() {
return listItems.size();
return listItems.size() + dummyViews;
}
@Override
public long getItemId(int position) {
if (position >= listItems.size()) {
return RecyclerView.NO_ID; // Dummy views
}
return listItems.get(position).id;
}
@ -202,6 +211,10 @@ public class SubscriptionsRecyclerAdapter extends SelectableAdapter<Subscription
return items;
}
public void setDummyViews(int dummyViews) {
this.dummyViews = dummyViews;
}
public void setItems(List<NavDrawerData.DrawerItem> listItems) {
this.listItems = listItems;
}
@ -270,6 +283,17 @@ public class SubscriptionsRecyclerAdapter extends SelectableAdapter<Subscription
.load();
}
}
public void bindDummy() {
feedTitle.setText("███████");
feedTitle.setVisibility(View.VISIBLE);
count.setVisibility(View.GONE);
new CoverLoader(mainActivityRef.get())
.withResource(android.R.color.transparent)
.withPlaceholderView(feedTitle, false)
.withCoverView(imageView)
.load();
}
}
public static float convertDpToPixel(Context context, float dp) {

View File

@ -1,5 +1,6 @@
package de.danoeh.antennapod.fragment;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.ContextMenu;
@ -7,7 +8,6 @@ import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ProgressBar;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.Toolbar;
@ -46,6 +46,7 @@ import org.greenrobot.eventbus.ThreadMode;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
@ -56,12 +57,12 @@ public class CompletedDownloadsFragment extends Fragment
public static final String TAG = "DownloadsFragment";
public static final String ARG_SHOW_LOGS = "show_logs";
private static final String KEY_UP_ARROW = "up_arrow";
private static final String PREF_PREVIOUS_EPISODE_COUNT = "episodeCount";
private long[] runningDownloads = new long[0];
private List<FeedItem> items = new ArrayList<>();
private CompletedDownloadsListAdapter adapter;
private EpisodeItemListRecyclerView recyclerView;
private ProgressBar progressBar;
private Disposable disposable;
private EmptyViewHandler emptyView;
private boolean displayUpArrow;
@ -91,11 +92,12 @@ public class CompletedDownloadsFragment extends Fragment
recyclerView.setRecycledViewPool(((MainActivity) getActivity()).getRecycledViewPool());
adapter = new CompletedDownloadsListAdapter((MainActivity) getActivity());
adapter.setOnSelectModeListener(this);
int previousEpisodesCount = getContext().getSharedPreferences(TAG, Context.MODE_PRIVATE)
.getInt(PREF_PREVIOUS_EPISODE_COUNT, 5);
adapter.setDummyViews(Math.max(1, previousEpisodesCount));
recyclerView.setAdapter(adapter);
swipeActions = new SwipeActions(this, TAG).attachTo(recyclerView);
swipeActions.setFilter(new FeedItemFilter(FeedItemFilter.DOWNLOADED));
progressBar = root.findViewById(R.id.progLoading);
progressBar.setVisibility(View.VISIBLE);
speedDialView = root.findViewById(R.id.fabSD);
speedDialView.setOverlayLayout(root.findViewById(R.id.fabSDOverlay));
@ -159,6 +161,9 @@ public class CompletedDownloadsFragment extends Fragment
if (disposable != null) {
disposable.dispose();
}
getContext().getSharedPreferences(TAG, Context.MODE_PRIVATE).edit()
.putInt(PREF_PREVIOUS_EPISODE_COUNT, adapter.getItemCount())
.apply();
}
@Override
@ -291,11 +296,16 @@ public class CompletedDownloadsFragment extends Fragment
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
items = result;
adapter.updateItems(result);
progressBar.setVisibility(View.GONE);
}, error -> Log.e(TAG, Log.getStackTraceString(error)));
.subscribe(
result -> {
items = result;
adapter.setDummyViews(0);
adapter.updateItems(result);
}, error -> {
adapter.setDummyViews(0);
adapter.updateItems(Collections.emptyList());
Log.e(TAG, Log.getStackTraceString(error));
});
}
@Override

View File

@ -1,5 +1,6 @@
package de.danoeh.antennapod.fragment;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.Handler;
@ -11,7 +12,6 @@ import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.Toolbar;
@ -56,6 +56,7 @@ import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
@ -65,16 +66,15 @@ 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";
private static final String PREF_PREVIOUS_EPISODE_COUNT = "episodeCount";
protected static final int EPISODES_PER_PAGE = 150;
protected int page = 1;
protected boolean isLoadingMore = false;
protected boolean hasMoreItems = true;
protected boolean hasMoreItems = false;
private boolean displayUpArrow;
EpisodeItemListRecyclerView recyclerView;
EpisodeItemListAdapter listAdapter;
ProgressBar progLoading;
View loadingMoreView;
EmptyViewHandler emptyView;
SpeedDialView speedDialView;
Toolbar toolbar;
@ -113,6 +113,9 @@ public abstract class EpisodesListFragment extends Fragment
if (disposable != null) {
disposable.dispose();
}
getContext().getSharedPreferences(getPrefName(), Context.MODE_PRIVATE).edit()
.putInt(PREF_PREVIOUS_EPISODE_COUNT, episodes.size())
.apply();
}
@Override
@ -187,17 +190,28 @@ public abstract class EpisodesListFragment extends Fragment
getResources().getInteger(R.integer.swipe_to_refresh_duration_in_ms));
});
progLoading = root.findViewById(R.id.progLoading);
progLoading.setVisibility(View.VISIBLE);
loadingMoreView = root.findViewById(R.id.loadingMore);
listAdapter = new EpisodeItemListAdapter((MainActivity) getActivity()) {
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
if (!inActionMode()) {
menu.findItem(R.id.multi_select).setVisible(true);
}
MenuItemUtils.setOnClickListeners(menu, EpisodesListFragment.this::onContextItemSelected);
}
};
listAdapter.setOnSelectModeListener(this);
int previousEpisodesCount = getContext().getSharedPreferences(getPrefName(), Context.MODE_PRIVATE)
.getInt(PREF_PREVIOUS_EPISODE_COUNT, 5);
listAdapter.setDummyViews(Math.max(1, previousEpisodesCount));
recyclerView.setAdapter(listAdapter);
emptyView = new EmptyViewHandler(getContext());
emptyView.attachToRecyclerView(recyclerView);
emptyView.setIcon(R.drawable.ic_feed);
emptyView.setTitle(R.string.no_all_episodes_head_label);
emptyView.setMessage(R.string.no_all_episodes_label);
createRecycleAdapter(recyclerView, emptyView);
emptyView.updateAdapter(listAdapter);
emptyView.hide();
speedDialView = root.findViewById(R.id.fabSD);
@ -286,68 +300,36 @@ public abstract class EpisodesListFragment extends Fragment
disposable.dispose();
}
isLoadingMore = true;
loadingMoreView.setVisibility(View.VISIBLE);
listAdapter.setDummyViews(1);
listAdapter.notifyItemInserted(listAdapter.getItemCount() - 1);
disposable = Observable.fromCallable(() -> loadMoreData(page))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(data -> {
if (data.size() < EPISODES_PER_PAGE) {
hasMoreItems = false;
}
episodes.addAll(data);
updateAdapterWithNewItems();
if (listAdapter.shouldSelectLazyLoadedItems()) {
listAdapter.setSelected(episodes.size() - data.size(), episodes.size(), true);
}
}, error -> Log.e(TAG, Log.getStackTraceString(error)),
() -> {
recyclerView.post(() -> isLoadingMore = false); // Make sure to not always load 2 pages at once
progLoading.setVisibility(View.GONE);
loadingMoreView.setVisibility(View.GONE);
});
}
protected void updateAdapterWithNewItems() {
boolean restoreScrollPosition = listAdapter.getItemCount() == 0;
if (episodes.size() == 0) {
createRecycleAdapter(recyclerView, emptyView);
} else {
listAdapter.updateItems(episodes);
}
if (restoreScrollPosition) {
recyclerView.restoreScrollPosition(getPrefName());
}
}
/**
* Currently, we need to recreate the list adapter in order to be able to undo last item via the
* snackbar. See #3084 for details.
*/
private void createRecycleAdapter(RecyclerView recyclerView, EmptyViewHandler emptyViewHandler) {
MainActivity mainActivity = (MainActivity) getActivity();
listAdapter = new EpisodeItemListAdapter(mainActivity) {
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
if (!inActionMode()) {
menu.findItem(R.id.multi_select).setVisible(true);
}
MenuItemUtils.setOnClickListeners(menu, EpisodesListFragment.this::onContextItemSelected);
}
};
listAdapter.setOnSelectModeListener(this);
listAdapter.updateItems(episodes);
recyclerView.setAdapter(listAdapter);
emptyViewHandler.updateAdapter(listAdapter);
.subscribe(
data -> {
if (data.size() < EPISODES_PER_PAGE) {
hasMoreItems = false;
}
episodes.addAll(data);
listAdapter.setDummyViews(0);
listAdapter.updateItems(episodes);
if (listAdapter.shouldSelectLazyLoadedItems()) {
listAdapter.setSelected(episodes.size() - data.size(), episodes.size(), true);
}
}, error -> {
listAdapter.setDummyViews(0);
listAdapter.updateItems(Collections.emptyList());
Log.e(TAG, Log.getStackTraceString(error));
}, () -> {
// Make sure to not always load 2 pages at once
recyclerView.post(() -> isLoadingMore = false);
});
}
@Override
public void onDestroyView() {
super.onDestroyView();
if (listAdapter != null) {
listAdapter.endSelectMode();
}
listAdapter = null;
listAdapter.endSelectMode();
}
@Override
@ -380,13 +362,11 @@ public abstract class EpisodesListFragment extends Fragment
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEventMainThread(PlaybackPositionEvent event) {
if (listAdapter != null) {
for (int i = 0; i < listAdapter.getItemCount(); i++) {
EpisodeItemViewHolder holder = (EpisodeItemViewHolder) recyclerView.findViewHolderForAdapterPosition(i);
if (holder != null && holder.isCurrentlyPlayingItem()) {
holder.notifyPlaybackPositionUpdated(event);
break;
}
for (int i = 0; i < listAdapter.getItemCount(); i++) {
EpisodeItemViewHolder holder = (EpisodeItemViewHolder) recyclerView.findViewHolderForAdapterPosition(i);
if (holder != null && holder.isCurrentlyPlayingItem()) {
holder.notifyPlaybackPositionUpdated(event);
break;
}
}
}
@ -445,16 +425,20 @@ public abstract class EpisodesListFragment extends Fragment
disposable = Observable.fromCallable(() -> new Pair<>(loadData(), loadTotalItemCount()))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(data -> {
progLoading.setVisibility(View.GONE);
loadingMoreView.setVisibility(View.GONE);
hasMoreItems = true;
episodes = data.first;
listAdapter.notifyDataSetChanged();
listAdapter.setTotalNumberOfItems(data.second);
updateAdapterWithNewItems();
updateToolbar();
}, error -> Log.e(TAG, Log.getStackTraceString(error)));
.subscribe(
data -> {
episodes = data.first;
hasMoreItems = !(page == 1 && episodes.size() < EPISODES_PER_PAGE);
listAdapter.setDummyViews(0);
listAdapter.updateItems(episodes);
listAdapter.setTotalNumberOfItems(data.second);
recyclerView.restoreScrollPosition(getPrefName());
updateToolbar();
}, error -> {
listAdapter.setDummyViews(0);
listAdapter.updateItems(Collections.emptyList());
Log.e(TAG, Log.getStackTraceString(error));
});
}
@NonNull

View File

@ -74,6 +74,7 @@ import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import java.util.Collections;
import java.util.List;
/**
@ -142,7 +143,12 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
updateToolbar();
viewBinding.recyclerView.setRecycledViewPool(((MainActivity) getActivity()).getRecycledViewPool());
viewBinding.progLoading.setVisibility(View.VISIBLE);
adapter = new FeedItemListAdapter((MainActivity) getActivity());
adapter.setOnSelectModeListener(this);
adapter.setDummyViews(10);
viewBinding.recyclerView.setAdapter(adapter);
swipeActions = new SwipeActions(this, TAG).attachTo(viewBinding.recyclerView);
ToolbarIconTintManager iconTintManager = new ToolbarIconTintManager(
getContext(), viewBinding.toolbar, viewBinding.collapsingToolbar) {
@Override
@ -221,10 +227,7 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
if (disposable != null) {
disposable.dispose();
}
if (adapter != null) {
adapter.endSelectMode();
}
adapter = null;
adapter.endSelectMode();
}
@Override
@ -294,9 +297,6 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (adapter == null) {
return;
}
MainActivity activity = (MainActivity) getActivity();
long[] ids = FeedItemUtil.getIds(feed.getItems());
activity.loadChildFragment(ItemPagerFragment.newInstance(ids, position));
@ -315,9 +315,6 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
if (feed == null || feed.getItems() == 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);
@ -335,7 +332,7 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
DownloaderUpdate update = event.update;
updateToolbar();
if (adapter != null && update.mediaIds.length > 0 && feed != null) {
if (update.mediaIds.length > 0 && feed != null) {
for (long mediaId : update.mediaIds) {
int pos = FeedItemUtil.indexOfItemWithMediaId(feed.getItems(), mediaId);
if (pos >= 0) {
@ -347,14 +344,12 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEventMainThread(PlaybackPositionEvent event) {
if (adapter != null) {
for (int i = 0; i < adapter.getItemCount(); i++) {
EpisodeItemViewHolder holder = (EpisodeItemViewHolder)
viewBinding.recyclerView.findViewHolderForAdapterPosition(i);
if (holder != null && holder.isCurrentlyPlayingItem()) {
holder.notifyPlaybackPositionUpdated(event);
break;
}
for (int i = 0; i < adapter.getItemCount(); i++) {
EpisodeItemViewHolder holder = (EpisodeItemViewHolder)
viewBinding.recyclerView.findViewHolderForAdapterPosition(i);
if (holder != null && holder.isCurrentlyPlayingItem()) {
holder.notifyPlaybackPositionUpdated(event);
break;
}
}
}
@ -417,28 +412,6 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
nextPageLoader.setLoadingState(DownloadService.isDownloadingFeeds());
}
private void displayList() {
if (getView() == null) {
Log.e(TAG, "Required root view is not yet created. Stop binding data to UI.");
return;
}
if (adapter == null) {
viewBinding.recyclerView.setAdapter(null);
adapter = new FeedItemListAdapter((MainActivity) getActivity());
adapter.setOnSelectModeListener(this);
viewBinding.recyclerView.setAdapter(adapter);
swipeActions = new SwipeActions(this, TAG).attachTo(viewBinding.recyclerView);
}
viewBinding.progLoading.setVisibility(View.GONE);
if (feed != null) {
adapter.updateItems(feed.getItems());
swipeActions.setFilter(feed.getItemFilter());
}
updateToolbar();
updateSyncProgressBarVisibility();
}
private void refreshHeaderView() {
setupHeaderView();
if (viewBinding == null || feed == null) {
@ -557,12 +530,19 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
.subscribe(
result -> {
feed = result;
swipeActions.setFilter(feed.getItemFilter());
refreshHeaderView();
displayList();
adapter.setDummyViews(0);
adapter.updateItems(feed.getItems());
updateToolbar();
updateSyncProgressBarVisibility();
}, error -> {
feed = null;
refreshHeaderView();
displayList();
adapter.setDummyViews(0);
adapter.updateItems(Collections.emptyList());
updateToolbar();
updateSyncProgressBarVisibility();
Log.e(TAG, Log.getStackTraceString(error));
});
}

View File

@ -14,7 +14,6 @@ import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
@ -24,10 +23,8 @@ import androidx.recyclerview.widget.ItemTouchHelper;
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;
@ -35,26 +32,26 @@ import de.danoeh.antennapod.adapter.QueueRecyclerAdapter;
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.event.playback.PlaybackPositionEvent;
import de.danoeh.antennapod.event.PlayerStatusEvent;
import de.danoeh.antennapod.event.QueueEvent;
import de.danoeh.antennapod.event.UnreadItemsUpdateEvent;
import de.danoeh.antennapod.core.menuhandler.MenuItemUtils;
import de.danoeh.antennapod.fragment.actions.EpisodeMultiSelectActionHandler;
import de.danoeh.antennapod.fragment.swipeactions.SwipeActions;
import de.danoeh.antennapod.model.feed.FeedItem;
import de.danoeh.antennapod.core.feed.util.PlaybackSpeedUtils;
import de.danoeh.antennapod.core.menuhandler.MenuItemUtils;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.service.download.DownloadService;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.util.Converter;
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.PlayerStatusEvent;
import de.danoeh.antennapod.event.QueueEvent;
import de.danoeh.antennapod.event.UnreadItemsUpdateEvent;
import de.danoeh.antennapod.event.playback.PlaybackPositionEvent;
import de.danoeh.antennapod.fragment.actions.EpisodeMultiSelectActionHandler;
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.model.feed.SortOrder;
import de.danoeh.antennapod.core.util.download.AutoUpdateManager;
import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
import de.danoeh.antennapod.view.EmptyViewHandler;
import de.danoeh.antennapod.view.EpisodeItemListRecyclerView;
import de.danoeh.antennapod.view.viewholder.EpisodeItemViewHolder;
@ -81,7 +78,6 @@ public class QueueFragment extends Fragment implements Toolbar.OnMenuItemClickLi
private EpisodeItemListRecyclerView recyclerView;
private QueueRecyclerAdapter recyclerAdapter;
private EmptyViewHandler emptyView;
private ProgressBar progLoading;
private Toolbar toolbar;
private boolean displayUpArrow;
@ -89,6 +85,7 @@ public class QueueFragment extends Fragment implements Toolbar.OnMenuItemClickLi
private static final String PREFS = "QueueFragment";
private static final String PREF_SHOW_LOCK_WARNING = "show_lock_warning";
private static final String PREF_PREVIOUS_EPISODE_COUNT = "episodeCount";
private Disposable disposable;
private SwipeActions swipeActions;
@ -107,7 +104,7 @@ public class QueueFragment extends Fragment implements Toolbar.OnMenuItemClickLi
public void onStart() {
super.onStart();
if (queue != null) {
onFragmentLoaded(true);
recyclerView.restoreScrollPosition(QueueFragment.TAG);
}
loadItems(true);
EventBus.getDefault().register(this);
@ -126,6 +123,7 @@ public class QueueFragment extends Fragment implements Toolbar.OnMenuItemClickLi
if (disposable != null) {
disposable.dispose();
}
prefs.edit().putInt(PREF_PREVIOUS_EPISODE_COUNT, queue.size()).apply();
}
@Subscribe(threadMode = ThreadMode.MAIN)
@ -161,7 +159,7 @@ public class QueueFragment extends Fragment implements Toolbar.OnMenuItemClickLi
return;
}
recyclerView.saveScrollPosition(QueueFragment.TAG);
onFragmentLoaded(false);
refreshInfoBar();
}
@Subscribe(threadMode = ThreadMode.MAIN)
@ -456,6 +454,17 @@ public class QueueFragment extends Fragment implements Toolbar.OnMenuItemClickLi
recyclerView.setRecycledViewPool(((MainActivity) getActivity()).getRecycledViewPool());
registerForContextMenu(recyclerView);
recyclerAdapter = new QueueRecyclerAdapter((MainActivity) getActivity(), swipeActions) {
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
MenuItemUtils.setOnClickListeners(menu, QueueFragment.this::onContextItemSelected);
}
};
recyclerAdapter.setOnSelectModeListener(this);
recyclerAdapter.setDummyViews(Math.max(1, prefs.getInt(PREF_PREVIOUS_EPISODE_COUNT, 5)));
recyclerView.setAdapter(recyclerAdapter);
SwipeRefreshLayout swipeRefreshLayout = root.findViewById(R.id.swipeRefresh);
swipeRefreshLayout.setDistanceToTriggerSync(getResources().getInteger(R.integer.swipe_refresh_distance));
swipeRefreshLayout.setOnRefreshListener(() -> {
@ -473,9 +482,7 @@ public class QueueFragment extends Fragment implements Toolbar.OnMenuItemClickLi
emptyView.setIcon(R.drawable.ic_playlist_play);
emptyView.setTitle(R.string.no_items_header_label);
emptyView.setMessage(R.string.no_items_label);
progLoading = root.findViewById(R.id.progLoading);
progLoading.setVisibility(View.VISIBLE);
emptyView.updateAdapter(recyclerAdapter);
speedDialView = root.findViewById(R.id.fabSD);
speedDialView.setOverlayLayout(root.findViewById(R.id.fabSDOverlay));
@ -513,38 +520,6 @@ public class QueueFragment extends Fragment implements Toolbar.OnMenuItemClickLi
super.onSaveInstanceState(outState);
}
private void onFragmentLoaded(final boolean restoreScrollPosition) {
if (queue != null) {
if (recyclerAdapter == null) {
MainActivity activity = (MainActivity) getActivity();
recyclerAdapter = new QueueRecyclerAdapter(activity, swipeActions) {
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
MenuItemUtils.setOnClickListeners(menu, QueueFragment.this::onContextItemSelected);
}
};
recyclerAdapter.setOnSelectModeListener(this);
recyclerView.setAdapter(recyclerAdapter);
emptyView.updateAdapter(recyclerAdapter);
}
recyclerAdapter.updateItems(queue);
} else {
recyclerAdapter = null;
emptyView.updateAdapter(null);
}
if (restoreScrollPosition) {
recyclerView.restoreScrollPosition(QueueFragment.TAG);
}
// we need to refresh the options menu because it sometimes
// needs data that may have just been loaded.
refreshToolbarState();
refreshInfoBar();
}
private void refreshInfoBar() {
String info = String.format(Locale.getDefault(), "%d%s",
queue.size(), getString(R.string.episodes_suffix));
@ -574,18 +549,18 @@ public class QueueFragment extends Fragment implements Toolbar.OnMenuItemClickLi
}
if (queue == null) {
emptyView.hide();
progLoading.setVisibility(View.VISIBLE);
}
disposable = Observable.fromCallable(DBReader::getQueue)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(items -> {
progLoading.setVisibility(View.GONE);
queue = items;
onFragmentLoaded(restoreScrollPosition);
if (recyclerAdapter != null) {
recyclerAdapter.notifyDataSetChanged();
recyclerAdapter.setDummyViews(0);
recyclerAdapter.updateItems(queue);
if (restoreScrollPosition) {
recyclerView.restoreScrollPosition(QueueFragment.TAG);
}
refreshInfoBar();
}, error -> Log.e(TAG, Log.getStackTraceString(error)));
}

View File

@ -3,6 +3,7 @@ package de.danoeh.antennapod.fragment;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import androidx.fragment.app.Fragment;
@ -14,7 +15,6 @@ import android.widget.AdapterView;
import android.widget.Button;
import android.widget.GridView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import de.danoeh.antennapod.net.discovery.ItunesTopListLoader;
@ -41,7 +41,6 @@ public class QuickFeedDiscoveryFragment extends Fragment implements AdapterView.
private static final String TAG = "FeedDiscoveryFragment";
private static final int NUM_SUGGESTIONS = 12;
private ProgressBar progressBar;
private Disposable disposable;
private FeedDiscoverAdapter adapter;
private GridView discoverGridLayout;
@ -59,7 +58,6 @@ public class QuickFeedDiscoveryFragment extends Fragment implements AdapterView.
((MainActivity) getActivity()).loadChildFragment(new DiscoveryFragment()));
discoverGridLayout = root.findViewById(R.id.discover_grid);
progressBar = root.findViewById(R.id.discover_progress_bar);
errorView = root.findViewById(R.id.discover_error);
errorTextView = root.findViewById(R.id.discover_error_txtV);
errorRetry = root.findViewById(R.id.discover_error_retry_btn);
@ -108,8 +106,6 @@ public class QuickFeedDiscoveryFragment extends Fragment implements AdapterView.
}
private void loadToplist() {
progressBar.setVisibility(View.VISIBLE);
discoverGridLayout.setVisibility(View.INVISIBLE);
errorView.setVisibility(View.GONE);
errorRetry.setVisibility(View.INVISIBLE);
poweredByTextView.setVisibility(View.VISIBLE);
@ -121,7 +117,6 @@ public class QuickFeedDiscoveryFragment extends Fragment implements AdapterView.
if (countryCode.equals(ItunesTopListLoader.DISCOVER_HIDE_FAKE_COUNTRY_CODE)) {
errorTextView.setText(R.string.discover_is_hidden);
errorView.setVisibility(View.VISIBLE);
progressBar.setVisibility(View.GONE);
discoverGridLayout.setVisibility(View.GONE);
errorRetry.setVisibility(View.GONE);
poweredByTextView.setVisibility(View.GONE);
@ -132,20 +127,18 @@ public class QuickFeedDiscoveryFragment extends Fragment implements AdapterView.
.subscribe(
podcasts -> {
errorView.setVisibility(View.GONE);
progressBar.setVisibility(View.GONE);
discoverGridLayout.setVisibility(View.VISIBLE);
if (podcasts.size() == 0) {
errorTextView.setText(getResources().getText(R.string.search_status_no_results));
errorView.setVisibility(View.VISIBLE);
discoverGridLayout.setVisibility(View.INVISIBLE);
} else {
discoverGridLayout.setVisibility(View.VISIBLE);
adapter.updateData(podcasts);
}
}, error -> {
Log.e(TAG, Log.getStackTraceString(error));
errorTextView.setText(error.getLocalizedMessage());
errorView.setVisibility(View.VISIBLE);
progressBar.setVisibility(View.GONE);
discoverGridLayout.setVisibility(View.INVISIBLE);
errorRetry.setVisibility(View.VISIBLE);
});
@ -154,7 +147,7 @@ public class QuickFeedDiscoveryFragment extends Fragment implements AdapterView.
@Override
public void onItemClick(AdapterView<?> parent, final View view, int position, long id) {
PodcastSearchResult podcast = adapter.getItem(position);
if (podcast.feedUrl == null) {
if (TextUtils.isEmpty(podcast.feedUrl)) {
return;
}
Intent intent = new Intent(getActivity(), OnlineFeedViewActivity.class);

View File

@ -13,7 +13,6 @@ import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.annotation.NonNull;
@ -75,6 +74,7 @@ public class SubscriptionFragment extends Fragment
public static final String TAG = "SubscriptionFragment";
private static final String PREFS = "SubscriptionFragment";
private static final String PREF_NUM_COLUMNS = "columns";
private static final String PREF_PREVIOUS_EPISODE_COUNT = "episodeCount";
private static final String KEY_UP_ARROW = "up_arrow";
private static final String ARGUMENT_FOLDER = "folder";
@ -88,7 +88,6 @@ public class SubscriptionFragment extends Fragment
private RecyclerView subscriptionRecycler;
private SubscriptionsRecyclerAdapter subscriptionAdapter;
private FloatingActionButton subscriptionAddButton;
private ProgressBar progressBar;
private EmptyViewHandler emptyView;
private TextView feedsFilteredMsg;
private Toolbar toolbar;
@ -153,8 +152,24 @@ public class SubscriptionFragment extends Fragment
setColumnNumber(prefs.getInt(PREF_NUM_COLUMNS, getDefaultNumOfColumns()));
subscriptionRecycler.addItemDecoration(new SubscriptionsRecyclerAdapter.GridDividerItemDecorator());
registerForContextMenu(subscriptionRecycler);
subscriptionAdapter = new SubscriptionsRecyclerAdapter((MainActivity) getActivity()) {
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
MenuItemUtils.setOnClickListeners(menu, SubscriptionFragment.this::onContextItemSelected);
}
};
subscriptionAdapter.setOnSelectModeListener(this);
subscriptionAdapter.setDummyViews(Math.max(1, prefs.getInt(PREF_PREVIOUS_EPISODE_COUNT, 5)));
subscriptionRecycler.setAdapter(subscriptionAdapter);
setupEmptyView();
subscriptionAddButton = root.findViewById(R.id.subscriptions_add);
progressBar = root.findViewById(R.id.progLoading);
subscriptionAddButton.setOnClickListener(view -> {
if (getActivity() instanceof MainActivity) {
((MainActivity) getActivity()).loadChildFragment(new AddFeedFragment());
}
});
feedsFilteredMsg = root.findViewById(R.id.feeds_filtered_message);
feedsFilteredMsg.setOnClickListener((l) -> SubscriptionsFilterDialog.showDialog(requireContext()));
@ -253,26 +268,6 @@ public class SubscriptionFragment extends Fragment
emptyView.attachToRecyclerView(subscriptionRecycler);
}
@Override
public void onViewCreated(@NonNull View v, Bundle savedInstanceState) {
super.onViewCreated(v, savedInstanceState);
subscriptionAdapter = new SubscriptionsRecyclerAdapter((MainActivity) getActivity()) {
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
MenuItemUtils.setOnClickListeners(menu, SubscriptionFragment.this::onContextItemSelected);
}
};
subscriptionAdapter.setOnSelectModeListener(this);
subscriptionRecycler.setAdapter(subscriptionAdapter);
setupEmptyView();
subscriptionAddButton.setOnClickListener(view -> {
if (getActivity() instanceof MainActivity) {
((MainActivity) getActivity()).loadChildFragment(new AddFeedFragment());
}
});
}
@Override
public void onStart() {
super.onStart();
@ -287,6 +282,7 @@ public class SubscriptionFragment extends Fragment
if (disposable != null) {
disposable.dispose();
}
prefs.edit().putInt(PREF_PREVIOUS_EPISODE_COUNT, subscriptionAdapter.getItemCount()).apply();
if (subscriptionAdapter != null) {
subscriptionAdapter.endSelectMode();
@ -319,13 +315,12 @@ public class SubscriptionFragment extends Fragment
subscriptionAdapter.endSelectMode();
}
listItems = result;
subscriptionAdapter.setDummyViews(0);
subscriptionAdapter.setItems(result);
subscriptionAdapter.notifyDataSetChanged();
emptyView.updateVisibility();
progressBar.setVisibility(View.GONE); // Keep hidden to avoid flickering while refreshing
}, error -> {
Log.e(TAG, Log.getStackTraceString(error));
progressBar.setVisibility(View.GONE);
});
if (UserPreferences.getSubscriptionsFilter().isEnabled()) {

View File

@ -220,6 +220,7 @@ public class EpisodeItemViewHolder extends RecyclerView.ViewHolder {
.withPlaceholderView(placeholder)
.withCoverView(cover)
.load();
hideSeparatorIfNecessary();
}
private void updateDuration(PlaybackPositionEvent event) {

View File

@ -32,8 +32,7 @@
android:id="@+id/swipeRefresh"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/txtvInformation"
android:layout_above="@id/loadingMore">
android:layout_below="@+id/txtvInformation">
<de.danoeh.antennapod.view.EpisodeItemListRecyclerView
android:id="@android:id/list"
@ -49,45 +48,6 @@
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
<ProgressBar
android:id="@+id/progLoading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:indeterminateOnly="true"
android:visibility="gone"
android:layout_centerInParent="true"
tools:background="@android:color/holo_red_light" />
<LinearLayout
android:id="@+id/loadingMore"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:orientation="horizontal"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingTop="4dp"
android:paddingBottom="4dp"
android:visibility="gone"
android:gravity="center">
<ProgressBar
android:layout_width="16dp"
android:layout_height="16dp"
android:gravity="center_horizontal"
android:indeterminateOnly="true"
tools:background="@android:color/holo_red_light" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="4dp"
android:layout_marginStart="4dp"
android:text="@string/loading_more" />
</LinearLayout>
<include
layout="@layout/multi_select_speed_dial" />

View File

@ -61,14 +61,6 @@
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
<ProgressBar
android:id="@+id/progLoading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:indeterminateOnly="true"
android:visibility="gone" />
<include
android:id="@+id/more_content"
android:layout_width="match_parent"

View File

@ -49,14 +49,6 @@
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
<ProgressBar
android:id="@+id/progLoading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:indeterminateOnly="true"
android:visibility="visible" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/subscriptions_add"
android:layout_width="56dp"

View File

@ -49,14 +49,6 @@
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
<ProgressBar
android:id="@+id/progLoading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:indeterminateOnly="true"
android:visibility="gone" />
<include
layout="@layout/multi_select_speed_dial" />

View File

@ -1,98 +1,92 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
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="wrap_content"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical">
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="0dip"
android:layout_height="wrap_content"
android:text="@string/discover"
android:textSize="18sp"
android:layout_marginBottom="8dp"
android:layout_weight="1"
android:textColor="?android:attr/textColorPrimary"/>
android:layout_width="0dip"
android:layout_height="wrap_content"
android:text="@string/discover"
android:textSize="18sp"
android:layout_marginBottom="8dp"
android:layout_weight="1"
android:textColor="?android:attr/textColorPrimary" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minHeight="48dp"
android:minWidth="0dp"
android:text="@string/discover_more"
style="@style/Widget.MaterialComponents.Button.TextButton"
android:id="@+id/discover_more"/>
android:id="@+id/discover_more"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minHeight="48dp"
android:minWidth="0dp"
android:text="@string/discover_more"
style="@style/Widget.MaterialComponents.Button.TextButton" />
</LinearLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_width="match_parent"
android:layout_height="wrap_content">
<de.danoeh.antennapod.ui.common.WrappingGridView
android:id="@+id/discover_grid"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:numColumns="4"
app:layout_columnWeight="1"
app:layout_rowWeight="1"
android:scrollbars="none"
android:layout_marginTop="8dp"
android:layout_centerInParent="true"
android:layout_gravity="center_horizontal"/>
<ProgressBar
android:id="@+id/discover_progress_bar"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_centerInParent="true"
android:layout_marginTop="30dp"/>
android:id="@+id/discover_grid"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:numColumns="4"
android:scrollbars="none"
android:layout_marginTop="8dp"
android:layout_centerInParent="true"
android:layout_gravity="center_horizontal"
app:layout_columnWeight="1"
app:layout_rowWeight="1" />
<LinearLayout
android:id="@+id/discover_error"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:gravity="center"
android:orientation="vertical">
android:id="@+id/discover_error"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/discover_error_txtV"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_margin="16dp"
android:textSize="@dimen/text_size_small"
tools:text="Error message"
tools:background="@android:color/holo_red_light" />
android:id="@+id/discover_error_txtV"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_margin="16dp"
android:textSize="@dimen/text_size_small"
tools:text="Error message"
tools:background="@android:color/holo_red_light" />
<Button
android:id="@+id/discover_error_retry_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:text="@string/retry_label"
tools:background="@android:color/holo_red_light" />
android:id="@+id/discover_error_retry_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:text="@string/retry_label"
tools:background="@android:color/holo_red_light" />
</LinearLayout>
</RelativeLayout>
<TextView
android:id="@+id/discover_powered_by_itunes"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="?android:attr/textColorTertiary"
android:text="@string/discover_powered_by_itunes"
android:textSize="12sp"
android:layout_gravity="right|end"
android:paddingHorizontal="4dp"
android:textAlignment="textEnd"/>
android:id="@+id/discover_powered_by_itunes"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="?android:attr/textColorTertiary"
android:text="@string/discover_powered_by_itunes"
android:textSize="12sp"
android:layout_gravity="right|end"
android:paddingHorizontal="4dp"
android:textAlignment="textEnd" />
</LinearLayout>

View File

@ -146,7 +146,6 @@
<item quantity="one">%d episode</item>
<item quantity="other">%d episodes</item>
</plurals>
<string name="loading_more">Loading more…</string>
<string name="episode_notification">Episode Notifications</string>
<string name="episode_notification_summary">Show a notification when a new episode is released.</string>
<plurals name="new_episode_notification_message">