summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordaniel oeh <daniel.oeh@gmail.com>2014-04-04 21:00:48 +0200
committerdaniel oeh <daniel.oeh@gmail.com>2014-04-04 21:00:48 +0200
commit66641ccdd96887fd3f5870b182d6b47957893f85 (patch)
tree7f37348b182fdc493bdb0224659cf966cd4f2799 /src
parent5b74a4cc39885e74488b31afc5071ab71e74ce21 (diff)
downloadAntennaPod-66641ccdd96887fd3f5870b182d6b47957893f85.zip
Added queue fragment
Diffstat (limited to 'src')
-rw-r--r--src/de/danoeh/antennapod/activity/MainActivity.java20
-rw-r--r--src/de/danoeh/antennapod/adapter/QueueListAdapter.java176
-rw-r--r--src/de/danoeh/antennapod/fragment/NewEpisodesFragment.java4
-rw-r--r--src/de/danoeh/antennapod/fragment/QueueFragment.java282
-rw-r--r--src/de/danoeh/antennapod/util/gui/FeedItemUndoToken.java55
5 files changed, 530 insertions, 7 deletions
diff --git a/src/de/danoeh/antennapod/activity/MainActivity.java b/src/de/danoeh/antennapod/activity/MainActivity.java
index 03f44a97d..3b2cc52e9 100644
--- a/src/de/danoeh/antennapod/activity/MainActivity.java
+++ b/src/de/danoeh/antennapod/activity/MainActivity.java
@@ -26,10 +26,7 @@ import de.danoeh.antennapod.R;
import de.danoeh.antennapod.asynctask.ImageLoader;
import de.danoeh.antennapod.feed.EventDistributor;
import de.danoeh.antennapod.feed.Feed;
-import de.danoeh.antennapod.fragment.EpisodesFragment;
-import de.danoeh.antennapod.fragment.ExternalPlayerFragment;
-import de.danoeh.antennapod.fragment.ItemlistFragment;
-import de.danoeh.antennapod.fragment.NewEpisodesFragment;
+import de.danoeh.antennapod.fragment.*;
import de.danoeh.antennapod.preferences.UserPreferences;
import de.danoeh.antennapod.storage.DBReader;
import de.danoeh.antennapod.util.StorageUtils;
@@ -126,8 +123,15 @@ public class MainActivity extends ActionBarActivity {
FragmentTransaction fT = fragmentManager.beginTransaction();
Fragment fragment = null;
if (viewType == NavListAdapter.VIEW_TYPE_NAV) {
+ switch (relPos) {
+ case 0:
+ fragment = new NewEpisodesFragment();
+ break;
+ case 1:
+ fragment = new QueueFragment();
+ break;
+ }
currentTitle = getString(NavListAdapter.NAV_TITLES[relPos]);
- fragment = new NewEpisodesFragment();
} else if (viewType == NavListAdapter.VIEW_TYPE_SUBSCRIPTION) {
Feed feed = itemAccess.getItem(relPos);
@@ -145,13 +149,13 @@ public class MainActivity extends ActionBarActivity {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
int viewType = parent.getAdapter().getItemViewType(position);
- if (viewType != NavListAdapter.VIEW_TYPE_SECTION_DIVIDER) {
+ if (viewType != NavListAdapter.VIEW_TYPE_SECTION_DIVIDER && position != selectedNavListIndex) {
int relPos = (viewType == NavListAdapter.VIEW_TYPE_NAV) ? position : position - NavListAdapter.SUBSCRIPTION_OFFSET;
loadFragment(viewType, relPos);
- drawerLayout.closeDrawer(navList);
selectedNavListIndex = position;
navAdapter.notifyDataSetChanged();
}
+ drawerLayout.closeDrawer(navList);
}
};
@@ -164,6 +168,7 @@ public class MainActivity extends ActionBarActivity {
if (!drawerLayout.isDrawerOpen(navList)) {
getSupportActionBar().setTitle(currentTitle);
}
+ selectedNavListIndex = savedInstanceState.getInt("selectedNavIndex");
}
}
@@ -177,6 +182,7 @@ public class MainActivity extends ActionBarActivity {
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("title", currentTitle.toString());
+ outState.putInt("selectedNavIndex", selectedNavListIndex);
}
diff --git a/src/de/danoeh/antennapod/adapter/QueueListAdapter.java b/src/de/danoeh/antennapod/adapter/QueueListAdapter.java
new file mode 100644
index 000000000..ae53f6837
--- /dev/null
+++ b/src/de/danoeh/antennapod/adapter/QueueListAdapter.java
@@ -0,0 +1,176 @@
+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.ViewGroup;
+import android.widget.*;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.asynctask.ImageLoader;
+import de.danoeh.antennapod.feed.FeedItem;
+import de.danoeh.antennapod.feed.FeedMedia;
+import de.danoeh.antennapod.storage.DownloadRequester;
+import de.danoeh.antennapod.util.Converter;
+
+/**
+ * List adapter for the queue.
+ */
+public class QueueListAdapter extends BaseAdapter {
+
+
+ private final Context context;
+ private final ItemAccess itemAccess;
+ private final TypedArray drawables;
+ private final int[] labels;
+
+ public QueueListAdapter(Context context, ItemAccess itemAccess) {
+ super();
+ this.context = context;
+ this.itemAccess = itemAccess;
+ drawables = context.obtainStyledAttributes(new int[]{
+ R.attr.av_play, R.attr.navigation_cancel, R.attr.av_download});
+ labels = new int[]{R.string.play_label, R.string.cancel_download_label, R.string.download_label};
+ }
+
+ @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,
+ null);
+ 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.statusPlaying = (ImageView) convertView
+ .findViewById(R.id.statusPlaying);
+ 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));
+ FeedItem.State state = item.getState();
+
+ if (state == FeedItem.State.PLAYING) {
+ holder.statusPlaying.setVisibility(View.VISIBLE);
+ } else {
+ holder.statusPlaying.setVisibility(View.INVISIBLE);
+ }
+
+ 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.butSecondary.setVisibility(View.VISIBLE);
+ holder.butSecondary.setImageDrawable(drawables
+ .getDrawable(1));
+ holder.butSecondary.setContentDescription(context.getString(labels[1]));
+
+ holder.downloadProgress.setProgress(itemAccess.getItemDownloadProgressPercent(item));
+ } else {
+ // item is not downloaded and not being downloaded
+ holder.butSecondary.setVisibility(View.VISIBLE);
+ holder.butSecondary.setImageDrawable(drawables.getDrawable(2));
+ holder.butSecondary.setContentDescription(context.getString(labels[2]));
+ }
+ } else {
+ // item is not being downloaded
+ holder.butSecondary.setVisibility(View.VISIBLE);
+ holder.butSecondary
+ .setImageDrawable(drawables.getDrawable(0));
+ holder.butSecondary.setContentDescription(context.getString(labels[0]));
+ }
+ } else {
+ holder.butSecondary.setVisibility(View.INVISIBLE);
+ }
+
+ holder.butSecondary.setFocusable(false);
+ holder.butSecondary.setTag(item);
+ holder.butSecondary.setOnClickListener(secondaryActionListener);
+
+
+ ImageLoader.getInstance().loadThumbnailBitmap(
+ item,
+ holder.imageView,
+ (int) convertView.getResources().getDimension(
+ R.dimen.thumbnail_length)
+ );
+ 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;
+ ImageView statusPlaying;
+ ProgressBar downloadProgress;
+ TextView txtvDuration;
+ ImageButton butSecondary;
+ }
+
+ public interface ItemAccess {
+ int getCount();
+
+ FeedItem getItem(int position);
+
+ int getItemDownloadProgressPercent(FeedItem item);
+
+ void onFeedItemSecondaryAction(FeedItem item);
+ }
+}
diff --git a/src/de/danoeh/antennapod/fragment/NewEpisodesFragment.java b/src/de/danoeh/antennapod/fragment/NewEpisodesFragment.java
index aa3f9ab65..cb5632d05 100644
--- a/src/de/danoeh/antennapod/fragment/NewEpisodesFragment.java
+++ b/src/de/danoeh/antennapod/fragment/NewEpisodesFragment.java
@@ -111,6 +111,10 @@ public class NewEpisodesFragment extends Fragment {
txtvEmpty = (TextView) root.findViewById(android.R.id.empty);
progLoading = (ProgressBar) root.findViewById(R.id.progLoading);
+ if (!itemsLoaded) {
+ progLoading.setVisibility(View.VISIBLE);
+ txtvEmpty.setVisibility(View.GONE);
+ }
viewsCreated = true;
diff --git a/src/de/danoeh/antennapod/fragment/QueueFragment.java b/src/de/danoeh/antennapod/fragment/QueueFragment.java
new file mode 100644
index 000000000..a18994af5
--- /dev/null
+++ b/src/de/danoeh/antennapod/fragment/QueueFragment.java
@@ -0,0 +1,282 @@
+package de.danoeh.antennapod.fragment;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Parcelable;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+import com.mobeta.android.dslv.DragSortListView;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.MainActivity;
+import de.danoeh.antennapod.adapter.QueueListAdapter;
+import de.danoeh.antennapod.asynctask.DownloadObserver;
+import de.danoeh.antennapod.feed.EventDistributor;
+import de.danoeh.antennapod.feed.FeedItem;
+import de.danoeh.antennapod.feed.FeedMedia;
+import de.danoeh.antennapod.service.download.Downloader;
+import de.danoeh.antennapod.storage.DBReader;
+import de.danoeh.antennapod.storage.DBWriter;
+import de.danoeh.antennapod.util.UndoBarController;
+import de.danoeh.antennapod.util.gui.FeedItemUndoToken;
+
+import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * Shows all items in the queue
+ */
+public class QueueFragment extends Fragment {
+ private static final String TAG = "QueueFragment";
+ private static final int EVENTS = EventDistributor.DOWNLOAD_HANDLED |
+ EventDistributor.DOWNLOAD_QUEUED |
+ EventDistributor.QUEUE_UPDATE;
+
+ private DragSortListView listView;
+ private QueueListAdapter listAdapter;
+ private TextView txtvEmpty;
+ private ProgressBar progLoading;
+ private UndoBarController undoBarController;
+
+ private List<FeedItem> queue;
+ private List<Downloader> downloaderList;
+
+ private boolean itemsLoaded = false;
+ private boolean viewsCreated = false;
+
+ private AtomicReference<Activity> activity = new AtomicReference<Activity>();
+
+ private DownloadObserver downloadObserver = null;
+
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setRetainInstance(true);
+
+ startItemLoader();
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ EventDistributor.getInstance().register(contentUpdate);
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ EventDistributor.getInstance().unregister(contentUpdate);
+ stopItemLoader();
+ }
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ this.activity.set((MainActivity) activity);
+ if (downloadObserver != null) {
+ downloadObserver.setActivity(activity);
+ downloadObserver.onResume();
+ }
+ if (viewsCreated && itemsLoaded) {
+ onFragmentLoaded();
+ }
+
+
+ }
+
+ @Override
+ public void onDetach() {
+ super.onDetach();
+ listAdapter = null;
+ undoBarController = null;
+ activity.set(null);
+ viewsCreated = false;
+ if (downloadObserver != null) {
+ downloadObserver.onPause();
+ }
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ super.onCreateView(inflater, container, savedInstanceState);
+ View root = inflater.inflate(R.layout.queue_fragment, container, false);
+ listView = (DragSortListView) root.findViewById(android.R.id.list);
+ txtvEmpty = (TextView) root.findViewById(android.R.id.empty);
+ progLoading = (ProgressBar) root.findViewById(R.id.progLoading);
+ listView.setEmptyView(txtvEmpty);
+
+ listView.setDropListener(new DragSortListView.DropListener() {
+ @Override
+ public void drop(int from, int to) {
+ stopItemLoader();
+ final FeedItem item = queue.remove(from);
+ queue.add(to, item);
+ listAdapter.notifyDataSetChanged();
+ DBWriter.moveQueueItem(getActivity(), from, to, true);
+ }
+ });
+
+ listView.setRemoveListener(new DragSortListView.RemoveListener() {
+ @Override
+ public void remove(int which) {
+ stopItemLoader();
+ FeedItem item = (FeedItem) listView.getAdapter().getItem(which);
+ DBWriter.removeQueueItem(getActivity(), item.getId(), true);
+ undoBarController.showUndoBar(false,
+ getString(R.string.removed_from_queue), new FeedItemUndoToken(item,
+ which));
+ }
+ });
+
+ undoBarController = new UndoBarController(root.findViewById(R.id.undobar), new UndoBarController.UndoListener() {
+ @Override
+ public void onUndo(Parcelable token) {
+ // Perform the undo
+ FeedItemUndoToken undoToken = (FeedItemUndoToken) token;
+ if (token != null) {
+ long itemId = undoToken.getFeedItemId();
+ int position = undoToken.getPosition();
+ DBWriter.addQueueItemAt(getActivity(), itemId, position, false);
+ }
+ }
+ });
+
+ if (!itemsLoaded) {
+ progLoading.setVisibility(View.VISIBLE);
+ txtvEmpty.setVisibility(View.GONE);
+ }
+
+ viewsCreated = true;
+
+ if (itemsLoaded && activity.get() != null) {
+ onFragmentLoaded();
+ }
+
+ return root;
+ }
+
+ private void onFragmentLoaded() {
+ if (listAdapter == null) {
+ listAdapter = new QueueListAdapter(activity.get(), itemAccess);
+ listView.setAdapter(listAdapter);
+ downloadObserver = new DownloadObserver(activity.get(), new Handler(), downloadObserverCallback);
+ downloadObserver.onResume();
+ }
+ listAdapter.notifyDataSetChanged();
+ }
+
+ private DownloadObserver.Callback downloadObserverCallback = new DownloadObserver.Callback() {
+ @Override
+ public void onContentChanged() {
+ if (listAdapter != null) {
+ listAdapter.notifyDataSetChanged();
+ }
+ }
+
+ @Override
+ public void onDownloadDataAvailable(List<Downloader> downloaderList) {
+ QueueFragment.this.downloaderList = downloaderList;
+ if (listAdapter != null) {
+ listAdapter.notifyDataSetChanged();
+ }
+ }
+ };
+
+ private QueueListAdapter.ItemAccess itemAccess = new QueueListAdapter.ItemAccess() {
+ @Override
+ public int getCount() {
+ return (itemsLoaded) ? queue.size() : 0;
+ }
+
+ @Override
+ public FeedItem getItem(int position) {
+ return (itemsLoaded) ? queue.get(position) : null;
+ }
+
+ @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 void onFeedItemSecondaryAction(FeedItem item) {
+
+ }
+ };
+
+ private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
+ @Override
+ public void update(EventDistributor eventDistributor, Integer arg) {
+ if ((arg & EVENTS) != 0) {
+ startItemLoader();
+ }
+ }
+ };
+
+ private ItemLoader itemLoader;
+
+ private void startItemLoader() {
+ if (itemLoader != null) {
+ itemLoader.cancel(true);
+ }
+ itemLoader = new ItemLoader();
+ itemLoader.execute();
+ }
+
+ private void stopItemLoader() {
+ if (itemLoader != null) {
+ itemLoader.cancel(true);
+ }
+ }
+
+ private class ItemLoader extends AsyncTask<Void, Void, List<FeedItem>> {
+ @Override
+ protected void onPreExecute() {
+ super.onPreExecute();
+ if (viewsCreated && !itemsLoaded) {
+ listView.setVisibility(View.GONE);
+ txtvEmpty.setVisibility(View.GONE);
+ progLoading.setVisibility(View.VISIBLE);
+ }
+ }
+
+ @Override
+ protected void onPostExecute(List<FeedItem> feedItems) {
+ super.onPostExecute(feedItems);
+ listView.setVisibility(View.VISIBLE);
+ progLoading.setVisibility(View.GONE);
+
+ if (feedItems != null) {
+ queue = feedItems;
+ itemsLoaded = true;
+ if (viewsCreated && activity.get() != null) {
+ onFragmentLoaded();
+ }
+ }
+ }
+
+ @Override
+ protected List<FeedItem> doInBackground(Void... params) {
+ Context context = activity.get();
+ if (context != null) {
+ return DBReader.getQueue(context);
+ }
+ return null;
+ }
+ }
+}
diff --git a/src/de/danoeh/antennapod/util/gui/FeedItemUndoToken.java b/src/de/danoeh/antennapod/util/gui/FeedItemUndoToken.java
new file mode 100644
index 000000000..b920559db
--- /dev/null
+++ b/src/de/danoeh/antennapod/util/gui/FeedItemUndoToken.java
@@ -0,0 +1,55 @@
+package de.danoeh.antennapod.util.gui;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import de.danoeh.antennapod.feed.FeedItem;
+
+/**
+ * Used by an UndoBarController for saving a removed FeedItem
+ */
+public class FeedItemUndoToken implements Parcelable {
+ private long itemId;
+ private long feedId;
+ private int position;
+
+ public FeedItemUndoToken(FeedItem item, int position) {
+ this.itemId = item.getId();
+ this.feedId = item.getFeed().getId();
+ this.position = position;
+ }
+
+ private FeedItemUndoToken(Parcel in) {
+ itemId = in.readLong();
+ feedId = in.readLong();
+ position = in.readInt();
+ }
+
+ public static final Parcelable.Creator<FeedItemUndoToken> CREATOR = new Parcelable.Creator<FeedItemUndoToken>() {
+ public FeedItemUndoToken createFromParcel(Parcel in) {
+ return new FeedItemUndoToken(in);
+ }
+
+ public FeedItemUndoToken[] newArray(int size) {
+ return new FeedItemUndoToken[size];
+ }
+ };
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeLong(itemId);
+ out.writeLong(feedId);
+ out.writeInt(position);
+ }
+
+ public long getFeedItemId() {
+ return itemId;
+ }
+
+ public int getPosition() {
+ return position;
+ }
+}
+