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