package ar.rulosoft.mimanganu.componentes.readers.continuos; import android.animation.Animator; import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Canvas; import android.view.MotionEvent; public class VerticalReader extends ReaderContinuous { private float totalHeight = 0; public VerticalReader(Context context) { super(context); } @Override public void calculateParticularScale() { for (Page dimension : pages) { dimension.unification_scale = (screenWidth / dimension.original_width); dimension.scaled_width = screenWidth; dimension.scaled_height = dimension.original_height * dimension.unification_scale; } } @Override public void calculateParticularScale(Page dimension) { dimension.unification_scale = (screenWidth / dimension.original_width); dimension.scaled_width = screenWidth; dimension.scaled_height = dimension.original_height * dimension.unification_scale; } @Override public void calculateVisibilities() { float acc = 0; for (int i = 0; i < pages.size(); i++) { Page d = pages.get(i); d.init_visibility = (float) Math.floor(acc); acc += d.scaled_height; acc = (float) Math.floor(acc); d.end_visibility = acc; } totalHeight = acc; pagesLoaded = true; } public void reloadImage(int idx) { int pageIdx; if(idx == 0) pageIdx = idx; else pageIdx = idx - 1; if (pages != null && pageIdx < pages.size() && pageIdx >= 0) { int cPage = currentPage; if (pages.size() < cPage || cPage < 0) cPage = 0; if(cPage >= pages.size()) cPage = pages.size()-1; float value = 0; if (pages.get(cPage) != null) value = pages.get(cPage).init_visibility; Page page = initValues(pages.get(pageIdx).path); pages.set(pageIdx, page); calculateParticularScale(pages.get(pageIdx)); calculateVisibilities(); if (pages.get(cPage) != null) value = value - pages.get(cPage).init_visibility; relativeScroll(0, -value); generateDrawPool(); } } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, final float velocityX, final float velocityY) { if (readerListener != null) if (e1.getY() - e2.getY() > 100 && (yScroll == (((totalHeight * mScaleFactor) - screenHeight)) / mScaleFactor)) { readerListener.onEndOver(); } else if (yScroll < 0.1) { readerListener.onStartOver(); } return super.onFling(e1, e2, velocityX, velocityY); } @Override public boolean onSingleTapConfirmed(MotionEvent e) { if (readerListener != null) if (e.getX() < getWidth() / 4) { if (currentPage == 0) readerListener.onStartOver(); else goToPage(currentPage); } else if (e.getX() > getWidth() / 4 * 3) { if (isLastPageVisible()) readerListener.onEndOver(); else goToPage(currentPage + 2); } else { readerListener.onMenuRequired(); } return false; } @Override public boolean onDoubleTapEvent(MotionEvent e) { return false; } @Override public void relativeScroll(double distanceX, double distanceY) { if (yScroll + distanceY > (((totalHeight * mScaleFactor) - screenHeight)) / mScaleFactor) { yScroll = ((totalHeight * mScaleFactor) - screenHeight) / mScaleFactor; stopAnimationOnVerticalOver = true; } else if (yScroll + distanceY > 0) { yScroll += distanceY; } else { yScroll = 0; stopAnimationOnVerticalOver = true; } if (mScaleFactor >= 1) { if (xScroll + distanceX > (((screenWidth * mScaleFactor) - screenWidth)) / mScaleFactor) { xScroll = ((screenWidth * mScaleFactor) - screenWidth) / mScaleFactor; stopAnimationOnHorizontalOver = true; } else if (xScroll + distanceX < 0) { xScroll = 0; } else { xScroll += distanceX; stopAnimationOnHorizontalOver = true; } } else { xScroll = (screenWidthSS - screenWidth) / 2; stopAnimationOnHorizontalOver = true; } } @Override public void absoluteScroll(float x, float y) { if (y > (((totalHeight * mScaleFactor) - screenHeight)) / mScaleFactor) { yScroll = ((totalHeight * mScaleFactor) - screenHeight) / mScaleFactor; stopAnimationOnVerticalOver = true; } else if (y > 0) { yScroll = y; } else { yScroll = 0; stopAnimationOnVerticalOver = true; } if (mScaleFactor >= 1) { if (x > (((screenWidth * mScaleFactor) - screenWidth)) / mScaleFactor) { xScroll = ((screenWidth * mScaleFactor) - screenWidth) / mScaleFactor; stopAnimationOnHorizontalOver = true; } else if (x < 0) { xScroll = 0; } else { xScroll = x; stopAnimationOnHorizontalOver = true; } } else { xScroll = (screenWidthSS - screenWidth) / 2; stopAnimationOnHorizontalOver = true; } } @Override public void postLayout() { absoluteScroll(xScroll, getPagePosition(currentPage)); generateDrawPool(); if (readerListener != null) { readerListener.onPageChanged(transformPage(currentPage)); } } @Override public void seekPage(int index) { int page = index - 1; if (page < 0) page = 0; else if (index >= pages.size()) page = pages.size() - 1; if (viewReady && pagesLoaded) { absoluteScroll(xScroll, getPagePosition(page)); generateDrawPool(); } if (readerListener != null) { readerListener.onPageChanged(index); } currentPage = page; } @Override protected int transformPage(int page) { return page + 1; } public void goToPage(final int aPage) { if (pages != null) { final float finalScroll = getPagePosition(aPage - 1); final ValueAnimator va = ValueAnimator.ofFloat(yScroll, finalScroll).setDuration(500); va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { relativeScroll(0, (float) valueAnimator.getAnimatedValue() - yScroll); mHandler.post(new Runnable() { @Override public void run() { VerticalReader.this.generateDrawPool(); } }); } }); va.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animation) { animatingSeek = true; } @Override public void onAnimationEnd(Animator animation) { animatingSeek = false; currentPage = aPage; VerticalReader.this.generateDrawPool(); } @Override public void onAnimationCancel(Animator animation) { } @Override public void onAnimationRepeat(Animator animation) { } }); va.start(); } } @Override protected Page getNewPage() { return new VPage(); } @Override public void reset() { xScroll = 0; yScroll = 0; currentPage = 0; pages = null; pagesLoaded = false; viewReady = false; animatingSeek = false; totalHeight = 0; } @Override public float getPagePosition(int page) { if (pages != null && pages.size() > 1) { if (page < 0) { return pages.get(0).init_visibility; } else if (page < pages.size()) { if (pages.get(page).scaled_height * mScaleFactor > screenHeight) { return pages.get(page).init_visibility; } else { int add = (int) (pages.get(page).scaled_height * mScaleFactor - screenHeight) / 2; return pages.get(page).init_visibility + add; } } else { return pages.get(pages.size() - 1).end_visibility; } } else { return 0; } } protected class VPage extends Page { @Override public boolean isVisible() { float visibleBottom = (yScroll * mScaleFactor + screenHeight); final boolean visibility = (yScroll * mScaleFactor <= init_visibility * mScaleFactor && init_visibility * mScaleFactor <= visibleBottom) || (yScroll * mScaleFactor <= end_visibility * mScaleFactor && end_visibility * mScaleFactor <= visibleBottom) || (init_visibility * mScaleFactor < yScroll * mScaleFactor && end_visibility * mScaleFactor >= visibleBottom); new Thread(new Runnable() { @Override public void run() { if (visibility != lastVisibleState) { lastVisibleState = visibility; if (!visibility) { freeMemory(); } } if (visibility && segments != null) for (Segment s : segments) { s.checkVisibility(); } } }).start(); return visibility; } @Override public Segment getNewSegment() { return new VSegment(); } @Override public float getVisiblePercent() { if (init_visibility < yScroll) { if (end_visibility < yScroll + screenHeight) { return (end_visibility - yScroll) / scaled_height; } else { return screenHeight / scaled_height; } } else { if (end_visibility < yScroll + screenHeight) { return 1; } else { return (yScroll + screenHeight - init_visibility) / scaled_height; } } } public class VSegment extends Segment { @Override public boolean checkVisibility() { float visibleTop = yScroll * mScaleFactor; float visibleBottom = visibleTop + screenHeight; float _init_visibility = init_visibility + dy * unification_scale; float _end_visibility = _init_visibility + ph * unification_scale; boolean visibility = (visibleTop <= _init_visibility * mScaleFactor && _init_visibility * mScaleFactor <= visibleBottom) || (visibleTop <= _end_visibility * mScaleFactor && _end_visibility * mScaleFactor <= visibleBottom) || (_init_visibility * mScaleFactor < visibleTop && _end_visibility * mScaleFactor >= visibleBottom); if (visible != visibility) { visibilityChanged(); } return visibility; } @Override public void draw(Canvas canvas) { if (state == ImagesStates.LOADED) { mPaint.setAlpha(alpha); m.reset(); m.postTranslate(dx, dy); m.postScale(unification_scale, unification_scale); m.postTranslate(-xScroll, init_visibility - yScroll); m.postScale(mScaleFactor, mScaleFactor); try { canvas.drawBitmap(segment, m, mPaint); } catch (Exception ignored) { ignored.printStackTrace(); } } } } } }