diff options
Diffstat (limited to 'app/src/main')
21 files changed, 661 insertions, 1558 deletions
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/AdapterUtils.java b/app/src/main/java/de/danoeh/antennapod/adapter/AdapterUtils.java deleted file mode 100644 index 315b3a173..000000000 --- a/app/src/main/java/de/danoeh/antennapod/adapter/AdapterUtils.java +++ /dev/null @@ -1,74 +0,0 @@ -package de.danoeh.antennapod.adapter; - -import android.util.Log; -import android.view.View; -import android.widget.ProgressBar; -import android.widget.TextView; - -import com.joanzapata.iconify.Iconify; - -import de.danoeh.antennapod.core.feed.FeedItem; -import de.danoeh.antennapod.core.feed.FeedMedia; -import de.danoeh.antennapod.core.util.Converter; -import de.danoeh.antennapod.core.util.NetworkUtils; - -/** - * Utility methods for adapters - */ -class AdapterUtils { - - private static final String TAG = AdapterUtils.class.getSimpleName(); - - private AdapterUtils() { - - } - - /** - * Updates the contents of the TextView that shows the current playback position and the ProgressBar. - */ - static void updateEpisodePlaybackProgress(FeedItem item, TextView txtvPos, ProgressBar episodeProgress) { - FeedMedia media = item.getMedia(); - episodeProgress.setVisibility(View.GONE); - if (media == null) { - txtvPos.setVisibility(View.GONE); - return; - } else { - txtvPos.setVisibility(View.VISIBLE); - } - - FeedItem.State state = item.getState(); - if (state == FeedItem.State.PLAYING - || state == FeedItem.State.IN_PROGRESS) { - if (media.getDuration() > 0) { - episodeProgress.setVisibility(View.VISIBLE); - episodeProgress.setProgress((int) (((double) media - .getPosition()) / media.getDuration() * 100)); - txtvPos.setText(Converter.getDurationStringLong(media.getDuration() - - media.getPosition())); - } - } else if (!media.isDownloaded()) { - if (media.getSize() > 0) { - txtvPos.setText(Converter.byteToString(media.getSize())); - } else if(NetworkUtils.isEpisodeHeadDownloadAllowed() && !media.checkedOnSizeButUnknown()) { - txtvPos.setText("{fa-spinner}"); - Iconify.addIcons(txtvPos); - NetworkUtils.getFeedMediaSizeObservable(media) - .subscribe( - size -> { - if (size > 0) { - txtvPos.setText(Converter.byteToString(size)); - } else { - txtvPos.setText(""); - } - }, error -> { - txtvPos.setText(""); - Log.e(TAG, Log.getStackTraceString(error)); - }); - } else { - txtvPos.setText(""); - } - } else { - txtvPos.setText(Converter.getDurationStringLong(media.getDuration())); - } - } -} diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java index d0e0eac9e..c9b8e5ab2 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java @@ -1,204 +1,73 @@ 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.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.joanzapata.iconify.Iconify; - -import java.lang.ref.WeakReference; -import java.util.List; - +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +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.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.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.fragment.ItemFragment; +import de.danoeh.antennapod.core.util.FeedItemUtil; 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 java.util.ArrayList; +import java.util.List; /** - * List adapter for the list of new episodes + * List adapter for the list of new episodes. */ -public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesRecycleAdapter.Holder> { - - private static final String TAG = AllEpisodesRecycleAdapter.class.getSimpleName(); +public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<EpisodeItemViewHolder> + implements View.OnCreateContextMenuListener { private final WeakReference<MainActivity> mainActivityRef; - private final ItemAccess itemAccess; - private final boolean showOnlyNewEpisodes; + private List<FeedItem> episodes = new ArrayList<>(); private FeedItem selectedItem; - private final int playingBackGroundColor; - private final int normalBackGroundColor; - - public AllEpisodesRecycleAdapter(MainActivity mainActivity, - ItemAccess itemAccess, - boolean showOnlyNewEpisodes) { + public AllEpisodesRecycleAdapter(MainActivity mainActivity) { super(); this.mainActivityRef = new WeakReference<>(mainActivity); - this.itemAccess = itemAccess; - this.showOnlyNewEpisodes = showOnlyNewEpisodes; + } - playingBackGroundColor = ThemeUtils.getColorFromAttr(mainActivity, R.attr.currently_playing_background); - normalBackGroundColor = ContextCompat.getColor(mainActivity, android.R.color.transparent); + public void updateItems(List<FeedItem> items) { + episodes = items; + notifyDataSetChanged(); } + @NonNull @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 = 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; + public EpisodeItemViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + EpisodeItemViewHolder viewHolder = new EpisodeItemViewHolder(mainActivityRef.get(), parent); + viewHolder.dragHandle.setVisibility(View.GONE); + return viewHolder; } @Override - public void onBindViewHolder(final Holder holder, int position) { - final FeedItem item = itemAccess.getItem(position); - if (item == null) return; + public void onBindViewHolder(EpisodeItemViewHolder holder, int pos) { + FeedItem item = episodes.get(pos); + holder.bind(item); holder.itemView.setOnLongClickListener(v -> { - this.selectedItem = item; + selectedItem = item; return false; }); - holder.item = item; - 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()) { - 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.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); + holder.itemView.setOnClickListener(v -> { + MainActivity activity = mainActivityRef.get(); + if (activity != null) { + long[] ids = FeedItemUtil.getIds(episodes); + int position = ArrayUtils.indexOf(ids, item.getId()); + activity.loadChildFragment(ItemPagerFragment.newInstance(ids, position)); } - - 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, true); - 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(); + }); + holder.itemView.setOnCreateContextMenuListener(this); + holder.hideSeparatorIfNecessary(); } @Nullable @@ -208,98 +77,21 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter<AllEpisodesR @Override public long getItemId(int position) { - FeedItem item = itemAccess.getItem(position); + FeedItem item = episodes.get(position); return item != null ? item.getId() : RecyclerView.NO_POSITION; } @Override public int getItemCount() { - return itemAccess.getCount(); + return episodes.size(); } - 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 - 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.feeditemlist_context, menu); - - if (item != null) { - 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 { - - int getCount(); - - FeedItem getItem(int position); - - LongList getItemsIds(); - - int getItemDownloadProgressPercent(FeedItem item); - - boolean isInQueue(FeedItem item); - - LongList getQueueIds(); - + @Override + public void onCreateContextMenu(final ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { + MenuInflater inflater = mainActivityRef.get().getMenuInflater(); + inflater.inflate(R.menu.feeditemlist_context, menu); + menu.setHeaderTitle(selectedItem.getTitle()); + FeedItemMenuHandler.onPrepareMenu(menu, selectedItem, R.id.skip_episode_item); } /** diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/DownloadedEpisodesListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/DownloadedEpisodesListAdapter.java index b083908a8..37d570e26 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/DownloadedEpisodesListAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/DownloadedEpisodesListAdapter.java @@ -1,37 +1,24 @@ package de.danoeh.antennapod.adapter; -import android.content.Context; -import android.os.Build; -import android.text.Layout; -import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; -import android.widget.ImageButton; -import android.widget.ImageView; -import android.widget.TextView; - -import com.bumptech.glide.Glide; - -import com.bumptech.glide.request.RequestOptions; import de.danoeh.antennapod.R; +import de.danoeh.antennapod.activity.MainActivity; import de.danoeh.antennapod.core.feed.FeedItem; -import de.danoeh.antennapod.core.glide.ApGlideSettings; -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.view.EpisodeItemViewHolder; /** - * Shows a list of downloaded episodes + * Shows a list of downloaded episodes. */ public class DownloadedEpisodesListAdapter extends BaseAdapter { - private final Context context; + private final MainActivity activity; private final ItemAccess itemAccess; - public DownloadedEpisodesListAdapter(Context context, ItemAccess itemAccess) { + public DownloadedEpisodesListAdapter(MainActivity activity, ItemAccess itemAccess) { super(); - this.context = context; + this.activity = activity; this.itemAccess = itemAccess; } @@ -52,77 +39,21 @@ public class DownloadedEpisodesListAdapter extends BaseAdapter { @Override public View getView(int position, View convertView, ViewGroup parent) { - Holder holder; - final FeedItem item = getItem(position); - if (item == null) return null; - + EpisodeItemViewHolder holder; if (convertView == null) { - holder = new Holder(); - LayoutInflater inflater = (LayoutInflater) context - .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - convertView = inflater.inflate(R.layout.downloaded_episodeslist_item, - parent, false); - holder.imageView = convertView.findViewById(R.id.imgvImage); - holder.title = convertView.findViewById(R.id.txtvTitle); - if(Build.VERSION.SDK_INT >= 23) { - holder.title.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_FULL); - } - holder.txtvSize = convertView.findViewById(R.id.txtvSize); - holder.queueStatus = convertView.findViewById(R.id.imgvInPlaylist); - holder.pubDate = convertView - .findViewById(R.id.txtvPublished); - holder.butSecondary = convertView - .findViewById(R.id.butSecondaryAction); - convertView.setTag(holder); - } else { - holder = (Holder) convertView.getTag(); - } - - Glide.with(context) - .load(ImageResourceUtils.getImageLocation(item)) - .apply(new RequestOptions() - .placeholder(R.color.light_gray) - .error(R.color.light_gray) - .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY) - .fitCenter() - .dontAnimate()) - .into(holder.imageView); - - if(item.isPlayed()) { - convertView.setAlpha(0.5f); + holder = new EpisodeItemViewHolder(activity, parent); } else { - convertView.setAlpha(1.0f); + holder = (EpisodeItemViewHolder) convertView.getTag(); } - holder.title.setText(item.getTitle()); - holder.txtvSize.setText(Converter.byteToString(item.getMedia().getSize())); - holder.queueStatus.setVisibility(item.isTagged(FeedItem.TAG_QUEUE) ? View.VISIBLE : View.GONE); - String pubDateStr = DateUtils.formatAbbrev(context, item.getPubDate()); - holder.pubDate.setText(pubDateStr); - - holder.butSecondary.setFocusable(false); - holder.butSecondary.setTag(item); - holder.butSecondary.setOnClickListener(secondaryActionListener); - - return convertView; - } - - private final View.OnClickListener secondaryActionListener = new View.OnClickListener() { - @Override - public void onClick(View v) { - FeedItem item = (FeedItem) v.getTag(); - itemAccess.onFeedItemSecondaryAction(item); - } - }; - + final FeedItem item = getItem(position); + holder.bind(item); + holder.dragHandle.setVisibility(View.GONE); + holder.secondaryActionIcon.setImageResource(R.drawable.ic_delete_grey600_24dp); + holder.secondaryActionButton.setOnClickListener(v -> itemAccess.onFeedItemSecondaryAction(item)); + holder.hideSeparatorIfNecessary(); - static class Holder { - ImageView imageView; - TextView title; - TextView txtvSize; - ImageView queueStatus; - TextView pubDate; - ImageButton butSecondary; + return holder.itemView; } public interface ItemAccess { diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java index 6a88a39ce..87bd3aa5e 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java @@ -1,33 +1,13 @@ package de.danoeh.antennapod.adapter; -import android.content.Context; -import android.content.res.TypedArray; -import android.os.Build; -import androidx.core.content.ContextCompat; -import android.text.Layout; -import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.Adapter; import android.widget.BaseAdapter; -import android.widget.ImageButton; -import android.widget.ImageView; -import android.widget.LinearLayout; import android.widget.ListView; -import android.widget.ProgressBar; -import android.widget.TextView; - -import de.danoeh.antennapod.R; -import de.danoeh.antennapod.adapter.actionbutton.ItemActionButton; +import de.danoeh.antennapod.activity.MainActivity; 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.MediaType; -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.ThemeUtils; +import de.danoeh.antennapod.view.EpisodeItemViewHolder; /** * List adapter for items of feeds that the user has already subscribed to. @@ -35,27 +15,21 @@ import de.danoeh.antennapod.core.util.ThemeUtils; public class FeedItemlistAdapter extends BaseAdapter { private final ItemAccess itemAccess; - private final Context context; - private final boolean showFeedtitle; - /** true if played items should be made partially transparent */ + private final MainActivity activity; private final boolean makePlayedItemsTransparent; - private final int playingBackGroundColor; - private final int normalBackGroundColor; + private final boolean showIcons; private int currentlyPlayingItem = -1; - public FeedItemlistAdapter(Context context, + public FeedItemlistAdapter(MainActivity activity, ItemAccess itemAccess, - boolean showFeedtitle, + boolean showIcons, boolean makePlayedItemsTransparent) { super(); - this.context = context; + this.activity = activity; this.itemAccess = itemAccess; - this.showFeedtitle = showFeedtitle; + this.showIcons = showIcons; this.makePlayedItemsTransparent = makePlayedItemsTransparent; - - playingBackGroundColor = ThemeUtils.getColorFromAttr(context, R.attr.currently_playing_background); - normalBackGroundColor = ContextCompat.getColor(context, android.R.color.transparent); } @Override @@ -75,130 +49,27 @@ public class FeedItemlistAdapter extends BaseAdapter { } @Override - @SuppressWarnings("ResourceType") public View getView(final int position, View convertView, ViewGroup parent) { - Holder holder; - final FeedItem item = getItem(position); - + EpisodeItemViewHolder holder; if (convertView == null) { - holder = new Holder(); - LayoutInflater inflater = (LayoutInflater) context - .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - convertView = inflater.inflate(R.layout.feeditemlist_item, parent, false); - holder.container = convertView - .findViewById(R.id.container); - holder.title = convertView.findViewById(R.id.txtvItemname); - if(Build.VERSION.SDK_INT >= 23) { - holder.title.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_FULL); - } - holder.lenSize = convertView - .findViewById(R.id.txtvLenSize); - holder.butAction = convertView - .findViewById(R.id.butSecondaryAction); - holder.published = convertView - .findViewById(R.id.txtvPublished); - holder.inPlaylist = convertView - .findViewById(R.id.imgvInPlaylist); - holder.type = convertView.findViewById(R.id.imgvType); - holder.statusUnread = convertView - .findViewById(R.id.statusUnread); - holder.episodeProgress = convertView - .findViewById(R.id.pbar_episode_progress); - - convertView.setTag(holder); + holder = new EpisodeItemViewHolder(activity, parent); } else { - holder = (Holder) convertView.getTag(); + holder = (EpisodeItemViewHolder) convertView.getTag(); } - if (!(getItemViewType(position) == Adapter.IGNORE_ITEM_VIEW_TYPE)) { - convertView.setVisibility(View.VISIBLE); - - StringBuilder buffer = new StringBuilder(item.getTitle()); - if (showFeedtitle) { - buffer.append(" ("); - buffer.append(item.getFeed().getTitle()); - buffer.append(")"); - } - holder.title.setText(buffer.toString()); - - if(item.isNew()) { - holder.statusUnread.setVisibility(View.VISIBLE); - } else { - holder.statusUnread.setVisibility(View.INVISIBLE); - } - if(item.isPlayed() && makePlayedItemsTransparent) { - convertView.setAlpha(0.5f); - } else { - convertView.setAlpha(1.0f); - } - - String pubDateStr = DateUtils.formatAbbrev(context, item.getPubDate()); - holder.published.setText(pubDateStr); - - boolean isInQueue = item.isTagged(FeedItem.TAG_QUEUE); - - FeedMedia media = item.getMedia(); - if (media == null) { - holder.episodeProgress.setVisibility(View.INVISIBLE); - holder.inPlaylist.setVisibility(View.INVISIBLE); - holder.type.setVisibility(View.INVISIBLE); - holder.lenSize.setVisibility(View.INVISIBLE); - } else { - - AdapterUtils.updateEpisodePlaybackProgress(item, holder.lenSize, holder.episodeProgress); - - if (isInQueue) { - holder.inPlaylist.setVisibility(View.VISIBLE); - } else { - holder.inPlaylist.setVisibility(View.INVISIBLE); - } - - if (DownloadRequester.getInstance().isDownloadingFile(item.getMedia())) { - holder.episodeProgress.setVisibility(View.VISIBLE); - holder.episodeProgress.setProgress(itemAccess.getItemDownloadProgressPercent(item)); - } else { - if(media.getPosition() == 0) { - holder.episodeProgress.setVisibility(View.INVISIBLE); - } - } - - TypedArray typeDrawables = context.obtainStyledAttributes( - new int[]{R.attr.type_audio, R.attr.type_video}); - final int[] labels = new int[]{R.string.media_type_audio_label, R.string.media_type_video_label}; - - MediaType mediaType = item.getMedia().getMediaType(); - if (mediaType == MediaType.AUDIO) { - holder.type.setImageDrawable(typeDrawables.getDrawable(0)); - holder.type.setContentDescription(context.getString(labels[0])); - holder.type.setVisibility(View.VISIBLE); - } else if (mediaType == MediaType.VIDEO) { - holder.type.setImageDrawable(typeDrawables.getDrawable(1)); - holder.type.setContentDescription(context.getString(labels[1])); - holder.type.setVisibility(View.VISIBLE); - } else { - holder.type.setImageBitmap(null); - holder.type.setVisibility(View.GONE); - } - typeDrawables.recycle(); - - if (media.isCurrentlyPlaying()) { - holder.container.setBackgroundColor(playingBackGroundColor); - currentlyPlayingItem = position; - } else { - holder.container.setBackgroundColor(normalBackGroundColor); - } - } - - ItemActionButton actionButton = ItemActionButton.forItem(item, isInQueue, true); - actionButton.configure(holder.butAction, context); + if (!showIcons) { + holder.coverHolder.setVisibility(View.GONE); + } - holder.butAction.setFocusable(false); - holder.butAction.setTag(item); + final FeedItem item = getItem(position); + holder.bind(item); + holder.dragHandle.setVisibility(View.GONE); - } else { - convertView.setVisibility(View.GONE); + if (item.getMedia() != null && item.getMedia().isCurrentlyPlaying()) { + currentlyPlayingItem = position; } - return convertView; + holder.hideSeparatorIfNecessary(); + return holder.itemView; } public void notifyCurrentlyPlayingItemChanged(PlaybackPositionEvent event, ListView listView) { @@ -208,35 +79,15 @@ public class FeedItemlistAdapter extends BaseAdapter { if (view == null) { return; } - Holder holder = (Holder) view.getTag(); - holder.episodeProgress.setVisibility(View.VISIBLE); - holder.episodeProgress.setProgress((int) (100.0 * event.getPosition() / event.getDuration())); - holder.lenSize.setText(Converter.getDurationStringLong(event.getDuration() - event.getPosition())); + EpisodeItemViewHolder holder = (EpisodeItemViewHolder) view.getTag(); + holder.notifyPlaybackPositionUpdated(event); } } - static class Holder { - LinearLayout container; - TextView title; - TextView published; - TextView lenSize; - ImageView type; - ImageView inPlaylist; - ImageButton butAction; - View statusUnread; - ProgressBar episodeProgress; - } - public interface ItemAccess { - - int getItemDownloadProgressPercent(FeedItem item); - int getCount(); FeedItem getItem(int position); - - LongList getQueueIds(); - } } diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java index 681dee380..d629df4fa 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java @@ -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 de.danoeh.antennapod.fragment.ItemPagerFragment; -import org.apache.commons.lang3.ArrayUtils; - -import java.lang.ref.WeakReference; - +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.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.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; /** * 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,40 @@ 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(), parent); + 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); + holder.isInQueue.setVisibility(View.GONE); + holder.hideSeparatorIfNecessary(); } @Nullable @@ -112,211 +103,30 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter<QueueRecyclerAdap return itemAccess.getCount(); } - public class ViewHolder extends RecyclerView.ViewHolder - implements View.OnClickListener, - View.OnCreateContextMenuListener, - ItemTouchHelperViewHolder { - - 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; - }); - } - - @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, 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(); + @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 + + 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); } - - 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 +151,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; - } } diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/ItemActionButton.java b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/ItemActionButton.java index ffc73c5fb..47eab7d05 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/ItemActionButton.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/actionbutton/ItemActionButton.java @@ -2,6 +2,7 @@ package de.danoeh.antennapod.adapter.actionbutton; import android.content.Context; import android.content.res.TypedArray; +import android.widget.ImageView; import androidx.annotation.AttrRes; import androidx.annotation.NonNull; import androidx.annotation.StringRes; @@ -54,14 +55,13 @@ public abstract class ItemActionButton { } } - public void configure(@NonNull ImageButton button, Context context) { - TypedArray drawables = context.obtainStyledAttributes(new int[]{getDrawable()}); - + public void configure(@NonNull View button, @NonNull ImageView icon, Context context) { button.setVisibility(getVisibility()); button.setContentDescription(context.getString(getLabel())); - button.setImageDrawable(drawables.getDrawable(0)); button.setOnClickListener((view) -> onClick(context)); + TypedArray drawables = context.obtainStyledAttributes(new int[]{getDrawable()}); + icon.setImageDrawable(drawables.getDrawable(0)); drawables.recycle(); } } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java index e4276b3b9..edcc566f2 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java @@ -39,11 +39,6 @@ public class AllEpisodesFragment extends EpisodesListFragment { } @Override - protected boolean showOnlyNewEpisodes() { - return false; - } - - @Override protected String getPrefName() { return PREF_NAME; } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java index 7f70daaec..101c5da27 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java @@ -52,7 +52,7 @@ public class CompletedDownloadsFragment extends ListFragment { addVerticalPadding(); addEmptyView(); - listAdapter = new DownloadedEpisodesListAdapter(getActivity(), itemAccess); + listAdapter = new DownloadedEpisodesListAdapter((MainActivity) getActivity(), itemAccess); setListAdapter(listAdapter); setListShown(false); EventBus.getDefault().register(this); diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java index 89cf3b07f..9a353e05a 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java @@ -28,6 +28,7 @@ import de.danoeh.antennapod.core.event.FeedListUpdateEvent; import de.danoeh.antennapod.core.event.PlaybackPositionEvent; import de.danoeh.antennapod.core.event.PlayerStatusEvent; import de.danoeh.antennapod.core.event.UnreadItemsUpdateEvent; +import de.danoeh.antennapod.view.EpisodeItemViewHolder; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; @@ -82,8 +83,6 @@ public abstract class EpisodesListFragment extends Fragment { @NonNull List<FeedItem> episodes = new ArrayList<>(); - @NonNull - private List<Downloader> downloaderList = new ArrayList<>(); private boolean isUpdatingFeeds; boolean isMenuInvalidationAllowed = false; @@ -92,10 +91,6 @@ public abstract class EpisodesListFragment extends Fragment { private LinearLayoutManager layoutManager; protected TextView txtvInformation; - boolean showOnlyNewEpisodes() { - return false; - } - String getPrefName() { return DEFAULT_PREF_NAME; } @@ -347,10 +342,10 @@ public abstract class EpisodesListFragment extends Fragment { } protected void onFragmentLoaded(List<FeedItem> episodes) { - listAdapter.notifyDataSetChanged(); - if (episodes.size() == 0) { createRecycleAdapter(recyclerView, emptyView); + } else { + listAdapter.updateItems(episodes); } restoreScrollPosition(); @@ -363,66 +358,13 @@ public abstract class EpisodesListFragment extends Fragment { */ private void createRecycleAdapter(RecyclerView recyclerView, EmptyViewHandler emptyViewHandler) { MainActivity mainActivity = (MainActivity) getActivity(); - listAdapter = new AllEpisodesRecycleAdapter(mainActivity, itemAccess, showOnlyNewEpisodes()); + listAdapter = new AllEpisodesRecycleAdapter(mainActivity); listAdapter.setHasStableIds(true); + listAdapter.updateItems(episodes); recyclerView.setAdapter(listAdapter); emptyViewHandler.updateAdapter(listAdapter); } - private final AllEpisodesRecycleAdapter.ItemAccess itemAccess = new AllEpisodesRecycleAdapter.ItemAccess() { - - @Override - public int getCount() { - return episodes.size(); - } - - @Override - public FeedItem getItem(int position) { - if (0 <= position && position < episodes.size()) { - return episodes.get(position); - } - 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 - public LongList getQueueIds() { - LongList queueIds = new LongList(); - for (FeedItem item : episodes) { - if (item.isTagged(FeedItem.TAG_QUEUE)) { - queueIds.add(item.getId()); - } - } - return queueIds; - } - - }; - @Subscribe(threadMode = ThreadMode.MAIN) public void onEventMainThread(FeedItemEvent event) { Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]"); @@ -444,8 +386,7 @@ public abstract class EpisodesListFragment extends Fragment { public void onEventMainThread(PlaybackPositionEvent event) { if (listAdapter != null) { for (int i = 0; i < listAdapter.getItemCount(); i++) { - AllEpisodesRecycleAdapter.Holder holder = (AllEpisodesRecycleAdapter.Holder) - recyclerView.findViewHolderForAdapterPosition(i); + EpisodeItemViewHolder holder = (EpisodeItemViewHolder) recyclerView.findViewHolderForAdapterPosition(i); if (holder != null && holder.isCurrentlyPlayingItem()) { holder.notifyPlaybackPositionUpdated(event); break; @@ -462,7 +403,7 @@ public abstract class EpisodesListFragment extends Fragment { public void onEventMainThread(DownloadEvent event) { Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]"); DownloaderUpdate update = event.update; - downloaderList = update.downloaders; + List<Downloader> downloaderList = update.downloaders; if (isMenuInvalidationAllowed && event.hasChangedFeedUpdateStatus(isUpdatingFeeds)) { requireActivity().invalidateOptionsMenu(); } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java index 87a555cfd..70150a915 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java @@ -10,6 +10,7 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import de.danoeh.antennapod.view.EpisodeItemViewHolder; import org.greenrobot.eventbus.Subscribe; import java.util.List; @@ -31,11 +32,6 @@ public class FavoriteEpisodesFragment extends EpisodesListFragment { private static final String PREF_NAME = "PrefFavoriteEpisodesFragment"; @Override - protected boolean showOnlyNewEpisodes() { - return true; - } - - @Override protected String getPrefName() { return PREF_NAME; } @@ -63,8 +59,8 @@ public class FavoriteEpisodesFragment extends EpisodesListFragment { @Override public void onSwiped(RecyclerView.ViewHolder viewHolder, int swipeDir) { - AllEpisodesRecycleAdapter.Holder holder = (AllEpisodesRecycleAdapter.Holder) viewHolder; - Log.d(TAG, String.format("remove(%s)", holder.getItemId())); + EpisodeItemViewHolder holder = (EpisodeItemViewHolder) viewHolder; + Log.d(TAG, String.format("remove(%s)", holder.getFeedItem().getId())); if (disposable != null) { disposable.dispose(); diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java index 9c04886f6..16787a1c5 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java @@ -89,25 +89,18 @@ public class FeedItemlistFragment extends ListFragment { private static final String ARGUMENT_FEED_ID = "argument.de.danoeh.antennapod.feed_id"; private FeedItemlistAdapter adapter; - private ContextMenu contextMenu; private AdapterView.AdapterContextMenuInfo lastMenuInfo = null; + private MoreContentListFooterUtil listFooter; private long feedID; private Feed feed; - private boolean headerCreated = false; - - private List<Downloader> downloaderList; - - private MoreContentListFooterUtil listFooter; - private boolean isUpdatingFeed; private TextView txtvTitle; private IconTextView txtvFailure; private ImageView imgvBackground; private ImageView imgvCover; - private TextView txtvInformation; private Disposable disposable; @@ -305,7 +298,6 @@ public class FeedItemlistFragment extends ListFragment { menu.setHeaderTitle(item.getTitle()); } - contextMenu = menu; lastMenuInfo = (AdapterView.AdapterContextMenuInfo) menuInfo; FeedItemMenuHandler.onPrepareMenu(menu, item); } @@ -366,7 +358,6 @@ public class FeedItemlistFragment extends ListFragment { public void onEventMainThread(DownloadEvent event) { Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]"); DownloaderUpdate update = event.update; - downloaderList = update.downloaders; if (event.hasChangedFeedUpdateStatus(isUpdatingFeed)) { updateProgressBarVisibility(); } @@ -424,7 +415,7 @@ public class FeedItemlistFragment extends ListFragment { setListAdapter(null); setupHeaderView(); setupFooterView(); - adapter = new FeedItemlistAdapter(getActivity(), itemAccess, false, true); + adapter = new FeedItemlistAdapter((MainActivity) getActivity(), itemAccess, false, true); setListAdapter(adapter); } refreshHeaderView(); @@ -575,39 +566,12 @@ public class FeedItemlistFragment extends ListFragment { } @Override - public LongList getQueueIds() { - LongList queueIds = new LongList(); - if(feed == null) { - return queueIds; - } - for(FeedItem item : feed.getItems()) { - if(item.isTagged(FeedItem.TAG_QUEUE)) { - queueIds.add(item.getId()); - } - } - return queueIds; - } - - @Override public int getCount() { return (feed != null) ? feed.getNumOfItems() : 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; - } }; - private void loadItems() { if(disposable != null) { disposable.dispose(); diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java index bd3fd06b0..21e2800e6 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java @@ -16,6 +16,7 @@ import de.danoeh.antennapod.adapter.AllEpisodesRecycleAdapter; import de.danoeh.antennapod.core.feed.FeedItem; import de.danoeh.antennapod.core.storage.DBReader; import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler; +import de.danoeh.antennapod.view.EpisodeItemViewHolder; /** * Like 'EpisodesFragment' except that it only shows new episodes and @@ -27,11 +28,6 @@ public class NewEpisodesFragment extends EpisodesListFragment { private static final String PREF_NAME = "PrefNewEpisodesFragment"; @Override - protected boolean showOnlyNewEpisodes() { - return true; - } - - @Override protected String getPrefName() { return PREF_NAME; } @@ -63,7 +59,7 @@ public class NewEpisodesFragment extends EpisodesListFragment { @Override public void onSwiped(RecyclerView.ViewHolder viewHolder, int swipeDir) { - AllEpisodesRecycleAdapter.Holder holder = (AllEpisodesRecycleAdapter.Holder) viewHolder; + EpisodeItemViewHolder holder = (EpisodeItemViewHolder) viewHolder; FeedItemMenuHandler.removeNewFlagWithUndo(NewEpisodesFragment.this, holder.getFeedItem()); } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java index a97e3dae8..63a2fc657 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java @@ -73,7 +73,7 @@ public class PlaybackHistoryFragment extends ListFragment { // played items shoudln't be transparent for this fragment since, *all* items // in this fragment will, by definition, be played. So it serves no purpose and can make // it harder to read. - adapter = new FeedItemlistAdapter(getActivity(), itemAccess, true, false); + adapter = new FeedItemlistAdapter((MainActivity) getActivity(), itemAccess, true, false); setListAdapter(adapter); } @@ -181,19 +181,6 @@ public class PlaybackHistoryFragment extends ListFragment { private final FeedItemlistAdapter.ItemAccess itemAccess = new FeedItemlistAdapter.ItemAccess() { @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 int getCount() { return (playbackHistory != null) ? playbackHistory.size() : 0; } @@ -206,20 +193,6 @@ public class PlaybackHistoryFragment extends ListFragment { return null; } } - - @Override - public LongList getQueueIds() { - LongList queueIds = new LongList(); - if(playbackHistory == null) { - return queueIds; - } - for (FeedItem item : playbackHistory) { - if (item.isTagged(FeedItem.TAG_QUEUE)) { - queueIds.add(item.getId()); - } - } - return queueIds; - } }; private void loadItems() { diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java index c13ddc3b1..48df5ab32 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java @@ -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); @@ -693,46 +692,6 @@ public class QueueFragment extends Fragment { } @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); } diff --git a/app/src/main/java/de/danoeh/antennapod/view/CircularProgressBar.java b/app/src/main/java/de/danoeh/antennapod/view/CircularProgressBar.java new file mode 100644 index 000000000..4b3c51cfc --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/view/CircularProgressBar.java @@ -0,0 +1,87 @@ +package de.danoeh.antennapod.view; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.RectF; +import android.util.AttributeSet; +import android.view.View; +import androidx.annotation.Nullable; + +public class CircularProgressBar extends View { + private static final float EPSILON = 0.005f; + + private final Paint paintBackground = new Paint(); + private final Paint paintProgress = new Paint(); + private float percentage = 0; + private float targetPercentage = 0; + private Object tag = null; + + public CircularProgressBar(Context context) { + super(context); + setup(); + } + + public CircularProgressBar(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + setup(); + } + + public CircularProgressBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + setup(); + } + + private void setup() { + paintBackground.setAntiAlias(true); + paintBackground.setStyle(Paint.Style.STROKE); + + paintProgress.setAntiAlias(true); + paintProgress.setStyle(Paint.Style.STROKE); + paintProgress.setStrokeCap(Paint.Cap.ROUND); + + int[] colorAttrs = new int[] { android.R.attr.textColorPrimary, android.R.attr.textColorSecondary }; + TypedArray a = getContext().obtainStyledAttributes(colorAttrs); + paintProgress.setColor(a.getColor(0, 0xffffffff)); + paintBackground.setColor(a.getColor(1, 0xffffffff)); + a.recycle(); + } + + /** + * Sets the percentage to be displayed. + * @param percentage Number from 0 to 1 + * @param tag When the tag is the same as last time calling setPercentage, the update is animated + */ + public void setPercentage(float percentage, Object tag) { + targetPercentage = percentage; + + if (tag == null || !tag.equals(this.tag)) { + // Do not animate + this.percentage = percentage; + this.tag = tag; + } + invalidate(); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + float padding = getHeight() * 0.06f; + paintBackground.setStrokeWidth(getHeight() * 0.02f); + paintProgress.setStrokeWidth(padding); + RectF bounds = new RectF(padding, padding, getWidth() - padding, getHeight() - padding); + canvas.drawArc(bounds, 0, 360, false, paintBackground); + + if (percentage > EPSILON && 1 - percentage > EPSILON) { + canvas.drawArc(bounds, -90, percentage * 360, false, paintProgress); + } + + if (Math.abs(percentage - targetPercentage) > EPSILON) { + float delta = Math.min(0.02f, Math.abs(targetPercentage - percentage)); + percentage += delta * ((targetPercentage - percentage) > 0 ? 1f : -1f); + invalidate(); + } + } +} diff --git a/app/src/main/java/de/danoeh/antennapod/view/EpisodeItemViewHolder.java b/app/src/main/java/de/danoeh/antennapod/view/EpisodeItemViewHolder.java new file mode 100644 index 000000000..968bd71a9 --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/view/EpisodeItemViewHolder.java @@ -0,0 +1,212 @@ +package de.danoeh.antennapod.view; + +import android.graphics.Color; +import android.os.Build; +import android.text.Layout; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageButton; +import android.widget.ImageView; +import android.widget.ProgressBar; +import android.widget.RelativeLayout; +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.MediaType; +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 View container; + public final ImageView dragHandle; + private final TextView placeholder; + private final ImageView cover; + private final TextView title; + private final TextView pubDate; + private final TextView position; + private final TextView duration; + private final TextView size; + public final TextView isNew; + public final ImageView isInQueue; + private final ImageView isVideo; + public final ImageView isFavorite; + private final ProgressBar progressBar; + public final View secondaryActionButton; + public final ImageView secondaryActionIcon; + private final CircularProgressBar secondaryActionProgress; + private final TextView separatorIcons; + public final RelativeLayout coverHolder; + + private final MainActivity activity; + private FeedItem item; + + public EpisodeItemViewHolder(MainActivity activity, ViewGroup parent) { + super(LayoutInflater.from(activity).inflate(R.layout.feeditemlist_item, parent, false)); + 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); + position = itemView.findViewById(R.id.txtvPosition); + duration = itemView.findViewById(R.id.txtvDuration); + progressBar = itemView.findViewById(R.id.progressBar); + isInQueue = itemView.findViewById(R.id.ivInPlaylist); + isVideo = itemView.findViewById(R.id.ivIsVideo); + isNew = itemView.findViewById(R.id.statusUnread); + isFavorite = itemView.findViewById(R.id.isFavorite); + size = itemView.findViewById(R.id.size); + separatorIcons = itemView.findViewById(R.id.separatorIcons); + secondaryActionProgress = itemView.findViewById(R.id.secondaryActionProgress); + secondaryActionButton = itemView.findViewById(R.id.secondaryActionButton); + secondaryActionIcon = itemView.findViewById(R.id.secondaryActionIcon); + coverHolder = itemView.findViewById(R.id.coverHolder); + 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(DateUtils.formatAbbrev(activity, item.getPubDate())); + isNew.setVisibility(item.isNew() ? View.VISIBLE : View.GONE); + isFavorite.setVisibility(item.isTagged(FeedItem.TAG_FAVORITE) ? View.VISIBLE : View.GONE); + isInQueue.setVisibility(item.isTagged(FeedItem.TAG_QUEUE) ? View.VISIBLE : View.GONE); + itemView.setAlpha(item.isPlayed() /*&& makePlayedItemsTransparent*/ ? 0.5f : 1.0f); + + ItemActionButton actionButton = ItemActionButton.forItem(item, true); + actionButton.configure(secondaryActionButton, secondaryActionIcon, activity); + secondaryActionButton.setFocusable(false); + + if (item.getMedia() != null) { + bind(item.getMedia()); + } else { + secondaryActionProgress.setPercentage(0, item); + } + + if (coverHolder.getVisibility() == View.VISIBLE) { + new CoverLoader(activity) + .withUri(ImageResourceUtils.getImageLocation(item)) + .withFallbackUri(item.getFeed().getImageLocation()) + .withPlaceholderView(placeholder) + .withCoverView(cover) + .load(); + } + } + + private void bind(FeedMedia media) { + isVideo.setVisibility(media.getMediaType() == MediaType.VIDEO ? View.VISIBLE : View.GONE); + duration.setText(Converter.getDurationStringLong(media.getDuration())); + + if (media.isCurrentlyPlaying()) { + container.setBackgroundColor(ThemeUtils.getColorFromAttr(activity, R.attr.currently_playing_background)); + } else { + container.setBackgroundResource(ThemeUtils.getDrawableFromAttr(activity, R.attr.selectableItemBackground)); + } + + if (DownloadRequester.getInstance().isDownloadingFile(media)) { + final DownloadRequest downloadRequest = DownloadRequester.getInstance().getRequestFor(media); + float percent = 0.01f * downloadRequest.getProgressPercent(); + secondaryActionProgress.setPercentage(Math.max(percent, 0.01f), item); + } else if (media.isDownloaded()) { + secondaryActionProgress.setPercentage(1, item); // Do not animate 100% -> 0% + } else { + secondaryActionProgress.setPercentage(0, item); // Animate X% -> 0% + } + + if (media.getDuration() > 0 + && (item.getState() == FeedItem.State.PLAYING || item.getState() == FeedItem.State.IN_PROGRESS)) { + int progress = (int) (100.0 * media.getPosition() / media.getDuration()); + progressBar.setProgress(progress); + position.setText(Converter.getDurationStringLong(media.getPosition())); + duration.setText(Converter.getDurationStringLong(media.getDuration())); + progressBar.setVisibility(View.VISIBLE); + position.setVisibility(View.VISIBLE); + } else { + progressBar.setVisibility(View.GONE); + position.setVisibility(View.GONE); + } + + if (media.getSize() > 0) { + size.setText(Converter.byteToString(media.getSize())); + } else if (NetworkUtils.isEpisodeHeadDownloadAllowed() && !media.checkedOnSizeButUnknown()) { + size.setText("{fa-spinner}"); + Iconify.addIcons(size); + NetworkUtils.getFeedMediaSizeObservable(media).subscribe( + sizeValue -> { + if (sizeValue > 0) { + size.setText(Converter.byteToString(sizeValue)); + } else { + size.setText(""); + } + }, error -> { + size.setText(""); + Log.e(TAG, Log.getStackTraceString(error)); + }); + } else { + size.setText(""); + } + } + + public FeedItem getFeedItem() { + return item; + } + + public boolean isCurrentlyPlayingItem() { + return item.getMedia() != null && item.getMedia().isCurrentlyPlaying(); + } + + public void notifyPlaybackPositionUpdated(PlaybackPositionEvent event) { + progressBar.setProgress((int) (100.0 * event.getPosition() / event.getDuration())); + position.setText(Converter.getDurationStringLong(event.getPosition())); + duration.setText(Converter.getDurationStringLong(event.getDuration())); + } + + /** + * Hides the separator dot between icons and text if there are no icons. + */ + public void hideSeparatorIfNecessary() { + boolean hasIcons = isNew.getVisibility() == View.VISIBLE + || isInQueue.getVisibility() == View.VISIBLE + || isVideo.getVisibility() == View.VISIBLE + || isFavorite.getVisibility() == View.VISIBLE + || isNew.getVisibility() == View.VISIBLE; + separatorIcons.setVisibility(hasIcons ? View.VISIBLE : View.GONE); + } +} diff --git a/app/src/main/res/layout/downloaded_episodeslist_item.xml b/app/src/main/res/layout/downloaded_episodeslist_item.xml deleted file mode 100644 index 3f8065466..000000000 --- a/app/src/main/res/layout/downloaded_episodeslist_item.xml +++ /dev/null @@ -1,102 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<LinearLayout 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" - android:orientation="horizontal" - tools:background="@android:color/darker_gray"> - - <ImageView - android:id="@+id/imgvImage" - android:layout_width="@dimen/thumbnail_length_downloaded_item" - android:layout_height="@dimen/thumbnail_length_downloaded_item" - 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:contentDescription="@string/cover_label" - android:scaleType="centerCrop" - tools:src="@drawable/ic_antenna" - tools:background="@android:color/holo_green_dark"/> - - - <LinearLayout - android:layout_width="0dp" - android:layout_height="wrap_content" - 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_marginBottom="@dimen/listitem_threeline_verticalpadding" - android:layout_weight="1" - android:orientation="vertical" - tools:background="@android:color/holo_red_dark"> - - <TextView - android:id="@+id/txtvTitle" - style="@style/AntennaPod.TextView.ListItemPrimaryTitle" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginBottom="4dp" - tools:text="Downloaded episode title" - tools:background="@android:color/holo_green_dark"/> - - <LinearLayout - android:layout_width="match_parent" - android:layout_height="wrap_content" - tools:background="@android:color/holo_red_dark" > - - <TextView - android:id="@+id/txtvSize" - style="@style/AntennaPod.TextView.ListItemSecondaryTitle" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - tools:text="23 MB" - tools:background="@android:color/holo_green_dark"/> - - <View - android:layout_width="0dip" - android:layout_height="1dip" - android:layout_weight="1" /> - - <ImageView - android:id="@+id/imgvInPlaylist" - android:layout_width="@dimen/enc_icons_size" - android:layout_height="@dimen/enc_icons_size" - android:contentDescription="@string/in_queue_label" - android:src="?attr/stat_playlist" - android:visibility="visible" - tools:src="@drawable/ic_list_white_24dp" - tools:background="@android:color/holo_red_light"/> - - <TextView - android:id="@+id/txtvPublished" - style="@style/AntennaPod.TextView.ListItemSecondaryTitle" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginLeft="8dp" - android:layout_marginStart="8dp" - tools:text="Jan 23" - tools:background="@android:color/holo_green_dark"/> - - </LinearLayout> - </LinearLayout> - - <include layout="@layout/vertical_list_divider"/> - - <ImageButton - android:id="@+id/butSecondaryAction" - android:layout_width="@dimen/listview_secondary_button_width" - android:layout_height="match_parent" - android:background="?attr/selectableItemBackground" - android:clickable="false" - android:contentDescription="@string/delete_episode_label" - android:focusable="false" - android:focusableInTouchMode="false" - android:src="?attr/content_discard" - tools:src="@drawable/ic_delete_white_24dp" - tools:background="@android:color/holo_green_dark" /> - -</LinearLayout>
\ No newline at end of file diff --git a/app/src/main/res/layout/feeditemlist_item.xml b/app/src/main/res/layout/feeditemlist_item.xml index adf0748eb..c919fc4b4 100644 --- a/app/src/main/res/layout/feeditemlist_item.xml +++ b/app/src/main/res/layout/feeditemlist_item.xml @@ -1,124 +1,195 @@ <?xml version="1.0" encoding="utf-8"?> - <LinearLayout - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:tools="http://schemas.android.com/tools" - android:id="@+id/container" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="horizontal" - tools:background="@android:color/darker_gray"> + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:id="@+id/container" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:gravity="center_vertical" + android:baselineAligned="false"> + + <LinearLayout + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:minWidth="16dp"> + <ImageView + android:id="@+id/drag_handle" + android:layout_width="36dp" + android:layout_height="match_parent" + android:contentDescription="@string/drag_handle_content_description" + android:scaleType="center" + android:src="?attr/dragview_background" + tools:src="@drawable/ic_drag_vertical_grey600_48dp" + tools:background="@android:color/holo_green_dark" /> + + </LinearLayout> <RelativeLayout - android:layout_width="0dp" - android:layout_height="match_parent" - android:layout_marginLeft="@dimen/listitem_threeline_horizontalpadding" - android:layout_marginStart="@dimen/listitem_threeline_horizontalpadding" - android:layout_weight="1" - android:layout_marginTop="@dimen/listitem_threeline_verticalpadding" - android:layout_marginBottom="@dimen/listitem_threeline_verticalpadding" - tools:background="@android:color/holo_orange_dark"> + android:layout_width="@dimen/thumbnail_length_queue_item" + android:layout_height="@dimen/thumbnail_length_queue_item" + android:layout_marginBottom="@dimen/listitem_threeline_verticalpadding" + android:layout_marginTop="@dimen/listitem_threeline_verticalpadding" + android:layout_marginRight="@dimen/listitem_threeline_textleftpadding" + android:layout_marginEnd="@dimen/listitem_threeline_textleftpadding" + android:id="@+id/coverHolder"> <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_marginRight="8dp" - tools:text="NEW" - tools:background="@android:color/white" /> + android:id="@+id/txtvPlaceholder" + android:layout_width="@dimen/thumbnail_length_queue_item" + android:layout_height="@dimen/thumbnail_length_queue_item" + android:layout_centerVertical="true" + android:gravity="center" + android:background="@color/light_gray" + android:maxLines="2" + android:ellipsize="end"/> + <ImageView + android:id="@+id/imgvCover" + android:layout_width="@dimen/thumbnail_length_queue_item" + android:layout_height="@dimen/thumbnail_length_queue_item" + android:layout_centerVertical="true" + android:contentDescription="@string/cover_label" + tools:src="@tools:sample/avatars" /> - <TextView - android:id="@+id/txtvItemname" - style="@style/AntennaPod.TextView.ListItemPrimaryTitle" + </RelativeLayout> + + <LinearLayout android:layout_width="0dp" android:layout_height="wrap_content" - android:layout_alignParentLeft="true" - android:layout_alignParentStart="true" - android:layout_alignParentTop="true" - android:layout_marginBottom="4dp" - android:layout_toLeftOf="@id/statusUnread" - android:layout_toStartOf="@id/statusUnread" - tools:text="Episode title" - tools:background="@android:color/holo_green_dark" /> + android:layout_marginBottom="@dimen/listitem_threeline_verticalpadding" + 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" + tools:background="@android:color/holo_red_dark" + android:orientation="vertical"> - <TextView - android:id="@+id/txtvLenSize" - style="@style/AntennaPod.TextView.ListItemSecondaryTitle" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_alignParentLeft="true" - android:layout_alignParentStart="true" - android:layout_below="@id/txtvItemname" - tools:text="00:42:23" - tools:background="@android:color/holo_green_dark" /> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:id="@+id/status" + android:orientation="horizontal" + android:gravity="center_vertical"> - <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_below="@id/txtvItemname" - android:layout_marginRight="8dp" - android:layout_marginEnd="8dp" - android:contentDescription="@string/in_queue_label" - android:src="?attr/stat_playlist" - android:visibility="visible" - tools:src="@drawable/ic_list_white_24dp" - tools:background="@android:color/holo_red_light" /> + <TextView + android:text="@string/new_episodes_label" + style="@style/AntennaPod.TextView.UnreadIndicator" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:id="@+id/statusUnread" + android:layout_marginRight="4dp" + android:layout_marginEnd="4dp" + tools:text="@sample/episodes.json/data/status_label"/> - <ImageView - android:id="@+id/imgvType" - android:layout_width="@dimen/enc_icons_size" - android:layout_height="@dimen/enc_icons_size" - android:layout_below="@id/txtvItemname" - android:layout_marginRight="8dp" - android:layout_marginEnd="8dp" - android:layout_toLeftOf="@id/imgvInPlaylist" - android:layout_toStartOf="@id/imgvInPlaylist" - tools:ignore="ContentDescription" - tools:src="@drawable/ic_hearing_white_18dp" - tools:background="@android:color/holo_red_light" /> + <ImageView + android:layout_width="16dp" + android:layout_height="16dp" + app:srcCompat="?attr/type_video" + tools:srcCompat="@drawable/ic_videocam_grey600_24dp" + android:id="@+id/ivIsVideo"/> + <ImageView + android:layout_width="16dp" + android:layout_height="16dp" + app:srcCompat="?attr/ic_unfav" + tools:srcCompat="@drawable/ic_star_grey600_24dp" + android:id="@+id/isFavorite"/> + + <ImageView + android:layout_width="20dp" + android:layout_height="20dp" + app:srcCompat="?attr/stat_playlist" + tools:srcCompat="@drawable/ic_playlist_grey_24dp" + android:id="@+id/ivInPlaylist"/> + + <TextView + android:id="@+id/separatorIcons" + style="@style/AntennaPod.TextView.ListItemSecondaryTitle" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginLeft="4dp" + android:layout_marginStart="4dp" + android:layout_marginRight="4dp" + android:layout_marginEnd="4dp" + android:text="·" + tools:background="@android:color/holo_blue_light"/> + + <TextView + android:id="@+id/txtvPubDate" + style="@style/AntennaPod.TextView.ListItemSecondaryTitle" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginRight="4dp" + android:layout_marginEnd="4dp" + tools:text="@sample/episodes.json/data/published_at"/> + + <TextView + style="@style/AntennaPod.TextView.ListItemSecondaryTitle" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginRight="4dp" + android:layout_marginEnd="4dp" + android:text="·" + tools:background="@android:color/holo_blue_light"/> + + <TextView + android:id="@+id/size" + style="@style/AntennaPod.TextView.ListItemSecondaryTitle" + android:layout_marginRight="4dp" + android:layout_marginEnd="4dp" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + tools:text="10 MB"/> + + </LinearLayout> <TextView - android:id="@+id/txtvPublished" - style="@style/AntennaPod.TextView.ListItemSecondaryTitle" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_below="@id/txtvItemname" - android:layout_marginRight="8dp" - android:layout_marginEnd="8dp" - android:layout_toLeftOf="@id/imgvType" - android:layout_toStartOf="@id/imgvType" - tools:text="Jan 23" - tools:background="@android:color/holo_green_dark" /> - - <ProgressBar - android:id="@+id/pbar_episode_progress" - style="?android:attr/progressBarStyleHorizontal" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:layout_alignBottom="@id/txtvPublished" - android:layout_marginLeft="8dp" - android:layout_marginRight="8dp" - android:layout_toStartOf="@id/txtvPublished" - android:layout_toLeftOf="@id/txtvPublished" - android:layout_toEndOf="@id/txtvLenSize" - android:layout_toRightOf="@id/txtvLenSize" - android:layoutDirection="ltr" - android:indeterminate="false" - android:max="100" - android:progress="42" - tools:background="@android:color/holo_blue_light" /> + android:id="@+id/txtvTitle" + style="@style/AntennaPod.TextView.ListItemPrimaryTitle" + android:layout_width="match_parent" + android:layout_height="wrap_content" + tools:text="@sample/episodes.json/data/title" + android:ellipsize="end" + tools:background="@android:color/holo_blue_light"/> - </RelativeLayout> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:id="@+id/progress" + android:orientation="horizontal" + android:gravity="center_vertical"> + + <TextView + android:id="@+id/txtvPosition" + style="@style/AntennaPod.TextView.ListItemSecondaryTitle" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginBottom="0dp" + tools:text="00:42:23" + tools:background="@android:color/holo_blue_light"/> + + <ProgressBar + android:id="@+id/progressBar" + style="?attr/progressBarTheme" + android:layout_width="0dp" + android:layout_weight="1" + android:layout_height="4dp" + android:max="100" + android:layout_margin="4dp" + tools:background="@android:color/holo_blue_light"/> + + <TextView + android:id="@+id/txtvDuration" + style="@style/AntennaPod.TextView.ListItemSecondaryTitle" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginBottom="0dp" + tools:text="@sample/episodes.json/data/duration" + tools:background="@android:color/holo_blue_light"/> + + </LinearLayout> - <include layout="@layout/vertical_list_divider"/> + </LinearLayout> <include layout="@layout/secondary_action"/> diff --git a/app/src/main/res/layout/new_episodes_listitem.xml b/app/src/main/res/layout/new_episodes_listitem.xml deleted file mode 100644 index 150d692e7..000000000 --- a/app/src/main/res/layout/new_episodes_listitem.xml +++ /dev/null @@ -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> diff --git a/app/src/main/res/layout/queue_listitem.xml b/app/src/main/res/layout/queue_listitem.xml deleted file mode 100644 index 1dcc34bce..000000000 --- a/app/src/main/res/layout/queue_listitem.xml +++ /dev/null @@ -1,153 +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:layout_width="match_parent" - android:layout_height="wrap_content" - android:background="?attr/selectableItemBackground" - android:orientation="horizontal" - android:gravity="center_vertical" - android:layout_marginLeft="8dp" - android:layout_marginStart="8dp" - tools:background="@android:color/darker_gray" > - - <ImageView - android:id="@+id/drag_handle" - android:layout_width="104dp" - android:layout_height="64dp" - android:layout_marginLeft="-16dp" - android:layout_marginStart="-16dp" - android:layout_marginRight="-72dp" - android:layout_marginEnd="-72dp" - android:contentDescription="@string/drag_handle_content_description" - android:scaleType="fitXY" - android:src="?attr/dragview_background" - tools:src="@drawable/ic_drag_vertical_grey600_48dp" - tools:background="@android:color/holo_green_dark" /> - - <RelativeLayout - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginLeft="8dp" - android:layout_marginStart="8dp"> - <TextView - android:id="@+id/txtvPlaceholder" - android:layout_width="@dimen/thumbnail_length_queue_item" - android:layout_height="@dimen/thumbnail_length_queue_item" - android:layout_centerVertical="true" - android:gravity="center" - android:background="@color/light_gray" - android:maxLines="3" - android:ellipsize="end"/> - <ImageView - android:id="@+id/imgvCover" - android:layout_width="@dimen/thumbnail_length_queue_item" - android:layout_height="@dimen/thumbnail_length_queue_item" - android:layout_centerVertical="true" - android:contentDescription="@string/cover_label" - tools:src="@drawable/ic_antenna" - tools:background="@android:color/holo_green_dark"/> - </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" - tools:background="@android:color/holo_red_dark"> - - <!-- order is important, pubDate first! --> - <TextView - android:id="@+id/txtvPubDate" - style="@style/AntennaPod.TextView.ListItemSecondaryTitle" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:lines="2" - android:layout_alignParentRight="true" - android:layout_alignParentEnd="true" - android:layout_alignParentTop="true" - android:layout_marginLeft="8dp" - android:layout_marginStart="8dp" - android:gravity="end|top" - android:text="Feb\n12" - tools:background="@android:color/holo_blue_light" /> - - <TextView - android:id="@+id/txtvTitle" - style="@style/AntennaPod.TextView.ListItemPrimaryTitle" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_toLeftOf="@id/txtvPubDate" - android:layout_toStartOf="@id/txtvPubDate" - android:layout_alignParentLeft="true" - android:layout_alignParentStart="true" - android:layout_alignParentTop="true" - android:text="Queue item title" - android:ellipsize="end" - tools:background="@android:color/holo_blue_light" /> - - <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/txtvProgressLeft" - style="@style/AntennaPod.TextView.ListItemSecondaryTitle" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_alignParentLeft="true" - android:layout_alignParentStart="true" - android:layout_marginBottom="0dp" - android:text="00:42:23" - tools:background="@android:color/holo_blue_light"/> - - <TextView - android:id="@+id/txtvProgressRight" - style="@style/AntennaPod.TextView.ListItemSecondaryTitle" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_alignParentRight="true" - android:layout_alignParentEnd="true" - android:layout_marginBottom="0dp" - tools:text="Jan 23" - tools:background="@android:color/holo_green_dark" /> - - <ProgressBar - android:id="@+id/progressBar" - style="?attr/progressBarTheme" - android:layout_width="match_parent" - android:layout_height="4dp" - android:layout_below="@id/txtvProgressLeft" - android:layoutDirection="ltr" - android:max="100" - tools:background="@android:color/holo_blue_light" /> - - - </RelativeLayout> - </RelativeLayout> - - <include layout="@layout/vertical_list_divider"/> - - <include layout="@layout/secondary_action"/> - -</LinearLayout> - -</FrameLayout> diff --git a/app/src/main/res/layout/secondary_action.xml b/app/src/main/res/layout/secondary_action.xml index 1f4d9e4e6..73ca174a6 100644 --- a/app/src/main/res/layout/secondary_action.xml +++ b/app/src/main/res/layout/secondary_action.xml @@ -1,12 +1,27 @@ <?xml version="1.0" encoding="utf-8"?> -<ImageButton xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:tools="http://schemas.android.com/tools" - android:id="@+id/butSecondaryAction" - android:layout_width="@dimen/listview_secondary_button_width" - android:layout_height="match_parent" - android:background="?attr/selectableItemBackground" - android:clickable="false" - android:focusable="false" - android:focusableInTouchMode="false" - tools:ignore="ContentDescription" - tools:src="@sample/secondaryaction" /> +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="48dp" + android:layout_height="48dp" + android:layout_marginRight="12dp" + android:layout_marginEnd="12dp" + android:id="@+id/secondaryActionButton" + android:background="?selectableItemBackgroundBorderless" + android:clickable="true" + android:focusable="false" + android:focusableInTouchMode="false" > + + <ImageView + android:id="@+id/secondaryActionIcon" + android:layout_width="24dp" + android:layout_height="24dp" + android:layout_gravity="center" + tools:ignore="ContentDescription" + tools:src="@sample/secondaryaction"/> + + <de.danoeh.antennapod.view.CircularProgressBar + android:id="@+id/secondaryActionProgress" + android:layout_width="40dp" + android:layout_gravity="center" + android:layout_height="40dp"/> +</FrameLayout> |