Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2b35905e authored by Jon Miranda's avatar Jon Miranda
Browse files

Add overscroll to the top of All Apps.

* Overscroll at the top of all apps will occur when the user scrolls
  up, hits the top, and continues to scroll up.
* Fixed bug where All Apps jumps when the user enters overscroll
  from a scroll that doesn't start at the bottom.
* Fix bug where AllAppsRecyclerView stays translated even after
  the user has finished dragging.

Bug: 62628421
Change-Id: Ia1d230a7cc07a7cf8c1a7c5211a025034ae5f6df
parent 35005ef2
Loading
Loading
Loading
Loading
+7 −10
Original line number Diff line number Diff line
@@ -410,22 +410,19 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc

        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            if (mScrollState == RecyclerView.SCROLL_STATE_DRAGGING
                    || (dx == 0 && dy == 0)) {
            if (mScrollState == RecyclerView.SCROLL_STATE_DRAGGING || (dx == 0 && dy == 0)) {
                if (mSpringAnimationHandler.isRunning()){
                    mSpringAnimationHandler.skipToEnd();
                }
                return;
            }

            int first = mLayoutManager.findFirstVisibleItemPosition();
            int last = mLayoutManager.findLastVisibleItemPosition();

            // We only show the spring animation when at the top or bottom, so we wait until the
            // first or last row is visible to ensure that all animations run in sync.
            boolean scrollUp = dy < 0;
            if ((first == 0 && scrollUp) || (last == mAdapter.getItemCount() - 1 && dy > 0)) {
                mSpringAnimationHandler.animateToFinalPosition(0, scrollUp ? 1 : -1);
            // We only start the spring animation when we fling and hit the top/bottom, to ensure
            // that all of the animations start at the same time.
            if (dy < 0 && !mAppsRecyclerView.canScrollVertically(-1)) {
                mSpringAnimationHandler.animateToFinalPosition(0, 1);
            } else if (dy > 0 && !mAppsRecyclerView.canScrollVertically(1)) {
                mSpringAnimationHandler.animateToFinalPosition(0, -1);
            }
        }

+36 −9
Original line number Diff line number Diff line
@@ -96,8 +96,7 @@ public class AllAppsRecyclerView extends BaseRecyclerView {
        mOverScrollHelper = new OverScrollHelper();
        mPullDetector = new VerticalPullDetector(getContext());
        mPullDetector.setListener(mOverScrollHelper);
        mPullDetector.setDetectableScrollConditions(VerticalPullDetector.DIRECTION_UP
                | VerticalPullDetector.DIRECTION_DOWN, true);
        mPullDetector.setDetectableScrollConditions(VerticalPullDetector.DIRECTION_BOTH, true);
    }

    public void setSpringAnimationHandler(SpringAnimationHandler springAnimationHandler) {
@@ -487,28 +486,53 @@ public class AllAppsRecyclerView extends BaseRecyclerView {

        private boolean mIsInOverScroll;

        // We use this value to calculate the actual amount the user has overscrolled.
        private float mFirstDisplacement = 0;

        private boolean mAlreadyScrollingUp;
        private int mFirstScrollYOnScrollUp;

        @Override
        public void onDragStart(boolean start) {
        }

        @Override
        public boolean onDrag(float displacement, float velocity) {
            // We are in overscroll iff we are trying to drag further down when we're already at
            // the bottom of All Apps.
            mIsInOverScroll = !canScrollVertically(1) && displacement < 0
                    && !mScrollbar.isDraggingThumb();
            boolean isScrollingUp = displacement > 0;
            if (isScrollingUp) {
                if (!mAlreadyScrollingUp) {
                    mFirstScrollYOnScrollUp = getCurrentScrollY();
                    mAlreadyScrollingUp = true;
                }
            } else {
                mAlreadyScrollingUp = false;
            }

            // Only enter overscroll if the user is interacting with the RecyclerView directly
            // and if one of the following criteria are met:
            // - User scrolls down when they're already at the bottom.
            // - User starts scrolling up, hits the top, and continues scrolling up.
            mIsInOverScroll = !mScrollbar.isDraggingThumb() &&
                    ((!canScrollVertically(1) && displacement < 0) ||
                    (!canScrollVertically(-1) && isScrollingUp && mFirstScrollYOnScrollUp != 0));

            if (mIsInOverScroll) {
                displacement = getDampedOverScroll(displacement);
                setContentTranslationY(displacement);
                if (Float.compare(mFirstDisplacement, 0) == 0) {
                    // Because users can scroll before entering overscroll, we need to
                    // subtract the amount where the user was not in overscroll.
                    mFirstDisplacement = displacement;
                }
                float overscrollY = displacement - mFirstDisplacement;
                setContentTranslationY(getDampedOverScroll(overscrollY));
            }

            return mIsInOverScroll;
        }

        @Override
        public void onDragEnd(float velocity, boolean fling) {
            float y = getContentTranslationY();
            if (mIsInOverScroll && Float.compare(y, 0) != 0) {
            if (Float.compare(y, 0) != 0) {
                if (FeatureFlags.LAUNCHER3_PHYSICS) {
                    // We calculate our own velocity to give the springs the desired effect.
                    velocity = y / getDampedOverScroll(getHeight()) * MAX_RELEASE_VELOCITY;
@@ -523,6 +547,9 @@ public class AllAppsRecyclerView extends BaseRecyclerView {
                        .start();
            }
            mIsInOverScroll = false;
            mFirstDisplacement = 0;
            mFirstScrollYOnScrollUp = 0;
            mAlreadyScrollingUp = false;
        }

        public boolean isInOverScroll() {