From 33f86fd32ba59d8cea6b34b005d16f16c8f39287 Mon Sep 17 00:00:00 2001 From: seven332 Date: Fri, 12 Feb 2016 23:32:02 +0800 Subject: [PATCH] Add ScrollLayoutManager --- .../hippo/ehviewer/ui/GalleryActivity.java | 30 +- .../com/hippo/ehviewer/ui/MainActivity.java | 5 - .../hippo/ehviewer/ui/gl/GalleryPageView.java | 4 +- .../com/hippo/ehviewer/ui/gl/GalleryView.java | 10 +- .../ehviewer/ui/gl/GestureRecognizer.java | 5 + .../com/hippo/ehviewer/ui/gl/ImageView.java | 76 ++- .../ehviewer/ui/gl/PagerLayoutManager.java | 68 ++- .../ehviewer/ui/gl/ScrollLayoutManager.java | 515 +++++++++++++++++- .../java/com/hippo/gl/anim/Animation.java | 3 +- app/src/main/java/com/hippo/util/Dpad.java | 94 ---- .../com/hippo/util/PermissionRequester.java | 3 +- app/src/main/res/values-zh-rCN/strings.xml | 2 +- app/src/main/res/values/strings.xml | 2 +- build.gradle | 2 +- 14 files changed, 648 insertions(+), 171 deletions(-) delete mode 100644 app/src/main/java/com/hippo/util/Dpad.java diff --git a/app/src/main/java/com/hippo/ehviewer/ui/GalleryActivity.java b/app/src/main/java/com/hippo/ehviewer/ui/GalleryActivity.java index e28eb2f0d..153fb4261 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/GalleryActivity.java +++ b/app/src/main/java/com/hippo/ehviewer/ui/GalleryActivity.java @@ -20,7 +20,6 @@ import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v7.app.AppCompatActivity; import android.view.KeyEvent; -import android.view.MotionEvent; import com.hippo.ehviewer.R; import com.hippo.ehviewer.ui.gl.GalleryPageView; @@ -28,7 +27,6 @@ import com.hippo.ehviewer.ui.gl.GalleryView; import com.hippo.gl.glrenderer.ImageTexture; import com.hippo.gl.view.GLRootView; import com.hippo.image.Image; -import com.hippo.util.Dpad; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -57,29 +55,6 @@ public class GalleryActivity extends AppCompatActivity { mUploader = null; } - @Override - public boolean onGenericMotionEvent(MotionEvent event) { - switch (Dpad.getDirectionPressed(event)) { - case Dpad.LEFT: - // TODO do something - return true; - case Dpad.UP: - // TODO do something - return true; - case Dpad.RIGHT: - // TODO do something - return true; - case Dpad.DOWN: - // TODO do something - return true; - case Dpad.CENTER: - // TODO do something - return true; - } - - return super.onGenericMotionEvent(event); - } - @Override public boolean onKeyDown(int keyCode, KeyEvent event) { // Check volume @@ -154,7 +129,7 @@ public class GalleryActivity extends AppCompatActivity { } - private static final int MAX_SIZE = 10; + private static final int MAX_SIZE = 2; private class InvalidPageIterator implements GalleryView.PageIterator { @@ -214,7 +189,7 @@ public class GalleryActivity extends AppCompatActivity { @Override public void bind(GalleryPageView view) { - //view.showImage(); + view.showImage(); view.getImageView().setTexture(mImageTexture); } @@ -223,5 +198,4 @@ public class GalleryActivity extends AppCompatActivity { view.getImageView().setTexture(null); } } - } diff --git a/app/src/main/java/com/hippo/ehviewer/ui/MainActivity.java b/app/src/main/java/com/hippo/ehviewer/ui/MainActivity.java index 4065d6419..8a595957c 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/MainActivity.java +++ b/app/src/main/java/com/hippo/ehviewer/ui/MainActivity.java @@ -91,8 +91,6 @@ public final class MainActivity extends StageActivity @Override protected void onNewIntent(Intent intent) { - Log.d("TAG", "onNewIntent"); - super.onNewIntent(intent); if (!handleIntent(intent) && intent != null && Intent.ACTION_VIEW.equals(intent.getAction())) { Toast.makeText(this, R.string.error_cannot_parse_the_url, Toast.LENGTH_SHORT).show(); @@ -100,9 +98,6 @@ public final class MainActivity extends StageActivity } private void onInit() { - Log.d("TAG", "onInit"); - - Intent intent = getIntent(); if (!handleIntent(intent)) { if (intent != null && Intent.ACTION_VIEW.equals(intent.getAction())) { diff --git a/app/src/main/java/com/hippo/ehviewer/ui/gl/GalleryPageView.java b/app/src/main/java/com/hippo/ehviewer/ui/gl/GalleryPageView.java index f8fb38cb6..b08485c1e 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/gl/GalleryPageView.java +++ b/app/src/main/java/com/hippo/ehviewer/ui/gl/GalleryPageView.java @@ -79,8 +79,8 @@ public class GalleryPageView extends GLFrameLayout { } public void showImage() { - //mImage.setVisibility(VISIBLE); - //mInfo.setVisibility(INVISIBLE); + mImage.setVisibility(VISIBLE); + mInfo.setVisibility(INVISIBLE); } public ImageView getImageView() { diff --git a/app/src/main/java/com/hippo/ehviewer/ui/gl/GalleryView.java b/app/src/main/java/com/hippo/ehviewer/ui/gl/GalleryView.java index f487d6520..22d07036f 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/gl/GalleryView.java +++ b/app/src/main/java/com/hippo/ehviewer/ui/gl/GalleryView.java @@ -65,6 +65,7 @@ public class GalleryView extends GLView implements GestureRecognizer.Listener { private static final int BACKGROUND_COLOR = 0xff212121; private static final int INTERVAL_IN_DP = 24; private static final int PROGRESS_SIZE_IN_DP = 48; + private static final int PAGE_MIN_HEIGHT_IN_DP = 256; private static final int PAGE_STATE_UNKNOWN_SEEN = 0; private static final int PAGE_STATE_SEEN = 1; @@ -96,6 +97,7 @@ public class GalleryView extends GLView implements GestureRecognizer.Listener { private GestureRecognizer mGestureRecognizer; private LayoutManager mPagerLayoutManager; + private LayoutManager mScrollLayoutManager; private LayoutManager mLayoutManager; private Recycler mRecycler; @@ -103,6 +105,7 @@ public class GalleryView extends GLView implements GestureRecognizer.Listener { private GLProgressView mProgressCache; private int mProgressColor; + private int mPageMinHeight; private boolean mEnableRequestLayout = true; @@ -137,12 +140,14 @@ public class GalleryView extends GLView implements GestureRecognizer.Listener { mRecycler = new Recycler(); mProgressColor = ResourcesUtils.getAttrColor(context, R.attr.colorPrimary); + mPageMinHeight = LayoutUtils.dp2pix(context, PAGE_MIN_HEIGHT_IN_DP); int interval = LayoutUtils.dp2pix(context, INTERVAL_IN_DP); int progressSize = LayoutUtils.dp2pix(context, PROGRESS_SIZE_IN_DP); mPagerLayoutManager = new PagerLayoutManager(context, this, interval, progressSize); - mPagerLayoutManager.onAttach(iterator); - mLayoutManager = mPagerLayoutManager; + mScrollLayoutManager = new ScrollLayoutManager(context, this, interval, progressSize); + mScrollLayoutManager.onAttach(iterator); + mLayoutManager = mScrollLayoutManager; setBackgroundColor(BACKGROUND_COLOR); } @@ -355,6 +360,7 @@ public class GalleryView extends GLView implements GestureRecognizer.Listener { GalleryPageView page = mRecycler.obtain(); if (page == null) { page = new GalleryPageView(mContext); + page.setMinimumHeight(mPageMinHeight); } return page; } diff --git a/app/src/main/java/com/hippo/ehviewer/ui/gl/GestureRecognizer.java b/app/src/main/java/com/hippo/ehviewer/ui/gl/GestureRecognizer.java index b58ec462f..b958ced62 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/gl/GestureRecognizer.java +++ b/app/src/main/java/com/hippo/ehviewer/ui/gl/GestureRecognizer.java @@ -35,6 +35,11 @@ public class GestureRecognizer { boolean onDoubleTap(float x, float y); boolean onDoubleTapConfirmed(float x, float y); boolean onScroll(float dx, float dy, float totalX, float totalY, float x, float y); + + /** + * @param velocityX Finger from top to bottom is positive + * @param velocityY Finger from left to right is positive + */ boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY); boolean onScaleBegin(float focusX, float focusY); boolean onScale(float focusX, float focusY, float scale); diff --git a/app/src/main/java/com/hippo/ehviewer/ui/gl/ImageView.java b/app/src/main/java/com/hippo/ehviewer/ui/gl/ImageView.java index 6e39f13f0..1ddd90ed5 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/gl/ImageView.java +++ b/app/src/main/java/com/hippo/ehviewer/ui/gl/ImageView.java @@ -57,6 +57,8 @@ public class ImageView extends GLView { public static final int START_POSITION_CENTER = 4; private Texture mTexture; + private int mTextureWidth; + private int mTextureHeight; private RectF mDst = new RectF(); private RectF mSrcActual = new RectF(); @@ -75,13 +77,52 @@ public class ImageView extends GLView { @Override protected int getSuggestedMinimumWidth() { return Math.max(super.getSuggestedMinimumWidth(), - mTexture == null ? 0 : mTexture.getWidth()); + mTexture == null ? 0 : mTextureWidth); } @Override protected int getSuggestedMinimumHeight() { return Math.max(super.getSuggestedMinimumHeight(), - mTexture == null ? 0 : mTexture.getHeight()); + mTexture == null ? 0 : mTextureHeight); + } + + @Override + protected void onMeasure(int widthSpec, int heightSpec) { + if (mTexture == null) { + super.onMeasure(widthSpec, heightSpec); + } else { + float ratio = (float) mTextureWidth / mTextureHeight; + int widthSize = MeasureSpec.getSize(widthSpec); + int heightSize = MeasureSpec.getSize(heightSpec); + int widthMode = MeasureSpec.getMode(widthSpec); + int heightMode = MeasureSpec.getMode(heightSpec); + int measureWidth = -1; + int measureHeight = -1; + + if (widthMode == MeasureSpec.EXACTLY) { + measureWidth = widthSize; + if (heightMode == MeasureSpec.EXACTLY) { + measureHeight = heightSize; + } else { + measureHeight = (int) (widthSize / ratio); + if (heightMode == MeasureSpec.AT_MOST) { + measureHeight = Math.min(measureHeight, heightSize); + } + } + } else if (heightMode == MeasureSpec.EXACTLY) { + measureHeight = heightSize; + measureWidth = (int) (heightSize * ratio); + if (widthMode == MeasureSpec.AT_MOST) { + measureWidth = Math.min(measureWidth, widthSize); + } + } + + if (measureWidth == -1 || measureHeight == -1) { + super.onMeasure(widthSpec, heightSpec); + } else { + setMeasuredSize(measureWidth, measureHeight); + } + } } @Override @@ -102,8 +143,8 @@ public class ImageView extends GLView { scaleDefault[0] = 1.0f; - float scaleX = (float) getWidth() / mTexture.getWidth(); - float scaleY = (float) getHeight() / mTexture.getHeight(); + float scaleX = (float) getWidth() / mTextureWidth; + float scaleY = (float) getHeight() / mTextureHeight; if (scaleX < scaleY) { scaleDefault[1] = scaleX; } else { @@ -117,6 +158,22 @@ public class ImageView extends GLView { public void setTexture(Texture texture) { mTexture = texture; + + if (texture != null) { + mTextureWidth = texture.getWidth(); + mTextureHeight = texture.getHeight(); + // Avoid zero and negative + if (mTextureWidth <= 0) { + mTextureWidth = 1; + } + if (mTextureHeight <= 0) { + mTextureHeight = 1; + } + } else { + mTextureWidth = 1; + mTextureHeight = 1; + } + mScaleOffsetDirty = true; mPositionInRootDirty = true; } @@ -254,15 +311,8 @@ public class ImageView extends GLView { return; } - int textureWidth = mTexture.getWidth(); - int textureHeight = mTexture.getHeight(); - // Avoid zero and negative - if (textureWidth <= 0) { - textureWidth = 1; - } - if (textureHeight <= 0) { - textureHeight = 1; - } + int textureWidth = mTextureWidth; + int textureHeight = mTextureHeight; // Set scale float targetWidth; diff --git a/app/src/main/java/com/hippo/ehviewer/ui/gl/PagerLayoutManager.java b/app/src/main/java/com/hippo/ehviewer/ui/gl/PagerLayoutManager.java index 717072a89..5a772e21d 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/gl/PagerLayoutManager.java +++ b/app/src/main/java/com/hippo/ehviewer/ui/gl/PagerLayoutManager.java @@ -19,6 +19,7 @@ package com.hippo.ehviewer.ui.gl; import android.content.Context; import android.support.annotation.IntDef; import android.support.annotation.NonNull; +import android.util.Log; import android.view.MotionEvent; import android.view.animation.Interpolator; @@ -35,8 +36,6 @@ import java.lang.annotation.RetentionPolicy; public class PagerLayoutManager extends GalleryView.LayoutManager { - private static final String TAG = PagerLayoutManager.class.getSimpleName(); - @IntDef({MODE_LEFT_TO_RIGHT, MODE_RIGHT_TO_LEFT}) @Retention(RetentionPolicy.SOURCE) private @interface Mode {} @@ -62,17 +61,16 @@ public class PagerLayoutManager extends GalleryView.LayoutManager { @Mode private int mMode = MODE_RIGHT_TO_LEFT; private int mOffset; + private int mDeltaX; + private int mDeltaY; + private boolean mCanScrollBetweenPages = false; + private int mInterval; private int mProgressSpec; private int[] mScrollRemain = new int[2]; private float[] mScaleDefault = new float[3]; - private boolean mCanScrollBetweenPages = false; - - private int mDeltaX; - private int mDeltaY; - private PageFling mPageFling; private SmoothScroller mSmoothScroller; private SmoothScaler mSmoothScaler; @@ -88,12 +86,36 @@ public class PagerLayoutManager extends GalleryView.LayoutManager { mSmoothScaler = new SmoothScaler(); } + private void resetParameters() { + mOffset = 0; + mDeltaX = 0; + mDeltaY = 0; + mCanScrollBetweenPages = false; + } + + private void cancelAllAnimations() { + mSmoothScroller.cancel(); + mPageFling.cancel(); + mSmoothScaler.cancel(); + } + public void setMode(@Mode int mode) { - // TODO + if (mMode == mode) { + return; + } + + mMode = mode; if (mIterator != null) { - - } else { - + // It is attached, refill + // Cancel all animations + cancelAllAnimations(); + // Remove all view + removeProgress(); + removeAllPages(); + // Reset parameters + resetParameters(); + // Request fill + mGalleryView.requestFill(); } } @@ -101,6 +123,8 @@ public class PagerLayoutManager extends GalleryView.LayoutManager { public void onAttach(GalleryView.PageIterator iterator) { AssertUtils.assertEquals("The PagerLayoutManager is attached", mIterator, null); mIterator = iterator; + // Reset parameters + resetParameters(); } private void removeProgress() { @@ -136,6 +160,11 @@ public class PagerLayoutManager extends GalleryView.LayoutManager { public GalleryView.PageIterator onDetach() { AssertUtils.assertNotEquals("The PagerLayoutManager is not attached", mIterator, null); + // Cancel all animations + cancelAllAnimations(); + + // Remove all view + removeProgress(); removeAllPages(); // Clear iterator @@ -268,19 +297,17 @@ public class PagerLayoutManager extends GalleryView.LayoutManager { mDeltaX = 0; mDeltaY = 0; - mSmoothScroller.cancel(); - mPageFling.cancel(); - mSmoothScaler.cancel(); + cancelAllAnimations(); } @Override public void onUp() { + mGalleryView.getEdgeView().onRelease(); + if (mCurrent == null) { return; } - mGalleryView.getEdgeView().onRelease(); - // Scroll if (mOffset != 0) { int width = mGalleryView.getWidth(); @@ -447,6 +474,9 @@ public class PagerLayoutManager extends GalleryView.LayoutManager { mDeltaX += dx; mDeltaY += dy; + + Log.d("TAG", "mDeltaX = " + mDeltaX); + if (mDeltaX < 0) { edgeView.onPull(-mDeltaX, y, GLEdgeView.LEFT); if (!edgeView.isFinished(GLEdgeView.RIGHT)) { @@ -466,7 +496,7 @@ public class PagerLayoutManager extends GalleryView.LayoutManager { edgeView.onRelease(GLEdgeView.BOTTOM); } } else if (mDeltaY > 0) { - edgeView.onPull(mDeltaY, y, GLEdgeView.BOTTOM); + edgeView.onPull(mDeltaY, x, GLEdgeView.BOTTOM); if (!edgeView.isFinished(GLEdgeView.TOP)) { edgeView.onRelease(GLEdgeView.TOP); } @@ -646,6 +676,10 @@ public class PagerLayoutManager extends GalleryView.LayoutManager { mDy = maxY; } + if (mDx == 0 && mDy == 0) { + return; + } + setDuration(Math.max(durationX, durationY)); start(); mGalleryView.invalidate(); diff --git a/app/src/main/java/com/hippo/ehviewer/ui/gl/ScrollLayoutManager.java b/app/src/main/java/com/hippo/ehviewer/ui/gl/ScrollLayoutManager.java index 8b9772da9..3b682ce47 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/gl/ScrollLayoutManager.java +++ b/app/src/main/java/com/hippo/ehviewer/ui/gl/ScrollLayoutManager.java @@ -16,38 +16,256 @@ package com.hippo.ehviewer.ui.gl; +import android.content.Context; import android.support.annotation.NonNull; +import android.util.Log; import android.view.MotionEvent; +import com.hippo.gl.view.GLView; +import com.hippo.gl.widget.GLEdgeView; +import com.hippo.gl.widget.GLProgressView; +import com.hippo.yorozuya.AssertUtils; + +import java.util.Iterator; +import java.util.LinkedList; + public class ScrollLayoutManager extends GalleryView.LayoutManager { - public ScrollLayoutManager(@NonNull GalleryView galleryView) { + private static final String TAG = ScrollLayoutManager.class.getSimpleName(); + + private static final float RESERVATIONS = 0.5f; + + private GalleryView.PageIterator mIterator; + + private GLProgressView mProgress; + private LinkedList mPages = new LinkedList<>(); + + private int mOffset; + private int mDeltaX; + private int mDeltaY; + + private int mInterval; + private int mProgressSpec; + + private PageFling mPageFling; + + public ScrollLayoutManager(Context context, @NonNull GalleryView galleryView, + int interval, int progressSize) { super(galleryView); + + mInterval = interval; + mProgressSpec = GLView.MeasureSpec.makeMeasureSpec(progressSize, GLView.MeasureSpec.EXACTLY); + mPageFling = new PageFling(context); + } + + private void resetParameters() { + mOffset = 0; + mDeltaX = 0; + mDeltaY = 0; + } + + private void cancelAllAnimations() { + mPageFling.cancel(); } @Override public void onAttach(GalleryView.PageIterator iterator) { + AssertUtils.assertEquals("The PagerLayoutManager is attached", mIterator, null); + mIterator = iterator; + // Reset parameters + resetParameters(); + } + private void removeProgress() { + if (mProgress != null) { + mGalleryView.removeComponent(mProgress); + mProgress = null; + } + } + + private void removePage(@NonNull GalleryPageView page) { + mGalleryView.removeComponent(page); + mIterator.unbind(page); + mGalleryView.releasePage(page); + } + + private void removeAllPages() { + for (GalleryPageView page : mPages) { + removePage(page); + } + mPages.clear(); } @Override public GalleryView.PageIterator onDetach() { - return null; + AssertUtils.assertNotEquals("The PagerLayoutManager is not attached", mIterator, null); + + // Cancel all animations + cancelAllAnimations(); + + // Remove all view + removeProgress(); + removeAllPages(); + + // Clear iterator + GalleryView.PageIterator iterator = mIterator; + mIterator = null; + + return iterator; } @Override - public void onFill() { + public synchronized void onFill() { + GalleryView.PageIterator iterator = mIterator; + GalleryView galleryView = mGalleryView; + AssertUtils.assertNotEquals("The PagerLayoutManager is not attached", iterator, null); + int width = galleryView.getWidth(); + int height = galleryView.getHeight(); + + if (!iterator.isValid()) { + // Remove all pages + removeAllPages(); + + // Ensure progress + if (mProgress == null) { + mProgress = galleryView.obtainProgress(); + galleryView.addComponent(mProgress); + } + + // Measure and layout progress + mProgress.measure(mProgressSpec, mProgressSpec); + int progressWidth = mProgress.getMeasuredWidth(); + int progressHeight = mProgress.getMeasuredHeight(); + int progressLeft = width / 2 - progressWidth / 2; + int progressTop = height / 2 - progressHeight / 2; + mProgress.layout(progressLeft, progressTop, progressLeft + progressWidth, progressTop + progressHeight); + } else { + // Remove progress + removeProgress(); + + int minY = (int) (-height * RESERVATIONS); + + // Remove useless top view + Iterator pages = mPages.iterator(); + while (pages.hasNext()) { + GalleryPageView page = pages.next(); + int nextTop = page.bounds().bottom + mInterval; + if (nextTop < minY) { + removePage(page); + pages.remove(); + // Update offset + mOffset = nextTop; + if (iterator.hasNext()) { + iterator.next(); + } else { + Log.e(TAG, "iterator should has next"); + } + } else { + break; + } + } + + // Fill missing top + int oldOffset = mOffset; + int y = oldOffset; + int widthSpec = GLView.MeasureSpec.makeMeasureSpec(width, GLView.MeasureSpec.EXACTLY); + int heightSpec = GLView.MeasureSpec.makeMeasureSpec(height, GLView.MeasureSpec.UNSPECIFIED); + int pageSize = 0; + while (y >= minY && iterator.hasPrevious()) { + iterator.previous(); + + GalleryPageView page = galleryView.obtainPage(); + iterator.bind(page); + galleryView.addComponent(page); + mPages.add(0, page); + + // Add interval + y -= mInterval; + + // Measure and layout + page.measure(widthSpec, heightSpec); + page.layout(0, y - page.getMeasuredHeight(), width, y); + + // Update y + y -= page.getMeasuredHeight(); + + // size increase + pageSize++; + } + mOffset = y; + + // Fill from oldOffset + iterator.mark(); + // Go to oldOffset + int maxY = (int) (height * (1 + RESERVATIONS)); + y = oldOffset; + pages = mPages.iterator(); + for (int i = 0; i < pageSize; i++) { + if (iterator.hasNext()) { + iterator.next(); + } else { + Log.e(TAG, "iterator should has next"); + } + pages.next(); + } + // Do fill + while (true) { + GalleryPageView page; + if (pages == null || !pages.hasNext()) { + pages = null; + // New page + page = galleryView.obtainPage(); + iterator.bind(page); + galleryView.addComponent(page); + mPages.add(page); + } else { + page = pages.next(); + } + + // Measure and layout + page.measure(widthSpec, heightSpec); + page.layout(0, y, width, y + page.getMeasuredHeight()); + + // size increase + pageSize++; + + // Update y and check out of range + y += page.getMeasuredHeight(); + if (y > maxY) { + break; + } + + y += mInterval; + + // Check has next + if (!iterator.hasNext()) { + break; + } + + iterator.next(); + } + iterator.reset(); + + // Remove useless page + while (mPages.size() > pageSize) { + GalleryPageView page = mPages.removeLast(); + removePage(page); + } + } } @Override public void onDown() { + mDeltaX = 0; + mDeltaY = 0; + cancelAllAnimations(); } @Override public void onUp() { - + mGalleryView.getEdgeView().onRelease(); } @Override @@ -55,14 +273,196 @@ public class ScrollLayoutManager extends GalleryView.LayoutManager { } + public void overScrollEdge(int dx, int dy, float x, float y) { + GLEdgeView edgeView = mGalleryView.getEdgeView(); + + mDeltaX += dx; + mDeltaY += dy; + + /* + if (mDeltaX < 0) { + edgeView.onPull(-mDeltaX, y, GLEdgeView.LEFT); + if (!edgeView.isFinished(GLEdgeView.RIGHT)) { + edgeView.onRelease(GLEdgeView.RIGHT); + } + } else if (mDeltaX > 0) { + edgeView.onPull(mDeltaX, y, GLEdgeView.RIGHT); + if (!edgeView.isFinished(GLEdgeView.LEFT)) { + edgeView.onRelease(GLEdgeView.LEFT); + } + } + */ + + if (mDeltaY < 0) { + edgeView.onPull(-mDeltaY, x, GLEdgeView.TOP); + if (!edgeView.isFinished(GLEdgeView.BOTTOM)) { + edgeView.onRelease(GLEdgeView.BOTTOM); + } + } else if (mDeltaY > 0) { + edgeView.onPull(mDeltaY, x, GLEdgeView.BOTTOM); + if (!edgeView.isFinished(GLEdgeView.TOP)) { + edgeView.onRelease(GLEdgeView.TOP); + } + } + } + + // True for get top or bottom + private boolean scrollInternal(float dx, float dy, boolean fling, float x, float y) { + if (mPages.size() == 0) { + return false; + } + + int height = mGalleryView.getHeight(); + boolean requestFill = false; + int remainY = (int) dy; + boolean result = false; + + while (remainY != 0) { + if (remainY < 0) { // Try to show top + int limit; + if (mIterator.hasPrevious()) { + limit = (int) (-height * RESERVATIONS); + } else { + limit = 0; + } + + if (mOffset - remainY < limit) { + mOffset -= remainY; + remainY = 0; + requestFill = true; + mDeltaX = 0; + mDeltaY = 0; + } else { + if (mIterator.hasPrevious()) { + mOffset = limit; + remainY = remainY + limit - mOffset; + onFill(); + requestFill = false; + mDeltaX = 0; + mDeltaY = 0; + } else { + if (mOffset != limit) { + mOffset = limit; + requestFill = true; + } + if (!fling) { + overScrollEdge(0, remainY + limit - mOffset, x, y); + } + remainY = 0; + result = true; + } + } + } else { // Try to show bottom + boolean hasNext = hasNextPage(); + int limit; + if (hasNext) { + limit = (int) (height * (1 + RESERVATIONS)); + } else { + limit = height; + } + int pageBottom = mPages.getLast().bounds().bottom; + // Fix limit for page not fill screen + limit = Math.min(pageBottom, limit); + + if (pageBottom - remainY > limit) { + mOffset -= remainY; + remainY = 0; + requestFill = true; + mDeltaX = 0; + mDeltaY = 0; + } else { + if (hasNext) { + mOffset -= pageBottom - limit; + remainY = remainY + limit - pageBottom; + onFill(); + requestFill = false; + mDeltaX = 0; + mDeltaY = 0; + } else { + if (mOffset != limit) { + mOffset -= pageBottom - limit; + requestFill = true; + } + if (!fling) { + overScrollEdge(0, remainY + limit - pageBottom, x, y); + } + remainY = 0; + result = true; + } + } + } + } + + if (requestFill) { + mGalleryView.requestFill(); + } + + return result; + } + @Override public void onScroll(float dx, float dy, float totalX, float totalY, float x, float y) { + scrollInternal(dx, dy, false, x, y); + } + private boolean hasNextPage() { + boolean hasNext = true; + GalleryView.PageIterator iterator = mIterator; + iterator.mark(); + + for (int i = 0, size = mPages.size(); i < size; i++) { + if (iterator.hasNext()) { + iterator.next(); + } else { + hasNext = false; + break; + } + } + + iterator.reset(); + return hasNext; } @Override public void onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { + if (mPages.size() <= 0) { + return; + } + // FIXME Bug here + int maxY; + if (mIterator.hasPrevious()) { + maxY = Integer.MAX_VALUE; + } else { + maxY = -mOffset; + } + int bottom = mOffset; + boolean hasNext = true; + GalleryView.PageIterator iterator = mIterator; + iterator.mark(); + for (int i = 0, size = mPages.size(); i < size; i++) { + if (i != 0) { + bottom += mInterval; + } + bottom += mPages.get(i).getHeight(); + if (iterator.hasNext()) { + iterator.next(); + } else { + hasNext = false; + break; + } + } + iterator.reset(); + + int minY; + if (hasNext) { + minY = Integer.MIN_VALUE; + } else { + minY = mGalleryView.getHeight() - bottom; + } + + mPageFling.startFling((int) velocityX, 0, 0, + (int) velocityY, minY, maxY); } @Override @@ -77,6 +477,111 @@ public class ScrollLayoutManager extends GalleryView.LayoutManager { @Override public boolean onUpdateAnimation(long time) { - return false; + boolean invalidate = mPageFling.calculate(time); + return invalidate; + } + + class PageFling extends Fling { + + private int mVelocityX; + private int mVelocityY; + private int mDx; + private int mDy; + private int mLastX; + private int mLastY; + + public PageFling(Context context) { + super(context); + } + + public void startFling(int velocityX, int minX, int maxX, + int velocityY, int minY, int maxY) { + mVelocityX = velocityX; + mVelocityY = velocityY; + mDx = (int) (getSplineFlingDistance(velocityX) * Math.signum(velocityX)); + mDy = (int) (getSplineFlingDistance(velocityY) * Math.signum(velocityY)); + mLastX = 0; + mLastY = 0; + int durationX = getSplineFlingDuration(velocityX); + int durationY = getSplineFlingDuration(velocityY); + + if (mDx < minX) { + durationX = adjustDuration(0, mDx, minX, durationX); + mDx = minX; + } + if (mDx > maxX) { + durationX = adjustDuration(0, mDx, maxX, durationX); + mDx = maxX; + } + if (mDy < minY) { + durationY = adjustDuration(0, mDy, minY, durationY); + mDy = minY; + } + if (mDy > maxY) { + durationY = adjustDuration(0, mDy, maxY, durationY); + mDy = maxY; + } + + if (mDx == 0 && mDy == 0) { + return; + } + + setDuration(Math.max(durationX, durationY)); + start(); + mGalleryView.invalidate(); + } + + @Override + protected void onCalculate(float progress) { + int x = (int) (mDx * progress); + int y = (int) (mDy * progress); + int offsetX = x - mLastX; + int offsetY = y - mLastY; + if (scrollInternal(-offsetX, -offsetY, true, 0, 0)) { + cancel(); + onFinish(); + } + mLastX = x; + mLastY = y; + } + + @Override + protected void onFinish() { + boolean topEdge = !mIterator.hasPrevious() && mOffset >= 0; + + int bottom = mOffset; + boolean hasNext = true; + GalleryView.PageIterator iterator = mIterator; + iterator.mark(); + for (int i = 0, size = mPages.size(); i < size; i++) { + if (i != 0) { + bottom += mInterval; + } + bottom += mPages.get(i).getHeight(); + if (iterator.hasNext()) { + iterator.next(); + } else { + hasNext = false; + break; + } + } + iterator.reset(); + boolean bottomEdge = !hasNext && bottom <= mGalleryView.getHeight(); + + if (topEdge && bottomEdge) { + return; + } + + // FIXME Bug here + Log.d(TAG, "bottom = " + bottom); + Log.d(TAG, "mGalleryView.getHeight() = " + mGalleryView.getHeight()); + + GLEdgeView edgeView = mGalleryView.getEdgeView(); + if (topEdge && edgeView.isFinished(GLEdgeView.TOP)) { + edgeView.onAbsorb(mVelocityY, GLEdgeView.TOP); + } else if (bottomEdge && edgeView.isFinished(GLEdgeView.BOTTOM)) { + edgeView.onAbsorb(-mVelocityY, GLEdgeView.BOTTOM); + } + } } } diff --git a/app/src/main/java/com/hippo/gl/anim/Animation.java b/app/src/main/java/com/hippo/gl/anim/Animation.java index db7149222..2910e94da 100644 --- a/app/src/main/java/com/hippo/gl/anim/Animation.java +++ b/app/src/main/java/com/hippo/gl/anim/Animation.java @@ -150,7 +150,8 @@ abstract public class Animation { Interpolator i = mInterpolator; onCalculate(i != null ? i.getInterpolation(x) : x); - if (elapse >= mDuration) { + // It is ok to call cancel() in onCalculate() + if (mStartTime != NO_ANIMATION && elapse >= mDuration) { mRunnedCount++; if (mRunnedCount >= mRepeatCount && mRepeatCount != INFINITE) { onFinish(); diff --git a/app/src/main/java/com/hippo/util/Dpad.java b/app/src/main/java/com/hippo/util/Dpad.java deleted file mode 100644 index ce01ba894..000000000 --- a/app/src/main/java/com/hippo/util/Dpad.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2016 Hippo Seven - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.hippo.util; - -import android.view.InputDevice; -import android.view.InputEvent; -import android.view.KeyEvent; -import android.view.MotionEvent; - -// From http://developer.android.com/training/game-controllers/controller-input.html#dpad -public class Dpad { - - public static final int INVALID = -1; - public static final int UP = 0; - public static final int LEFT = 1; - public static final int RIGHT = 2; - public static final int DOWN = 3; - public static final int CENTER = 4; - - public static int getDirectionPressed(InputEvent event) { - if (!isDpadDevice(event)) { - return INVALID; - } - - int directionPressed = INVALID; - - // If the input event is a MotionEvent, check its hat axis values. - if (event instanceof MotionEvent) { - - // Use the hat axis value to find the D-pad direction - MotionEvent motionEvent = (MotionEvent) event; - float xaxis = motionEvent.getAxisValue(MotionEvent.AXIS_HAT_X); - float yaxis = motionEvent.getAxisValue(MotionEvent.AXIS_HAT_Y); - - // Check if the AXIS_HAT_X value is -1 or 1, and set the D-pad - // LEFT and RIGHT direction accordingly. - if (Float.compare(xaxis, -1.0f) == 0) { - directionPressed = Dpad.LEFT; - } else if (Float.compare(xaxis, 1.0f) == 0) { - directionPressed = Dpad.RIGHT; - } - // Check if the AXIS_HAT_Y value is -1 or 1, and set the D-pad - // UP and DOWN direction accordingly. - else if (Float.compare(yaxis, -1.0f) == 0) { - directionPressed = Dpad.UP; - } else if (Float.compare(yaxis, 1.0f) == 0) { - directionPressed = Dpad.DOWN; - } - } - - // If the input event is a KeyEvent, check its key code. - else if (event instanceof KeyEvent) { - - // Use the key code to find the D-pad direction. - KeyEvent keyEvent = (KeyEvent) event; - if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_LEFT) { - directionPressed = Dpad.LEFT; - } else if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_RIGHT) { - directionPressed = Dpad.RIGHT; - } else if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_UP) { - directionPressed = Dpad.UP; - } else if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_DOWN) { - directionPressed = Dpad.DOWN; - } else if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_CENTER) { - directionPressed = Dpad.CENTER; - } - } - return directionPressed; - } - - public static boolean isDpadDevice(InputEvent event) { - // Check that input comes from a device with directional pads. - if ((event.getSource() & InputDevice.SOURCE_DPAD) - != InputDevice.SOURCE_DPAD) { - return true; - } else { - return false; - } - } -} diff --git a/app/src/main/java/com/hippo/util/PermissionRequester.java b/app/src/main/java/com/hippo/util/PermissionRequester.java index b0034b818..2863e0c48 100644 --- a/app/src/main/java/com/hippo/util/PermissionRequester.java +++ b/app/src/main/java/com/hippo/util/PermissionRequester.java @@ -48,7 +48,8 @@ public class PermissionRequester { new String[]{permission}, requestCode); } - }).setNegativeButton(android.R.string.cancel, null); + }).setNegativeButton(android.R.string.cancel, null) + .show(); } else { ActivityCompat.requestPermissions(activity, new String[]{permission}, diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 3b78c7742..af622fb00 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -50,7 +50,7 @@ 登陆失败。这可能是网站更新导致的。你愿意跳过登陆么? 再按一次退出 点击重试 - 写!写!写! + EhViewer 将申请设备存储空间访问权限以便下载画廊。你愿意授权吗? 好痛 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f404293e3..07d77f761 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -89,7 +89,7 @@ Sign in failed. But perhaps it is a mistake due to website update. Do you want to skip signing in? Press twice to exit Click to retry - Write! Write! Write! + EhViewer will request WRITE_EXTERNAL_STORAGE permission for downloading gallery. Do you want to grant the permission? It hurts diff --git a/build.gradle b/build.gradle index f357b55d9..ea9ecb6f2 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:2.0.0-beta2' + classpath 'com.android.tools.build:gradle:2.0.0-beta4' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files