Bug 1116415 - 3. Add an ItemTouchHelper to the tabs panel list for swipe to close. r?sebastian draft
authorTom Klein <twointofive@gmail.com>
Mon, 12 Sep 2016 10:46:30 -0500
changeset 425501 2da7c360ca45b2d6dc11e69d0399c00f8467453b
parent 425500 4a2b54b24d24495875121d764f3e07f07be46f7b
child 425502 601fc8169aa2b9d93907ebab5669a1653df5bc31
push id32434
push userbmo:twointofive@gmail.com
push dateFri, 14 Oct 2016 20:21:22 +0000
reviewerssebastian
bugs1116415
milestone52.0a1
Bug 1116415 - 3. Add an ItemTouchHelper to the tabs panel list for swipe to close. r?sebastian MozReview-Commit-ID: 8QlbSg7qsZK
mobile/android/base/java/org/mozilla/gecko/tabs/TabsLayout.java
mobile/android/base/java/org/mozilla/gecko/tabs/TabsListLayout.java
mobile/android/base/java/org/mozilla/gecko/tabs/TabsTouchHelperCallback.java
mobile/android/base/moz.build
--- a/mobile/android/base/java/org/mozilla/gecko/tabs/TabsLayout.java
+++ b/mobile/android/base/java/org/mozilla/gecko/tabs/TabsLayout.java
@@ -18,17 +18,18 @@ import android.util.AttributeSet;
 import android.view.View;
 import android.widget.Button;
 
 import java.util.ArrayList;
 
 public abstract class TabsLayout extends RecyclerView
         implements TabsPanel.TabsLayout,
         Tabs.OnTabsChangedListener,
-        RecyclerViewClickSupport.OnItemClickListener {
+        RecyclerViewClickSupport.OnItemClickListener,
+        TabsTouchHelperCallback.DismissListener {
 
     private static final String LOGTAG = "Gecko" + TabsLayout.class.getSimpleName();
 
     private final boolean isPrivate;
     private TabsPanel tabsPanel;
     private final TabsLayoutRecyclerAdapter tabsAdapter;
 
     public TabsLayout(Context context, AttributeSet attrs, int itemViewLayoutResId) {
@@ -169,16 +170,21 @@ public abstract class TabsLayout extends
             // In the normal panel we want to close all tabs (both private and normal),
             // but in the private panel we only want to close private tabs.
             if (!isPrivate || tab.isPrivate()) {
                 Tabs.getInstance().closeTab(tab, false);
             }
         }
     }
 
+    @Override
+    public void onItemDismiss(View view) {
+        closeTab(view);
+    }
+
     private Tab getTabForView(View view) {
         if (view == null) {
             return null;
         }
         return Tabs.getInstance().getTab(((TabsLayoutItemView) view).getTabId());
     }
 
     @Override
--- a/mobile/android/base/java/org/mozilla/gecko/tabs/TabsListLayout.java
+++ b/mobile/android/base/java/org/mozilla/gecko/tabs/TabsListLayout.java
@@ -6,16 +6,17 @@
 package org.mozilla.gecko.tabs;
 
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.animation.PropertyAnimator;
 import org.mozilla.gecko.util.ThreadUtils;
 
 import android.content.Context;
 import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.helper.ItemTouchHelper;
 import android.util.AttributeSet;
 import android.view.View;
 
 public class TabsListLayout extends TabsLayout {
     // Time to animate non-flinged tabs of screen, in milliseconds
     private static final int ANIMATION_DURATION = 250;
 
     // Time between starting successive tab animations in closeAllTabs.
@@ -24,16 +25,21 @@ public class TabsListLayout extends Tabs
     private int closeAllAnimationCount;
 
     public TabsListLayout(Context context, AttributeSet attrs) {
         super(context, attrs, R.layout.tabs_list_item_view);
 
         setHasFixedSize(true);
 
         setLayoutManager(new LinearLayoutManager(context));
+
+        // A TouchHelper handler for swipe to close.
+        final TabsTouchHelperCallback callback = new TabsTouchHelperCallback(this);
+        final ItemTouchHelper touchHelper = new ItemTouchHelper(callback);
+        touchHelper.attachToRecyclerView(this);
     }
 
     @Override
     public void closeAll() {
         final int childCount = getChildCount();
 
         // Just close the panel if there are no tabs to close.
         if (childCount == 0) {
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/java/org/mozilla/gecko/tabs/TabsTouchHelperCallback.java
@@ -0,0 +1,69 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.tabs;
+
+import android.graphics.Canvas;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.helper.ItemTouchHelper;
+import android.view.View;
+
+class TabsTouchHelperCallback extends ItemTouchHelper.Callback {
+    private final DismissListener dismissListener;
+
+    interface DismissListener {
+        void onItemDismiss(View view);
+    }
+
+    public TabsTouchHelperCallback(DismissListener dismissListener) {
+        this.dismissListener = dismissListener;
+    }
+
+    @Override
+    public boolean isItemViewSwipeEnabled() {
+        return true;
+    }
+
+    @Override
+    public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
+        return makeFlag(ItemTouchHelper.ACTION_STATE_SWIPE, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT);
+    }
+
+    @Override
+    public void onSwiped(RecyclerView.ViewHolder viewHolder, int i) {
+        dismissListener.onItemDismiss(viewHolder.itemView);
+    }
+
+    @Override
+    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,
+                          RecyclerView.ViewHolder target) {
+        return false;
+    }
+
+    // Alpha on an itemView being swiped should decrease to a min over a distance equal to the
+    // width of the item being swiped.
+    @Override
+    public void onChildDraw(Canvas c,
+                            RecyclerView recyclerView,
+                            RecyclerView.ViewHolder viewHolder,
+                            float dX,
+                            float dY,
+                            int actionState,
+                            boolean isCurrentlyActive) {
+        if (actionState != ItemTouchHelper.ACTION_STATE_SWIPE) {
+            return;
+        }
+
+        super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
+
+        viewHolder.itemView.setAlpha(Math.max(0.1f,
+                Math.min(1f, 1f - 2f * Math.abs(dX) / viewHolder.itemView.getWidth())));
+    }
+
+    public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
+        super.clearView(recyclerView, viewHolder);
+        viewHolder.itemView.setAlpha(1);
+    }
+}
--- a/mobile/android/base/moz.build
+++ b/mobile/android/base/moz.build
@@ -669,16 +669,17 @@ gbjar.sources += ['java/org/mozilla/geck
     'tabs/TabsGridLayout.java',
     'tabs/TabsLayout.java',
     'tabs/TabsLayoutAdapter.java',
     'tabs/TabsLayoutItemView.java',
     'tabs/TabsLayoutRecyclerAdapter.java',
     'tabs/TabsListLayout.java',
     'tabs/TabsPanel.java',
     'tabs/TabsPanelThumbnailView.java',
+    'tabs/TabsTouchHelperCallback.java',
     'Telemetry.java',
     'telemetry/measurements/CampaignIdMeasurements.java',
     'telemetry/measurements/SearchCountMeasurements.java',
     'telemetry/measurements/SessionMeasurements.java',
     'telemetry/pingbuilders/TelemetryCorePingBuilder.java',
     'telemetry/pingbuilders/TelemetryPingBuilder.java',
     'telemetry/schedulers/TelemetryUploadAllPingsImmediatelyScheduler.java',
     'telemetry/schedulers/TelemetryUploadScheduler.java',