Dbrant has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/158370

Change subject: Bounce out the ToC when scrolling like a madman.
......................................................................

Bounce out the ToC when scrolling like a madman.

- Nudge out the ToC when scrolled beyond a defined vertical threshold.
- Also expand the active drag edge of the drawers for easier pulling (see
  bug)

Bug: 65004

Change-Id: I4cf0f4693c7c38e743b46a69aa84c2c61a0d1d00
---
M wikipedia/res/layout/activity_main.xml
M wikipedia/src/main/java/org/wikipedia/ViewAnimations.java
M wikipedia/src/main/java/org/wikipedia/page/PageViewFragment.java
M wikipedia/src/main/java/org/wikipedia/page/ToCHandler.java
M wikipedia/src/main/java/org/wikipedia/views/DisableableDrawerLayout.java
M wikipedia/src/main/java/org/wikipedia/views/ObservableWebView.java
6 files changed, 146 insertions(+), 45 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/apps/android/wikipedia 
refs/changes/70/158370/1

diff --git a/wikipedia/res/layout/activity_main.xml 
b/wikipedia/res/layout/activity_main.xml
index fca585f..cccdc98 100644
--- a/wikipedia/res/layout/activity_main.xml
+++ b/wikipedia/res/layout/activity_main.xml
@@ -1,7 +1,7 @@
 <FrameLayout
         xmlns:android="http://schemas.android.com/apk/res/android";
         xmlns:tools="http://schemas.android.com/tools"; 
android:layout_width="match_parent" android:layout_height="match_parent">
-    <android.support.v4.widget.DrawerLayout
+    <org.wikipedia.views.DisableableDrawerLayout
             android:id="@+id/drawer_layout"
             android:layout_width="match_parent"
             android:saveEnabled="false"
@@ -19,7 +19,7 @@
                   android:layout_gravity="start"
                   tools:layout="@layout/fragment_navdrawer"/>
 
-    </android.support.v4.widget.DrawerLayout>
+    </org.wikipedia.views.DisableableDrawerLayout>
     <LinearLayout android:layout_width="match_parent" 
android:layout_height="match_parent" android:id="@+id/zero_crouton_container">
     <fragment
             android:id="@+id/search_fragment"
diff --git a/wikipedia/src/main/java/org/wikipedia/ViewAnimations.java 
b/wikipedia/src/main/java/org/wikipedia/ViewAnimations.java
index e2dd558..65d9522 100644
--- a/wikipedia/src/main/java/org/wikipedia/ViewAnimations.java
+++ b/wikipedia/src/main/java/org/wikipedia/ViewAnimations.java
@@ -197,4 +197,18 @@
             
animate(view).translationY(translation).setDuration(SHORT_ANIMATION_DURATION).start();
         }
     }
+
+    /**
+     * Ensures that the translationX of a particular view is the given value.
+     *
+     * If it isn't the current value, then it performs a short animation to 
make it so.
+     *
+     * @param view The view to translate
+     * @param translation The value to ensure it is translated by
+     */
+    public static void ensureTranslationX(View view, int translation) {
+        if (ViewHelper.getTranslationX(view) != translation) {
+            
animate(view).translationX(translation).setDuration(SHORT_ANIMATION_DURATION).start();
+        }
+    }
 }
diff --git a/wikipedia/src/main/java/org/wikipedia/page/PageViewFragment.java 
b/wikipedia/src/main/java/org/wikipedia/page/PageViewFragment.java
index 9cdbd9b..8c4ea38 100644
--- a/wikipedia/src/main/java/org/wikipedia/page/PageViewFragment.java
+++ b/wikipedia/src/main/java/org/wikipedia/page/PageViewFragment.java
@@ -435,6 +435,17 @@
 
         new QuickReturnHandler(webView, quickReturnBar);
 
+        webView.setOnFrustratedScrollListener(new 
ObservableWebView.OnFrustratedScrollListener() {
+            private boolean shown = false;
+            @Override
+            public void onFrustratedScroll() {
+                if (!shown) {
+                    tocDrawer.nudgeOut();
+                    //shown = true;
+                }
+            }
+        });
+
         setState(state);
         performActionForState(state);
     }
