package de.danoeh.antennapod.adapter;
import android.os.Build;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;
import android.text.Layout;
import android.util.Log;
import android.view.ContextMenu;
import android.view.LayoutInflater;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.joanzapata.iconify.Iconify;
import com.nineoldandroids.view.ViewHelper;
import java.lang.ref.WeakReference;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.glide.ApGlideSettings;
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.util.LongList;
import de.danoeh.antennapod.core.util.NetworkUtils;
import de.danoeh.antennapod.fragment.ItemFragment;
import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
/**
* List adapter for the list of new episodes
*/
public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesRecycleAdapter.Holder> {
private static final String TAG = AllEpisodesRecycleAdapter.class.getSimpleName();
private final WeakReference<MainActivity> mainActivityRef;
private final ItemAccess itemAccess;
private final ActionButtonCallback actionButtonCallback;
private final ActionButtonUtils actionButtonUtils;
private final boolean showOnlyNewEpisodes;
private int position = -1;
private final int playingBackGroundColor;
private final int normalBackGroundColor;
public AllEpisodesRecycleAdapter(MainActivity mainActivity,
ItemAccess itemAccess,
ActionButtonCallback actionButtonCallback,
boolean showOnlyNewEpisodes) {
super();
this.mainActivityRef = new WeakReference<>(mainActivity);
this.itemAccess = itemAccess;
this.actionButtonUtils = new ActionButtonUtils(mainActivity);
this.actionButtonCallback = actionButtonCallback;
this.showOnlyNewEpisodes = showOnlyNewEpisodes;
if(UserPreferences.getTheme() == R.style.Theme_AntennaPod_Dark) {
playingBackGroundColor = ContextCompat.getColor(mainActivity, R.color.highlight_dark);
} else {
playingBackGroundColor = ContextCompat.getColor(mainActivity, R.color.highlight_light);
}
normalBackGroundColor = ContextCompat.getColor(mainActivity, android.R.color.transparent);
}
@Override
public Holder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.new_episodes_listitem, parent, false);
Holder holder = new Holder(view);
holder.container = (FrameLayout) view.findViewById(R.id.container);
holder.content = (LinearLayout) view.findViewById(R.id.content);
holder.placeholder = (TextView) view.findViewById(R.id.txtvPlaceholder);
holder.title = (TextView) view.findViewById(R.id.txtvTitle);
if(Build.VERSION.SDK_INT >= 23) {
holder.title.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_FULL);
}
holder.pubDate = (TextView) view
.findViewById(R.id.txtvPublished);
holder.statusUnread = view.findViewById(R.id.statusUnread);
holder.butSecondary = (ImageButton) view
.findViewById(R.id.butSecondaryAction);
holder.queueStatus = (ImageView) view
.findViewById(R.id.imgvInPlaylist);
holder.progress = (ProgressBar) view
.findViewById(R.id.pbar_progress);
holder.cover = (ImageView) view.findViewById(R.id.imgvCover);
holder.txtvDuration = (TextView) view.findViewById(R.id.txtvDuration);
holder.item = null;
holder.mainActivityRef = mainActivityRef;
holder.position = -1;
// so we can grab this later
view.setTag(holder);
return holder;
}
@Override
public void onBindViewHolder(final Holder holder, int position) {
final FeedItem item = itemAccess.getItem(position);
if (item == null) return;
holder.itemView.setOnLongClickListener(v -> {
this.position = position;
return false;
});
holder.item = item;
holder.position = position;
holder.placeholder.setVisibility(View.VISIBLE);
holder.placeholder.setText(item.getFeed().getTitle());
holder.title.setText(item.getTitle());
String pubDateStr = DateUtils.formatAbbrev(mainActivityRef.get(), item.getPubDate());
holder.pubDate.setText(pubDateStr);
if (showOnlyNewEpisodes || !item.isNew()) {
holder.statusUnread.setVisibility(View.INVISIBLE);
} else {
holder.statusUnread.setVisibility(View.VISIBLE);
}
if(item.isPlayed()) {
ViewHelper.setAlpha(holder.content, 0.5f);
} else {
ViewHelper.setAlpha(holder.content, 1.0f);
}
FeedMedia media = item.getMedia();
if (media != null) {
final boolean isDownloadingMedia = DownloadRequester.getInstance().isDownloadingFile(media);
if (media.getDuration() > 0) {
holder.txtvDuration.setText(Converter.getDurationStringLong(media.getDuration()));
} else if (media.getSize() > 0) {
holder.txtvDuration.setText(Converter.byteToString(media.getSize()));
} else if(NetworkUtils.isDownloadAllowed() && !media.checkedOnSizeButUnknown()) {
holder.txtvDuration.setText("{fa-spinner}");
Iconify.addIcons(holder.txtvDuration);
NetworkUtils.getFeedMediaSizeObservable(media)
.subscribe(
size -> {
if (size > 0) {
holder.txtvDuration.setText(Converter.byteToString(size));
} else {
holder.txtvDuration.setText("");
}
}, error -> {
holder.txtvDuration.setText("");
Log.e(TAG, Log.getStackTraceString(error));
});
} else {
holder.txtvDuration.setText("");
}
FeedItem.State state = item.getState();
if (isDownloadingMedia) {
holder.progress.setVisibility(View.VISIBLE);
// item is being downloaded
holder.progress.setProgress(itemAccess.getItemDownloadProgressPercent(item));
} else if (state == FeedItem.State.PLAYING
|| state == FeedItem.State.IN_PROGRESS) {
if (media.getDuration() > 0) {
int progress = (int) (100.0 * media.getPosition() / media.getDuration());
holder.progress.setProgress(progress);
holder.progress.setVisibility(View.VISIBLE);
}
} else {
holder.progress.setVisibility(View.GONE);
}
if(media.isCurrentlyPlaying()) {
holder.container.setBackgroundColor(playingBackGroundColor);
} else {
holder.container.setBackgroundColor(normalBackGroundColor);
}
} else {
holder.progress.setVisibility(View.GONE);
holder.txtvDuration.setVisibility(View.GONE);
}
boolean isInQueue = itemAccess.isInQueue(item);
if (isInQueue) {
holder.queueStatus.setVisibility(View.VISIBLE);
} else {
holder.queueStatus.setVisibility(View.INVISIBLE);
}
actionButtonUtils.configureActionButton(holder.butSecondary, item, isInQueue);
holder.butSecondary.setFocusable(false);
holder.butSecondary.setTag(item);
holder.butSecondary.setOnClickListener(secondaryActionListener);
Glide.with(mainActivityRef.get())
.load(item.getImageUri())
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
.fitCenter()
.dontAnimate()
.into(new CoverTarget(item.getFeed().getImageUri(), holder.placeholder, holder.cover, mainActivityRef.get()));
}
@Override
public long getItemId(int position) {
FeedItem item = itemAccess.getItem(position);
return item != null ? item.getId() : RecyclerView.NO_POSITION;
}
@Override
public int getItemCount() {
return itemAccess.getCount();
}
public FeedItem getItem(int position) {
return itemAccess.getItem(position);
}
public int getPosition() {
int pos = position;
position = -1; // reset
return pos;
}
private View.OnClickListener secondaryActionListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
FeedItem item = (FeedItem) v.getTag();
actionButtonCallback.onActionButtonPressed(item);
}
};
public class Holder extends RecyclerView.ViewHolder
implements View.OnClickListener,
View.OnCreateContextMenuListener,
ItemTouchHelperViewHolder {
LinearLayout content;
FrameLayout container;
TextView placeholder;
TextView title;
TextView pubDate;
View statusUnread;
ImageView queueStatus;
ImageView cover;
ProgressBar progress;
TextView txtvDuration;
ImageButton butSecondary;
FeedItem item;
WeakReference<MainActivity> mainActivityRef;
int position;
public Holder(View itemView) {
super(itemView);
itemView.setOnClickListener(this);
itemView.setOnCreateContextMenuListener(this);
}
@Override
public void onClick(View v) {
MainActivity mainActivity = mainActivityRef.get();
if (mainActivity != null) {
long[] ids = itemAccess.getItemsIds().toArray();
mainActivity.loadChildFragment(ItemFragment.newInstance(ids, position));
}
}
@Override
public void onItemSelected() {
ViewHelper.setAlpha(itemView, 0.5f);
}
@Override
public void onItemClear() {
ViewHelper.setAlpha(itemView, 1.0f);
}
public FeedItem getFeedItem() { return item; }
@Override
public void onCreateContextMenu(final ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
FeedItem item = itemAccess.getItem(getAdapterPosition());
MenuInflater inflater = mainActivityRef.get().getMenuInflater();
inflater.inflate(R.menu.allepisodes_context, menu);
if (item != null) {
menu.setHeaderTitle(item.getTitle());
}
FeedItemMenuHandler.MenuInterface contextMenuInterface = (id, visible) -> {
if (menu == null) {
return;
}
MenuItem item1 = menu.findItem(id);
if (item1 != null) {
item1.setVisible(visible);
}
};
FeedItemMenuHandler.onPrepareMenu(contextMenuInterface, item, true, null);
}
}
public interface ItemAccess {
int getCount();
FeedItem getItem(int position);
LongList getItemsIds();
int getItemDownloadProgressPercent(FeedItem item);
boolean isInQueue(FeedItem item);
}
/**
* Notifies a View Holder of relevant callbacks from
* {@link ItemTouchHelper.Callback}.
*/
public interface ItemTouchHelperViewHolder {
/**
* Called when the {@link ItemTouchHelper} first registers an
* item as being moved or swiped.
* Implementations should update the item view to indicate
* it's active state.
*/
void onItemSelected();
/**
* Called when the {@link ItemTouchHelper} has completed the
* move or swipe, and the active item state should be cleared.
*/
void onItemClear();
}
}