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