package info.guardianproject.securereaderinterface.adapters;
import info.guardianproject.securereaderinterface.models.FeedFilterType;
import info.guardianproject.securereaderinterface.ui.UICallbacks;
import info.guardianproject.securereaderinterface.uiutil.AnimationHelpers;
import info.guardianproject.securereaderinterface.uiutil.AnimationHelpers.FadeInFadeOutListener;
import info.guardianproject.securereaderinterface.R;
import java.util.ArrayList;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import com.tinymission.rss.Feed;
public class FeedListAdapter extends BaseAdapter
{
public final static String LOGTAG = "FeedList";
public interface FeedListAdapterListener
{
void addFeed(Feed feed);
void removeFeed(Feed feed);
void deleteFeed(Feed feed);
}
public enum FeedListItemType
{
CATEGORY(0), FEED(1), EXPAND(2), CLOSE(3);
private final int value;
private FeedListItemType(int value)
{
this.value = value;
}
public int getValue()
{
return value;
}
}
/*
* The number of items to show in the drop down before the "Show all" item
* appears.
*/
private final static int DEFAULT_NUMBER_OF_ITEMS_SHOWN = 3;
private final Context mContext;
private final FeedListAdapterListener mListener;
private final LayoutInflater mInflater;
private final ArrayList<Object> mItems;
private ArrayList<Object> mVisibleItems;
private View mCurrentOperationsView; // Only allow operations for one view
// at a time!
public FeedListAdapter(Context context, FeedListAdapterListener listener, ArrayList<Feed> feeds)
{
super();
mContext = context;
mListener = listener;
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// TODO - order the feed on topic and name
mItems = new ArrayList<Object>();
Topic currentTopic = null;
for (Feed feed : feeds)
{
if (feed.getStatus() != Feed.STATUS_LAST_SYNC_GOOD)
{
if (currentTopic == null)
{
currentTopic = new Topic(mContext.getString(R.string.add_feed_processing));
currentTopic.isExpanded = true;
mItems.add(currentTopic);
}
mItems.add(new FeedViewModel(feed, currentTopic));
}
}
currentTopic = null;
for (Feed feed : feeds)
{
if (feed.getStatus() != Feed.STATUS_LAST_SYNC_GOOD)
continue; // Already added above
/*
* if (feed.is_cat) { mItems.add(new Topic(feed)); } else {
*/
if (currentTopic == null)
{
// Safeguard to make sure that the list starts with a TOPIC
// item
// (need this for Collapse/Expand to work as expected)
currentTopic = new Topic(mContext.getString(R.string.add_feed_default_topic));
currentTopic.isExpanded = true;
mItems.add(currentTopic);
}
mItems.add(new FeedViewModel(feed, currentTopic));
/*
* }
*/
}
updateVisibleItems();
}
private void updateVisibleItems()
{
if (mVisibleItems == null)
mVisibleItems = new ArrayList<Object>();
mVisibleItems.clear();
int nInThisTopic = 0;
Topic currentTopic = null;
for (Object o : mItems)
{
if (o instanceof Topic)
{
if (nInThisTopic > DEFAULT_NUMBER_OF_ITEMS_SHOWN)
mVisibleItems.add(new Closer(currentTopic));
mVisibleItems.add(o);
nInThisTopic = 0;
currentTopic = (Topic) o;
}
else if (o instanceof FeedViewModel)
{
FeedViewModel model = (FeedViewModel) o;
if (!model.topic.isExpanded)
{
if (nInThisTopic == DEFAULT_NUMBER_OF_ITEMS_SHOWN)
{
mVisibleItems.add(new Expander(currentTopic));
}
else if (nInThisTopic < DEFAULT_NUMBER_OF_ITEMS_SHOWN)
{
mVisibleItems.add(o);
}
}
else
{
mVisibleItems.add(o);
}
nInThisTopic++;
}
}
if (nInThisTopic > DEFAULT_NUMBER_OF_ITEMS_SHOWN && currentTopic.isExpanded)
mVisibleItems.add(new Closer(currentTopic));
}
@Override
public int getCount()
{
return mVisibleItems.size();
}
@Override
public Object getItem(int position)
{
return mVisibleItems.get(position);
}
@Override
public long getItemId(int position)
{
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
Object o = getItem(position);
if (o instanceof Topic)
{
Topic topic = (Topic) o;
View view;
if (convertView == null)
{
view = mInflater.inflate(R.layout.add_feed_header_item, parent, false);
}
else
{
view = convertView;
}
TextView tv = (TextView) view.findViewById(R.id.tvTopic);
tv.setText(topic.title);
return view;
}
if (o instanceof Expander)
{
Expander expander = (Expander) o;
View view;
if (convertView == null)
{
view = mInflater.inflate(R.layout.add_feed_expander, parent, false);
}
else
{
view = convertView;
}
view.setOnClickListener(new ExpandClickListener(expander.topic, true));
return view;
}
if (o instanceof Closer)
{
Closer closer = (Closer) o;
View view;
if (convertView == null)
{
view = mInflater.inflate(R.layout.add_feed_closer, parent, false);
}
else
{
view = convertView;
}
view.setOnClickListener(new ExpandClickListener(closer.topic, false));
return view;
}
if (o instanceof FeedViewModel)
{
FeedViewModel feedModel = (FeedViewModel) o;
View view;
if (convertView == null)
{
view = mInflater.inflate(R.layout.add_feed_list_item, parent, false);
}
else
{
view = convertView;
}
// ImageView iv = (ImageView) view.findViewById(R.id.ivFeedIcon);
// if (feedModel.feed.getImageManager() != null)
// feedModel.feed.getImageManager().download(feedModel.feed.,
// imageView)
// App.getInstance().socialReader.loadDisplayImageMediaContent(feedModel.feed.getImageManager(),
// iv);
// Name
TextView tv = (TextView) view.findViewById(R.id.tvFeedName);
tv.setText(feedModel.feed.getTitle());
tv.setTextColor(mContext.getResources().getColor(R.color.feed_list_title_normal));
int feedStatus = feedModel.feed.getStatus();
if (feedStatus == Feed.STATUS_LAST_SYNC_FAILED_404 || feedStatus == Feed.STATUS_LAST_SYNC_FAILED_BAD_URL
|| feedStatus == Feed.STATUS_LAST_SYNC_FAILED_UNKNOWN)
{
tv.setText(R.string.add_feed_error_loading);
tv.setTextColor(mContext.getResources().getColor(R.color.feed_list_title_error));
}
else if (TextUtils.isEmpty(feedModel.feed.getTitle()))
tv.setText(R.string.add_feed_not_loaded);
// Description
tv = (TextView) view.findViewById(R.id.tvFeedDescription);
tv.setText(feedModel.feed.getDescription());
if (TextUtils.isEmpty(feedModel.feed.getTitle()) || tv.getText().length() == 0)
tv.setText(feedModel.feed.getFeedURL());
// Operation?
View btnAdd = view.findViewById(R.id.btnAdd);
View btnRemove = view.findViewById(R.id.btnRemove);
if (feedStatus == Feed.STATUS_NOT_SYNCED || feedStatus == Feed.STATUS_LAST_SYNC_FAILED_404 || feedStatus == Feed.STATUS_LAST_SYNC_FAILED_BAD_URL
|| feedStatus == Feed.STATUS_LAST_SYNC_FAILED_UNKNOWN)
{
// Error, hide add and remove
btnAdd.setVisibility(View.GONE);
btnRemove.setVisibility(View.GONE);
view.setOnClickListener(null);
view.setOnLongClickListener(new FeedLongClickedListener(feedModel.feed, view.findViewById(R.id.llOperationButtons), true));
}
else if (feedModel.feed.isSubscribed())
{
btnAdd.setVisibility(View.GONE);
btnRemove.setVisibility(View.VISIBLE);
btnAdd.setOnClickListener(null);
btnRemove.setTag(feedModel);
btnRemove.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
FeedViewModel model = (FeedViewModel) v.getTag();
mListener.removeFeed(model.feed);
}
});
view.setOnClickListener(new FeedClickedListener(feedModel));
view.setOnLongClickListener(new FeedLongClickedListener(feedModel.feed, view.findViewById(R.id.llOperationButtons), false));
}
else
{
btnAdd.setVisibility(View.VISIBLE);
btnRemove.setVisibility(View.GONE);
btnAdd.setTag(feedModel);
btnAdd.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
FeedViewModel model = (FeedViewModel) v.getTag();
mListener.addFeed(model.feed);
}
});
btnRemove.setOnClickListener(null);
view.setOnClickListener(new FeedClickedListener(feedModel));
view.setOnLongClickListener(new FeedLongClickedListener(feedModel.feed, view.findViewById(R.id.llOperationButtons), false));
}
return view;
}
return null;
}
@Override
public void notifyDataSetChanged()
{
mCurrentOperationsView = null;
super.notifyDataSetChanged();
}
private class FeedClickedListener implements View.OnClickListener
{
private final FeedViewModel mFeedViewModel;
public FeedClickedListener(FeedViewModel feedViewModel)
{
mFeedViewModel = feedViewModel;
}
@Override
public void onClick(View v)
{
UICallbacks.setFeedFilter(FeedFilterType.SINGLE_FEED, mFeedViewModel.feed.getDatabaseId(), this);
if (mContext instanceof Activity)
{
((Activity) mContext).finish();
}
}
}
private class FeedLongClickedListener implements View.OnLongClickListener, OnClickListener, FadeInFadeOutListener
{
private final View mOperationsView;
private final View mBtnRemove;
private final View mBtnCopyURL;
private final View mBtnCancel;
private final Feed mFeed;
public FeedLongClickedListener(Feed feed, View operationsView, boolean showCopy)
{
mFeed = feed;
mOperationsView = operationsView;
mBtnRemove = mOperationsView.findViewById(R.id.btnRemove);
mBtnCopyURL = mOperationsView.findViewById(R.id.btnCopyURL);
mBtnCancel = mOperationsView.findViewById(R.id.btnCancel);
mBtnRemove.setOnClickListener(this);
mBtnCopyURL.setOnClickListener(this);
mBtnCancel.setOnClickListener(this);
if (showCopy)
{
mBtnCopyURL.setVisibility(View.VISIBLE);
mBtnCancel.setVisibility(View.GONE);
}
else
{
mBtnCopyURL.setVisibility(View.GONE);
mBtnCancel.setVisibility(View.VISIBLE);
}
mOperationsView.setVisibility(View.GONE);
AnimationHelpers.fadeOut(mOperationsView, 0, 0, false);
}
@Override
public boolean onLongClick(View v)
{
if (mCurrentOperationsView == null && mOperationsView.getVisibility() == View.GONE)
{
mCurrentOperationsView = mOperationsView;
mOperationsView.setVisibility(View.VISIBLE);
AnimationHelpers.fadeIn(mOperationsView, 200, 5000, false, this);
}
return true;
}
@Override
public void onClick(View v)
{
AnimationHelpers.fadeOut(mOperationsView, 200, 0, false);
if (v == mBtnRemove)
{
v.post(new Runnable()
{
@Override
public void run()
{
mCurrentOperationsView = null;
mListener.deleteFeed(mFeed);
}
});
}
else if (v == mBtnCopyURL)
{
v.post(new Runnable()
{
@SuppressLint("NewApi")
@Override
public void run()
{
mCurrentOperationsView = null;
int sdk = android.os.Build.VERSION.SDK_INT;
if (sdk < android.os.Build.VERSION_CODES.HONEYCOMB)
{
android.text.ClipboardManager clipboard = (android.text.ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE);
clipboard.setText(mFeed.getFeedURL());
}
else
{
android.content.ClipboardManager clipboard = (android.content.ClipboardManager) mContext
.getSystemService(Context.CLIPBOARD_SERVICE);
android.content.ClipData clip = android.content.ClipData.newPlainText(
mContext.getString(R.string.add_feed_operation_copy_url_clipboard_label), mFeed.getFeedURL());
clipboard.setPrimaryClip(clip);
}
}
});
}
else
{
mCurrentOperationsView = null;
}
}
@Override
public void onFadeInStarted(View view)
{
}
@Override
public void onFadeInEnded(View view)
{
}
@Override
public void onFadeOutStarted(View view)
{
mCurrentOperationsView = null;
}
@Override
public void onFadeOutEnded(View view)
{
}
}
@Override
public int getItemViewType(int position)
{
Object o = getItem(position);
if (o instanceof Topic)
return FeedListItemType.CATEGORY.getValue();
else if (o instanceof Expander)
return FeedListItemType.EXPAND.getValue();
else if (o instanceof Closer)
return FeedListItemType.CLOSE.getValue();
return FeedListItemType.FEED.getValue();
}
@Override
public int getViewTypeCount()
{
return 4;
}
private class ExpandClickListener implements OnClickListener
{
private final Topic mTopic;
private final boolean mExpand;
public ExpandClickListener(Topic topic, boolean expand)
{
mTopic = topic;
mExpand = expand;
}
@Override
public void onClick(View v)
{
expandTopic(mTopic, mExpand);
}
}
private void expandTopic(Topic topic, boolean expand)
{
topic.isExpanded = expand;
this.updateVisibleItems();
this.notifyDataSetChanged();
}
private class Topic
{
public Feed feed;
public String title;
public boolean isExpanded;
public Topic(Feed feed)
{
this.feed = feed;
this.title = feed.getTitle();
isExpanded = false;
}
public Topic(String title)
{
this.title = title;
}
}
private class Expander
{
public Topic topic;
public Expander(Topic topic)
{
this.topic = topic;
}
}
private class Closer
{
public Topic topic;
public Closer(Topic topic)
{
this.topic = topic;
}
}
private class FeedViewModel
{
public Feed feed;
public Topic topic;
public FeedViewModel(Feed feed, Topic topic)
{
this.feed = feed;
this.topic = topic;
}
}
}