diff options
author | daniel oeh <daniel.oeh@gmail.com> | 2014-10-24 20:40:07 +0200 |
---|---|---|
committer | daniel oeh <daniel.oeh@gmail.com> | 2014-10-24 20:40:07 +0200 |
commit | cc052e91ad8a87b00b93649ec0f6a06bcae6267a (patch) | |
tree | 12cacac4fb5c94af2955812a3167eefb325f286d /app/src/main/java/de/danoeh/antennapod/adapter | |
parent | baa7d5f11283cb7668d45b561af5d38f0ccb9632 (diff) | |
parent | b5066d02b4acf31da093190a1a57a9d961bb04ca (diff) | |
download | AntennaPod-cc052e91ad8a87b00b93649ec0f6a06bcae6267a.zip |
Merge branch 'migration' into develop
Non-GUI classes have been moved into the 'core' project in order to allow AntennaPod SP to reference it as a subproject.
Conflicts:
app/src/main/AndroidManifest.xml
build.gradle
core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java
core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSSimpleChapters.java
core/src/main/java/de/danoeh/antennapod/core/util/ChapterUtils.java
gradle/wrapper/gradle-wrapper.properties
pom.xml
Diffstat (limited to 'app/src/main/java/de/danoeh/antennapod/adapter')
16 files changed, 2040 insertions, 0 deletions
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/ActionButtonCallback.java b/app/src/main/java/de/danoeh/antennapod/adapter/ActionButtonCallback.java new file mode 100644 index 000000000..a75789815 --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/adapter/ActionButtonCallback.java @@ -0,0 +1,8 @@ +package de.danoeh.antennapod.adapter; + +import de.danoeh.antennapod.core.feed.FeedItem; + +public interface ActionButtonCallback { + /** Is called when the action button of a list item has been pressed. */ + abstract void onActionButtonPressed(FeedItem item); +} diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/ActionButtonUtils.java b/app/src/main/java/de/danoeh/antennapod/adapter/ActionButtonUtils.java new file mode 100644 index 000000000..fecddeaf4 --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/adapter/ActionButtonUtils.java @@ -0,0 +1,78 @@ +package de.danoeh.antennapod.adapter; + +import android.content.Context; +import android.content.res.TypedArray; +import android.view.View; +import android.widget.ImageButton; + +import org.apache.commons.lang3.Validate; + +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.core.feed.FeedItem; +import de.danoeh.antennapod.core.feed.FeedMedia; +import de.danoeh.antennapod.core.storage.DownloadRequester; + +/** + * Utility methods for the action button that is displayed on the right hand side + * of a listitem. + */ +public class ActionButtonUtils { + + private final int[] labels; + private final TypedArray drawables; + private final Context context; + + public ActionButtonUtils(Context context) { + Validate.notNull(context); + + this.context = context; + drawables = context.obtainStyledAttributes(new int[]{ + R.attr.av_play, R.attr.navigation_cancel, R.attr.av_download, R.attr.navigation_chapters, R.attr.navigation_accept}); + labels = new int[]{R.string.play_label, R.string.cancel_download_label, R.string.download_label, R.string.mark_read_label}; + } + + /** + * Sets the displayed bitmap and content description of the given + * action button so that it matches the state of the FeedItem. + */ + public void configureActionButton(ImageButton butSecondary, FeedItem item) { + Validate.isTrue(butSecondary != null && item != null, "butSecondary or item was null"); + + final FeedMedia media = item.getMedia(); + if (media != null) { + final boolean isDownloadingMedia = DownloadRequester.getInstance().isDownloadingFile(media); + if (!media.isDownloaded()) { + if (isDownloadingMedia) { + // item is being downloaded + butSecondary.setVisibility(View.VISIBLE); + butSecondary.setImageDrawable(drawables + .getDrawable(1)); + butSecondary.setContentDescription(context.getString(labels[1])); + } else { + // item is not downloaded and not being downloaded + butSecondary.setVisibility(View.VISIBLE); + butSecondary.setImageDrawable(drawables.getDrawable(2)); + butSecondary.setContentDescription(context.getString(labels[2])); + } + } else { + // item is not being downloaded + butSecondary.setVisibility(View.VISIBLE); + if (media.isPlaying()) { + butSecondary.setImageDrawable(drawables.getDrawable(3)); + } else { + butSecondary + .setImageDrawable(drawables.getDrawable(0)); + } + butSecondary.setContentDescription(context.getString(labels[0])); + } + } else { + if (item.isRead()) { + butSecondary.setVisibility(View.INVISIBLE); + } else { + butSecondary.setVisibility(View.VISIBLE); + butSecondary.setImageDrawable(drawables.getDrawable(4)); + butSecondary.setContentDescription(context.getString(labels[3])); + } + } + } +} diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/AdapterUtils.java b/app/src/main/java/de/danoeh/antennapod/adapter/AdapterUtils.java new file mode 100644 index 000000000..c3902639a --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/adapter/AdapterUtils.java @@ -0,0 +1,57 @@ +package de.danoeh.antennapod.adapter; + +import android.content.res.Resources; +import android.view.View; +import android.widget.ProgressBar; +import android.widget.TextView; +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.core.feed.FeedItem; +import de.danoeh.antennapod.core.feed.FeedMedia; +import de.danoeh.antennapod.core.util.Converter; + +/** + * Utility methods for adapters + */ +public class AdapterUtils { + + private AdapterUtils() { + + } + + /** + * Updates the contents of the TextView that shows the current playback position and the ProgressBar. + */ + public static void updateEpisodePlaybackProgress(FeedItem item, Resources res, 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()) { + txtvPos.setText(res.getString( + R.string.size_prefix) + + Converter.byteToString(media.getSize())); + } else { + txtvPos.setText(res.getString( + R.string.length_prefix) + + Converter.getDurationStringLong(media + .getDuration())); + } + } +} diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/ChapterListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/ChapterListAdapter.java new file mode 100644 index 000000000..9e59a2a1a --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/adapter/ChapterListAdapter.java @@ -0,0 +1,180 @@ +package de.danoeh.antennapod.adapter; + +import android.content.Context; +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.util.Log; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.view.View.OnTouchListener; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.TextView; +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.playback.Playable; + +import java.util.List; + +public class ChapterListAdapter extends ArrayAdapter<Chapter> { + + private static final String TAG = "ChapterListAdapter"; + + private List<Chapter> chapters; + private Playable media; + + private int defaultTextColor; + + public ChapterListAdapter(Context context, int textViewResourceId, + List<Chapter> objects, Playable media) { + super(context, textViewResourceId, objects); + this.chapters = objects; + this.media = media; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + Holder holder; + + Chapter sc = getItem(position); + + // Inflate Layout + if (convertView == null) { + holder = new Holder(); + LayoutInflater inflater = (LayoutInflater) getContext() + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + + convertView = inflater.inflate(R.layout.simplechapter_item, parent, false); + holder.title = (TextView) convertView.findViewById(R.id.txtvTitle); + defaultTextColor = holder.title.getTextColors().getDefaultColor(); + holder.start = (TextView) convertView.findViewById(R.id.txtvStart); + holder.link = (TextView) convertView.findViewById(R.id.txtvLink); + convertView.setTag(holder); + } else { + holder = (Holder) convertView.getTag(); + + } + + holder.title.setText(sc.getTitle()); + holder.start.setText(Converter.getDurationStringLong((int) sc + .getStart())); + if (sc.getLink() != null) { + 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.setMovementMethod(null); + holder.link.setOnTouchListener(new OnTouchListener() { + + @Override + public boolean onTouch(View v, MotionEvent 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; + + } + }); + Chapter current = ChapterUtils.getCurrentChapter(media); + if (current != null) { + if (current == sc) { + holder.title.setTextColor(convertView.getResources().getColor( + R.color.bright_blue)); + holder.start.setTextColor(convertView.getResources().getColor( + R.color.bright_blue)); + } else { + holder.title.setTextColor(defaultTextColor); + holder.start.setTextColor(defaultTextColor); + } + } else { + Log.w(TAG, "Could not find out what the current chapter is."); + } + + return convertView; + } + + static class Holder { + TextView title; + TextView start; + TextView link; + } + + @Override + public int getCount() { + // ignore invalid chapters + int counter = 0; + for (Chapter chapter : chapters) { + if (!ignoreChapter(chapter)) { + counter++; + } + } + return counter; + } + + private boolean ignoreChapter(Chapter c) { + return media.getDuration() > 0 && media.getDuration() < c.getStart(); + } + + @Override + public Chapter getItem(int position) { + int i = 0; + for (Chapter chapter : chapters) { + if (!ignoreChapter(chapter)) { + if (i == position) { + return chapter; + } else { + i++; + } + } + } + return super.getItem(position); + } + +} diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/DefaultActionButtonCallback.java b/app/src/main/java/de/danoeh/antennapod/adapter/DefaultActionButtonCallback.java new file mode 100644 index 000000000..800462023 --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/adapter/DefaultActionButtonCallback.java @@ -0,0 +1,57 @@ +package de.danoeh.antennapod.adapter; + +import android.content.Context; +import android.widget.Toast; + +import org.apache.commons.lang3.Validate; + +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.core.dialog.DownloadRequestErrorDialogCreator; +import de.danoeh.antennapod.core.feed.FeedItem; +import de.danoeh.antennapod.core.feed.FeedMedia; +import de.danoeh.antennapod.core.storage.DBTasks; +import de.danoeh.antennapod.core.storage.DBWriter; +import de.danoeh.antennapod.core.storage.DownloadRequestException; +import de.danoeh.antennapod.core.storage.DownloadRequester; + +/** + * Default implementation of an ActionButtonCallback + */ +public class DefaultActionButtonCallback implements ActionButtonCallback { + private static final String TAG = "DefaultActionButtonCallback"; + + private final Context context; + + public DefaultActionButtonCallback(Context context) { + Validate.notNull(context); + this.context = context; + } + + @Override + public void onActionButtonPressed(final FeedItem item) { + + + if (item.hasMedia()) { + final FeedMedia media = item.getMedia(); + boolean isDownloading = DownloadRequester.getInstance().isDownloadingFile(media); + if (!isDownloading && !media.isDownloaded()) { + try { + DBTasks.downloadFeedItems(context, item); + Toast.makeText(context, R.string.status_downloading_label, Toast.LENGTH_SHORT).show(); + } catch (DownloadRequestException e) { + e.printStackTrace(); + DownloadRequestErrorDialogCreator.newRequestErrorDialog(context, e.getMessage()); + } + } else if (isDownloading) { + DownloadRequester.getInstance().cancelDownload(context, media); + Toast.makeText(context, R.string.download_cancelled_msg, Toast.LENGTH_SHORT).show(); + } else { // media is downloaded + DBTasks.playMedia(context, media, true, true, false); + } + } else { + if (!item.isRead()) { + DBWriter.markItemRead(context, item, true, true); + } + } + } +} diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java new file mode 100644 index 000000000..f982e86ce --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java @@ -0,0 +1,112 @@ +package de.danoeh.antennapod.adapter; + +import android.content.Context; +import android.text.format.DateUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.TextView; +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.core.feed.Feed; +import de.danoeh.antennapod.core.feed.FeedImage; +import de.danoeh.antennapod.core.feed.FeedMedia; +import de.danoeh.antennapod.core.service.download.DownloadStatus; + +/** Displays a list of DownloadStatus entries. */ +public class DownloadLogAdapter extends BaseAdapter { + + private Context context; + + private ItemAccess itemAccess; + + public DownloadLogAdapter(Context context, ItemAccess itemAccess) { + super(); + this.itemAccess = itemAccess; + 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.title = (TextView) convertView.findViewById(R.id.txtvTitle); + holder.type = (TextView) convertView.findViewById(R.id.txtvType); + holder.date = (TextView) convertView.findViewById(R.id.txtvDate); + holder.successful = (TextView) convertView + .findViewById(R.id.txtvStatus); + holder.reason = (TextView) 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); + } else if (status.getFeedfileType() == FeedImage.FEEDFILETYPE_FEEDIMAGE) { + holder.type.setText(R.string.download_type_image); + } + 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.successful.setTextColor(convertView.getResources().getColor( + R.color.download_success_green)); + holder.successful.setText(R.string.download_successful); + holder.reason.setVisibility(View.GONE); + } else { + holder.successful.setTextColor(convertView.getResources().getColor( + R.color.download_failed_red)); + holder.successful.setText(R.string.download_failed); + String reasonText = status.getReason().getErrorString(context); + if (status.getReasonDetailed() != null) { + reasonText += ": " + status.getReasonDetailed(); + } + holder.reason.setText(reasonText); + holder.reason.setVisibility(View.VISIBLE); + } + + return convertView; + } + + static class Holder { + TextView title; + TextView type; + TextView date; + TextView successful; + TextView reason; + } + + @Override + public int getCount() { + return itemAccess.getCount(); + } + + @Override + public DownloadStatus getItem(int position) { + return itemAccess.getItem(position); + } + + @Override + public long getItemId(int position) { + return position; + } + + public static interface ItemAccess { + public int getCount(); + public DownloadStatus getItem(int position); + } + +} diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/DownloadedEpisodesListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/DownloadedEpisodesListAdapter.java new file mode 100644 index 000000000..8785916a0 --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/adapter/DownloadedEpisodesListAdapter.java @@ -0,0 +1,122 @@ +package de.danoeh.antennapod.adapter; + +import android.content.Context; +import android.text.format.DateUtils; +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 de.danoeh.antennapod.R; +import de.danoeh.antennapod.core.asynctask.PicassoProvider; +import de.danoeh.antennapod.core.feed.FeedItem; +import de.danoeh.antennapod.core.util.Converter; + +/** + * Shows a list of downloaded episodes + */ +public class DownloadedEpisodesListAdapter extends BaseAdapter { + + private final Context context; + private final ItemAccess itemAccess; + + private final int imageSize; + + public DownloadedEpisodesListAdapter(Context context, ItemAccess itemAccess) { + super(); + this.context = context; + this.itemAccess = itemAccess; + this.imageSize = (int) context.getResources().getDimension(R.dimen.thumbnail_length_downloaded_item); + } + + @Override + public int getCount() { + return itemAccess.getCount(); + } + + @Override + public FeedItem getItem(int position) { + return itemAccess.getItem(position); + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + Holder holder; + final FeedItem item = (FeedItem) getItem(position); + if (item == null) return null; + + 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.title = (TextView) convertView.findViewById(R.id.txtvTitle); + holder.pubDate = (TextView) convertView + .findViewById(R.id.txtvPublished); + holder.butSecondary = (ImageButton) convertView + .findViewById(R.id.butSecondaryAction); + holder.imageView = (ImageView) convertView.findViewById(R.id.imgvImage); + holder.txtvSize = (TextView) convertView.findViewById(R.id.txtvSize); + convertView.setTag(holder); + } else { + holder = (Holder) convertView.getTag(); + } + + holder.title.setText(item.getTitle()); + holder.pubDate.setText(DateUtils.formatDateTime(context, item.getPubDate().getTime(), DateUtils.FORMAT_SHOW_DATE)); + holder.txtvSize.setText(Converter.byteToString(item.getMedia().getSize())); + FeedItem.State state = item.getState(); + + if (state == FeedItem.State.PLAYING) { + holder.butSecondary.setEnabled(false); + } else { + holder.butSecondary.setEnabled(true); + } + + holder.butSecondary.setFocusable(false); + holder.butSecondary.setTag(item); + holder.butSecondary.setOnClickListener(secondaryActionListener); + + + PicassoProvider.getMediaMetadataPicassoInstance(context) + .load(item.getImageUri()) + .fit() + .into(holder.imageView); + + return convertView; + } + + private View.OnClickListener secondaryActionListener = new View.OnClickListener() { + @Override + public void onClick(View v) { + FeedItem item = (FeedItem) v.getTag(); + itemAccess.onFeedItemSecondaryAction(item); + } + }; + + + static class Holder { + TextView title; + TextView pubDate; + ImageView imageView; + TextView txtvSize; + ImageButton butSecondary; + } + + public interface ItemAccess { + int getCount(); + + FeedItem getItem(int position); + + void onFeedItemSecondaryAction(FeedItem item); + } +} diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/DownloadlistAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/DownloadlistAdapter.java new file mode 100644 index 000000000..4257c6eb9 --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/adapter/DownloadlistAdapter.java @@ -0,0 +1,142 @@ +package de.danoeh.antennapod.adapter; + +import android.content.Context; +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.TextView; +import de.danoeh.antennapod.R; +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; + +public class DownloadlistAdapter extends BaseAdapter { + + public static final int SELECTION_NONE = -1; + + private int selectedItemIndex; + private ItemAccess itemAccess; + private Context context; + + public DownloadlistAdapter(Context context, + ItemAccess itemAccess) { + super(); + this.selectedItemIndex = SELECTION_NONE; + this.context = context; + this.itemAccess = itemAccess; + } + + @Override + public int getCount() { + return itemAccess.getCount(); + } + + @Override + public Downloader getItem(int position) { + return itemAccess.getItem(position); + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + 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); + convertView = inflater.inflate(R.layout.downloadlist_item, parent, false); + holder.title = (TextView) convertView.findViewById(R.id.txtvTitle); + holder.message = (TextView) convertView + .findViewById(R.id.txtvMessage); + holder.downloaded = (TextView) convertView + .findViewById(R.id.txtvDownloaded); + holder.percent = (TextView) convertView + .findViewById(R.id.txtvPercent); + holder.progbar = (ProgressBar) convertView + .findViewById(R.id.progProgress); + holder.butSecondary = (ImageButton) convertView + .findViewById(R.id.butSecondaryAction); + + convertView.setTag(holder); + } else { + holder = (Holder) convertView.getTag(); + } + + if (position == selectedItemIndex) { + convertView.setBackgroundColor(convertView.getResources().getColor( + ThemeUtils.getSelectionBackgroundColor())); + } else { + convertView.setBackgroundResource(0); + } + + holder.title.setText(request.getTitle()); + if (request.getStatusMsg() != 0) { + holder.message.setText(request.getStatusMsg()); + } + 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); + } + + holder.downloaded.setText(strDownloaded); + + holder.butSecondary.setFocusable(false); + holder.butSecondary.setTag(downloader); + holder.butSecondary.setOnClickListener(butSecondaryListener); + + return convertView; + } + + private View.OnClickListener butSecondaryListener = new View.OnClickListener() { + @Override + public void onClick(View v) { + Downloader downloader = (Downloader) v.getTag(); + itemAccess.onSecondaryActionClick(downloader); + } + }; + + static class Holder { + TextView title; + TextView message; + TextView downloaded; + TextView percent; + ProgressBar progbar; + ImageButton butSecondary; + } + + public int getSelectedItemIndex() { + return selectedItemIndex; + } + + public void setSelectedItemIndex(int selectedItemIndex) { + this.selectedItemIndex = selectedItemIndex; + notifyDataSetChanged(); + } + + public interface ItemAccess { + public int getCount(); + + public Downloader getItem(int position); + + public void onSecondaryActionClick(Downloader downloader); + } + +} diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/ExternalEpisodesListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/ExternalEpisodesListAdapter.java new file mode 100644 index 000000000..8b1ed9112 --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/adapter/ExternalEpisodesListAdapter.java @@ -0,0 +1,306 @@ +package de.danoeh.antennapod.adapter; + +import android.content.Context; +import android.content.res.TypedArray; +import android.view.LayoutInflater; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.widget.BaseExpandableListAdapter; +import android.widget.ImageButton; +import android.widget.ImageView; +import android.widget.ProgressBar; +import android.widget.TextView; + +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.core.asynctask.PicassoProvider; +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; + +/** + * Displays unread items and items in the queue in one combined list. The + * structure of this list is: [header] [queueItems] [header] [unreadItems]. + */ +public class ExternalEpisodesListAdapter extends BaseExpandableListAdapter { + private static final String TAG = "ExternalEpisodesListAdapter"; + + public static final int GROUP_POS_QUEUE = 0; + public static final int GROUP_POS_UNREAD = 1; + + private Context context; + private ItemAccess itemAccess; + + private ActionButtonCallback feedItemActionCallback; + private OnGroupActionClicked groupActionCallback; + + private final int imageSize; + + public ExternalEpisodesListAdapter(Context context, + ActionButtonCallback callback, + OnGroupActionClicked groupActionCallback, + ItemAccess itemAccess) { + super(); + this.context = context; + this.itemAccess = itemAccess; + this.feedItemActionCallback = callback; + this.groupActionCallback = groupActionCallback; + this.imageSize = (int) context.getResources().getDimension(R.dimen.thumbnail_length); + } + + @Override + public boolean areAllItemsEnabled() { + return true; + } + + @Override + public FeedItem getChild(int groupPosition, int childPosition) { + if (groupPosition == GROUP_POS_QUEUE) { + return itemAccess.getQueueItemAt(childPosition); + } else if (groupPosition == GROUP_POS_UNREAD) { + return itemAccess.getUnreadItemAt(childPosition); + } + return null; + } + + @Override + public long getChildId(int groupPosition, int childPosition) { + return childPosition; + } + + @Override + public View getChildView(int groupPosition, final int childPosition, + boolean isLastChild, View convertView, ViewGroup parent) { + Holder holder; + final FeedItem item = getChild(groupPosition, childPosition); + + if (convertView == null) { + holder = new Holder(); + LayoutInflater inflater = (LayoutInflater) context + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + convertView = inflater.inflate(R.layout.external_itemlist_item, + parent, false); + holder.title = (TextView) convertView.findViewById(R.id.txtvTitle); + holder.feedTitle = (TextView) convertView + .findViewById(R.id.txtvFeedname); + holder.lenSize = (TextView) convertView + .findViewById(R.id.txtvLenSize); + holder.downloadStatus = (ImageView) convertView + .findViewById(R.id.imgvDownloadStatus); + holder.feedImage = (ImageView) convertView + .findViewById(R.id.imgvFeedimage); + holder.butAction = (ImageButton) convertView + .findViewById(R.id.butAction); + holder.statusPlaying = (View) convertView + .findViewById(R.id.statusPlaying); + holder.episodeProgress = (ProgressBar) convertView + .findViewById(R.id.pbar_episode_progress); + convertView.setTag(holder); + } else { + holder = (Holder) convertView.getTag(); + } + + holder.title.setText(item.getTitle()); + holder.feedTitle.setText(item.getFeed().getTitle()); + FeedItem.State state = item.getState(); + + if (groupPosition == GROUP_POS_QUEUE) { + switch (state) { + case PLAYING: + holder.statusPlaying.setVisibility(View.VISIBLE); + holder.episodeProgress.setVisibility(View.VISIBLE); + break; + case IN_PROGRESS: + holder.statusPlaying.setVisibility(View.GONE); + holder.episodeProgress.setVisibility(View.VISIBLE); + break; + case NEW: + holder.statusPlaying.setVisibility(View.GONE); + holder.episodeProgress.setVisibility(View.GONE); + break; + default: + holder.statusPlaying.setVisibility(View.GONE); + holder.episodeProgress.setVisibility(View.GONE); + break; + } + } else { + holder.statusPlaying.setVisibility(View.GONE); + holder.episodeProgress.setVisibility(View.GONE); + } + + FeedMedia media = item.getMedia(); + if (media != null) { + + if (state == FeedItem.State.PLAYING + || state == FeedItem.State.IN_PROGRESS) { + if (media.getDuration() > 0) { + holder.episodeProgress.setProgress((int) (((double) media + .getPosition()) / media.getDuration() * 100)); + holder.lenSize.setText(Converter + .getDurationStringLong(media.getDuration() + - media.getPosition())); + } + } else if (!media.isDownloaded()) { + holder.lenSize.setText(context.getString(R.string.size_prefix) + + Converter.byteToString(media.getSize())); + } else { + holder.lenSize.setText(context + .getString(R.string.length_prefix) + + Converter.getDurationStringLong(media.getDuration())); + } + + TypedArray drawables = context.obtainStyledAttributes(new int[]{ + R.attr.av_download, R.attr.navigation_refresh}); + final int[] labels = new int[]{R.string.status_downloaded_label, R.string.downloading_label}; + holder.lenSize.setVisibility(View.VISIBLE); + if (!media.isDownloaded()) { + if (DownloadRequester.getInstance().isDownloadingFile(media)) { + holder.downloadStatus.setVisibility(View.VISIBLE); + holder.downloadStatus.setImageDrawable(drawables + .getDrawable(1)); + holder.downloadStatus.setContentDescription(context.getString(labels[1])); + } else { + holder.downloadStatus.setVisibility(View.INVISIBLE); + } + } else { + holder.downloadStatus.setVisibility(View.VISIBLE); + holder.downloadStatus + .setImageDrawable(drawables.getDrawable(0)); + holder.downloadStatus.setContentDescription(context.getString(labels[0])); + } + } else { + holder.downloadStatus.setVisibility(View.INVISIBLE); + holder.lenSize.setVisibility(View.INVISIBLE); + } + + PicassoProvider.getMediaMetadataPicassoInstance(context) + .load(item.getImageUri()) + .fit() + .into(holder.feedImage); + + holder.butAction.setFocusable(false); + holder.butAction.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + feedItemActionCallback.onActionButtonPressed(item); + } + }); + + return convertView; + + } + + static class Holder { + TextView title; + TextView feedTitle; + TextView lenSize; + ImageView downloadStatus; + ImageView feedImage; + ImageButton butAction; + View statusPlaying; + ProgressBar episodeProgress; + } + + @Override + public int getChildrenCount(int groupPosition) { + if (groupPosition == GROUP_POS_QUEUE) { + return itemAccess.getQueueSize(); + } else if (groupPosition == GROUP_POS_UNREAD) { + return itemAccess.getUnreadItemsSize(); + } + return 0; + } + + @Override + public int getGroupCount() { + // Hide 'unread items' group if empty + if (itemAccess.getUnreadItemsSize() > 0) { + return 2; + } else { + return 1; + } + } + + @Override + public long getGroupId(int groupPosition) { + return groupPosition; + } + + @Override + public View getGroupView(final int groupPosition, boolean isExpanded, + View convertView, ViewGroup parent) { + LayoutInflater inflater = (LayoutInflater) context + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + convertView = inflater.inflate(R.layout.feeditemlist_header, parent, false); + TextView headerTitle = (TextView) convertView + .findViewById(0); + ImageButton actionButton = (ImageButton) convertView + .findViewById(R.id.butAction); + TextView numItems = (TextView) convertView.findViewById(0); + + String headerString = null; + int childrenCount = 0; + + if (groupPosition == 0) { + headerString = context.getString(R.string.queue_label); + childrenCount = getChildrenCount(GROUP_POS_QUEUE); + } else { + headerString = context.getString(R.string.waiting_list_label); + childrenCount = getChildrenCount(GROUP_POS_UNREAD); + } + headerTitle.setText(headerString); + if (childrenCount <= 0) { + numItems.setVisibility(View.INVISIBLE); + } else { + numItems.setVisibility(View.VISIBLE); + numItems.setText(Integer.toString(childrenCount)); + } + actionButton.setFocusable(false); + actionButton.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + groupActionCallback.onClick(getGroupId(groupPosition)); + } + }); + return convertView; + } + + @Override + public boolean isEmpty() { + return itemAccess.getUnreadItemsSize() == 0 + && itemAccess.getQueueSize() == 0; + } + + @Override + public Object getGroup(int groupPosition) { + return null; + } + + @Override + public boolean hasStableIds() { + return true; + } + + @Override + public boolean isChildSelectable(int groupPosition, int childPosition) { + return true; + } + + public interface OnGroupActionClicked { + public void onClick(long groupId); + } + + public static interface ItemAccess { + public int getQueueSize(); + + public int getUnreadItemsSize(); + + public FeedItem getQueueItemAt(int position); + + public FeedItem getUnreadItemAt(int position); + } + +} diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java new file mode 100644 index 000000000..2f69e6580 --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java @@ -0,0 +1,219 @@ +package de.danoeh.antennapod.adapter; + +import android.content.Context; +import android.content.res.TypedArray; +import android.text.format.DateUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.widget.*; +import de.danoeh.antennapod.R; +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.ThemeUtils; + +/** + * List adapter for items of feeds that the user has already subscribed to. + */ +public class FeedItemlistAdapter extends BaseAdapter { + + private ActionButtonCallback callback; + private final ItemAccess itemAccess; + private final Context context; + private boolean showFeedtitle; + private int selectedItemIndex; + private final ActionButtonUtils actionButtonUtils; + + public static final int SELECTION_NONE = -1; + + public FeedItemlistAdapter(Context context, + ItemAccess itemAccess, + ActionButtonCallback callback, boolean showFeedtitle) { + super(); + this.callback = callback; + this.context = context; + this.itemAccess = itemAccess; + this.showFeedtitle = showFeedtitle; + this.selectedItemIndex = SELECTION_NONE; + this.actionButtonUtils = new ActionButtonUtils(context); + } + + @Override + public int getCount() { + return itemAccess.getCount(); + + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public FeedItem getItem(int position) { + return itemAccess.getItem(position); + } + + @Override + public View getView(final int position, View convertView, ViewGroup parent) { + Holder holder; + final FeedItem item = getItem(position); + + 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.title = (TextView) convertView + .findViewById(R.id.txtvItemname); + holder.lenSize = (TextView) convertView + .findViewById(R.id.txtvLenSize); + holder.butAction = (ImageButton) convertView + .findViewById(R.id.butSecondaryAction); + holder.published = (TextView) convertView + .findViewById(R.id.txtvPublished); + holder.inPlaylist = (ImageView) convertView + .findViewById(R.id.imgvInPlaylist); + holder.type = (ImageView) convertView.findViewById(R.id.imgvType); + holder.statusUnread = (View) convertView + .findViewById(R.id.statusUnread); + holder.episodeProgress = (ProgressBar) convertView + .findViewById(R.id.pbar_episode_progress); + + convertView.setTag(holder); + } else { + holder = (Holder) convertView.getTag(); + } + if (!(getItemViewType(position) == Adapter.IGNORE_ITEM_VIEW_TYPE)) { + convertView.setVisibility(View.VISIBLE); + if (position == selectedItemIndex) { + convertView.setBackgroundColor(convertView.getResources() + .getColor(ThemeUtils.getSelectionBackgroundColor())); + } else { + convertView.setBackgroundResource(0); + } + + StringBuilder buffer = new StringBuilder(item.getTitle()); + if (showFeedtitle) { + buffer.append("("); + buffer.append(item.getFeed().getTitle()); + buffer.append(")"); + } + holder.title.setText(buffer.toString()); + + FeedItem.State state = item.getState(); + switch (state) { + case PLAYING: + holder.statusUnread.setVisibility(View.GONE); + holder.episodeProgress.setVisibility(View.VISIBLE); + break; + case IN_PROGRESS: + holder.statusUnread.setVisibility(View.GONE); + holder.episodeProgress.setVisibility(View.VISIBLE); + break; + case NEW: + holder.statusUnread.setVisibility(View.VISIBLE); + break; + default: + holder.statusUnread.setVisibility(View.GONE); + break; + } + + holder.published.setText(DateUtils.formatDateTime(context, item.getPubDate().getTime(), DateUtils.FORMAT_SHOW_DATE)); + + + FeedMedia media = item.getMedia(); + if (media == null) { + holder.episodeProgress.setVisibility(View.GONE); + holder.inPlaylist.setVisibility(View.INVISIBLE); + holder.type.setVisibility(View.INVISIBLE); + holder.lenSize.setVisibility(View.INVISIBLE); + } else { + + AdapterUtils.updateEpisodePlaybackProgress(item, context.getResources(), holder.lenSize, holder.episodeProgress); + + if (((ItemAccess) itemAccess).isInQueue(item)) { + 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) itemAccess).getItemDownloadProgressPercent(item)); + } + + 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); + } + } + + actionButtonUtils.configureActionButton(holder.butAction, item); + holder.butAction.setFocusable(false); + holder.butAction.setTag(item); + holder.butAction.setOnClickListener(butActionListener); + + } else { + convertView.setVisibility(View.GONE); + } + return convertView; + + } + + private final OnClickListener butActionListener = new OnClickListener() { + @Override + public void onClick(View v) { + FeedItem item = (FeedItem) v.getTag(); + callback.onActionButtonPressed(item); + } + }; + + static class Holder { + TextView title; + TextView published; + TextView lenSize; + ImageView type; + ImageView inPlaylist; + ImageButton butAction; + View statusUnread; + ProgressBar episodeProgress; + } + + public int getSelectedItemIndex() { + return selectedItemIndex; + } + + public void setSelectedItemIndex(int selectedItemIndex) { + this.selectedItemIndex = selectedItemIndex; + notifyDataSetChanged(); + } + + public static interface ItemAccess { + public boolean isInQueue(FeedItem item); + + int getItemDownloadProgressPercent(FeedItem item); + + int getCount(); + + FeedItem getItem(int position); + } + +} diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistDescriptionAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistDescriptionAdapter.java new file mode 100644 index 000000000..9011c8b02 --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/adapter/FeedItemlistDescriptionAdapter.java @@ -0,0 +1,55 @@ +package de.danoeh.antennapod.adapter; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.TextView; +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.core.feed.FeedItem; + +import java.util.List; + +/** + * List adapter for showing a list of FeedItems with their title and description. + */ +public class FeedItemlistDescriptionAdapter extends ArrayAdapter<FeedItem> { + + public FeedItemlistDescriptionAdapter(Context context, int resource, List<FeedItem> objects) { + super(context, resource, objects); + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + Holder holder; + + FeedItem item = getItem(position); + + // Inflate layout + if (convertView == null) { + holder = new Holder(); + LayoutInflater inflater = (LayoutInflater) getContext() + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + convertView = inflater.inflate(R.layout.itemdescription_listitem, parent, false); + holder.title = (TextView) convertView.findViewById(R.id.txtvTitle); + holder.description = (TextView) convertView.findViewById(R.id.txtvDescription); + + convertView.setTag(holder); + } else { + holder = (Holder) convertView.getTag(); + } + + holder.title.setText(item.getTitle()); + if (item.getDescription() != null) { + holder.description.setText(item.getDescription()); + } + + return convertView; + } + + static class Holder { + TextView title; + TextView description; + } +} diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java new file mode 100644 index 000000000..a917633e6 --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java @@ -0,0 +1,229 @@ +package de.danoeh.antennapod.adapter; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Typeface; +import android.graphics.drawable.Drawable; +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 de.danoeh.antennapod.R; +import de.danoeh.antennapod.core.asynctask.PicassoProvider; +import de.danoeh.antennapod.core.feed.Feed; + +/** + * BaseAdapter for the navigation drawer + */ +public class NavListAdapter extends BaseAdapter { + public static final int VIEW_TYPE_COUNT = 3; + public static final int VIEW_TYPE_NAV = 0; + public static final int VIEW_TYPE_SECTION_DIVIDER = 1; + public static final int VIEW_TYPE_SUBSCRIPTION = 2; + + public static final int[] NAV_TITLES = {R.string.all_episodes_label, R.string.queue_label, R.string.downloads_label, R.string.playback_history_label, R.string.add_feed_label}; + + private final Drawable[] drawables; + + public static final int SUBSCRIPTION_OFFSET = 1 + NAV_TITLES.length; + + private ItemAccess itemAccess; + private Context context; + + public NavListAdapter(ItemAccess itemAccess, Context context) { + this.itemAccess = itemAccess; + this.context = context; + + TypedArray ta = context.obtainStyledAttributes(new int[]{R.attr.ic_new, R.attr.stat_playlist, + R.attr.av_download, R.attr.device_access_time, R.attr.content_new}); + drawables = new Drawable[]{ta.getDrawable(0), ta.getDrawable(1), ta.getDrawable(2), + ta.getDrawable(3), ta.getDrawable(4)}; + ta.recycle(); + } + + @Override + public int getCount() { + return NAV_TITLES.length + 1 + itemAccess.getCount(); + } + + @Override + public Object getItem(int position) { + int viewType = getItemViewType(position); + if (viewType == VIEW_TYPE_NAV) { + return context.getString(NAV_TITLES[position]); + } else if (viewType == VIEW_TYPE_SECTION_DIVIDER) { + return context.getString(R.string.podcasts_label); + } else { + return itemAccess.getItem(position); + } + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public int getItemViewType(int position) { + if (0 <= position && position < NAV_TITLES.length) { + return VIEW_TYPE_NAV; + } else if (position < NAV_TITLES.length + 1) { + return VIEW_TYPE_SECTION_DIVIDER; + } else { + return VIEW_TYPE_SUBSCRIPTION; + } + } + + @Override + public int getViewTypeCount() { + return VIEW_TYPE_COUNT; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + int viewType = getItemViewType(position); + View v = null; + if (viewType == VIEW_TYPE_NAV) { + v = getNavView((String) getItem(position), position, convertView, parent); + } else if (viewType == VIEW_TYPE_SECTION_DIVIDER) { + v = getSectionDividerView((String) getItem(position), position, convertView, parent); + } else { + v = getFeedView(position - SUBSCRIPTION_OFFSET, convertView, parent); + } + if (v != null) { + TextView txtvTitle = (TextView) v.findViewById(R.id.txtvTitle); + if (position == itemAccess.getSelectedItemIndex()) { + txtvTitle.setTypeface(null, Typeface.BOLD); + } else { + txtvTitle.setTypeface(null, Typeface.NORMAL); + } + } + return v; + } + + private View getNavView(String title, int position, View convertView, ViewGroup parent) { + NavHolder holder; + if (convertView == null) { + holder = new NavHolder(); + LayoutInflater inflater = (LayoutInflater) context + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + + convertView = inflater.inflate(R.layout.nav_listitem, parent, false); + + holder.title = (TextView) convertView.findViewById(R.id.txtvTitle); + holder.count = (TextView) convertView.findViewById(R.id.txtvCount); + holder.image = (ImageView) convertView.findViewById(R.id.imgvCover); + convertView.setTag(holder); + } else { + holder = (NavHolder) convertView.getTag(); + } + + holder.title.setText(title); + + if (NAV_TITLES[position] == R.string.queue_label) { + int queueSize = itemAccess.getQueueSize(); + if (queueSize > 0) { + holder.count.setVisibility(View.VISIBLE); + holder.count.setText(String.valueOf(queueSize)); + } else { + holder.count.setVisibility(View.GONE); + } + } else if (NAV_TITLES[position] == R.string.all_episodes_label) { + int unreadItems = itemAccess.getNumberOfUnreadItems(); + if (unreadItems > 0) { + holder.count.setVisibility(View.VISIBLE); + holder.count.setText(String.valueOf(unreadItems)); + } else { + holder.count.setVisibility(View.GONE); + } + } else { + holder.count.setVisibility(View.GONE); + } + + holder.image.setImageDrawable(drawables[position]); + + return convertView; + } + + private View getSectionDividerView(String title, int position, View convertView, ViewGroup parent) { + SectionHolder holder; + if (convertView == null) { + holder = new SectionHolder(); + LayoutInflater inflater = (LayoutInflater) context + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + + convertView = inflater.inflate(R.layout.nav_section_item, parent, false); + + holder.title = (TextView) convertView.findViewById(R.id.txtvTitle); + convertView.setTag(holder); + } else { + holder = (SectionHolder) convertView.getTag(); + } + + holder.title.setText(title); + + convertView.setEnabled(false); + convertView.setOnClickListener(null); + + return convertView; + } + + private View getFeedView(int feedPos, View convertView, ViewGroup parent) { + FeedHolder holder; + Feed feed = itemAccess.getItem(feedPos); + + if (convertView == null) { + holder = new FeedHolder(); + LayoutInflater inflater = (LayoutInflater) context + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + + convertView = inflater.inflate(R.layout.nav_feedlistitem, parent, false); + + holder.title = (TextView) convertView.findViewById(R.id.txtvTitle); + holder.image = (ImageView) convertView.findViewById(R.id.imgvCover); + convertView.setTag(holder); + } else { + holder = (FeedHolder) convertView.getTag(); + } + + holder.title.setText(feed.getTitle()); + + PicassoProvider.getDefaultPicassoInstance(context) + .load(feed.getImageUri()) + .fit() + .into(holder.image); + + return convertView; + } + + static class NavHolder { + TextView title; + TextView count; + ImageView image; + } + + static class SectionHolder { + TextView title; + } + + static class FeedHolder { + TextView title; + ImageView image; + } + + + public interface ItemAccess { + public int getCount(); + + public Feed getItem(int position); + + public int getSelectedItemIndex(); + + public int getQueueSize(); + + public int getNumberOfUnreadItems(); + } + +} diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/NewEpisodesListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/NewEpisodesListAdapter.java new file mode 100644 index 000000000..a0829286c --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/adapter/NewEpisodesListAdapter.java @@ -0,0 +1,170 @@ +package de.danoeh.antennapod.adapter; + +import android.content.Context; +import android.text.format.DateUtils; +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.ProgressBar; +import android.widget.TextView; + +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.core.asynctask.PicassoProvider; +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; + +/** + * List adapter for the list of new episodes + */ +public class NewEpisodesListAdapter extends BaseAdapter { + + private final Context context; + private final ItemAccess itemAccess; + private final ActionButtonCallback actionButtonCallback; + private final ActionButtonUtils actionButtonUtils; + + public NewEpisodesListAdapter(Context context, ItemAccess itemAccess, ActionButtonCallback actionButtonCallback) { + super(); + this.context = context; + this.itemAccess = itemAccess; + this.actionButtonUtils = new ActionButtonUtils(context); + this.actionButtonCallback = actionButtonCallback; + } + + @Override + public int getCount() { + return itemAccess.getCount(); + } + + @Override + public Object getItem(int position) { + return itemAccess.getItem(position); + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public int getViewTypeCount() { + return 1; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + Holder holder; + final FeedItem item = (FeedItem) getItem(position); + if (item == null) return null; + + if (convertView == null) { + holder = new Holder(); + LayoutInflater inflater = (LayoutInflater) context + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + convertView = inflater.inflate(R.layout.new_episodes_listitem, + parent, false); + holder.title = (TextView) convertView.findViewById(R.id.txtvTitle); + holder.pubDate = (TextView) convertView + .findViewById(R.id.txtvPublished); + holder.statusUnread = convertView.findViewById(R.id.statusUnread); + holder.butSecondary = (ImageButton) convertView + .findViewById(R.id.butSecondaryAction); + holder.queueStatus = (ImageView) convertView + .findViewById(R.id.imgvInPlaylist); + holder.downloadProgress = (ProgressBar) convertView + .findViewById(R.id.pbar_download_progress); + holder.imageView = (ImageView) convertView.findViewById(R.id.imgvImage); + holder.txtvDuration = (TextView) convertView.findViewById(R.id.txtvDuration); + convertView.setTag(holder); + } else { + holder = (Holder) convertView.getTag(); + } + + holder.title.setText(item.getTitle()); + holder.pubDate.setText(DateUtils.formatDateTime(context, item.getPubDate().getTime(), DateUtils.FORMAT_SHOW_DATE)); + if (item.isRead()) { + holder.statusUnread.setVisibility(View.GONE); + } else { + holder.statusUnread.setVisibility(View.VISIBLE); + } + + 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 { + holder.txtvDuration.setText(""); + } + + if (isDownloadingMedia) { + holder.downloadProgress.setVisibility(View.VISIBLE); + holder.txtvDuration.setVisibility(View.GONE); + } else { + holder.txtvDuration.setVisibility(View.VISIBLE); + holder.downloadProgress.setVisibility(View.GONE); + } + + if (!media.isDownloaded()) { + if (isDownloadingMedia) { + // item is being downloaded + holder.downloadProgress.setProgress(itemAccess.getItemDownloadProgressPercent(item)); + } + } + } + if (itemAccess.isInQueue(item)) { + holder.queueStatus.setVisibility(View.VISIBLE); + } else { + holder.queueStatus.setVisibility(View.INVISIBLE); + } + + actionButtonUtils.configureActionButton(holder.butSecondary, item); + holder.butSecondary.setFocusable(false); + holder.butSecondary.setTag(item); + holder.butSecondary.setOnClickListener(secondaryActionListener); + + PicassoProvider.getMediaMetadataPicassoInstance(context) + .load(item.getImageUri()) + .fit() + .into(holder.imageView); + + return convertView; + } + + private View.OnClickListener secondaryActionListener = new View.OnClickListener() { + @Override + public void onClick(View v) { + FeedItem item = (FeedItem) v.getTag(); + actionButtonCallback.onActionButtonPressed(item); + } + }; + + + static class Holder { + TextView title; + TextView pubDate; + View statusUnread; + ImageView queueStatus; + ImageView imageView; + ProgressBar downloadProgress; + TextView txtvDuration; + ImageButton butSecondary; + } + + public interface ItemAccess { + + int getCount(); + + FeedItem getItem(int position); + + int getItemDownloadProgressPercent(FeedItem item); + + boolean isInQueue(FeedItem item); + } +} diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/QueueListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/QueueListAdapter.java new file mode 100644 index 000000000..bc42ad063 --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/adapter/QueueListAdapter.java @@ -0,0 +1,127 @@ +package de.danoeh.antennapod.adapter; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.*; +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.core.asynctask.PicassoProvider; +import de.danoeh.antennapod.core.feed.FeedItem; +import de.danoeh.antennapod.core.feed.FeedMedia; +import de.danoeh.antennapod.core.storage.DownloadRequester; + +/** + * List adapter for the queue. + */ +public class QueueListAdapter extends BaseAdapter { + + + private final Context context; + private final ItemAccess itemAccess; + private final ActionButtonCallback actionButtonCallback; + private final ActionButtonUtils actionButtonUtils; + + + public QueueListAdapter(Context context, ItemAccess itemAccess, ActionButtonCallback actionButtonCallback) { + super(); + this.context = context; + this.itemAccess = itemAccess; + this.actionButtonUtils = new ActionButtonUtils(context); + this.actionButtonCallback = actionButtonCallback; + } + + @Override + public int getCount() { + return itemAccess.getCount(); + } + + @Override + public Object getItem(int position) { + return itemAccess.getItem(position); + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + Holder holder; + final FeedItem item = (FeedItem) getItem(position); + if (item == null) return null; + + if (convertView == null) { + holder = new Holder(); + LayoutInflater inflater = (LayoutInflater) context + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + convertView = inflater.inflate(R.layout.queue_listitem, + parent, false); + holder.title = (TextView) convertView.findViewById(R.id.txtvTitle); + holder.butSecondary = (ImageButton) convertView + .findViewById(R.id.butSecondaryAction); + holder.position = (TextView) convertView.findViewById(R.id.txtvPosition); + holder.progress = (ProgressBar) convertView + .findViewById(R.id.pbar_download_progress); + holder.imageView = (ImageView) convertView.findViewById(R.id.imgvImage); + convertView.setTag(holder); + } else { + holder = (Holder) convertView.getTag(); + } + + holder.title.setText(item.getTitle()); + + AdapterUtils.updateEpisodePlaybackProgress(item, context.getResources(), holder.position, holder.progress); + + FeedMedia media = item.getMedia(); + if (media != null) { + final boolean isDownloadingMedia = DownloadRequester.getInstance().isDownloadingFile(media); + + if (!media.isDownloaded()) { + if (isDownloadingMedia) { + // item is being downloaded + holder.progress.setVisibility(View.VISIBLE); + holder.progress.setProgress(itemAccess.getItemDownloadProgressPercent(item)); + } + } + } + + actionButtonUtils.configureActionButton(holder.butSecondary, item); + holder.butSecondary.setFocusable(false); + holder.butSecondary.setTag(item); + holder.butSecondary.setOnClickListener(secondaryActionListener); + + PicassoProvider.getMediaMetadataPicassoInstance(context) + .load(item.getImageUri()) + .fit() + .into(holder.imageView); + + return convertView; + } + + private View.OnClickListener secondaryActionListener = new View.OnClickListener() { + @Override + public void onClick(View v) { + FeedItem item = (FeedItem) v.getTag(); + actionButtonCallback.onActionButtonPressed(item); + } + }; + + + static class Holder { + TextView title; + ImageView imageView; + TextView position; + ProgressBar progress; + ImageButton butSecondary; + } + + public interface ItemAccess { + int getCount(); + + FeedItem getItem(int position); + + int getItemDownloadProgressPercent(FeedItem item); + } +} diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/SearchlistAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/SearchlistAdapter.java new file mode 100644 index 000000000..79c1f6f99 --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/adapter/SearchlistAdapter.java @@ -0,0 +1,110 @@ +package de.danoeh.antennapod.adapter; + +import android.content.Context; +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 de.danoeh.antennapod.R; +import de.danoeh.antennapod.core.asynctask.PicassoProvider; +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.feed.SearchResult; + +/** + * 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 SearchResult 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; + SearchResult result = getItem(position); + FeedComponent component = result.getComponent(); + + // 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 = (TextView) convertView.findViewById(R.id.txtvTitle); + holder.cover = (ImageView) convertView + .findViewById(R.id.imgvFeedimage); + holder.subtitle = (TextView) 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); + + PicassoProvider.getDefaultPicassoInstance(context) + .load(feed.getImageUri()) + .fit() + .into(holder.cover); + + } else if (component.getClass() == FeedItem.class) { + final FeedItem item = (FeedItem) component; + holder.title.setText(item.getTitle()); + if (result.getSubtitle() != null) { + holder.subtitle.setVisibility(View.VISIBLE); + holder.subtitle.setText(result.getSubtitle()); + } + + PicassoProvider.getDefaultPicassoInstance(context) + .load(item.getFeed().getImageUri()) + .fit() + .into(holder.cover); + + } + + return convertView; + } + + static class Holder { + ImageView cover; + TextView title; + TextView subtitle; + } + + public static interface ItemAccess { + int getCount(); + + SearchResult getItem(int position); + } + +} diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/gpodnet/PodcastListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/gpodnet/PodcastListAdapter.java new file mode 100644 index 000000000..7bee8e861 --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/adapter/gpodnet/PodcastListAdapter.java @@ -0,0 +1,68 @@ +package de.danoeh.antennapod.adapter.gpodnet; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.ImageView; +import android.widget.TextView; + +import org.apache.commons.lang3.StringUtils; + +import java.util.List; + +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.core.asynctask.PicassoProvider; +import de.danoeh.antennapod.core.gpoddernet.model.GpodnetPodcast; + +/** + * Adapter for displaying a list of GPodnetPodcast-Objects. + */ +public class PodcastListAdapter extends ArrayAdapter<GpodnetPodcast> { + + public PodcastListAdapter(Context context, int resource, List<GpodnetPodcast> objects) { + super(context, resource, objects); + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + Holder holder; + + GpodnetPodcast podcast = getItem(position); + + // Inflate Layout + if (convertView == null) { + holder = new Holder(); + LayoutInflater inflater = (LayoutInflater) getContext() + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + + convertView = inflater.inflate(R.layout.gpodnet_podcast_listitem, parent, false); + holder.title = (TextView) convertView.findViewById(R.id.txtvTitle); + holder.description = (TextView) convertView.findViewById(R.id.txtvDescription); + holder.image = (ImageView) convertView.findViewById(R.id.imgvCover); + + convertView.setTag(holder); + } else { + holder = (Holder) convertView.getTag(); + } + + holder.title.setText(podcast.getTitle()); + holder.description.setText(podcast.getDescription()); + + if (StringUtils.isNoneBlank(podcast.getLogoUrl())) { + PicassoProvider.getDefaultPicassoInstance(convertView.getContext()) + .load(podcast.getLogoUrl()) + .fit() + .into(holder.image); + } + + return convertView; + } + + static class Holder { + TextView title; + TextView description; + ImageView image; + } +} |