Extract queue item holder to new class
First step to use a single item holder in the future
This commit is contained in:
parent
7e2fd0b1d7
commit
cae04b5b13
|
@ -1,56 +1,33 @@
|
|||
package de.danoeh.antennapod.adapter;
|
||||
|
||||
import android.os.Build;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.view.MotionEventCompat;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||
import android.text.Layout;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.joanzapata.iconify.Iconify;
|
||||
|
||||
import de.danoeh.antennapod.core.event.PlaybackPositionEvent;
|
||||
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.EpisodeItemViewHolder;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.activity.MainActivity;
|
||||
import de.danoeh.antennapod.adapter.actionbutton.ItemActionButton;
|
||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||
import de.danoeh.antennapod.core.feed.FeedMedia;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.storage.DownloadRequester;
|
||||
import de.danoeh.antennapod.core.util.Converter;
|
||||
import de.danoeh.antennapod.core.util.DateUtils;
|
||||
import de.danoeh.antennapod.core.feed.util.ImageResourceUtils;
|
||||
import de.danoeh.antennapod.core.util.LongList;
|
||||
import de.danoeh.antennapod.core.util.NetworkUtils;
|
||||
import de.danoeh.antennapod.core.util.ThemeUtils;
|
||||
import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
|
||||
|
||||
/**
|
||||
* List adapter for the queue.
|
||||
*/
|
||||
public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdapter.ViewHolder> {
|
||||
|
||||
private static final String TAG = QueueRecyclerAdapter.class.getSimpleName();
|
||||
public class QueueRecyclerAdapter extends RecyclerView.Adapter<EpisodeItemViewHolder> implements View.OnCreateContextMenuListener {
|
||||
private static final String TAG = "QueueRecyclerAdapter";
|
||||
|
||||
private final WeakReference<MainActivity> mainActivity;
|
||||
private final ItemAccess itemAccess;
|
||||
|
@ -60,9 +37,6 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap
|
|||
|
||||
private FeedItem selectedItem;
|
||||
|
||||
private final int playingBackGroundColor;
|
||||
private final int normalBackGroundColor;
|
||||
|
||||
public QueueRecyclerAdapter(MainActivity mainActivity,
|
||||
ItemAccess itemAccess,
|
||||
ItemTouchHelper itemTouchHelper) {
|
||||
|
@ -71,9 +45,6 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap
|
|||
this.itemAccess = itemAccess;
|
||||
this.itemTouchHelper = itemTouchHelper;
|
||||
locked = UserPreferences.isQueueLocked();
|
||||
|
||||
playingBackGroundColor = ThemeUtils.getColorFromAttr(mainActivity, R.attr.currently_playing_background);
|
||||
normalBackGroundColor = ContextCompat.getColor(mainActivity, android.R.color.transparent);
|
||||
}
|
||||
|
||||
public void setLocked(boolean locked) {
|
||||
|
@ -81,20 +52,38 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap
|
|||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.queue_listitem, parent, false);
|
||||
return new ViewHolder(view);
|
||||
public EpisodeItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
EpisodeItemViewHolder viewHolder = new EpisodeItemViewHolder(mainActivity.get());
|
||||
viewHolder.dragHandle.setOnTouchListener((v1, event) -> {
|
||||
if (MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN) {
|
||||
Log.d(TAG, "startDrag()");
|
||||
itemTouchHelper.startDrag(viewHolder);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
return viewHolder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(ViewHolder holder, int pos) {
|
||||
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));
|
||||
}
|
||||
});
|
||||
holder.itemView.setOnCreateContextMenuListener(this);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
@ -112,211 +101,30 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap
|
|||
return itemAccess.getCount();
|
||||
}
|
||||
|
||||
public class ViewHolder extends RecyclerView.ViewHolder
|
||||
implements View.OnClickListener,
|
||||
View.OnCreateContextMenuListener,
|
||||
ItemTouchHelperViewHolder {
|
||||
@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
|
||||
|
||||
private final FrameLayout container;
|
||||
private final ImageView dragHandle;
|
||||
private final TextView placeholder;
|
||||
private final ImageView cover;
|
||||
private final TextView title;
|
||||
private final TextView pubDate;
|
||||
private final TextView progressLeft;
|
||||
private final TextView progressRight;
|
||||
private final ProgressBar progressBar;
|
||||
private final ImageButton butSecondary;
|
||||
|
||||
private FeedItem item;
|
||||
|
||||
public ViewHolder(View v) {
|
||||
super(v);
|
||||
container = v.findViewById(R.id.container);
|
||||
dragHandle = v.findViewById(R.id.drag_handle);
|
||||
placeholder = v.findViewById(R.id.txtvPlaceholder);
|
||||
cover = v.findViewById(R.id.imgvCover);
|
||||
title = v.findViewById(R.id.txtvTitle);
|
||||
if(Build.VERSION.SDK_INT >= 23) {
|
||||
title.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_FULL);
|
||||
}
|
||||
pubDate = v.findViewById(R.id.txtvPubDate);
|
||||
progressLeft = v.findViewById(R.id.txtvProgressLeft);
|
||||
progressRight = v.findViewById(R.id.txtvProgressRight);
|
||||
butSecondary = v.findViewById(R.id.butSecondaryAction);
|
||||
progressBar = v.findViewById(R.id.progressBar);
|
||||
v.setTag(this);
|
||||
v.setOnClickListener(this);
|
||||
v.setOnCreateContextMenuListener(this);
|
||||
dragHandle.setOnTouchListener((v1, event) -> {
|
||||
if (MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN) {
|
||||
Log.d(TAG, "startDrag()");
|
||||
itemTouchHelper.startDrag(ViewHolder.this);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
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) {
|
||||
menu.findItem(R.id.move_to_top_item).setVisible(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View 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));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateContextMenu(final ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
|
||||
FeedItem item = itemAccess.getItem(getAdapterPosition());
|
||||
|
||||
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
|
||||
|
||||
if (item != null) {
|
||||
menu.setHeaderTitle(item.getTitle());
|
||||
}
|
||||
|
||||
FeedItemMenuHandler.onPrepareMenu(menu, item,
|
||||
R.id.skip_episode_item); // Skip Episode is not useful in Queue, so hide it.
|
||||
// Queue-specific menu preparation
|
||||
final boolean keepSorted = UserPreferences.isQueueKeepSorted();
|
||||
final LongList queueAccess = itemAccess.getQueueIds();
|
||||
if (queueAccess.size() == 0 || queueAccess.get(0) == item.getId() || keepSorted) {
|
||||
menu.findItem(R.id.move_to_top_item).setVisible(false);
|
||||
}
|
||||
if (queueAccess.size() == 0 || queueAccess.get(queueAccess.size()-1) == item.getId() || keepSorted) {
|
||||
menu.findItem(R.id.move_to_bottom_item).setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemSelected() {
|
||||
itemView.setAlpha(0.5f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClear() {
|
||||
itemView.setAlpha(1.0f);
|
||||
}
|
||||
|
||||
public void bind(FeedItem item) {
|
||||
this.item = item;
|
||||
if(locked) {
|
||||
dragHandle.setVisibility(View.GONE);
|
||||
} else {
|
||||
dragHandle.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
placeholder.setText(item.getFeed().getTitle());
|
||||
|
||||
title.setText(item.getTitle());
|
||||
FeedMedia media = item.getMedia();
|
||||
|
||||
title.setText(item.getTitle());
|
||||
String pubDateStr = DateUtils.formatAbbrev(mainActivity.get(), item.getPubDate());
|
||||
int index = 0;
|
||||
if(countMatches(pubDateStr, ' ') == 1 || countMatches(pubDateStr, ' ') == 2) {
|
||||
index = pubDateStr.lastIndexOf(' ');
|
||||
} else if(countMatches(pubDateStr, '.') == 2) {
|
||||
index = pubDateStr.lastIndexOf('.');
|
||||
} else if(countMatches(pubDateStr, '-') == 2) {
|
||||
index = pubDateStr.lastIndexOf('-');
|
||||
} else if(countMatches(pubDateStr, '/') == 2) {
|
||||
index = pubDateStr.lastIndexOf('/');
|
||||
}
|
||||
if(index > 0) {
|
||||
pubDateStr = pubDateStr.substring(0, index+1).trim() + "\n" + pubDateStr.substring(index+1);
|
||||
}
|
||||
pubDate.setText(pubDateStr);
|
||||
|
||||
if (media != null) {
|
||||
final boolean isDownloadingMedia = DownloadRequester.getInstance().isDownloadingFile(media);
|
||||
FeedItem.State state = item.getState();
|
||||
if (isDownloadingMedia) {
|
||||
progressLeft.setText(Converter.byteToString(itemAccess.getItemDownloadedBytes(item)));
|
||||
if(itemAccess.getItemDownloadSize(item) > 0) {
|
||||
progressRight.setText(Converter.byteToString(itemAccess.getItemDownloadSize(item)));
|
||||
} else {
|
||||
progressRight.setText(Converter.byteToString(media.getSize()));
|
||||
}
|
||||
progressBar.setProgress(itemAccess.getItemDownloadProgressPercent(item));
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
} else if (state == FeedItem.State.PLAYING
|
||||
|| state == FeedItem.State.IN_PROGRESS) {
|
||||
if (media.getDuration() > 0) {
|
||||
int progress = (int) (100.0 * media.getPosition() / media.getDuration());
|
||||
progressBar.setProgress(progress);
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
progressLeft.setText(Converter
|
||||
.getDurationStringLong(media.getPosition()));
|
||||
progressRight.setText(Converter.getDurationStringLong(media.getDuration()));
|
||||
}
|
||||
} else {
|
||||
if(media.getSize() > 0) {
|
||||
progressLeft.setText(Converter.byteToString(media.getSize()));
|
||||
} else if(NetworkUtils.isEpisodeHeadDownloadAllowed() && !media.checkedOnSizeButUnknown()) {
|
||||
progressLeft.setText("{fa-spinner}");
|
||||
Iconify.addIcons(progressLeft);
|
||||
NetworkUtils.getFeedMediaSizeObservable(media)
|
||||
.subscribe(
|
||||
size -> {
|
||||
if (size > 0) {
|
||||
progressLeft.setText(Converter.byteToString(size));
|
||||
} else {
|
||||
progressLeft.setText("");
|
||||
}
|
||||
}, error -> {
|
||||
progressLeft.setText("");
|
||||
Log.e(TAG, Log.getStackTraceString(error));
|
||||
});
|
||||
} else {
|
||||
progressLeft.setText("");
|
||||
}
|
||||
progressRight.setText(Converter.getDurationStringLong(media.getDuration()));
|
||||
progressBar.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
|
||||
if(media.isCurrentlyPlaying()) {
|
||||
container.setBackgroundColor(playingBackGroundColor);
|
||||
} else {
|
||||
container.setBackgroundColor(normalBackGroundColor);
|
||||
}
|
||||
}
|
||||
|
||||
ItemActionButton actionButton = ItemActionButton.forItem(item, true);
|
||||
actionButton.configure(butSecondary, mainActivity.get());
|
||||
|
||||
butSecondary.setFocusable(false);
|
||||
butSecondary.setTag(item);
|
||||
|
||||
new CoverLoader(mainActivity.get())
|
||||
.withUri(ImageResourceUtils.getImageLocation(item))
|
||||
.withFallbackUri(item.getFeed().getImageLocation())
|
||||
.withPlaceholderView(placeholder)
|
||||
.withCoverView(cover)
|
||||
.load();
|
||||
}
|
||||
|
||||
public boolean isCurrentlyPlayingItem() {
|
||||
return item.getMedia() != null && item.getMedia().isCurrentlyPlaying();
|
||||
}
|
||||
|
||||
public void notifyPlaybackPositionUpdated(PlaybackPositionEvent event) {
|
||||
progressBar.setProgress((int) (100.0 * event.getPosition() / event.getDuration()));
|
||||
progressLeft.setText(Converter.getDurationStringLong(event.getPosition()));
|
||||
progressRight.setText(Converter.getDurationStringLong(event.getDuration()));
|
||||
if (queueAccess.size() == 0 || queueAccess.get(queueAccess.size() - 1) == selectedItem.getId() || keepSorted) {
|
||||
menu.findItem(R.id.move_to_bottom_item).setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
public interface ItemAccess {
|
||||
FeedItem getItem(int position);
|
||||
|
||||
int getCount();
|
||||
long getItemDownloadedBytes(FeedItem item);
|
||||
long getItemDownloadSize(FeedItem item);
|
||||
int getItemDownloadProgressPercent(FeedItem item);
|
||||
|
||||
LongList getQueueIds();
|
||||
}
|
||||
|
||||
|
@ -341,18 +149,4 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap
|
|||
*/
|
||||
void onItemClear();
|
||||
}
|
||||
|
||||
// Oh Xiaomi, I hate you so much. How did you manage to fuck this up?
|
||||
private static int countMatches(final CharSequence str, final char ch) {
|
||||
if (TextUtils.isEmpty(str)) {
|
||||
return 0;
|
||||
}
|
||||
int count = 0;
|
||||
for (int i = 0; i < str.length(); i++) {
|
||||
if (ch == str.charAt(i)) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ import androidx.recyclerview.widget.SimpleItemAnimator;
|
|||
import com.google.android.material.snackbar.Snackbar;
|
||||
import com.yqritc.recyclerviewflexibledivider.HorizontalDividerItemDecoration;
|
||||
|
||||
import de.danoeh.antennapod.view.EpisodeItemViewHolder;
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
import org.greenrobot.eventbus.ThreadMode;
|
||||
|
@ -84,7 +85,6 @@ public class QueueFragment extends Fragment {
|
|||
private ProgressBar progLoading;
|
||||
|
||||
private List<FeedItem> queue;
|
||||
private List<Downloader> downloaderList;
|
||||
|
||||
private boolean isUpdatingFeeds = false;
|
||||
|
||||
|
@ -196,7 +196,6 @@ public class QueueFragment extends Fragment {
|
|||
public void onEventMainThread(DownloadEvent event) {
|
||||
Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
|
||||
DownloaderUpdate update = event.update;
|
||||
downloaderList = update.downloaders;
|
||||
if (event.hasChangedFeedUpdateStatus(isUpdatingFeeds)) {
|
||||
getActivity().invalidateOptionsMenu();
|
||||
}
|
||||
|
@ -214,7 +213,7 @@ public class QueueFragment extends Fragment {
|
|||
public void onEventMainThread(PlaybackPositionEvent event) {
|
||||
if (recyclerAdapter != null) {
|
||||
for (int i = 0; i < recyclerAdapter.getItemCount(); i++) {
|
||||
QueueRecyclerAdapter.ViewHolder holder = (QueueRecyclerAdapter.ViewHolder)
|
||||
EpisodeItemViewHolder holder = (EpisodeItemViewHolder)
|
||||
recyclerView.findViewHolderForAdapterPosition(i);
|
||||
if (holder != null && holder.isCurrentlyPlayingItem()) {
|
||||
holder.notifyPlaybackPositionUpdated(event);
|
||||
|
@ -688,46 +687,6 @@ public class QueueFragment extends Fragment {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemDownloadedBytes(FeedItem item) {
|
||||
if (downloaderList != null) {
|
||||
for (Downloader downloader : downloaderList) {
|
||||
if (downloader.getDownloadRequest().getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA
|
||||
&& downloader.getDownloadRequest().getFeedfileId() == item.getMedia().getId()) {
|
||||
Log.d(TAG, "downloaded bytes: " + downloader.getDownloadRequest().getSoFar());
|
||||
return downloader.getDownloadRequest().getSoFar();
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemDownloadSize(FeedItem item) {
|
||||
if (downloaderList != null) {
|
||||
for (Downloader downloader : downloaderList) {
|
||||
if (downloader.getDownloadRequest().getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA
|
||||
&& downloader.getDownloadRequest().getFeedfileId() == item.getMedia().getId()) {
|
||||
Log.d(TAG, "downloaded size: " + downloader.getDownloadRequest().getSize());
|
||||
return downloader.getDownloadRequest().getSize();
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@Override
|
||||
public int getItemDownloadProgressPercent(FeedItem item) {
|
||||
if (downloaderList != null) {
|
||||
for (Downloader downloader : downloaderList) {
|
||||
if (downloader.getDownloadRequest().getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA
|
||||
&& downloader.getDownloadRequest().getFeedfileId() == item.getMedia().getId()) {
|
||||
return downloader.getDownloadRequest().getProgressPercent();
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LongList getQueueIds() {
|
||||
return queue != null ? LongList.of(FeedItemUtil.getIds(queue)) : new LongList(0);
|
||||
|
|
|
@ -0,0 +1,196 @@
|
|||
package de.danoeh.antennapod.view;
|
||||
|
||||
import android.graphics.Color;
|
||||
import android.os.Build;
|
||||
import android.text.Layout;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import com.joanzapata.iconify.Iconify;
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.activity.MainActivity;
|
||||
import de.danoeh.antennapod.adapter.CoverLoader;
|
||||
import de.danoeh.antennapod.adapter.QueueRecyclerAdapter;
|
||||
import de.danoeh.antennapod.adapter.actionbutton.ItemActionButton;
|
||||
import de.danoeh.antennapod.core.event.PlaybackPositionEvent;
|
||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||
import de.danoeh.antennapod.core.feed.FeedMedia;
|
||||
import de.danoeh.antennapod.core.feed.util.ImageResourceUtils;
|
||||
import de.danoeh.antennapod.core.service.download.DownloadRequest;
|
||||
import de.danoeh.antennapod.core.storage.DownloadRequester;
|
||||
import de.danoeh.antennapod.core.util.Converter;
|
||||
import de.danoeh.antennapod.core.util.DateUtils;
|
||||
import de.danoeh.antennapod.core.util.NetworkUtils;
|
||||
import de.danoeh.antennapod.core.util.ThemeUtils;
|
||||
|
||||
/**
|
||||
* Holds the view which shows FeedItems.
|
||||
*/
|
||||
public class EpisodeItemViewHolder extends RecyclerView.ViewHolder
|
||||
implements QueueRecyclerAdapter.ItemTouchHelperViewHolder {
|
||||
private static final String TAG = "EpisodeItemViewHolder";
|
||||
|
||||
private final FrameLayout container;
|
||||
public final ImageView dragHandle;
|
||||
private final TextView placeholder;
|
||||
private final ImageView cover;
|
||||
private final TextView title;
|
||||
private final TextView pubDate;
|
||||
private final TextView progressLeft;
|
||||
private final TextView progressRight;
|
||||
private final ProgressBar progressBar;
|
||||
private final ImageButton butSecondary;
|
||||
private final MainActivity activity;
|
||||
|
||||
private FeedItem item;
|
||||
|
||||
public EpisodeItemViewHolder(MainActivity activity) {
|
||||
super(View.inflate(activity, R.layout.queue_listitem, null));
|
||||
this.activity = activity;
|
||||
container = itemView.findViewById(R.id.container);
|
||||
dragHandle = itemView.findViewById(R.id.drag_handle);
|
||||
placeholder = itemView.findViewById(R.id.txtvPlaceholder);
|
||||
cover = itemView.findViewById(R.id.imgvCover);
|
||||
title = itemView.findViewById(R.id.txtvTitle);
|
||||
if (Build.VERSION.SDK_INT >= 23) {
|
||||
title.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_FULL);
|
||||
}
|
||||
pubDate = itemView.findViewById(R.id.txtvPubDate);
|
||||
progressLeft = itemView.findViewById(R.id.txtvProgressLeft);
|
||||
progressRight = itemView.findViewById(R.id.txtvProgressRight);
|
||||
butSecondary = itemView.findViewById(R.id.butSecondaryAction);
|
||||
progressBar = itemView.findViewById(R.id.progressBar);
|
||||
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());
|
||||
title.setText(item.getTitle());
|
||||
title.setText(item.getTitle());
|
||||
pubDate.setText(formatPubDate());
|
||||
|
||||
FeedMedia media = item.getMedia();
|
||||
if (media != null) {
|
||||
final DownloadRequest downloadRequest = DownloadRequester.getInstance().getRequestFor(media);
|
||||
FeedItem.State state = item.getState();
|
||||
if (downloadRequest != null) {
|
||||
progressLeft.setText(Converter.byteToString(downloadRequest.getSoFar()));
|
||||
if (downloadRequest.getSize() > 0) {
|
||||
progressRight.setText(Converter.byteToString(downloadRequest.getSize()));
|
||||
} else {
|
||||
progressRight.setText(Converter.byteToString(media.getSize()));
|
||||
}
|
||||
progressBar.setProgress(downloadRequest.getProgressPercent());
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
} else if (state == FeedItem.State.PLAYING || state == FeedItem.State.IN_PROGRESS) {
|
||||
if (media.getDuration() > 0) {
|
||||
int progress = (int) (100.0 * media.getPosition() / media.getDuration());
|
||||
progressBar.setProgress(progress);
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
progressLeft.setText(Converter.getDurationStringLong(media.getPosition()));
|
||||
progressRight.setText(Converter.getDurationStringLong(media.getDuration()));
|
||||
}
|
||||
} else {
|
||||
if (media.getSize() > 0) {
|
||||
progressLeft.setText(Converter.byteToString(media.getSize()));
|
||||
} else if (NetworkUtils.isEpisodeHeadDownloadAllowed() && !media.checkedOnSizeButUnknown()) {
|
||||
progressLeft.setText("{fa-spinner}");
|
||||
Iconify.addIcons(progressLeft);
|
||||
NetworkUtils.getFeedMediaSizeObservable(media).subscribe(
|
||||
size -> {
|
||||
if (size > 0) {
|
||||
progressLeft.setText(Converter.byteToString(size));
|
||||
} else {
|
||||
progressLeft.setText("");
|
||||
}
|
||||
}, error -> {
|
||||
progressLeft.setText("");
|
||||
Log.e(TAG, Log.getStackTraceString(error));
|
||||
});
|
||||
} else {
|
||||
progressLeft.setText("");
|
||||
}
|
||||
progressRight.setText(Converter.getDurationStringLong(media.getDuration()));
|
||||
progressBar.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
|
||||
if (media.isCurrentlyPlaying()) {
|
||||
container.setBackgroundColor(ThemeUtils.getColorFromAttr(activity,
|
||||
R.attr.currently_playing_background));
|
||||
} else {
|
||||
container.setBackgroundColor(Color.TRANSPARENT);
|
||||
}
|
||||
}
|
||||
|
||||
ItemActionButton actionButton = ItemActionButton.forItem(item, true);
|
||||
actionButton.configure(butSecondary, activity);
|
||||
butSecondary.setFocusable(false);
|
||||
butSecondary.setTag(item);
|
||||
|
||||
new CoverLoader(activity)
|
||||
.withUri(ImageResourceUtils.getImageLocation(item))
|
||||
.withFallbackUri(item.getFeed().getImageLocation())
|
||||
.withPlaceholderView(placeholder)
|
||||
.withCoverView(cover)
|
||||
.load();
|
||||
}
|
||||
|
||||
private String formatPubDate() {
|
||||
String pubDateStr = DateUtils.formatAbbrev(activity, item.getPubDate());
|
||||
int index = 0;
|
||||
if (countMatches(pubDateStr, ' ') == 1 || countMatches(pubDateStr, ' ') == 2) {
|
||||
index = pubDateStr.lastIndexOf(' ');
|
||||
} else if (countMatches(pubDateStr, '.') == 2) {
|
||||
index = pubDateStr.lastIndexOf('.');
|
||||
} else if (countMatches(pubDateStr, '-') == 2) {
|
||||
index = pubDateStr.lastIndexOf('-');
|
||||
} else if (countMatches(pubDateStr, '/') == 2) {
|
||||
index = pubDateStr.lastIndexOf('/');
|
||||
}
|
||||
if (index > 0) {
|
||||
pubDateStr = pubDateStr.substring(0, index+1).trim() + "\n" + pubDateStr.substring(index+1);
|
||||
}
|
||||
return pubDateStr;
|
||||
}
|
||||
|
||||
public boolean isCurrentlyPlayingItem() {
|
||||
return item.getMedia() != null && item.getMedia().isCurrentlyPlaying();
|
||||
}
|
||||
|
||||
public void notifyPlaybackPositionUpdated(PlaybackPositionEvent event) {
|
||||
progressBar.setProgress((int) (100.0 * event.getPosition() / event.getDuration()));
|
||||
progressLeft.setText(Converter.getDurationStringLong(event.getPosition()));
|
||||
progressRight.setText(Converter.getDurationStringLong(event.getDuration()));
|
||||
}
|
||||
|
||||
// Oh Xiaomi, I hate you so much. How did you manage to fuck this up?
|
||||
private static int countMatches(final CharSequence str, final char ch) {
|
||||
if (TextUtils.isEmpty(str)) {
|
||||
return 0;
|
||||
}
|
||||
int count = 0;
|
||||
for (int i = 0; i < str.length(); i++) {
|
||||
if (ch == str.charAt(i)) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@ package de.danoeh.antennapod.core.service.download.handler;
|
|||
|
||||
import de.danoeh.antennapod.core.event.DownloadEvent;
|
||||
import de.danoeh.antennapod.core.service.download.Downloader;
|
||||
import de.danoeh.antennapod.core.storage.DownloadRequester;
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
@ -23,6 +24,7 @@ public class PostDownloaderTask implements Runnable {
|
|||
runningDownloads.add(downloader);
|
||||
}
|
||||
}
|
||||
DownloadRequester.getInstance().updateProgress(downloads);
|
||||
List<Downloader> list = Collections.unmodifiableList(runningDownloads);
|
||||
EventBus.getDefault().postSticky(DownloadEvent.refresh(list));
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import androidx.annotation.Nullable;
|
|||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import de.danoeh.antennapod.core.service.download.Downloader;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
|
||||
import java.io.File;
|
||||
|
@ -343,6 +344,16 @@ public class DownloadRequester implements DownloadStateProvider {
|
|||
return item.getDownload_url() != null && downloads.containsKey(item.getDownload_url());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the downloader for this item.
|
||||
*/
|
||||
public synchronized DownloadRequest getRequestFor(FeedFile item) {
|
||||
if (isDownloadingFile(item)) {
|
||||
return downloads.get(item.getDownload_url());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if feedfile with the given download url is in the downloads list
|
||||
*/
|
||||
|
@ -428,4 +439,13 @@ public class DownloadRequester implements DownloadStateProvider {
|
|||
}
|
||||
return filename;
|
||||
}
|
||||
|
||||
public void updateProgress(List<Downloader> newDownloads) {
|
||||
for (Downloader downloader : newDownloads) {
|
||||
DownloadRequest request = downloader.getDownloadRequest();
|
||||
if (downloads.containsKey(request.getSource())) {
|
||||
downloads.put(request.getSource(), request);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue