diff options
4 files changed, 272 insertions, 322 deletions
diff --git a/res/layout/feeditemlist_header.xml b/res/layout/feeditemlist_header.xml index 560013abd..4e640e056 100644 --- a/res/layout/feeditemlist_header.xml +++ b/res/layout/feeditemlist_header.xml @@ -1,56 +1,54 @@ <?xml version="1.0" encoding="utf-8"?> -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:background="?attr/borderless_button" - android:orientation="vertical" > - <RelativeLayout - android:layout_width="wrap_content" - android:layout_height="match_parent" > +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent" + tools:context="de.danoeh.antennapod.activity.MainActivity"> + + <ImageView + android:id="@+id/imgvCover" + android:contentDescription="@string/cover_label" + android:layout_width="@dimen/thumbnail_length_onlinefeedview" + android:layout_height="@dimen/thumbnail_length_onlinefeedview" + android:layout_alignParentLeft="true" + android:layout_alignParentTop="true" + android:layout_margin="4dp"/> - <TextView - android:id="@+id/txtvHeaderTitle" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_alignParentLeft="true" - android:layout_centerVertical="true" - android:layout_marginBottom="32dp" - android:layout_marginLeft="28dp" - android:layout_marginRight="16dp" - android:layout_marginTop="32dp" - android:paddingLeft="8dp" - android:textAllCaps="true" - android:textColor="@color/dark_blue" - android:textSize="@dimen/text_size_large" - android:typeface="sans" /> + <TextView + android:id="@+id/txtvTitle" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:ellipsize="end" + android:gravity="center_vertical" + android:layout_alignTop="@id/imgvCover" + android:layout_toRightOf="@id/imgvCover" + android:layout_alignParentRight="true" + android:lines="1" + android:textColor="?android:attr/textColorPrimary" + android:textSize="@dimen/text_size_medium" + android:layout_margin="4dp"/> - <ImageButton - android:id="@+id/butAction" - android:contentDescription="@string/butAction_label" - android:layout_width="48dp" - android:layout_height="match_parent" - android:layout_alignParentBottom="true" - android:layout_alignParentRight="true" - android:background="?attr/borderless_button" - android:clickable="false" - android:focusable="false" - android:focusableInTouchMode="false" - android:paddingLeft="24dp" - android:paddingRight="8dp" - android:paddingTop="16dp" - android:scaleType="fitEnd" - android:src="?attr/spinner_button" /> + <TextView + android:id="@+id/txtvAuthor" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_margin="4dp" + android:layout_below="@id/txtvTitle" + android:layout_toRightOf="@id/imgvCover" + android:lines="1" + android:ellipsize="end" + android:textColor="?android:attr/textColorSecondary" + android:textSize="@dimen/text_size_small"/> - <TextView - android:id="@+id/txtvNumItems" - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:layout_centerVertical="true" - android:layout_toLeftOf="@id/butAction" - android:textColor="@color/dark_blue" - android:textSize="@dimen/text_size_large" - android:textStyle="normal" /> - </RelativeLayout> + <TextView + android:id="@+id/txtvLink" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:lines="1" + android:ellipsize="end" + android:layout_below="@id/txtvAuthor" + android:layout_toRightOf="@id/imgvCover" + android:textSize="@dimen/text_size_small"/> -</LinearLayout>
\ No newline at end of file +</RelativeLayout>
\ No newline at end of file diff --git a/src/de/danoeh/antennapod/activity/FeedItemlistActivity.java b/src/de/danoeh/antennapod/activity/FeedItemlistActivity.java index d0305eada..95ccb859f 100644 --- a/src/de/danoeh/antennapod/activity/FeedItemlistActivity.java +++ b/src/de/danoeh/antennapod/activity/FeedItemlistActivity.java @@ -166,7 +166,7 @@ public class FeedItemlistActivity extends ActionBarActivity { public boolean onOptionsItemSelected(MenuItem item) { try { if (FeedMenuHandler.onOptionsItemClicked(this, item, feed)) { - filf.getListAdapter().notifyDataSetChanged(); + // filf.getListAdapter().notifyDataSetChanged(); } else { switch (item.getItemId()) { case R.id.remove_item: diff --git a/src/de/danoeh/antennapod/adapter/ExternalEpisodesListAdapter.java b/src/de/danoeh/antennapod/adapter/ExternalEpisodesListAdapter.java index aa724f991..9a7b607aa 100644 --- a/src/de/danoeh/antennapod/adapter/ExternalEpisodesListAdapter.java +++ b/src/de/danoeh/antennapod/adapter/ExternalEpisodesListAdapter.java @@ -227,10 +227,10 @@ public class ExternalEpisodesListAdapter extends BaseExpandableListAdapter { .getSystemService(Context.LAYOUT_INFLATER_SERVICE); convertView = inflater.inflate(R.layout.feeditemlist_header, null); TextView headerTitle = (TextView) convertView - .findViewById(R.id.txtvHeaderTitle); + .findViewById(0); ImageButton actionButton = (ImageButton) convertView .findViewById(R.id.butAction); - TextView numItems = (TextView) convertView.findViewById(R.id.txtvNumItems); + TextView numItems = (TextView) convertView.findViewById(0); String headerString = null; int childrenCount = 0; diff --git a/src/de/danoeh/antennapod/fragment/ItemlistFragment.java b/src/de/danoeh/antennapod/fragment/ItemlistFragment.java index e5845dd76..8072d219b 100644 --- a/src/de/danoeh/antennapod/fragment/ItemlistFragment.java +++ b/src/de/danoeh/antennapod/fragment/ItemlistFragment.java @@ -1,15 +1,19 @@ package de.danoeh.antennapod.fragment; import android.annotation.SuppressLint; +import android.app.Activity; import android.content.Context; import android.content.Intent; import android.os.AsyncTask; import android.os.Bundle; import android.support.v4.app.ListFragment; import android.support.v7.app.ActionBarActivity; +import android.text.util.Linkify; import android.util.Log; -import android.view.*; -import android.view.ContextMenu.ContextMenuInfo; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.ImageButton; +import android.widget.ImageView; import android.widget.ListView; import android.widget.TextView; import de.danoeh.antennapod.BuildConfig; @@ -17,311 +21,259 @@ import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.ItemviewActivity; import de.danoeh.antennapod.adapter.ActionButtonCallback; import de.danoeh.antennapod.adapter.InternalFeedItemlistAdapter; -import de.danoeh.antennapod.dialog.DownloadRequestErrorDialogCreator; +import de.danoeh.antennapod.asynctask.ImageLoader; import de.danoeh.antennapod.feed.EventDistributor; import de.danoeh.antennapod.feed.Feed; import de.danoeh.antennapod.feed.FeedItem; import de.danoeh.antennapod.service.download.DownloadService; import de.danoeh.antennapod.storage.DBReader; -import de.danoeh.antennapod.storage.DownloadRequestException; import de.danoeh.antennapod.storage.DownloadRequester; import de.danoeh.antennapod.util.QueueAccess; -import de.danoeh.antennapod.util.menuhandler.FeedItemMenuHandler; -import java.util.List; +import java.util.concurrent.atomic.AtomicReference; -/** Displays a list of FeedItems. */ +/** + * Displays a list of FeedItems. + */ @SuppressLint("ValidFragment") public class ItemlistFragment extends ListFragment { - private static final String TAG = "ItemlistFragment"; - - private static final int EVENTS = EventDistributor.DOWNLOAD_HANDLED - | EventDistributor.DOWNLOAD_QUEUED - | EventDistributor.QUEUE_UPDATE - | EventDistributor.UNREAD_ITEMS_UPDATE; - - public static final String EXTRA_SELECTED_FEEDITEM = "extra.de.danoeh.antennapod.activity.selected_feeditem"; - public static final String ARGUMENT_FEED_ID = "argument.de.danoeh.antennapod.feed_id"; - protected InternalFeedItemlistAdapter fila; - - private Feed feed; - protected List<Long> queue; - - protected FeedItem selectedItem = null; - protected boolean contextMenuClosed = true; - - /** Argument for FeeditemlistAdapter */ - protected boolean showFeedtitle; - - private AsyncTask<Long, Void, Feed> currentLoadTask; - - public ItemlistFragment(boolean showFeedtitle) { - super(); - this.showFeedtitle = showFeedtitle; - } - - public ItemlistFragment() { - } - - /** - * Creates new ItemlistFragment which shows the Feeditems of a specific - * feed. Sets 'showFeedtitle' to false - * - * @param feedId - * The id of the feed to show - * @return the newly created instance of an ItemlistFragment - */ - public static ItemlistFragment newInstance(long feedId) { - ItemlistFragment i = new ItemlistFragment(); - i.showFeedtitle = false; - Bundle b = new Bundle(); - b.putLong(ARGUMENT_FEED_ID, feedId); - i.setArguments(b); - return i; - } - - private InternalFeedItemlistAdapter.ItemAccess itemAccessRef; - protected InternalFeedItemlistAdapter.ItemAccess itemAccess() { - if (itemAccessRef == null) { - itemAccessRef = new InternalFeedItemlistAdapter.ItemAccess() { - - @Override - public FeedItem getItem(int position) { - return (feed != null) ? feed.getItemAtIndex(true, position) : null; - } + private static final String TAG = "ItemlistFragment"; - @Override - public int getCount() { - return (feed != null) ? feed.getNumOfItems(true) : 0; - } + private static final int EVENTS = EventDistributor.DOWNLOAD_HANDLED + | EventDistributor.DOWNLOAD_QUEUED + | EventDistributor.QUEUE_UPDATE + | EventDistributor.UNREAD_ITEMS_UPDATE; - @Override - public boolean isInQueue(FeedItem item) { - return (queue != null) && queue.contains(item.getId()); - } - }; - } - return itemAccessRef; + public static final String EXTRA_SELECTED_FEEDITEM = "extra.de.danoeh.antennapod.activity.selected_feeditem"; + public static final String ARGUMENT_FEED_ID = "argument.de.danoeh.antennapod.feed_id"; + + protected InternalFeedItemlistAdapter adapter; + + private long feedID; + private Feed feed; + protected QueueAccess queue; + + private boolean itemsLoaded = false; + private boolean viewsCreated = false; + + private AtomicReference<Activity> activity = new AtomicReference<Activity>(); + + + /** + * Creates new ItemlistFragment which shows the Feeditems of a specific + * feed. Sets 'showFeedtitle' to false + * + * @param feedId The id of the feed to show + * @return the newly created instance of an ItemlistFragment + */ + public static ItemlistFragment newInstance(long feedId) { + ItemlistFragment i = new ItemlistFragment(); + Bundle b = new Bundle(); + b.putLong(ARGUMENT_FEED_ID, feedId); + i.setArguments(b); + return i; } - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - return inflater.inflate(R.layout.feeditemlist, container, false); - } + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setRetainInstance(true); + + Bundle args = getArguments(); + if (args == null) throw new IllegalArgumentException("args invalid"); + feedID = args.getLong(ARGUMENT_FEED_ID); + + startItemLoader(); + } @Override public void onStart() { super.onStart(); EventDistributor.getInstance().register(contentUpdate); - loadData(); } @Override public void onStop() { super.onStop(); EventDistributor.getInstance().unregister(contentUpdate); - if (currentLoadTask != null) { - currentLoadTask.cancel(true); - } + stopItemLoader(); } - protected synchronized void loadData() { - final long feedId; - if (feed == null) { - feedId = getArguments().getLong(ARGUMENT_FEED_ID); - } else { - feedId = feed.getId(); + @Override + public void onResume() { + super.onResume(); + updateProgressBarVisibility(); + } + + @Override + public void onDetach() { + super.onDetach(); + stopItemLoader(); + adapter = null; + viewsCreated = false; + activity.set(null); + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + this.activity.set(activity); + if (viewsCreated && itemsLoaded) { + onFragmentLoaded(); } - if (currentLoadTask != null) { - currentLoadTask.cancel(true); + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + viewsCreated = true; + if (itemsLoaded) { + onFragmentLoaded(); } - AsyncTask<Long, Void, Feed> loadTask = new AsyncTask<Long, Void, Feed>(){ - private volatile List<Long> queueRef; - - @Override - protected Feed doInBackground(Long... longs) { - Context context = ItemlistFragment.this.getActivity(); - if (context != null) { - Feed result = DBReader.getFeed(context, longs[0]); - if (result != null) { - result.setItems(DBReader.getFeedItemList(context, result)); - queueRef = DBReader.getQueueIDList(context); - return result; - } - } - return null; - } + } - @Override - protected void onPostExecute(Feed result) { - super.onPostExecute(result); - if (result != null && result.getItems() != null) { - feed = result; - if (queueRef != null) { - queue = queueRef; - } else { - Log.e(TAG, "Could not load queue"); - } - setEmptyViewIfListIsEmpty(); - if (fila != null) { - fila.notifyDataSetChanged(); - } - } else { - if (result == null) { - Log.e(TAG, "Could not load feed with id " + feedId); - } else if (result.getItems() == null) { - Log.e(TAG, "Could not load feed items"); - } - } - } - }; - currentLoadTask = loadTask; - loadTask.execute(feedId); + @Override + public void onListItemClick(ListView l, View v, int position, long id) { + FeedItem selection = adapter.getItem(position - l.getHeaderViewsCount()); + Intent showItem = new Intent(getActivity(), ItemviewActivity.class); + showItem.putExtra(FeedlistFragment.EXTRA_SELECTED_FEED, selection + .getFeed().getId()); + showItem.putExtra(EXTRA_SELECTED_FEEDITEM, selection.getId()); + + startActivity(showItem); } - private void setEmptyViewIfListIsEmpty() { - if (getListView() != null && feed != null && feed.getItems() != null) { - if (feed.getItems().isEmpty()) { - ((TextView) getActivity().findViewById(android.R.id.empty)).setText(R.string.no_items_label); + private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() { + + @Override + public void update(EventDistributor eventDistributor, Integer arg) { + if ((EVENTS & arg) != 0) { + if (BuildConfig.DEBUG) + Log.d(TAG, "Received contentUpdate Intent."); + if ((EventDistributor.DOWNLOAD_QUEUED & arg) != 0) { + updateProgressBarVisibility(); + } else { + startItemLoader(); + updateProgressBarVisibility(); + } } } - } + }; - protected InternalFeedItemlistAdapter createListAdapter() { - return new InternalFeedItemlistAdapter(getActivity(), itemAccess(), - adapterCallback, showFeedtitle); - } - - @Override - public void onResume() { - super.onResume(); - getActivity().runOnUiThread(new Runnable() { - - @Override - public void run() { - fila.notifyDataSetChanged(); - } - }); - updateProgressBarVisibility(); - } - - @Override - public void onListItemClick(ListView l, View v, int position, long id) { - FeedItem selection = fila.getItem(position - l.getHeaderViewsCount()); - Intent showItem = new Intent(getActivity(), ItemviewActivity.class); - showItem.putExtra(FeedlistFragment.EXTRA_SELECTED_FEED, selection - .getFeed().getId()); - showItem.putExtra(EXTRA_SELECTED_FEEDITEM, selection.getId()); - - startActivity(showItem); - } - - private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() { - - @Override - public void update(EventDistributor eventDistributor, Integer arg) { - if ((EVENTS & arg) != 0) { - if (BuildConfig.DEBUG) - Log.d(TAG, "Received contentUpdate Intent."); - if ((EventDistributor.DOWNLOAD_QUEUED & arg) != 0) { - updateProgressBarVisibility(); - } else { - if (feed != null) { - loadData(); - } - updateProgressBarVisibility(); - } - } - } - }; - - private void updateProgressBarVisibility() { - if (feed != null) { - if (DownloadService.isRunning - && DownloadRequester.getInstance().isDownloadingFile(feed)) { + private void updateProgressBarVisibility() { + if (feed != null) { + if (DownloadService.isRunning + && DownloadRequester.getInstance().isDownloadingFile(feed)) { ((ActionBarActivity) getActivity()) - .setSupportProgressBarIndeterminateVisibility(true); - } else { + .setSupportProgressBarIndeterminateVisibility(true); + } else { ((ActionBarActivity) getActivity()) - .setSupportProgressBarIndeterminateVisibility(false); - } + .setSupportProgressBarIndeterminateVisibility(false); + } getActivity().supportInvalidateOptionsMenu(); - } - } - - protected ActionButtonCallback adapterCallback = new ActionButtonCallback() { - - @Override - public void onActionButtonPressed(FeedItem item) { - selectedItem = item; - contextMenuClosed = true; - getListView().showContextMenu(); - } - }; - - @Override - public void onViewCreated(View view, Bundle savedInstanceState) { - fila = createListAdapter(); - setListAdapter(fila); - this.getListView().setItemsCanFocus(true); - getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE); - registerForContextMenu(getListView()); - getListView().setOnItemLongClickListener(null); - } - - @Override - public void onCreateContextMenu(final ContextMenu menu, View v, - ContextMenuInfo menuInfo) { - super.onCreateContextMenu(menu, v, menuInfo); - if (!contextMenuClosed) { // true if context menu was cancelled before - selectedItem = null; - } - contextMenuClosed = false; - getListView().setOnItemLongClickListener(null); - if (selectedItem != null) { - new MenuInflater(ItemlistFragment.this.getActivity()).inflate( - R.menu.feeditem, menu); - - menu.setHeaderTitle(selectedItem.getTitle()); - FeedItemMenuHandler.onPrepareMenu( - new FeedItemMenuHandler.MenuInterface() { - - @Override - public void setItemVisibility(int id, boolean visible) { - menu.findItem(id).setVisible(visible); - } - }, selectedItem, false, QueueAccess.IDListAccess(queue)); - - } - } - - @Override - public boolean onContextItemSelected(android.view.MenuItem item) { - boolean handled = false; - - if (selectedItem != null) { - - try { - handled = FeedItemMenuHandler.onMenuItemClicked( - getActivity(), item.getItemId(), selectedItem); - } catch (DownloadRequestException e) { - e.printStackTrace(); - DownloadRequestErrorDialogCreator.newRequestErrorDialog( - getActivity(), e.getMessage()); - } - if (handled) { - fila.notifyDataSetChanged(); - } - - } - selectedItem = null; - contextMenuClosed = true; - return handled; - } - - public InternalFeedItemlistAdapter getListAdapter() { - return fila; - } + } + } + + private void onFragmentLoaded() { + if (adapter == null) { + setupHeaderView(); + adapter = new InternalFeedItemlistAdapter(getActivity(), itemAccess, actionButtonCallback, false); + setListAdapter(adapter); + } + setListShown(true); + adapter.notifyDataSetChanged(); + + } + + private void setupHeaderView() { + if (getListView() == null || feed == null) { + Log.e(TAG, "Unable to setup listview: listView = null or feed = null"); + return; + } + LayoutInflater inflater = (LayoutInflater) + activity.get().getSystemService(Context.LAYOUT_INFLATER_SERVICE); + View header = inflater.inflate(R.layout.feeditemlist_header, null); + getListView().addHeaderView(header); + + TextView txtvTitle = (TextView) header.findViewById(R.id.txtvTitle); + TextView txtvAuthor = (TextView) header.findViewById(R.id.txtvAuthor); + TextView txtvLink = (TextView) header.findViewById(R.id.txtvLink); + ImageView imgvCover = (ImageView) header.findViewById(R.id.imgvCover); + + txtvTitle.setText(feed.getTitle()); + txtvAuthor.setText(feed.getAuthor()); + txtvLink.setText(feed.getLink()); + Linkify.addLinks(txtvLink, Linkify.WEB_URLS); + ImageLoader.getInstance().loadThumbnailBitmap(feed.getImage(), imgvCover, + (int) getResources().getDimension(R.dimen.thumbnail_length_onlinefeedview)); + } + + private InternalFeedItemlistAdapter.ItemAccess itemAccess = new InternalFeedItemlistAdapter.ItemAccess() { + + @Override + public FeedItem getItem(int position) { + return (feed != null) ? feed.getItemAtIndex(true, position) : null; + } + + @Override + public int getCount() { + return (feed != null) ? feed.getNumOfItems(true) : 0; + } + + @Override + public boolean isInQueue(FeedItem item) { + return (queue != null) && queue.contains(item.getId()); + } + }; + + private ActionButtonCallback actionButtonCallback = new ActionButtonCallback() { + @Override + public void onActionButtonPressed(FeedItem item) { + } + }; + + + private ItemLoader itemLoader; + + private void startItemLoader() { + if (itemLoader != null) { + itemLoader.cancel(true); + } + itemLoader = new ItemLoader(); + itemLoader.execute(feedID); + } + + private void stopItemLoader() { + if (itemLoader != null) { + itemLoader.cancel(true); + } + } + + private class ItemLoader extends AsyncTask<Long, Void, Object[]> { + @Override + protected Object[] doInBackground(Long... params) { + long feedID = params[0]; + Context context = activity.get(); + if (context != null) { + return new Object[]{DBReader.getFeed(context, feedID), + QueueAccess.IDListAccess(DBReader.getQueueIDList(context))}; + } else { + return null; + } + } + + @Override + protected void onPostExecute(Object[] res) { + super.onPostExecute(res); + if (res != null) { + feed = (Feed) res[0]; + queue = (QueueAccess) res[1]; + itemsLoaded = true; + if (viewsCreated) { + onFragmentLoaded(); + } + } + } + } } |