Reimplemented ItemlistFragment

This commit is contained in:
daniel oeh 2014-04-17 21:40:50 +02:00
parent 8b6f16b918
commit a03b076a32
4 changed files with 268 additions and 318 deletions

View File

@ -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
<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/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"/>
<TextView
android:id="@+id/txtvAuthor"
android:layout_width="wrap_content"
android:layout_height="match_parent" >
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/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/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"/>
<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/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>
</LinearLayout>
</RelativeLayout>

View File

@ -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:

View File

@ -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;

View File

@ -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 String TAG = "ItemlistFragment";
private static final int EVENTS = EventDistributor.DOWNLOAD_HANDLED
| EventDistributor.DOWNLOAD_QUEUED
| EventDistributor.QUEUE_UPDATE
| EventDistributor.UNREAD_ITEMS_UPDATE;
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;
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";
private Feed feed;
protected List<Long> queue;
protected InternalFeedItemlistAdapter adapter;
protected FeedItem selectedItem = null;
protected boolean contextMenuClosed = true;
private long feedID;
private Feed feed;
protected QueueAccess queue;
/** Argument for FeeditemlistAdapter */
protected boolean showFeedtitle;
private boolean itemsLoaded = false;
private boolean viewsCreated = false;
private AsyncTask<Long, Void, Feed> currentLoadTask;
private AtomicReference<Activity> activity = new AtomicReference<Activity>();
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;
}
@Override
public int getCount() {
return (feed != null) ? feed.getNumOfItems(true) : 0;
}
@Override
public boolean isInQueue(FeedItem item) {
return (queue != null) && queue.contains(item.getId());
}
};
}
return itemAccessRef;
/**
* 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();
}
@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();
}
}
protected synchronized void loadData() {
final long feedId;
if (feed == null) {
feedId = getArguments().getLong(ARGUMENT_FEED_ID);
} else {
feedId = feed.getId();
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
viewsCreated = true;
if (itemsLoaded) {
onFragmentLoaded();
}
if (currentLoadTask != null) {
currentLoadTask.cancel(true);
}
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;
}
@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 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();
}
}
}
};
private void updateProgressBarVisibility() {
if (feed != null) {
if (DownloadService.isRunning
&& DownloadRequester.getInstance().isDownloadingFile(feed)) {
((ActionBarActivity) getActivity())
.setSupportProgressBarIndeterminateVisibility(true);
} else {
((ActionBarActivity) getActivity())
.setSupportProgressBarIndeterminateVisibility(false);
}
getActivity().supportInvalidateOptionsMenu();
}
}
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(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");
}
@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();
}
}
};
currentLoadTask = loadTask;
loadTask.execute(feedId);
}
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);
}
}
}
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)) {
((ActionBarActivity) getActivity())
.setSupportProgressBarIndeterminateVisibility(true);
} else {
((ActionBarActivity) getActivity())
.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;
}
}