SwipeableListView.java revision c79aec78d06928b3fa1464d6aed60019f9b4843b
1f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira/*
2f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira * Copyright (C) 2012 Google Inc.
3f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira * Licensed to The Android Open Source Project.
4f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira *
5f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira * Licensed under the Apache License, Version 2.0 (the "License");
6f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira * you may not use this file except in compliance with the License.
7f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira * You may obtain a copy of the License at
8f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira *
9f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira *      http://www.apache.org/licenses/LICENSE-2.0
10f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira *
11f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira * Unless required by applicable law or agreed to in writing, software
12f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira * distributed under the License is distributed on an "AS IS" BASIS,
13f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira * See the License for the specific language governing permissions and
15f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira * limitations under the License.
16f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira */
17f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira
18f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereirapackage com.android.mail.ui;
19f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira
20f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereiraimport android.content.Context;
21f913894d3f1fa80b7174477999074b813e1deb12Mindy Pereiraimport android.content.res.Configuration;
228db7e407109532557718c6b8064792f2df7a073dMindy Pereiraimport android.net.Uri;
23f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereiraimport android.util.AttributeSet;
24f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereiraimport android.view.MotionEvent;
25f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereiraimport android.view.View;
26f913894d3f1fa80b7174477999074b813e1deb12Mindy Pereiraimport android.view.ViewConfiguration;
27f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereiraimport android.widget.ListView;
28f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira
29f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereiraimport com.android.mail.R;
30bf232c3735f65b1a4746943e4a134e59e36f0bdePaul Westbrookimport com.android.mail.browse.ConversationCursor;
31f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereiraimport com.android.mail.browse.ConversationItemView;
321ef988f0c8be136fda75ed207c222413db1d3f0cMindy Pereiraimport com.android.mail.browse.SwipeableConversationItemView;
33f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereiraimport com.android.mail.providers.Conversation;
3406642fab1bf4ab95b5dd97a65b262845cf60c865Mindy Pereiraimport com.android.mail.providers.Folder;
35f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereiraimport com.android.mail.ui.SwipeHelper.Callback;
36b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrookimport com.android.mail.utils.LogTag;
37b0219eb7b77212902a38821c050922ac73a68250Mindy Pereiraimport com.android.mail.utils.LogUtils;
38f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira
39866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereiraimport java.util.ArrayList;
40f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereiraimport java.util.Collection;
418db7e407109532557718c6b8064792f2df7a073dMindy Pereiraimport java.util.HashMap;
42f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira
438937bf1552a86853efc798a4d8df34c01115cdfdMindy Pereirapublic class SwipeableListView extends ListView implements Callback {
44f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    private SwipeHelper mSwipeHelper;
45ff9aff3c28c4c20c7866ebfaaa642997e324f274Mindy Pereira    private boolean mEnableSwipe = false;
46489dd22c64c718b6953b4bd6acef925e82c53c87Andy Huang
47b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrook    public static final String LOG_TAG = LogTag.getLogTag();
48f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira
49866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira    private ConversationSelectionSet mConvSelectionSet;
506c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira    private int mSwipeAction;
5106642fab1bf4ab95b5dd97a65b262845cf60c865Mindy Pereira    private Folder mFolder;
52866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira
53f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    public SwipeableListView(Context context) {
54f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira        this(context, null);
55f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    }
56f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira
57f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    public SwipeableListView(Context context, AttributeSet attrs) {
58f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira        this(context, attrs, -1);
59f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    }
60f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira
61f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    public SwipeableListView(Context context, AttributeSet attrs, int defStyle) {
62f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira        super(context, attrs, defStyle);
63f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira        float densityScale = getResources().getDisplayMetrics().density;
64f913894d3f1fa80b7174477999074b813e1deb12Mindy Pereira        float pagingTouchSlop = ViewConfiguration.get(context).getScaledPagingTouchSlop();
656f0b2be9d3855e93ec2977b2736798c60adb9b7eMindy Pereira        mSwipeHelper = new SwipeHelper(context, SwipeHelper.X, this, densityScale,
666f0b2be9d3855e93ec2977b2736798c60adb9b7eMindy Pereira                pagingTouchSlop);
67f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    }
68f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira
69f913894d3f1fa80b7174477999074b813e1deb12Mindy Pereira    @Override
70f913894d3f1fa80b7174477999074b813e1deb12Mindy Pereira    protected void onConfigurationChanged(Configuration newConfig) {
71f913894d3f1fa80b7174477999074b813e1deb12Mindy Pereira        super.onConfigurationChanged(newConfig);
72f913894d3f1fa80b7174477999074b813e1deb12Mindy Pereira        float densityScale = getResources().getDisplayMetrics().density;
73f913894d3f1fa80b7174477999074b813e1deb12Mindy Pereira        mSwipeHelper.setDensityScale(densityScale);
74f913894d3f1fa80b7174477999074b813e1deb12Mindy Pereira        float pagingTouchSlop = ViewConfiguration.get(getContext()).getScaledPagingTouchSlop();
75f913894d3f1fa80b7174477999074b813e1deb12Mindy Pereira        mSwipeHelper.setPagingTouchSlop(pagingTouchSlop);
76f913894d3f1fa80b7174477999074b813e1deb12Mindy Pereira    }
77f913894d3f1fa80b7174477999074b813e1deb12Mindy Pereira
78ff9aff3c28c4c20c7866ebfaaa642997e324f274Mindy Pereira    /**
79ff9aff3c28c4c20c7866ebfaaa642997e324f274Mindy Pereira     * Enable swipe gestures.
80ff9aff3c28c4c20c7866ebfaaa642997e324f274Mindy Pereira     */
81ff9aff3c28c4c20c7866ebfaaa642997e324f274Mindy Pereira    public void enableSwipe(boolean enable) {
82ff9aff3c28c4c20c7866ebfaaa642997e324f274Mindy Pereira        mEnableSwipe = enable;
83ff9aff3c28c4c20c7866ebfaaa642997e324f274Mindy Pereira    }
84ff9aff3c28c4c20c7866ebfaaa642997e324f274Mindy Pereira
85f07269fdfbc0ca2607dad50bfc15c2c041c1faddMindy Pereira    public boolean isSwipeEnabled() {
86f07269fdfbc0ca2607dad50bfc15c2c041c1faddMindy Pereira        return mEnableSwipe;
87f07269fdfbc0ca2607dad50bfc15c2c041c1faddMindy Pereira    }
88f07269fdfbc0ca2607dad50bfc15c2c041c1faddMindy Pereira
896c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira    public void setSwipeAction(int action) {
906c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira        mSwipeAction = action;
91f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    }
92f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira
93de3e74a82043733243c7391d7f983a5af8842891Mindy Pereira    public int getSwipeAction() {
94de3e74a82043733243c7391d7f983a5af8842891Mindy Pereira        return mSwipeAction;
95de3e74a82043733243c7391d7f983a5af8842891Mindy Pereira    }
96de3e74a82043733243c7391d7f983a5af8842891Mindy Pereira
97866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira    public void setSelectionSet(ConversationSelectionSet set) {
98866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira        mConvSelectionSet = set;
99866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira    }
100866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira
10106642fab1bf4ab95b5dd97a65b262845cf60c865Mindy Pereira    public void setCurrentFolder(Folder folder) {
10206642fab1bf4ab95b5dd97a65b262845cf60c865Mindy Pereira        mFolder = folder;
10306642fab1bf4ab95b5dd97a65b262845cf60c865Mindy Pereira    }
10406642fab1bf4ab95b5dd97a65b262845cf60c865Mindy Pereira
105866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira    @Override
106866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira    public ConversationSelectionSet getSelectionSet() {
107866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira        return mConvSelectionSet;
108866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira    }
109866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira
110f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    @Override
111f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    public boolean onInterceptTouchEvent(MotionEvent ev) {
112ff9aff3c28c4c20c7866ebfaaa642997e324f274Mindy Pereira        if (mEnableSwipe) {
11300ffece08e94ff5774b2a53c0adeb2f3d0815d66Mindy Pereira            return mSwipeHelper.onInterceptTouchEvent(ev) || super.onInterceptTouchEvent(ev);
11419bf5f5a4944f5bb4e62e1f32c47dce87f662cbdMindy Pereira        } else {
11519bf5f5a4944f5bb4e62e1f32c47dce87f662cbdMindy Pereira            return super.onInterceptTouchEvent(ev);
11619bf5f5a4944f5bb4e62e1f32c47dce87f662cbdMindy Pereira        }
117f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    }
118f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira
119f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    @Override
120f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    public boolean onTouchEvent(MotionEvent ev) {
121ff9aff3c28c4c20c7866ebfaaa642997e324f274Mindy Pereira        if (mEnableSwipe) {
12219bf5f5a4944f5bb4e62e1f32c47dce87f662cbdMindy Pereira            return mSwipeHelper.onTouchEvent(ev) || super.onTouchEvent(ev);
12319bf5f5a4944f5bb4e62e1f32c47dce87f662cbdMindy Pereira        } else {
12419bf5f5a4944f5bb4e62e1f32c47dce87f662cbdMindy Pereira            return super.onTouchEvent(ev);
12519bf5f5a4944f5bb4e62e1f32c47dce87f662cbdMindy Pereira        }
126f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    }
127f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira
128f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    @Override
129f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    public View getChildAtPosition(MotionEvent ev) {
130f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira        // find the view under the pointer, accounting for GONE views
131f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira        final int count = getChildCount();
132f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira        int touchY = (int) ev.getY();
133f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira        int childIdx = 0;
134f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira        View slidingChild;
135f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira        for (; childIdx < count; childIdx++) {
136f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira            slidingChild = getChildAt(childIdx);
137f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira            if (slidingChild.getVisibility() == GONE) {
138f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira                continue;
139f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira            }
140866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira            if (touchY >= slidingChild.getTop() && touchY <= slidingChild.getBottom()) {
1411ef988f0c8be136fda75ed207c222413db1d3f0cMindy Pereira                if (slidingChild instanceof SwipeableConversationItemView) {
1421ef988f0c8be136fda75ed207c222413db1d3f0cMindy Pereira                    return ((SwipeableConversationItemView) slidingChild).getSwipeableItemView();
1431ef988f0c8be136fda75ed207c222413db1d3f0cMindy Pereira                }
144866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira                return slidingChild;
145866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira            }
146f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira        }
147f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira        return null;
148f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    }
149f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira
150f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    @Override
1516c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira    public boolean canChildBeDismissed(SwipeableItemView v) {
1526c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira        View view = v.getView();
1536c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira        return view instanceof ConversationItemView || view instanceof LeaveBehindItem;
154f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    }
155f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira
156f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    @Override
1576c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira    public void onChildDismissed(SwipeableItemView v) {
1586c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira        View view = v.getView();
159c3180e021cdf6aa13545682b7eda4f38a6baf51aMindy Pereira        if (view != null) {
160c3180e021cdf6aa13545682b7eda4f38a6baf51aMindy Pereira            if (view instanceof ConversationItemView) {
161c3180e021cdf6aa13545682b7eda4f38a6baf51aMindy Pereira                dismissChildren((ConversationItemView) view, null);
162c3180e021cdf6aa13545682b7eda4f38a6baf51aMindy Pereira            } else if (view instanceof LeaveBehindItem) {
163c3180e021cdf6aa13545682b7eda4f38a6baf51aMindy Pereira                ((LeaveBehindItem) view).commit();
164c3180e021cdf6aa13545682b7eda4f38a6baf51aMindy Pereira            }
1656c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira        }
166f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    }
167f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira
1688937bf1552a86853efc798a4d8df34c01115cdfdMindy Pereira    // Call this whenever a new action is taken; this forces a commit of any
1698937bf1552a86853efc798a4d8df34c01115cdfdMindy Pereira    // existing destructive actions.
1708937bf1552a86853efc798a4d8df34c01115cdfdMindy Pereira    public void commitDestructiveActions() {
1710fb551891757ecddccb299d9df770bb1675e3fd2Mindy Pereira        final AnimatedAdapter adapter = getAnimatedAdapter();
1728937bf1552a86853efc798a4d8df34c01115cdfdMindy Pereira        if (adapter != null) {
1738937bf1552a86853efc798a4d8df34c01115cdfdMindy Pereira            adapter.commitLeaveBehindItems();
1748937bf1552a86853efc798a4d8df34c01115cdfdMindy Pereira        }
1758937bf1552a86853efc798a4d8df34c01115cdfdMindy Pereira    }
1768937bf1552a86853efc798a4d8df34c01115cdfdMindy Pereira
177f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    @Override
17868f83843e821d9627a53f68244dbc4cb26662edcMindy Pereira    public void onChildrenDismissed(SwipeableItemView target,
17968f83843e821d9627a53f68244dbc4cb26662edcMindy Pereira            Collection<ConversationItemView> views) {
18000ffece08e94ff5774b2a53c0adeb2f3d0815d66Mindy Pereira        assert (target instanceof ConversationItemView);
1816c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira        dismissChildren((ConversationItemView) target.getView(), views);
182866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira    }
183866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira
1846c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira    private void dismissChildren(final ConversationItemView target,
1856c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira            final Collection<ConversationItemView> conversationViews) {
1866c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira        final Context context = getContext();
1870fb551891757ecddccb299d9df770bb1675e3fd2Mindy Pereira        final AnimatedAdapter adapter = getAnimatedAdapter();
188d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira        final ToastBarOperation undoOp;
1896c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira        if (conversationViews != null) {
1906c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira            final ArrayList<Conversation> conversations = new ArrayList<Conversation>(
1916c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira                    conversationViews.size());
19206642fab1bf4ab95b5dd97a65b262845cf60c865Mindy Pereira            Conversation conversation;
1936c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira            for (ConversationItemView view : conversationViews) {
1946c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira                if (view.getConversation().id != target.getConversation().id) {
19506642fab1bf4ab95b5dd97a65b262845cf60c865Mindy Pereira                    conversation = view.getConversation();
19606642fab1bf4ab95b5dd97a65b262845cf60c865Mindy Pereira                    conversation.localDeleteOnUpdate = true;
19706642fab1bf4ab95b5dd97a65b262845cf60c865Mindy Pereira                    conversations.add(conversation);
1986c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira                }
1996c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira            }
20000ffece08e94ff5774b2a53c0adeb2f3d0815d66Mindy Pereira            undoOp = new ToastBarOperation(conversationViews != null ? (conversations.size() + 1)
20100ffece08e94ff5774b2a53c0adeb2f3d0815d66Mindy Pereira                    : 1, mSwipeAction, ToastBarOperation.UNDO);
2026c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira            handleLeaveBehind(target, undoOp, context);
20309a4bfe3f81ee216b5c4a4e2d083432a4e387abdVikram Aggarwal            adapter.delete(conversations, new DestructiveAction() {
204bf232c3735f65b1a4746943e4a134e59e36f0bdePaul Westbrook                @Override
20509a4bfe3f81ee216b5c4a4e2d083432a4e387abdVikram Aggarwal                public void performAction() {
2068db7e407109532557718c6b8064792f2df7a073dMindy Pereira                    ConversationCursor cc = (ConversationCursor) adapter.getCursor();
2076c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira                    switch (mSwipeAction) {
2086c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira                        case R.id.archive:
209bf232c3735f65b1a4746943e4a134e59e36f0bdePaul Westbrook                            cc.archive(context, conversations);
2106c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira                            break;
21106642fab1bf4ab95b5dd97a65b262845cf60c865Mindy Pereira                        case R.id.change_folder:
2128db7e407109532557718c6b8064792f2df7a073dMindy Pereira                            FolderOperation folderOp = new FolderOperation(mFolder, false);
2138db7e407109532557718c6b8064792f2df7a073dMindy Pereira                            // For each conversation, for each operation, remove
2148db7e407109532557718c6b8064792f2df7a073dMindy Pereira                            // the current folder.
2158db7e407109532557718c6b8064792f2df7a073dMindy Pereira                            for (Conversation target : conversations) {
2168db7e407109532557718c6b8064792f2df7a073dMindy Pereira                                HashMap<Uri, Folder> targetFolders = Folder
21768f83843e821d9627a53f68244dbc4cb26662edcMindy Pereira                                        .hashMapForFolders(target.getRawFolders());
2188db7e407109532557718c6b8064792f2df7a073dMindy Pereira                                targetFolders.remove(folderOp.mFolder.uri);
21985c4a77abd849f5f3f0236d51554bb1bb99fe8f6Mindy Pereira                                target.setRawFolders(Folder.getSerializedFolderString(targetFolders
22085c4a77abd849f5f3f0236d51554bb1bb99fe8f6Mindy Pereira                                        .values()));
22100ffece08e94ff5774b2a53c0adeb2f3d0815d66Mindy Pereira                                cc.updateString(context, Conversation.listOf(target),
22285c4a77abd849f5f3f0236d51554bb1bb99fe8f6Mindy Pereira                                        Conversation.UPDATE_FOLDER_COLUMN,
22385c4a77abd849f5f3f0236d51554bb1bb99fe8f6Mindy Pereira                                        target.getRawFoldersString());
2248db7e407109532557718c6b8064792f2df7a073dMindy Pereira                            }
22506642fab1bf4ab95b5dd97a65b262845cf60c865Mindy Pereira                            break;
2266c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira                        case R.id.delete:
227bf232c3735f65b1a4746943e4a134e59e36f0bdePaul Westbrook                            cc.delete(context, conversations);
2286c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira                            break;
2296c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira                    }
2306c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira                }
2316c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira            });
2326c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira        } else {
233d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira            undoOp = new ToastBarOperation(1, mSwipeAction, ToastBarOperation.UNDO);
23468f83843e821d9627a53f68244dbc4cb26662edcMindy Pereira            target.getConversation().position = target.getParent() != null ?
23568f83843e821d9627a53f68244dbc4cb26662edcMindy Pereira                    getPositionForView(target) : -1;
2366c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira            handleLeaveBehind(target, undoOp, context);
237f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira        }
238866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira    }
239866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira
240d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira    private void handleLeaveBehind(ConversationItemView target, ToastBarOperation undoOp,
2416c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira            Context context) {
2426c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira        Conversation conv = target.getConversation();
2430fb551891757ecddccb299d9df770bb1675e3fd2Mindy Pereira        final AnimatedAdapter adapter = getAnimatedAdapter();
24409f1ae9a9f209436c0c6b44a6e76b32b27937a01Mindy Pereira        if (adapter == null) {
24509f1ae9a9f209436c0c6b44a6e76b32b27937a01Mindy Pereira            return;
24609f1ae9a9f209436c0c6b44a6e76b32b27937a01Mindy Pereira        }
2476c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira        adapter.setupLeaveBehind(conv, undoOp, conv.position);
24800ffece08e94ff5774b2a53c0adeb2f3d0815d66Mindy Pereira        ConversationCursor cc = (ConversationCursor) adapter.getCursor();
2496c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira        switch (mSwipeAction) {
25006642fab1bf4ab95b5dd97a65b262845cf60c865Mindy Pereira            case R.id.change_folder:
2518db7e407109532557718c6b8064792f2df7a073dMindy Pereira                FolderOperation folderOp = new FolderOperation(mFolder, false);
2528db7e407109532557718c6b8064792f2df7a073dMindy Pereira                HashMap<Uri, Folder> targetFolders = Folder
25368f83843e821d9627a53f68244dbc4cb26662edcMindy Pereira                        .hashMapForFolders(conv.getRawFolders());
2548db7e407109532557718c6b8064792f2df7a073dMindy Pereira                targetFolders.remove(folderOp.mFolder.uri);
25585c4a77abd849f5f3f0236d51554bb1bb99fe8f6Mindy Pereira                conv.setRawFolders(Folder.getSerializedFolderString(targetFolders.values()));
2568db7e407109532557718c6b8064792f2df7a073dMindy Pereira                cc.mostlyDestructiveUpdate(context, Conversation.listOf(conv),
25785c4a77abd849f5f3f0236d51554bb1bb99fe8f6Mindy Pereira                        Conversation.UPDATE_FOLDER_COLUMN, conv.getRawFoldersString());
25806642fab1bf4ab95b5dd97a65b262845cf60c865Mindy Pereira                break;
2596c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira            case R.id.archive:
260a8ead90ce1e6c66e4ecacdf7cfa25c2cafc9bb3bMindy Pereira                cc.mostlyArchive(context, Conversation.listOf(conv));
2616c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira                break;
2626c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira            case R.id.delete:
263a8ead90ce1e6c66e4ecacdf7cfa25c2cafc9bb3bMindy Pereira                cc.mostlyDelete(context, Conversation.listOf(conv));
2646c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira                break;
2656c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira        }
2666c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira        adapter.notifyDataSetChanged();
267a8ead90ce1e6c66e4ecacdf7cfa25c2cafc9bb3bMindy Pereira        if (mConvSelectionSet != null && !mConvSelectionSet.isEmpty()
268a8ead90ce1e6c66e4ecacdf7cfa25c2cafc9bb3bMindy Pereira                && mConvSelectionSet.contains(conv)) {
269a8ead90ce1e6c66e4ecacdf7cfa25c2cafc9bb3bMindy Pereira            mConvSelectionSet.toggle(null, conv);
270cff4a2b2e92258c6c85ed4af15bc13101aa71170Mindy Pereira        }
271f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    }
272f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira
273f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    @Override
274f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    public void onBeginDrag(View v) {
275f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira        // We do this so the underlying ScrollView knows that it won't get
276f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira        // the chance to intercept events anymore
277f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira        requestDisallowInterceptTouchEvent(true);
2781ef988f0c8be136fda75ed207c222413db1d3f0cMindy Pereira        SwipeableConversationItemView view = null;
2791ef988f0c8be136fda75ed207c222413db1d3f0cMindy Pereira        if (v instanceof ConversationItemView) {
28000ffece08e94ff5774b2a53c0adeb2f3d0815d66Mindy Pereira            view = (SwipeableConversationItemView) v.getParent();
2811ef988f0c8be136fda75ed207c222413db1d3f0cMindy Pereira        }
2821ef988f0c8be136fda75ed207c222413db1d3f0cMindy Pereira        if (view != null) {
2831ef988f0c8be136fda75ed207c222413db1d3f0cMindy Pereira            view.addBackground(getContext(), getSwipeActionText());
2841ef988f0c8be136fda75ed207c222413db1d3f0cMindy Pereira            view.setBackgroundVisibility(View.VISIBLE);
2851ef988f0c8be136fda75ed207c222413db1d3f0cMindy Pereira        }
286f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    }
287f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira
288f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    @Override
2896c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira    public void onDragCancelled(SwipeableItemView v) {
290709a174a40ec296c40368d723c2f51e3fc48ed50Mindy Pereira        SwipeableConversationItemView view = null;
291709a174a40ec296c40368d723c2f51e3fc48ed50Mindy Pereira        if (v instanceof ConversationItemView) {
29200ffece08e94ff5774b2a53c0adeb2f3d0815d66Mindy Pereira            view = (SwipeableConversationItemView) ((View) v).getParent();
293709a174a40ec296c40368d723c2f51e3fc48ed50Mindy Pereira        }
294709a174a40ec296c40368d723c2f51e3fc48ed50Mindy Pereira        if (view != null) {
295709a174a40ec296c40368d723c2f51e3fc48ed50Mindy Pereira            view.removeBackground();
296709a174a40ec296c40368d723c2f51e3fc48ed50Mindy Pereira        }
297f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    }
298f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira
29907118a01f7183645957010779222b84930f75b4eMindy Pereira    /**
300b0219eb7b77212902a38821c050922ac73a68250Mindy Pereira     * Get the position within the adapter's data set for the view, where view is a an adapter item
301b0219eb7b77212902a38821c050922ac73a68250Mindy Pereira     * or a descendant of an adapter item.
302b0219eb7b77212902a38821c050922ac73a68250Mindy Pereira     *
303b0219eb7b77212902a38821c050922ac73a68250Mindy Pereira     * @param view an adapter item, or a descendant of an adapter item. This must be visible in this
304b0219eb7b77212902a38821c050922ac73a68250Mindy Pereira     *        AdapterView at the time of the call.
305b0219eb7b77212902a38821c050922ac73a68250Mindy Pereira     * @return the position within the adapter's data set of the view, or {@link #INVALID_POSITION}
306b0219eb7b77212902a38821c050922ac73a68250Mindy Pereira     *         if the view does not correspond to a list item (or it is not currently visible).
307b0219eb7b77212902a38821c050922ac73a68250Mindy Pereira     */
308ea33a383f6966b67ea63d95566c0834abd5ad117Mindy Pereira    // TODO(mindyp): remove this override once I fix b/6884047
309b0219eb7b77212902a38821c050922ac73a68250Mindy Pereira    @Override
310b0219eb7b77212902a38821c050922ac73a68250Mindy Pereira    public int getPositionForView(View view) {
311b0219eb7b77212902a38821c050922ac73a68250Mindy Pereira        View listItem = view;
312b0219eb7b77212902a38821c050922ac73a68250Mindy Pereira        View v = null;
313b0219eb7b77212902a38821c050922ac73a68250Mindy Pereira        try {
314b0219eb7b77212902a38821c050922ac73a68250Mindy Pereira            while (!(v = (View) listItem.getParent()).equals(this)) {
315b0219eb7b77212902a38821c050922ac73a68250Mindy Pereira                listItem = v;
316b0219eb7b77212902a38821c050922ac73a68250Mindy Pereira            }
317b0219eb7b77212902a38821c050922ac73a68250Mindy Pereira        } catch (ClassCastException e) {
318b0219eb7b77212902a38821c050922ac73a68250Mindy Pereira            // We made it up to the window without find this list view
319b0219eb7b77212902a38821c050922ac73a68250Mindy Pereira            return INVALID_POSITION;
320b0219eb7b77212902a38821c050922ac73a68250Mindy Pereira        } catch (NullPointerException e) {
321c79aec78d06928b3fa1464d6aed60019f9b4843bMindy Pereira            LogUtils.e(LOG_TAG, e, "WHAT HAS NO PARENT "
322c79aec78d06928b3fa1464d6aed60019f9b4843bMindy Pereira                    + (listItem != null ? listItem.getClass() : null));
323b0219eb7b77212902a38821c050922ac73a68250Mindy Pereira            return INVALID_POSITION;
324b0219eb7b77212902a38821c050922ac73a68250Mindy Pereira        }
325b0219eb7b77212902a38821c050922ac73a68250Mindy Pereira        return super.getPositionForView(view);
326b0219eb7b77212902a38821c050922ac73a68250Mindy Pereira    }
327b0219eb7b77212902a38821c050922ac73a68250Mindy Pereira
328b0219eb7b77212902a38821c050922ac73a68250Mindy Pereira    /**
32907118a01f7183645957010779222b84930f75b4eMindy Pereira     * Archive items using the swipe away animation before shrinking them away.
33007118a01f7183645957010779222b84930f75b4eMindy Pereira     */
331c79aec78d06928b3fa1464d6aed60019f9b4843bMindy Pereira    public void destroyItems(final ArrayList<ConversationItemView> views,
33268f83843e821d9627a53f68244dbc4cb26662edcMindy Pereira            final DestructiveAction listener) {
33307118a01f7183645957010779222b84930f75b4eMindy Pereira        if (views == null || views.size() == 0) {
33407118a01f7183645957010779222b84930f75b4eMindy Pereira            return;
33507118a01f7183645957010779222b84930f75b4eMindy Pereira        }
336c79aec78d06928b3fa1464d6aed60019f9b4843bMindy Pereira        // Need to find the items in the LIST!
33707118a01f7183645957010779222b84930f75b4eMindy Pereira        final ArrayList<Conversation> conversations = new ArrayList<Conversation>();
33807118a01f7183645957010779222b84930f75b4eMindy Pereira        for (ConversationItemView view : views) {
339de3e74a82043733243c7391d7f983a5af8842891Mindy Pereira            Conversation conv = view.getConversation();
340c79aec78d06928b3fa1464d6aed60019f9b4843bMindy Pereira            conv.position = conv.position == -1 && view.getParent() != null ?
341c79aec78d06928b3fa1464d6aed60019f9b4843bMindy Pereira                    getPositionForView(view) : conv.position;
342de3e74a82043733243c7391d7f983a5af8842891Mindy Pereira            conversations.add(conv);
34307118a01f7183645957010779222b84930f75b4eMindy Pereira        }
344c79aec78d06928b3fa1464d6aed60019f9b4843bMindy Pereira        AnimatedAdapter adapter = getAnimatedAdapter();
345c79aec78d06928b3fa1464d6aed60019f9b4843bMindy Pereira        if (adapter != null) {
346c79aec78d06928b3fa1464d6aed60019f9b4843bMindy Pereira            adapter.delete(conversations, listener);
347c79aec78d06928b3fa1464d6aed60019f9b4843bMindy Pereira        }
34807118a01f7183645957010779222b84930f75b4eMindy Pereira    }
34907118a01f7183645957010779222b84930f75b4eMindy Pereira
3500fb551891757ecddccb299d9df770bb1675e3fd2Mindy Pereira    private AnimatedAdapter getAnimatedAdapter() {
3510fb551891757ecddccb299d9df770bb1675e3fd2Mindy Pereira        return (AnimatedAdapter) getAdapter();
3520fb551891757ecddccb299d9df770bb1675e3fd2Mindy Pereira    }
3530fb551891757ecddccb299d9df770bb1675e3fd2Mindy Pereira
354f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    public interface SwipeCompleteListener {
355f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira        public void onSwipeComplete(Collection<Conversation> conversations);
356f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    }
3578937bf1552a86853efc798a4d8df34c01115cdfdMindy Pereira
3588937bf1552a86853efc798a4d8df34c01115cdfdMindy Pereira    @Override
3598937bf1552a86853efc798a4d8df34c01115cdfdMindy Pereira    public boolean performItemClick(View view, int pos, long id) {
360dd9d3a16148b178cb95fd4db4168a67c64eb944fMindy Pereira        boolean handled = super.performItemClick(view, pos, id);
36100ffece08e94ff5774b2a53c0adeb2f3d0815d66Mindy Pereira        // Commit any existing destructive actions when the user selects a
36200ffece08e94ff5774b2a53c0adeb2f3d0815d66Mindy Pereira        // conversation to view.
3638937bf1552a86853efc798a4d8df34c01115cdfdMindy Pereira        commitDestructiveActions();
364dd9d3a16148b178cb95fd4db4168a67c64eb944fMindy Pereira        return handled;
3658937bf1552a86853efc798a4d8df34c01115cdfdMindy Pereira    }
3661ef988f0c8be136fda75ed207c222413db1d3f0cMindy Pereira
3671ef988f0c8be136fda75ed207c222413db1d3f0cMindy Pereira    /**
3681ef988f0c8be136fda75ed207c222413db1d3f0cMindy Pereira     * Get the text resource corresponding to the result of a swipe.
3691ef988f0c8be136fda75ed207c222413db1d3f0cMindy Pereira     */
3701ef988f0c8be136fda75ed207c222413db1d3f0cMindy Pereira    public int getSwipeActionText() {
3711ef988f0c8be136fda75ed207c222413db1d3f0cMindy Pereira        switch (mSwipeAction) {
3721ef988f0c8be136fda75ed207c222413db1d3f0cMindy Pereira            case R.id.archive:
3731ef988f0c8be136fda75ed207c222413db1d3f0cMindy Pereira                return R.string.archive;
3741ef988f0c8be136fda75ed207c222413db1d3f0cMindy Pereira            case R.id.delete:
3751ef988f0c8be136fda75ed207c222413db1d3f0cMindy Pereira                return R.string.delete;
3761ef988f0c8be136fda75ed207c222413db1d3f0cMindy Pereira            case R.id.change_folder:
377c1e93c71f2b2d689eda2c3309cf4c1c30118b2c2Mindy Pereira                return R.string.remove_folder;
3781ef988f0c8be136fda75ed207c222413db1d3f0cMindy Pereira        }
3791ef988f0c8be136fda75ed207c222413db1d3f0cMindy Pereira        return -1;
3801ef988f0c8be136fda75ed207c222413db1d3f0cMindy Pereira    }
38100ffece08e94ff5774b2a53c0adeb2f3d0815d66Mindy Pereira}
382