Replaced all episodes list with new adapter

This commit is contained in:
ByteHamster 2020-02-04 23:13:15 +01:00
parent e14ad4d859
commit 17aae8c2db
7 changed files with 54 additions and 425 deletions

View File

@ -1,54 +1,29 @@
package de.danoeh.antennapod.adapter; package de.danoeh.antennapod.adapter;
import android.os.Build;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.ItemTouchHelper;
import android.text.Layout;
import android.util.Log;
import android.view.ContextMenu; import android.view.ContextMenu;
import android.view.LayoutInflater;
import android.view.MenuInflater; import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.FrameLayout; import androidx.annotation.NonNull;
import android.widget.ImageButton; import androidx.annotation.Nullable;
import android.widget.ImageView; import androidx.recyclerview.widget.ItemTouchHelper;
import android.widget.LinearLayout; import androidx.recyclerview.widget.RecyclerView;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.joanzapata.iconify.Iconify;
import java.lang.ref.WeakReference;
import java.util.List;
import de.danoeh.antennapod.R; import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity; import de.danoeh.antennapod.activity.MainActivity;
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.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
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.LongList;
import de.danoeh.antennapod.core.util.NetworkUtils;
import de.danoeh.antennapod.core.util.ThemeUtils;
import de.danoeh.antennapod.fragment.ItemFragment;
import de.danoeh.antennapod.fragment.ItemPagerFragment; import de.danoeh.antennapod.fragment.ItemPagerFragment;
import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler; import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
import de.danoeh.antennapod.view.EpisodeItemViewHolder;
import org.apache.commons.lang3.ArrayUtils;
import java.lang.ref.WeakReference;
/** /**
* List adapter for the list of new episodes * List adapter for the list of new episodes.
*/ */
public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesRecycleAdapter.Holder> { public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<EpisodeItemViewHolder>
implements View.OnCreateContextMenuListener {
private static final String TAG = AllEpisodesRecycleAdapter.class.getSimpleName();
private final WeakReference<MainActivity> mainActivityRef; private final WeakReference<MainActivity> mainActivityRef;
private final ItemAccess itemAccess; private final ItemAccess itemAccess;
@ -56,149 +31,38 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
private FeedItem selectedItem; private FeedItem selectedItem;
private final int playingBackGroundColor; public AllEpisodesRecycleAdapter(MainActivity mainActivity, ItemAccess itemAccess, boolean showOnlyNewEpisodes) {
private final int normalBackGroundColor;
public AllEpisodesRecycleAdapter(MainActivity mainActivity,
ItemAccess itemAccess,
boolean showOnlyNewEpisodes) {
super(); super();
this.mainActivityRef = new WeakReference<>(mainActivity); this.mainActivityRef = new WeakReference<>(mainActivity);
this.itemAccess = itemAccess; this.itemAccess = itemAccess;
this.showOnlyNewEpisodes = showOnlyNewEpisodes; this.showOnlyNewEpisodes = showOnlyNewEpisodes;
}
playingBackGroundColor = ThemeUtils.getColorFromAttr(mainActivity, R.attr.currently_playing_background); @NonNull
normalBackGroundColor = ContextCompat.getColor(mainActivity, android.R.color.transparent); @Override
public EpisodeItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
EpisodeItemViewHolder viewHolder = new EpisodeItemViewHolder(mainActivityRef.get(), parent);
viewHolder.dragHandle.setVisibility(View.GONE);
return viewHolder;
} }
@Override @Override
public Holder onCreateViewHolder(ViewGroup parent, int viewType) { public void onBindViewHolder(EpisodeItemViewHolder holder, int pos) {
View view = LayoutInflater.from(parent.getContext()) FeedItem item = itemAccess.getItem(pos);
.inflate(R.layout.new_episodes_listitem, parent, false); holder.bind(item);
Holder holder = new Holder(view);
holder.container = view.findViewById(R.id.container);
holder.content = view.findViewById(R.id.content);
holder.placeholder = view.findViewById(R.id.txtvPlaceholder);
holder.title = view.findViewById(R.id.txtvTitle);
if(Build.VERSION.SDK_INT >= 23) {
holder.title.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_FULL);
}
holder.pubDate = view
.findViewById(R.id.txtvPublished);
holder.statusUnread = view.findViewById(R.id.statusUnread);
holder.butSecondary = view
.findViewById(R.id.butSecondaryAction);
holder.queueStatus = view
.findViewById(R.id.imgvInPlaylist);
holder.progress = view
.findViewById(R.id.pbar_progress);
holder.cover = view.findViewById(R.id.imgvCover);
holder.txtvDuration = view.findViewById(R.id.txtvDuration);
holder.item = null;
holder.mainActivityRef = mainActivityRef;
// 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 -> { holder.itemView.setOnLongClickListener(v -> {
this.selectedItem = item; selectedItem = item;
return false; return false;
}); });
holder.item = item; holder.itemView.setOnClickListener(v -> {
holder.placeholder.setVisibility(View.VISIBLE); MainActivity activity = mainActivityRef.get();
holder.placeholder.setText(item.getFeed().getTitle()); if (activity != null) {
holder.title.setText(item.getTitle()); long[] ids = itemAccess.getQueueIds().toArray();
String pubDateStr = DateUtils.formatAbbrev(mainActivityRef.get(), item.getPubDate()); int position = ArrayUtils.indexOf(ids, item.getId());
holder.pubDate.setText(pubDateStr); activity.loadChildFragment(ItemPagerFragment.newInstance(ids, position));
if (showOnlyNewEpisodes || !item.isNew()) {
holder.statusUnread.setVisibility(View.INVISIBLE);
} else {
holder.statusUnread.setVisibility(View.VISIBLE);
} }
if(item.isPlayed()) {
holder.content.setAlpha(0.5f);
} else {
holder.content.setAlpha(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.isEpisodeHeadDownloadAllowed() && !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.itemView.setOnCreateContextMenuListener(this);
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.INVISIBLE);
}
if (media.isCurrentlyPlaying()) {
holder.container.setBackgroundColor(playingBackGroundColor);
} else {
holder.container.setBackgroundColor(normalBackGroundColor);
}
} else {
holder.progress.setVisibility(View.INVISIBLE);
holder.txtvDuration.setVisibility(View.GONE);
}
boolean isInQueue = itemAccess.isInQueue(item);
if (isInQueue) {
holder.queueStatus.setVisibility(View.VISIBLE);
} else {
holder.queueStatus.setVisibility(View.INVISIBLE);
}
ItemActionButton actionButton = ItemActionButton.forItem(item, isInQueue);
actionButton.configure(holder.butSecondary, mainActivityRef.get());
holder.butSecondary.setFocusable(false);
holder.butSecondary.setTag(item);
new CoverLoader(mainActivityRef.get())
.withUri(ImageResourceUtils.getImageLocation(item))
.withFallbackUri(item.getFeed().getImageLocation())
.withPlaceholderView(holder.placeholder)
.withCoverView(holder.cover)
.load();
} }
@Nullable @Nullable
@ -217,73 +81,12 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
return itemAccess.getCount(); return itemAccess.getCount();
} }
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;
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) {
LongList itemIds = itemAccess.getItemsIds();
long[] ids = itemIds.toArray();
mainActivity.loadChildFragment(ItemPagerFragment.newInstance(ids, itemIds.indexOf(item.getId())));
}
}
@Override
public void onItemSelected() {
itemView.setAlpha(0.5f);
}
@Override
public void onItemClear() {
itemView.setAlpha(1.0f);
}
public FeedItem getFeedItem() { return item; }
@Override @Override
public void onCreateContextMenu(final ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { public void onCreateContextMenu(final ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
FeedItem item = itemAccess.getItem(getAdapterPosition());
MenuInflater inflater = mainActivityRef.get().getMenuInflater(); MenuInflater inflater = mainActivityRef.get().getMenuInflater();
inflater.inflate(R.menu.feeditemlist_context, menu); inflater.inflate(R.menu.feeditemlist_context, menu);
menu.setHeaderTitle(selectedItem.getTitle());
if (item != null) { FeedItemMenuHandler.onPrepareMenu(menu, selectedItem, R.id.skip_episode_item);
menu.setHeaderTitle(item.getTitle());
}
FeedItemMenuHandler.onPrepareMenu(menu, item);
}
public boolean isCurrentlyPlayingItem() {
return item.getMedia() != null && item.getMedia().isCurrentlyPlaying();
}
public void notifyPlaybackPositionUpdated(PlaybackPositionEvent event) {
progress.setProgress((int) (100.0 * event.getPosition() / event.getDuration()));
}
} }
public interface ItemAccess { public interface ItemAccess {
@ -292,12 +95,6 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR
FeedItem getItem(int position); FeedItem getItem(int position);
LongList getItemsIds();
int getItemDownloadProgressPercent(FeedItem item);
boolean isInQueue(FeedItem item);
LongList getQueueIds(); LongList getQueueIds();
} }

