diff options
18 files changed, 731 insertions, 18 deletions
diff --git a/res/drawable-hdpi/ic_drag_handle.png b/res/drawable-hdpi/ic_drag_handle.png Binary files differnew file mode 100755 index 000000000..38ec201de --- /dev/null +++ b/res/drawable-hdpi/ic_drag_handle.png diff --git a/res/drawable-hdpi/ic_drag_handle_dark.png b/res/drawable-hdpi/ic_drag_handle_dark.png Binary files differnew file mode 100755 index 000000000..e96d23252 --- /dev/null +++ b/res/drawable-hdpi/ic_drag_handle_dark.png diff --git a/res/drawable-mdpi/ic_drag_handle.png b/res/drawable-mdpi/ic_drag_handle.png Binary files differnew file mode 100755 index 000000000..4afbdc67d --- /dev/null +++ b/res/drawable-mdpi/ic_drag_handle.png diff --git a/res/drawable-mdpi/ic_drag_handle_dark.png b/res/drawable-mdpi/ic_drag_handle_dark.png Binary files differnew file mode 100755 index 000000000..2b25c4101 --- /dev/null +++ b/res/drawable-mdpi/ic_drag_handle_dark.png diff --git a/res/drawable-xhdpi/ic_drag_handle.png b/res/drawable-xhdpi/ic_drag_handle.png Binary files differnew file mode 100755 index 000000000..5bdcac342 --- /dev/null +++ b/res/drawable-xhdpi/ic_drag_handle.png diff --git a/res/drawable-xhdpi/ic_drag_handle_dark.png b/res/drawable-xhdpi/ic_drag_handle_dark.png Binary files differnew file mode 100755 index 000000000..d341c7c82 --- /dev/null +++ b/res/drawable-xhdpi/ic_drag_handle_dark.png diff --git a/res/drawable-xxhdpi/ic_drag_handle.png b/res/drawable-xxhdpi/ic_drag_handle.png Binary files differnew file mode 100755 index 000000000..f834699c6 --- /dev/null +++ b/res/drawable-xxhdpi/ic_drag_handle.png diff --git a/res/drawable-xxhdpi/ic_drag_handle_dark.png b/res/drawable-xxhdpi/ic_drag_handle_dark.png Binary files differnew file mode 100755 index 000000000..a9408bc9d --- /dev/null +++ b/res/drawable-xxhdpi/ic_drag_handle_dark.png diff --git a/res/layout/new_episodes_fragment.xml b/res/layout/new_episodes_fragment.xml index d8276cf38..460fe73d0 100644 --- a/res/layout/new_episodes_fragment.xml +++ b/res/layout/new_episodes_fragment.xml @@ -1,10 +1,10 @@ <?xml version="1.0" encoding="utf-8"?> -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:dslv="http://schemas.android.com/apk/res-auto" - android:orientation="vertical" - android:layout_width="match_parent" - android:layout_height="match_parent"> +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:dslv="http://schemas.android.com/apk/res-auto" + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent"> <com.mobeta.android.dslv.DragSortListView android:id="@android:id/list" @@ -24,7 +24,7 @@ dslv:sort_enabled="false" dslv:track_drag_sort="false" dslv:float_background_color="?attr/dragview_float_background" - dslv:use_default_controller="true" /> + dslv:use_default_controller="true"/> <TextView android:id="@id/android:empty" @@ -32,13 +32,14 @@ android:layout_height="match_parent" android:layout_gravity="center" android:gravity="center" - android:text="@string/no_items_label" /> + android:text="@string/no_items_label"/> <ProgressBar android:id="@+id/progLoading" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" - android:indeterminateOnly="true" /> + android:indeterminateOnly="true" + android:visibility="gone"/> -</LinearLayout>
\ No newline at end of file +</FrameLayout>
\ No newline at end of file diff --git a/res/layout/queue_fragment.xml b/res/layout/queue_fragment.xml new file mode 100644 index 000000000..1c48768a2 --- /dev/null +++ b/res/layout/queue_fragment.xml @@ -0,0 +1,58 @@ +<?xml version="1.0" encoding="utf-8"?> + +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:dslv="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <com.mobeta.android.dslv.DragSortListView + android:id="@android:id/list" + android:paddingLeft="8dp" + android:paddingRight="8dp" + android:scrollbarStyle="outsideOverlay" + android:layout_width="match_parent" + android:layout_height="match_parent" + dslv:collapsed_height="2dp" + dslv:drag_enabled="true" + dslv:drag_handle_id="@id/drag_handle" + dslv:drag_scroll_start="0.33" + dslv:float_alpha="0.6" + dslv:max_drag_scroll_speed="0.5" + dslv:remove_enabled="true" + dslv:remove_mode="flingRemove" + dslv:slide_shuffle_speed="0.3" + dslv:sort_enabled="true" + dslv:track_drag_sort="true" + dslv:float_background_color="?attr/dragview_float_background" + dslv:use_default_controller="true"/> + + <TextView + android:id="@id/android:empty" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_gravity="center" + android:gravity="center" + android:text="@string/no_items_label"/> + + <ProgressBar + android:id="@+id/progLoading" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:indeterminateOnly="true" + android:visibility="gone"/> + + <LinearLayout + android:id="@+id/undobar" + style="@style/UndoBar"> + + <TextView + android:id="@+id/undobar_message" + style="@style/UndoBarMessage"/> + + <Button + android:id="@+id/undobar_button" + style="@style/UndoBarButton"/> + </LinearLayout> + +</FrameLayout>
\ No newline at end of file diff --git a/res/layout/queue_listitem.xml b/res/layout/queue_listitem.xml new file mode 100644 index 000000000..5bac726f3 --- /dev/null +++ b/res/layout/queue_listitem.xml @@ -0,0 +1,130 @@ +<?xml version="1.0" encoding="utf-8"?> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:orientation="horizontal" + android:layout_height="match_parent"> + + <ImageView + android:layout_width="24dp" + android:layout_height="match_parent" + android:id="@+id/drag_handle" + android:src="?attr/dragview_background" + android:scaleType="center" + android:layout_margin="8dp" + android:contentDescription="@string/drag_handle_content_description"/> + + <RelativeLayout + android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_weight="1" + android:layout_marginRight="16dp"> + + <ImageView + android:id="@+id/imgvImage" + android:contentDescription="@string/cover_label" + android:layout_width="@dimen/thumbnail_length_itemlist" + android:layout_height="@dimen/thumbnail_length_itemlist" + android:layout_alignParentLeft="true" + android:scaleType="centerCrop"/> + + <ImageView + android:id="@+id/statusPlaying" + android:contentDescription="@string/status_playing_label" + android:layout_width="@dimen/status_indicator_width" + android:layout_height="18dp" + android:layout_alignParentRight="true" + android:layout_alignParentTop="true" + android:layout_marginBottom="8dp" + android:layout_marginTop="8dp" + android:background="@color/status_playing" + android:gravity="center" + android:padding="2dp" + android:src="@drawable/av_play_dark"/> + + <TextView + android:id="@+id/txtvPublished" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginLeft="8dp" + android:layout_marginRight="8dp" + android:layout_alignParentTop="true" + android:layout_toRightOf="@id/imgvImage" + android:layout_toLeftOf="@id/statusPlaying" + android:ellipsize="end" + android:maxLines="1" + android:textColor="?android:attr/textColorTertiary" + android:textSize="@dimen/text_size_micro"/> + + <TextView + android:id="@+id/txtvTitle" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_below="@id/txtvPublished" + android:layout_marginLeft="8dp" + android:layout_marginRight="4dp" + android:layout_marginTop="2dp" + android:layout_toRightOf="@id/imgvImage" + android:layout_toLeftOf="@id/statusPlaying" + android:ellipsize="end" + android:lines="2" + android:textColor="?android:attr/textColorPrimary" + android:textSize="@dimen/text_size_small"/> + + <LinearLayout + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_alignParentBottom="true" + android:layout_alignParentRight="true" + android:layout_toRightOf="@id/imgvImage" + android:orientation="vertical"> + + <RelativeLayout + android:id="@+id/bottom_bar" + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <ProgressBar + android:id="@+id/pbar_download_progress" + style="?android:attr/progressBarStyleHorizontal" + android:max="100" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_alignParentRight="true" + android:layout_marginLeft="8dp" + android:layout_marginRight="8dp" + android:layout_alignParentLeft="true"/> + + <TextView + android:id="@+id/txtvDuration" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginLeft="8dp" + android:layout_marginRight="8dp" + android:layout_alignParentLeft="true" + android:layout_alignParentRight="true" + android:textColor="?android:attr/textColorTertiary" + android:textSize="@dimen/text_size_micro"/> + </RelativeLayout> + </LinearLayout> + </RelativeLayout> + + <View + android:layout_width="1dp" + android:layout_height="match_parent" + android:background="@drawable/vertical_divider" + android:layout_marginTop="8dp" + android:layout_marginBottom="8dp"/> + + <ImageButton + android:id="@+id/butSecondaryAction" + android:focusable="false" + android:clickable="false" + android:focusableInTouchMode="false" + android:layout_width="@dimen/listview_secondary_button_width" + android:layout_height="match_parent" + android:background="?attr/borderless_button" + tools:ignore="ContentDescription"/> + +</LinearLayout>
\ No newline at end of file diff --git a/res/values/strings.xml b/res/values/strings.xml index 2f64c88b0..ca448f8a8 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -362,6 +362,7 @@ <string name="in_queue_label">Episode is in the queue</string> <string name="new_episodes_count_label">Number of new episodes</string> <string name="in_progress_episodes_count_label">Number of episodes you have started listening to</string> + <string name="drag_handle_content_description">Drag to change the position of this item</string> <!-- AntennaPodSP --> diff --git a/res/values/styles.xml b/res/values/styles.xml index 769630046..e29329c78 100644 --- a/res/values/styles.xml +++ b/res/values/styles.xml @@ -33,7 +33,7 @@ <item name="attr/overlay_background">@color/overlay_light</item> <item name="attr/spinner_button">@drawable/spinner_button</item> <item name="attr/overlay_drawable">@drawable/overlay_drawable</item> - <item name="attr/dragview_background">@drawable/dragview_background</item> + <item name="attr/dragview_background">@drawable/ic_drag_handle</item> <item name="attr/dragview_float_background">@color/white</item> <item name="attr/nav_drawer_background">@color/white</item> <item name="attr/nav_drawer_toggle">@drawable/ic_drawer</item> @@ -71,7 +71,7 @@ <item name="attr/overlay_background">@color/overlay_dark</item> <item name="attr/spinner_button">@drawable/spinner_button_dark</item> <item name="attr/overlay_drawable">@drawable/overlay_drawable_dark</item> - <item name="attr/dragview_background">@drawable/dragview_background_dark</item> + <item name="attr/dragview_background">@drawable/ic_drag_handle_dark</item> <item name="attr/dragview_float_background">@color/black</item> <item name="attr/nav_drawer_background">#3B3B3B</item> <item name="attr/nav_drawer_toggle">@drawable/ic_drawer_dark</item> 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; + } +} + |