content: package com.alium.orin.util.snaphelper;
  
  
  import android.os.Build;
  import android.support.annotation.NonNull;
  import android.support.v7.widget.GridLayoutManager;
  import android.support.v7.widget.LinearLayoutManager;
  import android.support.v7.widget.OrientationHelper;
  import android.support.v7.widget.RecyclerView;
  import android.view.Gravity;
  import android.view.View;
  
  class GravityDelegate {
  
      private OrientationHelper verticalHelper;
      private OrientationHelper horizontalHelper;
      private int gravity;
      private boolean isRtlHorizontal;
      private boolean snapLastItem;
      GravitySnapHelper.SnapListener listener;
      boolean snapping;
      private RecyclerView.OnScrollListener mScrollListener = new RecyclerView.OnScrollListener() {
          @Override
          public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
              super.onScrollStateChanged(recyclerView, newState);
              if (newState == RecyclerView.SCROLL_STATE_SETTLING) {
                  snapping = false;
              }
              if (newState == RecyclerView.SCROLL_STATE_IDLE && snapping && listener != null) {
                  int position = getSnappedPosition(recyclerView);
                  if (position != RecyclerView.NO_POSITION) {
                      listener.onSnap(position);
                  }
                  snapping = false;
              }
          }
      };
  
      public GravityDelegate(int gravity) {
          this(gravity, false, null);
      }
  
      public GravityDelegate(int gravity, GravitySnapHelper.SnapListener listener) {
          this(gravity, false, listener);
      }
  
      public GravityDelegate(int gravity, boolean enableSnapLast,
                             GravitySnapHelper.SnapListener listener) {
          if (gravity != Gravity.START && gravity != Gravity.END
                  && gravity != Gravity.BOTTOM && gravity != Gravity.TOP) {
              throw new IllegalArgumentException("Invalid gravity value. Use START " +
                      "| END | BOTTOM | TOP constants");
          }
          this.snapLastItem = enableSnapLast;
          this.gravity = gravity;
          this.listener = listener;
      }
  
      public void attachToRecyclerView(@NonNull RecyclerView recyclerView) {
          if (recyclerView != null) {
              if ((gravity == Gravity.START || gravity == Gravity.END)
                      && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
                  isRtlHorizontal
                          = recyclerView.getContext().getResources().getConfiguration()
                          .getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
              }
              if (listener != null) {
                  recyclerView.addOnScrollListener(mScrollListener);
              }
          }
      }
  
      public int[] calculateDistanceToFinalSnap(@NonNull RecyclerView.LayoutManager layoutManager,
                                                @NonNull View targetView) {
          int[] out = new int[2];
  
          if (layoutManager.canScrollHorizontally()) {
              if (gravity == Gravity.START) {
                  out[0] = distanceToStart(targetView, getHorizontalHelper(layoutManager), false);
              } else { // END
                  out[0] = distanceToEnd(targetView, getHorizontalHelper(layoutManager), false);
              }
          } else {
              out[0] = 0;
          }
  
          if (layoutManager.canScrollVertically()) {
              if (gravity == Gravity.TOP) {
                  out[1] = distanceToStart(targetView, getVerticalHelper(layoutManager), false);
              } else { // BOTTOM
                  out[1] = distanceToEnd(targetView, getVerticalHelper(layoutManager), false);
              }
          } else {
              out[1] = 0;
          }
  
          return out;
      }
  
      public View findSnapView(RecyclerView.LayoutManager layoutManager) {
          View snapView = null;
          if (layoutManager instanceof LinearLayoutManager) {
              switch (gravity) {
                  case Gravity.START:
                      snapView = findStartView(layoutManager, getHorizontalHelper(layoutManager));
                      break;
                  case Gravity.END:
                      snapView = findEndView(layoutManager, getHorizontalHelper(layoutManager));
                      break;
                  case Gravity.TOP:
                      snapView = findStartView(layoutManager, getVerticalHelper(layoutManager));
                      break;
                  case Gravity.BOTTOM:
                      snapView = findEndView(layoutManager, getVerticalHelper(layoutManager));
                      break;
              }
          }
          snapping = snapView != null;
          return snapView;
      }
  
      public void enableLastItemSnap(boolean snap) {
          snapLastItem = snap;
      }
  
      private int distanceToStart(View targetView, OrientationHelper helper, boolean fromEnd) {
          if (isRtlHorizontal && !fromEnd) {
              return distanceToEnd(targetView, helper, true);
          }
  
          return helper.getDecoratedStart(targetView) - helper.getStartAfterPadding();
      }
  
      private int distanceToEnd(View targetView, OrientationHelper helper, boolean fromStart) {
          if (isRtlHorizontal && !fromStart) {
              return distanceToStart(targetView, helper, true);
          }
  
          return helper.getDecoratedEnd(targetView) - helper.getEndAfterPadding();
      }
  
      /**
       * Returns the first view that we should snap to.
       *
       * @param layoutManager the recyclerview's layout manager
       * @param helper        orientation helper to calculate view sizes
       * @return the first view in the LayoutManager to snap to
       */
      private View findStartView(RecyclerView.LayoutManager layoutManager,
                                 OrientationHelper helper) {
  
          if (layoutManager instanceof LinearLayoutManager) {
              int firstChild = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition();
              int offset = 1;
  
              if (layoutManager instanceof GridLayoutManager) {
                  offset += ((GridLayoutManager) layoutManager).getSpanCount() - 1;
              }
  
              if (firstChild == RecyclerView.NO_POSITION) {
                  return null;
              }
  
              View child = layoutManager.findViewByPosition(firstChild);
  
              float visibleWidth;
  
              // We should return the child if it's visible width
              // is greater than 0.5 of it's total width.
              // In a RTL configuration, we need to check the start point and in LTR the end point
              if (isRtlHorizontal) {
                  visibleWidth = (float) (helper.getTotalSpace() - helper.getDecoratedStart(child))
                          / helper.getDecoratedMeasurement(child);
              } else {
                  visibleWidth = (float) helper.getDecoratedEnd(child)
                          / helper.getDecoratedMeasurement(child);
              }
  
              // If we're at the end of the list, we shouldn't snap
              // to avoid having the last item not completely visible.
              boolean endOfList = ((LinearLayoutManager) layoutManager)
                      .findLastCompletelyVisibleItemPosition()
                      == layoutManager.getItemCount() - 1;
  
              if (visibleWidth > 0.5f && !endOfList) {
                  return child;
              } else if (snapLastItem && endOfList) {
                  return child;
              } else if (endOfList) {
                  return null;
              } else {
                  // If the child wasn't returned, we need to return
                  // the next view close to the start.
                  return layoutManager.findViewByPosition(firstChild + offset);
              }
          }
  
          return null;
      }
  
      private View findEndView(RecyclerView.LayoutManager layoutManager,
                               OrientationHelper helper) {
  
          if (layoutManager instanceof LinearLayoutManager) {
              int lastChild = ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition();
              int offset = 1;
  
              if (layoutManager instanceof GridLayoutManager) {
                  offset += ((GridLayoutManager) layoutManager).getSpanCount() - 1;
              }
  
              if (lastChild == RecyclerView.NO_POSITION) {
                  return null;
              }
  
              View child = layoutManager.findViewByPosition(lastChild);
  
              float visibleWidth;
  
              if (isRtlHorizontal) {
                  visibleWidth = (float) helper.getDecoratedEnd(child)
                          / helper.getDecoratedMeasurement(child);
              } else {
                  visibleWidth = (float) (helper.getTotalSpace() - helper.getDecoratedStart(child))
                          / helper.getDecoratedMeasurement(child);
              }
  
              // If we're at the start of the list, we shouldn't snap
              // to avoid having the first item not completely visible.
              boolean startOfList = ((LinearLayoutManager) layoutManager)
                      .findFirstCompletelyVisibleItemPosition() == 0;
  
              if (visibleWidth > 0.5f && !startOfList) {
                  return child;
              } else if (snapLastItem && startOfList) {
                  return child;
              } else if (startOfList) {
                  return null;
              } else {
                  // If the child wasn't returned, we need to return the previous view
                  return layoutManager.findViewByPosition(lastChild - offset);
              }
          }
          return null;
      }
  
      int getSnappedPosition(RecyclerView recyclerView) {
          RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
  
          if (layoutManager instanceof LinearLayoutManager) {
              if (gravity == Gravity.START || gravity == Gravity.TOP) {
                  return ((LinearLayoutManager) layoutManager).findFirstCompletelyVisibleItemPosition();
              } else if (gravity == Gravity.END || gravity == Gravity.BOTTOM) {
                  return ((LinearLayoutManager) layoutManager).findLastCompletelyVisibleItemPosition();
              }
          }
  
          return RecyclerView.NO_POSITION;
      }
  
      private OrientationHelper getVerticalHelper(RecyclerView.LayoutManager layoutManager) {
          if (verticalHelper == null) {
              verticalHelper = OrientationHelper.createVerticalHelper(layoutManager);
          }
          return verticalHelper;
      }
  
      private OrientationHelper getHorizontalHelper(RecyclerView.LayoutManager layoutManager) {
          if (horizontalHelper == null) {
              horizontalHelper = OrientationHelper.createHorizontalHelper(layoutManager);
          }
          return horizontalHelper;
      }
  }
  