diff --git a/wikipedia/src/main/java/org/wikipedia/page/ToCHandler.java 
b/wikipedia/src/main/java/org/wikipedia/page/ToCHandler.java
index c3f4385..954da77 100644
--- a/wikipedia/src/main/java/org/wikipedia/page/ToCHandler.java
+++ b/wikipedia/src/main/java/org/wikipedia/page/ToCHandler.java
@@ -4,6 +4,7 @@
 import android.support.v4.widget.DrawerLayout;
 import android.text.Html;
 import android.util.Log;
+import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -81,6 +82,15 @@
             public void onDrawerSlide(View drawerView, float slideOffset) {
                 super.onDrawerSlide(drawerView, slideOffset);
             }
+
+            @Override
+            public void onDrawerStateChanged(int state) {
+                super.onDrawerStateChanged(state);
+                //if we're in the process of pulling the ToC, make sure to 
un-nudge it, in case it's nudged out.
+                if (state != DrawerLayout.STATE_IDLE) {
+                    slidingPane.unNudge();
+                }
+            }
         });
     }
 
@@ -145,17 +155,17 @@
     }
 
     public void show() {
-        if (slidingPane.getSlidingEnabled()) {
-            slidingPane.openDrawer();
+        if (slidingPane.getSlidingEnabled(Gravity.END)) {
+            slidingPane.openDrawer(Gravity.END);
         }
     }
 
     public void hide() {
-        slidingPane.closeDrawer();
+        slidingPane.closeDrawer(Gravity.END);
     }
 
     public boolean isVisible() {
-        return slidingPane.isDrawerOpen();
+        return slidingPane.isDrawerOpen(Gravity.END);
     }
 
     private final class ToCAdapter extends BaseAdapter {
diff --git 
a/wikipedia/src/main/java/org/wikipedia/views/DisableableDrawerLayout.java 
b/wikipedia/src/main/java/org/wikipedia/views/DisableableDrawerLayout.java
index 72691df..a55e779 100644
--- a/wikipedia/src/main/java/org/wikipedia/views/DisableableDrawerLayout.java
+++ b/wikipedia/src/main/java/org/wikipedia/views/DisableableDrawerLayout.java
@@ -1,17 +1,22 @@
 package org.wikipedia.views;
 
+import org.wikipedia.ViewAnimations;
 import android.content.Context;
 import android.support.v4.view.GravityCompat;
 import android.support.v4.view.ViewCompat;
 import android.support.v4.widget.DrawerLayout;
+import android.support.v4.widget.ViewDragHelper;
+import android.text.format.DateUtils;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.Gravity;
 import android.view.View;
+import java.lang.reflect.Field;
 
 public class DisableableDrawerLayout extends DrawerLayout {
 
-    public boolean getSlidingEnabled() {
-        return getDrawerLockMode(getGravity()) == 
DrawerLayout.LOCK_MODE_UNLOCKED;
+    public boolean getSlidingEnabled(int gravity) {
+        return getDrawerLockMode(gravity) == DrawerLayout.LOCK_MODE_UNLOCKED;
     }
 
     public void setSlidingEnabled(boolean enable) {
@@ -22,53 +27,85 @@
         }
     }
 
-    private int gravity = -1;
-
-    /**
-     * Ascertain the gravity of the child drawer of this layout. When 
constructing the layout in XML,
-     * the gravity is assigned as an attribute. However, in an RTL 
environment, the gravity may actually
-     * be flipped. This will help us determine the actual gravity of the 
drawer at runtime.
-     * @return Gravity of the drawer view that this layout contains.
-     */
-    private int getGravity() {
-        if (gravity == -1) {
-            int childCount = getChildCount();
-            for (int i = 0; i < childCount; i++) {
-                final View child = getChildAt(i);
-                int childGravity = 
GravityCompat.getAbsoluteGravity(((LayoutParams) 
child.getLayoutParams()).gravity,
-                                                                     
ViewCompat.getLayoutDirection(child));
-                if ((childGravity & Gravity.HORIZONTAL_GRAVITY_MASK) == 
(Gravity.LEFT & Gravity.HORIZONTAL_GRAVITY_MASK)) {
-                    gravity = Gravity.LEFT;
-                } else if ((childGravity & Gravity.HORIZONTAL_GRAVITY_MASK) == 
(Gravity.RIGHT & Gravity.HORIZONTAL_GRAVITY_MASK)) {
-                    gravity = Gravity.RIGHT;
-                }
-            }
-        }
-        return gravity;
-    }
-
-    public void openDrawer() {
-        openDrawer(getGravity());
-    }
-
-    public void closeDrawer() {
-        closeDrawer(getGravity());
-    }
-
-    public boolean isDrawerOpen() {
-        return isDrawerOpen(getGravity());
-    }
-
     public DisableableDrawerLayout(Context context) {
         super(context);
+        setDragEdgeWidth();
     }
 
     public DisableableDrawerLayout(Context context, AttributeSet attrs) {
         super(context, attrs);
+        setDragEdgeWidth();
     }
 
     public DisableableDrawerLayout(Context context, AttributeSet attrs, int 
defStyle) {
         super(context, attrs, defStyle);
+        setDragEdgeWidth();
+    }
+
+    /**
+     * The logical width (in dp) of the drag edge from which the user can drag 
out the drawer.
+     */
+    private static final int DRAG_EDGE_WIDTH = 48;
+
+    /**
+     * The amount (in dp) by which the drawer can be "nudged" out.
+     */
+    private static final int NUDGE_AMOUNT_DP = 60;
+
+    private void setDragEdgeWidth() {
+        this.post(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    // Use a little bit of reflection to set a private member 
in DrawerLayout that extends the
+                    // "drag edge" from which the drawer can be pulled by the 
user.
+                    // A bit hacky, but what are you gonna do...
+                    View pullOutView = getChildAt(1);
+                    int absGravity = 
GravityCompat.getAbsoluteGravity(((LayoutParams)pullOutView.getLayoutParams()).gravity,
+                                                                      
ViewCompat.getLayoutDirection(pullOutView));
+                    // Determine whether to modify the left or right dragger, 
based on RTL/LTR orientation
+                    Field mDragger = (absGravity & 
Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.LEFT
+                            ? 
DisableableDrawerLayout.this.getClass().getSuperclass().getDeclaredField("mLeftDragger")
+                            : 
DisableableDrawerLayout.this.getClass().getSuperclass().getDeclaredField("mRightDragger");
+                    mDragger.setAccessible(true);
+                    ViewDragHelper dragHelper = (ViewDragHelper) 
mDragger.get(DisableableDrawerLayout.this);
+                    Field edgeWidth = 
dragHelper.getClass().getDeclaredField("mEdgeSize");
+                    edgeWidth.setAccessible(true);
+                    edgeWidth.setInt(dragHelper, (int)(DRAG_EDGE_WIDTH * 
getResources().getDisplayMetrics().density));
+                } catch (Exception e) {
+                    Log.e("DisableableDrawerLayout", "Setting the draggable 
zone for the drawer failed!", e);
+                }
+            }
+        });
+    }
+
+    /**
+     * Nudge out the drawer, and automatically put it back after a short time.
+     */
+    public void nudgeOut() {
+        View pullOutView = getChildAt(1);
+        int absGravity = 
GravityCompat.getAbsoluteGravity(((LayoutParams)pullOutView.getLayoutParams()).gravity,
+                                                   
ViewCompat.getLayoutDirection(pullOutView));
+        pullOutView.setVisibility(View.VISIBLE);
+        // Determine whether to move it left or right, based on RTL/LTR 
orientation
+        ViewAnimations.ensureTranslationX(pullOutView, ((absGravity & 
Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.LEFT ? 1 : -1)
+                                                * (int)(NUDGE_AMOUNT_DP * 
getResources().getDisplayMetrics().density));
+
+        // un-nudge the drawer after two seconds!
+        this.postDelayed(new Runnable() {
+            @Override
+            public void run() {
+                unNudge();
+            }
+        }, DateUtils.SECOND_IN_MILLIS * 2);
+    }
+
+    /**
+     * Explicitly un-nudge the drawer. (Does nothing if the drawer isn't 
nudged to begin with.)
+     */
+    public void unNudge() {
+        View pullOutView = getChildAt(1);
+        ViewAnimations.ensureTranslationX(pullOutView, 0);
     }
 
 }
diff --git a/wikipedia/src/main/java/org/wikipedia/views/ObservableWebView.java 
b/wikipedia/src/main/java/org/wikipedia/views/ObservableWebView.java
index f3771e3..b41f9c4 100644
--- a/wikipedia/src/main/java/org/wikipedia/views/ObservableWebView.java
+++ b/wikipedia/src/main/java/org/wikipedia/views/ObservableWebView.java
@@ -1,6 +1,7 @@
 package org.wikipedia.views;
 
 import android.content.Context;
+import android.text.format.DateUtils;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
 import android.webkit.WebView;
@@ -12,6 +13,7 @@
     private OnScrollChangeListener onScrollChangeListener;
     private OnDownMotionEventListener onDownMotionEventListener;
     private OnUpOrCancelMotionEventListener onUpOrCancelMotionEventListener;
+    private OnFrustratedScrollListener onFrustratedScrollListener;
 
     public OnScrollChangeListener getOnScrollChangeListener() {
         return onScrollChangeListener;
@@ -37,6 +39,14 @@
         this.onUpOrCancelMotionEventListener = onUpOrCancelMotionEventListener;
     }
 
+    public OnFrustratedScrollListener getOnFrustratedScrollListener() {
+        return onFrustratedScrollListener;
+    }
+
+    public void setOnFrustratedScrollListener(OnFrustratedScrollListener 
onFrustratedScrollListener) {
+        this.onFrustratedScrollListener = onFrustratedScrollListener;
+    }
+
     public interface OnScrollChangeListener {
         void onScrollChanged(int oldScrollY, int scrollY);
     }
@@ -47,6 +57,10 @@
 
     public interface OnUpOrCancelMotionEventListener {
         void onUpOrCancelMotionEvent();
+    }
+
+    public interface OnFrustratedScrollListener {
+        void onFrustratedScroll();
     }
 
     public ObservableWebView(Context context) {
@@ -65,12 +79,24 @@
         super(context, attrs, defStyle, privateBrowsing);
     }
 
+
+    private long lastScrollTime;
+    private int totalAmountScrolled;
+    private static final int SCROLL_FRUSTRATION_THRESHOLD = 5000;
+
     @Override
     protected void onScrollChanged(int l, int t, int oldl, int oldt) {
         super.onScrollChanged(l, t, oldl, oldt);
         if (onScrollChangeListener != null) {
             onScrollChangeListener.onScrollChanged(oldt, t);
         }
+        totalAmountScrolled += (t - oldt);
+        if (Math.abs(totalAmountScrolled) > (int)(SCROLL_FRUSTRATION_THRESHOLD 
* getResources().getDisplayMetrics().density)
+            && onFrustratedScrollListener != null) {
+            onFrustratedScrollListener.onFrustratedScroll();
+            totalAmountScrolled = 0;
+        }
+        lastScrollTime = System.currentTimeMillis();
     }
 
     @Override
@@ -79,6 +105,9 @@
             switch (event.getActionMasked()) {
                 case MotionEvent.ACTION_DOWN:
                     onDownMotionEventListener.onDownMotionEvent();
+                    if (System.currentTimeMillis() - lastScrollTime > 
DateUtils.SECOND_IN_MILLIS / 2) {
+                        totalAmountScrolled = 0;
+                    }
                     break;
                 case MotionEvent.ACTION_UP:
                 case MotionEvent.ACTION_CANCEL:

-- 
To view, visit https://gerrit.wikimedia.org/r/158370
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I4cf0f4693c7c38e743b46a69aa84c2c61a0d1d00
Gerrit-PatchSet: 1
Gerrit-Project: apps/android/wikipedia
Gerrit-Branch: master
Gerrit-Owner: Dbrant <dbr...@wikimedia.org>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to