/******************************************************************************* * This file is part of RedReader. * * RedReader is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * RedReader is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with RedReader. If not, see <http://www.gnu.org/licenses/>. ******************************************************************************/ package org.quantumbadger.redreader.views; import android.content.Context; import android.content.res.TypedArray; import android.graphics.drawable.Drawable; import android.support.annotation.NonNull; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; import android.widget.TextView; import org.quantumbadger.redreader.R; import org.quantumbadger.redreader.common.General; public abstract class FlingableItemView extends SwipableItemView { private final FrameLayout mFlingHintOuter; private final TextView mFlingHintLeft; private final TextView mFlingHintRight; private boolean mSwipeReady = false; private boolean mRightFlingHintShown = false; private boolean mLeftFlingHintShown = false; private FlingHintAnimation mFlingHintAnimation; private float mFlingHintYPos = 0; private final int mOffsetBeginAllowed; private final int mOffsetActionPerformed; private final Drawable rrIconFfLeft, rrIconFfRight, rrIconTick; public FlingableItemView(@NonNull final Context context) { super(context); mOffsetBeginAllowed = General.dpToPixels(context, 50); mOffsetActionPerformed = General.dpToPixels(context, 150); final int rrListBackgroundCol; { final TypedArray attr = context.obtainStyledAttributes(new int[]{ R.attr.rrIconFfLeft, R.attr.rrIconFfRight, R.attr.rrIconTick, R.attr.rrListBackgroundCol }); rrIconFfLeft = attr.getDrawable(0); rrIconFfRight = attr.getDrawable(1); rrIconTick = attr.getDrawable(2); rrListBackgroundCol = attr.getColor(3, General.COLOR_INVALID); attr.recycle(); } mFlingHintOuter = (FrameLayout)LayoutInflater.from(context).inflate(R.layout.fling_hint, null); addView(mFlingHintOuter); final ViewGroup.LayoutParams flingHintLayoutParams = mFlingHintOuter.getLayoutParams(); flingHintLayoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT; flingHintLayoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT; mFlingHintLeft = (TextView)mFlingHintOuter.findViewById(R.id.reddit_post_fling_text_left); mFlingHintRight = (TextView)mFlingHintOuter.findViewById(R.id.reddit_post_fling_text_right); mFlingHintLeft.setCompoundDrawablesWithIntrinsicBounds(null, rrIconFfLeft, null, null); mFlingHintRight.setCompoundDrawablesWithIntrinsicBounds(null, rrIconFfRight, null, null); setBackgroundColor(rrListBackgroundCol); } public void setFlingingEnabled(final boolean flingingEnabled) { mFlingHintOuter.setVisibility(flingingEnabled ? VISIBLE : GONE); setSwipingEnabled(flingingEnabled); } protected abstract void onSetItemFlingPosition(final float position); @NonNull protected abstract String getFlingLeftText(); @NonNull protected abstract String getFlingRightText(); protected abstract boolean allowFlingingLeft(); protected abstract boolean allowFlingingRight(); protected abstract void onFlungLeft(); protected abstract void onFlungRight(); @Override protected final boolean allowSwipingLeft() { return allowFlingingLeft(); } @Override protected final boolean allowSwipingRight() { return allowFlingingRight(); } private void updateFlingHintPosition() { mFlingHintOuter.setTranslationY(mFlingHintYPos); } private class FlingHintAnimation extends RRDHMAnimation { private FlingHintAnimation(final LiveDHM.Params params) { super(params); } @Override protected void onUpdatedPosition(final float position) { mFlingHintYPos = position; updateFlingHintPosition(); } @Override protected void onEndPosition(final float endPosition) { mFlingHintYPos = endPosition; updateFlingHintPosition(); mFlingHintAnimation = null; } } @Override protected void onSwipeFingerDown(final int x, final int y, final float xOffsetPixels, final boolean wasOldSwipeInterrupted) { if(mOffsetBeginAllowed > Math.abs(xOffsetPixels)) { mFlingHintLeft.setText(getFlingLeftText()); mFlingHintRight.setText(getFlingRightText()); mFlingHintLeft.setCompoundDrawablesWithIntrinsicBounds(null, rrIconFfLeft, null, null); mFlingHintRight.setCompoundDrawablesWithIntrinsicBounds(null, rrIconFfRight, null, null); mSwipeReady = true; } final int height = mFlingHintOuter.getMeasuredHeight(); final int parentHeight = getMeasuredHeight(); final FlingHintAnimation oldAnimation = mFlingHintAnimation; if(mFlingHintAnimation != null) { mFlingHintAnimation.stop(); mFlingHintAnimation = null; } if(parentHeight > height * 3) { int yPos = Math.min(Math.max(y - height / 2, 0), parentHeight - height); if(wasOldSwipeInterrupted) { if(Math.abs(yPos - mFlingHintYPos) < height) { yPos = (int)mFlingHintYPos; } final LiveDHM.Params params = new LiveDHM.Params(); params.startPosition = mFlingHintYPos; params.endPosition = yPos; if(oldAnimation != null) { params.startVelocity = oldAnimation.getCurrentVelocity(); } mFlingHintAnimation = new FlingHintAnimation(params); mFlingHintAnimation.start(); } else { mFlingHintYPos = yPos; updateFlingHintPosition(); } } else { mFlingHintYPos = (parentHeight - height) / 2; updateFlingHintPosition(); } } @Override public void onSwipeDeltaChanged(final float xOffsetPixels) { onSetItemFlingPosition(xOffsetPixels); final float absOffset = Math.abs(xOffsetPixels); if(mSwipeReady && absOffset > mOffsetActionPerformed) { if(xOffsetPixels > 0) { onFlungRight(); mFlingHintRight.setCompoundDrawablesWithIntrinsicBounds(null, rrIconTick, null, null); } else { onFlungLeft(); mFlingHintLeft.setCompoundDrawablesWithIntrinsicBounds(null, rrIconTick, null, null); } mSwipeReady = false; } else if(absOffset > 5) { if(xOffsetPixels > 0) { // Right swipe if(!mRightFlingHintShown) { mRightFlingHintShown = true; mFlingHintRight.setVisibility(View.VISIBLE); } if(mLeftFlingHintShown) { mLeftFlingHintShown = false; mFlingHintLeft.setVisibility(View.INVISIBLE); } } else { // Left swipe if(!mLeftFlingHintShown) { mLeftFlingHintShown = true; mFlingHintLeft.setVisibility(View.VISIBLE); } if(mRightFlingHintShown) { mRightFlingHintShown = false; mFlingHintRight.setVisibility(View.INVISIBLE); } } } else { if(mRightFlingHintShown) { mRightFlingHintShown = false; mFlingHintRight.setVisibility(View.INVISIBLE); } if(mLeftFlingHintShown) { mLeftFlingHintShown = false; mFlingHintLeft.setVisibility(View.INVISIBLE); } } } }