From cae04b5b138f8dd232c19062ec115c81ed818ae2 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Tue, 4 Feb 2020 14:53:49 +0100 Subject: [PATCH 01/24] Extract queue item holder to new class First step to use a single item holder in the future --- .../adapter/QueueRecyclerAdapter.java | 310 +++--------------- .../antennapod/fragment/QueueFragment.java | 45 +-- .../view/EpisodeItemViewHolder.java | 196 +++++++++++ .../download/handler/PostDownloaderTask.java | 2 + .../core/storage/DownloadRequester.java | 20 ++ 5 files changed, 272 insertions(+), 301 deletions(-) create mode 100644 app/src/main/java/de/danoeh/antennapod/view/EpisodeItemViewHolder.java 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 2a39321ef..3aeee1c9f 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 androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.core.view.MotionEventCompat; +import androidx.recyclerview.widget.ItemTouchHelper; +import androidx.recyclerview.widget.RecyclerView; +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.activity.MainActivity; +import de.danoeh.antennapod.core.feed.FeedItem; +import de.danoeh.antennapod.core.preferences.UserPreferences; +import de.danoeh.antennapod.core.util.LongList; import de.danoeh.antennapod.fragment.ItemPagerFragment; +import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler; +import de.danoeh.antennapod.view.EpisodeItemViewHolder; import org.apache.commons.lang3.ArrayUtils; import java.lang.ref.WeakReference; -import de.danoeh.antennapod.R; -import de.danoeh.antennapod.activity.MainActivity; -import de.danoeh.antennapod.adapter.actionbutton.ItemActionButton; -import de.danoeh.antennapod.core.feed.FeedItem; -import de.danoeh.antennapod.core.feed.FeedMedia; -import de.danoeh.antennapod.core.preferences.UserPreferences; -import de.danoeh.antennapod.core.storage.DownloadRequester; -import de.danoeh.antennapod.core.util.Converter; -import de.danoeh.antennapod.core.util.DateUtils; -import de.danoeh.antennapod.core.feed.util.ImageResourceUtils; -import de.danoeh.antennapod.core.util.LongList; -import de.danoeh.antennapod.core.util.NetworkUtils; -import de.danoeh.antennapod.core.util.ThemeUtils; -import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler; - /** * List adapter for the queue. */ -public class QueueRecyclerAdapter extends RecyclerView.Adapter { - - private static final String TAG = QueueRecyclerAdapter.class.getSimpleName(); +public class QueueRecyclerAdapter extends RecyclerView.Adapter implements View.OnCreateContextMenuListener { + private static final String TAG = "QueueRecyclerAdapter"; private final WeakReference mainActivity; private final ItemAccess itemAccess; @@ -60,9 +37,6 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter { + if (MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN) { + Log.d(TAG, "startDrag()"); + itemTouchHelper.startDrag(viewHolder); + } + return false; + }); + return viewHolder; } @Override - public void onBindViewHolder(ViewHolder holder, int pos) { + public void onBindViewHolder(EpisodeItemViewHolder holder, int pos) { FeedItem item = itemAccess.getItem(pos); holder.bind(item); + holder.dragHandle.setVisibility(locked ? View.GONE : View.VISIBLE); holder.itemView.setOnLongClickListener(v -> { selectedItem = item; return false; }); + holder.itemView.setOnClickListener(v -> { + MainActivity activity = mainActivity.get(); + if (activity != null) { + long[] ids = itemAccess.getQueueIds().toArray(); + int position = ArrayUtils.indexOf(ids, item.getId()); + activity.loadChildFragment(ItemPagerFragment.newInstance(ids, position)); + } + }); + holder.itemView.setOnCreateContextMenuListener(this); } @Nullable @@ -112,211 +101,30 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter= 23) { - title.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_FULL); - } - pubDate = v.findViewById(R.id.txtvPubDate); - progressLeft = v.findViewById(R.id.txtvProgressLeft); - progressRight = v.findViewById(R.id.txtvProgressRight); - butSecondary = v.findViewById(R.id.butSecondaryAction); - progressBar = v.findViewById(R.id.progressBar); - v.setTag(this); - v.setOnClickListener(this); - v.setOnCreateContextMenuListener(this); - dragHandle.setOnTouchListener((v1, event) -> { - if (MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN) { - Log.d(TAG, "startDrag()"); - itemTouchHelper.startDrag(ViewHolder.this); - } - return false; - }); + menu.setHeaderTitle(selectedItem.getTitle()); + FeedItemMenuHandler.onPrepareMenu(menu, selectedItem, R.id.skip_episode_item); + // Queue-specific menu preparation + final boolean keepSorted = UserPreferences.isQueueKeepSorted(); + final LongList queueAccess = itemAccess.getQueueIds(); + if (queueAccess.size() == 0 || queueAccess.get(0) == selectedItem.getId() || keepSorted) { + menu.findItem(R.id.move_to_top_item).setVisible(false); } - - @Override - public void onClick(View v) { - MainActivity activity = mainActivity.get(); - if (activity != null) { - long[] ids = itemAccess.getQueueIds().toArray(); - int position = ArrayUtils.indexOf(ids, item.getId()); - activity.loadChildFragment(ItemPagerFragment.newInstance(ids, position)); - } - } - - @Override - public void onCreateContextMenu(final ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { - FeedItem item = itemAccess.getItem(getAdapterPosition()); - - MenuInflater inflater = mainActivity.get().getMenuInflater(); - inflater.inflate(R.menu.queue_context, menu); // queue-specific menu items - inflater.inflate(R.menu.feeditemlist_context, menu); // generic menu items for item feeds - - if (item != null) { - menu.setHeaderTitle(item.getTitle()); - } - - FeedItemMenuHandler.onPrepareMenu(menu, item, - R.id.skip_episode_item); // Skip Episode is not useful in Queue, so hide it. - // Queue-specific menu preparation - final boolean keepSorted = UserPreferences.isQueueKeepSorted(); - final LongList queueAccess = itemAccess.getQueueIds(); - if (queueAccess.size() == 0 || queueAccess.get(0) == item.getId() || keepSorted) { - menu.findItem(R.id.move_to_top_item).setVisible(false); - } - if (queueAccess.size() == 0 || queueAccess.get(queueAccess.size()-1) == item.getId() || keepSorted) { - menu.findItem(R.id.move_to_bottom_item).setVisible(false); - } - } - - @Override - public void onItemSelected() { - itemView.setAlpha(0.5f); - } - - @Override - public void onItemClear() { - itemView.setAlpha(1.0f); - } - - public void bind(FeedItem item) { - this.item = item; - if(locked) { - dragHandle.setVisibility(View.GONE); - } else { - dragHandle.setVisibility(View.VISIBLE); - } - - placeholder.setText(item.getFeed().getTitle()); - - title.setText(item.getTitle()); - FeedMedia media = item.getMedia(); - - title.setText(item.getTitle()); - String pubDateStr = DateUtils.formatAbbrev(mainActivity.get(), item.getPubDate()); - int index = 0; - if(countMatches(pubDateStr, ' ') == 1 || countMatches(pubDateStr, ' ') == 2) { - index = pubDateStr.lastIndexOf(' '); - } else if(countMatches(pubDateStr, '.') == 2) { - index = pubDateStr.lastIndexOf('.'); - } else if(countMatches(pubDateStr, '-') == 2) { - index = pubDateStr.lastIndexOf('-'); - } else if(countMatches(pubDateStr, '/') == 2) { - index = pubDateStr.lastIndexOf('/'); - } - if(index > 0) { - pubDateStr = pubDateStr.substring(0, index+1).trim() + "\n" + pubDateStr.substring(index+1); - } - pubDate.setText(pubDateStr); - - if (media != null) { - final boolean isDownloadingMedia = DownloadRequester.getInstance().isDownloadingFile(media); - FeedItem.State state = item.getState(); - if (isDownloadingMedia) { - progressLeft.setText(Converter.byteToString(itemAccess.getItemDownloadedBytes(item))); - if(itemAccess.getItemDownloadSize(item) > 0) { - progressRight.setText(Converter.byteToString(itemAccess.getItemDownloadSize(item))); - } else { - progressRight.setText(Converter.byteToString(media.getSize())); - } - progressBar.setProgress(itemAccess.getItemDownloadProgressPercent(item)); - progressBar.setVisibility(View.VISIBLE); - } else if (state == FeedItem.State.PLAYING - || state == FeedItem.State.IN_PROGRESS) { - if (media.getDuration() > 0) { - int progress = (int) (100.0 * media.getPosition() / media.getDuration()); - progressBar.setProgress(progress); - progressBar.setVisibility(View.VISIBLE); - progressLeft.setText(Converter - .getDurationStringLong(media.getPosition())); - progressRight.setText(Converter.getDurationStringLong(media.getDuration())); - } - } else { - if(media.getSize() > 0) { - progressLeft.setText(Converter.byteToString(media.getSize())); - } else if(NetworkUtils.isEpisodeHeadDownloadAllowed() && !media.checkedOnSizeButUnknown()) { - progressLeft.setText("{fa-spinner}"); - Iconify.addIcons(progressLeft); - NetworkUtils.getFeedMediaSizeObservable(media) - .subscribe( - size -> { - if (size > 0) { - progressLeft.setText(Converter.byteToString(size)); - } else { - progressLeft.setText(""); - } - }, error -> { - progressLeft.setText(""); - Log.e(TAG, Log.getStackTraceString(error)); - }); - } else { - progressLeft.setText(""); - } - progressRight.setText(Converter.getDurationStringLong(media.getDuration())); - progressBar.setVisibility(View.INVISIBLE); - } - - if(media.isCurrentlyPlaying()) { - container.setBackgroundColor(playingBackGroundColor); - } else { - container.setBackgroundColor(normalBackGroundColor); - } - } - - ItemActionButton actionButton = ItemActionButton.forItem(item, true); - actionButton.configure(butSecondary, mainActivity.get()); - - butSecondary.setFocusable(false); - butSecondary.setTag(item); - - new CoverLoader(mainActivity.get()) - .withUri(ImageResourceUtils.getImageLocation(item)) - .withFallbackUri(item.getFeed().getImageLocation()) - .withPlaceholderView(placeholder) - .withCoverView(cover) - .load(); - } - - public boolean isCurrentlyPlayingItem() { - return item.getMedia() != null && item.getMedia().isCurrentlyPlaying(); - } - - public void notifyPlaybackPositionUpdated(PlaybackPositionEvent event) { - progressBar.setProgress((int) (100.0 * event.getPosition() / event.getDuration())); - progressLeft.setText(Converter.getDurationStringLong(event.getPosition())); - progressRight.setText(Converter.getDurationStringLong(event.getDuration())); + if (queueAccess.size() == 0 || queueAccess.get(queueAccess.size() - 1) == selectedItem.getId() || keepSorted) { + menu.findItem(R.id.move_to_bottom_item).setVisible(false); } } public interface ItemAccess { FeedItem getItem(int position); + int getCount(); - long getItemDownloadedBytes(FeedItem item); - long getItemDownloadSize(FeedItem item); - int getItemDownloadProgressPercent(FeedItem item); + LongList getQueueIds(); } @@ -341,18 +149,4 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter queue; - private List downloaderList; private boolean isUpdatingFeeds = false; @@ -196,7 +196,6 @@ public class QueueFragment extends Fragment { public void onEventMainThread(DownloadEvent event) { Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]"); DownloaderUpdate update = event.update; - downloaderList = update.downloaders; if (event.hasChangedFeedUpdateStatus(isUpdatingFeeds)) { getActivity().invalidateOptionsMenu(); } @@ -214,7 +213,7 @@ public class QueueFragment extends Fragment { public void onEventMainThread(PlaybackPositionEvent event) { if (recyclerAdapter != null) { for (int i = 0; i < recyclerAdapter.getItemCount(); i++) { - QueueRecyclerAdapter.ViewHolder holder = (QueueRecyclerAdapter.ViewHolder) + EpisodeItemViewHolder holder = (EpisodeItemViewHolder) recyclerView.findViewHolderForAdapterPosition(i); if (holder != null && holder.isCurrentlyPlayingItem()) { holder.notifyPlaybackPositionUpdated(event); @@ -688,46 +687,6 @@ public class QueueFragment extends Fragment { return null; } - @Override - public long getItemDownloadedBytes(FeedItem item) { - if (downloaderList != null) { - for (Downloader downloader : downloaderList) { - if (downloader.getDownloadRequest().getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA - && downloader.getDownloadRequest().getFeedfileId() == item.getMedia().getId()) { - Log.d(TAG, "downloaded bytes: " + downloader.getDownloadRequest().getSoFar()); - return downloader.getDownloadRequest().getSoFar(); - } - } - } - return 0; - } - - @Override - public long getItemDownloadSize(FeedItem item) { - if (downloaderList != null) { - for (Downloader downloader : downloaderList) { - if (downloader.getDownloadRequest().getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA - && downloader.getDownloadRequest().getFeedfileId() == item.getMedia().getId()) { - Log.d(TAG, "downloaded size: " + downloader.getDownloadRequest().getSize()); - return downloader.getDownloadRequest().getSize(); - } - } - } - return 0; - } - @Override - public int getItemDownloadProgressPercent(FeedItem item) { - if (downloaderList != null) { - for (Downloader downloader : downloaderList) { - if (downloader.getDownloadRequest().getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA - && downloader.getDownloadRequest().getFeedfileId() == item.getMedia().getId()) { - return downloader.getDownloadRequest().getProgressPercent(); - } - } - } - return 0; - } - @Override public LongList getQueueIds() { return queue != null ? LongList.of(FeedItemUtil.getIds(queue)) : new LongList(0); 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..e605ddd06 --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/view/EpisodeItemViewHolder.java @@ -0,0 +1,196 @@ +package de.danoeh.antennapod.view; + +import android.graphics.Color; +import android.os.Build; +import android.text.Layout; +import android.text.TextUtils; +import android.util.Log; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.ImageButton; +import android.widget.ImageView; +import android.widget.ProgressBar; +import android.widget.TextView; +import androidx.recyclerview.widget.RecyclerView; +import com.joanzapata.iconify.Iconify; +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.activity.MainActivity; +import de.danoeh.antennapod.adapter.CoverLoader; +import de.danoeh.antennapod.adapter.QueueRecyclerAdapter; +import de.danoeh.antennapod.adapter.actionbutton.ItemActionButton; +import de.danoeh.antennapod.core.event.PlaybackPositionEvent; +import de.danoeh.antennapod.core.feed.FeedItem; +import de.danoeh.antennapod.core.feed.FeedMedia; +import de.danoeh.antennapod.core.feed.util.ImageResourceUtils; +import de.danoeh.antennapod.core.service.download.DownloadRequest; +import de.danoeh.antennapod.core.storage.DownloadRequester; +import de.danoeh.antennapod.core.util.Converter; +import de.danoeh.antennapod.core.util.DateUtils; +import de.danoeh.antennapod.core.util.NetworkUtils; +import de.danoeh.antennapod.core.util.ThemeUtils; + +/** + * Holds the view which shows FeedItems. + */ +public class EpisodeItemViewHolder extends RecyclerView.ViewHolder + implements QueueRecyclerAdapter.ItemTouchHelperViewHolder { + private static final String TAG = "EpisodeItemViewHolder"; + + private final FrameLayout container; + public final ImageView dragHandle; + private final TextView placeholder; + private final ImageView cover; + private final TextView title; + private final TextView pubDate; + private final TextView progressLeft; + private final TextView progressRight; + private final ProgressBar progressBar; + private final ImageButton butSecondary; + private final MainActivity activity; + + private FeedItem item; + + public EpisodeItemViewHolder(MainActivity activity) { + super(View.inflate(activity, R.layout.queue_listitem, null)); + this.activity = activity; + container = itemView.findViewById(R.id.container); + dragHandle = itemView.findViewById(R.id.drag_handle); + placeholder = itemView.findViewById(R.id.txtvPlaceholder); + cover = itemView.findViewById(R.id.imgvCover); + title = itemView.findViewById(R.id.txtvTitle); + if (Build.VERSION.SDK_INT >= 23) { + title.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_FULL); + } + pubDate = itemView.findViewById(R.id.txtvPubDate); + progressLeft = itemView.findViewById(R.id.txtvProgressLeft); + progressRight = itemView.findViewById(R.id.txtvProgressRight); + butSecondary = itemView.findViewById(R.id.butSecondaryAction); + progressBar = itemView.findViewById(R.id.progressBar); + itemView.setTag(this); + } + + @Override + public void onItemSelected() { + itemView.setAlpha(0.5f); + } + + @Override + public void onItemClear() { + itemView.setAlpha(1.0f); + } + + public void bind(FeedItem item) { + this.item = item; + placeholder.setText(item.getFeed().getTitle()); + title.setText(item.getTitle()); + title.setText(item.getTitle()); + pubDate.setText(formatPubDate()); + + FeedMedia media = item.getMedia(); + if (media != null) { + final DownloadRequest downloadRequest = DownloadRequester.getInstance().getRequestFor(media); + FeedItem.State state = item.getState(); + if (downloadRequest != null) { + progressLeft.setText(Converter.byteToString(downloadRequest.getSoFar())); + if (downloadRequest.getSize() > 0) { + progressRight.setText(Converter.byteToString(downloadRequest.getSize())); + } else { + progressRight.setText(Converter.byteToString(media.getSize())); + } + progressBar.setProgress(downloadRequest.getProgressPercent()); + progressBar.setVisibility(View.VISIBLE); + } else if (state == FeedItem.State.PLAYING || state == FeedItem.State.IN_PROGRESS) { + if (media.getDuration() > 0) { + int progress = (int) (100.0 * media.getPosition() / media.getDuration()); + progressBar.setProgress(progress); + progressBar.setVisibility(View.VISIBLE); + progressLeft.setText(Converter.getDurationStringLong(media.getPosition())); + progressRight.setText(Converter.getDurationStringLong(media.getDuration())); + } + } else { + if (media.getSize() > 0) { + progressLeft.setText(Converter.byteToString(media.getSize())); + } else if (NetworkUtils.isEpisodeHeadDownloadAllowed() && !media.checkedOnSizeButUnknown()) { + progressLeft.setText("{fa-spinner}"); + Iconify.addIcons(progressLeft); + NetworkUtils.getFeedMediaSizeObservable(media).subscribe( + size -> { + if (size > 0) { + progressLeft.setText(Converter.byteToString(size)); + } else { + progressLeft.setText(""); + } + }, error -> { + progressLeft.setText(""); + Log.e(TAG, Log.getStackTraceString(error)); + }); + } else { + progressLeft.setText(""); + } + progressRight.setText(Converter.getDurationStringLong(media.getDuration())); + progressBar.setVisibility(View.INVISIBLE); + } + + if (media.isCurrentlyPlaying()) { + container.setBackgroundColor(ThemeUtils.getColorFromAttr(activity, + R.attr.currently_playing_background)); + } else { + container.setBackgroundColor(Color.TRANSPARENT); + } + } + + ItemActionButton actionButton = ItemActionButton.forItem(item, true); + actionButton.configure(butSecondary, activity); + butSecondary.setFocusable(false); + butSecondary.setTag(item); + + new CoverLoader(activity) + .withUri(ImageResourceUtils.getImageLocation(item)) + .withFallbackUri(item.getFeed().getImageLocation()) + .withPlaceholderView(placeholder) + .withCoverView(cover) + .load(); + } + + private String formatPubDate() { + String pubDateStr = DateUtils.formatAbbrev(activity, item.getPubDate()); + int index = 0; + if (countMatches(pubDateStr, ' ') == 1 || countMatches(pubDateStr, ' ') == 2) { + index = pubDateStr.lastIndexOf(' '); + } else if (countMatches(pubDateStr, '.') == 2) { + index = pubDateStr.lastIndexOf('.'); + } else if (countMatches(pubDateStr, '-') == 2) { + index = pubDateStr.lastIndexOf('-'); + } else if (countMatches(pubDateStr, '/') == 2) { + index = pubDateStr.lastIndexOf('/'); + } + if (index > 0) { + pubDateStr = pubDateStr.substring(0, index+1).trim() + "\n" + pubDateStr.substring(index+1); + } + return pubDateStr; + } + + public boolean isCurrentlyPlayingItem() { + return item.getMedia() != null && item.getMedia().isCurrentlyPlaying(); + } + + public void notifyPlaybackPositionUpdated(PlaybackPositionEvent event) { + progressBar.setProgress((int) (100.0 * event.getPosition() / event.getDuration())); + progressLeft.setText(Converter.getDurationStringLong(event.getPosition())); + progressRight.setText(Converter.getDurationStringLong(event.getDuration())); + } + + // Oh Xiaomi, I hate you so much. How did you manage to fuck this up? + private static int countMatches(final CharSequence str, final char ch) { + if (TextUtils.isEmpty(str)) { + return 0; + } + int count = 0; + for (int i = 0; i < str.length(); i++) { + if (ch == str.charAt(i)) { + count++; + } + } + return count; + } +} diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/handler/PostDownloaderTask.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/handler/PostDownloaderTask.java index 5d2c48679..7c998146d 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/download/handler/PostDownloaderTask.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/handler/PostDownloaderTask.java @@ -2,6 +2,7 @@ package de.danoeh.antennapod.core.service.download.handler; import de.danoeh.antennapod.core.event.DownloadEvent; import de.danoeh.antennapod.core.service.download.Downloader; +import de.danoeh.antennapod.core.storage.DownloadRequester; import org.greenrobot.eventbus.EventBus; import java.util.ArrayList; @@ -23,6 +24,7 @@ public class PostDownloaderTask implements Runnable { runningDownloads.add(downloader); } } + DownloadRequester.getInstance().updateProgress(downloads); List list = Collections.unmodifiableList(runningDownloads); EventBus.getDefault().postSticky(DownloadEvent.refresh(list)); } diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DownloadRequester.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DownloadRequester.java index 3d4ee443b..8bd9afe38 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/DownloadRequester.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DownloadRequester.java @@ -12,6 +12,7 @@ import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import androidx.core.content.ContextCompat; +import de.danoeh.antennapod.core.service.download.Downloader; import org.apache.commons.io.FilenameUtils; import java.io.File; @@ -343,6 +344,16 @@ public class DownloadRequester implements DownloadStateProvider { return item.getDownload_url() != null && downloads.containsKey(item.getDownload_url()); } + /** + * Get the downloader for this item. + */ + public synchronized DownloadRequest getRequestFor(FeedFile item) { + if (isDownloadingFile(item)) { + return downloads.get(item.getDownload_url()); + } + return null; + } + /** * Checks if feedfile with the given download url is in the downloads list */ @@ -428,4 +439,13 @@ public class DownloadRequester implements DownloadStateProvider { } return filename; } + + public void updateProgress(List newDownloads) { + for (Downloader downloader : newDownloads) { + DownloadRequest request = downloader.getDownloadRequest(); + if (downloads.containsKey(request.getSource())) { + downloads.put(request.getSource(), request); + } + } + } } From 1313cde4812fa8daf26b7cb0fabd1349a2f39838 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Tue, 4 Feb 2020 16:38:53 +0100 Subject: [PATCH 02/24] Converted FeedItemlistAdapter to use new EpisodeItemViewHolder --- .../antennapod/adapter/AdapterUtils.java | 74 ----- .../adapter/FeedItemlistAdapter.java | 187 +----------- .../fragment/FeedItemlistFragment.java | 29 +- .../fragment/PlaybackHistoryFragment.java | 29 +- .../view/EpisodeItemViewHolder.java | 157 +++++----- app/src/main/res/layout/feeditemlist_item.xml | 283 +++++++++++------- app/src/main/res/layout/queue_listitem.xml | 153 ---------- 7 files changed, 259 insertions(+), 653 deletions(-) delete mode 100644 app/src/main/java/de/danoeh/antennapod/adapter/AdapterUtils.java delete mode 100644 app/src/main/res/layout/queue_listitem.xml 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/FeedItemlistAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java index aec0f0c91..322b5a489 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,20 @@ import de.danoeh.antennapod.core.util.ThemeUtils; public class FeedItemlistAdapter extends BaseAdapter { private final ItemAccess itemAccess; - private final Context context; - private final boolean showFeedtitle; + private final MainActivity activity; /** true if played items should be made partially transparent */ private final boolean makePlayedItemsTransparent; - private final int playingBackGroundColor; - private final int normalBackGroundColor; private int currentlyPlayingItem = -1; - public FeedItemlistAdapter(Context context, + public FeedItemlistAdapter(MainActivity activity, ItemAccess itemAccess, boolean showFeedtitle, boolean makePlayedItemsTransparent) { super(); - this.context = context; + this.activity = activity; this.itemAccess = itemAccess; - this.showFeedtitle = showFeedtitle; this.makePlayedItemsTransparent = makePlayedItemsTransparent; - - playingBackGroundColor = ThemeUtils.getColorFromAttr(context, R.attr.currently_playing_background); - normalBackGroundColor = ContextCompat.getColor(context, android.R.color.transparent); } @Override @@ -75,130 +48,22 @@ 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); } else { - holder = (Holder) convertView.getTag(); + holder = (EpisodeItemViewHolder) convertView.getTag(); } - if (!(getItemViewType(position) == Adapter.IGNORE_ITEM_VIEW_TYPE)) { - convertView.setVisibility(View.VISIBLE); + final FeedItem item = getItem(position); + holder.bind(item); + holder.dragHandle.setVisibility(View.GONE); - 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); - actionButton.configure(holder.butAction, context); - - holder.butAction.setFocusable(false); - holder.butAction.setTag(item); - - } else { - convertView.setVisibility(View.GONE); + if (item.getMedia() != null && item.getMedia().isCurrentlyPlaying()) { + currentlyPlayingItem = position; } - return convertView; + return holder.itemView; } public void notifyCurrentlyPlayingItemChanged(PlaybackPositionEvent event, ListView listView) { @@ -208,35 +73,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/fragment/FeedItemlistFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java index 081f4d604..123b0d1a2 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java @@ -424,7 +424,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(); @@ -574,40 +574,13 @@ 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/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); } @@ -180,19 +180,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/view/EpisodeItemViewHolder.java b/app/src/main/java/de/danoeh/antennapod/view/EpisodeItemViewHolder.java index e605ddd06..1281a53b7 100644 --- a/app/src/main/java/de/danoeh/antennapod/view/EpisodeItemViewHolder.java +++ b/app/src/main/java/de/danoeh/antennapod/view/EpisodeItemViewHolder.java @@ -21,6 +21,7 @@ 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; @@ -42,8 +43,12 @@ public class EpisodeItemViewHolder extends RecyclerView.ViewHolder private final ImageView cover; private final TextView title; private final TextView pubDate; - private final TextView progressLeft; - private final TextView progressRight; + private final TextView position; + private final TextView duration; + private final TextView size; + private final TextView isNew; + private final ImageView isInQueue; + private final ImageView isVideo; private final ProgressBar progressBar; private final ImageButton butSecondary; private final MainActivity activity; @@ -51,7 +56,7 @@ public class EpisodeItemViewHolder extends RecyclerView.ViewHolder private FeedItem item; public EpisodeItemViewHolder(MainActivity activity) { - super(View.inflate(activity, R.layout.queue_listitem, null)); + super(View.inflate(activity, R.layout.feeditemlist_item, null)); this.activity = activity; container = itemView.findViewById(R.id.container); dragHandle = itemView.findViewById(R.id.drag_handle); @@ -62,10 +67,14 @@ public class EpisodeItemViewHolder extends RecyclerView.ViewHolder title.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_FULL); } pubDate = itemView.findViewById(R.id.txtvPubDate); - progressLeft = itemView.findViewById(R.id.txtvProgressLeft); - progressRight = itemView.findViewById(R.id.txtvProgressRight); + position = itemView.findViewById(R.id.txtvProgressLeft); + duration = itemView.findViewById(R.id.txtvProgressRight); butSecondary = itemView.findViewById(R.id.butSecondaryAction); progressBar = itemView.findViewById(R.id.progressBar); + isInQueue = itemView.findViewById(R.id.ivInPlaylist); + isVideo = itemView.findViewById(R.id.ivIsVideo); + isNew = itemView.findViewById(R.id.statusUnread); + size = itemView.findViewById(R.id.size); itemView.setTag(this); } @@ -84,59 +93,13 @@ public class EpisodeItemViewHolder extends RecyclerView.ViewHolder placeholder.setText(item.getFeed().getTitle()); title.setText(item.getTitle()); title.setText(item.getTitle()); - pubDate.setText(formatPubDate()); + pubDate.setText(DateUtils.formatAbbrev(activity, item.getPubDate())); + isNew.setVisibility(item.isNew() ? View.VISIBLE : View.INVISIBLE); + isInQueue.setVisibility(item.isTagged(FeedItem.TAG_QUEUE) ? View.VISIBLE : View.INVISIBLE); + itemView.setAlpha(item.isPlayed() /*&& makePlayedItemsTransparent*/ ? 0.5f : 1.0f); - FeedMedia media = item.getMedia(); - if (media != null) { - final DownloadRequest downloadRequest = DownloadRequester.getInstance().getRequestFor(media); - FeedItem.State state = item.getState(); - if (downloadRequest != null) { - progressLeft.setText(Converter.byteToString(downloadRequest.getSoFar())); - if (downloadRequest.getSize() > 0) { - progressRight.setText(Converter.byteToString(downloadRequest.getSize())); - } else { - progressRight.setText(Converter.byteToString(media.getSize())); - } - progressBar.setProgress(downloadRequest.getProgressPercent()); - progressBar.setVisibility(View.VISIBLE); - } else if (state == FeedItem.State.PLAYING || state == FeedItem.State.IN_PROGRESS) { - if (media.getDuration() > 0) { - int progress = (int) (100.0 * media.getPosition() / media.getDuration()); - progressBar.setProgress(progress); - progressBar.setVisibility(View.VISIBLE); - progressLeft.setText(Converter.getDurationStringLong(media.getPosition())); - progressRight.setText(Converter.getDurationStringLong(media.getDuration())); - } - } else { - if (media.getSize() > 0) { - progressLeft.setText(Converter.byteToString(media.getSize())); - } else if (NetworkUtils.isEpisodeHeadDownloadAllowed() && !media.checkedOnSizeButUnknown()) { - progressLeft.setText("{fa-spinner}"); - Iconify.addIcons(progressLeft); - NetworkUtils.getFeedMediaSizeObservable(media).subscribe( - size -> { - if (size > 0) { - progressLeft.setText(Converter.byteToString(size)); - } else { - progressLeft.setText(""); - } - }, error -> { - progressLeft.setText(""); - Log.e(TAG, Log.getStackTraceString(error)); - }); - } else { - progressLeft.setText(""); - } - progressRight.setText(Converter.getDurationStringLong(media.getDuration())); - progressBar.setVisibility(View.INVISIBLE); - } - - if (media.isCurrentlyPlaying()) { - container.setBackgroundColor(ThemeUtils.getColorFromAttr(activity, - R.attr.currently_playing_background)); - } else { - container.setBackgroundColor(Color.TRANSPARENT); - } + if (item.getMedia() != null) { + bind(item.getMedia()); } ItemActionButton actionButton = ItemActionButton.forItem(item, true); @@ -152,22 +115,56 @@ public class EpisodeItemViewHolder extends RecyclerView.ViewHolder .load(); } - private String formatPubDate() { - String pubDateStr = DateUtils.formatAbbrev(activity, item.getPubDate()); - int index = 0; - if (countMatches(pubDateStr, ' ') == 1 || countMatches(pubDateStr, ' ') == 2) { - index = pubDateStr.lastIndexOf(' '); - } else if (countMatches(pubDateStr, '.') == 2) { - index = pubDateStr.lastIndexOf('.'); - } else if (countMatches(pubDateStr, '-') == 2) { - index = pubDateStr.lastIndexOf('-'); - } else if (countMatches(pubDateStr, '/') == 2) { - index = pubDateStr.lastIndexOf('/'); + private void bind(FeedMedia media) { + isVideo.setVisibility(media.getMediaType() == MediaType.VIDEO ? View.VISIBLE : View.INVISIBLE); + duration.setText(Converter.getDurationStringLong(media.getDuration())); + + if (media.isCurrentlyPlaying()) { + container.setBackgroundColor(ThemeUtils.getColorFromAttr(activity, R.attr.currently_playing_background)); + } else { + container.setBackgroundColor(Color.TRANSPARENT); } - if (index > 0) { - pubDateStr = pubDateStr.substring(0, index+1).trim() + "\n" + pubDateStr.substring(index+1); + + final DownloadRequest downloadRequest = DownloadRequester.getInstance().getRequestFor(media); + progressBar.setVisibility(View.INVISIBLE); + if (downloadRequest != null) { + position.setText(Converter.byteToString(downloadRequest.getSoFar())); + if (downloadRequest.getSize() > 0) { + duration.setText(Converter.byteToString(downloadRequest.getSize())); + } else { + duration.setText(Converter.byteToString(media.getSize())); + } + progressBar.setProgress(downloadRequest.getProgressPercent()); + progressBar.setVisibility(View.VISIBLE); + } else if (item.getState() == FeedItem.State.PLAYING || item.getState() == FeedItem.State.IN_PROGRESS) { + if (media.getDuration() > 0) { + int progress = (int) (100.0 * media.getPosition() / media.getDuration()); + progressBar.setProgress(progress); + progressBar.setVisibility(View.VISIBLE); + position.setText(Converter.getDurationStringLong(media.getPosition())); + duration.setText(Converter.getDurationStringLong(media.getDuration())); + } + } + + 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(""); } - return pubDateStr; } public boolean isCurrentlyPlayingItem() { @@ -176,21 +173,7 @@ public class EpisodeItemViewHolder extends RecyclerView.ViewHolder public void notifyPlaybackPositionUpdated(PlaybackPositionEvent event) { progressBar.setProgress((int) (100.0 * event.getPosition() / event.getDuration())); - progressLeft.setText(Converter.getDurationStringLong(event.getPosition())); - progressRight.setText(Converter.getDurationStringLong(event.getDuration())); - } - - // Oh Xiaomi, I hate you so much. How did you manage to fuck this up? - private static int countMatches(final CharSequence str, final char ch) { - if (TextUtils.isEmpty(str)) { - return 0; - } - int count = 0; - for (int i = 0; i < str.length(); i++) { - if (ch == str.charAt(i)) { - count++; - } - } - return count; + position.setText(Converter.getDurationStringLong(event.getPosition())); + duration.setText(Converter.getDurationStringLong(event.getDuration())); } } diff --git a/app/src/main/res/layout/feeditemlist_item.xml b/app/src/main/res/layout/feeditemlist_item.xml index adf0748eb..5a369c7a6 100644 --- a/app/src/main/res/layout/feeditemlist_item.xml +++ b/app/src/main/res/layout/feeditemlist_item.xml @@ -1,125 +1,184 @@ + - - - - - - - - - + android:layout_marginStart="8dp" > + 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" /> - + + + + - + - + + - + - + - + - + + + + + + + + + + + + + + + + + + + + + + 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 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From cb702a2de6b4975c307ac711461890a7fddb0fc9 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Tue, 4 Feb 2020 22:46:13 +0100 Subject: [PATCH 03/24] Cleaned up layout --- .../adapter/FeedItemlistAdapter.java | 2 +- .../adapter/QueueRecyclerAdapter.java | 2 +- .../view/EpisodeItemViewHolder.java | 27 +- app/src/main/res/layout/feeditemlist_item.xml | 303 +++++++++--------- core/src/main/res/values-large/dimens.xml | 2 - core/src/main/res/values/dimens.xml | 4 +- 6 files changed, 180 insertions(+), 160 deletions(-) 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 322b5a489..c1413b6db 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java @@ -51,7 +51,7 @@ public class FeedItemlistAdapter extends BaseAdapter { public View getView(final int position, View convertView, ViewGroup parent) { EpisodeItemViewHolder holder; if (convertView == null) { - holder = new EpisodeItemViewHolder(activity); + holder = new EpisodeItemViewHolder(activity, parent); } else { holder = (EpisodeItemViewHolder) convertView.getTag(); } 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 3aeee1c9f..88dac34ca 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java @@ -55,7 +55,7 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter { if (MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN) { Log.d(TAG, "startDrag()"); diff --git a/app/src/main/java/de/danoeh/antennapod/view/EpisodeItemViewHolder.java b/app/src/main/java/de/danoeh/antennapod/view/EpisodeItemViewHolder.java index 1281a53b7..20218c445 100644 --- a/app/src/main/java/de/danoeh/antennapod/view/EpisodeItemViewHolder.java +++ b/app/src/main/java/de/danoeh/antennapod/view/EpisodeItemViewHolder.java @@ -5,12 +5,15 @@ import android.os.Build; import android.text.Layout; import android.text.TextUtils; import android.util.Log; +import android.view.LayoutInflater; 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 androidx.core.view.LayoutInflaterCompat; import androidx.recyclerview.widget.RecyclerView; import com.joanzapata.iconify.Iconify; import de.danoeh.antennapod.R; @@ -37,7 +40,7 @@ public class EpisodeItemViewHolder extends RecyclerView.ViewHolder implements QueueRecyclerAdapter.ItemTouchHelperViewHolder { private static final String TAG = "EpisodeItemViewHolder"; - private final FrameLayout container; + private final View container; public final ImageView dragHandle; private final TextView placeholder; private final ImageView cover; @@ -49,14 +52,15 @@ public class EpisodeItemViewHolder extends RecyclerView.ViewHolder private final TextView isNew; private final ImageView isInQueue; private final ImageView isVideo; + private final ImageView isFavorite; private final ProgressBar progressBar; private final ImageButton butSecondary; private final MainActivity activity; private FeedItem item; - public EpisodeItemViewHolder(MainActivity activity) { - super(View.inflate(activity, R.layout.feeditemlist_item, null)); + 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); @@ -67,13 +71,14 @@ public class EpisodeItemViewHolder extends RecyclerView.ViewHolder title.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_FULL); } pubDate = itemView.findViewById(R.id.txtvPubDate); - position = itemView.findViewById(R.id.txtvProgressLeft); - duration = itemView.findViewById(R.id.txtvProgressRight); + position = itemView.findViewById(R.id.txtvPosition); + duration = itemView.findViewById(R.id.txtvDuration); butSecondary = itemView.findViewById(R.id.butSecondaryAction); 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); itemView.setTag(this); } @@ -94,8 +99,9 @@ public class EpisodeItemViewHolder extends RecyclerView.ViewHolder title.setText(item.getTitle()); title.setText(item.getTitle()); pubDate.setText(DateUtils.formatAbbrev(activity, item.getPubDate())); - isNew.setVisibility(item.isNew() ? View.VISIBLE : View.INVISIBLE); - isInQueue.setVisibility(item.isTagged(FeedItem.TAG_QUEUE) ? View.VISIBLE : View.INVISIBLE); + 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); if (item.getMedia() != null) { @@ -116,7 +122,7 @@ public class EpisodeItemViewHolder extends RecyclerView.ViewHolder } private void bind(FeedMedia media) { - isVideo.setVisibility(media.getMediaType() == MediaType.VIDEO ? View.VISIBLE : View.INVISIBLE); + isVideo.setVisibility(media.getMediaType() == MediaType.VIDEO ? View.VISIBLE : View.GONE); duration.setText(Converter.getDurationStringLong(media.getDuration())); if (media.isCurrentlyPlaying()) { @@ -126,7 +132,8 @@ public class EpisodeItemViewHolder extends RecyclerView.ViewHolder } final DownloadRequest downloadRequest = DownloadRequester.getInstance().getRequestFor(media); - progressBar.setVisibility(View.INVISIBLE); + progressBar.setVisibility(View.GONE); + position.setVisibility(View.GONE); if (downloadRequest != null) { position.setText(Converter.byteToString(downloadRequest.getSoFar())); if (downloadRequest.getSize() > 0) { @@ -136,11 +143,13 @@ public class EpisodeItemViewHolder extends RecyclerView.ViewHolder } progressBar.setProgress(downloadRequest.getProgressPercent()); progressBar.setVisibility(View.VISIBLE); + position.setVisibility(View.VISIBLE); } else if (item.getState() == FeedItem.State.PLAYING || item.getState() == FeedItem.State.IN_PROGRESS) { if (media.getDuration() > 0) { int progress = (int) (100.0 * media.getPosition() / media.getDuration()); progressBar.setProgress(progress); progressBar.setVisibility(View.VISIBLE); + position.setVisibility(View.VISIBLE); position.setText(Converter.getDurationStringLong(media.getPosition())); duration.setText(Converter.getDurationStringLong(media.getDuration())); } diff --git a/app/src/main/res/layout/feeditemlist_item.xml b/app/src/main/res/layout/feeditemlist_item.xml index 5a369c7a6..6401530c4 100644 --- a/app/src/main/res/layout/feeditemlist_item.xml +++ b/app/src/main/res/layout/feeditemlist_item.xml @@ -1,184 +1,197 @@ - + android:orientation="horizontal" + tools:layout_height="150dp" + android:gravity="center_vertical" + android:baselineAligned="false"> - + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:minWidth="16dp"> - + + + + + + + + + + + + android:id="@+id/status" + android:orientation="horizontal" + android:gravity="center_vertical"> + + 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"/> + - + android:layout_width="16dp" + android:layout_height="16dp" + app:srcCompat="?attr/ic_unfav" + tools:srcCompat="@drawable/ic_star_grey600_24dp" + android:id="@+id/isFavorite"/> - + + + + + - + android:layout_marginRight="4dp" + android:layout_marginEnd="4dp" + tools:text="Feb 12"/> + android:layout_marginRight="4dp" + android:layout_marginEnd="4dp" + android:text="·" + tools:background="@android:color/holo_blue_light"/> - + tools:text="10 MB"/> - + + - + - + - + - + - - - - - - - - - - + - + + + + + diff --git a/core/src/main/res/values-large/dimens.xml b/core/src/main/res/values-large/dimens.xml index 2d107eef0..27e269099 100644 --- a/core/src/main/res/values-large/dimens.xml +++ b/core/src/main/res/values-large/dimens.xml @@ -2,6 +2,4 @@ 170dp - 64dp - 64dp \ No newline at end of file diff --git a/core/src/main/res/values/dimens.xml b/core/src/main/res/values/dimens.xml index 02c398b62..d9d1bc6fe 100644 --- a/core/src/main/res/values/dimens.xml +++ b/core/src/main/res/values/dimens.xml @@ -10,8 +10,8 @@ 16sp 18sp 22sp - 64dp - 64dp + 56dp + 56dp 64dp 100dp 132dp From e14ad4d8594b15a430ed2c843dfce38a2c271543 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Tue, 4 Feb 2020 22:58:25 +0100 Subject: [PATCH 04/24] Converted download list to new item view --- .../DownloadedEpisodesListAdapter.java | 103 +++--------------- .../fragment/CompletedDownloadsFragment.java | 2 +- .../view/EpisodeItemViewHolder.java | 2 +- .../layout/downloaded_episodeslist_item.xml | 102 ----------------- 4 files changed, 20 insertions(+), 189 deletions(-) delete mode 100644 app/src/main/res/layout/downloaded_episodeslist_item.xml 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..ec1425a35 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,23 @@ 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); + holder = new EpisodeItemViewHolder(activity, parent); } else { - holder = (Holder) convertView.getTag(); + holder = (EpisodeItemViewHolder) 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); + final FeedItem item = getItem(position); + holder.bind(item); + holder.dragHandle.setVisibility(View.GONE); + holder.butSecondary.setImageResource(R.drawable.ic_delete_grey600_24dp); + holder.butSecondary.setOnClickListener(v -> { + FeedItem item1 = (FeedItem) v.getTag(); + itemAccess.onFeedItemSecondaryAction(item1); + }); - if(item.isPlayed()) { - convertView.setAlpha(0.5f); - } else { - convertView.setAlpha(1.0f); - } - - 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); - } - }; - - - 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/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/view/EpisodeItemViewHolder.java b/app/src/main/java/de/danoeh/antennapod/view/EpisodeItemViewHolder.java index 20218c445..23cd1314d 100644 --- a/app/src/main/java/de/danoeh/antennapod/view/EpisodeItemViewHolder.java +++ b/app/src/main/java/de/danoeh/antennapod/view/EpisodeItemViewHolder.java @@ -54,7 +54,7 @@ public class EpisodeItemViewHolder extends RecyclerView.ViewHolder private final ImageView isVideo; private final ImageView isFavorite; private final ProgressBar progressBar; - private final ImageButton butSecondary; + public final ImageButton butSecondary; private final MainActivity activity; private FeedItem item; 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 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file From 17aae8c2db352f6a426e8b2098f710df09aaaba3 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Tue, 4 Feb 2020 23:13:15 +0100 Subject: [PATCH 05/24] Replaced all episodes list with new adapter --- .../adapter/AllEpisodesRecycleAdapter.java | 277 +++--------------- .../fragment/EpisodesListFragment.java | 30 +- .../fragment/FavoriteEpisodesFragment.java | 5 +- .../fragment/NewEpisodesFragment.java | 3 +- .../view/EpisodeItemViewHolder.java | 4 + app/src/main/res/layout/feeditemlist_item.xml | 13 +- .../main/res/layout/new_episodes_listitem.xml | 147 ---------- 7 files changed, 54 insertions(+), 425 deletions(-) delete mode 100644 app/src/main/res/layout/new_episodes_listitem.xml 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 f1946d9a8..8d3a70542 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java @@ -1,54 +1,29 @@ 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.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 list of new episodes + * List adapter for the list of new episodes. */ -public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter { - - private static final String TAG = AllEpisodesRecycleAdapter.class.getSimpleName(); +public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter + implements View.OnCreateContextMenuListener { private final WeakReference mainActivityRef; private final ItemAccess itemAccess; @@ -56,149 +31,38 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter(mainActivity); this.itemAccess = itemAccess; this.showOnlyNewEpisodes = showOnlyNewEpisodes; + } - playingBackGroundColor = ThemeUtils.getColorFromAttr(mainActivity, R.attr.currently_playing_background); - normalBackGroundColor = ContextCompat.getColor(mainActivity, android.R.color.transparent); + @NonNull + @Override + public EpisodeItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + EpisodeItemViewHolder viewHolder = new EpisodeItemViewHolder(mainActivityRef.get(), parent); + viewHolder.dragHandle.setVisibility(View.GONE); + return viewHolder; } @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; - } - - @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 = itemAccess.getItem(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(""); + holder.itemView.setOnClickListener(v -> { + MainActivity activity = mainActivityRef.get(); + if (activity != null) { + long[] ids = itemAccess.getQueueIds().toArray(); + int position = ArrayUtils.indexOf(ids, item.getId()); + activity.loadChildFragment(ItemPagerFragment.newInstance(ids, position)); } - - FeedItem.State state = item.getState(); - if (isDownloadingMedia) { - holder.progress.setVisibility(View.VISIBLE); - // item is being downloaded - holder.progress.setProgress(itemAccess.getItemDownloadProgressPercent(item)); - } else if (state == FeedItem.State.PLAYING - || state == FeedItem.State.IN_PROGRESS) { - if (media.getDuration() > 0) { - int progress = (int) (100.0 * media.getPosition() / media.getDuration()); - holder.progress.setProgress(progress); - holder.progress.setVisibility(View.VISIBLE); - } - } else { - holder.progress.setVisibility(View.INVISIBLE); - } - - if (media.isCurrentlyPlaying()) { - holder.container.setBackgroundColor(playingBackGroundColor); - } else { - holder.container.setBackgroundColor(normalBackGroundColor); - } - } else { - holder.progress.setVisibility(View.INVISIBLE); - holder.txtvDuration.setVisibility(View.GONE); - } - - boolean isInQueue = itemAccess.isInQueue(item); - if (isInQueue) { - holder.queueStatus.setVisibility(View.VISIBLE); - } else { - holder.queueStatus.setVisibility(View.INVISIBLE); - } - - ItemActionButton actionButton = ItemActionButton.forItem(item, isInQueue); - actionButton.configure(holder.butSecondary, mainActivityRef.get()); - - holder.butSecondary.setFocusable(false); - holder.butSecondary.setTag(item); - - new CoverLoader(mainActivityRef.get()) - .withUri(ImageResourceUtils.getImageLocation(item)) - .withFallbackUri(item.getFeed().getImageLocation()) - .withPlaceholderView(holder.placeholder) - .withCoverView(holder.cover) - .load(); + }); + holder.itemView.setOnCreateContextMenuListener(this); } @Nullable @@ -217,73 +81,12 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter 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())); - } - + @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); } public interface ItemAccess { @@ -292,12 +95,6 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter @@ -48,8 +47,7 @@ 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"/> + tools:src="@tools:sample/avatars" /> @@ -80,7 +78,8 @@ android:layout_height="wrap_content" android:id="@+id/statusUnread" android:layout_marginRight="4dp" - android:layout_marginEnd="4dp"/> + android:layout_marginEnd="4dp" + tools:text="@sample/episodes.json/data/status_label"/> + tools:text="@sample/episodes.json/data/published_at"/> @@ -183,7 +182,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="0dp" - tools:text="01:23:23" + tools:text="@sample/episodes.json/data/duration" tools:background="@android:color/holo_blue_light"/> 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 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From f3cbaee61b2fbffdc76c782cb04457c17dc5d7d7 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Wed, 5 Feb 2020 10:07:01 +0100 Subject: [PATCH 06/24] Replaced eye icon with video cam --- app/src/main/res/layout/feeditemlist_item.xml | 12 ++++++------ .../res/drawable-hdpi/ic_hearing_grey600_18dp.png | Bin 478 -> 0 bytes .../res/drawable-hdpi/ic_hearing_white_18dp.png | Bin 449 -> 0 bytes .../ic_remove_red_eye_grey600_18dp.png | Bin 380 -> 0 bytes .../ic_remove_red_eye_white_18dp.png | Bin 358 -> 0 bytes .../res/drawable-mdpi/ic_hearing_grey600_18dp.png | Bin 324 -> 0 bytes .../res/drawable-mdpi/ic_hearing_white_18dp.png | Bin 301 -> 0 bytes .../ic_remove_red_eye_grey600_18dp.png | Bin 265 -> 0 bytes .../ic_remove_red_eye_white_18dp.png | Bin 259 -> 0 bytes .../drawable-xhdpi/ic_hearing_grey600_18dp.png | Bin 621 -> 0 bytes .../res/drawable-xhdpi/ic_hearing_white_18dp.png | Bin 588 -> 0 bytes .../ic_remove_red_eye_grey600_18dp.png | Bin 492 -> 0 bytes .../ic_remove_red_eye_white_18dp.png | Bin 472 -> 0 bytes .../drawable-xxhdpi/ic_hearing_grey600_18dp.png | Bin 885 -> 0 bytes .../res/drawable-xxhdpi/ic_hearing_white_18dp.png | Bin 840 -> 0 bytes .../ic_remove_red_eye_grey600_18dp.png | Bin 697 -> 0 bytes .../ic_remove_red_eye_white_18dp.png | Bin 669 -> 0 bytes .../res/drawable/ic_videocam_grey600_24dp.xml | 8 ++++++++ .../main/res/drawable/ic_videocam_white_24dp.xml | 8 ++++++++ core/src/main/res/values/attrs.xml | 1 - core/src/main/res/values/styles.xml | 6 ++---- 21 files changed, 24 insertions(+), 11 deletions(-) delete mode 100644 core/src/main/res/drawable-hdpi/ic_hearing_grey600_18dp.png delete mode 100644 core/src/main/res/drawable-hdpi/ic_hearing_white_18dp.png delete mode 100644 core/src/main/res/drawable-hdpi/ic_remove_red_eye_grey600_18dp.png delete mode 100644 core/src/main/res/drawable-hdpi/ic_remove_red_eye_white_18dp.png delete mode 100644 core/src/main/res/drawable-mdpi/ic_hearing_grey600_18dp.png delete mode 100644 core/src/main/res/drawable-mdpi/ic_hearing_white_18dp.png delete mode 100644 core/src/main/res/drawable-mdpi/ic_remove_red_eye_grey600_18dp.png delete mode 100644 core/src/main/res/drawable-mdpi/ic_remove_red_eye_white_18dp.png delete mode 100644 core/src/main/res/drawable-xhdpi/ic_hearing_grey600_18dp.png delete mode 100644 core/src/main/res/drawable-xhdpi/ic_hearing_white_18dp.png delete mode 100644 core/src/main/res/drawable-xhdpi/ic_remove_red_eye_grey600_18dp.png delete mode 100644 core/src/main/res/drawable-xhdpi/ic_remove_red_eye_white_18dp.png delete mode 100644 core/src/main/res/drawable-xxhdpi/ic_hearing_grey600_18dp.png delete mode 100644 core/src/main/res/drawable-xxhdpi/ic_hearing_white_18dp.png delete mode 100644 core/src/main/res/drawable-xxhdpi/ic_remove_red_eye_grey600_18dp.png delete mode 100644 core/src/main/res/drawable-xxhdpi/ic_remove_red_eye_white_18dp.png create mode 100644 core/src/main/res/drawable/ic_videocam_grey600_24dp.xml create mode 100644 core/src/main/res/drawable/ic_videocam_white_24dp.xml diff --git a/app/src/main/res/layout/feeditemlist_item.xml b/app/src/main/res/layout/feeditemlist_item.xml index b57e347ba..3d9043caa 100644 --- a/app/src/main/res/layout/feeditemlist_item.xml +++ b/app/src/main/res/layout/feeditemlist_item.xml @@ -84,16 +84,16 @@ + app:srcCompat="?attr/type_video" + tools:srcCompat="@drawable/ic_videocam_grey600_24dp" + android:id="@+id/ivIsVideo"/> + app:srcCompat="?attr/ic_unfav" + tools:srcCompat="@drawable/ic_star_grey600_24dp" + android:id="@+id/isFavorite"/> )c7qc7|tZlSoD)xo@oaV z4jQdh`o{<&JC7CQCc<~JyO$Dcp-@e!ob~SEZaf}$5stXm8Y6rrywVn>W0ng|Yt}NA zR2EgRc5bi7NQC27`dO*Dmx{Pwel$x-@EPOm<7dxYmk$CMTr#b6Q7 zId4t8&@x%yyh=Ttm1*bmhS& zUL=ig!~*=}FI9}Y^BdtM8GR$RpoKFRxXAyp}kg2>7vrPeRWj?Qo+qQ~dpPfT zDq%vjbT`sRy~==19*pYcC~~gW0$rlt4ljpvt-SzBMQeJZ@wr+nv=6V3f@edz(NO>u zPJZ8$?m1VhiJ{^3ItTGf)awm6?2X{!ksa$J8jqF{-LAFuX80wzRJ;h@2`MKIcru7t z%t5Q@n^s|r>td#5#}VOI_yzQFb4;}B%)?x_giz~tBNKn785NEj`=a-$L&DAm}pm4nb_D3m6k&V#>rg-=nX^7f?T}s;TZl+rStG zJ~r6mlq?VGIpII+`1)JId{>Pd9oIeI2=_8QA|sj>70L^oW~rO$9W|@TF3Y$S=VXB$ zlU4fbcGGK-_csoq*!d~6XVNr7Ra8T(i8+vs!?|jLVV_~%L%yUBf!ydXD&`u*Wti ahS3D)PkQLle`ee~3E)mY2Aadm1U7*kCdK>z>%07*qoM6N<$ Ef^>zTC;$Ke diff --git a/core/src/main/res/drawable-mdpi/ic_hearing_grey600_18dp.png b/core/src/main/res/drawable-mdpi/ic_hearing_grey600_18dp.png deleted file mode 100644 index ea44e3f073cf0619724a3d08f87220f0c50e4e78..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 324 zcmV-K0lWT*P)4#t zze^MV90$i3Mdkeb)UP$0q!;p^?E1+4jSjrt-mP26IQp ztHeut+RkS%_l=~-oL%p75=;KLkRH!G&0uco_~e{fyWZwFp6e>*yNfxV+j!zk{@*_> WMuzcKrl-RI0000YoWO2)?s(PF#*kV$Kpg0brnf0MwfiyfP0C} z9w?=}OSqt%(jM55FC25?Inp(6P`MO|@ISq0dqbbe1)ugyu!^u`61^Lqv;mG=zv!jAll)t;-C_lz?( zzo)g=j;N%M7nbEuOz{?6S3Q5Glj%k&lmGV)o#W6!B{bxZ00000NkvXXu0mjfN(hLX diff --git a/core/src/main/res/drawable-mdpi/ic_remove_red_eye_grey600_18dp.png b/core/src/main/res/drawable-mdpi/ic_remove_red_eye_grey600_18dp.png deleted file mode 100644 index daa8e568ef5f0dacec4091b54c9cf19e2ae27aff..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 265 zcmV+k0rvihP)U*|+@%<_0%XIF-t*3fv(MA{ZYExoTceZ~##yjF zMl+>{<*eP8zQ|S~8kZ6+Jj7dhjMo0fDWp zJh|EdC3-(<*pW6xO2&+o4XS>A%uX(O`_?aL|L?by(8vh$)`w}(ZSrXET_>_mx*9oA P00000NkvXXu0mjf(9dn` diff --git a/core/src/main/res/drawable-mdpi/ic_remove_red_eye_white_18dp.png b/core/src/main/res/drawable-mdpi/ic_remove_red_eye_white_18dp.png deleted file mode 100644 index a6b4ff0da47f76de87d348e4b5f0aa1820c9d1a4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 259 zcmV+e0sQ`nP)qG6P;kM!*>X*Bx+&9(NgrhfIJp=*KPM86f|a<62WS_@&*9)o`Y@ z`Bmxg!+;0HxYy@Lu}gy!@Mc~{%3R>!P+g(Sb=IXVNO6hqw`ScgvSm#G<^#VCwgNW~ z7zr*SUH}rr9w2Z~9%dXneW%jsLjQ_f7D&eOVlUBl+&>YHC3*T%12ou#h{!#z{002ov JPDHLkV1oI_aG(GH diff --git a/core/src/main/res/drawable-xhdpi/ic_hearing_grey600_18dp.png b/core/src/main/res/drawable-xhdpi/ic_hearing_grey600_18dp.png deleted file mode 100644 index d014684e19bd4ccabf7fd4fee33a32ffbea1d635..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 621 zcmV-z0+RiSP)A8u!7Z_aD*VL^y@Wa{G< zGI=hO8=vqO_mENd#Gxm);URu#&qHiQ55zi_3BXzW)t;M3CJw?Ve56NxK41g_?F;o` z;Ai9|O2RQ>YtLaM+Lj5$Qw9wpip51~bOZg72ayOyPV~YR@t#MtEuq#7xQ`&B%|w4N z8i8ihAAvvQ*4q-=t&FF-^xM^HWG7*(SfAKel4*(d(q5;t!6=Sm2-5Ld^1H1Gl_YgV zmiafQl|{IEct-XK>WC*ZBYq>nQm73>H_&cK`-CtB@dJP5`Hp?F8=0FQf`r2T#a8LQTgPHca|WLv%o0C0^g6C}Me4 z9iQxGv_Bz(JGrPW8{b2aX8Yre+;Z3RB|_!=4j?Kf$8ZNCT$k!C`6w4rPuZ!n$l|I{ zAWpOCbtDpx6sb3;>T=FzYQ2s0g4;<>_=d`^O4Y-4b+1qu_bK%pajr@Qo8feLM5%EG zPYaq$682Mk{s`0_KUX*51*PgLzM1q4c6CgX*z6L*1xLwr>$obEiVtjf6h#q?k~m8A z)b(@ERBZ9IbZ^Of;)f#g3w_+*z5G~%$M}W^Sb_Y8|E2r`L~i295Q4Y%00000NkvXX Hu0mjf?ad%U diff --git a/core/src/main/res/drawable-xhdpi/ic_hearing_white_18dp.png b/core/src/main/res/drawable-xhdpi/ic_hearing_white_18dp.png deleted file mode 100644 index 91adb443756e586ca2dae777ea94a779725f75b5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 588 zcmV-S0<-;zP)lNgKh$U+BtR= z)@x5|l(&z`_BFU8cEw%?yysRs$(Lz+H+T#1s>1d_7lKb^#BL5~^pNxx%fDYEn9&|+ zNn$?70A1cPj10*bNsS8Kq2QL*pohR? ziTd%7tdP{Q&^^i{9&uP}(B0t4#Eb@qWHdmSXUB3Wm=-n{R)=I){{r~OPMv`c1aHQ5 znFiFW4%tb*0$(^j>P&L{3pR?~%CJj8GVE=y4xef}H~Sp$hs~ny%f;Xm8BrwFOJI%e z|1V|x2HY0Aebj=5^16?@5&UU~*j*2J*;d^JrF#*)t337(0Df|G_y5_y<3pPUe~G`r zKaT7!>J;xL&&r-Y1>Y*^E-JHy-^3T-(Wtj_F8EYRqL(UNx|Hr7!gt{0L~jtdE9#y+ z3Eq$!e1R{(N!fIFeRCYDhm;UjYiFS?t aFZvI(k;JtWcYlun0000i5QiUD&adF^Ue5{+z2erx-G^q}t>F$YV+}93L&Dv?o$cw){7xG(lioM8|KGkH zasEF0Z-g03BIjcXw2d!Cz%@lgYEQcEYg|f{1!*G|6(bf z>)++FIPw{n^{nJ5??vPyJ!;8};)Rv^j)in7N4qeWw^sZa!yRo55ovent8#jB$I5xl zKwYIr;xm*$EXj1>rU<#kpOR&d8Gc;QYbBv+>cD!#lZvMdU#0leT0$!gUsOYAwc=Aszji|e zjvAg&2cm|%f?lmW_9PK{UwrH{7Cl*f><=P)e0AOSiQwE~`A=752pYCfWbU&2$j<{S z{Fa{OhD_x=TAD^t{Cjw1Zx7)Vvnsb-%a?}{vVg)^v diff --git a/core/src/main/res/drawable-xhdpi/ic_remove_red_eye_white_18dp.png b/core/src/main/res/drawable-xhdpi/ic_remove_red_eye_white_18dp.png deleted file mode 100644 index 6dd240bcaf35465a613b46dba12ebb2a33731cf1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 472 zcmV;}0Vn>6P)Nklb4IS&inF&j*A(Y4|GhNZ&fnGPeY@wJm)$sg^6~R~ zI`ZG&ha%&tQDZzsX#_du;_wpP3(hi^tRzKW_VI%--`Ptai9=V`@{2e>SxwjIx7@_^ z35Tt$=QQsyU8h&rF=Kd+?k$VyCN8=$pEu~9GE)2)W-V)>zgXx^GrCs{_IK$ay0_jj zR9MOiYNF7Gx9Hl*h>qi!7OT+$7w}x7pvD$rI;>!$G}$|*6ZbJW zZc(<18b6Eaj(5-uY+Kd%Qf$lA_y%m#!wy=n##e+Kv=Q4hue5uZPOI@6wz3*`Fx?gp zQ!u@A!@h*>yc_m=OcSM!Bbes9?Y~$*hP)bEjOl>r$kLAP4ZTI7!ZMao_I{(){8rLp zVhFF$HPgrcscA*`f`Q`4NS>m5%R=MRF1B9tnBfwP-dy*^ewGbv#PLOZg&q=)uB_w- zalW&hE)s{{?BW|?zOj>@k`x(camvc<38$DvMjAn$u~exthMfHO*ZB=P9J3dUFRNtxi??iiKY(!VuL3SiDQShTwx-sEAzf)=($xV?|<BrKXQl1MsruG6CpRy5T=Xi3%7Ssp zK0#>i2-m6Gi(o2s1HglWEF0cS-!6taS#UfAcM{S@nk8IFovsdteTB57oh02ybb+H9 znWJ<8zYcfu#+s|>Bsi(jg~3fR*>h@mK0K0iLsb2gDe*#9kw?Q}NmopjF1J=i?uF%) zUFDB#uLd`4m*=a!buqYwZ6vf`oorc<<>3H>a&K)c-A z*}#Wtd*8a+Ma#HTa*vL=j^SQSyUS?Ne3p`YE`QN9KG8fMn<|>iGm=$vo5I&*!`)(I zQ|qC z8coqN59-HrTU0XCGSMi@875gE8fQhx7P&nt*&&)_7s-RsI41!{7^PBXkUUzPLwZ=m z+7{8hP}_S_GHo;_fAGazj+87MnU41J6W~XC>kyg6B!@+9+8F>iGq+~}?-W*&D-~T{ zcsGsRr=m8aOLnZ3&iR3#To`rLHjK<^c|diHT1+chxl$%+@W)LYT$05r zWmd^zQK659^^OWlNM?>&%p;kC9Jo^^RK1B3Ytp;ICM3B>t@0k2*w4 zm{_u2rHm}uBQh7Oc7C*sI>~{#eFnHSGUNG9(YMBlmdZ2ahN?w)klvA*(-$(InLS$0 zwScd+uaxy9TSYzk+1o?j@{qmsjn=TEWR6PdZ9v|mI!BpIDLFZ}vm`r5x$^4pgI;-z z4h0M_d6db{l0B<79$wWq%A;SNvfmpuuLvJWp3pDK<7mm{xh-Ir@Eq9+Q4WjdLlx-eCdmi7MBCEYLz4BPt(hn2Or7s+czkIc4`TcRxLyeIk8y87vAW*3qz7Ujr$ zL2cJZxom2LhP|R+l+7xBQ0;yrM_VwCiwz-r!-m>N+tJrDwzsSGO%wn77x@L^sp9h1 Sn+eST0000NusvHf1<19Equ}H~K#_O1TupIAv`2hu-qx z{U}VJ&8Qf_ULpu*H~s8Jciq_b1C30mlAIT|gKj~6O@rLM9UO9X46&7OVZlzolf zXM_k9<|{{0f)wGp>Y_c3iMJn>4XV3@ZJu#HJD!m)dT!BNc`nMal{6neshcUMycHdZ z@){LEd*!R>ZTf}^)9Wv8bk9X2R&pMBh0-|BavG|_6V({P8cq_+4IX934PrUTYKBlv fS+ZowQjseQ$8@O(fjqm>00000NkvXXu0mjf&{9aJ diff --git a/core/src/main/res/drawable-xxhdpi/ic_remove_red_eye_white_18dp.png b/core/src/main/res/drawable-xxhdpi/ic_remove_red_eye_white_18dp.png deleted file mode 100644 index 695eb950ebf3a02d9df4800efef14a34c86fdf23..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 669 zcmV;O0%HA%P)S<52$I(f4OBG@8_8CFRtEgSP9!#i{6FZgMerMy)2BYTlJ=(D0CxwvIh-gR~kk{o_ezL<UpJ|s z$77L=^Q|h&Q)E4KCKpMj9`B9pF{PCo87z~*@NUI&6F8~ zv61ZH7iGY&hANBxf$wSy$x#|A0Zj}W_?kf~Fgo!Vi9;;C`CI4yp$~D$9@0()hiaU{ z#O5-4*~?{YOioZm1&`lYj72ys7V?`474=9VR7uoP;i84`8!EGj)DL?2D9?2EVq;>l zm#LIf1&9CW$Sk&#&N0q&o@1o5otbpxKUL^F9*^e@`E&Ce01@Mg00000NkvXXu0mjf Di~2R= diff --git a/core/src/main/res/drawable/ic_videocam_grey600_24dp.xml b/core/src/main/res/drawable/ic_videocam_grey600_24dp.xml new file mode 100644 index 000000000..40c893883 --- /dev/null +++ b/core/src/main/res/drawable/ic_videocam_grey600_24dp.xml @@ -0,0 +1,8 @@ + + + diff --git a/core/src/main/res/drawable/ic_videocam_white_24dp.xml b/core/src/main/res/drawable/ic_videocam_white_24dp.xml new file mode 100644 index 000000000..a8cfd71e3 --- /dev/null +++ b/core/src/main/res/drawable/ic_videocam_white_24dp.xml @@ -0,0 +1,8 @@ + + + diff --git a/core/src/main/res/values/attrs.xml b/core/src/main/res/values/attrs.xml index 53cf7b211..066594f3d 100644 --- a/core/src/main/res/values/attrs.xml +++ b/core/src/main/res/values/attrs.xml @@ -26,7 +26,6 @@ - diff --git a/core/src/main/res/values/styles.xml b/core/src/main/res/values/styles.xml index f5b43629c..d341048ff 100644 --- a/core/src/main/res/values/styles.xml +++ b/core/src/main/res/values/styles.xml @@ -38,8 +38,7 @@ @drawable/navigation_up @drawable/ic_share_grey600_24dp @drawable/ic_list_grey600_24dp - @drawable/ic_hearing_grey600_18dp - @drawable/ic_remove_red_eye_grey600_18dp + @drawable/ic_videocam_grey600_24dp @color/white @color/overlay_light @drawable/overlay_drawable @@ -127,8 +126,7 @@ @drawable/navigation_up_dark @drawable/ic_share_white_24dp @drawable/ic_list_white_24dp - @drawable/ic_hearing_white_18dp - @drawable/ic_remove_red_eye_white_18dp + @drawable/ic_videocam_white_24dp @color/black @color/overlay_dark @drawable/overlay_drawable_dark From 8b6a53fb88a3bdc70e22f316dbeed7a71b868266 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Wed, 5 Feb 2020 10:18:06 +0100 Subject: [PATCH 07/24] Hide separator dot if there are no icons --- .../adapter/AllEpisodesRecycleAdapter.java | 7 +++---- .../DownloadedEpisodesListAdapter.java | 1 + .../adapter/FeedItemlistAdapter.java | 1 + .../adapter/QueueRecyclerAdapter.java | 2 ++ .../fragment/AllEpisodesFragment.java | 5 ----- .../fragment/EpisodesListFragment.java | 6 +----- .../fragment/FavoriteEpisodesFragment.java | 5 ----- .../fragment/NewEpisodesFragment.java | 5 ----- .../view/EpisodeItemViewHolder.java | 20 ++++++++++++++++--- app/src/main/res/layout/feeditemlist_item.xml | 1 + 10 files changed, 26 insertions(+), 27 deletions(-) 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 8d3a70542..8e232a17f 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java @@ -27,20 +27,18 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter mainActivityRef; private final ItemAccess itemAccess; - private final boolean showOnlyNewEpisodes; private FeedItem selectedItem; - public AllEpisodesRecycleAdapter(MainActivity mainActivity, ItemAccess itemAccess, boolean showOnlyNewEpisodes) { + public AllEpisodesRecycleAdapter(MainActivity mainActivity, ItemAccess itemAccess) { super(); this.mainActivityRef = new WeakReference<>(mainActivity); this.itemAccess = itemAccess; - this.showOnlyNewEpisodes = showOnlyNewEpisodes; } @NonNull @Override - public EpisodeItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + public EpisodeItemViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { EpisodeItemViewHolder viewHolder = new EpisodeItemViewHolder(mainActivityRef.get(), parent); viewHolder.dragHandle.setVisibility(View.GONE); return viewHolder; @@ -63,6 +61,7 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter Date: Wed, 5 Feb 2020 11:21:30 +0100 Subject: [PATCH 08/24] Added circular action buttons --- .../antennapod/view/CircularProgressBar.java | 87 +++++++++++++++++++ .../view/EpisodeItemViewHolder.java | 54 ++++++------ app/src/main/res/layout/feeditemlist_item.xml | 2 - app/src/main/res/layout/secondary_action.xml | 36 +++++--- 4 files changed, 139 insertions(+), 40 deletions(-) create mode 100644 app/src/main/java/de/danoeh/antennapod/view/CircularProgressBar.java 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 index 6fb3c9d86..c3a007d5d 100644 --- a/app/src/main/java/de/danoeh/antennapod/view/EpisodeItemViewHolder.java +++ b/app/src/main/java/de/danoeh/antennapod/view/EpisodeItemViewHolder.java @@ -3,17 +3,14 @@ package de.danoeh.antennapod.view; import android.graphics.Color; import android.os.Build; import android.text.Layout; -import android.text.TextUtils; import android.util.Log; import android.view.LayoutInflater; 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 androidx.core.view.LayoutInflaterCompat; import androidx.recyclerview.widget.RecyclerView; import com.joanzapata.iconify.Iconify; import de.danoeh.antennapod.R; @@ -55,6 +52,7 @@ public class EpisodeItemViewHolder extends RecyclerView.ViewHolder public final ImageView isFavorite; private final ProgressBar progressBar; public final ImageButton butSecondary; + private final CircularProgressBar secondaryActionProgress; private final MainActivity activity; private final TextView separatorIcons; @@ -82,6 +80,7 @@ public class EpisodeItemViewHolder extends RecyclerView.ViewHolder isFavorite = itemView.findViewById(R.id.isFavorite); size = itemView.findViewById(R.id.size); separatorIcons = itemView.findViewById(R.id.separatorIcons); + secondaryActionProgress = itemView.findViewById(R.id.secondaryActionProgress); itemView.setTag(this); } @@ -106,15 +105,17 @@ public class EpisodeItemViewHolder extends RecyclerView.ViewHolder isInQueue.setVisibility(item.isTagged(FeedItem.TAG_QUEUE) ? View.VISIBLE : View.GONE); itemView.setAlpha(item.isPlayed() /*&& makePlayedItemsTransparent*/ ? 0.5f : 1.0f); - if (item.getMedia() != null) { - bind(item.getMedia()); - } - ItemActionButton actionButton = ItemActionButton.forItem(item, true); actionButton.configure(butSecondary, activity); butSecondary.setFocusable(false); butSecondary.setTag(item); + if (item.getMedia() != null) { + bind(item.getMedia()); + } else { + secondaryActionProgress.setPercentage(0, item); + } + new CoverLoader(activity) .withUri(ImageResourceUtils.getImageLocation(item)) .withFallbackUri(item.getFeed().getImageLocation()) @@ -133,28 +134,27 @@ public class EpisodeItemViewHolder extends RecyclerView.ViewHolder container.setBackgroundColor(Color.TRANSPARENT); } - final DownloadRequest downloadRequest = DownloadRequester.getInstance().getRequestFor(media); - progressBar.setVisibility(View.GONE); - position.setVisibility(View.GONE); - if (downloadRequest != null) { - position.setText(Converter.byteToString(downloadRequest.getSoFar())); - if (downloadRequest.getSize() > 0) { - duration.setText(Converter.byteToString(downloadRequest.getSize())); - } else { - duration.setText(Converter.byteToString(media.getSize())); - } - progressBar.setProgress(downloadRequest.getProgressPercent()); + 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 if (item.getState() == FeedItem.State.PLAYING || item.getState() == FeedItem.State.IN_PROGRESS) { - if (media.getDuration() > 0) { - int progress = (int) (100.0 * media.getPosition() / media.getDuration()); - progressBar.setProgress(progress); - progressBar.setVisibility(View.VISIBLE); - position.setVisibility(View.VISIBLE); - position.setText(Converter.getDurationStringLong(media.getPosition())); - duration.setText(Converter.getDurationStringLong(media.getDuration())); - } + } else { + progressBar.setVisibility(View.GONE); + position.setVisibility(View.GONE); } if (media.getSize() > 0) { diff --git a/app/src/main/res/layout/feeditemlist_item.xml b/app/src/main/res/layout/feeditemlist_item.xml index 09dbc8908..cd983ffca 100644 --- a/app/src/main/res/layout/feeditemlist_item.xml +++ b/app/src/main/res/layout/feeditemlist_item.xml @@ -190,8 +190,6 @@ - - diff --git a/app/src/main/res/layout/secondary_action.xml b/app/src/main/res/layout/secondary_action.xml index 1f4d9e4e6..d083d5181 100644 --- a/app/src/main/res/layout/secondary_action.xml +++ b/app/src/main/res/layout/secondary_action.xml @@ -1,12 +1,26 @@ - + + + + + + From 3ca6be8b04cf3c96517cb5ca9c16d2b0b67eead5 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Wed, 5 Feb 2020 11:38:30 +0100 Subject: [PATCH 09/24] Increase touchable area --- .../DownloadedEpisodesListAdapter.java | 7 ++----- .../actionbutton/ItemActionButton.java | 8 +++---- .../view/EpisodeItemViewHolder.java | 15 ++++++------- app/src/main/res/layout/secondary_action.xml | 21 ++++++++++--------- .../antennapod/core/util/ThemeUtils.java | 7 +++++++ 5 files changed, 32 insertions(+), 26 deletions(-) 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 c9cf07621..37d570e26 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/DownloadedEpisodesListAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/DownloadedEpisodesListAdapter.java @@ -49,11 +49,8 @@ public class DownloadedEpisodesListAdapter extends BaseAdapter { final FeedItem item = getItem(position); holder.bind(item); holder.dragHandle.setVisibility(View.GONE); - holder.butSecondary.setImageResource(R.drawable.ic_delete_grey600_24dp); - holder.butSecondary.setOnClickListener(v -> { - FeedItem item1 = (FeedItem) v.getTag(); - itemAccess.onFeedItemSecondaryAction(item1); - }); + holder.secondaryActionIcon.setImageResource(R.drawable.ic_delete_grey600_24dp); + holder.secondaryActionButton.setOnClickListener(v -> itemAccess.onFeedItemSecondaryAction(item)); holder.hideSeparatorIfNecessary(); return holder.itemView; 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 861c6a4be..970a1cfae 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; @@ -53,14 +54,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/view/EpisodeItemViewHolder.java b/app/src/main/java/de/danoeh/antennapod/view/EpisodeItemViewHolder.java index c3a007d5d..d9aa92717 100644 --- a/app/src/main/java/de/danoeh/antennapod/view/EpisodeItemViewHolder.java +++ b/app/src/main/java/de/danoeh/antennapod/view/EpisodeItemViewHolder.java @@ -51,7 +51,8 @@ public class EpisodeItemViewHolder extends RecyclerView.ViewHolder private final ImageView isVideo; public final ImageView isFavorite; private final ProgressBar progressBar; - public final ImageButton butSecondary; + public final View secondaryActionButton; + public final ImageView secondaryActionIcon; private final CircularProgressBar secondaryActionProgress; private final MainActivity activity; private final TextView separatorIcons; @@ -72,7 +73,6 @@ public class EpisodeItemViewHolder extends RecyclerView.ViewHolder pubDate = itemView.findViewById(R.id.txtvPubDate); position = itemView.findViewById(R.id.txtvPosition); duration = itemView.findViewById(R.id.txtvDuration); - butSecondary = itemView.findViewById(R.id.butSecondaryAction); progressBar = itemView.findViewById(R.id.progressBar); isInQueue = itemView.findViewById(R.id.ivInPlaylist); isVideo = itemView.findViewById(R.id.ivIsVideo); @@ -81,6 +81,8 @@ public class EpisodeItemViewHolder extends RecyclerView.ViewHolder 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); itemView.setTag(this); } @@ -106,9 +108,8 @@ public class EpisodeItemViewHolder extends RecyclerView.ViewHolder itemView.setAlpha(item.isPlayed() /*&& makePlayedItemsTransparent*/ ? 0.5f : 1.0f); ItemActionButton actionButton = ItemActionButton.forItem(item, true); - actionButton.configure(butSecondary, activity); - butSecondary.setFocusable(false); - butSecondary.setTag(item); + actionButton.configure(secondaryActionButton, secondaryActionIcon, activity); + secondaryActionButton.setFocusable(false); if (item.getMedia() != null) { bind(item.getMedia()); @@ -131,7 +132,7 @@ public class EpisodeItemViewHolder extends RecyclerView.ViewHolder if (media.isCurrentlyPlaying()) { container.setBackgroundColor(ThemeUtils.getColorFromAttr(activity, R.attr.currently_playing_background)); } else { - container.setBackgroundColor(Color.TRANSPARENT); + container.setBackgroundResource(ThemeUtils.getDrawableFromAttr(activity, R.attr.selectableItemBackground)); } if (DownloadRequester.getInstance().isDownloadingFile(media)) { @@ -146,7 +147,7 @@ public class EpisodeItemViewHolder extends RecyclerView.ViewHolder if (media.getDuration() > 0 && (item.getState() == FeedItem.State.PLAYING || item.getState() == FeedItem.State.IN_PROGRESS)) { - int progress = (int) (100.0 * media.getPosition() / media.getDuration()); + int progress = (int) (100.0 * media.getPosition() / media.getDuration()); progressBar.setProgress(progress); position.setText(Converter.getDurationStringLong(media.getPosition())); duration.setText(Converter.getDurationStringLong(media.getDuration())); diff --git a/app/src/main/res/layout/secondary_action.xml b/app/src/main/res/layout/secondary_action.xml index d083d5181..ac8d6504c 100644 --- a/app/src/main/res/layout/secondary_action.xml +++ b/app/src/main/res/layout/secondary_action.xml @@ -2,20 +2,21 @@ + android:layout_marginEnd="16dp" + android:id="@+id/secondaryActionButton" + android:background="?selectableItemBackgroundBorderless" + android:clickable="true" + android:focusable="false" + android:focusableInTouchMode="false" > - Date: Wed, 5 Feb 2020 11:48:49 +0100 Subject: [PATCH 10/24] Removed unnecessary ItemAccess --- .../adapter/AllEpisodesRecycleAdapter.java | 32 +++++++-------- .../fragment/EpisodesListFragment.java | 39 +++---------------- 2 files changed, 19 insertions(+), 52 deletions(-) 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 8e232a17f..c9b8e5ab2 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java @@ -11,13 +11,15 @@ import androidx.recyclerview.widget.RecyclerView; import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.MainActivity; import de.danoeh.antennapod.core.feed.FeedItem; -import de.danoeh.antennapod.core.util.LongList; +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. @@ -26,14 +28,18 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter mainActivityRef; - private final ItemAccess itemAccess; + private List episodes = new ArrayList<>(); private FeedItem selectedItem; - public AllEpisodesRecycleAdapter(MainActivity mainActivity, ItemAccess itemAccess) { + public AllEpisodesRecycleAdapter(MainActivity mainActivity) { super(); this.mainActivityRef = new WeakReference<>(mainActivity); - this.itemAccess = itemAccess; + } + + public void updateItems(List items) { + episodes = items; + notifyDataSetChanged(); } @NonNull @@ -46,7 +52,7 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter { selectedItem = item; @@ -55,7 +61,7 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter { MainActivity activity = mainActivityRef.get(); if (activity != null) { - long[] ids = itemAccess.getQueueIds().toArray(); + long[] ids = FeedItemUtil.getIds(episodes); int position = ArrayUtils.indexOf(ids, item.getId()); activity.loadChildFragment(ItemPagerFragment.newInstance(ids, position)); } @@ -71,13 +77,13 @@ public class AllEpisodesRecycleAdapter extends RecyclerView.Adapter episodes = new ArrayList<>(); - @NonNull - private List downloaderList = new ArrayList<>(); private boolean isUpdatingFeeds; boolean isMenuInvalidationAllowed = false; @@ -344,10 +342,10 @@ public abstract class EpisodesListFragment extends Fragment { } protected void onFragmentLoaded(List episodes) { - listAdapter.notifyDataSetChanged(); - if (episodes.size() == 0) { createRecycleAdapter(recyclerView, emptyView); + } else { + listAdapter.updateItems(episodes); } restoreScrollPosition(); @@ -360,40 +358,13 @@ public abstract class EpisodesListFragment extends Fragment { */ private void createRecycleAdapter(RecyclerView recyclerView, EmptyViewHandler emptyViewHandler) { MainActivity mainActivity = (MainActivity) getActivity(); - listAdapter = new AllEpisodesRecycleAdapter(mainActivity, itemAccess); + 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 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 + "]"); @@ -432,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 downloaderList = update.downloaders; if (isMenuInvalidationAllowed && event.hasChangedFeedUpdateStatus(isUpdatingFeeds)) { requireActivity().invalidateOptionsMenu(); } From df99d684b715327aa58cd733baaaa521174ac5e9 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Wed, 5 Feb 2020 16:17:51 +0100 Subject: [PATCH 11/24] Hide images on podcast details screen --- .../adapter/FeedItemlistAdapter.java | 9 +++++++-- .../fragment/FeedItemlistFragment.java | 11 +---------- .../view/EpisodeItemViewHolder.java | 19 ++++++++++++------- app/src/main/res/layout/feeditemlist_item.xml | 7 ++++--- 4 files changed, 24 insertions(+), 22 deletions(-) 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 f2fbe0770..87bd3aa5e 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java @@ -16,18 +16,19 @@ public class FeedItemlistAdapter extends BaseAdapter { private final ItemAccess itemAccess; private final MainActivity activity; - /** true if played items should be made partially transparent */ private final boolean makePlayedItemsTransparent; + private final boolean showIcons; private int currentlyPlayingItem = -1; public FeedItemlistAdapter(MainActivity activity, ItemAccess itemAccess, - boolean showFeedtitle, + boolean showIcons, boolean makePlayedItemsTransparent) { super(); this.activity = activity; this.itemAccess = itemAccess; + this.showIcons = showIcons; this.makePlayedItemsTransparent = makePlayedItemsTransparent; } @@ -56,6 +57,10 @@ public class FeedItemlistAdapter extends BaseAdapter { holder = (EpisodeItemViewHolder) convertView.getTag(); } + if (!showIcons) { + holder.coverHolder.setVisibility(View.GONE); + } + final FeedItem item = getItem(position); holder.bind(item); holder.dragHandle.setVisibility(View.GONE); 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 123b0d1a2..5d3c811f5 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 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(); } diff --git a/app/src/main/java/de/danoeh/antennapod/view/EpisodeItemViewHolder.java b/app/src/main/java/de/danoeh/antennapod/view/EpisodeItemViewHolder.java index d9aa92717..968bd71a9 100644 --- a/app/src/main/java/de/danoeh/antennapod/view/EpisodeItemViewHolder.java +++ b/app/src/main/java/de/danoeh/antennapod/view/EpisodeItemViewHolder.java @@ -10,6 +10,7 @@ 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; @@ -54,9 +55,10 @@ public class EpisodeItemViewHolder extends RecyclerView.ViewHolder public final View secondaryActionButton; public final ImageView secondaryActionIcon; private final CircularProgressBar secondaryActionProgress; - private final MainActivity activity; private final TextView separatorIcons; + public final RelativeLayout coverHolder; + private final MainActivity activity; private FeedItem item; public EpisodeItemViewHolder(MainActivity activity, ViewGroup parent) { @@ -83,6 +85,7 @@ public class EpisodeItemViewHolder extends RecyclerView.ViewHolder 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); } @@ -117,12 +120,14 @@ public class EpisodeItemViewHolder extends RecyclerView.ViewHolder secondaryActionProgress.setPercentage(0, item); } - new CoverLoader(activity) - .withUri(ImageResourceUtils.getImageLocation(item)) - .withFallbackUri(item.getFeed().getImageLocation()) - .withPlaceholderView(placeholder) - .withCoverView(cover) - .load(); + 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) { diff --git a/app/src/main/res/layout/feeditemlist_item.xml b/app/src/main/res/layout/feeditemlist_item.xml index cd983ffca..af8323567 100644 --- a/app/src/main/res/layout/feeditemlist_item.xml +++ b/app/src/main/res/layout/feeditemlist_item.xml @@ -30,7 +30,10 @@ 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_marginTop="@dimen/listitem_threeline_verticalpadding" + android:layout_marginRight="@dimen/listitem_threeline_textleftpadding" + android:layout_marginEnd="@dimen/listitem_threeline_textleftpadding" + android:id="@+id/coverHolder"> Date: Wed, 5 Feb 2020 16:43:41 +0100 Subject: [PATCH 12/24] Made a bit more space --- app/src/main/res/layout/feeditemlist_item.xml | 2 +- app/src/main/res/layout/secondary_action.xml | 4 ++-- core/src/main/res/values/dimens.xml | 2 +- core/src/main/res/values/styles.xml | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/main/res/layout/feeditemlist_item.xml b/app/src/main/res/layout/feeditemlist_item.xml index af8323567..c919fc4b4 100644 --- a/app/src/main/res/layout/feeditemlist_item.xml +++ b/app/src/main/res/layout/feeditemlist_item.xml @@ -42,7 +42,7 @@ android:layout_centerVertical="true" android:gravity="center" android:background="@color/light_gray" - android:maxLines="3" + android:maxLines="2" android:ellipsize="end"/> 16dp 8dp - 16dp + 8dp 16dp 8dp diff --git a/core/src/main/res/values/styles.xml b/core/src/main/res/values/styles.xml index d341048ff..c7f45a29e 100644 --- a/core/src/main/res/values/styles.xml +++ b/core/src/main/res/values/styles.xml @@ -285,7 +285,7 @@ From 164581c598af91f8487ddba195e73942f6e0912c Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Wed, 5 Feb 2020 17:00:54 +0100 Subject: [PATCH 13/24] Allow to drag images like before --- .../adapter/QueueRecyclerAdapter.java | 30 ++++++++++++------- .../view/EpisodeItemViewHolder.java | 2 +- app/src/main/res/layout/feeditemlist_item.xml | 2 +- 3 files changed, 22 insertions(+), 12 deletions(-) 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 d629df4fa..883335b01 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java @@ -1,5 +1,6 @@ package de.danoeh.antennapod.adapter; +import android.annotation.SuppressLint; import android.util.Log; import android.view.ContextMenu; import android.view.MenuInflater; @@ -54,19 +55,12 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter { - if (MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN) { - Log.d(TAG, "startDrag()"); - itemTouchHelper.startDrag(viewHolder); - } - return false; - }); - return viewHolder; + public EpisodeItemViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + return new EpisodeItemViewHolder(mainActivity.get(), parent); } @Override + @SuppressLint("ClickableViewAccessibility") public void onBindViewHolder(EpisodeItemViewHolder holder, int pos) { FeedItem item = itemAccess.getItem(pos); holder.bind(item); @@ -83,6 +77,22 @@ public class QueueRecyclerAdapter extends RecyclerView.Adapter { + if (MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN) { + Log.d(TAG, "startDrag()"); + itemTouchHelper.startDrag(holder); + } + return false; + }; + if (!locked) { + holder.dragHandle.setOnTouchListener(startDragTouchListener); + holder.coverHolder.setOnTouchListener(startDragTouchListener); + } else { + holder.dragHandle.setOnTouchListener(null); + holder.coverHolder.setOnTouchListener(null); + } + holder.itemView.setOnCreateContextMenuListener(this); holder.isInQueue.setVisibility(View.GONE); holder.hideSeparatorIfNecessary(); diff --git a/app/src/main/java/de/danoeh/antennapod/view/EpisodeItemViewHolder.java b/app/src/main/java/de/danoeh/antennapod/view/EpisodeItemViewHolder.java index 968bd71a9..8e722a4c1 100644 --- a/app/src/main/java/de/danoeh/antennapod/view/EpisodeItemViewHolder.java +++ b/app/src/main/java/de/danoeh/antennapod/view/EpisodeItemViewHolder.java @@ -110,7 +110,7 @@ public class EpisodeItemViewHolder extends RecyclerView.ViewHolder 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); + ItemActionButton actionButton = ItemActionButton.forItem(item, true, true); actionButton.configure(secondaryActionButton, secondaryActionIcon, activity); secondaryActionButton.setFocusable(false); diff --git a/app/src/main/res/layout/feeditemlist_item.xml b/app/src/main/res/layout/feeditemlist_item.xml index c919fc4b4..bf8dca0cc 100644 --- a/app/src/main/res/layout/feeditemlist_item.xml +++ b/app/src/main/res/layout/feeditemlist_item.xml @@ -100,7 +100,7 @@ android:layout_width="20dp" android:layout_height="20dp" app:srcCompat="?attr/stat_playlist" - tools:srcCompat="@drawable/ic_playlist_grey_24dp" + tools:srcCompat="@drawable/ic_list_grey600_24dp" android:id="@+id/ivInPlaylist"/> Date: Wed, 5 Feb 2020 17:14:37 +0100 Subject: [PATCH 14/24] Rounded covers --- .../view/EpisodeItemViewHolder.java | 3 +- app/src/main/res/layout/feeditemlist_item.xml | 46 +++++++++++-------- 2 files changed, 29 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/de/danoeh/antennapod/view/EpisodeItemViewHolder.java b/app/src/main/java/de/danoeh/antennapod/view/EpisodeItemViewHolder.java index 8e722a4c1..038f8b6d3 100644 --- a/app/src/main/java/de/danoeh/antennapod/view/EpisodeItemViewHolder.java +++ b/app/src/main/java/de/danoeh/antennapod/view/EpisodeItemViewHolder.java @@ -12,6 +12,7 @@ import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.RelativeLayout; import android.widget.TextView; +import androidx.cardview.widget.CardView; import androidx.recyclerview.widget.RecyclerView; import com.joanzapata.iconify.Iconify; import de.danoeh.antennapod.R; @@ -56,7 +57,7 @@ public class EpisodeItemViewHolder extends RecyclerView.ViewHolder public final ImageView secondaryActionIcon; private final CircularProgressBar secondaryActionProgress; private final TextView separatorIcons; - public final RelativeLayout coverHolder; + public final CardView coverHolder; private final MainActivity activity; private FeedItem item; diff --git a/app/src/main/res/layout/feeditemlist_item.xml b/app/src/main/res/layout/feeditemlist_item.xml index bf8dca0cc..38ba73c36 100644 --- a/app/src/main/res/layout/feeditemlist_item.xml +++ b/app/src/main/res/layout/feeditemlist_item.xml @@ -22,37 +22,45 @@ android:scaleType="center" android:src="?attr/dragview_background" tools:src="@drawable/ic_drag_vertical_grey600_48dp" - tools:background="@android:color/holo_green_dark" /> + tools:background="@android:color/holo_green_dark"/> - + android:id="@+id/coverHolder" + app:cardCornerRadius="4dp" + app:cardElevation="0dp"> - - + android:layout_height="@dimen/thumbnail_length_queue_item"> - + + + + + Date: Wed, 5 Feb 2020 17:23:22 +0100 Subject: [PATCH 15/24] Honor makePlayedItemsTransparent flag --- .../de/danoeh/antennapod/adapter/FeedItemlistAdapter.java | 4 ++++ 1 file changed, 4 insertions(+) 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 87bd3aa5e..295edaf51 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java @@ -65,6 +65,10 @@ public class FeedItemlistAdapter extends BaseAdapter { holder.bind(item); holder.dragHandle.setVisibility(View.GONE); + if (!makePlayedItemsTransparent) { + holder.itemView.setAlpha(1.0f); + } + if (item.getMedia() != null && item.getMedia().isCurrentlyPlaying()) { currentlyPlayingItem = position; } From a80bf2265a8c120a6865effd75bd2ddb6d513968 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Wed, 5 Feb 2020 17:53:25 +0100 Subject: [PATCH 16/24] Moved ViewHolder class --- .../adapter/AllEpisodesRecycleAdapter.java | 2 +- .../DownloadedEpisodesListAdapter.java | 2 +- .../adapter/FeedItemlistAdapter.java | 2 +- .../adapter/QueueRecyclerAdapter.java | 2 +- .../fragment/EpisodesListFragment.java | 5 +- .../fragment/FavoriteEpisodesFragment.java | 3 +- .../fragment/NewEpisodesFragment.java | 2 +- .../antennapod/fragment/QueueFragment.java | 5 +- .../EpisodeItemViewHolder.java | 8 +- .../viewholder/FeedComponentViewHolder.java | 15 +++ .../view/viewholder/FeedViewHolder.java | 93 +++++++++++++++++++ .../main/res/layout/all_episodes_fragment.xml | 2 +- 12 files changed, 121 insertions(+), 20 deletions(-) rename app/src/main/java/de/danoeh/antennapod/view/{ => viewholder}/EpisodeItemViewHolder.java (97%) create mode 100644 app/src/main/java/de/danoeh/antennapod/view/viewholder/FeedComponentViewHolder.java create mode 100644 app/src/main/java/de/danoeh/antennapod/view/viewholder/FeedViewHolder.java 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 c9b8e5ab2..71c872de2 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/AllEpisodesRecycleAdapter.java @@ -14,7 +14,7 @@ import de.danoeh.antennapod.core.feed.FeedItem; 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 de.danoeh.antennapod.view.viewholder.EpisodeItemViewHolder; import org.apache.commons.lang3.ArrayUtils; import java.lang.ref.WeakReference; 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 37d570e26..81aa2655a 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/DownloadedEpisodesListAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/DownloadedEpisodesListAdapter.java @@ -6,7 +6,7 @@ import android.widget.BaseAdapter; import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.MainActivity; import de.danoeh.antennapod.core.feed.FeedItem; -import de.danoeh.antennapod.view.EpisodeItemViewHolder; +import de.danoeh.antennapod.view.viewholder.EpisodeItemViewHolder; /** * Shows a list of downloaded episodes. 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 295edaf51..9e7778c12 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java @@ -7,7 +7,7 @@ import android.widget.ListView; import de.danoeh.antennapod.activity.MainActivity; import de.danoeh.antennapod.core.event.PlaybackPositionEvent; import de.danoeh.antennapod.core.feed.FeedItem; -import de.danoeh.antennapod.view.EpisodeItemViewHolder; +import de.danoeh.antennapod.view.viewholder.EpisodeItemViewHolder; /** * List adapter for items of feeds that the user has already subscribed to. 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 883335b01..456f45fd2 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/QueueRecyclerAdapter.java @@ -19,7 +19,7 @@ import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.core.util.LongList; import de.danoeh.antennapod.fragment.ItemPagerFragment; import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler; -import de.danoeh.antennapod.view.EpisodeItemViewHolder; +import de.danoeh.antennapod.view.viewholder.EpisodeItemViewHolder; import org.apache.commons.lang3.ArrayUtils; import java.lang.ref.WeakReference; 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 9a353e05a..6176ca410 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java @@ -28,7 +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 de.danoeh.antennapod.view.viewholder.EpisodeItemViewHolder; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; @@ -44,14 +44,11 @@ import de.danoeh.antennapod.core.event.DownloadEvent; import de.danoeh.antennapod.core.event.DownloaderUpdate; import de.danoeh.antennapod.core.event.FeedItemEvent; import de.danoeh.antennapod.core.feed.FeedItem; -import de.danoeh.antennapod.core.feed.FeedMedia; -import de.danoeh.antennapod.core.service.download.DownloadRequest; import de.danoeh.antennapod.core.service.download.DownloadService; import de.danoeh.antennapod.core.service.download.Downloader; import de.danoeh.antennapod.core.storage.DBWriter; import de.danoeh.antennapod.core.storage.DownloadRequester; import de.danoeh.antennapod.core.util.FeedItemUtil; -import de.danoeh.antennapod.core.util.LongList; import de.danoeh.antennapod.core.util.download.AutoUpdateManager; import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler; import de.danoeh.antennapod.menuhandler.MenuItemUtils; 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 70150a915..4953ccc6c 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/FavoriteEpisodesFragment.java @@ -10,13 +10,12 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import de.danoeh.antennapod.view.EpisodeItemViewHolder; +import de.danoeh.antennapod.view.viewholder.EpisodeItemViewHolder; import org.greenrobot.eventbus.Subscribe; import java.util.List; import de.danoeh.antennapod.R; -import de.danoeh.antennapod.adapter.AllEpisodesRecycleAdapter; import de.danoeh.antennapod.core.event.FavoritesEvent; import de.danoeh.antennapod.core.feed.FeedItem; import de.danoeh.antennapod.core.storage.DBReader; 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 21e2800e6..33e686a90 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/NewEpisodesFragment.java @@ -16,7 +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; +import de.danoeh.antennapod.view.viewholder.EpisodeItemViewHolder; /** * Like 'EpisodesFragment' except that it only shows new episodes and 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 48df5ab32..36c837a25 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java @@ -27,7 +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 de.danoeh.antennapod.view.viewholder.EpisodeItemViewHolder; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; @@ -46,11 +46,9 @@ import de.danoeh.antennapod.core.event.PlayerStatusEvent; import de.danoeh.antennapod.core.event.UnreadItemsUpdateEvent; import de.danoeh.antennapod.core.event.QueueEvent; import de.danoeh.antennapod.core.feed.FeedItem; -import de.danoeh.antennapod.core.feed.FeedMedia; import de.danoeh.antennapod.core.feed.util.PlaybackSpeedUtils; import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.core.service.download.DownloadService; -import de.danoeh.antennapod.core.service.download.Downloader; import de.danoeh.antennapod.core.storage.DBReader; import de.danoeh.antennapod.core.storage.DBWriter; import de.danoeh.antennapod.core.storage.DownloadRequester; @@ -509,7 +507,6 @@ public class QueueFragment extends Fragment { layoutManager = new LinearLayoutManager(getActivity()); recyclerView.setLayoutManager(layoutManager); recyclerView.addItemDecoration(new HorizontalDividerItemDecoration.Builder(getActivity()).build()); - recyclerView.setHasFixedSize(true); registerForContextMenu(recyclerView); itemTouchHelper = new ItemTouchHelper( diff --git a/app/src/main/java/de/danoeh/antennapod/view/EpisodeItemViewHolder.java b/app/src/main/java/de/danoeh/antennapod/view/viewholder/EpisodeItemViewHolder.java similarity index 97% rename from app/src/main/java/de/danoeh/antennapod/view/EpisodeItemViewHolder.java rename to app/src/main/java/de/danoeh/antennapod/view/viewholder/EpisodeItemViewHolder.java index 038f8b6d3..369574190 100644 --- a/app/src/main/java/de/danoeh/antennapod/view/EpisodeItemViewHolder.java +++ b/app/src/main/java/de/danoeh/antennapod/view/viewholder/EpisodeItemViewHolder.java @@ -1,4 +1,4 @@ -package de.danoeh.antennapod.view; +package de.danoeh.antennapod.view.viewholder; import android.graphics.Color; import android.os.Build; @@ -31,11 +31,12 @@ 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; +import de.danoeh.antennapod.view.CircularProgressBar; /** * Holds the view which shows FeedItems. */ -public class EpisodeItemViewHolder extends RecyclerView.ViewHolder +public class EpisodeItemViewHolder extends FeedComponentViewHolder implements QueueRecyclerAdapter.ItemTouchHelperViewHolder { private static final String TAG = "EpisodeItemViewHolder"; @@ -104,12 +105,11 @@ public class EpisodeItemViewHolder extends RecyclerView.ViewHolder 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); + itemView.setAlpha(item.isPlayed() ? 0.5f : 1.0f); ItemActionButton actionButton = ItemActionButton.forItem(item, true, true); actionButton.configure(secondaryActionButton, secondaryActionIcon, activity); diff --git a/app/src/main/java/de/danoeh/antennapod/view/viewholder/FeedComponentViewHolder.java b/app/src/main/java/de/danoeh/antennapod/view/viewholder/FeedComponentViewHolder.java new file mode 100644 index 000000000..f55ea9bc8 --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/view/viewholder/FeedComponentViewHolder.java @@ -0,0 +1,15 @@ +package de.danoeh.antennapod.view.viewholder; + +import android.view.View; +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +/** + * Holds the view which shows FeedComponents. + */ +public class FeedComponentViewHolder extends RecyclerView.ViewHolder { + + public FeedComponentViewHolder(@NonNull View itemView) { + super(itemView); + } +} diff --git a/app/src/main/java/de/danoeh/antennapod/view/viewholder/FeedViewHolder.java b/app/src/main/java/de/danoeh/antennapod/view/viewholder/FeedViewHolder.java new file mode 100644 index 000000000..39d428a6e --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/view/viewholder/FeedViewHolder.java @@ -0,0 +1,93 @@ +package de.danoeh.antennapod.view.viewholder; + +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.ImageView; +import android.widget.ProgressBar; +import android.widget.TextView; +import androidx.cardview.widget.CardView; +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.Feed; +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; +import de.danoeh.antennapod.view.CircularProgressBar; + +/** + * Holds the view which shows feeds. + */ +public class FeedViewHolder extends FeedComponentViewHolder { + private static final String TAG = "FeedViewHolder"; + + private final View container; + public final ImageView dragHandle; + private final TextView placeholder; + private final ImageView cover; + private final TextView title; + public final View secondaryActionButton; + public final ImageView secondaryActionIcon; + private final CircularProgressBar secondaryActionProgress; + public final CardView coverHolder; + + private final MainActivity activity; + private Feed feed; + + public FeedViewHolder(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); + } + + itemView.findViewById(R.id.status).setVisibility(View.GONE); + itemView.findViewById(R.id.progress).setVisibility(View.GONE); + 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); + } + + public void bind(Feed feed) { + this.feed = feed; + placeholder.setText(feed.getTitle()); + title.setText(feed.getTitle()); + + /*ItemActionButton actionButton = ItemActionButton.forItem(item, true, true); + actionButton.configure(secondaryActionButton, secondaryActionIcon, activity); + secondaryActionButton.setFocusable(false); + secondaryActionProgress.setPercentage(0, null);*/ + + if (coverHolder.getVisibility() == View.VISIBLE) { + new CoverLoader(activity) + .withUri(feed.getImageLocation()) + .withPlaceholderView(placeholder) + .withCoverView(cover) + .load(); + } + } + +} diff --git a/app/src/main/res/layout/all_episodes_fragment.xml b/app/src/main/res/layout/all_episodes_fragment.xml index 784e7a1c8..2ccfe2494 100644 --- a/app/src/main/res/layout/all_episodes_fragment.xml +++ b/app/src/main/res/layout/all_episodes_fragment.xml @@ -34,7 +34,7 @@ app:fastScrollVerticalThumbDrawable="@drawable/thumb_drawable" app:fastScrollVerticalTrackDrawable="@drawable/line_drawable" tools:itemCount="13" - tools:listitem="@layout/new_episodes_listitem" /> + tools:listitem="@layout/feeditemlist_item" /> Date: Wed, 5 Feb 2020 18:18:10 +0100 Subject: [PATCH 17/24] Using unified item view in search fragment --- .../adapter/FeedItemlistAdapter.java | 44 +++++-- .../antennapod/adapter/SearchlistAdapter.java | 123 ------------------ .../fragment/FeedItemlistFragment.java | 6 +- .../antennapod/fragment/SearchFragment.java | 12 +- .../view/viewholder/FeedViewHolder.java | 37 +----- app/src/main/res/layout/search_fragment.xml | 5 +- .../antennapod/core/storage/FeedSearcher.java | 9 +- 7 files changed, 53 insertions(+), 183 deletions(-) delete mode 100644 app/src/main/java/de/danoeh/antennapod/adapter/SearchlistAdapter.java 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 9e7778c12..a5cfcb3e7 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java @@ -6,8 +6,12 @@ import android.widget.BaseAdapter; import android.widget.ListView; import de.danoeh.antennapod.activity.MainActivity; import de.danoeh.antennapod.core.event.PlaybackPositionEvent; +import de.danoeh.antennapod.core.feed.Feed; +import de.danoeh.antennapod.core.feed.FeedComponent; import de.danoeh.antennapod.core.feed.FeedItem; import de.danoeh.antennapod.view.viewholder.EpisodeItemViewHolder; +import de.danoeh.antennapod.view.viewholder.FeedComponentViewHolder; +import de.danoeh.antennapod.view.viewholder.FeedViewHolder; /** * List adapter for items of feeds that the user has already subscribed to. @@ -21,10 +25,8 @@ public class FeedItemlistAdapter extends BaseAdapter { private int currentlyPlayingItem = -1; - public FeedItemlistAdapter(MainActivity activity, - ItemAccess itemAccess, - boolean showIcons, - boolean makePlayedItemsTransparent) { + public FeedItemlistAdapter(MainActivity activity, ItemAccess itemAccess, + boolean showIcons, boolean makePlayedItemsTransparent) { super(); this.activity = activity; this.itemAccess = itemAccess; @@ -44,14 +46,38 @@ public class FeedItemlistAdapter extends BaseAdapter { } @Override - public FeedItem getItem(int position) { + public FeedComponent getItem(int position) { return itemAccess.getItem(position); } @Override public View getView(final int position, View convertView, ViewGroup parent) { + final FeedComponent item = getItem(position); + if (item instanceof Feed) { + return getView((Feed) item, convertView, parent); + } else { + final FeedItem feeditem = (FeedItem) item; + if (feeditem.getMedia() != null && feeditem.getMedia().isCurrentlyPlaying()) { + currentlyPlayingItem = position; + } + return getView(feeditem, convertView, parent); + } + } + + private View getView(Feed item, View convertView, ViewGroup parent) { + FeedViewHolder holder; + if (convertView == null || !(convertView.getTag() instanceof FeedViewHolder)) { + holder = new FeedViewHolder(activity, parent); + } else { + holder = (FeedViewHolder) convertView.getTag(); + } + holder.bind(item); + return holder.itemView; + } + + private View getView(final FeedItem item, View convertView, ViewGroup parent) { EpisodeItemViewHolder holder; - if (convertView == null) { + if (convertView == null || !(convertView.getTag() instanceof EpisodeItemViewHolder)) { holder = new EpisodeItemViewHolder(activity, parent); } else { holder = (EpisodeItemViewHolder) convertView.getTag(); @@ -61,7 +87,6 @@ public class FeedItemlistAdapter extends BaseAdapter { holder.coverHolder.setVisibility(View.GONE); } - final FeedItem item = getItem(position); holder.bind(item); holder.dragHandle.setVisibility(View.GONE); @@ -69,9 +94,6 @@ public class FeedItemlistAdapter extends BaseAdapter { holder.itemView.setAlpha(1.0f); } - if (item.getMedia() != null && item.getMedia().isCurrentlyPlaying()) { - currentlyPlayingItem = position; - } holder.hideSeparatorIfNecessary(); return holder.itemView; } @@ -91,7 +113,7 @@ public class FeedItemlistAdapter extends BaseAdapter { public interface ItemAccess { int getCount(); - FeedItem getItem(int position); + FeedComponent getItem(int position); } } diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/SearchlistAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/SearchlistAdapter.java deleted file mode 100644 index d1615b410..000000000 --- a/app/src/main/java/de/danoeh/antennapod/adapter/SearchlistAdapter.java +++ /dev/null @@ -1,123 +0,0 @@ -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.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.core.feed.Feed; -import de.danoeh.antennapod.core.feed.FeedComponent; -import de.danoeh.antennapod.core.feed.FeedItem; -import de.danoeh.antennapod.core.glide.ApGlideSettings; - -/** - * List adapter for search activity. - */ -public class SearchlistAdapter extends BaseAdapter { - - private final Context context; - private final ItemAccess itemAccess; - - - public SearchlistAdapter(Context context, ItemAccess itemAccess) { - this.context = context; - this.itemAccess = itemAccess; - } - - @Override - public int getCount() { - return itemAccess.getCount(); - } - - @Override - public FeedComponent getItem(int position) { - return itemAccess.getItem(position); - } - - @Override - public long getItemId(int position) { - return 0; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - final Holder holder; - FeedComponent component = getItem(position); - - // Inflate Layout - if (convertView == null) { - holder = new Holder(); - LayoutInflater inflater = (LayoutInflater) context - .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - - convertView = inflater.inflate(R.layout.searchlist_item, parent, false); - holder.title = convertView.findViewById(R.id.txtvTitle); - if(Build.VERSION.SDK_INT >= 23) { - holder.title.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_FULL); - } - holder.cover = convertView - .findViewById(R.id.imgvFeedimage); - holder.subtitle = convertView - .findViewById(R.id.txtvSubtitle); - - convertView.setTag(holder); - } else { - holder = (Holder) convertView.getTag(); - } - if (component.getClass() == Feed.class) { - final Feed feed = (Feed) component; - holder.title.setText(feed.getTitle()); - holder.subtitle.setVisibility(View.GONE); - - Glide.with(context) - .load(feed.getImageLocation()) - .apply(new RequestOptions() - .placeholder(R.color.light_gray) - .error(R.color.light_gray) - .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY) - .fitCenter() - .dontAnimate()) - .into(holder.cover); - - } else if (component.getClass() == FeedItem.class) { - final FeedItem item = (FeedItem) component; - holder.title.setText(item.getTitle()); - holder.subtitle.setVisibility(View.VISIBLE); - - convertView.setAlpha(item.isPlayed() ? 0.5f : 1.0f); - - Glide.with(context) - .load(item.getFeed().getImageLocation()) - .apply(new RequestOptions() - .placeholder(R.color.light_gray) - .error(R.color.light_gray) - .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY) - .fitCenter() - .dontAnimate()) - .into(holder.cover); - - } - - return convertView; - } - - static class Holder { - ImageView cover; - TextView title; - TextView subtitle; - } - - public interface ItemAccess { - int getCount(); - - FeedComponent getItem(int position); - } - -} 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 16787a1c5..b9afa6d57 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java @@ -289,7 +289,7 @@ public class FeedItemlistFragment extends ListFragment { AdapterView.AdapterContextMenuInfo adapterInfo = (AdapterView.AdapterContextMenuInfo) menuInfo; // because of addHeaderView(), positions are increased by 1! - FeedItem item = itemAccess.getItem(adapterInfo.position-1); + FeedItem item = (FeedItem) itemAccess.getItem(adapterInfo.position - 1); MenuInflater inflater = getActivity().getMenuInflater(); inflater.inflate(R.menu.feeditemlist_context, menu); @@ -305,11 +305,11 @@ public class FeedItemlistFragment extends ListFragment { @Override public boolean onContextItemSelected(MenuItem item) { AdapterView.AdapterContextMenuInfo menuInfo = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo(); - if(menuInfo == null) { + if (menuInfo == null) { menuInfo = lastMenuInfo; } // because of addHeaderView(), positions are increased by 1! - FeedItem selectedItem = itemAccess.getItem(menuInfo.position-1); + FeedItem selectedItem = feed.getItemAtIndex(menuInfo.position - 1); if (selectedItem == null) { Log.i(TAG, "Selected item at position " + menuInfo.position + " was null, ignoring selection"); diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java index c640554ff..6a698ecce 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java @@ -20,11 +20,12 @@ import androidx.core.view.MenuItemCompat; import androidx.fragment.app.Fragment; import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.MainActivity; -import de.danoeh.antennapod.adapter.SearchlistAdapter; +import de.danoeh.antennapod.adapter.FeedItemlistAdapter; import de.danoeh.antennapod.core.event.UnreadItemsUpdateEvent; import de.danoeh.antennapod.core.feed.Feed; import de.danoeh.antennapod.core.feed.FeedComponent; import de.danoeh.antennapod.core.feed.FeedItem; +import de.danoeh.antennapod.core.storage.DBTasks; import de.danoeh.antennapod.core.storage.FeedSearcher; import de.danoeh.antennapod.view.EmptyViewHandler; import io.reactivex.Observable; @@ -33,6 +34,9 @@ import io.reactivex.disposables.Disposable; import io.reactivex.schedulers.Schedulers; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.FutureTask; + import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; @@ -45,7 +49,7 @@ public class SearchFragment extends Fragment implements AdapterView.OnItemClickL private static final String ARG_QUERY = "query"; private static final String ARG_FEED = "feed"; - private SearchlistAdapter searchAdapter; + private FeedItemlistAdapter searchAdapter; private List searchResults = new ArrayList<>(); private Disposable disposable; private ProgressBar progressBar; @@ -105,7 +109,7 @@ public class SearchFragment extends Fragment implements AdapterView.OnItemClickL View layout = inflater.inflate(R.layout.search_fragment, container, false); ListView listView = layout.findViewById(R.id.listview); progressBar = layout.findViewById(R.id.progressBar); - searchAdapter = new SearchlistAdapter(getActivity(), itemAccess); + searchAdapter = new FeedItemlistAdapter((MainActivity) getActivity(), itemAccess, true, true); listView.setAdapter(searchAdapter); listView.setOnItemClickListener(this); @@ -172,7 +176,7 @@ public class SearchFragment extends Fragment implements AdapterView.OnItemClickL emptyViewHandler.setMessage(getString(R.string.no_results_for_query, query)); } - private final SearchlistAdapter.ItemAccess itemAccess = new SearchlistAdapter.ItemAccess() { + private final FeedItemlistAdapter.ItemAccess itemAccess = new FeedItemlistAdapter.ItemAccess() { @Override public int getCount() { return searchResults.size(); diff --git a/app/src/main/java/de/danoeh/antennapod/view/viewholder/FeedViewHolder.java b/app/src/main/java/de/danoeh/antennapod/view/viewholder/FeedViewHolder.java index 39d428a6e..83250bbfa 100644 --- a/app/src/main/java/de/danoeh/antennapod/view/viewholder/FeedViewHolder.java +++ b/app/src/main/java/de/danoeh/antennapod/view/viewholder/FeedViewHolder.java @@ -2,34 +2,16 @@ package de.danoeh.antennapod.view.viewholder; 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.ImageView; -import android.widget.ProgressBar; import android.widget.TextView; import androidx.cardview.widget.CardView; -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.Feed; -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; -import de.danoeh.antennapod.view.CircularProgressBar; /** * Holds the view which shows feeds. @@ -37,14 +19,9 @@ import de.danoeh.antennapod.view.CircularProgressBar; public class FeedViewHolder extends FeedComponentViewHolder { private static final String TAG = "FeedViewHolder"; - private final View container; - public final ImageView dragHandle; private final TextView placeholder; private final ImageView cover; private final TextView title; - public final View secondaryActionButton; - public final ImageView secondaryActionIcon; - private final CircularProgressBar secondaryActionProgress; public final CardView coverHolder; private final MainActivity activity; @@ -53,21 +30,18 @@ public class FeedViewHolder extends FeedComponentViewHolder { public FeedViewHolder(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); + coverHolder = itemView.findViewById(R.id.coverHolder); title = itemView.findViewById(R.id.txtvTitle); if (Build.VERSION.SDK_INT >= 23) { title.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_FULL); } + itemView.findViewById(R.id.secondaryActionButton).setVisibility(View.GONE); itemView.findViewById(R.id.status).setVisibility(View.GONE); itemView.findViewById(R.id.progress).setVisibility(View.GONE); - 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.findViewById(R.id.drag_handle).setVisibility(View.GONE); itemView.setTag(this); } @@ -76,11 +50,6 @@ public class FeedViewHolder extends FeedComponentViewHolder { placeholder.setText(feed.getTitle()); title.setText(feed.getTitle()); - /*ItemActionButton actionButton = ItemActionButton.forItem(item, true, true); - actionButton.configure(secondaryActionButton, secondaryActionIcon, activity); - secondaryActionButton.setFocusable(false); - secondaryActionProgress.setPercentage(0, null);*/ - if (coverHolder.getVisibility() == View.VISIBLE) { new CoverLoader(activity) .withUri(feed.getImageLocation()) diff --git a/app/src/main/res/layout/search_fragment.xml b/app/src/main/res/layout/search_fragment.xml index 6f455a056..489c2d392 100644 --- a/app/src/main/res/layout/search_fragment.xml +++ b/app/src/main/res/layout/search_fragment.xml @@ -13,8 +13,5 @@ + android:layout_height="match_parent" /> \ No newline at end of file diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/FeedSearcher.java b/core/src/main/java/de/danoeh/antennapod/core/storage/FeedSearcher.java index bbe8b26f1..77c8d3b7f 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/FeedSearcher.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/FeedSearcher.java @@ -35,11 +35,12 @@ public class FeedSearcher { final List result = new ArrayList<>(); try { FutureTask> itemSearchTask = DBTasks.searchFeedItems(context, selectedFeed, query); - FutureTask> feedSearchTask = DBTasks.searchFeeds(context, query); itemSearchTask.run(); - feedSearchTask.run(); - - result.addAll(feedSearchTask.get()); + if (selectedFeed == 0) { + FutureTask> feedSearchTask = DBTasks.searchFeeds(context, query); + feedSearchTask.run(); + result.addAll(feedSearchTask.get()); + } result.addAll(itemSearchTask.get()); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); From dd53a6ed94d56f099a13e48b30ad8e90c587ec68 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Wed, 5 Feb 2020 18:33:36 +0100 Subject: [PATCH 18/24] Make lists react to events --- .../fragment/PlaybackHistoryFragment.java | 2 +- .../danoeh/antennapod/fragment/SearchFragment.java | 13 ++++++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) 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 63a2fc657..923a6325c 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java @@ -93,7 +93,7 @@ public class PlaybackHistoryFragment extends ListFragment { } } - @Subscribe(sticky = true) + @Subscribe(sticky = true, threadMode = ThreadMode.MAIN) public void onEvent(DownloadEvent event) { Log.d(TAG, "onEvent() called with: " + "event = [" + event + "]"); DownloaderUpdate update = event.update; diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java index 6a698ecce..7d284835d 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/SearchFragment.java @@ -21,11 +21,11 @@ import androidx.fragment.app.Fragment; import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.MainActivity; import de.danoeh.antennapod.adapter.FeedItemlistAdapter; +import de.danoeh.antennapod.core.event.DownloadEvent; import de.danoeh.antennapod.core.event.UnreadItemsUpdateEvent; import de.danoeh.antennapod.core.feed.Feed; import de.danoeh.antennapod.core.feed.FeedComponent; import de.danoeh.antennapod.core.feed.FeedItem; -import de.danoeh.antennapod.core.storage.DBTasks; import de.danoeh.antennapod.core.storage.FeedSearcher; import de.danoeh.antennapod.view.EmptyViewHandler; import io.reactivex.Observable; @@ -34,11 +34,10 @@ import io.reactivex.disposables.Disposable; import io.reactivex.schedulers.Schedulers; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.FutureTask; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; /** * Performs a search operation on all feeds or one specific feed and displays the search result. @@ -168,6 +167,14 @@ public class SearchFragment extends Fragment implements AdapterView.OnItemClickL search(); } + @Subscribe(sticky = true, threadMode = ThreadMode.MAIN) + public void onEventMainThread(DownloadEvent event) { + Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]"); + if (searchAdapter != null) { + searchAdapter.notifyDataSetChanged(); + } + } + private void onSearchResults(List results) { progressBar.setVisibility(View.GONE); searchResults = results; From d83549431d911b0c0f54791c17a465f277dd8ddf Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Thu, 6 Feb 2020 11:21:52 +0100 Subject: [PATCH 19/24] Respect theme in downloaded list --- .../antennapod/adapter/DownloadedEpisodesListAdapter.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 81aa2655a..307dabf14 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/DownloadedEpisodesListAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/DownloadedEpisodesListAdapter.java @@ -6,6 +6,7 @@ import android.widget.BaseAdapter; import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.MainActivity; import de.danoeh.antennapod.core.feed.FeedItem; +import de.danoeh.antennapod.core.util.ThemeUtils; import de.danoeh.antennapod.view.viewholder.EpisodeItemViewHolder; /** @@ -49,7 +50,7 @@ public class DownloadedEpisodesListAdapter extends BaseAdapter { final FeedItem item = getItem(position); holder.bind(item); holder.dragHandle.setVisibility(View.GONE); - holder.secondaryActionIcon.setImageResource(R.drawable.ic_delete_grey600_24dp); + holder.secondaryActionIcon.setImageResource(ThemeUtils.getDrawableFromAttr(activity, R.attr.content_discard)); holder.secondaryActionButton.setOnClickListener(v -> itemAccess.onFeedItemSecondaryAction(item)); holder.hideSeparatorIfNecessary(); From 24a51062e0c59b5ef2acea42d7536209254a37a1 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Thu, 6 Feb 2020 12:49:13 +0100 Subject: [PATCH 20/24] Updated download log list --- .../adapter/DownloadLogAdapter.java | 260 ++++++++---------- .../viewholder/DownloadItemViewHolder.java | 41 +++ app/src/main/res/layout/downloadlog_item.xml | 169 ++++++------ core/src/main/res/values/colors.xml | 4 +- 4 files changed, 238 insertions(+), 236 deletions(-) create mode 100644 app/src/main/java/de/danoeh/antennapod/view/viewholder/DownloadItemViewHolder.java diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java index 4d66fd486..9206cebea 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java @@ -26,171 +26,139 @@ import de.danoeh.antennapod.core.storage.DBReader; import de.danoeh.antennapod.core.storage.DBTasks; import de.danoeh.antennapod.core.storage.DownloadRequestException; import de.danoeh.antennapod.core.storage.DownloadRequester; +import de.danoeh.antennapod.core.util.ThemeUtils; +import de.danoeh.antennapod.view.viewholder.DownloadItemViewHolder; +import de.danoeh.antennapod.view.viewholder.FeedViewHolder; -/** Displays a list of DownloadStatus entries. */ +/** + * Displays a list of DownloadStatus entries. + */ public class DownloadLogAdapter extends BaseAdapter { + private static final String TAG = "DownloadLogAdapter"; - private static final String TAG = "DownloadLogAdapter"; - - private final Context context; - + private final Context context; private final ItemAccess itemAccess; - public DownloadLogAdapter(Context context, ItemAccess itemAccess) { - super(); + public DownloadLogAdapter(Context context, ItemAccess itemAccess) { + super(); this.itemAccess = itemAccess; - this.context = context; - } + this.context = context; + } - @Override - public View getView(int position, View convertView, ViewGroup parent) { - Holder holder; - DownloadStatus status = getItem(position); - if (convertView == null) { - holder = new Holder(); - LayoutInflater inflater = (LayoutInflater) context - .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - convertView = inflater.inflate(R.layout.downloadlog_item, parent, false); - holder.icon = convertView.findViewById(R.id.txtvIcon); - holder.retry = convertView.findViewById(R.id.btnRetry); - holder.date = convertView.findViewById(R.id.txtvDate); - holder.title = convertView.findViewById(R.id.txtvTitle); - if(Build.VERSION.SDK_INT >= 23) { - holder.title.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_FULL); - } - holder.type = convertView.findViewById(R.id.txtvType); - holder.reason = convertView.findViewById(R.id.txtvReason); - convertView.setTag(holder); - } else { - holder = (Holder) convertView.getTag(); - } - if (status.getFeedfileType() == Feed.FEEDFILETYPE_FEED) { - holder.type.setText(R.string.download_type_feed); - } else if (status.getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA) { - holder.type.setText(R.string.download_type_media); - } - if (status.getTitle() != null) { - holder.title.setText(status.getTitle()); - } else { - holder.title.setText(R.string.download_log_title_unknown); - } - holder.date.setText(DateUtils.getRelativeTimeSpanString( - status.getCompletionDate().getTime(), - System.currentTimeMillis(), 0, 0)); - if (status.isSuccessful()) { - holder.icon.setTextColor(ContextCompat.getColor(convertView.getContext(), - R.color.download_success_green)); - holder.icon.setText("{fa-check-circle}"); - holder.retry.setVisibility(View.GONE); - holder.reason.setVisibility(View.GONE); - } else { - holder.icon.setTextColor(ContextCompat.getColor(convertView.getContext(), - R.color.download_failed_red)); - holder.icon.setText("{fa-times-circle}"); - String reasonText = status.getReason().getErrorString(context); - if (status.getReasonDetailed() != null) { - reasonText += ": " + status.getReasonDetailed(); - } - holder.reason.setText(reasonText); - holder.reason.setVisibility(View.VISIBLE); - if(!newerWasSuccessful(position, status.getFeedfileType(), status.getFeedfileId())) { - holder.retry.setVisibility(View.VISIBLE); - holder.retry.setOnClickListener(clickListener); - ButtonHolder btnHolder; - if(holder.retry.getTag() != null) { - btnHolder = (ButtonHolder) holder.retry.getTag(); - } else { - btnHolder = new ButtonHolder(); - } - btnHolder.typeId = status.getFeedfileType(); - btnHolder.id = status.getFeedfileId(); - holder.retry.setTag(btnHolder); - } else { - holder.retry.setVisibility(View.GONE); - holder.retry.setOnClickListener(null); - holder.retry.setTag(null); - } - } + @Override + public View getView(int position, View convertView, ViewGroup parent) { + DownloadItemViewHolder holder; + if (convertView == null) { + holder = new DownloadItemViewHolder(context, parent); + } else { + holder = (DownloadItemViewHolder) convertView.getTag(); + } - return convertView; - } + DownloadStatus status = getItem(position); + if (status.getFeedfileType() == Feed.FEEDFILETYPE_FEED) { + holder.type.setText(R.string.download_type_feed); + } else if (status.getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA) { + holder.type.setText(R.string.download_type_media); + } - private final View.OnClickListener clickListener = new View.OnClickListener() { - @Override - public void onClick(View v) { - ButtonHolder holder = (ButtonHolder) v.getTag(); - if(holder.typeId == Feed.FEEDFILETYPE_FEED) { - Feed feed = DBReader.getFeed(holder.id); - if (feed != null) { - try { - DBTasks.forceRefreshFeed(context, feed); - } catch (DownloadRequestException e) { - e.printStackTrace(); - } - } else { - Log.wtf(TAG, "Could not find feed for feed id: " + holder.id); - } - } else if(holder.typeId == FeedMedia.FEEDFILETYPE_FEEDMEDIA) { - FeedMedia media = DBReader.getFeedMedia(holder.id); - if (media != null) { - try { - DownloadRequester.getInstance().downloadMedia(context, media.getItem()); - Toast.makeText(context, R.string.status_downloading_label, Toast.LENGTH_SHORT).show(); - } catch (DownloadRequestException e) { - e.printStackTrace(); - DownloadRequestErrorDialogCreator.newRequestErrorDialog(context, e.getMessage()); - } - } else { - Log.wtf(TAG, "Could not find media for id: " + holder.id); - } - } else { - Log.wtf(TAG, "Unexpected type id: " + holder.typeId); - } - v.setVisibility(View.GONE); - } - }; + if (status.getTitle() != null) { + holder.title.setText(status.getTitle()); + } else { + holder.title.setText(R.string.download_log_title_unknown); + } + holder.date.setText(DateUtils.getRelativeTimeSpanString(status.getCompletionDate().getTime(), + System.currentTimeMillis(), 0, 0)); - private boolean newerWasSuccessful(int position, int feedTypeId, long id) { - for (int i = 0; i < position; i++) { - DownloadStatus status = getItem(i); - if (status.getFeedfileType() == feedTypeId && status.getFeedfileId() == id && - status.isSuccessful()) return true; - } - return false; - } + if (status.isSuccessful()) { + holder.icon.setTextColor(ContextCompat.getColor(context, R.color.download_success_green)); + holder.icon.setText("{fa-check-circle}"); + holder.secondaryActionButton.setVisibility(View.INVISIBLE); + holder.reason.setVisibility(View.GONE); + } else { + holder.icon.setTextColor(ContextCompat.getColor(context, R.color.download_failed_red)); + holder.icon.setText("{fa-times-circle}"); + String reasonText = status.getReason().getErrorString(context); + if (status.getReasonDetailed() != null) { + reasonText += ": " + status.getReasonDetailed(); + } + holder.reason.setText(reasonText); + holder.reason.setVisibility(View.VISIBLE); - static class Holder { - IconTextView icon; - IconButton retry; - TextView title; - TextView type; - TextView date; - TextView reason; - } + if (newerWasSuccessful(position, status.getFeedfileType(), status.getFeedfileId())) { + holder.secondaryActionButton.setVisibility(View.INVISIBLE); + holder.secondaryActionButton.setOnClickListener(null); + holder.secondaryActionButton.setTag(null); + } else { + holder.secondaryActionIcon.setImageResource( + ThemeUtils.getDrawableFromAttr(context, R.attr.navigation_refresh)); + holder.secondaryActionButton.setVisibility(View.VISIBLE); - static class ButtonHolder { - int typeId; - long id; - } + if (status.getFeedfileType() == Feed.FEEDFILETYPE_FEED) { + holder.secondaryActionButton.setOnClickListener(v -> { + holder.secondaryActionButton.setVisibility(View.INVISIBLE); + Feed feed = DBReader.getFeed(status.getFeedfileId()); + if (feed == null) { + Log.e(TAG, "Could not find feed for feed id: " + status.getFeedfileId()); + return; + } + try { + DBTasks.forceRefreshFeed(context, feed); + } catch (DownloadRequestException e) { + e.printStackTrace(); + } + }); + } else if (status.getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA) { + holder.secondaryActionButton.setOnClickListener(v -> { + holder.secondaryActionButton.setVisibility(View.INVISIBLE); + FeedMedia media = DBReader.getFeedMedia(status.getFeedfileId()); + if (media == null) { + Log.e(TAG, "Could not find feed media for feed id: " + status.getFeedfileId()); + return; + } + try { + DownloadRequester.getInstance().downloadMedia(context, media.getItem()); + Toast.makeText(context, R.string.status_downloading_label, Toast.LENGTH_SHORT).show(); + } catch (DownloadRequestException e) { + e.printStackTrace(); + DownloadRequestErrorDialogCreator.newRequestErrorDialog(context, e.getMessage()); + } + }); + } + } + } - @Override - public int getCount() { + return holder.itemView; + } + + private boolean newerWasSuccessful(int position, int feedTypeId, long id) { + for (int i = 0; i < position; i++) { + DownloadStatus status = getItem(i); + if (status.getFeedfileType() == feedTypeId && status.getFeedfileId() == id && status.isSuccessful()) { + return true; + } + } + return false; + } + + @Override + public int getCount() { return itemAccess.getCount(); - } + } - @Override - public DownloadStatus getItem(int position) { + @Override + public DownloadStatus getItem(int position) { return itemAccess.getItem(position); - } + } - @Override - public long getItemId(int position) { - return position; - } + @Override + public long getItemId(int position) { + return position; + } public interface ItemAccess { - int getCount(); - DownloadStatus getItem(int position); + int getCount(); + + DownloadStatus getItem(int position); } } diff --git a/app/src/main/java/de/danoeh/antennapod/view/viewholder/DownloadItemViewHolder.java b/app/src/main/java/de/danoeh/antennapod/view/viewholder/DownloadItemViewHolder.java new file mode 100644 index 000000000..d48db196f --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/view/viewholder/DownloadItemViewHolder.java @@ -0,0 +1,41 @@ +package de.danoeh.antennapod.view.viewholder; + +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.ImageView; +import android.widget.TextView; +import androidx.recyclerview.widget.RecyclerView; +import com.joanzapata.iconify.widget.IconTextView; +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.view.CircularProgressBar; + +public class DownloadItemViewHolder extends RecyclerView.ViewHolder { + public final View secondaryActionButton; + public final ImageView secondaryActionIcon; + public final CircularProgressBar secondaryActionProgress; + public final IconTextView icon; + public final TextView title; + public final TextView type; + public final TextView date; + public final TextView reason; + + public DownloadItemViewHolder(Context context, ViewGroup parent) { + super(LayoutInflater.from(context).inflate(R.layout.downloadlog_item, parent, false)); + date = itemView.findViewById(R.id.txtvDate); + type = itemView.findViewById(R.id.txtvType); + icon = itemView.findViewById(R.id.txtvIcon); + reason = itemView.findViewById(R.id.txtvReason); + secondaryActionProgress = itemView.findViewById(R.id.secondaryActionProgress); + secondaryActionButton = itemView.findViewById(R.id.secondaryActionButton); + secondaryActionIcon = itemView.findViewById(R.id.secondaryActionIcon); + title = itemView.findViewById(R.id.txtvTitle); + if (Build.VERSION.SDK_INT >= 23) { + title.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_FULL); + } + itemView.setTag(this); + } +} diff --git a/app/src/main/res/layout/downloadlog_item.xml b/app/src/main/res/layout/downloadlog_item.xml index 505102ea4..c8cbf15f6 100644 --- a/app/src/main/res/layout/downloadlog_item.xml +++ b/app/src/main/res/layout/downloadlog_item.xml @@ -1,97 +1,90 @@ - + + android:id="@+id/txtvIcon" + android:layout_width="40dp" + android:layout_height="40dp" + android:layout_marginBottom="@dimen/listitem_threeline_verticalpadding" + android:layout_marginTop="@dimen/listitem_threeline_verticalpadding" + android:layout_marginLeft="@dimen/listitem_threeline_textleftpadding" + android:layout_marginStart="@dimen/listitem_threeline_textleftpadding" + android:textSize="40dp" + android:gravity="center" + tools:text="X"/> - + - + - + + + - + + - + - \ No newline at end of file + + + + + \ No newline at end of file diff --git a/core/src/main/res/values/colors.xml b/core/src/main/res/values/colors.xml index fea7da4a4..b162038cf 100644 --- a/core/src/main/res/values/colors.xml +++ b/core/src/main/res/values/colors.xml @@ -7,8 +7,8 @@ #000000 #33B5E5 #0099CC - #669900 - #CC0000 + #248800 + #B00020 #E033B5E5 #2C2C2C #FFFFFF From 7ec9b00e8b080df831adeafdccf3633a26de1836 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Thu, 6 Feb 2020 22:51:58 +0100 Subject: [PATCH 21/24] Updated running downloads list --- .../adapter/DownloadlistAdapter.java | 73 ++++++------ .../fragment/RunningDownloadsFragment.java | 7 +- app/src/main/res/layout/downloadlist_item.xml | 111 +++++------------- core/src/main/res/values/strings.xml | 1 + 4 files changed, 71 insertions(+), 121 deletions(-) diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/DownloadlistAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/DownloadlistAdapter.java index b0ee87b7e..fd9b76b9c 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/DownloadlistAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/DownloadlistAdapter.java @@ -5,23 +5,25 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; -import android.widget.ImageButton; -import android.widget.ProgressBar; +import android.widget.ImageView; import android.widget.TextView; import de.danoeh.antennapod.R; +import de.danoeh.antennapod.core.feed.Feed; +import de.danoeh.antennapod.core.feed.FeedMedia; import de.danoeh.antennapod.core.service.download.DownloadRequest; import de.danoeh.antennapod.core.service.download.DownloadStatus; import de.danoeh.antennapod.core.service.download.Downloader; import de.danoeh.antennapod.core.util.Converter; +import de.danoeh.antennapod.core.util.ThemeUtils; +import de.danoeh.antennapod.view.CircularProgressBar; public class DownloadlistAdapter extends BaseAdapter { private final ItemAccess itemAccess; private final Context context; - public DownloadlistAdapter(Context context, - ItemAccess itemAccess) { + public DownloadlistAdapter(Context context, ItemAccess itemAccess) { super(); this.context = context; this.itemAccess = itemAccess; @@ -47,47 +49,44 @@ public class DownloadlistAdapter extends BaseAdapter { Holder holder; Downloader downloader = getItem(position); DownloadRequest request = downloader.getDownloadRequest(); - // Inflate layout if (convertView == null) { holder = new Holder(); - LayoutInflater inflater = (LayoutInflater) context - .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); convertView = inflater.inflate(R.layout.downloadlist_item, parent, false); holder.title = convertView.findViewById(R.id.txtvTitle); - holder.downloaded = convertView - .findViewById(R.id.txtvDownloaded); - holder.percent = convertView - .findViewById(R.id.txtvPercent); - holder.progbar = convertView - .findViewById(R.id.progProgress); - holder.butSecondary = convertView - .findViewById(R.id.butSecondaryAction); - + holder.status = convertView.findViewById(R.id.txtvStatus); + holder.secondaryActionButton = convertView.findViewById(R.id.secondaryActionButton); + holder.secondaryActionIcon = convertView.findViewById(R.id.secondaryActionIcon); + holder.secondaryActionProgress = convertView.findViewById(R.id.secondaryActionProgress); convertView.setTag(holder); } else { holder = (Holder) convertView.getTag(); } holder.title.setText(request.getTitle()); + holder.secondaryActionIcon.setImageResource(ThemeUtils.getDrawableFromAttr(context, R.attr.navigation_cancel)); + holder.secondaryActionButton.setTag(downloader); + holder.secondaryActionButton.setOnClickListener(butSecondaryListener); + holder.secondaryActionProgress.setPercentage(0, request); - holder.progbar.setIndeterminate(request.getSoFar() <= 0); - - String strDownloaded = Converter.byteToString(request.getSoFar()); - if (request.getSize() != DownloadStatus.SIZE_UNKNOWN) { - strDownloaded += " / " + Converter.byteToString(request.getSize()); - holder.percent.setText(request.getProgressPercent() + "%"); - holder.progbar.setProgress(request.getProgressPercent()); - holder.percent.setVisibility(View.VISIBLE); - } else { - holder.progbar.setProgress(0); - holder.percent.setVisibility(View.INVISIBLE); + String status = ""; + if (request.getFeedfileType() == Feed.FEEDFILETYPE_FEED) { + status += context.getString(R.string.download_type_feed); + } else if (request.getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA) { + status += context.getString(R.string.download_type_media); } - - holder.downloaded.setText(strDownloaded); - - holder.butSecondary.setFocusable(false); - holder.butSecondary.setTag(downloader); - holder.butSecondary.setOnClickListener(butSecondaryListener); + status += " · "; + if (request.getSoFar() <= 0) { + status += context.getString(R.string.download_queued); + } else { + status += Converter.byteToString(request.getSoFar()); + if (request.getSize() != DownloadStatus.SIZE_UNKNOWN) { + status += " / " + Converter.byteToString(request.getSize()); + holder.secondaryActionProgress.setPercentage( + 0.01f * Math.max(1, request.getProgressPercent()), request); + } + } + holder.status.setText(status); return convertView; } @@ -102,10 +101,10 @@ public class DownloadlistAdapter extends BaseAdapter { static class Holder { TextView title; - TextView downloaded; - TextView percent; - ProgressBar progbar; - ImageButton butSecondary; + TextView status; + View secondaryActionButton; + ImageView secondaryActionIcon; + CircularProgressBar secondaryActionProgress; } public interface ItemAccess { diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/RunningDownloadsFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/RunningDownloadsFragment.java index 7e8823c27..1bfbd2d78 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/RunningDownloadsFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/RunningDownloadsFragment.java @@ -104,11 +104,12 @@ public class RunningDownloadsFragment extends ListFragment { DownloadRequest downloadRequest = downloader.getDownloadRequest(); DownloadRequester.getInstance().cancelDownload(getActivity(), downloadRequest.getSource()); - if(downloadRequest.getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA && - UserPreferences.isEnableAutodownload()) { + if (downloadRequest.getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA + && UserPreferences.isEnableAutodownload()) { FeedMedia media = DBReader.getFeedMedia(downloadRequest.getFeedfileId()); DBWriter.setFeedItemAutoDownload(media.getItem(), false); - Toast.makeText(getActivity(), R.string.download_canceled_autodownload_enabled_msg, Toast.LENGTH_SHORT).show(); + Toast.makeText(getActivity(), R.string.download_canceled_autodownload_enabled_msg, + Toast.LENGTH_SHORT).show(); } else { Toast.makeText(getActivity(), R.string.download_canceled_msg, Toast.LENGTH_SHORT).show(); } diff --git a/app/src/main/res/layout/downloadlist_item.xml b/app/src/main/res/layout/downloadlist_item.xml index 668ec817a..7a4c2fede 100644 --- a/app/src/main/res/layout/downloadlist_item.xml +++ b/app/src/main/res/layout/downloadlist_item.xml @@ -1,90 +1,39 @@ - + - - - - - - - - + + - - - - + tools:text="Media file · 10MB / 20MB"/> - - - - + diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml index e5d8247bc..8cb9f7b84 100644 --- a/core/src/main/res/values/strings.xml +++ b/core/src/main/res/values/strings.xml @@ -102,6 +102,7 @@ Light Heavy \u0020parallel downloads + Download queued Global default Always Never From b9d5ec1a085e17f60bb2d597e63c502c0e2ad482 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Thu, 6 Feb 2020 23:16:12 +0100 Subject: [PATCH 22/24] Updated chapters list --- .../adapter/ChaptersListAdapter.java | 84 +++---------- .../main/res/layout/simplechapter_item.xml | 114 +++++++----------- 2 files changed, 60 insertions(+), 138 deletions(-) diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/ChaptersListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/ChaptersListAdapter.java index f6e6da8b4..fa18621ac 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/ChaptersListAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/ChaptersListAdapter.java @@ -1,36 +1,26 @@ package de.danoeh.antennapod.adapter; import android.content.Context; -import androidx.annotation.NonNull; -import androidx.core.content.ContextCompat; -import android.text.Layout; -import android.text.Selection; -import android.text.Spannable; -import android.text.Spanned; -import android.text.style.ClickableSpan; -import android.text.util.Linkify; import android.view.LayoutInflater; -import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; -import android.widget.ImageButton; +import android.widget.ImageView; import android.widget.TextView; - +import androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; import de.danoeh.antennapod.R; import de.danoeh.antennapod.core.feed.Chapter; import de.danoeh.antennapod.core.util.ChapterUtils; import de.danoeh.antennapod.core.util.Converter; +import de.danoeh.antennapod.core.util.IntentUtils; import de.danoeh.antennapod.core.util.ThemeUtils; import de.danoeh.antennapod.core.util.playback.Playable; public class ChaptersListAdapter extends ArrayAdapter { - private static final String TAG = "ChapterListAdapter"; private Playable media; - - private int defaultTextColor; private final Callback callback; public ChaptersListAdapter(Context context, int textViewResourceId, Callback callback) { @@ -58,11 +48,11 @@ public class ChaptersListAdapter extends ArrayAdapter { convertView = inflater.inflate(R.layout.simplechapter_item, parent, false); holder.view = convertView; holder.title = convertView.findViewById(R.id.txtvTitle); - defaultTextColor = holder.title.getTextColors().getDefaultColor(); holder.start = convertView.findViewById(R.id.txtvStart); holder.link = convertView.findViewById(R.id.txtvLink); holder.duration = convertView.findViewById(R.id.txtvDuration); - holder.butPlayChapter = convertView.findViewById(R.id.butPlayChapter); + holder.secondaryActionButton = convertView.findViewById(R.id.secondaryActionButton); + holder.secondaryActionIcon = convertView.findViewById(R.id.secondaryActionIcon); convertView.setTag(holder); } else { holder = (Holder) convertView.getTag(); @@ -82,60 +72,15 @@ public class ChaptersListAdapter extends ArrayAdapter { holder.duration.setText(getContext().getString(R.string.chapter_duration, Converter.getDurationStringLong((int) duration))); - if (sc.getLink() != null) { + if (sc.getLink() == null) { + holder.link.setVisibility(View.GONE); + } else { holder.link.setVisibility(View.VISIBLE); holder.link.setText(sc.getLink()); - Linkify.addLinks(holder.link, Linkify.WEB_URLS); - } else { - holder.link.setVisibility(View.GONE); + holder.link.setOnClickListener(v -> IntentUtils.openInBrowser(getContext(), sc.getLink())); } - holder.link.setMovementMethod(null); - holder.link.setOnTouchListener((v, event) -> { - // from - // http://stackoverflow.com/questions/7236840/android-textview-linkify-intercepts-with-parent-view-gestures - TextView widget = (TextView) v; - Object text = widget.getText(); - if (text instanceof Spanned) { - Spannable buffer = (Spannable) text; - - int action = event.getAction(); - - if (action == MotionEvent.ACTION_UP - || action == MotionEvent.ACTION_DOWN) { - int x = (int) event.getX(); - int y = (int) event.getY(); - - x -= widget.getTotalPaddingLeft(); - y -= widget.getTotalPaddingTop(); - - x += widget.getScrollX(); - y += widget.getScrollY(); - - Layout layout = widget.getLayout(); - int line = layout.getLineForVertical(y); - int off = layout.getOffsetForHorizontal(line, x); - - ClickableSpan[] link = buffer.getSpans(off, off, - ClickableSpan.class); - - if (link.length != 0) { - if (action == MotionEvent.ACTION_UP) { - link[0].onClick(widget); - } else if (action == MotionEvent.ACTION_DOWN) { - Selection.setSelection(buffer, - buffer.getSpanStart(link[0]), - buffer.getSpanEnd(link[0])); - } - return true; - } - } - - } - - return false; - - }); - holder.butPlayChapter.setOnClickListener(v -> { + holder.secondaryActionIcon.setImageResource(ThemeUtils.getDrawableFromAttr(getContext(), R.attr.av_play)); + holder.secondaryActionButton.setOnClickListener(v -> { if (callback != null) { callback.onPlayChapterButtonClicked(position); } @@ -147,8 +92,6 @@ public class ChaptersListAdapter extends ArrayAdapter { holder.view.setBackgroundColor(playingBackGroundColor); } else { holder.view.setBackgroundColor(ContextCompat.getColor(getContext(), android.R.color.transparent)); - holder.title.setTextColor(defaultTextColor); - holder.start.setTextColor(defaultTextColor); } return convertView; @@ -160,7 +103,8 @@ public class ChaptersListAdapter extends ArrayAdapter { TextView start; TextView link; TextView duration; - ImageButton butPlayChapter; + View secondaryActionButton; + ImageView secondaryActionIcon; } @Override diff --git a/app/src/main/res/layout/simplechapter_item.xml b/app/src/main/res/layout/simplechapter_item.xml index 0d02eac1a..86927f32c 100644 --- a/app/src/main/res/layout/simplechapter_item.xml +++ b/app/src/main/res/layout/simplechapter_item.xml @@ -1,86 +1,64 @@ - - - + android:baselineAligned="false" + android:descendantFocusability="blocksDescendants"> + android:layout_width="0dp" + android:layout_height="wrap_content" + 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_marginLeft="16dp" + android:layout_marginStart="16dp" + android:layout_weight="1" + android:orientation="vertical"> + android:id="@+id/txtvStart" + style="@style/AntennaPod.TextView.ListItemSecondaryTitle" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + tools:text="00:00:00"/> + 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:text="Duration: 00:00:00"/> - + - - - \ No newline at end of file + From 331d59d60aba1a401a5f33004724089c04f20a74 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Fri, 7 Feb 2020 00:18:54 +0100 Subject: [PATCH 23/24] Fixed tests compilation --- .../java/de/test/antennapod/playback/PlaybackTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/androidTest/java/de/test/antennapod/playback/PlaybackTest.java b/app/src/androidTest/java/de/test/antennapod/playback/PlaybackTest.java index cc380813e..efd6070bb 100644 --- a/app/src/androidTest/java/de/test/antennapod/playback/PlaybackTest.java +++ b/app/src/androidTest/java/de/test/antennapod/playback/PlaybackTest.java @@ -228,7 +228,7 @@ public class PlaybackTest { final List episodes = DBReader.getRecentlyPublishedEpisodes(0, 10); Matcher allEpisodesMatcher = allOf(withId(android.R.id.list), isDisplayed(), hasMinimumChildCount(2)); onView(isRoot()).perform(waitForView(allEpisodesMatcher, 1000)); - onView(allEpisodesMatcher).perform(actionOnItemAtPosition(0, clickChildViewWithId(R.id.butSecondaryAction))); + onView(allEpisodesMatcher).perform(actionOnItemAtPosition(0, clickChildViewWithId(R.id.secondaryActionButton))); FeedMedia media = episodes.get(0).getMedia(); Awaitility.await().atMost(1, TimeUnit.SECONDS).until( @@ -244,7 +244,7 @@ public class PlaybackTest { Matcher queueMatcher = allOf(withId(R.id.recyclerView), isDisplayed(), hasMinimumChildCount(2)); onView(isRoot()).perform(waitForView(queueMatcher, 1000)); - onView(queueMatcher).perform(actionOnItemAtPosition(itemIdx, clickChildViewWithId(R.id.butSecondaryAction))); + onView(queueMatcher).perform(actionOnItemAtPosition(itemIdx, clickChildViewWithId(R.id.secondaryActionButton))); FeedMedia media = queue.get(itemIdx).getMedia(); Awaitility.await().atMost(1, TimeUnit.SECONDS).until( From 9f1bb8151a3e6245e523844ea30385ed3b46c082 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Fri, 7 Feb 2020 00:26:39 +0100 Subject: [PATCH 24/24] Do not change item height when changing status icons --- app/src/main/res/layout/feeditemlist_item.xml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/src/main/res/layout/feeditemlist_item.xml b/app/src/main/res/layout/feeditemlist_item.xml index 38ba73c36..11656fefc 100644 --- a/app/src/main/res/layout/feeditemlist_item.xml +++ b/app/src/main/res/layout/feeditemlist_item.xml @@ -91,22 +91,22 @@ tools:text="@sample/episodes.json/data/status_label"/>