View File

@ -28,6 +28,7 @@ import de.danoeh.antennapod.core.event.FeedListUpdateEvent;
import de.danoeh.antennapod.core.event.PlaybackPositionEvent; import de.danoeh.antennapod.core.event.PlaybackPositionEvent;
import de.danoeh.antennapod.core.event.PlayerStatusEvent; import de.danoeh.antennapod.core.event.PlayerStatusEvent;
import de.danoeh.antennapod.core.event.UnreadItemsUpdateEvent; import de.danoeh.antennapod.core.event.UnreadItemsUpdateEvent;
import de.danoeh.antennapod.view.EpisodeItemViewHolder;
import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode; import org.greenrobot.eventbus.ThreadMode;
@ -384,32 +385,6 @@ public abstract class EpisodesListFragment extends Fragment {
return null; return null;
} }
@Override
public LongList getItemsIds() {
LongList ids = new LongList(episodes.size());
for (FeedItem episode : episodes) {
ids.add(episode.getId());
}
return ids;
}
@Override
public int getItemDownloadProgressPercent(FeedItem item) {
for (Downloader downloader : downloaderList) {
DownloadRequest downloadRequest = downloader.getDownloadRequest();
if (downloadRequest.getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA
&& downloadRequest.getFeedfileId() == item.getMedia().getId()) {
return downloadRequest.getProgressPercent();
}
}
return 0;
}
@Override
public boolean isInQueue(FeedItem item) {
return item != null && item.isTagged(FeedItem.TAG_QUEUE);
}
@Override @Override
public LongList getQueueIds() { public LongList getQueueIds() {
LongList queueIds = new LongList(); LongList queueIds = new LongList();
@ -444,8 +419,7 @@ public abstract class EpisodesListFragment extends Fragment {
public void onEventMainThread(PlaybackPositionEvent event) { public void onEventMainThread(PlaybackPositionEvent event) {
if (listAdapter != null) { if (listAdapter != null) {
for (int i = 0; i < listAdapter.getItemCount(); i++) { for (int i = 0; i < listAdapter.getItemCount(); i++) {
AllEpisodesRecycleAdapter.Holder holder = (AllEpisodesRecycleAdapter.Holder) EpisodeItemViewHolder holder = (EpisodeItemViewHolder) recyclerView.findViewHolderForAdapterPosition(i);
recyclerView.findViewHolderForAdapterPosition(i);
if (holder != null && holder.isCurrentlyPlayingItem()) { if (holder != null && holder.isCurrentlyPlayingItem()) {
holder.notifyPlaybackPositionUpdated(event); holder.notifyPlaybackPositionUpdated(event);
break; break;

View File

@ -10,6 +10,7 @@ import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import de.danoeh.antennapod.view.EpisodeItemViewHolder;
import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.Subscribe;
import java.util.List; import java.util.List;
@ -63,8 +64,8 @@ public class FavoriteEpisodesFragment extends EpisodesListFragment {
@Override @Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int swipeDir) { public void onSwiped(RecyclerView.ViewHolder viewHolder, int swipeDir) {
AllEpisodesRecycleAdapter.Holder holder = (AllEpisodesRecycleAdapter.Holder) viewHolder; EpisodeItemViewHolder holder = (EpisodeItemViewHolder) viewHolder;
Log.d(TAG, String.format("remove(%s)", holder.getItemId())); Log.d(TAG, String.format("remove(%s)", holder.getFeedItem().getId()));
if (disposable != null) { if (disposable != null) {
disposable.dispose(); disposable.dispose();

View File

@ -16,6 +16,7 @@ import de.danoeh.antennapod.adapter.AllEpisodesRecycleAdapter;
import de.danoeh.antennapod.core.feed.FeedItem; import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.storage.DBReader; import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler; import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
import de.danoeh.antennapod.view.EpisodeItemViewHolder;
/** /**
* Like 'EpisodesFragment' except that it only shows new episodes and * Like 'EpisodesFragment' except that it only shows new episodes and
@ -63,7 +64,7 @@ public class NewEpisodesFragment extends EpisodesListFragment {
@Override @Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int swipeDir) { public void onSwiped(RecyclerView.ViewHolder viewHolder, int swipeDir) {
AllEpisodesRecycleAdapter.Holder holder = (AllEpisodesRecycleAdapter.Holder) viewHolder; EpisodeItemViewHolder holder = (EpisodeItemViewHolder) viewHolder;
FeedItemMenuHandler.removeNewFlagWithUndo(NewEpisodesFragment.this, holder.getFeedItem()); FeedItemMenuHandler.removeNewFlagWithUndo(NewEpisodesFragment.this, holder.getFeedItem());
} }

View File

@ -176,6 +176,10 @@ public class EpisodeItemViewHolder extends RecyclerView.ViewHolder
} }
} }
public FeedItem getFeedItem() {
return item;
}
public boolean isCurrentlyPlayingItem() { public boolean isCurrentlyPlayingItem() {
return item.getMedia() != null && item.getMedia().isCurrentlyPlaying(); return item.getMedia() != null && item.getMedia().isCurrentlyPlaying();
} }

View File

@ -7,7 +7,6 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="horizontal" android:orientation="horizontal"
tools:layout_height="150dp"
android:gravity="center_vertical" android:gravity="center_vertical"
android:baselineAligned="false"> android:baselineAligned="false">
@ -48,8 +47,7 @@
android:layout_height="@dimen/thumbnail_length_queue_item" android:layout_height="@dimen/thumbnail_length_queue_item"
android:layout_centerVertical="true" android:layout_centerVertical="true"
android:contentDescription="@string/cover_label" android:contentDescription="@string/cover_label"
tools:src="@drawable/ic_antenna" tools:src="@tools:sample/avatars" />
tools:background="@android:color/holo_green_dark"/>
</RelativeLayout> </RelativeLayout>
@ -80,7 +78,8 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:id="@+id/statusUnread" android:id="@+id/statusUnread"
android:layout_marginRight="4dp" android:layout_marginRight="4dp"
android:layout_marginEnd="4dp"/> android:layout_marginEnd="4dp"
tools:text="@sample/episodes.json/data/status_label"/>
<ImageView <ImageView
android:layout_width="16dp" android:layout_width="16dp"
@ -121,7 +120,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginRight="4dp" android:layout_marginRight="4dp"
android:layout_marginEnd="4dp" android:layout_marginEnd="4dp"
tools:text="Feb 12"/> tools:text="@sample/episodes.json/data/published_at"/>
<TextView <TextView
style="@style/AntennaPod.TextView.ListItemSecondaryTitle" style="@style/AntennaPod.TextView.ListItemSecondaryTitle"
@ -147,7 +146,7 @@
style="@style/AntennaPod.TextView.ListItemPrimaryTitle" style="@style/AntennaPod.TextView.ListItemPrimaryTitle"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
tools:text="Item title" tools:text="@sample/episodes.json/data/title"
android:ellipsize="end" android:ellipsize="end"
tools:background="@android:color/holo_blue_light"/> tools:background="@android:color/holo_blue_light"/>
@ -183,7 +182,7 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="0dp" android:layout_marginBottom="0dp"
tools:text="01:23:23" tools:text="@sample/episodes.json/data/duration"
tools:background="@android:color/holo_blue_light"/> tools:background="@android:color/holo_blue_light"/>
</LinearLayout> </LinearLayout>

View File

@ -1,147 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
android:id="@+id/container"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:orientation="horizontal"
android:gravity="center_vertical">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="@+id/txtvPlaceholder"
android:layout_width="@dimen/thumbnail_length_itemlist"
android:layout_height="@dimen/thumbnail_length_itemlist"
android:layout_gravity="center_vertical"
android:layout_marginBottom="@dimen/listitem_threeline_verticalpadding"
android:layout_marginLeft="@dimen/listitem_threeline_horizontalpadding"
android:layout_marginStart="@dimen/listitem_threeline_horizontalpadding"
android:layout_marginTop="@dimen/listitem_threeline_verticalpadding"
android:background="@color/light_gray"
android:ellipsize="end"
android:maxLines="3"
android:gravity="center"/>
<ImageView
android:id="@+id/imgvCover"
android:layout_height="64dp"
android:layout_width="64dp"
android:layout_alignLeft="@id/txtvPlaceholder"
android:layout_alignStart="@id/txtvPlaceholder"
android:layout_alignTop="@id/txtvPlaceholder"
android:layout_alignRight="@id/txtvPlaceholder"
android:layout_alignEnd="@id/txtvPlaceholder"
android:layout_alignBottom="@id/txtvPlaceholder"
android:contentDescription="@string/cover_label"
tools:src="@tools:sample/avatars" />
</RelativeLayout>
<RelativeLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/listitem_threeline_verticalpadding"
android:layout_marginLeft="@dimen/listitem_threeline_textleftpadding"
android:layout_marginStart="@dimen/listitem_threeline_textleftpadding"
android:layout_marginRight="@dimen/listitem_threeline_textrightpadding"
android:layout_marginEnd="@dimen/listitem_threeline_textrightpadding"
android:layout_marginTop="@dimen/listitem_threeline_verticalpadding"
android:layout_weight="1">
<TextView
android:id="@+id/statusUnread"
style="@style/AntennaPod.TextView.UnreadIndicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
tools:text="@sample/episodes.json/data/status_label"/>
<TextView
android:id="@+id/txtvTitle"
style="@style/AntennaPod.TextView.ListItemPrimaryTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_toLeftOf="@id/statusUnread"
android:layout_toStartOf="@id/statusUnread"
tools:text="@sample/episodes.json/data/title" />
<RelativeLayout
android:id="@+id/bottom_bar"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_below="@id/txtvTitle"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true">
<TextView
android:id="@+id/txtvDuration"
style="@style/AntennaPod.TextView.ListItemSecondaryTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
tools:text="@sample/episodes.json/data/duration" />
<ImageView
android:id="@+id/imgvInPlaylist"
android:layout_width="@dimen/enc_icons_size"
android:layout_height="@dimen/enc_icons_size"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:contentDescription="@string/in_queue_label"
android:src="?attr/stat_playlist"
tools:src="@sample/inplaylist" />
<TextView
android:id="@+id/txtvPublished"
style="@style/AntennaPod.TextView.ListItemSecondaryTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_toLeftOf="@id/imgvInPlaylist"
android:layout_toStartOf="@id/imgvInPlaylist"
android:ellipsize="end"
tools:text="@sample/episodes.json/data/published_at" />
<ProgressBar
android:id="@+id/pbar_progress"
style="?attr/progressBarTheme"
android:layout_width="match_parent"
android:layout_height="4dp"
android:layout_below="@id/txtvDuration"
android:max="100" />
</RelativeLayout>
</RelativeLayout>
<include layout="@layout/vertical_list_divider"/>
<include layout="@layout/secondary_action" />
</LinearLayout>
</FrameLayout>