blob: 4274167eb9fc1e5f725a2ea4dfa65486c8418798 [file] [log] [blame]
/*
* Copyright (C) 2012 Google Inc.
* Licensed to The Android Open Source Project.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.mail.ui;
import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.database.Cursor;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.SimpleCursorAdapter;
import com.android.mail.browse.ConversationCursor;
import com.android.mail.browse.ConversationItemView;
import com.android.mail.browse.ConversationListFooterView;
import com.android.mail.providers.Account;
import com.android.mail.providers.Conversation;
import com.android.mail.providers.UIProvider;
import com.android.mail.ui.UndoBarView.OnUndoCancelListener;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
public class AnimatedAdapter extends SimpleCursorAdapter implements
android.animation.Animator.AnimatorListener, OnUndoCancelListener {
private static int ITEM_VIEW_TYPE_FOOTER = 1;
private HashSet<Integer> mDeletingItems = new HashSet<Integer>();
private Account mSelectedAccount;
private Context mContext;
private ConversationSelectionSet mBatchConversations;
private ActionCompleteListener mActionCompleteListener;
private boolean mUndo = false;
private ArrayList<Integer> mLastDeletingItems = new ArrayList<Integer>();
private ViewMode mViewMode;
private View mFooter;
private boolean mShowFooter;
public AnimatedAdapter(Context context, int textViewResourceId, ConversationCursor cursor,
ConversationSelectionSet batch, Account account, ViewMode viewMode) {
super(context, textViewResourceId, cursor, UIProvider.CONVERSATION_PROJECTION, null, 0);
mContext = context;
mBatchConversations = batch;
mSelectedAccount = account;
mViewMode = viewMode;
mShowFooter = false;
}
@Override
public int getCount() {
int count = super.getCount();
return mShowFooter? count + 1 : count;
}
public void setUndo(boolean state) {
mUndo = state;
if (mUndo) {
mDeletingItems.clear();
mDeletingItems.addAll(mLastDeletingItems);
mActionCompleteListener = new ActionCompleteListener() {
@Override
public void onActionComplete() {
notifyDataSetChanged();
}};
}
}
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
ConversationItemView view = new ConversationItemView(context, mSelectedAccount.name);
return view;
}
@Override
public void bindView(View view, Context context, Cursor cursor) {
if (!isPositionAnimating(view) && !isPositionFooter(view)) {
((ConversationItemView) view).bind(cursor, mSelectedAccount.name, mViewMode,
mBatchConversations);
}
}
@Override
public boolean hasStableIds() {
return true;
}
@Override
public int getViewTypeCount() {
// Our normal view and the animating (not recycled) view
return 3;
}
@Override
public int getItemViewType(int position) {
// Don't recycle animating views
if (isPositionAnimating(position)) {
return AdapterView.ITEM_VIEW_TYPE_IGNORE;
} else if (mShowFooter && position == super.getCount()) {
return ITEM_VIEW_TYPE_FOOTER ;
}
return 0;
}
public void delete(Collection<Conversation> conversations,
ActionCompleteListener listener) {
// Animate out the positions.
// Call when all the animations are complete.
final ArrayList<Integer> positions = new ArrayList<Integer>();
for (Conversation c : conversations) {
positions.add(c.position);
}
delete(positions, listener);
}
public void delete(ArrayList<Integer> deletedRows, ActionCompleteListener listener) {
// Clear out any remaining items and add the new ones
mLastDeletingItems.clear();
mLastDeletingItems.addAll(deletedRows);
mDeletingItems.addAll(deletedRows);
mActionCompleteListener = listener;
// TODO(viki): Rather than notifying for a full data set change, perhaps we can mark
// only the affected conversations?
notifyDataSetChanged();
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (mShowFooter && position == super.getCount()) {
return mFooter;
}
if (isPositionAnimating(position)) {
return getAnimatingView(position, convertView, parent);
}
return super.getView(position, convertView, parent);
}
/**
* Get an animating view. This happens when a list item is in the process of being removed
* from the list (items being deleted).
* @param position the position of the view inside the list
* @param convertView if null, a recycled view that we can reuse
* @param parent the parent view
* @return the view to show when animating an operation.
*/
private View getAnimatingView(int position, View convertView, ViewGroup parent) {
assert (convertView instanceof AnimatingItemView);
Conversation conversation = new Conversation((ConversationCursor) getItem(position));
conversation.position = position;
final AnimatingItemView view = (convertView == null) ? new AnimatingItemView(mContext)
: (AnimatingItemView) convertView;
view.startAnimation(conversation, this, mUndo);
return view;
}
private boolean isPositionAnimating(int position) {
return mDeletingItems.contains(position);
}
private boolean isPositionAnimating(View view) {
return (view instanceof AnimatingItemView);
}
private boolean isPositionFooter(View view) {
return (view instanceof ConversationListFooterView);
}
@Override
public void onAnimationStart(Animator animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationEnd(Animator animation) {
if (!mDeletingItems.isEmpty()) {
// See if we have received all the animations we expected; if so,
// call the listener and reset it.
int position = ((AnimatingItemView)
((ObjectAnimator) animation).getTarget()).getData().position;
mDeletingItems.remove(position);
if (mDeletingItems.isEmpty()) {
if (mUndo) {
mLastDeletingItems.clear();
mUndo = false;
}
if (mActionCompleteListener != null) {
mActionCompleteListener.onActionComplete();
mActionCompleteListener = null;
}
}
}
}
@Override
public void onAnimationCancel(Animator animation) {
onAnimationEnd(animation);
}
@Override
public void onAnimationRepeat(Animator animation) {
// TODO Auto-generated method stub
}
@Override
public void onUndoCancel() {
mLastDeletingItems.clear();
}
public void showFooter() {
if (!mShowFooter) {
mShowFooter = true;
notifyDataSetChanged();
}
}
public void hideFooter() {
if (mShowFooter) {
mShowFooter = false;
notifyDataSetChanged();
}
}
public void addFooter(View footerView) {
mFooter = footerView;
}
}